diff --git a/.gitignore b/.gitignore index 36b13f1..8838db4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,176 +1,80 @@ -# ---> Python -# Byte-compiled / optimized / DLL files +# ---- Python / tooling ---- __pycache__/ *.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ *.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ .pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# UV -# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -#uv.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/latest/usage/project/#working-with-version-control -.pdm.toml -.pdm-python -.pdm-build/ - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -# Ruff stuff: .ruff_cache/ +.mypy_cache/ +.venv/ +dist/ +build/ -# PyPI configuration file -.pypirc +# ---- IDE ---- +.idea/ +.vscode/ +*.iml +# ---- 运行环境 ---- +.env +.env.dev +*.log + +# ---- hexi/ 数据与缓存(运行时生成,不入库) ---- +/hexi/data/ +/hexi/logs/ +/hexi/data/cache/ +/hexi/data/temp/ +/hexi/data/multincm/ + +# ---- hexi/ 配置(保留 memes 用户配置;其余运行时数据) ---- +/hexi/config/_legacy/ +/hexi/config/nonebot_plugin_memes/ + +# ---- 数据库 ---- +*.db +*.sqlite3 +hexi/plugins/user.db + +# ---- 插件运行时私有数据 ---- +/hexi/plugins/nonebot_plugin_bf_bot/avatar_cache/ +/hexi/plugins/nonebot_plugin_bf_bot/cookies/ +/hexi/plugins/nonebot_plugin_bf_bot/data/ +/hexi/plugins/nonebot_plugin_dailywife/config/ +/hexi/plugins/nonebot_plugin_helldivers_tools/temp/ +/hexi/plugins/nonebot_plugin_video_analysis/data/ +/hexi/plugins/nonebot_plugin_mc_server_status/data/ + +# ---- multincm cwd 调试产物(第三方插件硬编码 Path.cwd()/debug) ---- +/debug/ + +# ---- 前端依赖 ---- +node_modules/ + +# ---- 插件运行时数据(补充) ---- +# playwright chrome_profile +/hexi/plugins/nonebot_plugin_picfinder_take/data/ +# 群聊数据 json +/hexi/plugins/nonebot_plugin_deadlock/data/ +# QQ 头像缓存 +/hexi/plugins/nonebot_plugin_group_tools/res/img/memavatar/ +# 网页存档 +/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/wiki assets/ +# 调用统计/备份 +/hexi/plugins/nonebot_plugin_steam_info/data/ + +# ---- 临时文件 ---- +*.tmp +*.bak +bg.jpg +# 统一 Web 前端 +/hexi/web/node_modules/ +/hexi/web/dist/ +# HeroUI dev docs +/.heroui-docs/ + +# 插件配置运行时存储(含敏感值,勿提交) +/hexi/config/plugin_config*.json +/.ai/ +/.claude/ +/hexi/config/ +/CLAUDE.md diff --git a/README.md b/README.md index a5e9f5f..9962f56 100644 --- a/README.md +++ b/README.md @@ -1,2 +1 @@ -# Hexi - +个人娱乐bot,自己随便写点小功能 \ No newline at end of file diff --git a/bot.py b/bot.py new file mode 100644 index 0000000..d324fe5 --- /dev/null +++ b/bot.py @@ -0,0 +1,34 @@ +import nonebot +from nonebot.adapters.onebot.v11 import Adapter as ONEBOTV11Adapter +from nonebot.log import logger +from sqlalchemy import StaticPool +from starlette.middleware.cors import CORSMiddleware + +# 初始化 NoneBot 以及 数据库 +nonebot.init(datastore_engine_options={"poolclass": StaticPool}) + +# 获取应用和驱动实例 +app = nonebot.get_app() +app.add_middleware( + CORSMiddleware, + allow_origins=[ + "http://localhost:5173", + "http://192.168.2.186:5173", + "http://127.0.0.1:5173" + ], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) +driver = nonebot.get_driver() + +# 注册适配器 +driver.register_adapter(ONEBOTV11Adapter) + +# 加载插件 +nonebot.load_plugins("hexi") +nonebot.load_from_toml("pyproject.toml") + +if __name__ == "__main__": + logger.warning("hexi?启动!") + nonebot.run() # 直接运行,不需要传参 \ No newline at end of file diff --git a/docs/plugin-config-standard.md b/docs/plugin-config-standard.md new file mode 100644 index 0000000..0921182 --- /dev/null +++ b/docs/plugin-config-standard.md @@ -0,0 +1,433 @@ +# 插件配置文件标准(Plugin Config Standard) + +> HeXi 统一插件配置标准 —— 机器可读、带类型的 schema 声明 + 持久化值文件, +> 让 Web 管理台(/hub)能对任意插件**读取、展示、修改、热刷新、重启生效**。 +> +> 插件整体骨架/目录/入口/职责划分见《插件结构标准》(docs/plugin-structure-standard.md)。 + +--- + +## 0. 目标与一句话总结 + +- **核心原则**:插件只声明 `schema`,Web 自动生成表单;值统一写入值库;插件通过统一 API 读取生效值。 +- **一句话**:插件在导入时调用 `register_plugin_config(plugin_id, schema, apply, getter)` 声明配置;值写入 `hexi/config/plugin_config.json`;Web 端读 `{schema, values}` 渲染、保存后写回并热应用。 + +- **`plugin_id` 约定**:必须等于 NoneBot 插件模块名(如 `hexi.plugins.nonebot_plugin_helldivers_tools`)。Web 的 `/api/plugins//config` 才能命中,插件目录合表也用该 id。 + +--- + +## 1. 相关文件与位置 + +```text +hexi/ +├── web_config.py # 配置标准核心:schema 注册 / 值库 / 保存热刷新 +├── config_standard.py # pydantic Config 一键接入的辅助封装 +├── config/ +│ └── plugin_config.json # 统一值库:{ "": { key: value, ... } } +└── web/ # /hub 前端(通用 schema 表单渲染器) +``` + +> 值库按**插件聚合**,不每个插件一个文件:Web「插件管理」一页聚合所有插件配置、统一热刷新、统一迁移。 + +--- + +## 2. Schema 字段标准 + +每个插件声明一份 schema: + +```jsonc +{ + "version": 1, // 插件配置 schema 版本(用于迁移) + "fields": [ + { + "key": "hd2_api_base_url", // 必填,插件读取的字段名(snake_case) + "label": "API 根地址", // 必填,前端显示名 + "type": "string", // 必填,见 §3 + "default": "https://api.helldivers2.dev", + "description": "自托管 API 根地址;不填用公共社区 API。", + "secret": false, // true → 前端脱敏/掩码 + "required": false, + "placeholder": "http://192.168.2.15:18080", + "env": "HD2_API_BASE_URL", // 写回 .env 的变量名;缺省 = key.upper() + "options": [ // type=enum 时必填 + { "value": "auto", "label": "自动" }, + { "value": "manual", "label": "手动" } + ], + "min": 0, "max": 86400, // int/float 范围(可选) + "pattern": "^https?://", // 字符串校验(可选) + "group": "API 连接", // 表单分组(可选) + "depends_on": { "field": "enabled", "value": true }, // 条件显示(可选) + "item_type": "int", // type=list 的元素类型 int/float/str/bool(可选) + "newline_list": true // type=list 时:多行/逗号分隔(可选) + } + ] +} +``` + +### 字段说明 + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| `key` | string | 是 | 插件读取字段名,snake_case,唯一 | +| `label` | string | 是 | 前端显示名(中文) | +| `type` | string | 是 | 见 §3 | +| `default` | any | 否 | 用户未改时的回填默认 | +| `description` | string | 否 | 前端提示 | +| `secret` | bool | 否 | 敏感字段前端掩码,返回时脱敏 | +| `required` | bool | 否 | 保存时校验非空 | +| `options` | array | enum 必填 | `[{value,label}]` | +| `env` | string | 否 | 写 .env 变量名;缺省 `key.upper()` | +| `min` / `max` | number | 否 | 数值范围 | +| `pattern` | string | 否 | 字符串正则 | +| `item_type` | string | list 推荐 | 元素类型 | +| `newline_list` / `group` / `depends_on` | - | 否 | 展示/校验增强 | + +--- + +## 3. 支持的 type + +| type | 前端控件 | 存储 | 说明 | +|---|---|---|---| +| `string` | 单行输入 | 字符串 | 通用文本 | +| `text` | 多行文本域 | 字符串(支持 \n) | 长文本/提示词/模板 | +| `password` | 密码框(掩码) | 字符串 | 自动 `secret:true` | +| `int` | 数字输入 | 整数 | | +| `float` | 数字输入 | 浮点数 | | +| `bool` | 开关 | 布尔 | | +| `enum` | 下拉 | `options[].value` | 必须提供 options | +| `list` | 多行文本(每行一项) | 数组 | 需 `item_type`;兼容逗号分隔 | +| `json`/object | 代码文本域 | JSON 对象(校验后存) | 高级 | +| `path` | 单行输入 | 路径字符串 | 运行期转 `Path` | +| `object_set` | 通用表格(增删改) | list[dict] | 一组结构化条目;需 `item_schema` + `key_field`,见 §14 | + +**约定** +- `key` 一律 snake_case。 +- `secret` 字段只返回 `****`,绝不返回明文;提交未修改的 `****` 表示保持原值,只有提交 `null` 才清除。 +- 复杂类型(`list`/`path`/`object`/`object_set`)在 `.env` 里不易安全表达,**只做运行期热更新**,不落 `.env`;重启需插件自行从值库读取。 + +--- + +## 4. 值文件存储标准 + +```jsonc +{ + "hexi.plugins.nonebot_plugin_helldivers_tools": { + "hd2_api_base_url": "http://192.168.2.15:18080", + "hd2_api_language": "zh-Hans", + "hd2_cache_ttl": 60, + "hd2_super_client": "hexi-bot.local", + "hd2_super_contact": "https://github.com/..." + }, + "hexi.plugins.nonebot_plugin_steam_info": { + "steam_api_key": ["key1", "key2"], + "steam_request_interval": 300, + "steam_broadcast_type": "part", + "steam_playtime_theme": "light", + "proxy": null + } +} +``` + +- 键 = `plugin_id`;值 = 仅**用户显式设置过**的字段(未设置不写死,避免覆盖 .env)。 +- `null` 表示「清空/恢复默认」。 +- **原子写入**:先写临时文件再 `os.replace`;启动读取失败时保留原文件并告警,不得静默覆盖为空。 +- 读取优先级:**用户值库 > getter 生效值 > schema default**。 +- 保存校验失败返回 HTTP 422,不能静默把非法输入替换成默认值。 +- 值库按插件保存 `revision`;保存必须携带当前 revision,冲突返回 HTTP 409。 + +--- + +## 5. 插件读取配置的标准 API + +### 方式 A:pydantic Config 一键接入(推荐) + +```python +# 在插件 __init__.py 里 +from hexi.config_standard import register_model_config +from .config import config + +register_model_config( + __name__, # = NoneBot 插件模块名 + config, # 模块级 pydantic Config 实例 + fields=["hd2_api_base_url", "hd2_cache_ttl", ...], + labels={"hd2_api_base_url": "API 根地址", ...}, + descriptions={...}, + options={"mode": [{"value": "auto", "label": "自动"}]}, + types={"mode": "enum"}, # 覆盖自动推断的 type +) +``` + +运行期插件直接读 `config.hd2_api_base_url`。 + +`register_model_config` 自动: +- 推断字段类型(`bool/int/float/string/enum/text`); +- `Literal[...]` → 下拉枚举;`list[str]`/`list[int]` → 多行文本并按元素类型转换; +- 内置 getter(回填当前生效值) 与 apply(保存后热更新 pydantic 对象,无需重启); +- 密码/key/token 类字段自动 `secret=True`。 + +### 方式 B:非 pydantic 插件手动注册 + +```python +from hexi.web_config import register_plugin_config + +def _get(): # 返回当前生效值 dict + return {"field": get_my_cur_value("field")} + +def _apply(values): # 保存后热应用 + set_my_config(values) + +register_plugin_config( + __name__, + {"fields": [{"key": "field", "label": "字段", "type": "string", "default": ""}]}, + apply=_apply, + getter=_get, +) +``` + +--- + +> **同一插件可多次注册**:`register_plugin_config` / `register_model_config` / `register_config_items` / `register_object_set` 对同一 `plugin_id` 重复调用时,**字段按 key 自动合并到一个 schema**,getter 合并取值,apply 按注册顺序依次应用(不覆盖)。所以 `config.py` 里分多段注册(如 temp 清理 / S3 / 群分组 / object_set)是合理且推荐的。 + +## 6. 值读取优先级 + +`get_config(plugin_id)` 对每个字段按序取值: + +1. **用户已保存值**(值库 `plugin_config.json`); +2. **getter 返回的当前生效值**(插件运行态); +3. **schema.default**; +4. `None`。 + +这样 Web 表单打开时显示的是**插件当前真正生效的配置**,而不是只看默认值。 + +--- + +## 7. 保存流程(热刷新) + +`save_config(plugin_id, values)`: + +1. 按 schema 字段的 type/`item_type` 做 **类型校验与转换**(string/int/float/bool/enum/list)。 +2. **写值库** `plugin_config.json`(原子写)。 +3. **写 .env**:非 list 字段写入 `os.environ` + `.env`(保证重启仍生效);list/path/object 跳过,避免 `str(list)` 破坏重启解析。 +4. **调 `apply(values)`**:把值热应用到插件运行态对象(list/path/object 也在此生效)。 +5. 若插件未提供 apply,则 `hot_reload(plugin_id)` 让插件重载。 + +**为什么 apply 与 env 都做**:NoneBot 的 `get_driver().config` 在启动时即固定,重载插件也读不到新 env;所以运行期必须 apply,重启靠 env。 + +--- + +## 8. Web 端「读 / 改」标准接口(/hub) + +| 方法 | 路径 | 说明 | +|---|---|---| +| GET | `/api/plugins` | 所有已注册 Web 插件 | +| GET | `/api/plugins/catalog` | 所有应用插件 + `has_config/has_web/web_path` | +| GET | `/api/plugins/{id}/config` | 读 `{schema, values, revision}`(登录);secret 值只返回 `****` | +| POST | `/api/plugins/{id}/config` | 保存 `{ "revision": n, "values": { key: value } }`;冲突 409,校验失败 422 | +| DELETE | `/api/plugins/{id}/config` | 清空该插件覆盖,恢复默认(可选) | + +响应示例(GET): + +```jsonc +{ + "ok": true, + "revision": 3, + "schema": { "fields": [ { "key": "hd2_cache_ttl", "type": "int", "default": 60, ... } ] }, + "values": { "hd2_cache_ttl": 60, "hd2_api_base_url": "http://192.168.2.15:18080" } +} +``` + +前端 `hexi/web/src/pages/plugins/index.tsx` 已按 `type` 自动渲染:bool→开关、enum→下拉、text→多行、password→掩码、int/float→数字、secret→脱敏。 + +--- + +## 9. 权限与安全 + +- 全部配置接口走 `hexi.web_auth.require_admin`(OAuth2 + SQLite)。 +- 配置 POST 必须携带 GET 返回的 `revision`;缺失返回 428,冲突返回 409。 +- 只允许 `plugin_id` 存在于注册表,未注册返回 `ok:false`(防任意写入)。 +- 部署时必须显式设置 Web 管理员凭据;禁止生产环境使用默认的 `admin/admin`。 +- `secret` 字段只返回 `****`;提交 `****` 保持原值,提交 `null` 清除,写回明文仅限服务端受控存储。 +- 写 .env 用「原行更新/追加」,保留注释,不整文件覆盖。 + +--- + +## 10. 版本与迁移 + +配置保存状态至少区分:`persisted`(值库已保存)、`applied`(运行态已应用)、`restart_required`(需重启)和 `apply_failed`(应用失败)。apply 失败时接口必须返回错误,且保留上一份可恢复配置。 + +```jsonc +{ + "$schema_version": 3, + "plugins": { + "hexi.plugins.xxx": { + "schema_version": 1, + "values": { "...": "..." } + } + } +} +``` + +- 升级 schema 时保留 `values`:新增字段取 `default`,删除字段清理。 +- 提供 `migrate(plugin_id, old_schema, new_schema)` 钩子,支持字段改名/类型升级/`str` 列表迁 `list[int]`;迁移必须幂等,失败时保留旧值文件并阻止该插件配置加载。 +- 读到未知插件条目时保留并上报,不强制删除。 + +--- + +## 11. 落地示例 + +```python +# hexi/plugins/nonebot_plugin_helldivers_tools/__init__.py +from hexi.config_standard import register_model_config +from .config import config as _hd2_config + +register_model_config( + __name__, + _hd2_config, + fields=["hd2_api_base_url", "hd2_api_language", "hd2_cache_ttl", + "hd2_super_client", "hd2_super_contact"], + labels={"hd2_api_base_url": "API 根地址", "hd2_cache_ttl": "数据缓存秒数", ...}, + descriptions={"hd2_api_base_url": "自托管 API 根地址;不填用公共社区 API", ...}, +) +``` + +--- + +## 12. 已接入与待接入 + +- **已接入**:`helldivers_tools`、`mc_server_status`、`video_analysis`、`steam_info`、`picstatus`、`galgame_card`。 +- **未接入(建议后续)**:`learning_chat`、`group_daily_analysis`(已有独自 Web 配置,避免冲突)、`picfinder_take`、`bf_bot`、`group_tools`、`hexi_core`(模块级常量/SUPERUSERS,运行期热更复杂)。 + + +--- + +## 13. 插件内部配置项(来源无关)接入标准 + +> **不只是 `.env`**:插件内部自己的配置项(module 常量、YAML/JSON 配置、数据库里的开关等)同样遵循统一 schema,Web 可读可改。核心是让每个配置项自带 **getter/setter**,与来源解耦。 + +### 13.1 四种来源与接入方式 + +| 配置来源 | 接入方式 | getter/setter | 持久化 | 运行期生效点 | +|---|---|---|---|---| +| pydantic Config(`.env` 驱动) | `register_model_config` | 自动(读写 Config 对象) | 写值库 + 写 `.env` | apply 热更新对象 | +| 模块常量 | `register_config_items(..., store=模块)` | 自动(getattr/setattr) | 写值库(可选写 `.env`) | 需插件用 `get_effective_value` 读取 | +| 配置文件(dict/JSON/YAML) | `register_config_items(..., store=dict)` | 自动(读写 dict) | 插件自身写回文件 / 值库 | 插件从 dict 读取时即生效 | +| 自定义(DB/运行态) | `register_config_items` 传 `getter`/`setter` | 自定义 | 自定义回写 | 自定义 | + +### 13.2 通用注册 API(任意来源) + +```python +from hexi.config_standard import register_config_items + +register_config_items( + __name__, # = NoneBot 插件模块名 + [ + {"key": "DAILY_LIMIT", "label": "每日限额", "type": "int", "default": 50}, + {"key": "CHECK", "label": "开启截屏判定", "type": "bool", "default": True}, + {"key": "SAUCENAO_KEY", "label": "API Key", "type": "password", "secret": True}, + # 也可为某条目自定义 getter/setter + {"key": "custom", "label": "自定义", "type": "string", + "getter": lambda: my_get(), "setter": lambda v: my_set(v)}, + ], + store=config_module, # dict 或模块;未写 getter/setter 时默认读写这里 + apply_extra=None, # 可选:保存后做额外持久化/热加载 + getter_extra=None, # 可选:getter 额外返回非 items 的值 +) +``` + +### 13.3 关键规则:运行期要生效,插件必须读生效值 + +Web 保存后 apply 会把新值写回来源(模块属性/dict/自定义),但若插件在别处是用 `from .config import X` **值拷贝**进来的量,不受影响。要真正运行期生效,插件在读配置处改用统一 API: + +```python +from hexi.web_config import get_effective_value + +limit = get_effective_value("hexi.plugins.nonebot_plugin_picfinder_take", "DAILY_LIMIT", 50) +if not check_quota(limit): ... +``` + +优先级:**用户值库 > getter 生效值 > default**。这样 Web 改完即可生效,重启也不丢。 + +### 13.4 已接入的非 env 示例 + +- `picfinder_take`:把 `SAUCENAO_KEY / DAILY_LIMIT / SEARCH_TIMEOUT / CHECK / THUMB_ON / CHAIN_REPLY / IGNORE_STAMP / threshold` 这些内部常量注册为 Web 可读可改配置项(store=config 模块)。 + +- `video_analysis`:把原本硬编码在 `storage/s3.py` 的 S3 连接配置(PLANA/PLANB/PLANC/公网 endpoint/access/secret/bucket/region/secure/domain)注册为 Web 可读可改项;apply 时清空懒加载 S3 客户端缓存,且 s3 客户端创建时经 `get_effective_value` 读取,因此**运行期与重启均生效**。另用 `type=json` 暴露 `data/list.json` 的**群分组配置**(`groups` + `blacklist`),自定义 getter/setter 同步读写,并标记 `nosave`(不写入 plugin_config.json,权威源是 list.json),避免与 `添加白名单` 等指令互相覆盖为陈旧值。 + +- **生效说明**:注册后 Web 能读、能改、会持久化;若希望改完立刻反映到插件行为,需把插件内对应读取点改成 `get_effective_value`(见 §13.3),或让 apply_extra 里 `hot_reload` 并让 config 模块从值库初始化。 + +--- + +## 14. 通用对象集标准(object_set) + +> 当插件要暴露「一组结构化条目」时(群分组、测速站点、服务器列表、白/黑名单成员、装备表等),用 `object_set` 类型声明 **item_schema + key_field**,Web 端通用渲染成可增删改的表格,后端通用按子字段校验/去重。 + +### 14.1 Schema 形态 + +```jsonc +{ + "key": "groups", + "label": "群分组配置", + "type": "object_set", + "key_field": "group_id", // 子字段主键(定位/去重/删除行) + "item_schema": { + "fields": [ + {"key": "group_id", "label": "群号", "type": "string", "required": true}, + {"key": "auto", "label": "自动解析", "type": "bool", "default": false}, + {"key": "plan", "label": "存储方案", "type": "enum", + "options": [{"value":"A","label":"A"},{"value":"B","label":"B"}]}, + {"key": "auto_link", "label": "自动链接关键词", "type": "text", "item_type": "str"} + ] + }, + "default": [], + "nosave": true // 权威源在插件自身文件/DB 时填 true +} +``` + +### 14.2 值形态 + +```jsonc +[ + {"group_id":"123", "auto":true, "plan":"A", "auto_link":["xhs"]}, + {"group_id":"456", "auto":false, "plan":null, "auto_link":[]} +] +``` + +### 14.3 一键注册 API + +```python +from hexi.config_standard import register_object_set + +register_object_set( + __name__, # NoneBot 插件模块名 + "groups", # 对象集配置 key + [ # item_schema 子字段 + {"key": "group_id", "label": "群号", "type": "string"}, + {"key": "auto", "label": "自动解析", "type": "bool", "default": True}, + {"key": "plan", "label": "方案", "type": "enum", + "options": [{"value":"A","label":"A"},{"value":"B","label":"B"}]}, + {"key": "auto_link", "label": "关键词", "type": "text", "item_type": "str"}, + ], + key_field="group_id", + getter=get_groups, # () -> list[dict] + setter=set_groups, # (list[dict]) -> None(插件自行写回来源) + label="群分组配置", + nosave=True, # 权威源在 list.json/DB,不写 plugin_config.json +) +``` + +框架自动做:**按 `item_schema` 逐字段类型转换**(bool/int/float/string/enum/text/list/json)、触发 `_coerce_value` 的值转成目标类型、**按 `key_field` 去重并丢弃缺主键行**,再把归一整形的 list 交给你的 setter。 + +### 14.4 Web 端通用表格组件(建议) + +- 前端新增 `ObjectSetEditor` 组件,读 `field.item_schema.fields` 渲染表头 + 每行输入(与 §3 type 一一对应); +- 支持:**添加行、删除行、编辑单元格、上移/下移**(可选);主键列默认唯一校验; +- 保存时把整个 list 提交到既有 `POST /api/plugins/{id}/config`,无需新接口; +- 也可按需加细粒度:`POST /api/plugins/{id}/config/{key}` 单条 upsert、`DELETE .../{key}/{key_value}` 删除单行(后端需在 apply 里实现 upsert/delete)。 + +### 14.5 可接入示范(候选) + +- `video_analysis`:`list.json` 的 `groups` 群分组(从纯 JSON 升级为结构化 object_set,Key=group_id); +- `picstatus`:`ps_test_sites` 测速站点列表(Key=name); +- `mc_server_status`:`var.group_list` 每群服务器列表(Key=群号); +- `helldivers_tools`:战备数据(可只读展示,来源 SQLite,Key=id); +- `learning_chat`:分群配置(Key=group_id)。 diff --git a/docs/plugin-structure-standard.md b/docs/plugin-structure-standard.md new file mode 100644 index 0000000..5b4c2fb --- /dev/null +++ b/docs/plugin-structure-standard.md @@ -0,0 +1,156 @@ +# 插件结构标准(Plugin Structure Standard) + +> HeXi 所有自定义插件的统一骨架:包命名、目录布局、入口/配置/工具/服务/数据/Web 职责划分。 +> 配合《插件配置文件标准》(plugin-config-standard.md) 使用:结构标准管「怎么组织代码」,配置标准管「配置如何统一并暴露给 Web」。 + +--- + +## 0. 目标 + +- 让新插件**开箱即用**:照骨架抄一遍即可,天然接入统一配置 + Web 管理台。 +- 让旧插件**逐步收敛**到同一结构,避免「入口一大坨、配置散落、数据读写各自为政」。 +- 让 **Web 管理台能统一读/改所有插件的配置**(不是只针对 env)。 + +## 1. 包命名与位置 + +- 位置:`hexi/plugins/nonebot_plugin_/`(`bot.py` 用 `nonebot.load_plugins("hexi")` 加载)。 +- 包名 = NoneBot 模块名 = `hexi.plugins.nonebot_plugin_`。 +- **`plugin_id` 约定**:用于配置 schema / 插件控制 / Web 挂载的值,一律等于模块名(`__name__`)。 + +## 2. 架构分层:MTSS(Model–Trigger–Service–View) + +> 本插件结构可用一种「事件驱动的 MVC」来理解:Controller 被换成 **Trigger(触发器)**,并多出一个**双 View**(聊天 + 管理端)。我们称之为 **MTSS**。 + +### 2.1 四层职责 + +| 层 | 目录 | 职责 | +|---|---|---| +| **Trigger** | `handlers/*` | `on_command/on_message/on_notice`、定时任务、Web 按钮 → 统一**入口适配器**,接触发后调 service、出 View | +| **Service** | `services/*` | 业务编排:一个业务动作一个方法;不关心是哪个触发器进来的,可被多触发器/定时/Web 复用 | +| **Model** | `models.py` + `repository.py`/`storage/*` + `data/*` | 数据(ORM/JSON/SQLite/S3)与数据访问;唯一读写入口 | +| **View** | 聊天出图/`UniMessage`;Web 端 `web/` + schema 表单 | **双 View**:a) 发给聊天用户(文本/图片/转发);b) 管理端(Web REST + 前端) | + +### 2.2 依赖方向(单向、向下) + +```text +Trigger(handlers) → Service(services) → Model(repository/storage) + ↘ 外部 API / LLM +Trigger/View → 依赖 nonebot / OneBot / 平台 +Service/Model → 尽量不 import nonebot(可单测、未来可换框架) + ↑ 配置标准 config.py 是横切模块,各层都能读 +``` + +### 2.3 关键规则 + +- **Trigger 只做**:接触发 → 鉴权/校验 → 调 service → 出 View;**不要放大逻辑**。 +- **View 有两个出口**:`chat`(发给用户) 与 `web`(管理端),可共用同一个 Service 的结果(类似 MVVM 的「一个 ViewModel 两个 View」)。 +- **service/repository 不 import nonebot**,便于单测与切换框架;只依赖 Model 与配置标准。 +- **触发器来源不限**:群消息 / 私聊 / at / 定时 / Web 按钮。想加「Web 手动触发」,只需在 Trigger 层加一个入口复用同一个 service。 + +### 2.4 示例(video_analysis) + +```text +Trigger → handlers/entry.py 的 auto/active matcher(card/文本链接) +Service → dispatch_url 平台分派(可下沉到 services/) +Model → list_proc.py(list.json)、storage/s3.py、models.py(异常) +View → chat: UniMessage 文本/图片; web: config schema + 未来的 ObjectSetEditor +Config → config.py 统一注册(cleanup/S3/group_config) +``` + +--- + +## 3. 目录骨架模板 + +```text +nonebot_plugin_xxx/ +├── __init__.py # 入口:元数据 + 命令注册 + 配置注册 + 启动钩子 +├── config.py # 配置标准:Config(BaseModel) / register_object_set / register_config_items +├── models.py # ORM / dataclass 模型(可选) +├── repository.py # 数据访问层:唯一读写入口(可选) +├── handlers/ # 命令/消息处理(按域拆分) +│ ├── __init__.py +│ └── chat.py management.py notices.py ... +├── services/ # 业务编排层(被多个 handler/定时任务复用) +│ └── __init__.py +├── utils/ # 纯工具:无副作用、尽量无 nonebot 依赖、可单测 +│ └── __init__.py +├── data/ # 运行时数据(或统一放 hexi/data/) +├── res/ # 静态资源:图片/字体/模板 +├── web/ # 可选:插件自带 Web 前端(build 产物挂载) +├── README.md # 可选 +└── CLAUDE.md # 可选:插件内开发文档(在此插件内开发时优先读) +``` + +## 4. `__init__.py` 标准职责(固定顺序) + +1. `__plugin_meta__ = PluginMetadata(name=..., description=..., usage=..., type="application")`。 +2. 声明依赖 `require("nonebot_plugin_alconna")` 等。 +3. 显式导入子模块(`from . import handlers, services, utils`),注册 matcher/handler。 +4. **配置注册**(在 config 就绪后):`register_model_config`(pydantic Config)或 `register_config_items` / `register_object_set`(来源无关)。 +5. 可选 `register_web_plugin("id", "名称", "icon", lambda: build_app(), module_name=__name__)`。 +6. 启动钩子 `@driver.on_startup`:初始化 DB / 加载 data 文件 / 注册定时任务。 +7. 业务命令尽量放 `handlers/`,不要把大逻辑堆在 `__init__.py`。 + +## 5. config.py 标准 + +### 4.1 环境驱动型(读 `.env` / NoneBot config) +```python +from nonebot import get_plugin_config +from pydantic import BaseModel + +class Config(BaseModel): + enable: bool = True + api_key: str = "" + +config = get_plugin_config(Config) +``` +然后 `register_model_config(__name__, config, fields=[...], labels={...})` 接入 Web。 + +### 4.2 来源无关型(模块常量 / 配置文件 / DB) +```python +from hexi.config_standard import register_config_items, register_object_set +register_object_set(__name__, "groups", [ {item_schema...} ], key_field="group_id", + getter=get_groups, setter=set_groups, nosave=True) +``` +详见《plugin-config-standard.md》§5/§13/§14。 + +### 4.3 约定 +- 敏感字段 `type="password"` 且 `secret=True`; +- 默认值写进 schema,供 Web 回填; +- `nosave=True` 表示权威源在插件自身(文件/DB),Web 修改只 apply 到来源,不写 plugin_config.json。 + +## 6. 数据层标准 + +- 读写统一走 `repository.py`(或 services 内封装的仓储方法),避免 SQL/文件读写散落各处。 +- ORM:用 `nonebot_plugin_orm` 的 `get_session()`;模型在 `models.py`。 +- 文件:**原子写**(tmp + `os.replace`),避免并发/崩溃写坏 JSON。 +- SQLite:开 WAL、用事务;不要在循环里逐条写。 +- 路径:统一用插件 `get_data_dir()`/`get_plugin_cache_dir()` 或 `hexi` 的路径工具,**不硬编码绝对路径**。 + +## 7. 工具/服务标准 + +- `utils/`:纯函数、无状态、尽量不 import nonebot/driver,便于单测。 +- `services/`:业务编排,可依赖 repository / 外部 API;把「一个业务动作」收敛到一个方法。 +- **禁止** `from x import *`、`except: pass`、`print()`;用 `logger`。 +- async handler 内避免同步阻塞(`requests` / `time.sleep` / 同步爬虫);需要就 `asyncio.to_thread`。 +- 命令触发:需要 @ 用 `rule=to_me()`;全局命令注意与其它插件冲突;高开销命令加冷却/限频(`hexi_core` 的 `cooldown/rate_limit`)。 +- 外部 API:统一超时 + 重试 + 失败降级/用户提示。 + +## 8. Web 接入标准 + +- 需要独立 Web 页:`register_web_plugin(id, name, icon, lambda: build_app(), module_name=__name__)`,hub 启动自动挂载 `/api/`。 +- 需要 Web 配置:`register_plugin_config` / `register_model_config` / `register_config_items` / `register_object_set`(schema 驱动表单)。 +- 鉴权统一用 `hexi.web_auth.require_admin`(OAuth2 + SQLite),不要自造一套。 +- 敏感字段 `secret=True`,前端掩码;写回允许明文。 + +## 9. 插件迁移检查清单 + +- [ ] 包名改为 `nonebot_plugin_*`,位置在 `hexi/plugins/`。 +- [ ] 有 `__plugin_meta__`,`type="application"`。 +- [ ] 配置已接入统一标准(Web 能读能改,运行期/重启生效)。 +- [ ] 命令在 `handlers/`,业务在 `services/`,工具在 `utils/`。 +- [ ] 数据访问集中(repository / services),原子写 / 事务。 +- [ ] 无 `*` 导入、裸 `except`、`print`;无同步阻塞混入 async。 +- [ ] 运行数据写入统一数据目录,不写入插件源码目录;配置读取点支持标准热更新语义。 +- [ ] 外部请求有超时/重试/失败提示;命令有权限/限流。 +- [ ] 需要 Web 的已 `register_web_plugin`;鉴权走统一 `web_auth`。 diff --git a/hexi/__init__.py b/hexi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hexi/config_standard.py b/hexi/config_standard.py new file mode 100644 index 0000000..02abd92 --- /dev/null +++ b/hexi/config_standard.py @@ -0,0 +1,488 @@ +# -*- coding: utf-8 -*- +"""统一配置标准辅助:把插件 pydantic Config 模型一键接入 hexi.web_config。 + +这个模块是对 hexi.web_config 的薄封装,目的是把「插件配置标准」统一起来: +- 插件只需声明一份字段列表(或交给字段推断),就能在 Web 管理台可读可设置。 +- 提供 getter(回填当前生效值)与 apply(保存后热更新 pydantic 对象)。 + +约定: +- plugin_id 必须是 NoneBot 插件模块名(与 plugin_control.list_plugins 一致), + 这样 Web 的 /api/plugins//config 才能命中。 +- 字段 key 就是 Config 模型里的属性名;env 名默认等于 key.upper()。 +""" + +from __future__ import annotations + +import inspect +import json +from types import UnionType +from typing import Any, Callable, Iterable, Literal, Optional, Union, get_args, get_origin + +from pydantic import BaseModel + +from hexi.web_config import register_plugin_config + +# 常见「密码/密钥」类字段名,前端会自动脱敏 +_SECRET_HINTS = ("password", "secret", "token", "key", "cookie", "apikey", "api_key") + + +def _is_secret(key: str) -> bool: + kl = key.lower() + return any(h in kl for h in _SECRET_HINTS) + + +def _unwrap_optional(annotation: Any) -> tuple[Any, bool]: + """剥掉 Optional/Union[..., None] 包装,返回 (真实类型, 是否可选)。""" + is_optional = False + origin = get_origin(annotation) + if origin is Union or origin is UnionType: + args = get_args(annotation) + non_none = [a for a in args if a is not type(None)] + if len(non_none) != len(args): + is_optional = True + if non_none: + return non_none[0], is_optional + return annotation, is_optional + + +def _type_label(annotation: Any) -> str: + """把 pydantic 字段类型映射到 web_config 支持的 schema type。""" + annotation, _ = _unwrap_optional(annotation) + if annotation is bool: + return "bool" + if annotation is int: + return "int" + if annotation is float: + return "float" + if annotation is str: + return "string" + try: + origin = get_origin(annotation) + except Exception: # noqa: BLE001 + origin = None + if origin is Literal: + return "enum" + if origin in (list, set, tuple): + args = get_args(annotation) + if args and args[0] is str: + return "text" + return "text" + return "string" + + +def _enum_options(annotation: Any) -> list[dict[str, str]]: + annotation, _ = _unwrap_optional(annotation) + try: + origin = get_origin(annotation) + args = get_args(annotation) + except Exception: # noqa: BLE001 + return [] + if origin is Literal: + return [{"value": str(o), "label": str(o)} for o in args] + return [] + + +def _text_item_type(annotation: Any) -> str: + """List[int]/List[float]/List[str] 的元素类型,用于 text 字段的取值转换。""" + annotation, _ = _unwrap_optional(annotation) + try: + origin = get_origin(annotation) + args = get_args(annotation) + except Exception: # noqa: BLE001 + return "str" + if origin in (list, set, tuple) and args: + el, _ = _unwrap_optional(args[0]) + if el is int: + return "int" + if el is float: + return "float" + if el is bool: + return "bool" + return "str" + + +def _coerce_value(value: Any, typ: str, item_type: str = "str") -> Any: + """按 schema type 把前端字符串/值转成目标 python 值。""" + if value is None: + return None + if typ == "bool": + if isinstance(value, bool): + return value + return str(value).strip().lower() in {"1", "true", "yes", "on"} + if typ == "int": + try: + return int(value) + except (TypeError, ValueError): + return None + if typ == "float": + try: + return float(value) + except (TypeError, ValueError): + return None + if typ == "text": + if isinstance(value, (list, tuple, set)): + items = list(value) + else: + # TextArea 多行/逗号分隔都接受 + import re as _re + parts = _re.split(r"[,\n]+", str(value)) + items = [p.strip() for p in parts if p.strip()] + if item_type == "int": + out = [] + for it in items: + try: + out.append(int(it)) + except (TypeError, ValueError): + continue + return out + if item_type == "float": + out = [] + for it in items: + try: + out.append(float(it)) + except (TypeError, ValueError): + continue + return out + return items + if typ == "json": + # 前端提交的是 JSON 字符串,解析成 dict/list;已解析则原样返回 + if isinstance(value, str): + try: + return json.loads(value) + except ValueError: + return None + return value + if typ == "object_set": + # 前端提交的要么是字符串 JSON,要么已是 list[dict] + if isinstance(value, str): + try: + parsed = json.loads(value) + return parsed if isinstance(parsed, list) else [] + except ValueError: + return [] + if isinstance(value, list): + return value + return [] + return "" if value is None else str(value) + + +def _stringify(value: Any, typ: str) -> Any: + """把 python 值转成 Web 表单能显示的值。""" + if typ == "text": + if value is None: + return "" + if isinstance(value, (list, tuple, set)): + return "\n".join(str(v) for v in value) + return str(value) + if typ == "json": + if value is None: + return "" + if isinstance(value, (dict, list, tuple)): + return json.dumps(value, ensure_ascii=False, indent=2) + return str(value) + # object_set 保持结构化(list[dict])原样返回,前端用专用表格组件渲染 + return value + + +def register_model_config( + plugin_id: str, + config_instance: BaseModel, + fields: Optional[Iterable[str]] = None, + labels: Optional[dict[str, str]] = None, + descriptions: Optional[dict[str, str]] = None, + options: Optional[dict[str, list[dict[str, str]]]] = None, + types: Optional[dict[str, str]] = None, + apply_extra: Optional[Callable[[dict[str, Any], BaseModel], None]] = None, + getter_extra: Optional[Callable[[BaseModel], dict[str, Any]]] = None, +) -> None: + """把 pydantic Config 模型注册进统一 Web 配置标准。 + + Args: + plugin_id: NoneBot 插件模块名。 + config_instance: 插件模块级 pydantic Config 实例(如 `.config.config`)。 + fields: 需要暴露的字段名。缺省=全部非私有字段(自动推断)。 + labels/descriptions/options: 可选的中文透出/提示/枚举覆盖。 + apply_extra: 可选的额外热应用回调(如需要重注册定时任务)。 + getter_extra: 可选的额外取值(如会额外返回非模型字段)。 + """ + try: + hints = inspect.get_annotations(type(config_instance), eval_str=True) + except Exception: # noqa: BLE001 + try: + hints = { + k: f.annotation + for k, f in config_instance.__class__.model_fields.items() + } + except Exception: # noqa: BLE001 + hints = {} + + try: + defaults = { + k: f.default + for k, f in config_instance.__class__.model_fields.items() + } + except Exception: # noqa: BLE001 + defaults = {} + + field_names = list(fields) if fields else [k for k in hints if not k.startswith("_")] + schema_fields: list[dict[str, Any]] = [] + for key in field_names: + annotation = hints.get(key, str) + typ = (types or {}).get(key) or _type_label(annotation) + default = defaults.get(key) + field: dict[str, Any] = { + "key": key, + "label": (labels or {}).get(key, key), + "type": typ, + "default": _stringify(default, typ), + "description": (descriptions or {}).get(key, ""), + "secret": _is_secret(key), + } + if typ == "enum": + field["options"] = (options or {}).get(key) or _enum_options(annotation) + if typ == "text": + field["item_type"] = _text_item_type(annotation) + schema_fields.append(field) + + schema = {"fields": schema_fields} + + def _getter() -> dict[str, Any]: + values: dict[str, Any] = {} + for field in schema_fields: + key = field["key"] + try: + raw = getattr(config_instance, key) + except Exception: # noqa: BLE001 + raw = defaults.get(key) + values[key] = _stringify(raw, field["type"]) + if getter_extra: + values.update(getter_extra(config_instance)) + return values + + def _apply(values: dict[str, Any]) -> None: + for field in schema_fields: + key = field["key"] + if key not in values: + continue + coerced = _coerce_value(values[key], field["type"], field.get("item_type", "str")) + try: + setattr(config_instance, key, coerced) + except Exception: # noqa: BLE001 + pass + if apply_extra: + apply_extra(values, config_instance) + + register_plugin_config( + plugin_id, + schema, + apply=_apply, + getter=_getter, + ) + +def register_config_items( + plugin_id: str, + items: list[dict[str, Any]], + store: Optional[Any] = None, + apply_extra: Optional[Callable[[dict[str, Any], Any], None]] = None, + getter_extra: Optional[Callable[[Any], dict[str, Any]]] = None, +) -> None: + """注册「来源无关」的任意配置项(schema + getter/setter),供 Web 读/改。 + + 与 register_model_config 的区别:这里每个配置项可以来自任意来源: + - 模块常量(module attr) + - pydantic Config(字段) + - 配置文件(dict / JSON / YAML) + - 数据库/运行态状态 + + Args: + plugin_id: NoneBot 插件模块名。 + items: 配置项列表,每个 dict 需含 key/label/type,可选: + default/description/secret/options/item_type/env,以及 getter/setter。 + 若某 item 未提供 getter/setter,则读写 store: + - store 是 dict -> store[key] + - store 是 ModuleType -> getattr/setattr(store, key) + store: 缺省 getter/setter 时的回退存储(dict 或模块)。 + apply_extra: 保存后用额外回调做持久化/热加载等。 + getter_extra: getter 额外返回的非 items 值。 + """ + from types import ModuleType + + def _item_getter(item: dict[str, Any]) -> Any: + getter = item.get("getter") + if getter is not None: + try: + return getter() + except Exception: # noqa: BLE001 + return item.get("default") + if store is not None: + if isinstance(store, dict): + return store.get(item["key"], item.get("default")) + if isinstance(store, ModuleType): + try: + return getattr(store, item["key"]) + except AttributeError: + return item.get("default") + return item.get("default") + + def _item_setter(item: dict[str, Any], value: Any) -> None: + setter = item.get("setter") + if setter is not None: + try: + setter(value) + except Exception: # noqa: BLE001 + pass + return + if store is not None: + if isinstance(store, dict): + store[item["key"]] = value + elif isinstance(store, ModuleType): + try: + setattr(store, item["key"], value) + except Exception: # noqa: BLE001 + pass + + schema_fields: list[dict[str, Any]] = [] + for item in items: + field: dict[str, Any] = { + "key": item["key"], + "label": item.get("label", item["key"]), + "type": item.get("type", "string"), + "default": _stringify(item.get("default"), item.get("type", "string")), + "description": item.get("description", ""), + "secret": item.get("secret", _is_secret(item["key"])), + } + if item.get("options"): + field["options"] = item["options"] + if item.get("type") == "text": + field["item_type"] = item.get("item_type", "str") + if item.get("type") == "object_set" and item.get("item_schema"): + field["item_schema"] = item["item_schema"] + if item.get("key_field"): + field["key_field"] = item["key_field"] + if item.get("nosave"): + # 文件/外部源配置:值不写进 plugin_config.json(避免与命令修改互相覆盖为陈旧值), + # 但仍调用 apply(写入外部源)。 + field["nosave"] = True + schema_fields.append(field) + + schema = {"fields": schema_fields} + + def _getter() -> dict[str, Any]: + values: dict[str, Any] = {} + for item in items: + raw = _item_getter(item) + values[item["key"]] = _stringify(raw, item.get("type", "string")) + if getter_extra: + values.update(getter_extra(store) if store is not None else getter_extra()) + return values + + def _apply(values: dict[str, Any]) -> None: + for item in items: + key = item["key"] + if key not in values: + continue + typ = item.get("type", "string") + coerced = _coerce_value(values[key], typ, item.get("item_type", "str")) + _item_setter(item, coerced) + if apply_extra: + apply_extra(values, store) + + register_plugin_config( + plugin_id, + schema, + apply=_apply, + getter=_getter, + ) + + +def register_object_set( + plugin_id: str, + set_key: str, + item_schema_fields: list[dict[str, Any]], + key_field: str, + getter: Callable[[], list[dict[str, Any]]], + setter: Callable[[list[dict[str, Any]]], None], + *, + label: Optional[str] = None, + description: str = "", + nosave: bool = False, + options_by_key: Optional[dict[str, list[dict[str, str]]]] = None, +) -> None: + """注册一个「通用对象集」配置项(type=object_set)。 + + 适用场景:插件要暴露一组结构化条目(如群分组、测速站点、服务器列表、 + 白/黑名单成员等),Web 端用通用表格渲染,支持增删改。 + + Args: + plugin_id: NoneBot 插件模块名。 + set_key: 该对象集的配置 key。 + item_schema_fields: 子字段 schema(同标准字段;不必含 key),每条含 + key/label/type/default/options/item_type/secret 等。 + key_field: 子字段主键名(用于定位唯一行/去重)。 + getter: () -> list[dict] 取当前对象集。 + setter: (list[dict]) -> None 持久化整个对象集(应自行校验/写回来源)。 + label/description: Web 显示。 + nosave: True 时不写入 plugin_config.json(权威源在插件自身,如文件/DB)。 + options_by_key: 按子字段 key 覆盖 enum options。 + """ + sub_fields: list[dict[str, Any]] = [] + for sf in item_schema_fields: + field: dict[str, Any] = { + "key": sf["key"], + "label": sf.get("label", sf["key"]), + "type": sf.get("type", "string"), + "default": sf.get("default"), + "description": sf.get("description", ""), + "secret": sf.get("secret", _is_secret(sf["key"])), + } + if sf.get("type") == "text": + field["item_type"] = sf.get("item_type", "str") + opts = (options_by_key or {}).get(sf["key"]) or sf.get("options") + if opts: + field["options"] = opts + sub_fields.append(field) + + def _coerce_setter(rows: list[dict[str, Any]]) -> None: + """按 item_schema 把每行子字段转成目标类型,并按 key_field 去重后交给 setter。""" + if not isinstance(rows, list): + rows = [] + coerced: list[dict[str, Any]] = [] + seen: set[Any] = set() + for row in rows: + if not isinstance(row, dict): + continue + nrow: dict[str, Any] = {} + for sf in item_schema_fields: + key = sf["key"] + if key not in row: + if "default" in sf and key not in nrow: + nrow[key] = _coerce_value(sf["default"], sf.get("type", "string"), sf.get("item_type", "str")) + continue + nrow[key] = _coerce_value( + row[key], sf.get("type", "string"), sf.get("item_type", "str") + ) + key_val = nrow.get(key_field) + if key_val is None or key_val == "": + continue # 缺主键的行丢弃 + if key_val in seen: + continue # 主键重复只保留首个 + seen.add(key_val) + coerced.append(nrow) + setter(coerced) + + register_config_items( + plugin_id, + [ + { + "key": set_key, + "label": label or set_key, + "type": "object_set", + "item_schema": {"fields": sub_fields}, + "key_field": key_field, + "description": description, + "getter": getter, + "setter": _coerce_setter, + "nosave": nosave, + } + ], + ) diff --git a/hexi/plugins/__init__.py b/hexi/plugins/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hexi/plugins/memes_ops/__init__.py b/hexi/plugins/memes_ops/__init__.py new file mode 100644 index 0000000..ea67ebc --- /dev/null +++ b/hexi/plugins/memes_ops/__init__.py @@ -0,0 +1,125 @@ +""" +表情裸词操作 + +nonebot-plugin-memes 0.5+ 改用 Alconna 后,表情选项只能用 `-右`/`--right` 形式 +(0.4.x 旧版是 `对称 /右`)。本插件为表情作者声明的短别名(左/右/上/下/前/后/圆/爷) +追加裸词形式,恢复 `表情 操作词` 的用法,如: + + 对称 右 / 鬼畜 下 / 循环 上 / 摸 圆 / 小丑 爷 / 小丑面具 前 / ba说 左 + +实现方式:patch `nonebot_plugin_memes.matchers.command` 的 `build_option` +(追加裸词别名)和 `on_alconna`(重建的 matcher 用 priority=11 + block 抢占原 +priority=12 的 matcher),然后为受影响的表情重建 matcher。 + +注意:本补丁针对 nonebot-plugin-memes 0.8.1 的内部结构编写;插件大版本更新后 +若内部改名导致补丁失败,会记日志并自动跳过,原插件按默认方式工作(退回 `-右` 语法)。 +""" + +from nonebot import require + +require("nonebot_plugin_memes") + +from importlib.metadata import PackageNotFoundError, version + +from nonebot import logger +from nonebot.plugin import PluginMetadata + +from meme_generator import BooleanOption, FloatOption, IntegerOption +from nonebot_plugin_alconna import Args, Option, store_false, store_true +from nonebot_plugin_memes.manager import meme_manager +from nonebot_plugin_memes.matchers import command as memes_command + +__plugin_meta__ = PluginMetadata( + name="表情裸词操作", + description="恢复“表情 操作词”的裸词用法(对称 右、摸 圆、小丑 爷 等)", + usage="对称 右 / 鬼畜 下 / 摸 圆 / 小丑 爷 / 小丑面具 前", +) + +try: + _memes_version = version("nonebot-plugin-memes") +except PackageNotFoundError: + _memes_version = "?" +if _memes_version != "0.8.1": + logger.warning( + f"表情裸词操作:当前 nonebot-plugin-memes 版本为 {_memes_version}," + "本补丁按 0.8.1 编写,若下方出现补丁失败日志请检查兼容性" + ) + +# 幂等:热重载本插件时不重复打补丁 +if getattr(memes_command.build_option, "_memes_ops_patched", False): + logger.info("表情裸词操作:补丁已应用过,跳过") +else: + try: + _original_build_option = memes_command.build_option + _original_on_alconna = memes_command.on_alconna + + def _build_option(option): + """原版 build_option,并在选项名中追加作者声明的裸词短别名(如 `右`)。""" + declared_short_aliases = list(option.parser_flags.short_aliases) + names: list[str] = [] + parser_flags = option.parser_flags + short_aliases = parser_flags.short_aliases + if parser_flags.short: + short_aliases.insert(0, option.name[0]) + long_aliases = parser_flags.long_aliases + if parser_flags.long: + long_aliases.insert(0, option.name) + names.extend([f"-{flag}" for flag in short_aliases]) + names.extend([f"--{flag}" for flag in long_aliases]) + names.extend(declared_short_aliases) + if isinstance(option, BooleanOption): + action = None + if option.default is not None: + action = store_false if option.default else store_true + return Option( + name="|".join(names), + dest=option.name, + default=option.default, + action=action, + help_text=option.description, + ) + args = Args() + if isinstance(option, IntegerOption): + arg_type = int + elif isinstance(option, FloatOption): + arg_type = float + else: + arg_type = str + args.add(name=option.name, value=arg_type) + return Option( + name="|".join(names), + args=args, + dest=option.name, + help_text=option.description, + ) + + def _on_alconna(command, *args, **kwargs): + """重建的 matcher 提高优先级并 block,抢占原 priority=12 的 matcher。""" + kwargs["priority"] = 11 + kwargs["block"] = True + return _original_on_alconna(command, *args, **kwargs) + + memes_command.build_option = _build_option + memes_command.on_alconna = _on_alconna + _build_option._memes_ops_patched = True # noqa: B010 + + patched: list[str] = [] + for meme in meme_manager.get_memes(): + aliases = [ + flag + for option in meme.info.params.options + for flag in option.parser_flags.short_aliases + ] + if aliases: + memes_command.create_matcher(meme) + patched.append(f"{meme.key}({','.join(aliases)})") + logger.info(f"表情裸词操作:已为 {len(patched)} 个表情启用裸词操作: {patched}") + + except Exception: + # 版本不兼容时优雅降级,恢复原函数,不影响原插件 + memes_command.build_option = _original_build_option # type: ignore[possibly-undefined] + memes_command.on_alconna = _original_on_alconna # type: ignore[possibly-undefined] + logger.exception( + "表情裸词操作:补丁应用失败(可能与 nonebot-plugin-memes 版本不兼容)," + "已恢复原状,表情仍按 `-右` 形式使用" + ) diff --git a/hexi/plugins/nonebot_plugin_bf_bot/__init__.py b/hexi/plugins/nonebot_plugin_bf_bot/__init__.py new file mode 100644 index 0000000..be67d69 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/__init__.py @@ -0,0 +1,273 @@ +from nonebot import on_command, require +from nonebot.adapters import Message, Event, Bot +from nonebot.log import logger +from nonebot.matcher import Matcher +from nonebot.params import CommandArg +from nonebot.plugin import PluginMetadata +from nonebot.rule import to_me +import time +from .user_data.data_utils import UserManager + +require("nonebot_plugin_alconna") +from nonebot_plugin_alconna import UniMessage +from .data import * +from .data_utils import * +from .image_builder import * +from .text_utils import * + +__plugin_meta__ = PluginMetadata( + name="BF查询", + description="战地3,4,1,5,2042,6", + usage=""" + bf3: /bf3 EAID (查询BF3数据) + bf4: /bf4 EAID (查询BF4数据) + bf1: /bf1 EAID (查询BF5数据) + bfv: /bfv EAID (查询BF6数据) + bf2042: /bf2042 EAID (查询BF2042数据) + bf6: /bf6 EAID (查询BF6数据) + 绑定: /绑定 EAID (绑定你的QQ与EAID) + 解绑: /解绑 (解除你的QQ与当前绑定的EAID) + 修改绑定: /修改绑定 EAID (修改你的QQ与当前绑定的EAID) + """.strip(), + extra={ + + }, +) + +query = on_command("bft", rule=to_me(), aliases={"bf3", "bf4", "bfv", "bf1", "bf2042", "bf6"}, block=True) +bind = on_command("bfbind", rule=to_me(), aliases={"绑定"}, block=True) +unbind = on_command("unbind", rule=to_me(), aliases={"解绑"}, block=True) +update_bind = on_command("update_bind", rule=to_me(), aliases={"修改绑定"}, block=True) + +bf_dict = { + "bf3": "战地3", + "bf4": "战地4", + "bf1": "战地1", + "bfv": "战地5", + "bf2042": "战地2042", + "bf6": "战地6", +} + + +@query.handle() +async def handle_function(event: Event, matcher: Matcher, msg: Message = CommandArg()): + start_time = time.time() + usermanager = UserManager() + cmd = matcher.state["_prefix"]["command"][0] + game = cmd + input_text = msg.extract_plain_text().strip() + logger.info(f"{type(input_text)}, {repr(input_text)}") + if input_text is None or input_text == "": + content = usermanager.get_user_by_qq(event.get_user_id()) + if not content: + await UniMessage.at(user_id=event.get_user_id()).text( + "未检测到id,也未检测到绑定记录,请使用 绑定 EAID 进行绑定操作").send() + return + player_id = content['ea_player_id'] + user_id = content['ea_user_id'] + player = content['ea_player_name'] + platform = "pc" + else: + content = await get_player_info_by_name(input_text, "pc") + if 'errors' in content: + await UniMessage.at(user_id=event.get_user_id()).text("未找到玩家,请检查是否拼写正确").send() + return + player_id = content['personaId'] + user_id = content['userId'] + player = content.get('personaName') or content.get('displayName') or content.get('username', 'error') + if 'errors' in player: + await UniMessage.text(f"请检查id是否正确!").send() + return + platform = "pc" + await UniMessage.text(f"正在查询 {player} 的 {bf_dict[cmd]} 数据,请耐心等待").send() + play_stat = "" + try: + if cmd == "bf3": + play_stat = await get_data_bf3(player, player_id, user_id, platform) + elif cmd == "bf4": + play_stat = await get_data_bf4(player, player_id, user_id, platform) + elif cmd == "bf1": + play_stat = await get_data_bf1(player, player_id, user_id, platform) + elif cmd == "bfv": + play_stat = await get_data_bfv(player, player_id, user_id, platform) + elif cmd == "bf2042": + await UniMessage.at(event.get_user_id()).text("正在开发中,敬请期待!").send() + elif cmd == "bf6": + play_stat, rank = await asyncio.gather( + get_data_bf6(player, player_id, user_id, platform), + get_bf6_rank(player) + ) + logger.info(f"等级:{rank}") + else: + await UniMessage.at(event.get_user_id()).text("指令异常").send() + return + if "errors" in play_stat: + logger.warning(play_stat['errors'][0]) + msg = play_stat['errors'][0] + await UniMessage.text(f"{msg}").send() + return + else: + # logger.info(f"结果{play_stat}") + # player = play_stat['userName'] + weapon, vehicle = await get_best_weapon_and_best_vehicle(play_stat) + pid = play_stat['userId'] + kd = play_stat['killDeath'] + kpm = play_stat['killsPerMinute'] + acc = play_stat['accuracy'] + # 战地3 特化 + if cmd == 'bf3': + head_shots = play_stat['headShots'] + else: + head_shots = play_stat['headshots'] + time_play = convert_to_hours(play_stat['timePlayed']) + logger.info(f"游玩时长监测:{time_play}") + if time_play == 0: + await UniMessage.at(event.get_user_id()).text("查询接口异常,请等待一段时间后查询").send() + return + kills = int(play_stat['kills']) + kill_assists = int(play_stat['killAssists']) + revives = int(play_stat['revives']) + wins = int(play_stat['wins']) + loses = int(play_stat['loses']) + best_weapon = weapon + best_vehicle = vehicle + best_class = play_stat['bestClass'] + destroyed = await get_vehicle_destroyed(play_stat["vehicles"]) + if cmd == 'bf6': + best_class = await get_best_classes(play_stat) + captured = play_stat['objective']['captured'] + score = sum(item.get("score", 0) for item in play_stat['classes']) + # 计算4兵种游玩时长 + seconds = sum(item.get("secondsPlayed", 0) for item in play_stat['classes']) + kpm = round(kills / (int(seconds) / 60), 2) + logger.info(f"击杀数:{kills},游玩分钟数:{seconds / 60},计算kpm值:{kpm}") + spm = int(score / (int(seconds) / 60)) + logger.info(f"计算spm值:{spm}") + repairs = play_stat['repairs'] + img = await build_bf6_stats_card(game='bf6', + qq_id=event.get_user_id(), + player=player, + pid=pid, + rank=rank, + kd=kd, + kpm=kpm, + spm=spm, + acc=acc, + head_shots=head_shots, + time_play=time_play, + kills=kills, + kill_assists=kill_assists, + revives=revives, + repairs=repairs, + captured=captured, + score=score, + wins=wins, + loses=loses, + destroyed=destroyed, + best_weapon=best_weapon, + best_vehicle=best_vehicle, + best_class=best_class) + else: + spm = play_stat['scorePerMinute'] + rank = play_stat['rank'] + longest_head_shot = play_stat['longestHeadShot'] + highest_ill_streak = play_stat['highestKillStreak'] + stat_data, level_designation = await stats_calculator(play_stat, cmd) + img = await build_stats_card(game, player, pid, kd, kpm, spm, acc, head_shots, rank, time_play, kills, + kill_assists, revives, wins, loses, destroyed, best_weapon, best_vehicle, + best_class, + longest_head_shot, highest_ill_streak, stat_data, level_designation) + end_time = time.time() + duration = round(end_time - start_time, 3) + await UniMessage.image(raw=img.getvalue()).at(user_id=event.get_user_id()).text( + f"本次查询耗时:{duration}s").send() + except Exception as e: + logger.exception(f"异常:{e}") + + +@bind.handle() +async def bind_user(event: Event, matcher: Matcher, msg: Message = CommandArg()): + user_manager = UserManager() + player_name = msg.extract_plain_text() + qq_id = event.get_user_id() + + # 执行已有数据查询操作 + user_record = user_manager.get_user_by_qq(qq_id) + if user_record: + user_info = await get_player_info_by_ea_id(user_record['ea_player_id'], user_record['ea_user_id'], 'pc') + await (UniMessage.at(user_id=event.get_user_id()) + .text(f"您已经将账号绑定到: {user_info['personaName']},如果你需要更改绑定请发送 修改绑定 EAID ").send()) + return + else: + user_info_json = await get_player_info_by_name(player_name, "pc") + if 'errors' in user_info_json: + await UniMessage.at(user_id=event.get_user_id()).text("未找到玩家,请检查是否拼写正确").send() + player_id = user_info_json['personaId'] + user_id = user_info_json['userId'] + player_name = user_info_json.get('personaName') or user_info_json.get('displayName') or user_info_json.get( + 'username', 'error') + avatar_url = user_info_json['avatar'] + logger.info(f"QQ号:{qq_id},EA双ID:{player_id}-{user_id}") + + # 检测ea账号 是否被绑定至其他qq + bind_record = user_manager.get_user_by_ea_id(user_id) + if bind_record: + await (UniMessage.at(user_id=event.get_user_id()) + .text( + f"您的EA账号 {bind_record['ea_player_name']} 已经绑定到: {bind_record['qq_id']},请您确认绑定的EAID").send()) + return + else: + # 执行绑定操作 + record = user_manager.add_user(qq_id, player_name, player_id, user_id, "[]", "[]") + logger.info(f"插入数据返回结果:{record}") + if record > 0: + await UniMessage.at(user_id=event.get_user_id()).text(f"您已经成功绑定至: {player_name}").send() + + +@unbind.handle() +async def bind_user(event: Event, matcher: Matcher, msg: Message = CommandArg()): + user_manager = UserManager() + qq_id = event.get_user_id() + + # 执行已有数据查询操作 + user_record = user_manager.get_user_by_qq(qq_id) + if user_record: + user_info = await get_player_info_by_ea_id(user_record['ea_player_id'], user_record['ea_user_id'], 'pc') + rows = user_manager.delete_user_by_qq(qq_id) + if rows > 0: + await (UniMessage.at(user_id=event.get_user_id()) + .text( + f"您已经与: {user_info['personaName']} 成功解除绑定,如果你需要重新绑定请发送 修改绑定 EAID ").send()) + return + else: + await UniMessage.at(user_id=event.get_user_id()).text(f"未查询到绑定记录").send() + + +@update_bind.handle() +async def bind_user(event: Event, matcher: Matcher, msg: Message = CommandArg()): + user_manager = UserManager() + player_name = msg.extract_plain_text() + qq_id = event.get_user_id() + + # 执行已有数据查询操作 + user_record = user_manager.get_user_by_qq(qq_id) + if user_record: + user_info_json = await get_player_info_by_name(player_name, "pc") + if 'errors' in user_info_json: + await UniMessage.at(user_id=event.get_user_id()).text("未找到玩家,请检查是否拼写正确").send() + player_id = user_info_json['personaId'] + user_id = user_info_json['userId'] + player_name = user_info_json.get('personaName') or user_info_json.get('displayName') or user_info_json.get( + 'username', 'error') + avatar_url = user_info_json['avatar'] + logger.info(f"QQ号:{qq_id},EA双ID:{player_id}-{user_id}") + + # 执行修改绑定操作 + record = user_manager.update_user(qq_id, player_name, player_id, user_id, "[]", "[]") + logger.info(f"修改数据返回结果:{record}") + if record > 0 and record == 1: + await UniMessage.at(user_id=event.get_user_id()).text( + f"您已经成功从:{user_record['ea_player_name']}修改绑定至: {player_name}").send() + else: + await UniMessage.at(user_id=event.get_user_id()).text( + f"未查询到绑定记录: {player_name},如果需要绑定,请@机器人并发送 绑定 {player_name} ").send() diff --git a/hexi/plugins/nonebot_plugin_bf_bot/bf6_data.py b/hexi/plugins/nonebot_plugin_bf_bot/bf6_data.py new file mode 100644 index 0000000..a0b94d7 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/bf6_data.py @@ -0,0 +1,137 @@ +import asyncio +import os +import random +from pathlib import Path +from typing import List, Dict, Optional + +from curl_cffi import AsyncSession, CurlError +from nonebot import logger + +# ---------- 配置 ---------- +file_path = os.path.dirname(__file__).replace("\\", "/") +exported_cookie_path = Path(f"{file_path}/cookies/tracker.txt") # 你导出的 cookies.txt +CUSTOM_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36" + +RAW_BROWSER_HEADERS = """ +sec-ch-ua-platform: "Windows" +sec-ch-ua: "Google Chrome";v="141", "Not?A_Brand";v="8", "Chromium";v="141" +sec-ch-ua-mobile: ?0 +user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 +""" + +# ====================== + + +def parse_raw_headers(raw: str) -> Dict[str, str]: + headers = {} + skip_prefix = (":authority", ":method", ":path", ":scheme") + for line in raw.strip().splitlines(): + if not line.strip(): + continue + if any(line.lower().startswith(p) for p in skip_prefix): + continue + if ":" not in line: + continue + key, value = line.split(":", 1) + headers[key.strip()] = value.strip() + return headers + + +def load_cookies_from_txt(path: Path) -> List[Dict[str, str]]: + cookies = [] + if not path.exists(): + return cookies + with path.open("r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line or line.startswith("#"): + continue + parts = line.split("\t") + if len(parts) >= 7: + cookies.append({"name": parts[5], "value": parts[6]}) + elif "=" in line: + k, v = line.split("=", 1) + cookies.append({"name": k.strip(), "value": v.strip()}) + return cookies + + +def build_cookie_header(cookies: List[Dict[str, str]]) -> str: + return "; ".join(f"{c['name']}={c['value']}" for c in cookies) + + +def build_headers( + raw_headers: str, + cookies: Optional[List[Dict[str, str]]] = None, + ua_override: Optional[str] = None, +) -> Dict[str, str]: + headers = parse_raw_headers(raw_headers) + + # 强制改成 XHR 请求风格 + headers.update({ + "accept": "application/json, text/plain, */*", + "origin": "https://tracker.gg", + "referer": "https://tracker.gg/", + "sec-fetch-mode": "cors", + "sec-fetch-site": "same-site", + }) + + if cookies: + headers["cookie"] = build_cookie_header(cookies) + if ua_override: + headers["user-agent"] = ua_override + return headers + + +async def fetch_with_cookies(url: str, headers: dict, impersonate: str = "chrome110", timeout: int = 15): + async with AsyncSession() as session: + try: + await asyncio.sleep(random.uniform(0.5, 1.2)) # 模拟浏览器请求间隔 + response = await session.get(url, headers=headers, impersonate=impersonate, timeout=timeout) + + # 重试一次,防止偶尔 CF 拦截 + if getattr(response, "status_code", 0) in (403, 429): + await asyncio.sleep(2) + response = await session.get(url, headers=headers, impersonate=impersonate, timeout=timeout) + + return response + except CurlError as e: + return {"error": f"cURL 错误: {e}"} + except Exception as e: + return {"error": f"未知错误: {e}"} + + +def is_challenge_response(resp) -> bool: + if isinstance(resp, dict) and "error" in resp: + return True + try: + status = getattr(resp, "status_code", None) + text = getattr(resp, "text", "") or "" + if status in (429, 403): + return True + low = text.lower() + if any(k in low for k in ["cloudflare", "captcha", "cf-challenge", "just a moment"]): + return True + except Exception: + return True + return False + + +async def search_user_with_fallback(url: str): + # cookies.txt + cookies = load_cookies_from_txt(exported_cookie_path) + + headers = build_headers(RAW_BROWSER_HEADERS, cookies=cookies, ua_override=CUSTOM_UA) + logger.info(f"请求 URL: {url}") + logger.info(f"使用 headers 字段数: {len(headers)}") + + resp = await fetch_with_cookies(url, headers) + if is_challenge_response(resp): + logger.warning("Cloudflare 拦截或 cookies 失效。") + if isinstance(resp, dict): + return resp + return {"status": getattr(resp, "status_code", None), "preview": getattr(resp, "text", "")[:200]} + else: + logger.info("请求成功。") + return getattr(resp, "json", lambda: resp)() if hasattr(resp, "json") else resp + + diff --git a/hexi/plugins/nonebot_plugin_bf_bot/data.py b/hexi/plugins/nonebot_plugin_bf_bot/data.py new file mode 100644 index 0000000..6d8a9e7 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/data.py @@ -0,0 +1,284 @@ +import httpx +import re +from typing import Any, Dict, Optional +from .get_bf6_data import * +from .tracker_data import * + + +async def get_data_bf3(player, player_id, user_id, platform): + url = f"https://api.gametools.network/bf3/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us" + url = f"https://api.gametools.network/bf3/all/?format_values=true&name={player}&platform={platform}&skip_battlelog=false&lang=en-us" + async with httpx.AsyncClient(timeout=10.0) as client: + # 创建两个并发任务 + task_id = asyncio.create_task(client.get(url_by_id)) + task_name = asyncio.create_task(client.get(url_by_name)) + + # 等待第一个完成的任务 + done, pending = await asyncio.wait( + [task_id, task_name], + return_when=asyncio.FIRST_COMPLETED + ) + # 取消未完成的任务 + for task in pending: + task.cancel() + # 检查已完成的任务是否成功且无 errors + for task in done: + try: + response = await task + if response.status_code == 200: + data = response.json() + if 'errors' not in data: + logger.info(f"成功获取数据({'ID' if task is task_id else 'Name'}方式)") + return data + except (httpx.RequestError, ValueError) as e: + logger.warning(f"请求或解析失败: {e}") + if pending: + pass + # 如果所有尝试都失败,返回错误 + return {"errors": ["未找到玩家"]} + + +async def get_data_bf4(player, player_id, user_id, platform): + url_by_id = f"https://api.gametools.network/bf4/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us" + url_by_name = f"https://api.gametools.network/bf4/all/?format_values=true&name={player}&platform={platform}&skip_battlelog=false&lang=en-us" + async with httpx.AsyncClient(timeout=10.0) as client: + # 创建两个并发任务 + task_id = asyncio.create_task(client.get(url_by_id)) + task_name = asyncio.create_task(client.get(url_by_name)) + + # 等待第一个完成的任务 + done, pending = await asyncio.wait( + [task_id, task_name], + return_when=asyncio.FIRST_COMPLETED + ) + # 取消未完成的任务 + for task in pending: + task.cancel() + # 检查已完成的任务是否成功且无 errors + for task in done: + try: + response = await task + if response.status_code == 200: + data = response.json() + if 'errors' not in data: + logger.info(f"成功获取数据({'ID' if task is task_id else 'Name'}方式)") + return data + except (httpx.RequestError, ValueError) as e: + logger.warning(f"请求或解析失败: {e}") + if pending: + pass + # 如果所有尝试都失败,返回错误 + return {"errors": ["未找到玩家"]} + + +async def get_data_bf1(player, player_id, user_id, platform): + url_by_id = f"https://api.gametools.network/bf1/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us" + url_by_name = f"https://api.gametools.network/bf1/all/?format_values=true&name={player}&platform={platform}&skip_battlelog=false&lang=en-us" + async with httpx.AsyncClient(timeout=10.0) as client: + # 创建两个并发任务 + task_id = asyncio.create_task(client.get(url_by_id)) + task_name = asyncio.create_task(client.get(url_by_name)) + + # 等待第一个完成的任务 + done, pending = await asyncio.wait( + [task_id, task_name], + return_when=asyncio.FIRST_COMPLETED + ) + # 取消未完成的任务 + for task in pending: + task.cancel() + # 检查已完成的任务是否成功且无 errors + for task in done: + try: + response = await task + if response.status_code == 200: + data = response.json() + if 'errors' not in data: + logger.info(f"成功获取数据({'ID' if task is task_id else 'Name'}方式)") + return data + except (httpx.RequestError, ValueError) as e: + logger.warning(f"请求或解析失败: {e}") + if pending: + pass + # 如果所有尝试都失败,返回错误 + return {"errors": ["未找到玩家"]} + + +async def get_data_bfv(player, player_id, user_id, platform): + url_by_id = f"https://api.gametools.network/bfv/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us" + url_by_name = f"https://api.gametools.network/bfv/all/?format_values=true&name={player}&platform={platform}&skip_battlelog=false&lang=en-us" + + async with httpx.AsyncClient(timeout=10.0) as client: + # 创建两个并发任务 + task_id = asyncio.create_task(client.get(url_by_id)) + task_name = asyncio.create_task(client.get(url_by_name)) + + # 等待第一个完成的任务 + done, pending = await asyncio.wait( + [task_id, task_name], + return_when=asyncio.FIRST_COMPLETED + ) + # 取消未完成的任务 + for task in pending: + task.cancel() + # 检查已完成的任务是否成功且无 errors + for task in done: + try: + response = await task + if response.status_code == 200: + data = response.json() + if 'errors' not in data: + logger.info(f"成功获取数据({'ID' if task is task_id else 'Name'}方式)") + return data + except (httpx.RequestError, ValueError) as e: + logger.warning(f"请求或解析失败: {e}") + if pending: + pass + # 如果所有尝试都失败,返回错误 + return {"errors": ["未找到玩家"]} + + +async def get_data_bf6(player_name, player_id, user_id, platform): + # 构造两个 URL + url_by_id = f"https://api.gametools.network/bf6/all/?format_values=true&playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false&lang=en-us" + url_by_name = f"https://api.gametools.network/bf6/all/?format_values=true&name={player_name}&platform={platform}&skip_battlelog=false&lang=en-us" + + async with httpx.AsyncClient(timeout=10.0) as client: + # 创建两个并发任务 + task_id = asyncio.create_task(client.get(url_by_id)) + task_name = asyncio.create_task(client.get(url_by_name)) + + # 等待第一个完成的任务 + done, pending = await asyncio.wait( + [task_id, task_name], + return_when=asyncio.FIRST_COMPLETED + ) + # 取消未完成的任务 + for task in pending: + task.cancel() + # 检查已完成的任务是否成功且无 errors + for task in done: + try: + response = await task + if response.status_code == 200: + data = response.json() + if 'errors' not in data: + logger.info(f"成功获取数据({'ID' if task is task_id else 'Name'}方式)") + return data + except (httpx.RequestError, ValueError) as e: + logger.warning(f"请求或解析失败: {e}") + if pending: + pass + # 如果所有尝试都失败,返回错误 + return {"errors": ["未找到玩家"]} + + +async def get_player_info_by_name(user_name, platform): + user_info_url = f"https://api.gametools.network/bfglobal/player/?name={user_name}&platform={platform}&skip_battlelog=false" + + payload = {} + headers = { + 'accept': 'application/json' + } + logger.info(f"查询用户请求url:{user_info_url}") + response = requests.request("GET", user_info_url, headers=headers, data=payload) + + user_info_json = json.loads(response.text) + return user_info_json + + +async def get_player_info_by_ea_id(player_id, user_id, platform): + url = f"https://api.gametools.network/bfglobal/player/?playerid={player_id}&oid={user_id}&platform={platform}&skip_battlelog=false" + + payload = {} + headers = { + 'accept': 'application/json' + } + + response = requests.request("GET", url, headers=headers, data=payload) + + user_info_json = json.loads(response.text) + return user_info_json + + +def normalize_name(name: str) -> str: + """统一用户名格式(大小写 + 空格)""" + return (name or "").strip().lower() + + +def extract_rank(status: str) -> int: + """从 status 中提取 Rank 数值""" + if not status: + return 0 + match = re.search(r'Rank\s+(\d+)', status) + return int(match.group(1)) if match else 0 + +async def get_bf6_rank(player,player_id, user_id, platform): + url_by_name = f"https://api.gametools.network/bf6/profile/?name={player}&playerid=1234&nucleus_id=1234&platform=ea&skip_battlelog=true&lang=en-us" + url_by_id = f"https://api.gametools.network/bf6/profile/?name={player}&playerid=1234&nucleus_id=1234&platform=ea&skip_battlelog=true&lang=en-us" + payload = {} + headers = { + 'accept': 'application/json' + } + + response = requests.request("GET", url, headers=headers, data=payload) + result: Dict[str, Any] = response.json().get("playerProfiles") + logger.info(f"Tracker用户信息:{result}") + + if not result or "errors" in result: + logger.warning(f"查询失败或返回错误: {player}") + return 0 + + data = result.get("data") or [] + if not data: + logger.info(f"未搜索到用户: {player}") + return 0 + + norm_player = normalize_name(player) + + # 评分函数(核心策略) + def score(r: Dict[str, Any]) -> int: + if not r or not r.get("status"): + return -1 + + name = normalize_name(r.get("platformUserHandle")) + platform = r.get("platformSlug") + + s = 0 + + # 用户名匹配权重(最高优先级) + if name == norm_player: + s += 100 + elif norm_player in name: + s += 50 + + # 平台权重(次优先级) + if platform == "origin": + s += 20 + + return s + + # 选出最优 candidate + target: Optional[Dict[str, Any]] = max(data, key=score, default=None) + + if not target or score(target) <= 0: + logger.info(f"未匹配到有效用户: {player}") + return 0 + + # 提取信息 + name = target.get("platformUserHandle") + uid = target.get("titleUserId") + status = target.get("status", "") + + rank = extract_rank(status) + + user_info = { + "name": name, + "uid": uid, + "rank": rank, + "platform": target.get("platformSlug"), + } + + logger.info(f"最终匹配用户: {user_info}") + + return rank diff --git a/hexi/plugins/nonebot_plugin_bf_bot/data_utils.py b/hexi/plugins/nonebot_plugin_bf_bot/data_utils.py new file mode 100644 index 0000000..0be661a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/data_utils.py @@ -0,0 +1,151 @@ +import os +from functools import reduce + +from PIL import Image, ImageDraw, ImageFont +from nonebot import logger + +# from img_utils import png_resize +# from param import round_data, interval_table +from .param import round_data, interval_table + +filepath = os.path.dirname(__file__).replace("\\", "/") + + +# async def avatar_cache(avatar_url, player_id): +# if avatar_url: +# try: +# # 添加10s超时判断,如果超时直接使用默认头像 +# res = BytesIO(requests.get(avatar_url, timeout=10).content) +# avatar = Image.open(res).convert('RGBA') +# avatar.save(f'{filepath}/avatar_cache/{player_id}.png', 'PNG') +# return avatar +# except requests.exceptions.RequestException as e: +# logger.warning(f"请求异常:{e}") +# else: +# return None +# +# +# async def get_avatar(avatar_url, player_id): +# img = Image.open(filepath + "/avatar_cache/0.png").convert('RGBA') +# path = filepath + "/avatar_cache/" +# try: +# avatar_list = os.listdir(path) +# if player_id in str(avatar_list): +# logger.info(f"本地已存在{player_id}头像") +# img = Image.open(f"{path}{player_id}.png").convert('RGBA') +# else: +# logger.info(f"未检测到{player_id}头像,缓存至本地") +# out_put = filepath + f"/avatar_cache/{player_id}.png" +# img = await avatar_cache(avatar_url, out_put) +# except Exception as err: +# logger.error(f"获取头像失败:{str(err)}") +# return img + + +async def get_best_weapon_and_best_vehicle(player_stat): + weapon = sorted(player_stat["weapons"], key=lambda k: k['kills'], reverse=True)[0] + vehicle = sorted(player_stat["vehicles"], key=lambda k: k['kills'], reverse=True)[0] + return weapon, vehicle + + +async def get_best_classes(player_stat): + classes_data = player_stat['classes'] + data = [obj for obj in classes_data if obj.get("className") != "All"] + best_classes = max(data, key=lambda x: x["kills"]) + best_classes_name = best_classes["className"] + return best_classes_name + + +async def get_vehicle_destroyed(player_stat): + vehicle = reduce(lambda acc, x: acc + x['destroyed'], player_stat, 0) + return vehicle + + +async def stats_calculator(player_stat, game): + per500_data = round_data[game] + # 场次(无直接数值反馈,采用胜利数+失败数) + match_played = player_stat["wins"] + player_stat["loses"] + + kd = player_stat["killDeath"] + kpm = player_stat["killsPerMinute"] + kill_assists = player_stat["killAssists"] + acc = float(player_stat["accuracy"].replace("%", "")) + if game == "bf3": + headshots = float(0) + else: + headshots = float(player_stat["headshots"].replace("%", "")) + spm = player_stat["scorePerMinute"] + revives = player_stat["revives"] + + # second_play = player_stat["secondsPlayed"] + + apr = kill_assists / match_played + rpr = revives / match_played + + # SPM*秒数/60/场数=场均得分 + # dpr = score_perMinute * (second_play / 60) / match_played + + # 计算比值 + # kd + ratio_kd = round(kd / per500_data["kd"], 2) + # kpm + ratio_kpm = round(kpm / per500_data["kpm"], 2) + # 爆头率 + ratio_hs = round(headshots / 100 / per500_data["hs"], 2) + # 场均救援 + ratio_rpr = round(rpr / per500_data["rpr"], 2) + # 场均助攻 + ratio_apr = round(apr / per500_data["apr"], 2) + # 分钟得分 + ratio_spm = round(spm / per500_data["spm"], 2) + logger.info(f"雷达图数据") + logger.info(f"生涯KD比值:{ratio_kd}") + logger.info(f"生涯Kpm比值:{ratio_kpm}") + logger.info(f"生涯准度比值:{ratio_hs}") + logger.info(f"场均救援比值:{ratio_rpr}") + logger.info(f"场均助攻比值:{ratio_apr}") + logger.info(f"分钟得分比值:{ratio_spm}") + + stat_data = [ratio_kd, ratio_apr, ratio_hs, ratio_spm, ratio_kpm, ratio_rpr] + + # 血腥度 kd*0.5 + kpm *0.4 +hs*0.1 + player_blood = kd * 0.5 + kpm * 0.4 + headshots * 0.1 + ratio_blood = player_blood / per500_data["blood"] + + # 贡献度 场均助攻*0.4 + 场均救援*0.4 + spm*0.2 + player_dedication = rpr * 0.4 + apr * 0.4 + spm * 0.2 + ratio_dedication = player_dedication / per500_data["dedication"] + + # 全能度 血腥度*0.5 + 贡献度*0.5 + player_all_round = player_blood * 0.5 + player_dedication * 0.5 + ratio_all_round = player_all_round / per500_data["all_round"] + + logger.info(f"称号评级数据") + logger.info(f"血腥度:{player_blood} 比值:{ratio_blood}") + logger.info(f"贡献度:{player_dedication} 比值:{ratio_dedication}") + logger.info(f"全能度:{player_all_round} 比值:{ratio_all_round}") + level_designation = get_level_designation(ratio_blood, ratio_dedication, ratio_all_round) + return stat_data, level_designation + + +def get_level_designation(blood, dedication, all_round): + feature_type = "" + final_max = max([blood, dedication, all_round]) + if final_max == blood: + feature_type = "blood" + elif final_max == dedication: + feature_type = "dedication" + elif final_max == all_round: + feature_type = "all_round" + logger.info(f"最高能力:{feature_type}") + logger.info(f"最高能力值:{final_max}") + final_info = get_feature(final_max, feature_type) + return final_info + + +def get_feature(value, feature_type): + """根据输入值和数值类别,返回对应特征值""" + for (low, high), features in interval_table.items(): + if low <= value < high: + return features[feature_type] + raise ValueError(f"数值 {value} 不在任何区间内") diff --git a/hexi/plugins/nonebot_plugin_bf_bot/database_op.py b/hexi/plugins/nonebot_plugin_bf_bot/database_op.py new file mode 100644 index 0000000..a00de79 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/database_op.py @@ -0,0 +1,4 @@ + + +def bind_user(user_info): + user_info[''] diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/MYingHeiPRC-W5.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/MYingHeiPRC-W5.ttf new file mode 100644 index 0000000..b7d5a5e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/MYingHeiPRC-W5.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-Bold.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-Bold.ttf new file mode 100644 index 0000000..3a69ef8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-Bold.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-BoldItalic.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-BoldItalic.ttf new file mode 100644 index 0000000..5d8f781 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-BoldItalic.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-Light.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-Light.ttf new file mode 100644 index 0000000..5166300 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-Light.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-LightItalic.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-LightItalic.ttf new file mode 100644 index 0000000..2ca2c3e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-LightItalic.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-Medium.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-Medium.ttf new file mode 100644 index 0000000..bd863bb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-Medium.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-MediumItalic.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-MediumItalic.ttf new file mode 100644 index 0000000..20e52df Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-MediumItalic.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-SemiBold.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-SemiBold.ttf new file mode 100644 index 0000000..5a5fa2e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-SemiBold.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-SemiBoldItalic.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-SemiBoldItalic.ttf new file mode 100644 index 0000000..23fbbbf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-SemiBoldItalic.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-Thin.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-Thin.ttf new file mode 100644 index 0000000..077aee0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-Thin.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-ThinItalic.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-ThinItalic.ttf new file mode 100644 index 0000000..844bd51 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/Purista-ThinItalic.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/SourceHanSansCN-VF.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/SourceHanSansCN-VF.ttf new file mode 100644 index 0000000..8c6bccb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/SourceHanSansCN-VF.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/bf-sub-headline-bold 等宽数字.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/bf-sub-headline-bold 等宽数字.ttf new file mode 100644 index 0000000..4975599 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/bf-sub-headline-bold 等宽数字.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/bf-sub-headline-bold.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/bf-sub-headline-bold.ttf new file mode 100644 index 0000000..f3d51ee Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/bf-sub-headline-bold.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/演示创黑.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/演示创黑.ttf new file mode 100644 index 0000000..8cacfc4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/演示创黑.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/font/演示创黑FLY.ttf b/hexi/plugins/nonebot_plugin_bf_bot/font/演示创黑FLY.ttf new file mode 100644 index 0000000..9be851a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/font/演示创黑FLY.ttf differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/gametools_bf6.py b/hexi/plugins/nonebot_plugin_bf_bot/gametools_bf6.py new file mode 100644 index 0000000..2218110 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/gametools_bf6.py @@ -0,0 +1,67 @@ +import json + +import requests + + +async def get_data_bf6(player_id, user_id, platform): + url = "https://api.gametools.network/bf6/multiple/?raw=false&format_values=true" + payload = json.dumps([ + { + "player_id": player_id, + "user_id": user_id, + "platform": platform + } + ]) + + headers = { + 'accept': 'application/json', + 'Content-Type': 'application/json' + } + + response = requests.request("POST", url, headers=headers, data=payload) + info = json.loads(response.text) + return info + + +async def get_data_user(user_name, platform): + url = f"https://api.gametools.network/bfglobal/player/?name={user_name}&platform={platform}&skip_battlelog=false" + + payload = {} + headers = { + 'accept': 'application/json' + } + + response = requests.request("GET", url, headers=headers, data=payload) + data_json = json.loads(response.text) + + player_id = data_json["personaId"] + user_id = data_json["userId"] + platform = data_json["platform"] + if 'personaName' in data_json: + user_name = data_json["personaName"] + elif 'displayName' in data_json: + user_name = data_json["displayName"] + elif 'username' in data_json: + user_name = data_json["username"] + else: + data_json = 'errors' + + if "errors" in data_json: + return False, data_json + + user_info = { + "player_id": player_id, + "user_id": user_id, + "platform": platform, + "user_name": user_name + } + + return True, user_info + + +async def get_player_game_info(user_name, platform): + flag, user_info = await get_data_user(user_name, platform) + info = await get_data_bf6(user_info['player_id'], user_info['user_id'], user_info['platform']) + info['userName'] = user_name + info_format = json.dumps(info, ensure_ascii=False, indent=2) + print(info_format) diff --git a/hexi/plugins/nonebot_plugin_bf_bot/get_bf6_data.py b/hexi/plugins/nonebot_plugin_bf_bot/get_bf6_data.py new file mode 100644 index 0000000..2d0daee --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/get_bf6_data.py @@ -0,0 +1,271 @@ +from nonebot import logger +import json + +# from bf6_data import * +import requests +from curl_cffi import AsyncSession, CurlError +from nonebot import logger + +from .bf6_data import * + +url_search = "https://api.tracker.gg/api/v2/bf6/standard/search?platform={platform}&query={name}&autocomplete=true" +url_overview = "https://api.tracker.gg/api/v2/bf6/standard/profile/ign/{param}" + + +async def format_data(response, search_type): + status = "" + + platform_info = response['data']['platformInfo'] + segments = response['data']['segments'] + + overview = "" + weapons = [] + vehicles = [] + gamemodes = [] + gadgets = [] + kits = [] + maps = [] + + for segment in segments: + if segment['type'] == 'overview': + overview = segment + elif segment['type'] == 'weapon': + weapons.append(segment) + elif segment['type'] == 'vehicle': + vehicles.append(segment) + elif segment['type'] == 'gamemode': + gamemodes.append(segment) + elif segment['type'] == 'gadget': + gadgets.append(segment) + elif segment['type'] == 'kit': + kits.append(segment) + elif segment['type'] == 'level': + maps.append(segment) + if search_type == 0: + status = await get_overview(platform_info, overview, weapons, vehicles, gamemodes, gadgets, kits, maps) + if search_type == 1: + status = await get_weapons(platform_info, overview, weapons, vehicles, gamemodes, gadgets, kits, maps) + + return status + + +async def get_user_id_2_data(title_id, search_type): + url = url_overview.format(param=title_id) + info = await search_user_with_fallback(url) + info = await format_data(info, search_type) + return info + + +# 调用此方法获取格式化后的数据(调用此方法即可) +async def get_info(player, search_type): + # 先使用橘子搜索 + url = url_search.format(platform="orign", name=player) + result = await search_user_with_fallback(url) + # 无结果再使用steam搜索 + if "errors" in result: + url = url_search.format(platform="steam", name=player) + result = await search_user_with_fallback(url) + title_id_list = [] + logger.info(f"查询结果: \n{json.dumps(result, ensure_ascii=False, indent=2)}") + if "status" in result or "errors" in result: + return 3, '查询异常' + for res in result['data']: + if res['status'] is not None: + name = res['platformUserHandle'] + uid = res['titleUserId'] + status = res['status'].strip().split('•', 1)[0].replace("Rank", "") + user = { + 'name': name, + 'rank': status, + 'uid': uid, + } + title_id_list.append(user) + if len(title_id_list) > 1: + user_list = sorted(title_id_list, key=lambda k: int(k['rank']), reverse=True) + msg = '\n'.join(f'用户名:{info["name"]}-等级:{info["rank"]}-UID:{info["uid"]}' for info in user_list) + logger.info(f"检测到多个同名用户\n{msg}") + return 0, title_id_list + elif len(title_id_list) == 1: + logger.info(f"单用户{title_id_list}") + info = await get_user_id_2_data(title_id_list[0]['uid'], search_type) + logger.info(f"查询结果: {json.dumps(info, ensure_ascii=False, indent=2)}") + return 1, info + else: + logger.info(f"未查询到用户") + return 2, '未查询到用户' + + +async def get_overview(platform_info, overview, weapons, vehicles, gamemodes, gadgets, kits, maps): + top_kill_weapon = sorted(weapons, key=lambda k: k['stats']['kills']['value'], reverse=True)[0] + best_weapon = { + "名称": top_kill_weapon['metadata']['name'], + "击杀": top_kill_weapon['stats']['kills']['value'], + "KPM": top_kill_weapon['stats']['killsPerMinute']['value'], + "时长": top_kill_weapon['stats']['timePlayed']['displayValue'], + "爆头率": top_kill_weapon['stats']['headshotPercentage']['displayValue'], + "命中率": top_kill_weapon['stats']['shotsAccuracy']['displayValue'] + } + top_kill_vehicle = sorted(vehicles, key=lambda k: k['stats']['kills']['value'], reverse=True)[0] + best_vehicle = { + "名称": top_kill_vehicle['metadata']['name'], + "击杀": top_kill_vehicle['stats']['kills']['value'], + "KPM": top_kill_vehicle['stats']['killsPerMinute']['value'], + "时长": top_kill_vehicle['stats']['timePlayed']['displayValue'], + "碾压": top_kill_vehicle['stats']['roadKills']['value'], + "摧毁": top_kill_vehicle['stats']['destroyedWith']['value'], + + } + shot_count = overview['stats']['shotsFired']['value'] + hit_count = overview['stats']['shotsHit']['value'] + logger.info(f"开火数:{shot_count}") + logger.info(f"命中数:{hit_count}") + acc = round((hit_count / shot_count) * 100, 2) + logger.info(f"命中率:{acc}%") + player_info = { + '玩家名称': platform_info['platformUserHandle'], + '游玩平台': platform_info['platformSlug'], + '游戏等级': overview['stats']['careerPlayerRank']['displayValue'], + '游玩时长': overview['stats']['timePlayed']['displayValue'], + '游玩场次': overview['stats']['matchesPlayed']['displayValue'], + '对局胜率': overview['stats']['wlPercentage']['displayValue'], + '对局得分': overview['stats']['score']['displayValue'], + '玩家K/D': overview['stats']['kdRatio']['value'], + '玩家KPM': overview['stats']['killsPerMinute']['value'], + '玩家SPM': overview['stats']['scorePerMinute']['value'], + '真人击杀': overview['stats']['playerKills']['displayValue'], + '击杀总计': overview['stats']['kills']['displayValue'], + '目标占领': overview['stats']['objectivesCaptured']['value'], + '游戏助攻': overview['stats']['assists']['displayValue'], + '救援数量': overview['stats']['revives']['displayValue'], + '最高连杀': overview['stats']['multiKills']['value'], + '命中率': f"{acc}%", + '爆头率': overview['stats']['headshotPercentage']['displayValue'], + '最佳武器': best_weapon, + '最佳载具': best_vehicle, + } + return player_info + + +async def get_weapons(platform_info, overview, weapons, vehicles, gamemodes, gadgets, kits, maps): + top_kill_weapon = sorted(weapons, key=lambda k: k['stats']['kills']['value'], reverse=True)[0] + best_weapon = { + "名称": top_kill_weapon['metadata']['name'], + "击杀": top_kill_weapon['stats']['kills']['value'], + "KPM": top_kill_weapon['stats']['killsPerMinute']['value'], + "时长": top_kill_weapon['stats']['timePlayed']['displayValue'], + "爆头率": top_kill_weapon['stats']['headshotPercentage']['displayValue'], + "命中率": top_kill_weapon['stats']['shotsAccuracy']['displayValue'] + } + top_kill_vehicle = sorted(vehicles, key=lambda k: k['stats']['kills']['value'], reverse=True)[0] + best_vehicle = { + "名称": top_kill_vehicle['metadata']['name'], + "击杀": top_kill_vehicle['stats']['kills']['value'], + "KPM": top_kill_vehicle['stats']['killsPerMinute']['value'], + "时长": top_kill_vehicle['stats']['timePlayed']['displayValue'], + "碾压": top_kill_vehicle['stats']['roadKills']['value'], + "摧毁": top_kill_vehicle['stats']['destroyedWith']['value'], + + } + shot_count = overview['stats']['shotsFired']['value'] + hit_count = overview['stats']['shotsHit']['value'] + logger.info(f"开火数:{shot_count}") + logger.info(f"命中数:{hit_count}") + acc = round((hit_count / shot_count) * 100, 2) + logger.info(f"命中率:{acc}%") + player_info = { + '玩家名称': platform_info['platformUserHandle'], + '游玩平台': platform_info['platformSlug'], + '游戏等级': overview['stats']['careerPlayerRank']['displayValue'], + '游玩时长': overview['stats']['timePlayed']['displayValue'], + '游玩场次': overview['stats']['matchesPlayed']['displayValue'], + '对局胜率': overview['stats']['wlPercentage']['displayValue'], + '对局得分': overview['stats']['score']['displayValue'], + '玩家K/D': overview['stats']['kdRatio']['value'], + '玩家KPM': overview['stats']['killsPerMinute']['value'], + '玩家SPM': overview['stats']['scorePerMinute']['value'], + '真人击杀': overview['stats']['playerKills']['displayValue'], + '击杀总计': overview['stats']['kills']['displayValue'], + '目标占领': overview['stats']['objectivesCaptured']['value'], + '游戏助攻': overview['stats']['assists']['displayValue'], + '救援数量': overview['stats']['revives']['displayValue'], + '最高连杀': overview['stats']['multiKills']['value'], + '命中率': f"{acc}%", + '爆头率': overview['stats']['headshotPercentage']['displayValue'], + '最佳武器': best_weapon, + '最佳载具': best_vehicle, + } + return player_info + + +async def get_vehicles(platform_info, overview, weapons, vehicles, gamemodes, gadgets, kits, maps): + top_kill_weapon = sorted(weapons, key=lambda k: k['stats']['kills']['value'], reverse=True)[0] + best_weapon = { + "名称": top_kill_weapon['metadata']['name'], + "击杀": top_kill_weapon['stats']['kills']['value'], + "KPM": top_kill_weapon['stats']['killsPerMinute']['value'], + "时长": top_kill_weapon['stats']['timePlayed']['displayValue'], + "爆头率": top_kill_weapon['stats']['headshotPercentage']['displayValue'], + "命中率": top_kill_weapon['stats']['shotsAccuracy']['displayValue'] + } + top_kill_vehicle = sorted(vehicles, key=lambda k: k['stats']['kills']['value'], reverse=True)[0] + best_vehicle = { + "名称": top_kill_vehicle['metadata']['name'], + "击杀": top_kill_vehicle['stats']['kills']['value'], + "KPM": top_kill_vehicle['stats']['killsPerMinute']['value'], + "时长": top_kill_vehicle['stats']['timePlayed']['displayValue'], + "碾压": top_kill_vehicle['stats']['roadKills']['value'], + "摧毁": top_kill_vehicle['stats']['destroyedWith']['value'], + + } + shot_count = overview['stats']['shotsFired']['value'] + hit_count = overview['stats']['shotsHit']['value'] + logger.info(f"开火数:{shot_count}") + logger.info(f"命中数:{hit_count}") + acc = round((hit_count / shot_count) * 100, 2) + logger.info(f"命中率:{acc}%") + player_info = { + '玩家名称': platform_info['platformUserHandle'], + '游玩平台': platform_info['platformSlug'], + '游戏等级': overview['stats']['careerPlayerRank']['displayValue'], + '游玩时长': overview['stats']['timePlayed']['displayValue'], + '游玩场次': overview['stats']['matchesPlayed']['displayValue'], + '对局胜率': overview['stats']['wlPercentage']['displayValue'], + '对局得分': overview['stats']['score']['displayValue'], + '玩家K/D': overview['stats']['kdRatio']['value'], + '玩家KPM': overview['stats']['killsPerMinute']['value'], + '玩家SPM': overview['stats']['scorePerMinute']['value'], + '真人击杀': overview['stats']['playerKills']['displayValue'], + '击杀总计': overview['stats']['kills']['displayValue'], + '目标占领': overview['stats']['objectivesCaptured']['value'], + '游戏助攻': overview['stats']['assists']['displayValue'], + '救援数量': overview['stats']['revives']['displayValue'], + '最高连杀': overview['stats']['multiKills']['value'], + '命中率': f"{acc}%", + '爆头率': overview['stats']['headshotPercentage']['displayValue'], + '最佳武器': best_weapon, + '最佳载具': best_vehicle, + } + return player_info + + +async def get_bf6_data(player_id, user_id, platform): + + url = "https://api.gametools.network/bf6/multiple/?raw=false&format_values=true" + + payload = json.dumps([ + { + "player_id": player_id, + "user_id": user_id, + "platform": platform + } + ]) + headers = { + 'accept': 'application/json', + 'Content-Type': 'application/json' + } + + response = requests.request("POST", url, headers=headers, data=payload) + + player_stat_json = json.loads(response.text) + + return player_stat_json diff --git a/hexi/plugins/nonebot_plugin_bf_bot/image_builder.py b/hexi/plugins/nonebot_plugin_bf_bot/image_builder.py new file mode 100644 index 0000000..d5f32f9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/image_builder.py @@ -0,0 +1,592 @@ +import datetime +import io +import re + +import cv2 +import numpy as np +from PIL import Image, ImageDraw, ImageFont + +from .data_utils import * +from .img_utils import * +from .param import * + +# from img_utils import * +# from data_utils import * +# from param import * + +filepath = os.path.dirname(__file__).replace("\\", "/") + +# 字体 +font_XXL = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 72) +font_XL = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 64) +font_L = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 48) +font_ML = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 42) +font_M = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 36) +font_MS = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 32) +font_S = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 28) +font_XS = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 24) +font_XXS = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 18) +font_XXXS = ImageFont.truetype(f"{filepath}/font/bf-sub-headline-bold 等宽数字.ttf", 16) + +font_XXL_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 72) +font_XL_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 64) +font_L_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 48) +font_ML_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 42) +font_M_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 36) +font_MS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 32) +font_S_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 28) +font_XS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 24) +font_XXS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 18) +font_XXXS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 16) +font_S_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 28) +font_XS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 20) +font_XXS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 18) +font_XXXS_CH = ImageFont.truetype(f"{filepath}/font/演示创黑FLY.ttf", 16) + + +async def build_stats_card(game="bfv", player="Player001", pid=1145141919, kd=1.25, kpm=2.3, spm=500, acc=25.6, + head_shots=10, rank=100, time_play=100, kills=100, kill_assists=150, revives=114, wins=10, + loses=10, destroyed=514, best_weapon="M1907 SF", best_vehicle="坦克", best_class="Support", + longest_head_shot=1200, highest_ill_streak=100, stat_data=None, level_designation=None): + if stat_data is None: + stat_data = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + + # 获取当前事件并且格式化 + now = datetime.datetime.now() + formatted_time = now.strftime("%Y-%m-%d %H:%M:%S") + + # ---------------- OpenCV 部分 ---------------- + # 载入模板 + img = cv2.imread(f"{filepath}/template/{game}.png", cv2.IMREAD_COLOR) + + # 载入头像并缩放 + avatar = cv2.imread(f"{filepath}/avatar_cache/0.png", cv2.IMREAD_UNCHANGED) + avatar = cv2.resize(avatar, (200, 200), interpolation=cv2.INTER_AREA) + + # 创建圆形蒙版 + mask = np.zeros((200, 200), dtype=np.uint8) + cv2.circle(mask, (100, 100), 100, 255, -1) # 绘制半径100的实心圆 + + # 处理透明通道 + if avatar.shape[2] == 4: + # 合并圆形蒙版与原有alpha通道 + alpha = cv2.bitwise_and(avatar[:, :, 3], mask) + avatar[:, :, 3] = alpha + else: + # 无透明通道时创建BGRA图像 + avatar = cv2.cvtColor(avatar, cv2.COLOR_BGR2BGRA) + avatar[:, :, 3] = mask + + # 粘贴头像(保持原有坐标) + y, x = 55, 426 + h, w = avatar.shape[:2] + alpha = avatar[:, :, 3] / 255.0 + for c in range(3): + img[y:y + h, x:x + w, c] = (alpha * avatar[:, :, c] + + (1 - alpha) * img[y:y + h, x:x + w, c]) + + # 公告栏 + img = notice_paste(img) + + # ---------------- PIL 部分 ---------------- + pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) + draw = ImageDraw.Draw(pil_img) + + # 玩家信息 + draw.text((665, 65), f"{player}", fill="white", font=font_L_CH) + draw.text((745, 133), f"{pid}", fill="white", font=font_M_CH) + + # 等级游玩时长 + draw.text((740, 212), f"{rank}", fill="white", font=font_M_CH) + draw.text((985, 212), f"{time_play}H", fill="white", font=font_M_CH) + # draw_centered_text(draw=draw, text=rank, x_left=730, x_right=905, y=210, font=font_M, fill="white", ) + # draw_centered_text(draw=draw, text=f"{time_play}H", x_left=965, x_right=1120, y=210, font=font_M, fill="white", ) + # draw.text((730, 195), f"{rank}", fill="white", font=font_M) + # draw.text((1000, 195), f"{time_play}", fill="white", font=font_M) + + # 生涯总览 + + # 场次 + draw_centered_text(draw=draw, text=(wins + loses), x_left=45, x_right=265, y=350, + font=font_L_CH, + fill="white") + + # 命中率 + draw_centered_text(draw=draw, text=round(float(acc.replace("%", "")), 1), x_left=415, x_right=495, y=343, + font=font_M_CH, + fill="white") + # 爆头率 + if head_shots: + head_shots = head_shots.replace("%", "") + else: + head_shots = 0 + draw_centered_text(draw=draw, text=round(float(head_shots), 1), x_left=395, x_right=470, y=420, font=font_M_CH, + fill="white") + # kd + draw_centered_text(draw=draw, text=kd, x_left=585, x_right=785, y=340, font=font_XL_CH, fill="white") + # kpm + draw_centered_text(draw=draw, text=round(kpm, 1), x_left=825, x_right=1025, y=340, font=font_XL_CH, fill="white") + # spm + draw_centered_text(draw=draw, text=round(spm, 1), x_left=1065, x_right=1265, y=340, font=font_XL_CH, fill="white") + + # 击杀 + draw_centered_text(draw=draw, text=kills, x_left=870, x_right=1190, y=595, font=font_L_CH, fill="white") + + # 助攻 + draw_centered_text(draw=draw, text=kill_assists, x_left=820, x_right=1145, y=770, font=font_L_CH, fill="white") + + # 急救 + draw_centered_text(draw=draw, text=revives, x_left=770, x_right=1090, y=960, font=font_L_CH, fill="white") + + # 摧毁 + draw_centered_text(draw=draw, text=destroyed, x_left=720, x_right=1040, y=1140, font=font_L_CH, fill="white") + + # 底部栏 + + # 评级 + if game == 'bf6': + logger.info("bf6不计算称号") + else: + level = level_designation['level'] + des = level_designation['designation'] + color = level_designation['color'] + draw_centered_text(draw=draw, text=level, x_left=70, x_right=200, y=1120, font=font_XL_CH, fill=color) + draw_centered_text(draw=draw, text=des, x_left=200, x_right=550, y=1120, font=font_XL_CH, fill="white") + + # 最佳兵种 + + draw_centered_text(draw=draw, text=classes[best_class], x_left=140, x_right=310, y=1290, font=font_L_CH, + fill="white") + + # 最远击杀 + draw_centered_text(draw=draw, text=f"{longest_head_shot}m", x_left=455, x_right=625, y=1290, font=font_L_CH, + fill="white") + + # 最高连杀 + draw_centered_text(draw=draw, text=highest_ill_streak, x_left=765, x_right=935, y=1290, font=font_L_CH, + fill="white") + + # 最佳⭐ + pil_img = build_best(draw, pil_img, best_weapon, best_vehicle, game) + + # 生成时间 + draw.text((1870, 1420), f"{formatted_time}", fill=(154, 132, 149), font=font_XXXS_CH) + + # ---------------- 转回 OpenCV ---------------- + img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) + + # ---------------- 雷达图 ---------------- + if game != "bf6": + center = (311, 796) + r = 185 + scale_min = 0.25 if min(stat_data) < 0.25 else min(stat_data) + img = draw_radar(img, stat_data, center=center, r=r, + buffer=0.1, scale_min=scale_min, scale_max=1.10) + # 保存 + success, buffer = cv2.imencode(".png", img) + if success: + b_io = io.BytesIO(buffer) + return b_io # 就可以直接 return 二进制流 + else: + return None + + +async def build_bf6_stats_card(game="bfv", + qq_id=2931, + player="Player001", + pid=1145141919, + rank=114, + kd=1.25, + kpm=2.3, + spm=500, + acc=25.6, + head_shots=10, + time_play=100, + kills=100, + kill_assists=150, + revives=114, + repairs=1000, + captured=300, + score=145674, + wins=10, + loses=10, + destroyed=514, + best_weapon="M1907 SF", + best_vehicle="坦克", + best_class="Support", ): + # 获取当前事件并且格式化 + now = datetime.datetime.now() + formatted_time = now.strftime("%Y-%m-%d %H:%M:%S") + + # ---------------- OpenCV 部分 ---------------- + # 载入模板 + img = cv2.imread(f"{filepath}/template/{game}.png", cv2.IMREAD_COLOR) + + # 载入头像并缩放 + avatar = cv2.imread(f"{filepath}/avatar_cache/0.png", cv2.IMREAD_UNCHANGED) + avatar = cv2.resize(avatar, (134, 134), interpolation=cv2.INTER_AREA) + + # 粘贴头像(保持原有坐标) + y, x = 65, 105 + h, w = avatar.shape[:2] + img[y:y + h, x:x + w] = avatar + + # 公告栏 + img = notice_paste_bf6(img) + img = designation_paste(player, img, + user_id=qq_id, + start_x=104, + start_y=215, + target_height=30, + spacing=10) + + # ---------------- PIL 部分 ---------------- + pil_img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) + draw = ImageDraw.Draw(pil_img) + + # 玩家信息 105+160 + draw.text((265, 80), f"{player}", fill="white", font=font_XL) + draw.text((265, 140), f"UID: {pid}", fill="#CCCCCC", font=font_L) + + # 等级 + pil_img = paste_rank_icon(int(rank), pil_img) + draw_centered_text(draw=draw, text=f"{rank}", x_left=950, x_right=1075, y=205, + font=font_M, + fill="white") + # draw.text((740, 212), f"{rank}", fill="white", font=font_M) + + # 游玩时长 + draw.text((2300, 350), f"{time_play:.1f} H", fill="white", font=font_L) + # 场次 + draw.text((2300, 450), f"{wins + loses}", fill="white", font=font_L) + # draw_centered_text(draw=draw, text=(wins + loses), x_left=45, x_right=265, y=350, + # font=font_L, + # fill="white") + + # 生涯总览 + # 胜率 + + win_rate = round((wins / (wins + loses)) * 100, 1) + logger.info(f"胜场{wins},负场{loses},胜率{win_rate}") + + draw_centered_text(draw=draw, text=f"{win_rate}%", x_left=2090, x_right=2200, y=375, + font=font_XL, + fill="white") + + # 命中率 + acc_format = round(float(acc.replace("%", "")), 1) + draw_centered_text(draw=draw, text=f"{acc_format}%", x_left=1210, x_right=1303, y=363, + font=font_M, + fill="white") + # 爆头率 + if head_shots: + head_shots = head_shots.replace("%", "") + else: + head_shots = 0 + draw_centered_text(draw=draw, text=f"{round(float(head_shots), 1)}%", x_left=1210, x_right=1303, y=458, font=font_M, + fill="white") + # kd + draw.text((1350, 355), text=str(kd), fill="white", font=font_XXL) + # kpm + draw.text((1610, 355), text=f"{kpm:.2f}", fill="white", font=font_XXL) + # spm + draw.text((1870, 355), text=f"{int(spm)}", fill="white", font=font_XXL) + + # 击杀 + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1165, x_right=1455, y=805, + font=font_L, + fill="#444445") + draw_right_aligned_text(draw=draw, text=add_commas(str(kills)), x_left=1165, x_right=1455, y=805, + font=font_L, fill="white") + + # 急救 + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1165, x_right=1455, y=1080, + font=font_L, + fill="#444445") + draw_right_aligned_text(draw=draw, text=add_commas(str(revives)), x_left=1165, x_right=1455, y=1080, + font=font_L, fill="white") + + # 摧毁 + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1165, x_right=1455, y=1350, + font=font_L, + fill="#444445") + draw_right_aligned_text(draw=draw, text=add_commas(str(destroyed)), x_left=1165, x_right=1455, y=1350, + font=font_L, fill="white") + + # 右侧 + # 占领 + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1485, x_right=1780, y=745, + font=font_L, + fill="#444445") + draw_right_aligned_text(draw=draw, text=add_commas(str(captured)), x_left=1485, x_right=1780, y=745, + font=font_L, fill="white") + + # 得分 + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1485, x_right=1780, y=955, + font=font_L, + fill="#444445") + draw_right_aligned_text(draw=draw, text=add_commas(str(score)), x_left=1485, x_right=1780, y=955, + font=font_L, fill="white") + + # 助攻 + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1485, x_right=1780, y=1160, + font=font_L, + fill="#444445") + draw_right_aligned_text(draw=draw, text=add_commas(str(kill_assists)), x_left=1485, x_right=1780, y=1160, + font=font_L, fill="white") + + # 修理 + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 10), x_left=1485, x_right=1780, y=1370, + font=font_L, + fill="#444445") + draw_right_aligned_text(draw=draw, text=add_commas(str(repairs)), x_left=1485, x_right=1780, y=1370, + font=font_L, fill="white") + + # 底部栏 + + # # 最佳兵种 + # logger.info(f"最佳兵种:{best_class}") + # draw_centered_text(draw=draw, text=classes[best_class], x_left=140, x_right=310, y=1290, font=font_L, fill="white") + + # 最佳⭐ + pil_img = build_best_bf6(draw, pil_img, best_weapon, best_vehicle, best_class, game) + + # 生成时间 + draw.text((1750, 10), f"{formatted_time}/战地中文社区/维护 SANSENHOSHI", fill=(154, 132, 149), font=font_XS_CH) + + # ---------------- 转回 OpenCV ---------------- + img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) + + # ---------------- 雷达图 ---------------- + + # 保存 + success, buffer = cv2.imencode(".png", img) + if success: + b_io = io.BytesIO(buffer) + return b_io # 就可以直接 return 二进制流 + else: + return None + + +def build_best(draw: ImageDraw, img: Image, weapons, vehicle, game: str): + # 最佳武器 + weapon_name = weapons["weaponName"] + w_kills = weapons["kills"] + w_kpm = weapons["killsPerMinute"] + acc = weapons["accuracy"].replace("%", "") + headshots = weapons["headshots"].replace("%", "") + + # 最佳载具 + vehicle_name = vehicle["vehicleName"] + v_kills = vehicle["kills"] + v_kpm = vehicle["killsPerMinute"] + destroyed = vehicle["destroyed"] + + # 绘制最佳⭐ + # 武器 + draw_centered_text(draw=draw, text=bf_item[game][weapon_name].upper(), x_left=1240, x_right=1750, y=1355, + font=font_MS_CH, fill="white") + draw_centered_text(draw=draw, text=w_kills, x_left=1190, x_right=1390, y=1260, font=font_L_CH, fill="white") + draw_centered_text(draw=draw, text=w_kpm, x_left=1510, x_right=1635, y=1260, font=font_L_CH, fill="white") + draw_centered_text(draw=draw, text=acc, x_left=1735, x_right=1803, y=1030, font=font_M_CH, fill="white") + draw_centered_text(draw=draw, text=headshots, x_left=1695, x_right=1760, y=1200, font=font_M_CH, fill="white") + + # 载具 + draw_centered_text(draw=draw, text=bf_item[game][vehicle_name].upper(), x_left=1990, x_right=2440, y=1355, + font=font_MS_CH, fill="white") + draw_centered_text(draw=draw, text=v_kills, x_left=1940, x_right=2150, y=1260, font=font_L_CH, fill="white") + draw_centered_text(draw=draw, text=v_kpm, x_left=2295, x_right=2465, y=1055, font=font_XL_CH, fill="white") + draw_centered_text(draw=draw, text=destroyed, x_left=2265, x_right=2440, y=1260, font=font_L_CH, fill="white") + + # 图片 + weapon_url = weapons["image"] + vehicle_url = vehicle["image"] + wp_icon = get_save_icon(game, weapon_name, "weapon", weapon_url) + vc_icon = get_save_icon(game, vehicle_name, "vehicles", vehicle_url) + + img = image_paste_center(wp_icon, img, (1165, 1110)) + img = image_paste_center(vc_icon, img, (1920, 1110)) + return img + + +def build_best_bf6(draw: ImageDraw, img: Image, weapons, vehicle, classes, game: str): + # 最佳武器 + weapon_name = weapons["weaponName"] + w_kills = weapons["kills"] + w_kpm = weapons["killsPerMinute"] + acc = round(float(weapons["accuracy"].replace("%", "")), 1) + headshots = round(float(weapons["headshots"].replace("%", "")), 1) + + # 最佳载具 + vehicle_name = vehicle["vehicleName"] + v_kills = vehicle["kills"] + v_kpm = vehicle["killsPerMinute"] + destroyed = vehicle["destroyed"] + + # 绘制最佳⭐ + # 武器 + # draw_centered_text(draw=draw, text=bf_item[game][weapon_name].upper(), x_left=1240, x_right=1750, y=1355, + # font=font_MS, fill="white") + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 7), x_left=95, x_right=313, y=665, font=font_L, + fill="#313131") + draw_right_aligned_text(draw=draw, text=add_commas(str(w_kills)), x_left=95, x_right=313, y=665, + font=font_L, fill="white") + draw_centered_text(draw=draw, text=w_kpm, x_left=335, x_right=447, y=665, font=font_L, fill="white") + draw_centered_text(draw=draw, text=f"{acc}%", x_left=470, x_right=580, y=670, font=font_M, fill="white") + draw_centered_text(draw=draw, text=f"{headshots}%", x_left=610, x_right=717, y=670, font=font_M, fill="white") + + # 载具 + # draw_centered_text(draw=draw, text=bf_item[game][vehicle_name].upper(), x_left=1990, x_right=2440, y=1355, + # font=font_MS, fill="white") + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 7), x_left=125, x_right=325, y=1087, + font=font_L, + fill="#313131") + draw_right_aligned_text(draw=draw, text=add_commas(str(v_kills)), x_left=125, x_right=325, y=1087, + font=font_L, fill="white") + draw_centered_text(draw=draw, text=v_kpm, x_left=351, x_right=463, y=1087, font=font_L, fill="white") + draw_right_aligned_text(draw=draw, text=add_commas_with_padding("0", 7), x_left=477, x_right=688, y=1087, + font=font_L, + fill="#313131") + draw_right_aligned_text(draw=draw, text=destroyed, x_left=477, x_right=688, y=1087, font=font_L, fill="white") + + # 图片 + weapon_url = weapons["image"] + vehicle_url = vehicle["image"] + + wp_icon = get_save_icon(game, weapon_name, "weapon", weapon_url) + vc_icon = get_save_icon(game, vehicle_name, "vehicles", vehicle_url) + classes_icon = get_icon_from_cache(classes, 'bf6', 'classes') + wp_icon_new = png_resize(wp_icon, new_width=729 - 88) + vc_icon_new = png_resize(vc_icon, new_width=729 - 88) + classes_icon_new = png_resize(classes_icon, new_height=1165 - 326, new_width=1100 - 748) + + img = image_paste(wp_icon_new, img, (88, 325)) + img = image_paste(vc_icon_new, img, (88, 746)) + img = image_paste(classes_icon_new, img, (748, 326)) + + return img + + +def normalize_for_radar(data, buffer=0.1, scale_min=0.0, scale_max=1.0): + """ + 将数据动态归一化到指定区间 [scale_min, scale_max], + 并给最大值预留 buffer,让图形更饱满。 + + Args: + data (list/ndarray): 原始数据 + buffer (float): 缓冲比例,例如 0.1 表示最大值按 1.1 倍处理 + scale_min (float): 映射区间下限 + scale_max (float): 映射区间上限 + + Returns: + list: 归一化后的数据 + """ + data = np.array(data, dtype=float) + d_min, d_max = data.min(), data.max() + + # 给最大值留 buffer + d_max = d_max * (1 + buffer) + + if d_max == d_min: # 避免除零 + norm = np.ones_like(data) * (scale_min + scale_max) / 2 + else: + norm = (data - d_min) / (d_max - d_min) + norm = scale_min + norm * (scale_max - scale_min) + + return norm.tolist() + + +def add_commas(text): + return re.sub(r'(? 0 and new_height > 0: + scale = min(new_width / src_w, new_height / src_h) + target_w = int(src_w * scale) + target_h = int(src_h * scale) + + elif new_width > 0: + scale = new_width / src_w + target_w = new_width + target_h = int(src_h * scale) + + elif new_height > 0: + scale = new_height / src_h + target_h = new_height + target_w = int(src_w * scale) + + else: + # 未指定任何尺寸,直接返回 + return img + + # ------------------------- + # 重采样方式 + # ------------------------- + resample_map = { + "NEAREST": Image.NEAREST, + "BILINEAR": Image.BILINEAR, + "BICUBIC": Image.BICUBIC, + "LANCZOS": Image.LANCZOS + } + resample_method = resample_map.get(resample, Image.LANCZOS) + + # ------------------------- + # Alpha 安全 resize(逐通道) + # ------------------------- + bands = img.split() + resized_bands = [ + band.resize((target_w, target_h), resample=resample_method) + for band in bands + ] + + return Image.merge("RGBA", resized_bands) + + +# 图片粘贴 +def image_paste(paste_image, under_image, pos): + """ + + :param paste_image: 需要粘贴的图片 + :param under_image: 底图 + :param pos: 位置(x,y)坐标 + :return: 返回图片 + """ + # 获取需要贴入图片的透明通道 + r, g, b, alpha = paste_image.split() + # 粘贴时将alpha值传递至mask属性 + under_image.paste(paste_image, pos, alpha) + return under_image + + +def image_paste_center(paste_image: Image, under_image: Image, pos): + """ + 将一张图片粘贴到另一张图片上,并使粘贴图片的Y轴中心对齐到指定y坐标 + + :param paste_image: 需要粘贴的图片 (RGBA) + :param under_image: 底图 (RGBA) + :param pos: 粘贴位置 (x, y),其中y表示目标对齐的中心位置 + :return: 返回合成后的图片 + """ + x, y = pos + # 计算上下居中偏移 + paste_w, paste_h = paste_image.size + y_top = y - paste_h // 2 # 上边位置 = 中心点y - 半高 + + # 获取透明通道 + r, g, b, alpha = paste_image.split() + under_image.paste(paste_image, (x, y_top), alpha) + return under_image + + +def download_icon(url): + data = download_url(url) + img = BytesIO(data) + return img + + +# 下载QQ头像 +def download_avatar(user_id: str) -> bytes: + url = f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=640" + data = download_url(url) + if not data or hashlib.md5(data).hexdigest() == "acef72340ac0e914090bd35799f5594e": + url = f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=100" + data = download_url(url) + return data + + +# 根据URL下载文件 +def download_url(url: str) -> bytes: + for i in range(3): + try: + resp = requests.get(url) + if resp.status_code != 200: + continue + return resp.content + except Exception as e: + print(f"Error downloading {url}, retry {i}/3: {str(e)}") + + +# 图片裁剪 +def cut_image(pic_data: bytes, target_ratio: float): + try: + pic_data = Image.open(BytesIO(pic_data)) + w, h = pic_data.size + pic_ratio = w / h + if pic_ratio > target_ratio: + # 宽高比大于目标比例,按高度缩放。保持宽度不变 + new_h = w / target_ratio + h_delta = (h - new_h) / 2 + w_delta = 0 + else: + # 宽高比小于目标比例,按宽度缩放。保持高度不变 + new_w = h * target_ratio + w_delta = (w - new_w) / 2 + h_delta = 0 + cropped = pic_data.crop((w_delta, h_delta, w - w_delta, h - h_delta)) + return cropped + except Exception as e: + raise Exception(f"图片剪裁失败{str(e)}") + + +def draw_centered_text(draw, text, x_left, x_right, y, font, fill): + """ + 在指定区域水平居中绘制文本 + :param draw: ImageDraw对象 + :param text: 要绘制的文本 + :param x_left: 区域左边界x坐标 + :param x_right: 区域右边界x坐标 + :param y: 文本基线y坐标 + :param font: ImageFont对象 + :param fill: 文本颜色 + """ + text = str(text) + text_width = font.getlength(text) # 获取文本像素宽度 + area_width = x_right - x_left + x_center = x_left + (area_width - text_width) / 2 + draw.text((x_center, y), text, font=font, fill=fill) + + +def draw_right_aligned_text(draw, text, x_left, x_right, y, font, fill): + """ + 在指定区域内从右往左绘制文本(右对齐) + :param draw: ImageDraw 对象 + :param text: 要绘制的文本 + :param x_left: 区域左边界 x + :param x_right: 区域右边界 x(文本右侧贴齐这里) + :param y: 文本基线 y 坐标 + :param font: ImageFont 对象 + :param fill: 文本颜色 + """ + text = str(text) + text_width = font.getlength(text) + + # 右对齐:文本右边贴到 x_right + x_start = x_right - text_width + + # 可选:防止越界(超出左边界时截断) + if x_start < x_left: + x_start = x_left + + draw.text((x_start, y), text, font=font, fill=fill) + + +def get_save_icon(game, name, icon_type, url): + if game == 'bf6': + name = name.replace("/", "").upper() + else: + name = name.replace("/", "") + logger.info(f"查询的物品: {name},图标类型:{icon_type},游戏:{game}") + icon = get_icon_from_cache(name, game, icon_type) + if not icon: + if game == "bf1": + icon = get_icon_from_url(url) + if icon_type == "weapon": + icon = png_resize(icon, 500, 125) + else: + icon = png_resize(icon, 315, 79) + elif game == "bf3": + icon = get_icon_from_url(url) + if icon_type == "weapon": + icon = png_resize(icon, 500, 300) + else: + icon = png_resize(icon, 315, 200) + elif game == "bf4": + icon = get_icon_from_url(url) + if icon_type == "weapon": + icon = png_resize(icon, 500, 165) + else: + icon = png_resize(icon, 315, 80) + elif game == "bfv": + icon = get_icon_from_url(url) + if icon_type == "weapon": + icon = png_resize(icon, 500, 166) + else: + icon = png_resize(icon, 315, 315) + icon.save(f"{filepath}/img/{game}/{icon_type}/{name}.png") + logger.info(f"文件已经缓存至:{filepath}/img/{game}/{icon_type}/{name}.png") + + # 上述步骤处理完再执行一次icon判空 + if icon: + return icon + else: + # 针对空图片处理 + if icon_type == "weapon": + icon = Image.open(filepath + "/img/wp.png").convert('RGBA') + else: + icon = Image.open(filepath + "/img/vc.png").convert('RGBA') + return icon + + +# 获取icon +def get_icon_from_url(url): + if url: + try: + # 添加10s超时判断,如果超时返回空 + res = BytesIO(requests.get(url, timeout=10).content) + icon = Image.open(res).convert('RGBA') + return icon + except requests.exceptions.RequestException as e: + logger.error(f"请求异常:{e}") + + +def get_icon_from_cache(icon_name, game, icon_type): + path = f"{filepath}/img/{game}/{icon_type}" + logger.info(f"查询物品:{icon_name}物品路径:{path}") + try: + icon_list = os.listdir(path) + # logger.info(f"所有物品:{icon_list}") + if icon_name in str(icon_list): + logger.info(f"本地存在{icon_name}物品") + img = Image.open(f"{path}/{icon_name}.png").convert('RGBA') + return img + except Exception as err: + logger.error(f"获取图标失败:{str(err)}") + return None + + +def cutout_region(img, mask, alpha=0): + """ + 在图像指定区域设置透明度 + :param img: 输入图像 (BGR 或 BGRA) + :param mask: 区域定义 + - 矩形: (x1, y1, x2, y2) + - 圆形: (cx, cy, r) + - 任意 mask: numpy.ndarray (0/255) + :param alpha: 设置的透明度 (0=透明, 255=不透明, 0-255之间半透明) + :return: 处理后的图像 (BGRA) + """ + + # 转为 BGRA (确保有 alpha 通道) + if img.shape[2] == 3: + b, g, r = cv2.split(img) + a = np.ones(b.shape, dtype=np.uint8) * 255 + img = cv2.merge((b, g, r, a)) + + h, w = img.shape[:2] + region_mask = np.zeros((h, w), dtype=np.uint8) + + # 根据传入参数类型生成区域 mask + if isinstance(mask, tuple): + if len(mask) == 4: # 矩形 + x1, y1, x2, y2 = mask + region_mask[y1:y2, x1:x2] = 255 + elif len(mask) == 3: # 圆形 + cx, cy, r = mask + cv2.circle(region_mask, (cx, cy), r, 255, -1) + else: + raise ValueError("不支持的 mask tuple 格式") + elif isinstance(mask, np.ndarray): # 自定义 mask + if mask.shape != (h, w): + raise ValueError("mask 尺寸必须与图像一致") + region_mask = mask + else: + raise TypeError("mask 必须是 tuple 或 numpy.ndarray") + + # 修改 alpha 通道 + img[region_mask > 0, 3] = alpha + + return img + + +def paste_image_cv2(fg, bg, pos): + """ + 将前景图粘贴到背景图上,支持透明度 (Alpha 混合) + :param fg: 前景图 (必须是 BGRA) + :param bg: 背景图 (BGR 或 BGRA) + :param pos: 粘贴位置 (x, y) 左上角坐标 + :return: 合成后的图像 (BGRA) + """ + + x, y = pos + fh, fw = fg.shape[:2] + + # 确保背景有 alpha 通道 + if bg.shape[2] == 3: + b, g, r = cv2.split(bg) + a = np.ones(b.shape, dtype=np.uint8) * 255 + bg = cv2.merge((b, g, r, a)) + + # 截取 ROI 区域 + roi = bg[y:y + fh, x:x + fw] + + # 防止越界 + if roi.shape[0] != fh or roi.shape[1] != fw: + raise ValueError("前景图超出背景范围") + + # 提取 alpha 通道 + alpha_fg = fg[:, :, 3] / 255.0 + alpha_bg = 1.0 - alpha_fg + + # 混合 RGB + for c in range(3): + roi[:, :, c] = (alpha_fg * fg[:, :, c] + + alpha_bg * roi[:, :, c]) + + # 更新 alpha 通道(取最大值,保证透明度正确) + roi[:, :, 3] = np.clip(fg[:, :, 3] + roi[:, :, 3], 0, 255) + + # 放回背景 + bg[y:y + fh, x:x + fw] = roi + return bg + + +def notice_paste(cv2_bg): + pos = (1176, 318) + # 获取公告 + notice_path = f"{filepath}/notice/notice.png" + front_img = cv2.imread(notice_path) + mask = np.zeros((631, 1355), dtype=np.uint8) + pts = np.array([[0, 0], [167, 0], [0, 631]], np.int32) + cv2.fillPoly(mask, [pts], 255) + front_img = cutout_region(front_img, mask, alpha=0) + mix_bg = paste_image_cv2(front_img, cv2_bg, pos) + return mix_bg + + +def notice_paste_bf6(cv2_bg): + x, y = 0, 0 + + notice_path = f"{filepath}/notice/notice_bf6.png" + front_img = cv2.imread(notice_path, cv2.IMREAD_UNCHANGED) + + if front_img is None: + raise RuntimeError(f"Failed to load image: {notice_path}") + + h, w = front_img.shape[:2] + + # ROI 边界裁剪 + bg_h, bg_w = cv2_bg.shape[:2] + w = min(w, bg_w - x) + h = min(h, bg_h - y) + + roi = cv2_bg[y:y + h, x:x + w] + + # 有 Alpha 通道 → Alpha 混合 + if front_img.shape[2] == 4: + alpha = front_img[:h, :w, 3] / 255.0 + alpha = alpha[:, :, None] + + cv2_bg[y:y + h, x:x + w] = ( + alpha * front_img[:h, :w, :3] + + (1 - alpha) * roi + ).astype(np.uint8) + + # 无 Alpha → 直接覆盖 + else: + cv2_bg[y:y + h, x:x + w] = front_img[:h, :w] + + return cv2_bg + + +def designation_paste(player, + cv2_bg, + user_id, + start_x=10, + start_y=10, + target_height=40, + spacing=6 + ): + designation_list_path = get_designation_list_by_user_id(user_id, player) + if not designation_list_path: + return cv2_bg + + icons = [] + total_width = 0 + + for path in designation_list_path: + icon = cv2.imread(path, cv2.IMREAD_UNCHANGED) + if icon is None: + continue + + h, w = icon.shape[:2] + scale = target_height / h + new_w = int(w * scale) + + icon = cv2.resize(icon, (new_w, target_height)) + icons.append(icon) + total_width += new_w + + total_width += spacing * (len(icons) - 1) + + x = start_x + y = start_y # 关键变化点:直接使用 top-left + + bg_h, bg_w = cv2_bg.shape[:2] + + for icon in icons: + ih, iw = icon.shape[:2] + + if x + iw > bg_w or y + ih > bg_h: + break + + roi = cv2_bg[y:y + ih, x:x + iw] + + if icon.shape[2] == 4: + alpha = icon[:, :, 3] / 255.0 + for c in range(3): + roi[:, :, c] = roi[:, :, c] * (1 - alpha) + icon[:, :, c] * alpha + else: + roi[:] = icon + + cv2_bg[y:y + ih, x:x + iw] = roi + x += iw + spacing + + return cv2_bg + + +def get_designation_list_by_user_id(user_id, player): + usermanager = UserManager() + designationmanager = DesignationManager() + user_info = usermanager.get_user_by_qq(user_id) + icon_no_list = [] + if user_info is not None and user_info['ea_player_name'].upper() == player.upper(): + logger.info(f"玩家标签列表:{user_info}") + icon_no_list = user_info['designation'] + icon_list = designationmanager.get_designation_by_id_list(icon_no_list) + icon_path_list = [] + for icon in icon_list: + icon_file_name = icon['icon_path'] + icon_path_list.append(f"{filepath}/img/icon/designation/{icon_file_name}") + return icon_path_list + + +def paste_rank_icon(rank, img): + rank_pic_path = get_rank_pic(rank) + rank_icon_path = f"{filepath}/img/icon/rank/{rank_pic_path}" + rank_icon = Image.open(rank_icon_path) + rank_icon = png_resize(rank_icon, new_width=132, new_height=192) + fm_img = image_paste(rank_icon, img, (946, 61)) + return fm_img + + +def get_rank_pic(rank: int) -> str: + """ + 根据 rank 返回对应的 rank_pic 路径 + """ + for (start, end), info in rank_pic.items(): + if start <= rank <= end: + return info["path"] + return "t_ui_rankswatch_1-9 1.png" diff --git a/hexi/plugins/nonebot_plugin_bf_bot/notice/notice.png b/hexi/plugins/nonebot_plugin_bf_bot/notice/notice.png new file mode 100644 index 0000000..0219ff8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/notice/notice.png differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/notice/notice_bf6.png b/hexi/plugins/nonebot_plugin_bf_bot/notice/notice_bf6.png new file mode 100644 index 0000000..9cb55c0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/notice/notice_bf6.png differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/param.py b/hexi/plugins/nonebot_plugin_bf_bot/param.py new file mode 100644 index 0000000..99e3d8d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/param.py @@ -0,0 +1,1035 @@ +round_data = { + "bf1": { + "kd": 4.93, + "kpm": 2.69, + "hs": 0.26, + "rpr": 4.16, + "apr": 2.04, + "spm": 2739.54, + "blood": 3.5670, + "dedication": 7.5020, + "all_round": 5.5345 + }, + "bf3": { + "kd": 11.51, + "kpm": 4.59, + "hs": 0.26, + "rpr": 7.84, + "apr": 25.51, + "spm": 27983.00, + "blood": 7.6170, + "dedication": 846.7660, + "all_round": 427.1915 + }, + "bfv": { + "kd": 4.22, + "kpm": 1.78, + "hs": 0.26, + "rpr": 4.23, + "apr": 5.23, + "spm": 579.82, + "blood": 2.8480, + "dedication": 119.7840, + "all_round": 61.2980 + }, + "bf4": { + "kd": 6.0, + "kpm": 3.0, + "hs": 0.26, + "rpr": 10.00, + "apr": 10.00, + "spm": 5000.00, + "blood": 4.0, + "dedication": 2000.00, + "all_round": 1000.00 + }, +} + +classes = { + "Assault": "突击兵", + "Engineer": "工程兵", + "Support": "支援兵", + "Recon": "侦察兵", + "Commander": "指挥官", + "Medic": "医疗兵", + "Scout": "侦察兵", + "Pilot": "驾驶员", + "Cavalry": "骑兵", + "Tanker": "坦克" +} + +mods = { + +} + +rank_pic = { + (0, 9): {"path": "t_ui_rankswatch_1-9 1.png"}, + (10, 24): {"path": "t_ui_rankswatch_10-24 1.png"}, + (25, 44): {"path": "t_ui_rankswatch_25-44 1.png"}, + (45, 49): {"path": "t_ui_rankswatch_45-49 1.png"}, + (50, 99): {"path": "t_ui_rankswatch_50-99 1.png"}, + (100, 149): {"path": "t_ui_rankswatch_100-149 1.png"}, + (150, 199): {"path": "t_ui_rankswatch_150-190 1.png"}, + (200, 249): {"path": "t_ui_rankswatch_200-240 1.png"}, + (250, 299): {"path": "t_ui_rankswatch_250-290 1.png"}, + (300, 349): {"path": "t_ui_rankswatch_300-340 1.png"}, + (350, 399): {"path": "t_ui_rankswatch_350-390 1.png"}, + (400, 449): {"path": "t_ui_rankswatch_400-450 1.png"}, + (450, 499): {"path": "t_ui_rankswatch_450-490 1.png"}, + (500, 2999): {"path": "t_ui_rankswatch_500-3000 1.png"}, + (3000, 5000): {"path": "t_ui_rankswatch_3000-5000 1.png"}, +} + +bf_item = { + "bf1": { + "Wex": "韦克斯火焰喷射器", + "MG 08/15": "MG08/15轻机枪", + "Tankgewehr M1918": "M1918反坦克步枪", + "Villar Perosa": "维拉尔·佩罗萨双管机枪", + "Martini-Henry Grenade Launcher": "马蒂尼-亨利榴弹发射器", + "Mortar — HE": "迫击炮—高爆弹", + "Bandage Pouch": "绷带包", + "Crossbow Launcher — HE": "十字弩发射器—高爆弹", + "Trench Periscope": "战壕潜望镜", + "Tripwire Bomb — GAS": "绊雷—毒气", + "K Bullets": "K型子弹", + "Anti-Tank Grenade": "反坦克手榴弹", + "Flare Gun — Flash": "信号枪—闪光", + "Anti-Tank Mine": "反坦克地雷", + "Medical Syringe": "医疗注射器", + "Tripwire Bomb — HE": "绊雷—高爆", + "Tripwire Bomb — INC": "绊雷—燃烧", + "Flare Gun — Spot": "信号枪—标记", + "Crossbow Launcher — FRG": "十字弩发射器—破片", + "Ammo Pouch": "弹药包", + "Sniper Decoy": "狙击手诱饵", + "Medical Crate": "医疗箱", + "Sniper Shield": "狙击手盾牌", + "Ammo Crate": "弹药箱", + "AT Rocket Gun": "反坦克火箭枪", + "Mortar — AIR": "迫击炮—空爆弹", + "Dynamite": "炸药", + "Limpet Charge": "吸附式炸弹", + "Repair Tool": "维修工具", + "AA Rocket Gun": "防空火箭枪", + "Livens Projector": "利文斯投射器", + "Mondragón Storm": "蒙德拉贡风暴型", + "Mondragón Optical": "蒙德拉贡光学型", + "Cei-Rigotti Factory": "切-里戈蒂工厂型", + "M1907 SL Sweeper": "M1907 SL扫荡型", + "Autoloading 8 .25 Extended": "自动装填8型.25加长型", + "Selbstlader 1906 Factory": "1906半自动工厂型", + "M1907 SL Trench": "M1907 SL堑壕型", + "Selbstlader M1916 Factory": "M1916半自动工厂型", + "Selbstlader M1916 Optical": "M1916半自动光学型", + "Mondragón Sniper": "蒙德拉贡狙击型", + "Cei-Rigotti Optical": "切-里戈蒂光学型", + "Cei-Rigotti Trench": "切-里戈蒂堑壕型", + "Selbstlader M1916 Marksman": "M1916半自动神射手型", + "M1907 SL Factory": "M1907 SL工厂型", + "Autoloading 8 .35 Factory": "自动装填8型.35工厂型", + "Autoloading 8 .35 Marksman": "自动装填8型.35神射手型", + "RSC 1917 Factory": "RSC 1917工厂型", + "RSC 1917 Optical": "RSC 1917光学型", + "Selbstlader 1906 Sniper": "1906半自动狙击型", + "General Liu Rifle Storm": "刘将军步枪风暴型", + "General Liu Rifle Factory": "刘将军步枪工厂型", + "Fedorov Avtomat Trench": "费德洛夫自动步枪堑壕型", + "Fedorov Avtomat Optical": "费德洛夫自动步枪光学型", + "Farquhar-Hill Optical": "法夸尔-希尔光学型", + "Farquhar-Hill Storm": "法夸尔-希尔风暴型", + "Howell Automatic Factory": "豪厄尔自动步枪工厂型", + "Howell Automatic Sniper": "豪厄尔自动步枪狙击型", + "M1917 Patrol Carbine": "M1917巡逻卡宾枪", + "Carcano M91 Patrol Carbine": "卡尔卡诺M91巡逻卡宾枪", + "Hellfighter Trench Shotgun": "地狱战士堑壕霰弹枪", + "12g Automatic Hunter": "12号自动猎兵型", + "Model 10-A Factory": "10-A型工厂型", + "Model 10-A Hunter": "10-A型猎兵型", + "12g Automatic Backbored": "12号自动扩膛型", + "M97 Trench Gun Hunter": "M97堑壕枪猎兵型", + "M97 Trench Gun Backbored": "M97堑壕枪扩膛型", + "Model 10-A Slug": "10-A型独头弹型", + "12g Automatic Extended": "12号自动加长型", + "M97 Trench Gun Sweeper": "M97堑壕枪扫荡型", + "Sjögren Inertial Factory": "肖格伦惯性工厂型", + "Model 1900 Factory": "1900型工厂型", + "Model 1900 Slug": "1900型独头弹型", + "Sjögren Inertial Slug": "肖格伦惯性独头弹型", + "Mars Automatic": "火星自动手枪", + "Auto Revolver": "自动左轮手枪", + "Red Baron's P08": "红男爵的P08", + "C96": "C96手枪", + "C93": "C93手枪", + "Bodeo 1889": "博迪奥1889", + "Bull Dog Revolver": "斗牛犬左轮", + "Repetierpistole M1912": "M1912连发手枪", + "1903 Hammerless": "1903无击锤", + "Hellfighter M1911": "地狱战士M1911", + "Modello 1915": "1915型手枪", + "Gasser M1870": "加瑟M1870", + "Frommer Stop": "弗罗默停止式", + "No. 3 Revolver": "3号左轮", + "M1911": "M1911手枪", + "Kolibri": "蜂鸟手枪", + "Mle 1903": "1903型手枪", + "P08 Pistol": "P08手枪", + "Taschenpistole M1914": "M1914袖珍手枪", + "Obrez Pistol": "奥布雷兹手枪", + "Nagant Revolver": "纳甘左轮", + "Revolver Mk VI": "Mk VI左轮", + "Type 38 Arisaka Patrol": "三八式有坂巡逻卡宾枪", + "Madsen MG Trench": "麦德森机枪堑壕型", + "M1909 Benét–Mercié Storm": "M1909贝内特-梅西耶风暴型", + "Huot Automatic Low Weight": "胡特自动轻量型", + "Lewis Gun Low Weight": "刘易斯机枪轻量型", + "M1909 Benét–Mercié Telescopic": "M1909贝内特-梅西耶望远式", + "BAR M1918 Telescopic": "BAR M1918望远式", + "BAR M1918 Storm": "BAR M1918风暴型", + "Lewis Gun Suppressive": "刘易斯机枪压制型", + "Madsen MG Storm": "麦德森机枪风暴型", + "Madsen MG Low Weight": "麦德森机枪轻量型", + "BAR M1918 Trench": "BAR M1918堑壕型", + "Lewis Gun Optical": "刘易斯机枪光学型", + "MG15 n.A. Suppressive": "MG15 n.A.压制型", + "MG15 n.A. Storm": "MG15 n.A.风暴型", + "M1909 Benét–Mercié Optical": "M1909贝内特-梅西耶光学型", + "MG15 n.A. Low Weight": "MG15 n.A.轻量型", + "Chauchat Telescopic": "绍沙望远式", + "Chauchat Low Weight": "绍沙轻量型", + "Huot Automatic Optical": "胡特自动光学型", + "Perino Model 1908 Defensive": "佩里诺1908型防御型", + "Perino Model 1908 Low Weight": "佩里诺1908型轻量型", + "Parabellum MG14/17 Low Weight": "帕拉贝鲁姆MG14/17轻量型", + "Parabellum MG14/17 Suppressive": "帕拉贝鲁姆MG14/17压制型", + "M1917 MG Low Weight": "M1917机枪轻量型", + "M1917 MG Telescopic": "M1917机枪望远式", + "lMG 08/18 Low Weight": "lMG 08/18轻量型", + "lMG 08/18 Suppressive": "lMG 08/18压制型", + "Shovel": "工兵铲", + "Trench Mace": "战壕钉头锤", + "Sawtooth Knife": "锯齿刀", + "Club": "棍棒", + "Compact Trench Knife": "紧凑型战壕刀", + "Trench Knife": "战壕刀", + "Hellfighter Bolo Knife": "地狱战士波洛刀", + "US Trench Knife": "美军战壕刀", + "Bedouin Dagger": "贝都因匕首", + "Jambiya Knife": "詹比亚弯刀", + "Spiked Club": "尖刺棍棒", + "Bayonet Charge": "刺刀冲锋", + "Hatchet": "手斧", + "Bartek Bludgeon": "巴特克重棍", + "Cavalry Sword": "骑兵军刀", + "Combat Knife": "战斗刀", + "Survival Knife": "生存刀", + "Pickaxe": "镐", + "Nail Knife": "钉刀", + "Saber": "马刀", + "Trench Fleur": "战壕百合", + "Raider Club": "掠夺者棍棒", + "Billhook": "钩镰", + "Cogwheel Club": "齿轮棍", + "Kukri": "廓尔喀弯刀", + "Arditi Dagger": "敢死队匕首", + "Cavalry Lance": "骑兵长矛", + "Cossack Dagger": "哥萨克匕首", + "Dud Club": "哑弹棍", + "Totokia": "托托基亚权杖", + "French Butcher Knife": "法式屠刀", + "Russian Award Knife": "俄军奖赏刀", + "Coupe Coupe": "库普刀", + "Russian Axe": "俄式斧", + "Naval Cutlass": "海军弯刀", + "Grappling Hook": "抓钩", + "Ottoman Flanged Mace": "奥斯曼凸缘钉头锤", + "Ottoman Kilij": "奥斯曼基利杰弯刀", + "Yatagan Sword": "亚特坎剑", + "Meat Cleaver": "切肉刀", + "Prybar": "撬棍", + "Wine Bottle": "酒瓶", + "Sickle": "镰刀", + "Welsh Blade": "威尔士刀", + "M1903 Marksman": "M1903神射手型", + "Russian 1895 Sniper": "1895俄式狙击型", + "Lawrence of Arabia's SMLE": "阿拉伯的劳伦斯SMLE", + "Gewehr 98 Marksman": "Gewehr 98神射手型", + "Gewehr M.95 Infantry": "Gewehr M.95步兵型", + "SMLE MKIII Marksman": "SMLE MKIII神射手型", + "Martini-Henry Infantry": "马蒂尼-亨利步兵型", + "SMLE MKIII Infantry": "SMLE MKIII步兵型", + "Gewehr 98 Infantry": "Gewehr 98步兵型", + "Gewehr M.95 Carbine": "Gewehr M.95卡宾型", + "Gewehr M.95 Marksman": "Gewehr M.95神射手型", + "Russian 1895 Trench": "1895俄式堑壕型", + "Russian 1895 Infantry": "1895俄式步兵型", + "M1903 Sniper": "M1903狙击型", + "M1903 Experimental": "M1903实验型", + "SMLE MKIII Carbine": "SMLE MKIII卡宾型", + "Gewehr 98 Sniper": "Gewehr 98狙击型", + "Lebel Model 1886 Infantry": "勒贝尔1886型步兵型", + "Lebel Model 1886": "勒贝尔1886型", + "Lebel Model 1886 Sniper": "勒贝尔1886型狙击型", + "Martini-Henry Sniper": "马蒂尼-亨利狙击型", + "Vetterli-Vitali M1870/87 Carbine": "维特利-维塔利M1870/87卡宾型", + "Vetterli-Vitali M1870/87 Infantry": "维特利-维塔利M1870/87步兵型", + "Mosin-Nagant M91 Marksman": "莫辛-纳甘M91神射手型", + "Mosin-Nagant M91 Infantry": "莫辛-纳甘M91步兵型", + "Carcano M91 Carbine": "卡尔卡诺M91卡宾型", + "Type 38 Arisaka Infantry": "三八式有坂步兵型", + "Ross MkIII Marksman": "罗斯MkIII神射手型", + "M1917 Enfield Infantry": "M1917恩菲尔德步兵型", + "Ross MkIII Infantry": "罗斯MkIII步兵型", + "M1917 Enfield Silenced": "M1917恩菲尔德消音型", + "Incendiary Grenade": "燃烧手榴弹", + "Rifle Grenade — FRG": "步枪榴弹—破片", + "Impact Grenade": "冲击手榴弹", + "Frag Grenade": "破片手榴弹", + "Rifle Grenade — SMK": "步枪榴弹—烟雾", + "Mini Grenade": "迷你手榴弹", + "Smoke Grenade": "烟雾弹", + "Gas Grenade": "毒气弹", + "Light Anti-Tank Grenade": "轻型反坦克手榴弹", + "Rifle Grenade — HE": "步枪榴弹—高爆", + "Russian Standard Grenade": "俄军标准手榴弹", + "Improvised Grenade": "简易手榴弹", + "Gewehr M.95": "Gewehr M.95步枪", + "M1903": "M1903步枪", + "Gewehr 98": "Gewehr 98步枪", + "SMLE MKIII": "SMLE MKIII步枪", + "Russian 1895": "1895俄式步枪", + "Mosin-Nagant M91": "莫辛-纳甘M91步枪", + "Sawed Off Shotgun": "锯短型霰弹枪", + "Pieper M1893": "皮珀M1893", + "C96 Carbine": "C96卡宾枪", + "Frommer Stop Auto": "弗罗默停止式自动型", + "P08 Artillerie": "P08炮兵型", + "M1911 Extended": "M1911加长型", + "Mle 1903 Extended": "1903型加长型", + "C93 Carbine": "C93卡宾枪", + "MP 18 Trench": "MP18堑壕型", + "MP 18 Experimental": "MP18实验型", + "Automatico M1918 Factory": "M1918自动步枪工厂型", + "MP 18 Optical": "MP18光学型", + "Automatico M1918 Storm": "M1918自动步枪风暴型", + "Automatico M1918 Trench": "M1918自动步枪堑壕型", + "Hellriegel 1915 Factory": "赫尔里格尔1915工厂型", + "Ribeyrolles 1918 Factory": "里贝罗勒1918工厂型", + "Hellriegel 1915 Defensive": "赫尔里格尔1915防御型", + "SMG 08/18 Optical": "SMG08/18光学型", + "SMG 08/18 Factory": "SMG08/18工厂型", + "M1917 Trench Carbine": "M1917堑壕卡宾枪", + "Maschinenpistole M1912/P.16 Storm": "M1912/P.16冲锋枪风暴型", + "RSC SMG Factory": "RSC冲锋枪工厂型", + "RSC SMG Optical": "RSC冲锋枪光学型", + "Annihilator Trench": "歼灭者堑壕型", + "Maschinenpistole M1912/P.16 Experimental": "M1912/P.16冲锋枪实验型", + "Ribeyrolles 1918 Optical": "里贝罗勒1918光学型", + "A7v heavy tank": "A7V重型坦克", + "Mark v landship": "马克V型陆地舰", + "Ft-17 light tank": "FT-17轻型坦克", + "Artillery truck": "炮兵卡车", + "St chamond": "圣沙蒙坦克", + "Putilov garford": "普蒂洛夫加福德装甲车", + "Halberstadt cl. ii attack plane": "哈尔伯施塔特CL.II攻击机", + "Bristol f2.b attack plane": "布里斯托F2.B攻击机", + "A.e.f 2-a2 attack plane": "AEF 2-A2攻击机", + "Rumpler c.i attack plane": "鲁姆普勒C.I攻击机", + "Gotha g.iv bomber": "哥达G.IV轰炸机", + "Caproni ca.5 bomber": "卡普罗尼Ca.5轰炸机", + "Airco dh.10": "空客DH.10轰炸机", + "Hansa-brandenburg g.i": "汉莎-勃兰登堡G.I轰炸机", + "Spad s xiii fighter": "斯帕德S.XIII战斗机", + "Sopwith camel fighter": "索普威斯骆驼战斗机", + "Dr.1 fighter": "福克Dr.I战斗机", + "Albatros diii fighter": "阿尔巴特罗斯D.III战斗机", + "Ilya muromets": "伊利亚穆罗梅茨轰炸机", + "C-class airship": "C级飞艇", + "M30 scout": "M30侦察车", + "37/95 scout": "37/95侦察车", + "Kft scout": "KFT侦察车", + "Mc 18j sidecar": "MC 18J边车", + "Mc 3.5hp sidecar": "MC 3.5HP边车", + "Rnas armored car": "RNAS装甲车", + "Romfell armored car": "罗姆菲尔装甲车", + "Ev4 armored car": "EV4装甲车", + "F.t. armored car": "FT装甲车", + "M.a.s. torpedo boat": "MAS鱼雷艇", + "Y lighter landing craft": "Y型登陆艇", + "L-class destroyer": "L级驱逐舰", + "Fk 96 field gun": "FK 96野战炮", + "Fortress gun": "要塞炮", + "Qf 1 aa": "QF 1防空炮", + "Heavy machine gun": "重机枪", + "He auto-cannon": "高爆自动炮", + "Bl 9.2 siege gun": "BL 9.2英寸攻城炮", + "305/52 o coastal gun": "305/52 O海岸炮", + "Airship l30": "L30飞艇", + "Armored train": "装甲列车", + "Dreadnought": "无畏舰", + "Char 2c": "夏尔2C超重型坦克", + "Horse": "战马" + }, + "bfv": { + "MG 42": "MG42机枪", + "MG 34": "MG34机枪", + "VGO": "VGO机枪", + "M1922 MG": "M1922机枪", + "S2-200": "S2-200机枪", + "M1919A6": "M1919A6机枪", + "Boys AT Rifle": "博伊斯反坦克步枪", + "Panzerbüchse 39": "39型反坦克步枪", + "Frag Grenade Rifle": "步枪榴弹(高爆)", + "Sticky Dynamite": "粘性炸药", + "Panzerfaust": "铁拳", + "Ammo Crate": "弹药箱", + "Bandages": "绷带", + "AT Mine": "反坦克地雷", + "AP Mine": "人员杀伤地雷", + "Medical Crate": "医疗箱", + "Spotting Scope": "瞄准镜", + "Flare Gun": "信号枪", + "Spawn Beacon": "信标", + "Smoke Grenade": "烟雾弹", + "Frag Grenade": "破片手榴弹", + "Incendiary Grenade": "燃烧弹", + "PIAT": "PIAT反坦克发射器", + "AT Grenade Pistol": "反坦克榴弹手枪", + "Smoke Grenade Rifle": "步枪烟雾弹", + "Anti-Tank Bundle Grenade": "反坦克集束手榴弹", + "Throwing Blade": "飞刀", + "Impact Grenade": "冲击手榴弹", + "Medical Syringe": "医疗针", + "Fliegerfaust": "飞拳", + "Shaped Charge": "锥形炸药", + "Lunge Mine": "刺雷", + "M1A1 Bazooka": "M1A1巴祖卡", + "M2 Flamethrower": "M2火焰喷射器", + "Katana": "武士刀", + "Kunai": "苦无", + "Doppel-Schuss": "双管步枪", + "Type 99 Mine": "九九式地雷", + "Firecrackers": "鞭炮", + "RMN50 Rifle Frag": "RMN50步枪榴弹", + "Demolition Grenade": "爆破手榴弹", + "Pistol Flamethrower": "手枪式火焰喷射器", + "Kampfpistole": "战斗手枪", + "Trench Carbine": "战壕卡宾枪", + "P08 Carbine": "P08卡宾枪", + "Liberator": "解放者手枪", + "Repetierpistole M1912": "M1912连发手枪", + "Mk VI Revolver": "Mk VI左轮手枪", + "M1911": "M1911手枪", + "P38 Pistol": "P38手枪", + "Ruby": "鲁比手枪", + "P08 Pistol": "P08手枪", + "Type 94": "九四式手枪", + "Model 27": "27型左轮手枪", + "Welrod": "威尔罗德手枪", + "PPK": "PPK手枪", + "PPKS": "PPK/S手枪", + "M1911 Suppressed": "M1911消音手枪", + "StG 44": "StG44突击步枪", + "Sturmgewehr 1-5": "StG1-5突击步枪", + "M1907 SF": "M1907半自动步枪", + "Ribeyrolles 1918": "里贝罗勒1918", + "Breda M1935 PG": "贝雷塔M1935", + "M2 Carbine": "M2卡宾枪", + "Commando Carbine": "突击队卡宾枪", + "M28 con Tromboncino": "M28枪榴弹步枪", + "Jungle Carbine": "丛林卡宾枪", + "Gewehr 43": "Gewehr 43步枪", + "M1A1 Carbine": "M1A1卡宾枪", + "Turner SMLE": "特纳SMLE步枪", + "Selbstlader 1916": "1916型半自动步枪", + "Gewehr 1-5": "Gewehr 1-5步枪", + "Ag m/42": "Ag m/42步枪", + "MAS 44": "MAS 44步枪", + "Karabin 1938M": "1938M卡宾枪", + "M1 Garand": "M1加兰德步枪", + "M3 Infrared": "M3红外线步枪", + "M1941 Johnson": "M1941约翰逊步枪", + "Scout Knife M1916": "M1916侦察刀", + "Hatchet": "手斧", + "Club": "棍棒", + "Shovel": "工兵铲", + "Pickaxe": "镐", + "Kukri": "廓尔喀弯刀", + "British Army Jack Knife": "英军小刀", + "Lever Pipe": "撬棍", + "K98 Bayonet": "K98刺刀", + "Poignard": "匕首", + "German Naval Dagger": "德国海军匕首", + "Broken Bottle": "破瓶", + "Hachiwari": "破刀", + "Escape Axe": "逃生斧", + "EGW Survival Knife": "EGW生存刀", + "Combat Knife": "战斗刀", + "Commando Machete": "突击队砍刀", + "Sai": "十手", + "Bolo-Guna": "波洛刀", + "Ilse's Pickaxe": "伊尔丝的镐", + "Control Stick": "操纵杆", + "Lion Head Sword": "狮头剑", + "Golden Eagle": "金鹰", + "Lewis Gun": "刘易斯机枪", + "KE7": "KE7轻机枪", + "Bren Gun": "布伦轻机枪", + "FG-42": "FG-42伞兵步枪", + "LS/26": "LS/26轻机枪", + "Madsen MG": "麦德森机枪", + "Chauchat": "绍沙轻机枪", + "BAR M1918A2": "BAR M1918A2轻机枪", + "Type 97 MG": "九七式机枪", + "Type 11 LMG": "十一年式轻机枪", + "12g Automatic": "12号自动霰弹枪", + "M30 Drilling": "M30三管猎枪", + "M1897": "M1897霰弹枪", + "Model 37": "37型霰弹枪", + "Sjögren Shotgun": "肖格伦霰弹枪", + "M1928A1": "M1928A1冲锋枪", + "MP34": "MP34冲锋枪", + "MP28": "MP28冲锋枪", + "STEN": "斯登冲锋枪", + "Suomi KP/-31": "索米KP/-31冲锋枪", + "EMP": "EMP冲锋枪", + "MP40": "MP40冲锋枪", + "ZK-383": "ZK-383冲锋枪", + "MAB 38": "MAB 38冲锋枪", + "Type 100": "百式冲锋枪", + "M3 Grease Gun": "M3黄油枪", + "Type 2A": "二式冲锋枪", + "Welgun": "韦尔冈冲锋枪", + "Krag–Jørgensen": "克拉格-约根森步枪", + "Gewehr M95/30": "M95/30步枪", + "Lee-Enfield No.4 Mk I": "李-恩菲尔德No.4 Mk I步枪", + "Kar98k": "Kar98k步枪", + "Ross Rifle Mk III": "罗斯步枪Mk III", + "Type 99 Arisaka": "九九式步枪", + "K31/43": "K31/43步枪", + "RSC": "RSC步枪", + "Selbstlader 1906": "1906型半自动步枪", + "Model 8": "8型半自动步枪", + "ZH-29": "ZH-29步枪", + "Stuka b-1": "斯图卡B-1俯冲轰炸机", + "Stuka b-2": "斯图卡B-2俯冲轰炸机", + "Mosquito mkii": "蚊式MkII战斗机", + "Mosquito fb mkvi": "蚊式FB MkVI战斗轰炸机", + "Bf 109 g-2": "BF109 G-2战斗机", + "Bf 109 g-6": "BF109 G-6战斗机", + "Spitfire mk va": "喷火MkVA战斗机", + "Spitfire mk vb": "喷火MkVB战斗机", + "Blenheim mki": "布伦海姆MKI轰炸机", + "Blenheim mk if": "布伦海姆MK IF战斗机", + "Ju-88 a": "容克88A轰炸机", + "Ju-88 c": "容克88C重型战斗机", + "Corsair f4u-1a": "海盗F4U-1A战斗机", + "Corsair f4u-1c": "海盗F4U-1C战斗机", + "Zero a6m2": "零式A6M2战斗机", + "Zero a6m5": "零式A6M5战斗机", + "P51d fighter": "P51D野马战斗机", + "P51k fighter": "P51K野马战斗机", + "A-20 bomber": "A-20浩劫轰炸机", + "P-70 night fighter": "P-70夜间战斗机", + "Kübelwagen": "水桶车", + "M3": "M3半履带车", + "T48 gmc": "T48运兵车", + "Kettenkrad": "履带摩托车", + "Sd. kfz 251 halftrack": "Sd.Kfz 251半履带车", + "Sd. kfz. 251 pakwagen": "Sd.Kfz 251反坦克车", + "Universal carrier": "布伦通用载具", + "Tractor": "拖拉机", + "Type 95 car": "九五式小型乘用车", + "Gpw": "威利斯吉普", + "Dinghy": "橡皮艇", + "Lcvp": "登陆艇", + "Churchill mk vii": "丘吉尔Mk VII坦克", + "Churchill gun carrier": "丘吉尔运载坦克", + "Churchill crocodile": "丘吉尔鳄式喷火坦克", + "Tiger i": "虎式坦克", + "Sturmtiger": "突击虎式坦克", + "Panzer 38t": "38(t)坦克", + "Staghound t17e1": "猎鹿犬T17E1装甲车", + "Panzer iv": "四号坦克", + "Flakpanzer iv": "四号防空坦克", + "Sturmgeschutz iv": "四号突击炮", + "Valentine mk viii": "瓦伦丁Mk VIII坦克", + "Valentine archer": "瓦伦丁弓箭手坦克", + "Valentine aa mk i": "瓦伦丁防空坦克", + "Sherman": "谢尔曼坦克", + "T34 calliope": "T34管风琴火箭坦克", + "Hachi": "哈奇轻型坦克", + "Type 97": "九七式中型坦克", + "Lvt": "两栖登陆车", + "Ka-mi": "卡米两栖坦克", + "M8 greyhound": "M8灰狗装甲车", + "Sdkfz 234 puma": "Sd.Kfz 234美洲狮装甲车", + "6 pounder": "6磅反坦克炮", + "Flak 38": "Flak 38防空炮", + "Pak 40": "Pak 40反坦克炮", + "Vickers": "维克斯重机枪", + "Stationary mg34": "固定式MG34机枪", + "M2 hmg": "M2重机枪", + "Type 93 hmg": "九三式重机枪", + "40mm aa": "40mm防空炮", + "Type 10": "十年式120mm高射炮" + + }, + "bf3": { + "RPK": "RPK", + "SKS": "SKS", + "M39": "M39", + "Pecheneg": "Pecheneg", + "M416": "M416", + "Saiga": "Saiga", + "G36C": "G36C", + "M412 Rex": "M412 Rex", + "SV98": "SV98", + "AKS74U": "AKS74U", + "RPG-7": "RPG-7", + "Crossbow kobra": "Crossbow kobra", + "Glock 17": "Glock 17", + "AN94": "AN94", + "M60": "M60", + "M1911 LIT": "M1911 LIT", + "SCAR": "SCAR", + "MK11": "MK11", + "Glock 18 Silenced": "Glock 18 Silenced", + "UMP": "UMP", + "PDR": "PDR", + "M98B": "M98B", + "M9 Silenced": "M9 Silenced", + "XP2 L86A1": "XP2 L86A1", + "M40A5": "M40A5", + "USAS": "USAS", + "XP2 LSAT": "XP2 LSAT", + "XP1 QBB95": "XP1 QBB95", + "XP1 HK53": "XP1 HK53", + "M1911": "M1911", + "XP1 QBU88": "XP1 QBU88", + "M16A4": "M16A4", + "XP2 AUG": "XP2 AUG", + "M1014": "M1014", + "AEK971": "AEK971", + "G3A4": "G3A4", + "Taurus 44": "Taurus 44", + "Glock 17 Silenced": "Glock 17 Silenced", + "Underslung Launcher": "Underslung Launcher", + "Glock 18": "Glock 18", + "FGM-148 JAVELIN": "FGM-148 JAVELIN", + "F2000": "F2000", + "M1911 SILENCED": "M1911 SILENCED", + "Knife": "Knife", + "MP443 LIT": "MP443 LIT", + "Taurus 44 scoped": "Taurus 44 scoped", + "XP1 L96": "XP1 L96", + "XP1 FAMAS": "XP1 FAMAS", + "AK74M": "AK74M", + "M249": "M249", + "A91": "A91", + "AS-VAL": "AS-VAL", + "P90": "P90", + "M93R": "M93R", + "XP1 PP19": "XP1 PP19", + "870": "870", + "XP2 HK417": "XP2 HK417", + "MP443 Silenced": "MP443 Silenced", + "M9 Flashlight": "M9 Flashlight", + "PP2000": "PP2000", + "XP2 SPAS12": "XP2 SPAS12", + "MP7": "MP7", + "Underslung Shotgun": "Underslung Shotgun", + "MP 443": "MP 443", + "Crossbow Scoped": "Crossbow Scoped", + "XP1 L85A2": "XP1 L85A2", + "DAO": "DAO", + "M27": "M27", + "SG553": "SG553", + "Type88": "Type88", + "SA-18 IGLA AA": "SA-18 IGLA AA", + "M240": "M240", + "XP2 MTAR-21": "XP2 MTAR-21", + "SVD": "SVD", + "KH2002": "KH2002", + "XP1 Jackhammer": "XP1 Jackhammer", + "XP2 SCARL": "XP2 SCARL", + "M1911 Tactical": "M1911 Tactical", + "XP2 MP5K": "XP2 MP5K", + "FIM-92 STINGER AA": "FIM-92 STINGER AA", + "M9": "M9", + "XP2 ACR": "XP2 ACR", + "M4A1": "M4A1", + "XP2 JNG90": "XP2 JNG90", + "XP1 QBZ95B": "XP1 QBZ95B", + "XP1 MG36": "XP1 MG36", + "Mk153 SMAW": "Mk153 SMAW", + "VEHICLE IFV BTR 90": "VEHICLE IFV BTR 90", + "VEHICLE AIR HELICOPTER ATTACK MI28": "VEHICLE AIR HELICOPTER ATTACK MI28", + "STATIONARY AA CENTURION C-RAM": "STATIONARY AA CENTURION C-RAM", + "VEHICLE AIR JET ATTACK A10": "VEHICLE AIR JET ATTACK A10", + "VEHICLE AIR HELICOPTER SCOUT Z11": "VEHICLE AIR HELICOPTER SCOUT Z11", + "VEHICLE MBT T90": "VEHICLE MBT T90", + "VEHICLE AA LAV-AD": "VEHICLE AA LAV-AD", + "VEHICLE JEEP GROWLER ITV": "VEHICLE JEEP GROWLER ITV", + "VEHICLE JEEP VAN MODIFIED": "VEHICLE JEEP VAN MODIFIED", + "VEHICLE JEEP HUMVEE XP5": "VEHICLE JEEP HUMVEE XP5", + "VEHICLE TRANSPORT RIB BOAT": "VEHICLE TRANSPORT RIB BOAT", + "VEHICLE QUAD BIKE": "VEHICLE QUAD BIKE", + "VEHICLE AIR GUNSHIP": "VEHICLE AIR GUNSHIP", + "STATIONARY AA PANTSIR-S1": "STATIONARY AA PANTSIR-S1", + "VEHICLE AIR JET FIGHTER SU35": "VEHICLE AIR JET FIGHTER SU35", + "VEHICLE AIR HELICOPTER ATTACK AH1Z": "VEHICLE AIR HELICOPTER ATTACK AH1Z", + "VEHICLE IFV BMP": "VEHICLE IFV BMP", + "VEHICLE JEEP VODNIK": "VEHICLE JEEP VODNIK", + "STATIONARY AT KORNET": "STATIONARY AT KORNET", + "VEHICLE IFV LAV-25": "VEHICLE IFV LAV-25", + "VEHICLE JEEP DPV": "VEHICLE JEEP DPV", + "VEHICLE AIR JET ATTACK SU25": "VEHICLE AIR JET ATTACK SU25", + "VEHICLE AIR JET FIGHTER F18": "VEHICLE AIR JET FIGHTER F18", + "VEHICLE TD M1128": "VEHICLE TD M1128", + "VEHICLE AIR JET FIGHTER F-35 JSF": "VEHICLE AIR JET FIGHTER F-35 JSF", + "VEHICLE MBT M1 ABRAMS": "VEHICLE MBT M1 ABRAMS", + "VEHICLE JEEP VODNIK MODIFIED": "VEHICLE JEEP VODNIK MODIFIED", + "VEHICLE TRANSPORT KA-60": "VEHICLE TRANSPORT KA-60", + "VEHICLE TD SPRUT-SD": "VEHICLE TD SPRUT-SD", + "VEHICLE JEEP VODNIK XP5": "VEHICLE JEEP VODNIK XP5", + "VEHICLE AIR DROPSHIP": "VEHICLE AIR DROPSHIP", + "VEHICLE MART BM-23": "VEHICLE MART BM-23", + "STATIONARY AT TOW": "STATIONARY AT TOW", + "VEHICLE MART HIMARS": "VEHICLE MART HIMARS", + "VEHICLE AA 9K22 TUNGUSKA": "VEHICLE AA 9K22 TUNGUSKA", + "VEHICLE JEEP VDV": "VEHICLE JEEP VDV", + "VEHICLE TRANSPORT UH-1Y VENOM": "VEHICLE TRANSPORT UH-1Y VENOM", + "VEHICLE JEEP HUMVEE": "VEHICLE JEEP HUMVEE", + "VEHICLE TRANSPORT AAV-7A1": "VEHICLE TRANSPORT AAV-7A1", + "VEHICLE AIR HELICOPTER SCOUT AH6": "VEHICLE AIR HELICOPTER SCOUT AH6", + "VEHICLE SKIDLOADER": "VEHICLE SKIDLOADER", + "VEHICLE BIKE DIRTBIKE": "VEHICLE BIKE DIRTBIKE", + "VEHICLE JEEP HUMVEE MODIFIED": "VEHICLE JEEP HUMVEE MODIFIED" + }, + "bf4": { + "ak-12": "ak-12", + "ace-53-sv": "ace-53-sv", + "m224-mortar": "m224-mortar", + "mtar-21": "mtar-21", + "boot": "boot", + "ucav": "ucav", + "rpk": "rpk", + "m82a3-mid": "m82a3-mid", + "rorsch-mk-1": "rorsch-mk-1", + "m39-emr": "m39-emr", + "as-val": "as-val", + "338-recon": "338-recon", + "m67-frag": "m67-frag", + "pkp-pecheneg": "pkp-pecheneg", + "m416": "m416", + "qbu-88": "qbu-88", + "m32-mgl": "m32-mgl", + "aug-a3": "aug-a3", + "g36c": "g36c", + "acb-90": "acb-90", + "compact-45": "compact-45", + "mbt-law": "mbt-law", + "mare-s-leg": "mare-s-leg", + "repair-tool": "repair-tool", + "jng-90": "jng-90", + "m412-rex": "m412-rex", + "xm25-smoke": "xm25-smoke", + "hvm-ii": "hvm-ii", + "precision": "precision", + "mg4": "mg4", + "u-100-mk5": "u-100-mk5", + "acw-r": "acw-r", + "saiga-12k": "saiga-12k", + "m60-e4": "m60-e4", + "lsat": "lsat", + "m82a3-cqb": "m82a3-cqb", + "cbj-ms": "cbj-ms", + "unica-6": "unica-6", + "mpx": "mpx", + "scar-h": "scar-h", + "mk11-mod-0": "mk11-mod-0", + "dbv-12": "dbv-12", + "ump-45": "ump-45", + "scout": "scout", + "eod-bot": "eod-bot", + "deagle-44": "deagle-44", + "v40-mini": "v40-mini", + "m98b": "m98b", + "aku-12": "aku-12", + "scar-h-sv": "scar-h-sv", + "f2000": "f2000", + "cs-lr4": "cs-lr4", + "gol-magnum": "gol-magnum", + "qbz-95-1": "qbz-95-1", + "m40a5": "m40a5", + "usas-12": "usas-12", + "sks": "sks", + "tanto": "tanto", + "seal": "seal", + "carbon-fiber": "carbon-fiber", + "fy-js": "fy-js", + "weaver": "weaver", + "m1911": "m1911", + "rfb": "rfb", + "type-95b-1": "type-95b-1", + "xm25-airburst": "xm25-airburst", + "id-p-xp6-iname-m60ult": "id-p-xp6-iname-m60ult", + "m320-smk": "m320-smk", + "m16a4": "m16a4", + "l115": "l115", + "c4-explosive": "c4-explosive", + "trench": "trench", + "c100": "c100", + "neck": "neck", + "aek-971": "aek-971", + "44-magnum": "44-magnum", + "cz-3a1": "cz-3a1", + "l86a2": "l86a2", + "usas-12-flir": "usas-12-flir", + "m2-slam": "m2-slam", + "cz-805": "cz-805", + "amr-2": "amr-2", + "m320-he": "m320-he", + "bj-2": "bj-2", + "scout-elite": "scout-elite", + "shorty-12g": "shorty-12g", + "m320-dart": "m320-dart", + "sv-98": "sv-98", + "rpk-12": "rpk-12", + "defibrillator": "defibrillator", + "p226": "p226", + "p90": "p90", + "bulldog": "bulldog", + "spas-12": "spas-12", + "m249": "m249", + "qbs-09": "qbs-09", + "mx4": "mx4", + "a-91": "a-91", + "m82a3": "m82a3", + "an-94": "an-94", + "ace-21-cqb": "ace-21-cqb", + "groza-1": "groza-1", + "93r": "93r", + "machete": "machete", + "sw40": "sw40", + "xm25-dart": "xm25-dart", + "mp7": "mp7", + "m320-3gl": "m320-3gl", + "tactical": "tactical", + "dive": "dive", + "aa-mine": "aa-mine", + "m320-lvg": "m320-lvg", + "870-mcs": "870-mcs", + "rgo-impact": "rgo-impact", + "fgm-148-javelin": "fgm-148-javelin", + "m15-at-mine": "m15-at-mine", + "amr-2-cqb": "amr-2-cqb", + "groza-4": "groza-4", + "m26-frag": "m26-frag", + "sr338": "sr338", + "uts-15": "uts-15", + "m34-incendiary": "m34-incendiary", + "ace-52-cqb": "ace-52-cqb", + "hawk-12g": "hawk-12g", + "sar-21": "sar-21", + "pp-2000": "pp-2000", + "famas": "famas", + "aws": "aws", + "m26-mass": "m26-mass", + "qbb-95-1": "qbb-95-1", + "mp443": "mp443", + "g18": "g18", + "svd-12": "svd-12", + "bowie": "bowie", + "cs5": "cs5", + "sg553": "sg553", + "m18-smoke": "m18-smoke", + "type-88-lmg": "type-88-lmg", + "shank": "shank", + "sa-18-igla": "sa-18-igla", + "bayonet": "bayonet", + "m26-slug": "m26-slug", + "survival": "survival", + "m240b": "m240b", + "qsz-92": "qsz-92", + "pdw-r": "pdw-r", + "amr-2-mid": "amr-2-mid", + "rpg-7v2": "rpg-7v2", + "ar160": "ar160", + "fgm-172-sraw": "fgm-172-sraw", + "m1014": "m1014", + "l85a2": "l85a2", + "ump-9": "ump-9", + "srr-61": "srr-61", + "m26-dart": "m26-dart", + "fim-92-stinger": "fim-92-stinger", + "m84-flashbang": "m84-flashbang", + "m18-claymore": "m18-claymore", + "sr-2": "sr-2", + "m9": "m9", + "ak-5c": "ak-5c", + "ace-23": "ace-23", + "m320-fb": "m320-fb", + "m136-cs": "m136-cs", + "improvised": "improvised", + "cz-75": "cz-75", + "m4": "m4", + "fn57": "fn57", + "js2": "js2", + "ballistic-shield": "ballistic-shield", + "hand-flare": "hand-flare", + "dao-12": "dao-12", + "mk153-smaw": "mk153-smaw", + "BTR-90": "BTR-90", + "MI-28-HAVOC": "MI-28-HAVOC", + "PANTSIR-S1": "PANTSIR-S1", + "ZBD-09": "ZBD-09", + "A10-WARTHOG": "A10-WARTHOG", + "Z-11W": "Z-11W", + "T-90A": "T-90A", + "DV-15": "DV-15", + "ZFB-05": "ZFB-05", + "M1161-ITV": "M1161-ITV", + "UH-1Y-VENOM": "UH-1Y-VENOM", + "RAWR": "RAWR", + "KA-60-KASATKA": "KA-60-KASATKA", + "50-CAL": "50-CAL", + "Z-10W": "Z-10W", + "LAUNCH-POD": "LAUNCH-POD", + "M1-ABRAMS1": "M1-ABRAMS1", + "J-20": "J-20", + "UCAV1": "UCAV1", + "SPM-3": "SPM-3", + "SU-25TM-FROGFOOT": "SU-25TM-FROGFOOT", + "HJ-8-LAUNCHER": "HJ-8-LAUNCHER", + "PWC": "PWC", + "AH-1Z-VIPER": "AH-1Z-VIPER", + "MAV": "MAV", + "AH-6J-LITTLE-BIRD": "AH-6J-LITTLE-BIRD", + "Z-9-HAITUN": "Z-9-HAITUN", + "ACV": "ACV", + "Q-5-FANTAN": "Q-5-FANTAN", + "DV-151": "DV-151", + "9M133-KORNET-LAUNCHER": "9M133-KORNET-LAUNCHER", + "50-CAL1": "50-CAL1", + "DPV": "DPV", + "SUAV": "SUAV", + "XD-1-ACCIPITER": "XD-1-ACCIPITER", + "9K22-TUNGUSKA-M": "9K22-TUNGUSKA-M", + "HJ-8-LAUNCHER1": "HJ-8-LAUNCHER1", + "BOMBER": "BOMBER", + "LAV-25": "LAV-25", + "LD-2000-AA": "LD-2000-AA", + "UH-1Y-VENOM1": "UH-1Y-VENOM1", + "F35": "F35", + "LAV-251": "LAV-251", + "OLD-CANNON": "OLD-CANNON", + "TYPE-99-MBT": "TYPE-99-MBT", + "KA-60-KASATKA1": "KA-60-KASATKA1", + "LAV-AD": "LAV-AD", + "M224-MORTAR1": "M224-MORTAR1", + "Z-11W1": "Z-11W1", + "SPM-31": "SPM-31", + "M220-TOW-LAUNCHER": "M220-TOW-LAUNCHER", + "M1421": "M1421", + "UCAV2": "UCAV2", + "DIRTBIKE": "DIRTBIKE", + "9K22-TUNGUSKA-M1": "9K22-TUNGUSKA-M1", + "SNOWMOBILE": "SNOWMOBILE", + "SCHIPUNOV-42": "SCHIPUNOV-42", + "RHIB-BOAT": "RHIB-BOAT", + "UH-1Y-VENOM2": "UH-1Y-VENOM2", + "BOMBER1": "BOMBER1", + "BOMBER2": "BOMBER2", + "BTR-901": "BTR-901", + "SKID-LOADER": "SKID-LOADER", + "AC-130-GUNSHIP": "AC-130-GUNSHIP", + "VDV-BUGGY": "VDV-BUGGY", + "RCB": "RCB", + "EOD-BOT1": "EOD-BOT1", + "QUAD-BIKE": "QUAD-BIKE", + "AAV-7A1-AMTRAC": "AAV-7A1-AMTRAC", + "M142": "M142", + "MRAP": "MRAP", + "LAV-AD1": "LAV-AD1", + "LYT2021": "LYT2021", + "50-CAL2": "50-CAL2", + "AA-MINE1": "AA-MINE1", + "Z-11W2": "Z-11W2", + "M1-ABRAMS": "M1-ABRAMS", + "SU-50": "SU-50", + "TYPE-95-AA": "TYPE-95-AA", + "AH-6J-LITTLE-BIRD1": "AH-6J-LITTLE-BIRD1", + "T-90A1": "T-90A1", + "HT-95-LEVKOV": "HT-95-LEVKOV" + }, + "bf6": {'L110': 'L110', 'PW5A3': 'PW5A3', 'M433': 'M433', 'RPKM': 'RPKM', 'M87A1': 'M87A1', 'P18': 'P18', + 'M277': 'M277', 'B36A4': 'B36A4', 'L85A3': 'L85A3', 'M2010 ESR': 'M2010 ESR', 'M1014': 'M1014', + 'AK-205': 'AK-205', 'SVK-8.6': 'SVK-8.6', 'SGX': 'SGX', 'LMR27': 'LMR27', 'QBZ-192': 'QBZ-192', + 'M417 A2': 'M417 A2', 'DRS-IAR': 'DRS-IAR', 'KORD 6P67': 'KORD 6P67', 'USG-90': 'USG-90', 'M4A1': 'M4A1', + 'KTS100 MK8': 'KTS100 MK8', 'M45A1': 'M45A1', 'KV9': 'KV9', 'SOR-556 Mk2': 'SOR-556 MK2', 'PW7A2': 'PW7A2', + 'M123K': 'M123K', 'M44': 'M44', 'M250': 'M250', 'UMG-40': 'UMG-40', 'TR-7': 'TR-7', 'SL9': 'SL9', + 'M240L': 'M240L', 'SCW-10': 'SCW-10', 'NVO-228E': 'NVO-228E', 'M/60': 'M/60', 'PSR': 'PSR', 'SVDM': 'SVDM', + 'AK4D': 'AK4D', 'SOR-300SC': 'SOR-300SC', 'SG 553R': 'SG 553R', 'GRT-BC': 'GRT-BC', '18.5KS-K': '18.5KS-K', + 'ES 5.7': 'ES 5.7', 'M39 EMR': 'M39 EMR', 'SV-98': 'SV-98', 'Panthera KHT': 'PANTHERA KHT', + 'M77E Falchion': 'M77E FALCHION', 'Leo A4': 'LEO A4', 'Strf 09 A4': 'STRF 09 A4', + 'M1A2 SEPv3': 'M1A2 SEPV3', 'Cheetah 1A2': 'CHEETAH 1A2', 'Glider 96': 'GLIDER 96', + 'M3A3 Bradley': 'M3A3 BRADLEY', 'Su-57': 'SU-57', 'F-61V': 'F-61V', 'F-39E': 'F-39E', 'VECTOR': 'VECTOR'} +} + +color_select = { + "SS": (220, 20, 60), # 赤紅色 + "S": (255, 140, 0), # 橙色 + "A": (255, 225, 0), # 黃色 + "B": (30, 144, 255), # 藍色 + "C": (0, 204, 102) # 綠色 +} + +interval_table = { + (0, 0.25): {"blood": {"designation": "炮灰新兵", + "level": "C", + "color": color_select["C"], }, + "dedication": {"designation": "后勤新兵", + "level": "C", + "color": color_select["C"]}, + "all_round": {"designation": "战场新兵", + "level": "C", + "color": color_select["C"]}}, + (0.25, 0.50): {"blood": {"designation": "冷血先锋", + "level": "B", + "color": color_select["B"]}, + "dedication": {"designation": "战地医师", + "level": "B", + "color": color_select["B"]}, + "all_round": {"designation": "略知一二", + "level": "B", + "color": color_select["B"]}}, + (0.50, 0.75): {"blood": {"designation": "火线狂徒", + "level": "A", + "color": color_select["A"]}, + "dedication": {"designation": "风雨使者", + "level": "A", + "color": color_select["A"]}, + "all_round": {"designation": "博学多才", + "level": "A", + "color": color_select["A"]}}, + (0.75, 1.0): {"blood": {"designation": "绞肉战神", + "level": "S", + "color": color_select["S"]}, + "dedication": {"designation": "广厦之荫", + "level": "S", + "color": color_select["S"]}, + "all_round": {"designation": "六艺俱精", + "level": "S", + "color": color_select["S"]}}, + (1.0, float("inf")): {"blood": {"designation": "死神之眼", + "level": "SS", + "color": color_select["SS"]}, + "dedication": {"designation": "救世圣手", + "level": "SS", + "color": color_select["SS"]}, + "all_round": {"designation": "成为传奇", + "level": "SS", + "color": color_select["SS"]}} +} diff --git a/hexi/plugins/nonebot_plugin_bf_bot/template/bf1.png b/hexi/plugins/nonebot_plugin_bf_bot/template/bf1.png new file mode 100644 index 0000000..ecb5b91 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/template/bf1.png differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/template/bf3.png b/hexi/plugins/nonebot_plugin_bf_bot/template/bf3.png new file mode 100644 index 0000000..cb88a27 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/template/bf3.png differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/template/bf4.png b/hexi/plugins/nonebot_plugin_bf_bot/template/bf4.png new file mode 100644 index 0000000..b66c256 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/template/bf4.png differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/template/bf6.png b/hexi/plugins/nonebot_plugin_bf_bot/template/bf6.png new file mode 100644 index 0000000..930ffdb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/template/bf6.png differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/template/bfv.png b/hexi/plugins/nonebot_plugin_bf_bot/template/bfv.png new file mode 100644 index 0000000..cf037b4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/template/bfv.png differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/template/horizon/bf6.png b/hexi/plugins/nonebot_plugin_bf_bot/template/horizon/bf6.png new file mode 100644 index 0000000..a997db0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_bf_bot/template/horizon/bf6.png differ diff --git a/hexi/plugins/nonebot_plugin_bf_bot/test.py b/hexi/plugins/nonebot_plugin_bf_bot/test.py new file mode 100644 index 0000000..284e17a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/test.py @@ -0,0 +1,3380 @@ +from PIL import Image, ImageDraw, ImageFont + +from tracker_data import * + +weapon_data = { + "weapons": [ + { + "type": "Machine Guns", + "weaponName": "L110", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Minimi_PKG_Factory_MED-0e29fce7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Minimi_PKG_Factory_MED-0e29fce7.webp", + "id": "mg_l110", + "kills": 74, + "damage": 15353, + "assistsDamage": 35, + "bodyKills": 61, + "headshotKills": 13, + "hipfireKills": 1, + "multiKills": 12, + "accuracy": "9.52%", + "killsPerMinute": 1.07, + "damagePerMinute": 222.29, + "headshots": "17.57%", + "hitVKills": 8.59, + "shotsHit": 636, + "shotsFired": 6683, + "scopedKills": 73, + "spawns": 39, + "timeEquipped": 4144 + }, + { + "type": "SMG-PDWs", + "weaponName": "PW5A3", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MP5MLI_PKG_Factory_MED-2d1944b7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MP5MLI_PKG_Factory_MED-2d1944b7.webp", + "id": "smg_pw5a3", + "kills": 7, + "damage": 1562, + "assistsDamage": 1, + "bodyKills": 7, + "headshotKills": 0, + "hipfireKills": 1, + "multiKills": 0, + "accuracy": "18.99%", + "killsPerMinute": 0.46, + "damagePerMinute": 102.99, + "headshots": "0.0%", + "hitVKills": 18.71, + "shotsHit": 131, + "shotsFired": 690, + "scopedKills": 6, + "spawns": 0, + "timeEquipped": 910 + }, + { + "type": "Assault Rifles", + "weaponName": "M433", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_HK433_PKG_Factory_MED-b06f02f7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_HK433_PKG_Factory_MED-b06f02f7.webp", + "id": "ar_m433", + "kills": 607, + "damage": 71600, + "assistsDamage": 284, + "bodyKills": 526, + "headshotKills": 81, + "hipfireKills": 96, + "multiKills": 78, + "accuracy": "13.12%", + "killsPerMinute": 1.71, + "damagePerMinute": 201.52, + "headshots": "13.34%", + "hitVKills": 4.84, + "shotsHit": 2939, + "shotsFired": 22402, + "scopedKills": 511, + "spawns": 390, + "timeEquipped": 21318 + }, + { + "type": "Machine Guns", + "weaponName": "RPKM", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_RPKM_PKG_Factory_MED-755b785f.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_RPKM_PKG_Factory_MED-755b785f.webp", + "id": "mg_rpkm", + "kills": 88, + "damage": 16592, + "assistsDamage": 22, + "bodyKills": 80, + "headshotKills": 8, + "hipfireKills": 6, + "multiKills": 9, + "accuracy": "24.84%", + "killsPerMinute": 1.08, + "damagePerMinute": 202.79, + "headshots": "9.09%", + "hitVKills": 12.9, + "shotsHit": 1135, + "shotsFired": 4570, + "scopedKills": 82, + "spawns": 1, + "timeEquipped": 4909 + }, + { + "type": "Shotguns", + "weaponName": "M87A1", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_590A1_PKG_Factory_MED-4b387330.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_590A1_PKG_Factory_MED-4b387330.webp", + "id": "sg_m87a1", + "kills": 351, + "damage": 22678, + "assistsDamage": 72, + "bodyKills": 166, + "headshotKills": 185, + "hipfireKills": 122, + "multiKills": 31, + "accuracy": "91.29%", + "killsPerMinute": 2.72, + "damagePerMinute": 175.44, + "headshots": "52.71%", + "hitVKills": 1.88, + "shotsHit": 660, + "shotsFired": 723, + "scopedKills": 229, + "spawns": 149, + "timeEquipped": 7756 + }, + { + "type": "Pistols", + "weaponName": "P18", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M18_PKG_Factory_MED-88261bf8.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M18_PKG_Factory_MED-88261bf8.webp", + "id": "pst_p18", + "kills": 14, + "damage": 2080, + "assistsDamage": 12, + "bodyKills": 9, + "headshotKills": 5, + "hipfireKills": 6, + "multiKills": 4, + "accuracy": "23.77%", + "killsPerMinute": 0.79, + "damagePerMinute": 116.85, + "headshots": "35.71%", + "hitVKills": 6.93, + "shotsHit": 97, + "shotsFired": 408, + "scopedKills": 8, + "spawns": 1336, + "timeEquipped": 1068 + }, + { + "type": "Carbines", + "weaponName": "M277", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_XM7_PKG_Factory_MED-26271094.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_XM7_PKG_Factory_MED-26271094.webp", + "id": "crb_x277", + "kills": 420, + "damage": 52607, + "assistsDamage": 174, + "bodyKills": 309, + "headshotKills": 111, + "hipfireKills": 17, + "multiKills": 38, + "accuracy": "17.03%", + "killsPerMinute": 1.85, + "damagePerMinute": 231.61, + "headshots": "26.43%", + "hitVKills": 4.32, + "shotsHit": 1813, + "shotsFired": 10649, + "scopedKills": 403, + "spawns": 238, + "timeEquipped": 13628 + }, + { + "type": "Assault Rifles", + "weaponName": "B36A4", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_G36_PKG_Factory_MED-fb5466ec.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_G36_PKG_Factory_MED-fb5466ec.webp", + "id": "ar_b36a4", + "kills": 1045, + "damage": 48359, + "assistsDamage": 141, + "bodyKills": 547, + "headshotKills": 498, + "hipfireKills": 44, + "multiKills": 24, + "accuracy": "19.59%", + "killsPerMinute": 3.73, + "damagePerMinute": 172.69, + "headshots": "47.66%", + "hitVKills": 3.22, + "shotsHit": 3363, + "shotsFired": 17165, + "scopedKills": 1001, + "spawns": 172, + "timeEquipped": 16802 + }, + { + "type": "Assault Rifles", + "weaponName": "L85A3", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_L85A3_PKG_Factory_MED-9bd0deaa.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_L85A3_PKG_Factory_MED-9bd0deaa.webp", + "id": "ar_l85a3", + "kills": 785, + "damage": 16153, + "assistsDamage": 60, + "bodyKills": 315, + "headshotKills": 470, + "hipfireKills": 8, + "multiKills": 4, + "accuracy": "28.29%", + "killsPerMinute": 7.26, + "damagePerMinute": 149.47, + "headshots": "59.87%", + "hitVKills": 2.05, + "shotsHit": 1609, + "shotsFired": 5687, + "scopedKills": 777, + "spawns": 111, + "timeEquipped": 6484 + }, + { + "type": "Rifles", + "weaponName": "M2010 ESR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M2010ESR_PKG_Factory_MED-f94fdae6.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M2010ESR_PKG_Factory_MED-f94fdae6.webp", + "id": "snp_m2010", + "kills": 553, + "damage": 53403, + "assistsDamage": 32, + "bodyKills": 150, + "headshotKills": 403, + "hipfireKills": 200, + "multiKills": 51, + "accuracy": "47.56%", + "killsPerMinute": 2.49, + "damagePerMinute": 240.36, + "headshots": "72.88%", + "hitVKills": 1.37, + "shotsHit": 760, + "shotsFired": 1598, + "scopedKills": 353, + "spawns": 81, + "timeEquipped": 13331 + }, + { + "type": "Shotguns", + "weaponName": "M1014", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M1014_PKG_Factory_MED-e011854a.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M1014_PKG_Factory_MED-e011854a.webp", + "id": "sg_m1014", + "kills": 142, + "damage": 15520, + "assistsDamage": 19, + "bodyKills": 127, + "headshotKills": 15, + "hipfireKills": 138, + "multiKills": 11, + "accuracy": "76.98%", + "killsPerMinute": 4.06, + "damagePerMinute": 444.27, + "headshots": "10.56%", + "hitVKills": 2.8, + "shotsHit": 398, + "shotsFired": 517, + "scopedKills": 4, + "spawns": 31, + "timeEquipped": 2096 + }, + { + "type": "Carbines", + "weaponName": "AK-205", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_AK205_PKG_Factory_MED-6d376081.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_AK205_PKG_Factory_MED-6d376081.webp", + "id": "crb_ak205", + "kills": 30, + "damage": 5519, + "assistsDamage": 29, + "bodyKills": 25, + "headshotKills": 5, + "hipfireKills": 6, + "multiKills": 0, + "accuracy": "12.01%", + "killsPerMinute": 0.76, + "damagePerMinute": 139.49, + "headshots": "16.67%", + "hitVKills": 12.8, + "shotsHit": 384, + "shotsFired": 3197, + "scopedKills": 24, + "spawns": 26, + "timeEquipped": 2374 + }, + { + "type": "DMRs", + "weaponName": "SVK-8.6", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SVCh_PKG_Factory_MED-bb06d385.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SVCh_PKG_Factory_MED-bb06d385.webp", + "id": "dmr_svk86", + "kills": 262, + "damage": 42653, + "assistsDamage": 95, + "bodyKills": 144, + "headshotKills": 118, + "hipfireKills": 2, + "multiKills": 36, + "accuracy": "33.32%", + "killsPerMinute": 1.31, + "damagePerMinute": 212.95, + "headshots": "45.04%", + "hitVKills": 3.19, + "shotsHit": 837, + "shotsFired": 2512, + "scopedKills": 260, + "spawns": 76, + "timeEquipped": 12018 + }, + { + "type": "SMG-PDWs", + "weaponName": "SGX", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MPX_PKG_Factory_MED-e822f017.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MPX_PKG_Factory_MED-e822f017.webp", + "id": "smg_sgx", + "kills": 9788, + "damage": 526470, + "assistsDamage": 7, + "bodyKills": 7110, + "headshotKills": 2678, + "hipfireKills": 3088, + "multiKills": 85, + "accuracy": "54.83%", + "killsPerMinute": 56.3, + "damagePerMinute": 3028.3, + "headshots": "27.36%", + "hitVKills": 2.37, + "shotsHit": 23240, + "shotsFired": 42387, + "scopedKills": 6700, + "spawns": 65, + "timeEquipped": 10431 + }, + { + "type": "DMRs", + "weaponName": "LMR27", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_ARADMR_PKG_Factory_MED-dfe224de.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_ARADMR_PKG_Factory_MED-dfe224de.webp", + "id": "dmr_lmr27", + "kills": 5, + "damage": 765, + "assistsDamage": 2, + "bodyKills": 5, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "30.0%", + "killsPerMinute": 1.18, + "damagePerMinute": 180.0, + "headshots": "0.0%", + "hitVKills": 7.2, + "shotsHit": 36, + "shotsFired": 120, + "scopedKills": 5, + "spawns": 3, + "timeEquipped": 255 + }, + { + "type": "Carbines", + "weaponName": "QBZ-192", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_QBZ192_PKG_Factory_MED-dc0a546b.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_QBZ192_PKG_Factory_MED-dc0a546b.webp", + "id": "crb_qbz192", + "kills": 75, + "damage": 10219, + "assistsDamage": 52, + "bodyKills": 72, + "headshotKills": 3, + "hipfireKills": 4, + "multiKills": 7, + "accuracy": "12.36%", + "killsPerMinute": 1.08, + "damagePerMinute": 147.64, + "headshots": "4.0%", + "hitVKills": 3.83, + "shotsHit": 287, + "shotsFired": 2322, + "scopedKills": 71, + "spawns": 104, + "timeEquipped": 4153 + }, + { + "type": "Carbines", + "weaponName": "M417 A2", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_HK417A2_PKG_Factory_MED-494ffe6e.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_HK417A2_PKG_Factory_MED-494ffe6e.webp", + "id": "crb_m417a2", + "kills": 1942, + "damage": 52408, + "assistsDamage": 156, + "bodyKills": 638, + "headshotKills": 1304, + "hipfireKills": 103, + "multiKills": 54, + "accuracy": "24.49%", + "killsPerMinute": 6.87, + "damagePerMinute": 185.47, + "headshots": "67.15%", + "hitVKills": 1.78, + "shotsHit": 3464, + "shotsFired": 14143, + "scopedKills": 1839, + "spawns": 266, + "timeEquipped": 16954 + }, + { + "type": "Machine Guns", + "weaponName": "DRS-IAR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M27IAR_PKG_Factory_MED-ae6675cd.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M27IAR_PKG_Factory_MED-ae6675cd.webp", + "id": "mg_drsiar", + "kills": 729, + "damage": 83389, + "assistsDamage": 45, + "bodyKills": 599, + "headshotKills": 130, + "hipfireKills": 115, + "multiKills": 61, + "accuracy": "28.88%", + "killsPerMinute": 5.56, + "damagePerMinute": 636.4, + "headshots": "17.83%", + "hitVKills": 4.49, + "shotsHit": 3270, + "shotsFired": 11323, + "scopedKills": 614, + "spawns": 77, + "timeEquipped": 7862 + }, + { + "type": "Assault Rifles", + "weaponName": "KORD 6P67", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_6P67_PKG_Factory_MED-827b9414.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_6P67_PKG_Factory_MED-827b9414.webp", + "id": "ar_kord6p67", + "kills": 502, + "damage": 64820, + "assistsDamage": 98, + "bodyKills": 429, + "headshotKills": 73, + "hipfireKills": 42, + "multiKills": 107, + "accuracy": "25.85%", + "killsPerMinute": 2.55, + "damagePerMinute": 328.9, + "headshots": "14.54%", + "hitVKills": 7.41, + "shotsHit": 3722, + "shotsFired": 14397, + "scopedKills": 460, + "spawns": 178, + "timeEquipped": 11825 + }, + { + "type": "SMG-PDWs", + "weaponName": "USG-90", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_P90_PKG_Factory_MED-2ab1db64.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_P90_PKG_Factory_MED-2ab1db64.webp", + "id": "smg_usg90", + "kills": 10, + "damage": 1217, + "assistsDamage": 4, + "bodyKills": 6, + "headshotKills": 4, + "hipfireKills": 3, + "multiKills": 1, + "accuracy": "16.58%", + "killsPerMinute": 0.75, + "damagePerMinute": 91.39, + "headshots": "40.0%", + "hitVKills": 6.6, + "shotsHit": 66, + "shotsFired": 398, + "scopedKills": 7, + "spawns": 0, + "timeEquipped": 799 + }, + { + "type": "Carbines", + "weaponName": "M4A1", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M4A1_PKG_Factory_MED-34529a82.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M4A1_PKG_Factory_MED-34529a82.webp", + "id": "crb_m4a1", + "kills": 2309, + "damage": 36071, + "assistsDamage": 141, + "bodyKills": 730, + "headshotKills": 1579, + "hipfireKills": 92, + "multiKills": 42, + "accuracy": "26.14%", + "killsPerMinute": 13.41, + "damagePerMinute": 209.53, + "headshots": "68.38%", + "hitVKills": 1.6, + "shotsHit": 3691, + "shotsFired": 14118, + "scopedKills": 2217, + "spawns": 199, + "timeEquipped": 10329 + }, + { + "type": "Machine Guns", + "weaponName": "KTS100 MK8", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Ultimax_PKG_Factory_MED-a8ebb482.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Ultimax_PKG_Factory_MED-a8ebb482.webp", + "id": "mg_kts100mk8", + "kills": 4524, + "damage": 25524, + "assistsDamage": 76, + "bodyKills": 1865, + "headshotKills": 2659, + "hipfireKills": 54, + "multiKills": 23, + "accuracy": "41.99%", + "killsPerMinute": 19.76, + "damagePerMinute": 111.48, + "headshots": "58.78%", + "hitVKills": 1.38, + "shotsHit": 6236, + "shotsFired": 14851, + "scopedKills": 4470, + "spawns": 88, + "timeEquipped": 13737 + }, + { + "type": "Pistols", + "weaponName": "M45A1", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M45A1_PKG_Factory_MED-8c41691b.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M45A1_PKG_Factory_MED-8c41691b.webp", + "id": "pst_m45a1", + "kills": 228, + "damage": 252, + "assistsDamage": 0, + "bodyKills": 30, + "headshotKills": 198, + "hipfireKills": 37, + "multiKills": 2, + "accuracy": "211.11%", + "killsPerMinute": 93.7, + "damagePerMinute": 103.56, + "headshots": "86.84%", + "hitVKills": 1.0, + "shotsHit": 228, + "shotsFired": 108, + "scopedKills": 191, + "spawns": 69, + "timeEquipped": 146 + }, + { + "type": "SMG-PDWs", + "weaponName": "KV9", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Vector_PKG_Factory_MED-b5631ed7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Vector_PKG_Factory_MED-b5631ed7.webp", + "id": "smg_kv9", + "kills": 169, + "damage": 21081, + "assistsDamage": 83, + "bodyKills": 148, + "headshotKills": 21, + "hipfireKills": 58, + "multiKills": 18, + "accuracy": "16.2%", + "killsPerMinute": 1.42, + "damagePerMinute": 177.47, + "headshots": "12.43%", + "hitVKills": 5.8, + "shotsHit": 981, + "shotsFired": 6057, + "scopedKills": 111, + "spawns": 142, + "timeEquipped": 7127 + }, + { + "type": "Assault Rifles", + "weaponName": "SOR-556 Mk2", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SCARL_PKG_Factory_MED-b44467bb.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SCARL_PKG_Factory_MED-b44467bb.webp", + "id": "ar_sor556mk2", + "kills": 451, + "damage": 54559, + "assistsDamage": 175, + "bodyKills": 367, + "headshotKills": 84, + "hipfireKills": 23, + "multiKills": 47, + "accuracy": "20.04%", + "killsPerMinute": 2.27, + "damagePerMinute": 274.14, + "headshots": "18.63%", + "hitVKills": 4.89, + "shotsHit": 2205, + "shotsFired": 11002, + "scopedKills": 428, + "spawns": 139, + "timeEquipped": 11941 + }, + { + "type": "SMG-PDWs", + "weaponName": "PW7A2", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MP7A2_PKG_Factory_MED-406bc965.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MP7A2_PKG_Factory_MED-406bc965.webp", + "id": "smg_pw7a2", + "kills": 216, + "damage": 20576, + "assistsDamage": 15, + "bodyKills": 201, + "headshotKills": 15, + "hipfireKills": 75, + "multiKills": 54, + "accuracy": "26.43%", + "killsPerMinute": 5.13, + "damagePerMinute": 488.55, + "headshots": "6.94%", + "hitVKills": 6.2, + "shotsHit": 1339, + "shotsFired": 5066, + "scopedKills": 141, + "spawns": 4, + "timeEquipped": 2527 + }, + { + "type": "Machine Guns", + "weaponName": "M123K", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MG4K_PKG_Factory_MED-cc064690.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MG4K_PKG_Factory_MED-cc064690.webp", + "id": "mg_m123k", + "kills": 84, + "damage": 15303, + "assistsDamage": 40, + "bodyKills": 75, + "headshotKills": 9, + "hipfireKills": 22, + "multiKills": 8, + "accuracy": "12.66%", + "killsPerMinute": 1.03, + "damagePerMinute": 187.92, + "headshots": "10.71%", + "hitVKills": 11.15, + "shotsHit": 937, + "shotsFired": 7403, + "scopedKills": 62, + "spawns": 63, + "timeEquipped": 4886 + }, + { + "type": "Pistols", + "weaponName": "M44", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_RagingHunter_PKG_Factory_MED-f9773307.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_RagingHunter_PKG_Factory_MED-f9773307.webp", + "id": "pst_m44", + "kills": 18, + "damage": 4263, + "assistsDamage": 14, + "bodyKills": 12, + "headshotKills": 6, + "hipfireKills": 4, + "multiKills": 0, + "accuracy": "34.78%", + "killsPerMinute": 0.27, + "damagePerMinute": 63.98, + "headshots": "33.33%", + "hitVKills": 5.78, + "shotsHit": 104, + "shotsFired": 299, + "scopedKills": 14, + "spawns": 854, + "timeEquipped": 3998 + }, + { + "type": "Machine Guns", + "weaponName": "M250", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M250_PKG_Factory_MED-6e230a71.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M250_PKG_Factory_MED-6e230a71.webp", + "id": "mg_xm250", + "kills": 328, + "damage": 38530, + "assistsDamage": 90, + "bodyKills": 289, + "headshotKills": 39, + "hipfireKills": 27, + "multiKills": 58, + "accuracy": "18.11%", + "killsPerMinute": 2.33, + "damagePerMinute": 273.68, + "headshots": "11.89%", + "hitVKills": 4.3, + "shotsHit": 1412, + "shotsFired": 7796, + "scopedKills": 301, + "spawns": 166, + "timeEquipped": 8447 + }, + { + "type": "SMG-PDWs", + "weaponName": "UMG-40", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_UMP40_PKG_Factory_MED-22afa646.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_UMP40_PKG_Factory_MED-22afa646.webp", + "id": "smg_umg40", + "kills": 4, + "damage": 926, + "assistsDamage": 1, + "bodyKills": 4, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 1, + "accuracy": "24.37%", + "killsPerMinute": 0.43, + "damagePerMinute": 98.51, + "headshots": "0.0%", + "hitVKills": 21.75, + "shotsHit": 87, + "shotsFired": 357, + "scopedKills": 4, + "spawns": 3, + "timeEquipped": 564 + }, + { + "type": "Assault Rifles", + "weaponName": "TR-7", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Tavor7_PKG_Factory_MED-e682f267.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Tavor7_PKG_Factory_MED-e682f267.webp", + "id": "ar_tr7", + "kills": 616, + "damage": 68498, + "assistsDamage": 107, + "bodyKills": 474, + "headshotKills": 142, + "hipfireKills": 143, + "multiKills": 55, + "accuracy": "16.89%", + "killsPerMinute": 2.46, + "damagePerMinute": 273.5, + "headshots": "23.05%", + "hitVKills": 3.68, + "shotsHit": 2268, + "shotsFired": 13428, + "scopedKills": 473, + "spawns": 252, + "timeEquipped": 15027 + }, + { + "type": "SMG-PDWs", + "weaponName": "SL9", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_APDW_PKG_Factory_MED-c4d1b829.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_APDW_PKG_Factory_MED-c4d1b829.webp", + "id": "smg_sl9", + "kills": 376, + "damage": 37358, + "assistsDamage": 17, + "bodyKills": 316, + "headshotKills": 60, + "hipfireKills": 19, + "multiKills": 77, + "accuracy": "21.84%", + "killsPerMinute": 4.86, + "damagePerMinute": 483.08, + "headshots": "15.96%", + "hitVKills": 4.85, + "shotsHit": 1824, + "shotsFired": 8350, + "scopedKills": 357, + "spawns": 25, + "timeEquipped": 4640 + }, + { + "type": "Machine Guns", + "weaponName": "M240L", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M240L_PKG_Factory_MED-1fa18e0c.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M240L_PKG_Factory_MED-1fa18e0c.webp", + "id": "mg_m240l", + "kills": 45, + "damage": 4029, + "assistsDamage": 0, + "bodyKills": 40, + "headshotKills": 5, + "hipfireKills": 3, + "multiKills": 3, + "accuracy": "31.3%", + "killsPerMinute": 7.03, + "damagePerMinute": 629.53, + "headshots": "11.11%", + "hitVKills": 3.31, + "shotsHit": 149, + "shotsFired": 476, + "scopedKills": 42, + "spawns": 1, + "timeEquipped": 384 + }, + { + "type": "SMG-PDWs", + "weaponName": "SCW-10", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_APC10_PKG_Factory_MED-716a97fb.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_APC10_PKG_Factory_MED-716a97fb.webp", + "id": "smg_scw10", + "kills": 571, + "damage": 61171, + "assistsDamage": 139, + "bodyKills": 495, + "headshotKills": 76, + "hipfireKills": 48, + "multiKills": 105, + "accuracy": "18.37%", + "killsPerMinute": 2.47, + "damagePerMinute": 264.68, + "headshots": "13.31%", + "hitVKills": 4.04, + "shotsHit": 2308, + "shotsFired": 12565, + "scopedKills": 523, + "spawns": 232, + "timeEquipped": 13867 + }, + { + "type": "Assault Rifles", + "weaponName": "NVO-228E", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_ACE32_PKG_Factory_MED-39a97220.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_ACE32_PKG_Factory_MED-39a97220.webp", + "id": "ar_nvo228e", + "kills": 960, + "damage": 61885, + "assistsDamage": 101, + "bodyKills": 611, + "headshotKills": 349, + "hipfireKills": 72, + "multiKills": 39, + "accuracy": "28.84%", + "killsPerMinute": 5.78, + "damagePerMinute": 372.69, + "headshots": "36.35%", + "hitVKills": 2.44, + "shotsHit": 2344, + "shotsFired": 8128, + "scopedKills": 888, + "spawns": 114, + "timeEquipped": 9963 + }, + { + "type": "Machine Guns", + "weaponName": "M/60", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M60E6_PKG_Factory_MED-e600bb28.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M60E6_PKG_Factory_MED-e600bb28.webp", + "id": "mg_m60", + "kills": 5, + "damage": 1191, + "assistsDamage": 5, + "bodyKills": 5, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 1, + "accuracy": "6.74%", + "killsPerMinute": 0.47, + "damagePerMinute": 112.01, + "headshots": "0.0%", + "hitVKills": 11.8, + "shotsHit": 59, + "shotsFired": 876, + "scopedKills": 5, + "spawns": 1, + "timeEquipped": 638 + }, + { + "type": "Rifles", + "weaponName": "PSR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MRAD_PKG_Factory_MED-5035ce99.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MRAD_PKG_Factory_MED-5035ce99.webp", + "id": "snp_psr", + "kills": 39, + "damage": 7457, + "assistsDamage": 11, + "bodyKills": 17, + "headshotKills": 22, + "hipfireKills": 22, + "multiKills": 0, + "accuracy": "30.75%", + "killsPerMinute": 0.49, + "damagePerMinute": 94.61, + "headshots": "56.41%", + "hitVKills": 3.56, + "shotsHit": 139, + "shotsFired": 452, + "scopedKills": 17, + "spawns": 9, + "timeEquipped": 4729 + }, + { + "type": "DMRs", + "weaponName": "SVDM", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SVDM_PKG_Factory_MED-b6c9aa50.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SVDM_PKG_Factory_MED-b6c9aa50.webp", + "id": "dmr_svdm", + "kills": 3, + "damage": 475, + "assistsDamage": 3, + "bodyKills": 1, + "headshotKills": 2, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "20.0%", + "killsPerMinute": 0.28, + "damagePerMinute": 44.88, + "headshots": "66.67%", + "hitVKills": 6.33, + "shotsHit": 19, + "shotsFired": 95, + "scopedKills": 3, + "spawns": 1, + "timeEquipped": 635 + }, + { + "type": "Assault Rifles", + "weaponName": "AK4D", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_G3A4_PKG_Factory_MED-0575cf00.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_G3A4_PKG_Factory_MED-0575cf00.webp", + "id": "ar_ak4d", + "kills": 155, + "damage": 17827, + "assistsDamage": 48, + "bodyKills": 147, + "headshotKills": 8, + "hipfireKills": 6, + "multiKills": 23, + "accuracy": "20.76%", + "killsPerMinute": 1.53, + "damagePerMinute": 176.24, + "headshots": "5.16%", + "hitVKills": 4.49, + "shotsHit": 696, + "shotsFired": 3353, + "scopedKills": 149, + "spawns": 80, + "timeEquipped": 6069 + }, + { + "type": "Carbines", + "weaponName": "SOR-300SC", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SCARSC_PKG_Factory_MED-7a6a50ff.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SCARSC_PKG_Factory_MED-7a6a50ff.webp", + "id": "crb_sor300sc", + "kills": 5, + "damage": 1016, + "assistsDamage": 4, + "bodyKills": 4, + "headshotKills": 1, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "12.99%", + "killsPerMinute": 0.24, + "damagePerMinute": 47.77, + "headshots": "20.0%", + "hitVKills": 20.0, + "shotsHit": 100, + "shotsFired": 770, + "scopedKills": 5, + "spawns": 0, + "timeEquipped": 1276 + }, + { + "type": "Carbines", + "weaponName": "SG 553R", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SIG553R_PKG_Factory_MED-afc2dfa8.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SIG553R_PKG_Factory_MED-afc2dfa8.webp", + "id": "crb_sg553r", + "kills": 4207, + "damage": 30073, + "assistsDamage": 119, + "bodyKills": 3204, + "headshotKills": 1003, + "hipfireKills": 1264, + "multiKills": 37, + "accuracy": "45.09%", + "killsPerMinute": 21.64, + "damagePerMinute": 154.71, + "headshots": "23.84%", + "hitVKills": 1.16, + "shotsHit": 4895, + "shotsFired": 10855, + "scopedKills": 2943, + "spawns": 200, + "timeEquipped": 11663 + }, + { + "type": "Carbines", + "weaponName": "GRT-BC", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MSBSGROTB_PKG_Factory_MED-25acf006.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MSBSGROTB_PKG_Factory_MED-25acf006.webp", + "id": "crb_grtbc", + "kills": 22, + "damage": 3216, + "assistsDamage": 20, + "bodyKills": 17, + "headshotKills": 5, + "hipfireKills": 7, + "multiKills": 1, + "accuracy": "12.16%", + "killsPerMinute": 0.76, + "damagePerMinute": 111.15, + "headshots": "22.73%", + "hitVKills": 7.95, + "shotsHit": 175, + "shotsFired": 1439, + "scopedKills": 15, + "spawns": 21, + "timeEquipped": 1736 + }, + { + "type": "Shotguns", + "weaponName": "18.5KS-K", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_185KSK_PKG_Factory_MED-432c353f.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MSBSGROTB_PKG_Factory_MED-25acf006.webp", + "id": "sg_185ksk", + "kills": 17, + "damage": 2390, + "assistsDamage": 9, + "bodyKills": 15, + "headshotKills": 2, + "hipfireKills": 17, + "multiKills": 1, + "accuracy": "22.83%", + "killsPerMinute": 0.87, + "damagePerMinute": 122.46, + "headshots": "11.76%", + "hitVKills": 2.94, + "shotsHit": 50, + "shotsFired": 219, + "scopedKills": 0, + "spawns": 30, + "timeEquipped": 1171 + }, + { + "type": "Pistols", + "weaponName": "ES 5.7", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M18_PKG_Factory_MED-88261bf8.webp", + "id": "pst_es57", + "kills": 9183, + "damage": 565421, + "assistsDamage": 7, + "bodyKills": 3568, + "headshotKills": 5615, + "hipfireKills": 2930, + "multiKills": 60, + "accuracy": "105.3%", + "killsPerMinute": 51.52, + "damagePerMinute": 3172.07, + "headshots": "61.15%", + "hitVKills": 2.51, + "shotsHit": 23019, + "shotsFired": 21860, + "scopedKills": 6253, + "spawns": 715, + "timeEquipped": 10695 + }, + { + "type": "DMRs", + "weaponName": "M39 EMR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SVCh_PKG_Factory_MED-bb06d385.webp", + "id": "dmr_m39emr", + "kills": 0, + "damage": 0, + "assistsDamage": 0, + "bodyKills": 0, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "0.0%", + "killsPerMinute": 0.0, + "damagePerMinute": 0.0, + "headshots": "0.0%", + "hitVKills": 0.0, + "shotsHit": 0, + "shotsFired": 0, + "scopedKills": 0, + "spawns": 0, + "timeEquipped": 45 + }, + { + "type": "Rifles", + "weaponName": "SV-98", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M2010ESR_PKG_Factory_MED-f94fdae6.webp", + "id": "snp_sv98", + "kills": 2, + "damage": 334, + "assistsDamage": 1, + "bodyKills": 1, + "headshotKills": 1, + "hipfireKills": 1, + "multiKills": 0, + "accuracy": "25.93%", + "killsPerMinute": 0.3, + "damagePerMinute": 50.1, + "headshots": "50.0%", + "hitVKills": 3.5, + "shotsHit": 7, + "shotsFired": 27, + "scopedKills": 1, + "spawns": 1, + "timeEquipped": 400 + } + ], +} +vehicle_data = { + "vehicles": [ + { + "type": "Air Combat", + "vehicleName": "Panthera KHT", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Eurocopter_VSD0001-8003028d.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Eurocopter_VSD0001-8003028d.webp", + "id": "air_panthera", + "kills": 166, + "killsPerMinute": 7.07, + "damage": 27206, + "spawns": 6, + "roadKills": 7, + "passengerAssists": 13, + "multiKills": 5, + "distanceTraveled": 50779, + "driverAssists": 1, + "vehiclesDestroyedWith": 7, + "assists": 14, + "damageTo": 3918, + "destroyed": 0, + "timeIn": 1408 + }, + { + "type": "Air Combat", + "vehicleName": "M77E Falchion", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "id": "air_m77efalchio", + "kills": 0, + "killsPerMinute": 0, + "damage": 0, + "spawns": 0, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 0, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 0, + "destroyed": 0, + "timeIn": 0 + }, + { + "type": "Ground Combat", + "vehicleName": "Leo A4", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Leopard_VSD0001-f8da51ee.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Leopard_VSD0001-f8da51ee.webp", + "id": "sur_leoa4", + "kills": 22, + "killsPerMinute": 0.74, + "damage": 19307, + "spawns": 8, + "roadKills": 1, + "passengerAssists": 1, + "multiKills": 2, + "distanceTraveled": 6115, + "driverAssists": 13, + "vehiclesDestroyedWith": 1, + "assists": 14, + "damageTo": 43760, + "destroyed": 6, + "timeIn": 1789 + }, + { + "type": "Ground Combat", + "vehicleName": "Strf 09 A4", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_CV90_VSD0001-acd942b6.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_CV90_VSD0001-acd942b6.webp", + "id": "sur_strf09a4", + "kills": 140, + "killsPerMinute": 1.76, + "damage": 25699, + "spawns": 196, + "roadKills": 0, + "passengerAssists": 52, + "multiKills": 27, + "distanceTraveled": 12701, + "driverAssists": 41, + "vehiclesDestroyedWith": 2, + "assists": 93, + "damageTo": 20875, + "destroyed": 1, + "timeIn": 4770 + }, + { + "type": "Ground Combat", + "vehicleName": "M1A2 SEPv3", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Abrams_VSD0001-5412a78d.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Abrams_VSD0001-5412a78d.webp", + "id": "sur_m1a2sepv3", + "kills": 236, + "killsPerMinute": 1.54, + "damage": 67333, + "spawns": 46, + "roadKills": 0, + "passengerAssists": 164, + "multiKills": 32, + "distanceTraveled": 19222, + "driverAssists": 102, + "vehiclesDestroyedWith": 6, + "assists": 266, + "damageTo": 50600, + "destroyed": 9, + "timeIn": 9195 + }, + { + "type": "Ground Combat", + "vehicleName": "Cheetah 1A2", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Gepard_VSD0001-d796732f.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Gepard_VSD0001-d796732f.webp", + "id": "sur_cheetah1a2", + "kills": 0, + "killsPerMinute": 0.0, + "damage": 1521, + "spawns": 1, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 737, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 9876, + "destroyed": 0, + "timeIn": 139 + }, + { + "type": "Ground Combat", + "vehicleName": "Glider 96", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Flyer60_VSD0005-1569869f.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Flyer60_VSD0005-1569869f.webp", + "id": "sur_glider96", + "kills": 6, + "killsPerMinute": 0.28, + "damage": 1648, + "spawns": 7, + "roadKills": 1, + "passengerAssists": 0, + "multiKills": 1, + "distanceTraveled": 9884, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 14447, + "destroyed": 0, + "timeIn": 1298 + }, + { + "type": "Ground Combat", + "vehicleName": "M3A3 Bradley", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_OB_VEH_Tank_Bradley_VSD0001_Dressing-66f252ca.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_OB_VEH_Tank_Bradley_VSD0001_Dressing-66f252ca.webp", + "id": "sur_bradley", + "kills": 82, + "killsPerMinute": 1.15, + "damage": 16995, + "spawns": 59, + "roadKills": 0, + "passengerAssists": 60, + "multiKills": 12, + "distanceTraveled": 14396, + "driverAssists": 14, + "vehiclesDestroyedWith": 2, + "assists": 74, + "damageTo": 30066, + "destroyed": 11, + "timeIn": 4296 + }, + { + "type": "Air Combat", + "vehicleName": "Su-57", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_SU57_VSD0001-1b5aa5ee.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_SU57_VSD0001-1b5aa5ee.webp", + "id": "air_su57", + "kills": 0, + "killsPerMinute": 0.0, + "damage": 204, + "spawns": 3, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 13458, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 1091, + "destroyed": 0, + "timeIn": 150 + }, + { + "type": "Air Combat", + "vehicleName": "F-61V", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_F16_VSD0001-5f951ec9.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_F16_VSD0001-5f951ec9.webp", + "id": "air_f61v", + "kills": 26, + "killsPerMinute": 4.53, + "damage": 6870, + "spawns": 4, + "roadKills": 26, + "passengerAssists": 0, + "multiKills": 1, + "distanceTraveled": 33186, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 204, + "destroyed": 0, + "timeIn": 344 + }, + { + "type": "Air Combat", + "vehicleName": "F-39E", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_JAS39_VSD0001-9313d717.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_JAS39_VSD0001-9313d717.webp", + "id": "air_f39e", + "kills": 16, + "killsPerMinute": 5.36, + "damage": 3016, + "spawns": 0, + "roadKills": 6, + "passengerAssists": 0, + "multiKills": 4, + "distanceTraveled": 14990, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 6196, + "destroyed": 1, + "timeIn": 179 + }, + { + "type": "Air Combat", + "vehicleName": "M77E Falchion", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "id": "air_m77efalchion", + "kills": 4, + "killsPerMinute": 0.62, + "damage": 3246, + "spawns": 7, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 14466, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 6151, + "destroyed": 4, + "timeIn": 390 + }, + { + "type": "Ground Transport", + "vehicleName": "VECTOR", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Vector_VSD0002-241efa80.webp", + "id": "sur_vector", + "kills": 0, + "killsPerMinute": 0.0, + "damage": 3, + "spawns": 1, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 1496, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 1525, + "destroyed": 2, + "timeIn": 169 + } + ], +} +sttr_list = ['CHEETAH 1A2.png', 'F-39E.png', 'F-61V.png', 'F-97 KESTREL.png', 'GE-26.png', 'GLIDER 96.png', + 'LEO A4.png', 'M1A2 SEPV3.png', 'M3A3 BRADLEY.png', 'M77E FALCHION.png', 'PANTHERA KHT.png', + 'STRF 09 A4.png', 'SU-57.png', 'UH-79 NATO.png', 'UH-79 PAX.png', 'VECTOR.png'] + +play_stat = { + "userId": 1008269664784, + "avatar": "https://eaavatarservice.akamaized.net/production/avatar/prod/userAvatar/52082828/416x416.PNG", + "userName": "Sansorano_Yume", + "id": 1004152464784, + "hasResults": True, + "platform": "pc", + "platformId": 0, + "weapons": [ + { + "type": "Machine Guns", + "weaponName": "L110", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Minimi_PKG_Factory_MED-0e29fce7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Minimi_PKG_Factory_MED-0e29fce7.webp", + "id": "mg_l110", + "kills": 74, + "damage": 15353, + "assistsDamage": 35, + "bodyKills": 61, + "headshotKills": 13, + "hipfireKills": 1, + "multiKills": 12, + "accuracy": "9.52%", + "killsPerMinute": 1.07, + "damagePerMinute": 222.29, + "headshots": "17.57%", + "hitVKills": 8.59, + "shotsHit": 636, + "shotsFired": 6683, + "scopedKills": 73, + "spawns": 39, + "timeEquipped": 4144 + }, + { + "type": "SMG-PDWs", + "weaponName": "PW5A3", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MP5MLI_PKG_Factory_MED-2d1944b7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MP5MLI_PKG_Factory_MED-2d1944b7.webp", + "id": "smg_pw5a3", + "kills": 7, + "damage": 1562, + "assistsDamage": 1, + "bodyKills": 7, + "headshotKills": 0, + "hipfireKills": 1, + "multiKills": 0, + "accuracy": "18.99%", + "killsPerMinute": 0.46, + "damagePerMinute": 102.99, + "headshots": "0.0%", + "hitVKills": 18.71, + "shotsHit": 131, + "shotsFired": 690, + "scopedKills": 6, + "spawns": 0, + "timeEquipped": 910 + }, + { + "type": "Assault Rifles", + "weaponName": "M433", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_HK433_PKG_Factory_MED-b06f02f7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_HK433_PKG_Factory_MED-b06f02f7.webp", + "id": "ar_m433", + "kills": 607, + "damage": 71600, + "assistsDamage": 284, + "bodyKills": 526, + "headshotKills": 81, + "hipfireKills": 96, + "multiKills": 78, + "accuracy": "13.12%", + "killsPerMinute": 1.71, + "damagePerMinute": 201.52, + "headshots": "13.34%", + "hitVKills": 4.84, + "shotsHit": 2939, + "shotsFired": 22402, + "scopedKills": 511, + "spawns": 390, + "timeEquipped": 21318 + }, + { + "type": "Machine Guns", + "weaponName": "RPKM", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_RPKM_PKG_Factory_MED-755b785f.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_RPKM_PKG_Factory_MED-755b785f.webp", + "id": "mg_rpkm", + "kills": 88, + "damage": 16592, + "assistsDamage": 22, + "bodyKills": 80, + "headshotKills": 8, + "hipfireKills": 6, + "multiKills": 9, + "accuracy": "24.84%", + "killsPerMinute": 1.08, + "damagePerMinute": 202.79, + "headshots": "9.09%", + "hitVKills": 12.9, + "shotsHit": 1135, + "shotsFired": 4570, + "scopedKills": 82, + "spawns": 1, + "timeEquipped": 4909 + }, + { + "type": "Shotguns", + "weaponName": "M87A1", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_590A1_PKG_Factory_MED-4b387330.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_590A1_PKG_Factory_MED-4b387330.webp", + "id": "sg_m87a1", + "kills": 351, + "damage": 22678, + "assistsDamage": 72, + "bodyKills": 166, + "headshotKills": 185, + "hipfireKills": 122, + "multiKills": 31, + "accuracy": "91.29%", + "killsPerMinute": 2.72, + "damagePerMinute": 175.44, + "headshots": "52.71%", + "hitVKills": 1.88, + "shotsHit": 660, + "shotsFired": 723, + "scopedKills": 229, + "spawns": 149, + "timeEquipped": 7756 + }, + { + "type": "Pistols", + "weaponName": "P18", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M18_PKG_Factory_MED-88261bf8.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M18_PKG_Factory_MED-88261bf8.webp", + "id": "pst_p18", + "kills": 14, + "damage": 2080, + "assistsDamage": 12, + "bodyKills": 9, + "headshotKills": 5, + "hipfireKills": 6, + "multiKills": 4, + "accuracy": "23.77%", + "killsPerMinute": 0.79, + "damagePerMinute": 116.85, + "headshots": "35.71%", + "hitVKills": 6.93, + "shotsHit": 97, + "shotsFired": 408, + "scopedKills": 8, + "spawns": 1336, + "timeEquipped": 1068 + }, + { + "type": "Carbines", + "weaponName": "M277", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_XM7_PKG_Factory_MED-26271094.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_XM7_PKG_Factory_MED-26271094.webp", + "id": "crb_x277", + "kills": 420, + "damage": 52607, + "assistsDamage": 174, + "bodyKills": 309, + "headshotKills": 111, + "hipfireKills": 17, + "multiKills": 38, + "accuracy": "17.03%", + "killsPerMinute": 1.85, + "damagePerMinute": 231.61, + "headshots": "26.43%", + "hitVKills": 4.32, + "shotsHit": 1813, + "shotsFired": 10649, + "scopedKills": 403, + "spawns": 238, + "timeEquipped": 13628 + }, + { + "type": "Assault Rifles", + "weaponName": "B36A4", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_G36_PKG_Factory_MED-fb5466ec.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_G36_PKG_Factory_MED-fb5466ec.webp", + "id": "ar_b36a4", + "kills": 1045, + "damage": 48359, + "assistsDamage": 141, + "bodyKills": 547, + "headshotKills": 498, + "hipfireKills": 44, + "multiKills": 24, + "accuracy": "19.59%", + "killsPerMinute": 3.73, + "damagePerMinute": 172.69, + "headshots": "47.66%", + "hitVKills": 3.22, + "shotsHit": 3363, + "shotsFired": 17165, + "scopedKills": 1001, + "spawns": 172, + "timeEquipped": 16802 + }, + { + "type": "Assault Rifles", + "weaponName": "L85A3", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_L85A3_PKG_Factory_MED-9bd0deaa.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_L85A3_PKG_Factory_MED-9bd0deaa.webp", + "id": "ar_l85a3", + "kills": 785, + "damage": 16153, + "assistsDamage": 60, + "bodyKills": 315, + "headshotKills": 470, + "hipfireKills": 8, + "multiKills": 4, + "accuracy": "28.29%", + "killsPerMinute": 7.26, + "damagePerMinute": 149.47, + "headshots": "59.87%", + "hitVKills": 2.05, + "shotsHit": 1609, + "shotsFired": 5687, + "scopedKills": 777, + "spawns": 111, + "timeEquipped": 6484 + }, + { + "type": "Rifles", + "weaponName": "M2010 ESR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M2010ESR_PKG_Factory_MED-f94fdae6.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M2010ESR_PKG_Factory_MED-f94fdae6.webp", + "id": "snp_m2010", + "kills": 553, + "damage": 53403, + "assistsDamage": 32, + "bodyKills": 150, + "headshotKills": 403, + "hipfireKills": 200, + "multiKills": 51, + "accuracy": "47.56%", + "killsPerMinute": 2.49, + "damagePerMinute": 240.36, + "headshots": "72.88%", + "hitVKills": 1.37, + "shotsHit": 760, + "shotsFired": 1598, + "scopedKills": 353, + "spawns": 81, + "timeEquipped": 13331 + }, + { + "type": "Shotguns", + "weaponName": "M1014", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M1014_PKG_Factory_MED-e011854a.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M1014_PKG_Factory_MED-e011854a.webp", + "id": "sg_m1014", + "kills": 142, + "damage": 15520, + "assistsDamage": 19, + "bodyKills": 127, + "headshotKills": 15, + "hipfireKills": 138, + "multiKills": 11, + "accuracy": "76.98%", + "killsPerMinute": 4.06, + "damagePerMinute": 444.27, + "headshots": "10.56%", + "hitVKills": 2.8, + "shotsHit": 398, + "shotsFired": 517, + "scopedKills": 4, + "spawns": 31, + "timeEquipped": 2096 + }, + { + "type": "Carbines", + "weaponName": "AK-205", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_AK205_PKG_Factory_MED-6d376081.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_AK205_PKG_Factory_MED-6d376081.webp", + "id": "crb_ak205", + "kills": 30, + "damage": 5519, + "assistsDamage": 29, + "bodyKills": 25, + "headshotKills": 5, + "hipfireKills": 6, + "multiKills": 0, + "accuracy": "12.01%", + "killsPerMinute": 0.76, + "damagePerMinute": 139.49, + "headshots": "16.67%", + "hitVKills": 12.8, + "shotsHit": 384, + "shotsFired": 3197, + "scopedKills": 24, + "spawns": 26, + "timeEquipped": 2374 + }, + { + "type": "DMRs", + "weaponName": "SVK-8.6", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SVCh_PKG_Factory_MED-bb06d385.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SVCh_PKG_Factory_MED-bb06d385.webp", + "id": "dmr_svk86", + "kills": 262, + "damage": 42653, + "assistsDamage": 95, + "bodyKills": 144, + "headshotKills": 118, + "hipfireKills": 2, + "multiKills": 36, + "accuracy": "33.32%", + "killsPerMinute": 1.31, + "damagePerMinute": 212.95, + "headshots": "45.04%", + "hitVKills": 3.19, + "shotsHit": 837, + "shotsFired": 2512, + "scopedKills": 260, + "spawns": 76, + "timeEquipped": 12018 + }, + { + "type": "SMG-PDWs", + "weaponName": "SGX", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MPX_PKG_Factory_MED-e822f017.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MPX_PKG_Factory_MED-e822f017.webp", + "id": "smg_sgx", + "kills": 9788, + "damage": 526470, + "assistsDamage": 7, + "bodyKills": 7110, + "headshotKills": 2678, + "hipfireKills": 3088, + "multiKills": 85, + "accuracy": "54.83%", + "killsPerMinute": 56.3, + "damagePerMinute": 3028.3, + "headshots": "27.36%", + "hitVKills": 2.37, + "shotsHit": 23240, + "shotsFired": 42387, + "scopedKills": 6700, + "spawns": 65, + "timeEquipped": 10431 + }, + { + "type": "DMRs", + "weaponName": "LMR27", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_ARADMR_PKG_Factory_MED-dfe224de.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_ARADMR_PKG_Factory_MED-dfe224de.webp", + "id": "dmr_lmr27", + "kills": 5, + "damage": 765, + "assistsDamage": 2, + "bodyKills": 5, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "30.0%", + "killsPerMinute": 1.18, + "damagePerMinute": 180.0, + "headshots": "0.0%", + "hitVKills": 7.2, + "shotsHit": 36, + "shotsFired": 120, + "scopedKills": 5, + "spawns": 3, + "timeEquipped": 255 + }, + { + "type": "Carbines", + "weaponName": "QBZ-192", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_QBZ192_PKG_Factory_MED-dc0a546b.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_QBZ192_PKG_Factory_MED-dc0a546b.webp", + "id": "crb_qbz192", + "kills": 75, + "damage": 10219, + "assistsDamage": 52, + "bodyKills": 72, + "headshotKills": 3, + "hipfireKills": 4, + "multiKills": 7, + "accuracy": "12.36%", + "killsPerMinute": 1.08, + "damagePerMinute": 147.64, + "headshots": "4.0%", + "hitVKills": 3.83, + "shotsHit": 287, + "shotsFired": 2322, + "scopedKills": 71, + "spawns": 104, + "timeEquipped": 4153 + }, + { + "type": "Carbines", + "weaponName": "M417 A2", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_HK417A2_PKG_Factory_MED-494ffe6e.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_HK417A2_PKG_Factory_MED-494ffe6e.webp", + "id": "crb_m417a2", + "kills": 1942, + "damage": 52408, + "assistsDamage": 156, + "bodyKills": 638, + "headshotKills": 1304, + "hipfireKills": 103, + "multiKills": 54, + "accuracy": "24.49%", + "killsPerMinute": 6.87, + "damagePerMinute": 185.47, + "headshots": "67.15%", + "hitVKills": 1.78, + "shotsHit": 3464, + "shotsFired": 14143, + "scopedKills": 1839, + "spawns": 266, + "timeEquipped": 16954 + }, + { + "type": "Machine Guns", + "weaponName": "DRS-IAR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M27IAR_PKG_Factory_MED-ae6675cd.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M27IAR_PKG_Factory_MED-ae6675cd.webp", + "id": "mg_drsiar", + "kills": 729, + "damage": 83389, + "assistsDamage": 45, + "bodyKills": 599, + "headshotKills": 130, + "hipfireKills": 115, + "multiKills": 61, + "accuracy": "28.88%", + "killsPerMinute": 5.56, + "damagePerMinute": 636.4, + "headshots": "17.83%", + "hitVKills": 4.49, + "shotsHit": 3270, + "shotsFired": 11323, + "scopedKills": 614, + "spawns": 77, + "timeEquipped": 7862 + }, + { + "type": "Assault Rifles", + "weaponName": "KORD 6P67", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_6P67_PKG_Factory_MED-827b9414.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_6P67_PKG_Factory_MED-827b9414.webp", + "id": "ar_kord6p67", + "kills": 502, + "damage": 64820, + "assistsDamage": 98, + "bodyKills": 429, + "headshotKills": 73, + "hipfireKills": 42, + "multiKills": 107, + "accuracy": "25.85%", + "killsPerMinute": 2.55, + "damagePerMinute": 328.9, + "headshots": "14.54%", + "hitVKills": 7.41, + "shotsHit": 3722, + "shotsFired": 14397, + "scopedKills": 460, + "spawns": 178, + "timeEquipped": 11825 + }, + { + "type": "SMG-PDWs", + "weaponName": "USG-90", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_P90_PKG_Factory_MED-2ab1db64.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_P90_PKG_Factory_MED-2ab1db64.webp", + "id": "smg_usg90", + "kills": 10, + "damage": 1217, + "assistsDamage": 4, + "bodyKills": 6, + "headshotKills": 4, + "hipfireKills": 3, + "multiKills": 1, + "accuracy": "16.58%", + "killsPerMinute": 0.75, + "damagePerMinute": 91.39, + "headshots": "40.0%", + "hitVKills": 6.6, + "shotsHit": 66, + "shotsFired": 398, + "scopedKills": 7, + "spawns": 0, + "timeEquipped": 799 + }, + { + "type": "Carbines", + "weaponName": "M4A1", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M4A1_PKG_Factory_MED-34529a82.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M4A1_PKG_Factory_MED-34529a82.webp", + "id": "crb_m4a1", + "kills": 2309, + "damage": 36071, + "assistsDamage": 141, + "bodyKills": 730, + "headshotKills": 1579, + "hipfireKills": 92, + "multiKills": 42, + "accuracy": "26.14%", + "killsPerMinute": 13.41, + "damagePerMinute": 209.53, + "headshots": "68.38%", + "hitVKills": 1.6, + "shotsHit": 3691, + "shotsFired": 14118, + "scopedKills": 2217, + "spawns": 199, + "timeEquipped": 10329 + }, + { + "type": "Machine Guns", + "weaponName": "KTS100 MK8", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Ultimax_PKG_Factory_MED-a8ebb482.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Ultimax_PKG_Factory_MED-a8ebb482.webp", + "id": "mg_kts100mk8", + "kills": 4524, + "damage": 25524, + "assistsDamage": 76, + "bodyKills": 1865, + "headshotKills": 2659, + "hipfireKills": 54, + "multiKills": 23, + "accuracy": "41.99%", + "killsPerMinute": 19.76, + "damagePerMinute": 111.48, + "headshots": "58.78%", + "hitVKills": 1.38, + "shotsHit": 6236, + "shotsFired": 14851, + "scopedKills": 4470, + "spawns": 88, + "timeEquipped": 13737 + }, + { + "type": "Pistols", + "weaponName": "M45A1", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M45A1_PKG_Factory_MED-8c41691b.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M45A1_PKG_Factory_MED-8c41691b.webp", + "id": "pst_m45a1", + "kills": 228, + "damage": 252, + "assistsDamage": 0, + "bodyKills": 30, + "headshotKills": 198, + "hipfireKills": 37, + "multiKills": 2, + "accuracy": "211.11%", + "killsPerMinute": 93.7, + "damagePerMinute": 103.56, + "headshots": "86.84%", + "hitVKills": 1.0, + "shotsHit": 228, + "shotsFired": 108, + "scopedKills": 191, + "spawns": 69, + "timeEquipped": 146 + }, + { + "type": "SMG-PDWs", + "weaponName": "KV9", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Vector_PKG_Factory_MED-b5631ed7.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Vector_PKG_Factory_MED-b5631ed7.webp", + "id": "smg_kv9", + "kills": 169, + "damage": 21081, + "assistsDamage": 83, + "bodyKills": 148, + "headshotKills": 21, + "hipfireKills": 58, + "multiKills": 18, + "accuracy": "16.2%", + "killsPerMinute": 1.42, + "damagePerMinute": 177.47, + "headshots": "12.43%", + "hitVKills": 5.8, + "shotsHit": 981, + "shotsFired": 6057, + "scopedKills": 111, + "spawns": 142, + "timeEquipped": 7127 + }, + { + "type": "Assault Rifles", + "weaponName": "SOR-556 Mk2", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SCARL_PKG_Factory_MED-b44467bb.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SCARL_PKG_Factory_MED-b44467bb.webp", + "id": "ar_sor556mk2", + "kills": 451, + "damage": 54559, + "assistsDamage": 175, + "bodyKills": 367, + "headshotKills": 84, + "hipfireKills": 23, + "multiKills": 47, + "accuracy": "20.04%", + "killsPerMinute": 2.27, + "damagePerMinute": 274.14, + "headshots": "18.63%", + "hitVKills": 4.89, + "shotsHit": 2205, + "shotsFired": 11002, + "scopedKills": 428, + "spawns": 139, + "timeEquipped": 11941 + }, + { + "type": "SMG-PDWs", + "weaponName": "PW7A2", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MP7A2_PKG_Factory_MED-406bc965.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MP7A2_PKG_Factory_MED-406bc965.webp", + "id": "smg_pw7a2", + "kills": 216, + "damage": 20576, + "assistsDamage": 15, + "bodyKills": 201, + "headshotKills": 15, + "hipfireKills": 75, + "multiKills": 54, + "accuracy": "26.43%", + "killsPerMinute": 5.13, + "damagePerMinute": 488.55, + "headshots": "6.94%", + "hitVKills": 6.2, + "shotsHit": 1339, + "shotsFired": 5066, + "scopedKills": 141, + "spawns": 4, + "timeEquipped": 2527 + }, + { + "type": "Machine Guns", + "weaponName": "M123K", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MG4K_PKG_Factory_MED-cc064690.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MG4K_PKG_Factory_MED-cc064690.webp", + "id": "mg_m123k", + "kills": 84, + "damage": 15303, + "assistsDamage": 40, + "bodyKills": 75, + "headshotKills": 9, + "hipfireKills": 22, + "multiKills": 8, + "accuracy": "12.66%", + "killsPerMinute": 1.03, + "damagePerMinute": 187.92, + "headshots": "10.71%", + "hitVKills": 11.15, + "shotsHit": 937, + "shotsFired": 7403, + "scopedKills": 62, + "spawns": 63, + "timeEquipped": 4886 + }, + { + "type": "Pistols", + "weaponName": "M44", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_RagingHunter_PKG_Factory_MED-f9773307.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_RagingHunter_PKG_Factory_MED-f9773307.webp", + "id": "pst_m44", + "kills": 18, + "damage": 4263, + "assistsDamage": 14, + "bodyKills": 12, + "headshotKills": 6, + "hipfireKills": 4, + "multiKills": 0, + "accuracy": "34.78%", + "killsPerMinute": 0.27, + "damagePerMinute": 63.98, + "headshots": "33.33%", + "hitVKills": 5.78, + "shotsHit": 104, + "shotsFired": 299, + "scopedKills": 14, + "spawns": 854, + "timeEquipped": 3998 + }, + { + "type": "Machine Guns", + "weaponName": "M250", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M250_PKG_Factory_MED-6e230a71.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M250_PKG_Factory_MED-6e230a71.webp", + "id": "mg_xm250", + "kills": 328, + "damage": 38530, + "assistsDamage": 90, + "bodyKills": 289, + "headshotKills": 39, + "hipfireKills": 27, + "multiKills": 58, + "accuracy": "18.11%", + "killsPerMinute": 2.33, + "damagePerMinute": 273.68, + "headshots": "11.89%", + "hitVKills": 4.3, + "shotsHit": 1412, + "shotsFired": 7796, + "scopedKills": 301, + "spawns": 166, + "timeEquipped": 8447 + }, + { + "type": "SMG-PDWs", + "weaponName": "UMG-40", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_UMP40_PKG_Factory_MED-22afa646.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_UMP40_PKG_Factory_MED-22afa646.webp", + "id": "smg_umg40", + "kills": 4, + "damage": 926, + "assistsDamage": 1, + "bodyKills": 4, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 1, + "accuracy": "24.37%", + "killsPerMinute": 0.43, + "damagePerMinute": 98.51, + "headshots": "0.0%", + "hitVKills": 21.75, + "shotsHit": 87, + "shotsFired": 357, + "scopedKills": 4, + "spawns": 3, + "timeEquipped": 564 + }, + { + "type": "Assault Rifles", + "weaponName": "TR-7", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_Tavor7_PKG_Factory_MED-e682f267.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_Tavor7_PKG_Factory_MED-e682f267.webp", + "id": "ar_tr7", + "kills": 616, + "damage": 68498, + "assistsDamage": 107, + "bodyKills": 474, + "headshotKills": 142, + "hipfireKills": 143, + "multiKills": 55, + "accuracy": "16.89%", + "killsPerMinute": 2.46, + "damagePerMinute": 273.5, + "headshots": "23.05%", + "hitVKills": 3.68, + "shotsHit": 2268, + "shotsFired": 13428, + "scopedKills": 473, + "spawns": 252, + "timeEquipped": 15027 + }, + { + "type": "SMG-PDWs", + "weaponName": "SL9", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_APDW_PKG_Factory_MED-c4d1b829.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_APDW_PKG_Factory_MED-c4d1b829.webp", + "id": "smg_sl9", + "kills": 376, + "damage": 37358, + "assistsDamage": 17, + "bodyKills": 316, + "headshotKills": 60, + "hipfireKills": 19, + "multiKills": 77, + "accuracy": "21.84%", + "killsPerMinute": 4.86, + "damagePerMinute": 483.08, + "headshots": "15.96%", + "hitVKills": 4.85, + "shotsHit": 1824, + "shotsFired": 8350, + "scopedKills": 357, + "spawns": 25, + "timeEquipped": 4640 + }, + { + "type": "Machine Guns", + "weaponName": "M240L", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M240L_PKG_Factory_MED-1fa18e0c.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M240L_PKG_Factory_MED-1fa18e0c.webp", + "id": "mg_m240l", + "kills": 45, + "damage": 4029, + "assistsDamage": 0, + "bodyKills": 40, + "headshotKills": 5, + "hipfireKills": 3, + "multiKills": 3, + "accuracy": "31.3%", + "killsPerMinute": 7.03, + "damagePerMinute": 629.53, + "headshots": "11.11%", + "hitVKills": 3.31, + "shotsHit": 149, + "shotsFired": 476, + "scopedKills": 42, + "spawns": 1, + "timeEquipped": 384 + }, + { + "type": "SMG-PDWs", + "weaponName": "SCW-10", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_APC10_PKG_Factory_MED-716a97fb.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_APC10_PKG_Factory_MED-716a97fb.webp", + "id": "smg_scw10", + "kills": 571, + "damage": 61171, + "assistsDamage": 139, + "bodyKills": 495, + "headshotKills": 76, + "hipfireKills": 48, + "multiKills": 105, + "accuracy": "18.37%", + "killsPerMinute": 2.47, + "damagePerMinute": 264.68, + "headshots": "13.31%", + "hitVKills": 4.04, + "shotsHit": 2308, + "shotsFired": 12565, + "scopedKills": 523, + "spawns": 232, + "timeEquipped": 13867 + }, + { + "type": "Assault Rifles", + "weaponName": "NVO-228E", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_ACE32_PKG_Factory_MED-39a97220.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_ACE32_PKG_Factory_MED-39a97220.webp", + "id": "ar_nvo228e", + "kills": 960, + "damage": 61885, + "assistsDamage": 101, + "bodyKills": 611, + "headshotKills": 349, + "hipfireKills": 72, + "multiKills": 39, + "accuracy": "28.84%", + "killsPerMinute": 5.78, + "damagePerMinute": 372.69, + "headshots": "36.35%", + "hitVKills": 2.44, + "shotsHit": 2344, + "shotsFired": 8128, + "scopedKills": 888, + "spawns": 114, + "timeEquipped": 9963 + }, + { + "type": "Machine Guns", + "weaponName": "M/60", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M60E6_PKG_Factory_MED-e600bb28.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_M60E6_PKG_Factory_MED-e600bb28.webp", + "id": "mg_m60", + "kills": 5, + "damage": 1191, + "assistsDamage": 5, + "bodyKills": 5, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 1, + "accuracy": "6.74%", + "killsPerMinute": 0.47, + "damagePerMinute": 112.01, + "headshots": "0.0%", + "hitVKills": 11.8, + "shotsHit": 59, + "shotsFired": 876, + "scopedKills": 5, + "spawns": 1, + "timeEquipped": 638 + }, + { + "type": "Rifles", + "weaponName": "PSR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MRAD_PKG_Factory_MED-5035ce99.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MRAD_PKG_Factory_MED-5035ce99.webp", + "id": "snp_psr", + "kills": 39, + "damage": 7457, + "assistsDamage": 11, + "bodyKills": 17, + "headshotKills": 22, + "hipfireKills": 22, + "multiKills": 0, + "accuracy": "30.75%", + "killsPerMinute": 0.49, + "damagePerMinute": 94.61, + "headshots": "56.41%", + "hitVKills": 3.56, + "shotsHit": 139, + "shotsFired": 452, + "scopedKills": 17, + "spawns": 9, + "timeEquipped": 4729 + }, + { + "type": "DMRs", + "weaponName": "SVDM", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SVDM_PKG_Factory_MED-b6c9aa50.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SVDM_PKG_Factory_MED-b6c9aa50.webp", + "id": "dmr_svdm", + "kills": 3, + "damage": 475, + "assistsDamage": 3, + "bodyKills": 1, + "headshotKills": 2, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "20.0%", + "killsPerMinute": 0.28, + "damagePerMinute": 44.88, + "headshots": "66.67%", + "hitVKills": 6.33, + "shotsHit": 19, + "shotsFired": 95, + "scopedKills": 3, + "spawns": 1, + "timeEquipped": 635 + }, + { + "type": "Assault Rifles", + "weaponName": "AK4D", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_G3A4_PKG_Factory_MED-0575cf00.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_G3A4_PKG_Factory_MED-0575cf00.webp", + "id": "ar_ak4d", + "kills": 155, + "damage": 17827, + "assistsDamage": 48, + "bodyKills": 147, + "headshotKills": 8, + "hipfireKills": 6, + "multiKills": 23, + "accuracy": "20.76%", + "killsPerMinute": 1.53, + "damagePerMinute": 176.24, + "headshots": "5.16%", + "hitVKills": 4.49, + "shotsHit": 696, + "shotsFired": 3353, + "scopedKills": 149, + "spawns": 80, + "timeEquipped": 6069 + }, + { + "type": "Carbines", + "weaponName": "SOR-300SC", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SCARSC_PKG_Factory_MED-7a6a50ff.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SCARSC_PKG_Factory_MED-7a6a50ff.webp", + "id": "crb_sor300sc", + "kills": 5, + "damage": 1016, + "assistsDamage": 4, + "bodyKills": 4, + "headshotKills": 1, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "12.99%", + "killsPerMinute": 0.24, + "damagePerMinute": 47.77, + "headshots": "20.0%", + "hitVKills": 20.0, + "shotsHit": 100, + "shotsFired": 770, + "scopedKills": 5, + "spawns": 0, + "timeEquipped": 1276 + }, + { + "type": "Carbines", + "weaponName": "SG 553R", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SIG553R_PKG_Factory_MED-afc2dfa8.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_SIG553R_PKG_Factory_MED-afc2dfa8.webp", + "id": "crb_sg553r", + "kills": 4207, + "damage": 30073, + "assistsDamage": 119, + "bodyKills": 3204, + "headshotKills": 1003, + "hipfireKills": 1264, + "multiKills": 37, + "accuracy": "45.09%", + "killsPerMinute": 21.64, + "damagePerMinute": 154.71, + "headshots": "23.84%", + "hitVKills": 1.16, + "shotsHit": 4895, + "shotsFired": 10855, + "scopedKills": 2943, + "spawns": 200, + "timeEquipped": 11663 + }, + { + "type": "Carbines", + "weaponName": "GRT-BC", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_MSBSGROTB_PKG_Factory_MED-25acf006.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MSBSGROTB_PKG_Factory_MED-25acf006.webp", + "id": "crb_grtbc", + "kills": 22, + "damage": 3216, + "assistsDamage": 20, + "bodyKills": 17, + "headshotKills": 5, + "hipfireKills": 7, + "multiKills": 1, + "accuracy": "12.16%", + "killsPerMinute": 0.76, + "damagePerMinute": 111.15, + "headshots": "22.73%", + "hitVKills": 7.95, + "shotsHit": 175, + "shotsFired": 1439, + "scopedKills": 15, + "spawns": 21, + "timeEquipped": 1736 + }, + { + "type": "Shotguns", + "weaponName": "18.5KS-K", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_185KSK_PKG_Factory_MED-432c353f.webp", + "altImage": "https://cdn.gametools.network/weapons/bf6/white/T_UI_MSBSGROTB_PKG_Factory_MED-25acf006.webp", + "id": "sg_185ksk", + "kills": 17, + "damage": 2390, + "assistsDamage": 9, + "bodyKills": 15, + "headshotKills": 2, + "hipfireKills": 17, + "multiKills": 1, + "accuracy": "22.83%", + "killsPerMinute": 0.87, + "damagePerMinute": 122.46, + "headshots": "11.76%", + "hitVKills": 2.94, + "shotsHit": 50, + "shotsFired": 219, + "scopedKills": 0, + "spawns": 30, + "timeEquipped": 1171 + }, + { + "type": "Pistols", + "weaponName": "ES 5.7", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M18_PKG_Factory_MED-88261bf8.webp", + "id": "pst_es57", + "kills": 9183, + "damage": 565421, + "assistsDamage": 7, + "bodyKills": 3568, + "headshotKills": 5615, + "hipfireKills": 2930, + "multiKills": 60, + "accuracy": "105.3%", + "killsPerMinute": 51.52, + "damagePerMinute": 3172.07, + "headshots": "61.15%", + "hitVKills": 2.51, + "shotsHit": 23019, + "shotsFired": 21860, + "scopedKills": 6253, + "spawns": 715, + "timeEquipped": 10695 + }, + { + "type": "DMRs", + "weaponName": "M39 EMR", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_SVCh_PKG_Factory_MED-bb06d385.webp", + "id": "dmr_m39emr", + "kills": 0, + "damage": 0, + "assistsDamage": 0, + "bodyKills": 0, + "headshotKills": 0, + "hipfireKills": 0, + "multiKills": 0, + "accuracy": "0.0%", + "killsPerMinute": 0.0, + "damagePerMinute": 0.0, + "headshots": "0.0%", + "hitVKills": 0.0, + "shotsHit": 0, + "shotsFired": 0, + "scopedKills": 0, + "spawns": 0, + "timeEquipped": 45 + }, + { + "type": "Rifles", + "weaponName": "SV-98", + "image": "https://cdn.gametools.network/weapons/bf6/T_UI_M2010ESR_PKG_Factory_MED-f94fdae6.webp", + "id": "snp_sv98", + "kills": 2, + "damage": 334, + "assistsDamage": 1, + "bodyKills": 1, + "headshotKills": 1, + "hipfireKills": 1, + "multiKills": 0, + "accuracy": "25.93%", + "killsPerMinute": 0.3, + "damagePerMinute": 50.1, + "headshots": "50.0%", + "hitVKills": 3.5, + "shotsHit": 7, + "shotsFired": 27, + "scopedKills": 1, + "spawns": 1, + "timeEquipped": 400 + } + ], + "vehicles": [ + { + "type": "Air Combat", + "vehicleName": "Panthera KHT", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Eurocopter_VSD0001-8003028d.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Eurocopter_VSD0001-8003028d.webp", + "id": "air_panthera", + "kills": 166, + "killsPerMinute": 7.07, + "damage": 27206, + "spawns": 6, + "roadKills": 7, + "passengerAssists": 13, + "multiKills": 5, + "distanceTraveled": 50779, + "driverAssists": 1, + "vehiclesDestroyedWith": 7, + "assists": 14, + "damageTo": 3918, + "destroyed": 0, + "timeIn": 1408 + }, + { + "type": "Air Combat", + "vehicleName": "M77E Falchion", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "id": "air_m77efalchio", + "kills": 0, + "killsPerMinute": 0, + "damage": 0, + "spawns": 0, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 0, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 0, + "destroyed": 0, + "timeIn": 0 + }, + { + "type": "Ground Combat", + "vehicleName": "Leo A4", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Leopard_VSD0001-f8da51ee.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Leopard_VSD0001-f8da51ee.webp", + "id": "sur_leoa4", + "kills": 22, + "killsPerMinute": 0.74, + "damage": 19307, + "spawns": 8, + "roadKills": 1, + "passengerAssists": 1, + "multiKills": 2, + "distanceTraveled": 6115, + "driverAssists": 13, + "vehiclesDestroyedWith": 1, + "assists": 14, + "damageTo": 43760, + "destroyed": 6, + "timeIn": 1789 + }, + { + "type": "Ground Combat", + "vehicleName": "Strf 09 A4", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_CV90_VSD0001-acd942b6.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_CV90_VSD0001-acd942b6.webp", + "id": "sur_strf09a4", + "kills": 140, + "killsPerMinute": 1.76, + "damage": 25699, + "spawns": 196, + "roadKills": 0, + "passengerAssists": 52, + "multiKills": 27, + "distanceTraveled": 12701, + "driverAssists": 41, + "vehiclesDestroyedWith": 2, + "assists": 93, + "damageTo": 20875, + "destroyed": 1, + "timeIn": 4770 + }, + { + "type": "Ground Combat", + "vehicleName": "M1A2 SEPv3", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Abrams_VSD0001-5412a78d.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Abrams_VSD0001-5412a78d.webp", + "id": "sur_m1a2sepv3", + "kills": 236, + "killsPerMinute": 1.54, + "damage": 67333, + "spawns": 46, + "roadKills": 0, + "passengerAssists": 164, + "multiKills": 32, + "distanceTraveled": 19222, + "driverAssists": 102, + "vehiclesDestroyedWith": 6, + "assists": 266, + "damageTo": 50600, + "destroyed": 9, + "timeIn": 9195 + }, + { + "type": "Ground Combat", + "vehicleName": "Cheetah 1A2", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Gepard_VSD0001-d796732f.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Gepard_VSD0001-d796732f.webp", + "id": "sur_cheetah1a2", + "kills": 0, + "killsPerMinute": 0.0, + "damage": 1521, + "spawns": 1, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 737, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 9876, + "destroyed": 0, + "timeIn": 139 + }, + { + "type": "Ground Combat", + "vehicleName": "Glider 96", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Flyer60_VSD0005-1569869f.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_Flyer60_VSD0005-1569869f.webp", + "id": "sur_glider96", + "kills": 6, + "killsPerMinute": 0.28, + "damage": 1648, + "spawns": 7, + "roadKills": 1, + "passengerAssists": 0, + "multiKills": 1, + "distanceTraveled": 9884, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 14447, + "destroyed": 0, + "timeIn": 1298 + }, + { + "type": "Ground Combat", + "vehicleName": "M3A3 Bradley", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_OB_VEH_Tank_Bradley_VSD0001_Dressing-66f252ca.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_OB_VEH_Tank_Bradley_VSD0001_Dressing-66f252ca.webp", + "id": "sur_bradley", + "kills": 82, + "killsPerMinute": 1.15, + "damage": 16995, + "spawns": 59, + "roadKills": 0, + "passengerAssists": 60, + "multiKills": 12, + "distanceTraveled": 14396, + "driverAssists": 14, + "vehiclesDestroyedWith": 2, + "assists": 74, + "damageTo": 30066, + "destroyed": 11, + "timeIn": 4296 + }, + { + "type": "Air Combat", + "vehicleName": "Su-57", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_SU57_VSD0001-1b5aa5ee.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_SU57_VSD0001-1b5aa5ee.webp", + "id": "air_su57", + "kills": 0, + "killsPerMinute": 0.0, + "damage": 204, + "spawns": 3, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 13458, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 1091, + "destroyed": 0, + "timeIn": 150 + }, + { + "type": "Air Combat", + "vehicleName": "F-61V", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_F16_VSD0001-5f951ec9.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_F16_VSD0001-5f951ec9.webp", + "id": "air_f61v", + "kills": 26, + "killsPerMinute": 4.53, + "damage": 6870, + "spawns": 4, + "roadKills": 26, + "passengerAssists": 0, + "multiKills": 1, + "distanceTraveled": 33186, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 204, + "destroyed": 0, + "timeIn": 344 + }, + { + "type": "Air Combat", + "vehicleName": "F-39E", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_JAS39_VSD0001-9313d717.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_JAS39_VSD0001-9313d717.webp", + "id": "air_f39e", + "kills": 16, + "killsPerMinute": 5.36, + "damage": 3016, + "spawns": 0, + "roadKills": 6, + "passengerAssists": 0, + "multiKills": 4, + "distanceTraveled": 14990, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 6196, + "destroyed": 1, + "timeIn": 179 + }, + { + "type": "Air Combat", + "vehicleName": "M77E Falchion", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "altImage": "https://cdn.gametools.network/vehicles/bf6/white/T_UI_MDV_AH64E_VSD0001-dd0a7df6.webp", + "id": "air_m77efalchion", + "kills": 4, + "killsPerMinute": 0.62, + "damage": 3246, + "spawns": 7, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 14466, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 6151, + "destroyed": 4, + "timeIn": 390 + }, + { + "type": "Ground Transport", + "vehicleName": "VECTOR", + "image": "https://cdn.gametools.network/vehicles/bf6/T_UI_MDV_Vector_VSD0002-241efa80.webp", + "id": "sur_vector", + "kills": 0, + "killsPerMinute": 0.0, + "damage": 3, + "spawns": 1, + "roadKills": 0, + "passengerAssists": 0, + "multiKills": 0, + "distanceTraveled": 1496, + "driverAssists": 0, + "vehiclesDestroyedWith": 0, + "assists": 0, + "damageTo": 1525, + "destroyed": 2, + "timeIn": 169 + } + ], + "weaponGroups": [ + { + "groupName": "Rifles", + "id": "snp", + "kills": 1317, + "damage": 134277, + "assistsDamage": 86, + "bodyKills": 524, + "headshotKills": 793, + "hipfireKills": 255, + "multiKills": 70, + "accuracy": "52.64%", + "killsPerMinute": 2.88, + "damagePerMinute": 293.22, + "headshots": "60.21%", + "hitVKills": 1.42, + "shotsHit": 1866, + "shotsFired": 3545, + "scopedKills": 1062, + "spawns": 190, + "timeEquipped": 27476 + }, + { + "groupName": "Carbines", + "id": "crb", + "kills": 9010, + "damage": 191129, + "assistsDamage": 695, + "bodyKills": 4999, + "headshotKills": 4011, + "hipfireKills": 1493, + "multiKills": 179, + "accuracy": "25.76%", + "killsPerMinute": 8.7, + "damagePerMinute": 184.63, + "headshots": "44.52%", + "hitVKills": 1.64, + "shotsHit": 14809, + "shotsFired": 57493, + "scopedKills": 7517, + "spawns": 1054, + "timeEquipped": 62113 + }, + { + "groupName": "Machine Guns", + "id": "mg", + "kills": 5878, + "damage": 200011, + "assistsDamage": 313, + "bodyKills": 3015, + "headshotKills": 2863, + "hipfireKills": 228, + "multiKills": 175, + "accuracy": "25.61%", + "killsPerMinute": 7.82, + "damagePerMinute": 266.14, + "headshots": "48.71%", + "hitVKills": 2.35, + "shotsHit": 13838, + "shotsFired": 54035, + "scopedKills": 5650, + "spawns": 436, + "timeEquipped": 45092 + }, + { + "groupName": "Shotguns", + "id": "sg", + "kills": 510, + "damage": 40588, + "assistsDamage": 100, + "bodyKills": 308, + "headshotKills": 202, + "hipfireKills": 277, + "multiKills": 43, + "accuracy": "75.94%", + "killsPerMinute": 2.77, + "damagePerMinute": 220.33, + "headshots": "39.61%", + "hitVKills": 2.17, + "shotsHit": 1108, + "shotsFired": 1459, + "scopedKills": 233, + "spawns": 210, + "timeEquipped": 11053 + }, + { + "groupName": "Assault Rifles", + "id": "ar", + "kills": 5121, + "damage": 403701, + "assistsDamage": 1014, + "bodyKills": 3416, + "headshotKills": 1705, + "hipfireKills": 434, + "multiKills": 377, + "accuracy": "20.04%", + "killsPerMinute": 3.09, + "damagePerMinute": 243.61, + "headshots": "33.29%", + "hitVKills": 3.74, + "shotsHit": 19146, + "shotsFired": 95562, + "scopedKills": 4687, + "spawns": 1436, + "timeEquipped": 99429 + }, + { + "groupName": "SMG-PDWs", + "id": "smg", + "kills": 11141, + "damage": 670361, + "assistsDamage": 267, + "bodyKills": 8287, + "headshotKills": 2854, + "hipfireKills": 3292, + "multiKills": 341, + "accuracy": "39.51%", + "killsPerMinute": 16.36, + "damagePerMinute": 984.26, + "headshots": "25.62%", + "hitVKills": 2.69, + "shotsHit": 29976, + "shotsFired": 75870, + "scopedKills": 7849, + "spawns": 471, + "timeEquipped": 40865 + }, + { + "groupName": "DMRs", + "id": "dmr", + "kills": 270, + "damage": 43893, + "assistsDamage": 100, + "bodyKills": 150, + "headshotKills": 120, + "hipfireKills": 2, + "multiKills": 36, + "accuracy": "32.71%", + "killsPerMinute": 1.25, + "damagePerMinute": 203.32, + "headshots": "44.44%", + "hitVKills": 3.3, + "shotsHit": 892, + "shotsFired": 2727, + "scopedKills": 268, + "spawns": 80, + "timeEquipped": 12953 + } + ], + "vehicleGroups": [ + { + "groupName": "Air Combat", + "id": "air", + "kills": 228, + "killsPerMinute": 3.74, + "damage": 52741, + "spawns": 32, + "roadKills": 43, + "passengerAssists": 13, + "multiKills": 12, + "distanceTraveled": 187925, + "driverAssists": 7, + "vehiclesDestroyedWith": 9, + "assists": 20, + "damageTo": 37134, + "destroyed": 14, + "timeIn": 3653 + }, + { + "groupName": "Ground Combat", + "id": "sur", + "kills": 486, + "killsPerMinute": 1.33, + "damage": 132612, + "spawns": 326, + "roadKills": 2, + "passengerAssists": 277, + "multiKills": 74, + "distanceTraveled": 66653, + "driverAssists": 170, + "vehiclesDestroyedWith": 11, + "assists": 447, + "damageTo": 175787, + "destroyed": 31, + "timeIn": 21931 + } + ], + "classes": [ + { + "className": "Assault", + "image": "https://cdn.gametools.network/classes/bf6/white/Assault.svg", + "altImage": "https://cdn.gametools.network/classes/bf6/black/Assault.svg", + "id": "assault", + "kills": 3691, + "deaths": 1168, + "kpm": 1.65, + "killDeath": 3.16, + "spawns": 1276, + "score": 938610, + "assists": 1501, + "secondsPlayed": 134495 + }, + { + "className": "Engineer", + "image": "https://cdn.gametools.network/classes/bf6/white/Engineer.svg", + "altImage": "https://cdn.gametools.network/classes/bf6/black/Engineer.svg", + "id": "engineer", + "kills": 6123, + "deaths": 266, + "kpm": 11.4, + "killDeath": 23.02, + "spawns": 301, + "score": 192225, + "assists": 523, + "secondsPlayed": 32218 + }, + { + "className": "Support", + "image": "https://cdn.gametools.network/classes/bf6/white/Support.svg", + "altImage": "https://cdn.gametools.network/classes/bf6/black/Support.svg", + "id": "support", + "kills": 27896, + "deaths": 1998, + "kpm": 7.82, + "killDeath": 13.96, + "spawns": 2208, + "score": 1790650, + "assists": 2667, + "secondsPlayed": 214172 + }, + { + "className": "Recon", + "image": "https://cdn.gametools.network/classes/bf6/white/Recon.svg", + "altImage": "https://cdn.gametools.network/classes/bf6/black/Recon.svg", + "id": "recon", + "kills": 8163, + "deaths": 304, + "kpm": 9.02, + "killDeath": 26.85, + "spawns": 348, + "score": 345815, + "assists": 954, + "secondsPlayed": 54308 + } + ], + "maps": [ + { + "mapName": "Siege of Cairo", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Abbasid_Large_OPT-49a3761a.webp", + "id": "mpabbasid", + "wins": 48, + "losses": 29, + "matches": 77, + "winPercent": "62.34%", + "secondsPlayed": 108122 + }, + { + "mapName": "Empire State", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Aftermath_Large_OPT-bf883df1.webp", + "id": "mpaftermath", + "wins": 39, + "losses": 16, + "matches": 55, + "winPercent": "70.91%", + "secondsPlayed": 63995 + }, + { + "mapName": "Iberian Offensive", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Battery_Large_OPT-034d4636.webp", + "id": "mpbattery", + "wins": 15, + "losses": 8, + "matches": 23, + "winPercent": "65.22%", + "secondsPlayed": 19596 + }, + { + "mapName": "Liberation Peak", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Capstone_Large_OPT-2ccae694.webp", + "id": "mpcapstone", + "wins": 27, + "losses": 14, + "matches": 41, + "winPercent": "65.85%", + "secondsPlayed": 56559 + }, + { + "mapName": "Manhattan Bridge", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Dumbo_Large_OPT-20de031f.webp", + "id": "mpdumbo", + "wins": 20, + "losses": 9, + "matches": 29, + "winPercent": "68.97%", + "secondsPlayed": 33388 + }, + { + "mapName": "Operation Firestorm", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Firestorm_Large_OPT-45d582ad.webp", + "id": "mpfirestorm", + "wins": 5, + "losses": 3, + "matches": 8, + "winPercent": "62.5%", + "secondsPlayed": 10892 + }, + { + "mapName": "Saints Quarter", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Limestone_Large_OPT-c9160897.webp", + "id": "mplimestone", + "wins": 34, + "losses": 10, + "matches": 44, + "winPercent": "77.27%", + "secondsPlayed": 23532 + }, + { + "mapName": "New Sobek City", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Outskirts_Large_OPT-bf08f756.webp", + "id": "mpoutskirts", + "wins": 16, + "losses": 7, + "matches": 23, + "winPercent": "69.57%", + "secondsPlayed": 37590 + }, + { + "mapName": "Mirak Valley", + "image": "https://cdn.gametools.network/maps/bf6/T_UI_Tungsten_Large_OPT-935da06b.webp", + "id": "mptungsten", + "wins": 10, + "losses": 4, + "matches": 14, + "winPercent": "71.43%", + "secondsPlayed": 20429 + }, + { + "mapName": "Blackwell Fields", + "image": "https://cdn.gametools.network/maps/bf6/Battlefield_6_Blackwell_Fields.webp", + "id": "mpbadlands", + "wins": 3, + "losses": 2, + "matches": 5, + "winPercent": "60.0%", + "secondsPlayed": 7833 + }, + { + "mapName": "REDSEC", + "image": "https://cdn.gametools.network/maps/bf6/Battlefield_6_Redsec.webp", + "id": "ftpgranite", + "wins": 25, + "losses": 118, + "matches": 143, + "winPercent": "17.48%", + "secondsPlayed": 142037 + } + ], + "gadgets": [ + { + "type": "Strike Packages", + "gadgetName": "Air Strike", + "image": "https://cdn.gametools.network/gadgets/bf6/T_UI_CALLINS_Airstrike_Thumb-638b4ee1.png", + "id": "callin_airstrike", + "kills": 0, + "assistsDamage": 0, + "assists": 0, + "spawns": 0, + "damage": 0, + "uses": 33, + "multiKills": 0, + "vehiclesDestroyedWith": 0, + "kpm": 0.0, + "dpm": 0.0, + "secondsPlayed": 703 + } + ], + "redsec": [ + { + "seasonId": "Season1", + "season": "Season 1", + "modes": [ + { + "modeId": "GraniteDuo0", + "mode": "Duos", + "matches": 1, + "wins": 1, + "losses": 18, + "kills": 42, + "deaths": 28, + "killDeath": 1.5, + "score": 55475, + "secondsPlayed": 13274, + "timePlayed": "3:41:14", + "extrActions": 0 + }, + { + "modeId": "GraniteSquad0", + "mode": "Quads", + "matches": 29, + "wins": 20, + "losses": 9, + "kills": 449, + "deaths": 165, + "killDeath": 2.72, + "score": 736765, + "secondsPlayed": 112415, + "timePlayed": "1 day, 7:13:35", + "extrActions": 2 + }, + { + "modeId": "GraniteGauntlet0", + "mode": "Gauntlet", + "matches": 5, + "wins": 4, + "losses": 1, + "kills": 200, + "deaths": 118, + "killDeath": 1.69, + "score": 167560, + "secondsPlayed": 16196, + "timePlayed": "4:29:56", + "extrActions": 6 + } + ] + } + ], + "bestClass": "Support", + "humanPrecentage": "13.64%", + "kills": 45873, + "deaths": 3736, + "wins": 244, + "loses": 112, + "killsPerMinute": 3.7, + "damagePerMinute": 0.0, + "killsPerMatch": 127.78, + "damagePerMatch": 0.0, + "headShots": 19649, + "winPercent": "68.54%", + "headshots": "42.83%", + "killDeath": 12.28, + "infantryKillDeath": 1.67, + "damage": 0, + "timePlayed": "8 days, 14:37:41", + "accuracy": "40.17%", + "revives": 1345, + "heals": 30606, + "resupplies": 4979, + "repairs": 7925, + "squadmateRevive": 529, + "thrownThrowables": 319, + "inRound": { + "revives": 122, + "resupplies": 138, + "spotAssists": 62, + "thrownThrowables": 37, + "playerTakeDowns": 5 + }, + "gadgetsDestoyed": 991, + "playerTakeDowns": 55, + "matchesPlayed": 359, + "secondsPlayed": 743861, + "dividedSecondsPlayed": { + "flying": 2021, + "driving": 11974 + }, + "saviorKills": 2015, + "shotsFired": 348851, + "shotsHit": 140150, + "killAssists": 6083, + "vehiclesDestroyed": 45, + "enemiesSpotted": 8040, + "dividedKills": { + "ads": 35149, + "grenades": 144, + "hipfire": 9044, + "longDistance": 695, + "melee": 76, + "multiKills": 1482, + "passenger": 377, + "vehicle": 739, + "roadkills": 45, + "human": 6255, + "weapons": { + "SMG": 11141, + "LMG": 0, + "DMR": 270, + "Shotguns": 510, + "Assault Rifles": 510 + }, + "inRound": { + "total": 4935, + "grenade": 24, + "headshots": 3824, + "melee": 34, + "multiKills": 157, + "weapons": { + "SMG": 2685, + "AR": 1600, + "DMR": 117 + } + } + }, + "devidedDamage": { + "passenger": 65107, + "vehicleDriver": 129750, + "toVehicle": 212921, + "inRound": { + "asVehicle": 33412 + } + }, + "devidedAssists": { + "driver": 177, + "passenger": 290, + "spot": 1283, + "pilot": 177, + "inRound": { + "total": 113 + } + }, + "distanceTraveled": { + "foot": 857640, + "passenger": 358029, + "vehicle": 565509 + }, + "sector": { + "captured": 366 + }, + "objective": { + "time": { + "total": 62374, + "attacked": 19898, + "defended": 32446 + }, + "armed": 128, + "captured": 296, + "neutralized": 187, + "defused": 34, + "destroyed": 59, + "inRound": { + "armed": 26, + "captured": 8, + "neutralized": 9, + "defused": 27, + "destroyed": 8 + } + }, + "XP": [ + { + "total": 15253700, + "performance": 6681800, + "accolades": 3311400 + } + ] +} + + +async def build_card(): + # logger.info(f"结果{play_stat}") + weapon, vehicle = await get_best_weapon_and_best_vehicle(play_stat) + pid = play_stat['id'] + kd = play_stat['killDeath'] + kpm = play_stat['killsPerMinute'] + acc = play_stat['accuracy'] + head_shots = play_stat['headshots'] + time_play = 100 + kills = int(play_stat['kills']) + kill_assists = int(play_stat['killAssists']) + revives = int(play_stat['revives']) + wins = int(play_stat['wins']) + loses = int(play_stat['loses']) + best_weapon = weapon + best_vehicle = vehicle + best_class = play_stat['bestClass'] + captured = play_stat['objective']['captured'] + score = sum(item.get("score", 0) for item in play_stat['classes']) + repairs = play_stat['repairs'] + img = await build_bf6_stats_card(game='bf6', + player='Sansorano_Yume', + pid=pid, + kd=kd, + kpm=1.11, + spm=256.3, + acc=acc, + head_shots="18.96%", + rank=110, + time_play=time_play, + kills=kills, + kill_assists=kill_assists, + revives=revives, + repairs=repairs, + captured=captured, + score=score, + wins=wins, + loses=loses, + destroyed=120, + best_weapon=best_weapon, + best_vehicle=best_vehicle, + best_class=best_class) + tmimg = Image.open(img) + tmimg.show() + + +if __name__ == "__main__": + asyncio.run(fetch_tracker_search( + "https://api.tracker.gg/api/v2/bf6/standard/search?platform=origin&query=ABrokenWill&autocomplete=true", + "D:/QQ Bot/BF_BOT/src/plugins/nonebot_plugin_bf_bot/cookies/tracker.txt")) diff --git a/hexi/plugins/nonebot_plugin_bf_bot/text_utils.py b/hexi/plugins/nonebot_plugin_bf_bot/text_utils.py new file mode 100644 index 0000000..84511e8 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/text_utils.py @@ -0,0 +1,33 @@ +import re + + +def convert_to_hours(time_str): + """ + 将各种时间格式字符串转换为小时数 + 支持格式示例: + - "1 day, 1:49:15" (包含天数) + - "1:56:55" (小时:分钟:秒) + - "0:06:41" (分钟:秒) + - "14:11:36" (小时:分钟:秒) + """ + total_hours = 0.0 + + # 处理包含天数的部分 + if "day" in time_str: + days_part, time_part = time_str.split(", ") + days = float(re.search(r"\d+", days_part).group()) + total_hours += days * 24 + time_str = time_part + + # 分割时间部分 + parts = list(map(float, time_str.split(":"))) + + # 根据时间部分长度计算 + if len(parts) == 3: # 时:分:秒 + total_hours += parts[0] + parts[1] / 60 + parts[2] / 3600 + elif len(parts) == 2: # 分:秒 + total_hours += parts[0] / 60 + parts[1] / 3600 + elif len(parts) == 1: # 仅秒 + total_hours += parts[0] / 3600 + + return round(total_hours, 2) diff --git a/hexi/plugins/nonebot_plugin_bf_bot/tracker_data.py b/hexi/plugins/nonebot_plugin_bf_bot/tracker_data.py new file mode 100644 index 0000000..c167d1a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/tracker_data.py @@ -0,0 +1,109 @@ +import os +from typing import List, Dict, Optional + +from nonebot import logger +from playwright.async_api import async_playwright, Response + + +async def fetch_tracker_search( + search_url: str, + cookies_txt: str, + wait_seconds: int = 2, +) -> Optional[Dict]: + """ + 使用 Playwright + cookies 访问 tracker.gg API 并截获响应数据 + """ + cookies = parse_netscape_cookies(cookies_txt) + if not cookies: + logger.error("cookies.txt 解析失败或为空") + return None + + result: Optional[Dict] = None + + async with async_playwright() as p: + browser = await p.chromium.launch( + executable_path="C:/Program Files/Google/Chrome/Application/chrome.exe", + headless=True, # False 可以看到浏览器操作 + args=[ + "--autoplay-policy=no-user-gesture-required", + "--disable-features=AutoplayDisableSuppression", + "--use-fake-ui-for-media-stream", + ] + ) + + context = await browser.new_context( + viewport={"width": 640, "height": 320}, + user_agent=( + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " + "AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/143.0.0.0 Safari/537.36" + ), + ) + + await context.add_cookies(cookies) + page = await context.new_page() + + # 响应监听 + async def handle_response(response: Response): + nonlocal result + try: + if search_url in response.url: + # 尝试解析 JSON + data = await response.json() + if data and "data" in data: + result = data + logger.info(f"成功截获响应数据: {data}") + except Exception as e: + logger.warning(f"解析响应失败: {e}") + + page.on("response", handle_response) + + try: + # 直接访问 API 链接 + await page.goto(search_url, wait_until="domcontentloaded", timeout=60000) + # 等待响应截获 + await page.wait_for_timeout(wait_seconds * 1000) + except Exception as e: + logger.error(f"访问页面出错: {e}") + finally: + await browser.close() + + return result + + +def parse_netscape_cookies(cookies_txt_path: str) -> List[Dict]: + """ + 解析 Netscape HTTP Cookie File -> Playwright cookies + """ + cookies: List[Dict] = [] + + if not os.path.exists(cookies_txt_path): + return cookies + + with open(cookies_txt_path, "r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line or line.startswith("#"): + continue + + parts = line.split("\t") + if len(parts) != 7: + continue + + domain, include_sub, path, secure, expiry, name, value = parts + + cookie = { + "name": name, + "value": value, + "domain": domain, + "path": path, + "secure": secure.upper() == "TRUE", + "httpOnly": False, + } + + if expiry.isdigit() and int(expiry) > 0: + cookie["expires"] = int(expiry) + + cookies.append(cookie) + + return cookies diff --git a/hexi/plugins/nonebot_plugin_bf_bot/user_data/client_app.py b/hexi/plugins/nonebot_plugin_bf_bot/user_data/client_app.py new file mode 100644 index 0000000..bee7bf9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/user_data/client_app.py @@ -0,0 +1,26 @@ +import json +from fastapi import FastAPI, HTTPException, Header, Form, Request +from fastapi.responses import JSONResponse +from fastapi.middleware.cors import CORSMiddleware + +app = FastAPI() + +# ✅ 添加 CORS 支持 +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@app.post("/designation/page") +async def designation_page(): + return "1" + + +if __name__ == "__main__": + import uvicorn + + uvicorn.run(app, host="0.0.0.0", port=16661, log_level="info") diff --git a/hexi/plugins/nonebot_plugin_bf_bot/user_data/data_utils.py b/hexi/plugins/nonebot_plugin_bf_bot/user_data/data_utils.py new file mode 100644 index 0000000..a07d583 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/user_data/data_utils.py @@ -0,0 +1,133 @@ +import sqlite3 +import os +from typing import List, Dict, Any, Optional + + +class TableManager: + def __init__(self, db_path: str = 'user_data.db'): + base_dir = os.path.dirname(os.path.abspath(__file__)) + self.db_path = os.path.join(base_dir, 'user_data.db') + + def _execute(self, sql: str, params: tuple = ()) -> sqlite3.Cursor: + """执行SQL语句的通用方法""" + with sqlite3.connect(self.db_path) as conn: + conn.row_factory = sqlite3.Row + cursor = conn.cursor() + cursor.execute(sql, params) + conn.commit() + return cursor + + +class UserManager(TableManager): + def add_user(self, qq_id: str, ea_player_name: str, ea_player_id: str, ea_user_id: str, designation: str, + medals: str) -> int: + """添加用户""" + cursor = self._execute( + "INSERT INTO users (qq_id, ea_player_name,ea_player_id,ea_user_id, designation,medals) VALUES (?, ?, ?, ?, ?,?)", + (qq_id, ea_player_name, ea_player_id, ea_user_id, designation, medals) + ) + return cursor.lastrowid + + def update_user(self, qq_id: str, ea_player_name: str, ea_player_id: str, ea_user_id: str, designation: str, + medals: str) -> int: + """修改用户""" + cursor = self._execute( + "UPDATE users SET ea_player_name = ?, ea_player_id = ?,ea_user_id = ? WHERE qq_id = ?", + (ea_player_name, ea_player_id, ea_user_id, qq_id) + ) + return cursor.rowcount + + def get_user_by_qq(self, qq_id: str) -> Optional[Dict[str, Any]]: + cursor = self._execute( + "SELECT * FROM users WHERE qq_id = ?", + (qq_id,) + ) + row = cursor.fetchone() + return dict(row) if row else None + + def get_user_by_ea_id(self, ea_user_id: str) -> Optional[Dict[str, Any]]: + cursor = self._execute( + "SELECT * FROM users WHERE ea_user_id = ?", + (ea_user_id,) + ) + row = cursor.fetchone() + return dict(row) if row else None + + def delete_user_by_qq(self, qq_id: str) -> Optional[Dict[str, Any]]: + cursor = self._execute( + "DELETE FROM users WHERE qq_id = ?", + (qq_id,) + ) + return cursor.rowcount + + def update_dog_tags(self, qq_id: int, medals: str) -> bool: + """更新用户的狗牌列表""" + self._execute( + "UPDATE users SET medals = ? WHERE id = ?", + (medals, qq_id) + ) + return True + + +class DesignationManager(TableManager): + def create_designation(self, name: str, icon_path: str) -> int: + """创建新标签""" + cursor = self._execute( + "INSERT INTO designation (name,icon_path) VALUES (?,?)", + (name, icon_path) + ) + return cursor.lastrowid + + def get_all_designation(self) -> List[Dict[str, Any]]: + """获取所有标签""" + cursor = self._execute("SELECT * FROM designation") + return [dict(row) for row in cursor.fetchall()] + + def get_designation_by_id_list(self, ids: List[int]) -> List[Dict[str, Any]]: + """根据 ID 列表获取标签""" + + if not ids: + return [] + + placeholders = ",".join(["?"] * len(ids)) + sql = f""" + SELECT * + FROM designation + WHERE id IN ({placeholders}) + """ + + cursor = self._execute(sql, ids) + return [dict(row) for row in cursor.fetchall()] + + +# class QueryRecordManager(TableManager): +# def log_query(self, user_id: str, target_id: str, status: str) -> int: +# """记录查询操作""" +# cursor = self._execute( +# """INSERT INTO query_record +# (user_id, target_id, status) +# VALUES (?, ?, ?)""", +# (user_id, target_id, status) +# ) +# return cursor.lastrowid +# +# def get_user_history(self, user_id: str) -> List[Dict[str, Any]]: +# """获取用户查询历史""" +# cursor = self._execute( +# "SELECT * FROM query_record WHERE user_id = ?", +# (user_id,) +# ) +# return [dict(row) for row in cursor.fetchall()] + + +if __name__ == "__main__": + tag_db = DesignationManager() + # tag_id = tag_db.create_designation("DEV","DEV.png") + # tag_id = tag_db.create_designation("DICE", "DICE.png") + # tag_id = tag_db.create_designation("IC", "IC.png") + # tag_id = tag_db.create_designation("OWNER", "OWNER.png") + # print(f"Created tag with ID: {tag_id}") + + record_id = tag_db.get_designation_by_id_list([1, 2, 3]) + + print(f"Logged query with ID: {record_id}") diff --git a/hexi/plugins/nonebot_plugin_bf_bot/user_data/init_database.py b/hexi/plugins/nonebot_plugin_bf_bot/user_data/init_database.py new file mode 100644 index 0000000..ebb5bba --- /dev/null +++ b/hexi/plugins/nonebot_plugin_bf_bot/user_data/init_database.py @@ -0,0 +1,127 @@ +import os +import sqlite3 +from typing import List, Tuple + +from nonebot import logger + + +class DatabaseManager: + def __init__(self, db_path: str = 'user_data.db'): + self.db_path = db_path + self.expected_tables = { + 'users': [ + ('id', 'INTEGER PRIMARY KEY AUTOINCREMENT'), + ('qq_id', 'TEXT NOT NULL'), + ('ea_player_name', 'TEXT UNIQUE'), + ('ea_player_id', 'TEXT UNIQUE'), + ('ea_user_id', 'TEXT UNIQUE'), + ('designation', 'TEXT NOT NULL'), + ('medals', 'TEXT NOT NULL'), + ('create_time', 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP') + ], + 'designation': [ + ('id', 'INTEGER PRIMARY KEY'), + ('name', 'TEXT NOT NULL'), + ('icon_path', 'TEXT NOT NULL'), + ('create_time', 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP') + ], + 'medals': [ + ('id', 'INTEGER PRIMARY KEY'), + ('name', 'TEXT NOT NULL'), + ('icon_path', 'TEXT NOT NULL'), + ('create_time', 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP') + ] + , + 'query_record': [ + ('id', 'INTEGER PRIMARY KEY'), + ('user_id', 'TEXT NOT NULL'), + ('ea_player_name', 'TEXT NOT NULL'), + ('ea_player_id', 'TEXT NOT NULL'), + ('ea_user_id', 'TEXT NOT NULL'), + ('status', 'TEXT NOT NULL'), + ('create_time', 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP') + ] + } + + def initialize_database(self) -> bool: + """初始化数据库并创建表结构""" + try: + with sqlite3.connect(self.db_path) as conn: + cursor = conn.cursor() + + # 创建所有表 + for table_name, columns in self.expected_tables.items(): + columns_sql = ', '.join(f'{col} {typ}' for col, typ in columns) + cursor.execute(f''' + CREATE TABLE IF NOT EXISTS {table_name} ( + {columns_sql} + ) + ''') + + conn.commit() + return True + + except Exception as e: + logger.error(f"Database initialization failed: {str(e)}") + if os.path.exists(self.db_path): + conn.close() # 确保连接关闭 + for _ in range(3): # 重试机制 + try: + os.remove(self.db_path) + break + except PermissionError: + time.sleep(0.5) + return False + + def _verify_database_integrity(self, conn: sqlite3.Connection) -> bool: + """验证数据库完整性""" + cursor = conn.cursor() + + # 检查表是否存在 + cursor.execute("SELECT name FROM sqlite_master WHERE type='table'") + existing_tables = {row[0] for row in cursor.fetchall()} + + if existing_tables != set(self.expected_tables.keys()): + logger.warning(f"Missing tables: {set(self.expected_tables.keys()) - existing_tables}") + return False + + # 检查每个表的结构 + for table_name, expected_columns in self.expected_tables.items(): + cursor.execute(f"PRAGMA table_info({table_name})") + actual_columns = [(row[1], row[2]) for row in cursor.fetchall()] + + if not self._compare_columns(actual_columns, expected_columns): + logger.warning(f"Table {table_name} structure mismatch") + return False + + # 执行完整性检查 + cursor.execute("PRAGMA integrity_check") + integrity_result = cursor.fetchone() + if integrity_result[0] != 'ok': + logger.warning(f"Integrity check failed: {integrity_result}") + return False + + return True + + def _compare_columns(self, actual: List[Tuple], expected: List[Tuple]) -> bool: + """比较实际列与预期列是否匹配""" + if len(actual) != len(expected): + return False + + for (act_col, act_type), (exp_col, exp_type) in zip(actual, expected): + if act_col.lower() != exp_col.lower(): + return False + if not act_type.upper().startswith(exp_type.upper()): + return False + + return True + + +# 初始化 +if __name__ == '__main__': + db_manager = DatabaseManager() + if db_manager.initialize_database(): + print("Database initialized successfully") + print(f"Database file created at: {os.path.abspath(db_manager.db_path)}") + else: + print("Database initialization failed") diff --git a/hexi/plugins/nonebot_plugin_brash_general_supercredits_tools/__init__.py b/hexi/plugins/nonebot_plugin_brash_general_supercredits_tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hexi/plugins/nonebot_plugin_dailywife/LICENSE b/hexi/plugins/nonebot_plugin_dailywife/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_dailywife/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/hexi/plugins/nonebot_plugin_dailywife/README.md b/hexi/plugins/nonebot_plugin_dailywife/README.md new file mode 100644 index 0000000..b8cccc9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_dailywife/README.md @@ -0,0 +1,47 @@ +# 今日老婆 + +一个适用于HoshinoBot的随机群友老婆插件 + +### ★ 如果你喜欢的话,请给仓库点一个star支持一下23333 ★ + +## 本项目地址: + +https://github.com/SonderXiaoming/dailywife + +## 部署教程: + +1.下载或git clone本插件: + +在 HoshinoBot\hoshino\modules 目录下使用以下命令拉取本项目 + +git clone https://github.com/SonderXiaoming/dailywife + +2.启用: + +在 HoshinoBot\hoshino\config\ **bot**.py 文件的 MODULES_ON 加入 'dailywife' + +然后重启 HoshinoBot + +## 指令 + +【今日老婆】 + +随机抓一位群友当老婆 + +每天群友老婆是固定的 + +每个群友只能当一个人的老婆 + +## 彩蛋 + +超管必抽到bot + +群友必抽不到bot + +(与原版老婆指令对应,想ntr我老婆?) + +修改的话只要把laopo.py的82,83,94行注释掉,84行elif改成if + +## 已知问题 + +储存数据用json可能不太好 diff --git a/hexi/plugins/nonebot_plugin_dailywife/__init__.py b/hexi/plugins/nonebot_plugin_dailywife/__init__.py new file mode 100644 index 0000000..5148883 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_dailywife/__init__.py @@ -0,0 +1,126 @@ +import base64 +import datetime +import hashlib +import json +import os +from random import choice +from tkinter import Image + +from PIL import * +from .utils import * + +import httpx +from nonebot import on_command, logger +from nonebot.adapters.onebot.v11 import MessageEvent, Bot, MessageSegment +from nonebot.plugin import PluginMetadata + +__plugin_meta__ = PluginMetadata( + name="今日老婆", + description="随机抓取群友作为老婆", + usage="发送【今日老婆】", + type="application", +) + +wife = on_command("今日老婆", aliases={"今日老婆"}) + + +def get_member_list(all_list): + id_list = [] + for member_list in all_list: + id_list.append(member_list['user_id']) + return id_list + + +async def download_avatar(user_id: str) -> bytes: + url = f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=640" + data = await download_url(url) + if not data or hashlib.md5(data).hexdigest() == "acef72340ac0e914090bd35799f5594e": + url = f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=100" + data = await download_url(url) + return data + + +async def download_url(url: str) -> bytes: + async with httpx.AsyncClient() as client: + for i in range(3): + try: + resp = await client.get(url) + if resp.status_code != 200: + continue + return resp.content + except Exception as e: + logger.error(f"Error downloading {url}, retry {i}/3: {str(e)}") + + +async def get_wife_info(member_info, qq_id): + img = await download_avatar(qq_id) + avatar = Image.open(BytesIO(img)).convert('RGBA') + avatar = png_resize(avatar, new_width=145, new_height=145) + + b_io = BytesIO() + avatar.save(b_io, format="PNG") + avatar_str = 'base64://' + base64.b64encode(b_io.getvalue()).decode() + member_name = (member_info["card"] or member_info["nickname"]) + msg = (MessageSegment.text('你今天的群友老婆是:'), MessageSegment.image(avatar_str), + MessageSegment.text(f'{member_name}({qq_id})')) + return msg + + +def load_group_config(group_id: str) -> int: + filename = os.path.join(os.path.dirname(__file__), 'config', f'{group_id}.json') + try: + with open(filename, encoding='utf8') as f: + config = json.load(f) + return config + except: + return None + + +def write_group_config(group_id: str, link_id: str, wife_id: str, date: str, config) -> int: + config_file = os.path.join(os.path.dirname(__file__), 'config', f'{group_id}.json') + if config is not None: + config[link_id] = [wife_id, date] + else: + config = {link_id: [wife_id, date]} + with open(config_file, 'w', encoding='utf-8') as f: + json.dump(config, f, ensure_ascii=False) + + +@wife.handle() +async def wife_handle(bot: Bot, ev: MessageEvent): + group_id = ev.group_id + user_id = ev.user_id + bot_id = ev.self_id + wife_id = None + today = str(datetime.date.today()) + config = load_group_config(group_id) + + # if priv.check_priv(ev, priv.SUPERUSER): + # wife_id = bot_id + if config is not None: + if str(user_id) in list(config): + if config[str(user_id)][1] == today: + wife_id = config[str(user_id)][0] + else: + del config[str(user_id)] + + if wife_id is None: + all_list = await bot.get_group_member_list(group_id=group_id) + id_list = get_member_list(all_list) + id_list.remove(bot_id) + id_list.remove(user_id) + if config is not None: + for record_id in list(config): + if config[record_id][1] != today: + del config[record_id] + else: + try: + id_list.remove(int(config[record_id][0])) + except: + del config[record_id] + wife_id = choice(id_list) + + write_group_config(group_id, user_id, wife_id, today, config) + member_info = await bot.get_group_member_info(group_id=group_id, user_id=wife_id) + result = await get_wife_info(member_info, wife_id) + await bot.send(ev, result, at_sender=True) diff --git a/hexi/plugins/nonebot_plugin_dailywife/utils.py b/hexi/plugins/nonebot_plugin_dailywife/utils.py new file mode 100644 index 0000000..7922039 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_dailywife/utils.py @@ -0,0 +1,50 @@ +import hashlib +import json +from nonebot.log import logger as sv +import os +import random +import time +from io import BytesIO + +import aiohttp +import qrcode +import requests +import requests.exceptions +from PIL import Image, ImageDraw, ImageFont + + +# PNG重绘大小 +def png_resize(source_file, new_width=0, new_height=0, resample="LANCZOS", ref_file=''): + """ + PNG缩放透明度处理 + :param source_file: 源文件(Image.open()) + :param new_width: 设置的宽度 + :param new_height: 设置的高度 + :param resample: 抗锯齿 + :param ref_file: 参考文件 + :return: + """ + img = source_file + img = img.convert("RGBA") + width, height = img.size + + if ref_file != '': + imgRef = Image.open(ref_file) + new_width, new_height = imgRef.size + else: + if new_height == 0: + new_height = new_width * width / height + + bands = img.split() + resample_map = { + "NEAREST": Image.NEAREST, + "BILINEAR": Image.BILINEAR, + "BICUBIC": Image.BICUBIC, + "LANCZOS": Image.LANCZOS + } + resample_method = resample_map.get(resample, Image.LANCZOS) # 默认使用 LANCZOS + + bands = [b.resize((new_width, new_height), resample=resample_method) for b in bands] + resized_file = Image.merge('RGBA', bands) + + return resized_file diff --git a/hexi/plugins/nonebot_plugin_deadlock/__init__.py b/hexi/plugins/nonebot_plugin_deadlock/__init__.py new file mode 100644 index 0000000..ba647b2 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_deadlock/__init__.py @@ -0,0 +1,203 @@ +# import asyncio +# import base64 +# import io +# import json +# import os +# from datetime import datetime +# from nonebot import logger +# from PIL import Image, ImageOps, ImageDraw, ImageFont +# from nonebot.internal.params import ArgPlainText +# from nonebot.params import CommandArg +# from nonebot.typing import T_State +# from playwright.async_api import async_playwright +# from nonebot import on_command +# from nonebot.adapters.onebot.v11 import MessageEvent, Bot, MessageSegment, GroupMessageEvent, Message +# from nonebot.plugin import PluginMetadata +# from typing import Optional, Union +# from nonebot.matcher import Matcher +# +# __plugin_meta__ = PluginMetadata( +# name="DeadLock助手", +# description="DeadLock助手,我要成为DeadLock高手", +# usage="nekoscore:neko查分 [steam好友代码]\n" +# "nekobind:neko绑定 [steam好友代码]\n" +# "nekorank:neko排行[TODO]\n" +# "nekomatch:dl比赛详情[TODO]\n", +# type="application", +# extra={ +# +# } +# ) +# +# neko_score = on_command("nekoscore", aliases={"dl查分"}) +# neko_bind = on_command("nekobind", aliases={"dl绑定"}) +# neko_unbind = on_command("nekounbind", aliases={"取消dl绑定"}) +# neko_rank = on_command("nekorank", aliases={"dl排行"}) +# neko_match = on_command("nekomatch", aliases={"dl比赛详情"}) +# +# basic_path = os.path.dirname(__file__) +# save_path = os.path.join(basic_path, "temp") +# img_path = os.path.join(basic_path, "img") +# data_path = os.path.join(basic_path, "data") +# +# +# @neko_score.handle() +# async def get_neko_score(ev: MessageEvent, rgs: Message = CommandArg()): +# steam_id = rgs.extract_plain_text() +# # 查询绑定情况 +# if steam_id is None or steam_id == "" or steam_id.isdigit() is False: +# bind_steam_id = await get_neko_bind(ev.group_id, ev.user_id) +# if bind_steam_id is None: +# await neko_score.finish("请输入正确的steam好友代码!") +# return +# else: +# steam_id = bind_steam_id +# await neko_score.send(f"正在获取{steam_id}的数据") +# url = f"https://deadlock.blast.tv/users/{steam_id}" +# time_present1 = get_present_time() +# result = await capture_screenshot(url, time_present1) +# if result != "success": +# await neko_score.finish(MessageSegment.reply(ev.message_id) + result) +# img_path1 = os.path.join(save_path, f"{time_present1}.png") +# images = gen_ms_img(Image.open(img_path1)) +# mes = (MessageSegment.reply(ev.message_id), images) +# await neko_score.send(mes) +# os.remove(img_path1) +# +# +# @neko_bind.handle() +# async def play_neko_bind(ev: MessageEvent, rgs: Message = CommandArg()): +# # 获取群号 +# group_id = ev.group_id +# steam_id = rgs.extract_plain_text() +# if steam_id is None or steam_id == "" or steam_id.isdigit() is False: +# await neko_score.finish("请输入正确的steam好友代码!") +# return +# qq_id = ev.user_id +# res = await to_neko_bind(group_id, steam_id, qq_id) +# await neko_score.send(res) +# +# +# @neko_unbind.handle() +# async def play_neko_unbind(ev: MessageEvent, rgs: Message = CommandArg()): +# # 获取群号 +# group_id = ev.group_id +# steam_id = rgs.extract_plain_text() +# qq_id = ev.user_id +# res = await to_neko_unbind(group_id, qq_id) +# if res is None: +# await neko_score.finish(f"{qq_id}未绑定过") +# else: +# await neko_score.send(f"{qq_id}已经取消与{res}的绑定") +# +# +# async def to_neko_bind(group_id, steam_id, qq_id): +# if os.path.exists(f"{data_path}/{group_id}.json"): +# with open(f"{data_path}/{group_id}.json", 'r') as file: +# json_data = json.load(file) +# else: +# # 如果文件不存在,创建一个新的空字典 +# json_data = {} +# # 检查指定的 key 是否存在 +# if str(qq_id) in json_data: +# # 如果 key 存在,将对应键值更新 +# old_steam_id = json_data[str(qq_id)] +# json_data[str(qq_id)] = steam_id +# # 将更新后的数据写回 JSON 文件 +# with open(f"{data_path}/{group_id}.json", 'w') as file: +# json.dump(json_data, file, indent=4) +# return f"已经将[ {str(qq_id)} ]的绑定[ {old_steam_id} ]更新到了[ {str(steam_id)} ]" +# else: +# # 如果 key 不存在,添加新的 key-value 对 +# json_data[str(qq_id)] = steam_id +# +# # 将更新后的数据写回 JSON 文件 +# with open(f"{data_path}/{group_id}.json", 'w') as file: +# json.dump(json_data, file, indent=4) +# return f"[ {str(qq_id)} ]已经绑定[ {steam_id} ]" +# +# +# async def get_neko_bind(group_id, qq_id): +# if os.path.exists(f"{data_path}/{group_id}.json"): +# with open(f"{data_path}/{group_id}.json", 'r') as file: +# json_data = json.load(file) +# else: +# # 如果文件不存在,创建一个新的空字典 +# json_data = { +# "000000": 000000 +# } +# # 检查指定的 key 是否存在 +# if str(qq_id) in json_data: +# return json_data[str(qq_id)] +# else: +# return None +# +# +# async def to_neko_unbind(group_id, qq_id): +# if os.path.exists(f"{data_path}/{group_id}.json"): +# with open(f"{data_path}/{group_id}.json", 'r') as file: +# json_data = json.load(file) +# else: +# # 如果文件不存在,创建一个新的空字典 +# json_data = { +# "000000": 000000 +# } +# # 检查指定的 key 是否存在 +# if str(qq_id) in json_data: +# remove_value = json_data.pop(str(qq_id)) +# # 将更新后的数据写回 JSON 文件 +# with open(f"{data_path}/{group_id}.json", 'w') as file: +# json.dump(json_data, file, indent=4) +# return remove_value +# else: +# return None +# +# +# def get_present_time() -> int: +# return int(datetime.timestamp(datetime.now())) +# +# +# async def capture_screenshot(url: str, time_present: int): +# async with async_playwright() as p: +# browser = await p.chromium.launch() +# page = await browser.new_page() +# try: +# # 设置视口大小 +# await page.set_viewport_size({"width": 1600, "height": 900}) +# await page.goto(url) +# await page.wait_for_load_state('networkidle') +# +# except Exception as e: +# return f"访问网站异常{type(e)}`{e}`" +# +# await asyncio.sleep(1) +# i_path = os.path.join(save_path, f'{time_present}.png') +# await page.screenshot( +# path=i_path, +# full_page=True +# ) +# logger.info("正在压缩图片...") +# await asyncio.sleep(2) +# img_convert = Image.open(i_path) +# img_convert.save(i_path, quality=80) +# logger.info("图片保存成功!") +# await browser.close() +# return "success" +# +# +# def gen_ms_img(image: Union[bytes, Image.Image]) -> MessageSegment: +# if isinstance(image, bytes): +# return MessageSegment.image( +# pic2b64(Image.open(io.BytesIO(image))) +# ) +# else: +# return MessageSegment.image( +# pic2b64(image) +# ) +# +# +# def pic2b64(pic: Image) -> str: +# buf = io.BytesIO() +# pic.save(buf, format='PNG') +# base64_str = base64.b64encode(buf.getvalue()).decode() +# return 'base64://' + base64_str diff --git a/hexi/plugins/nonebot_plugin_deadlock/temp/1728540429.png b/hexi/plugins/nonebot_plugin_deadlock/temp/1728540429.png new file mode 100644 index 0000000..eb18bec Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deadlock/temp/1728540429.png differ diff --git a/hexi/plugins/nonebot_plugin_deadlock/temp/1728540619.png b/hexi/plugins/nonebot_plugin_deadlock/temp/1728540619.png new file mode 100644 index 0000000..eb18bec Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deadlock/temp/1728540619.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/__init__.py b/hexi/plugins/nonebot_plugin_deer_pipe/__init__.py new file mode 100644 index 0000000..f1d85e5 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_deer_pipe/__init__.py @@ -0,0 +1,69 @@ +from nonebot import on_command +from nonebot.adapters.onebot.v11 import MessageEvent, Bot, MessageSegment +from nonebot.plugin import PluginMetadata +from nonebot.rule import to_me + +from .data_proc import * +from .img_generator import * +import io +import base64 + +__plugin_meta__ = PluginMetadata( + name="打卡记鹿", + description="你今天鹿管了ma?", + usage="at机器人 发送:打卡 " + "直接发送:查卡(查询打卡记录)", + type="application", +) + +record = on_command("打卡记鹿", aliases={"打卡"}, rule=to_me()) +query = on_command("查询记录", aliases={"查卡"}) + + +@record.handle() +async def do_job(bot: Bot, ev: MessageEvent): + # 获取当前日期的年份和月份 + now = datetime.now() + year = now.year + month = now.month + # 获取发信人信息 + uid = str(ev.user_id) + message_id = ev.message_id + # 添加一条记录 + await record_month(uid) + # 获取记录 + img = await draw_calendar_grid_image(uid, year, month) + text_msg = MessageSegment.text("这是您的打卡记鹿:\n") + image_msg = MessageSegment.image(pic2b64(img)) + mix_msg = (text_msg,) + mix_msg += image_msg + reply_msg = (MessageSegment.reply(message_id),) + reply_msg += mix_msg + await record.finish(reply_msg) + + +def pic2b64(pic: Image) -> str: + buf = io.BytesIO() + pic.save(buf, format='PNG') + base64_str = base64.b64encode(buf.getvalue()).decode() + return 'base64://' + base64_str + + +@query.handle() +async def query_job(bot: Bot, ev: MessageEvent): + # 获取当前日期的年份和月份 + now = datetime.now() + year = now.year + month = now.month + # 获取发信人信息 + uid = str(ev.user_id) + message_id = ev.message_id + # 获取记录 + img_file = await draw_calendar_grid_image(uid, year, month) + text_msg = MessageSegment.text("这是您的记鹿:\n") + image_msg = MessageSegment.image(pic2b64(img_file)) + mix_msg = (text_msg,) + mix_msg += image_msg + reply_msg = (MessageSegment.reply(message_id),) + reply_msg += mix_msg + await record.finish(reply_msg) diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/data_proc.py b/hexi/plugins/nonebot_plugin_deer_pipe/data_proc.py new file mode 100644 index 0000000..250c7e2 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_deer_pipe/data_proc.py @@ -0,0 +1,47 @@ +from datetime import datetime + +from nonebot import require + +require("nonebot_plugin_orm") + +from nonebot_plugin_orm import Model, get_session +from sqlalchemy import BigInteger, Date, Integer, select +from sqlalchemy.orm import Mapped, mapped_column + + +class CheckInRecord(Model): + """打卡记录,一行一次打卡,同一天可多次""" + + __tablename__ = "deer_pipe_checkin" + + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + uid: Mapped[int] = mapped_column(BigInteger, index=True) + date: Mapped[datetime.date] = mapped_column(Date, index=True) + + +# 记录信息 +async def record_month(uid): + now = datetime.now() + async with get_session() as session: + session.add(CheckInRecord(uid=int(uid), date=now.date())) + await session.commit() + + +# 读取当月信息(返回当月所有打卡的日,同一天多次打卡会有重复项) +async def get_records(uid): + now = datetime.now() + month_start = datetime(now.year, now.month, 1).date() + if now.month == 12: + month_end = datetime(now.year + 1, 1, 1).date() + else: + month_end = datetime(now.year, now.month + 1, 1).date() + async with get_session() as session: + result = await session.execute( + select(CheckInRecord.date).where( + CheckInRecord.uid == int(uid), + CheckInRecord.date >= month_start, + CheckInRecord.date < month_end, + ) + ) + days = result.all() + return [row[0].day for row in days] diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/font/SourceHanSansCN-Medium.otf b/hexi/plugins/nonebot_plugin_deer_pipe/font/SourceHanSansCN-Medium.otf new file mode 100644 index 0000000..630d546 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/font/SourceHanSansCN-Medium.otf differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/deer_pipe.jpg b/hexi/plugins/nonebot_plugin_deer_pipe/img/deer_pipe.jpg new file mode 100644 index 0000000..1cb0928 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/deer_pipe.jpg differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J1.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J1.png new file mode 100644 index 0000000..fa9514a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J1.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J10.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J10.png new file mode 100644 index 0000000..194dc95 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J10.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J11.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J11.png new file mode 100644 index 0000000..65910f5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J11.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J12.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J12.png new file mode 100644 index 0000000..522acc0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J12.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J13.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J13.png new file mode 100644 index 0000000..e4e1528 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J13.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J14.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J14.png new file mode 100644 index 0000000..6279baf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J14.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J15.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J15.png new file mode 100644 index 0000000..38e847e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J15.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J16.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J16.PNG new file mode 100644 index 0000000..c3458ea Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J16.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J17.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J17.PNG new file mode 100644 index 0000000..6676351 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J17.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J18.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J18.PNG new file mode 100644 index 0000000..d3bba23 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J18.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J19.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J19.PNG new file mode 100644 index 0000000..cbcd022 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J19.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J2.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J2.png new file mode 100644 index 0000000..2b1c18a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J2.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J20.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J20.PNG new file mode 100644 index 0000000..e68c6f1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J20.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J21.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J21.PNG new file mode 100644 index 0000000..fd0dc44 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J21.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J22.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J22.PNG new file mode 100644 index 0000000..e2f570c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J22.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J23.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J23.PNG new file mode 100644 index 0000000..fd02592 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J23.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J24.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J24.PNG new file mode 100644 index 0000000..ba8b4ec Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J24.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J25.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J25.PNG new file mode 100644 index 0000000..15b6b4d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J25.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J26.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J26.PNG new file mode 100644 index 0000000..a8a3686 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J26.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J27.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J27.PNG new file mode 100644 index 0000000..ebb6598 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J27.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J28.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J28.PNG new file mode 100644 index 0000000..824c4f8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J28.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J29.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J29.PNG new file mode 100644 index 0000000..b091815 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J29.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J3.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J3.png new file mode 100644 index 0000000..c31b77b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J3.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J30.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J30.PNG new file mode 100644 index 0000000..bb8fb31 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J30.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J31.PNG b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J31.PNG new file mode 100644 index 0000000..4ca86f7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J31.PNG differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J4.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J4.png new file mode 100644 index 0000000..7d10d5a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J4.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J5.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J5.png new file mode 100644 index 0000000..5066828 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J5.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J6.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J6.png new file mode 100644 index 0000000..8e28da3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J6.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J7.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J7.png new file mode 100644 index 0000000..b7b1fff Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J7.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J8.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J8.png new file mode 100644 index 0000000..80c63a2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J8.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J9.png b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J9.png new file mode 100644 index 0000000..c9f750a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_deer_pipe/img/right/J9.png differ diff --git a/hexi/plugins/nonebot_plugin_deer_pipe/img_generator.py b/hexi/plugins/nonebot_plugin_deer_pipe/img_generator.py new file mode 100644 index 0000000..36dfc5e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_deer_pipe/img_generator.py @@ -0,0 +1,121 @@ +import calendar +from collections import Counter +import os +from datetime import datetime, timedelta +from PIL import Image, ImageDraw, ImageFont, ImageOps +from .data_proc import * +import random + +filepath = os.path.dirname(__file__).replace("\\", "/") + + +async def draw_calendar_grid_image(uid, year, month): + # 获取该月的第一天是星期几,以及这个月有多少天 + first_weekday, num_days = calendar.monthrange(year, month) + + # 调整第一天的索引,使周日对应0,周六对应6 + first_weekday = (first_weekday + 1) % 7 + + # 设置单元格尺寸和内边距 + cell_size = 50 + cell_padding = 5 + + # 计算当前月份的行数 + num_rows = (num_days + first_weekday + 6) // 7 + 1 # +1 行用于留空 + + # 计算图片宽度和高度 + image_width = 7 * (cell_size + cell_padding) - cell_padding + image_height = num_rows * (cell_size + cell_padding) - cell_padding + + # 创建图像对象 + img = Image.new("RGBA", (image_width, image_height), "white") + draw = ImageDraw.Draw(img) + font_path = filepath + "/font/SourceHanSansCN-Medium.otf" + print(font_path) + font_normal = ImageFont.truetype(font=font_path, size=18) + font_large = ImageFont.truetype(font=font_path, size=24) + + # 绘制网格线 + for i in range(7): + x = i * (cell_size + cell_padding) + draw.line([(x, 55), (x, image_height)], fill="black", width=1) + for j in range(0, image_height + cell_size, cell_size + cell_padding): + draw.line([(0, j), (image_width, j)], fill="black", width=1) + + # 小🦌 + deer_pipe_path = filepath + "/img/deer_pipe.jpg" + deer_pipe_img = Image.open(deer_pipe_path) + deer_pipe_img = deer_pipe_img.resize((54, 50)) + + # 画标题 + title = f"{month}月打卡记鹿" + text_length = draw.textlength(text=title, font=font_large) + img_xy = (int(((image_width - text_length + 55) / 2) - 55), 5) + title_pos = ((image_width - text_length + 55) / 2, 10) + img.paste(deer_pipe_img, img_xy) + draw.text(title_pos, title, fill="black", font=font_large) + + # 获取🦌信息(同一天多次打卡会得到重复项) + day_counts = Counter(await get_records(uid)) + # 填充日期 + date = datetime(year, month, 1) + for day in range(1, num_days + 1): + weekday = (first_weekday + day - 1) % 7 + row = (first_weekday + day - 1) // 7 + 1 # +1 行用于留空 + x = weekday * (cell_size + cell_padding) + cell_padding + y = row * (cell_size + cell_padding) + cell_padding + img.paste(deer_pipe_img, (x - 4, y)) + draw.text((x+20, y - 2), f"{str(day)}", fill="black", font=font_normal) + # 🦌是天的标记,打卡的PNG印记才是要多次绘制的对象,横向错开 + for i in range(day_counts.get(day, 0)): + im = get_random_right() + img = image_paste(im, img, (x - 4 + i * 10, y)) + + # 保存图片 + # img.save(output_image_path) + + # 显示图片 + # img.show() + img = ImageOps.expand(img, border=5, fill="black") + img = ImageOps.expand(img, border=5, fill="white") + return img + + +# 全局变量,用于存储已经选择过的文件名 +selected_images = [] + + +def get_random_right(): + global selected_images + path = filepath + "/img/right" + # 过滤掉已经选择过的文件名 + im_name = [name for name in os.listdir(path) if name not in selected_images] + + # 如果所有文件都已经选择过,重新初始化已选择列表 + if not im_name: + selected_images = [] + im_name = os.listdir(path) + + index = random.randint(0, len(im_name) - 1) + im = im_name[index] + selected_images.append(im) # 将选择的文件名添加到已选择列表中 + + im_path = os.path.join(path, im) + im_file = Image.open(im_path) + im_file = im_file.resize((50, 50)) + return im_file + + +# 图片粘贴 +def image_paste(paste_image, under_image, pos): + """ + :param paste_image: 需要粘贴的图片 + :param under_image: 底图 + :param pos: 位置(x,y)坐标 + :return: 返回图片 + """ + # 获取需要贴入图片的透明通道 + r, g, b, alpha = paste_image.split() + # 粘贴时将alpha值传递至mask属性 + under_image.paste(paste_image, pos, alpha) + return under_image diff --git a/hexi/plugins/nonebot_plugin_dice/__init__.py b/hexi/plugins/nonebot_plugin_dice/__init__.py new file mode 100644 index 0000000..24c09d8 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_dice/__init__.py @@ -0,0 +1,84 @@ +import random +import re + +from nonebot import on_regex, on_startswith, require +from nonebot.adapters.onebot.v11 import MessageEvent +from nonebot.plugin import PluginMetadata +from nonebot.typing import T_State + +require("nonebot_plugin_alconna") +from nonebot_plugin_alconna import UniMessage + +__plugin_meta__ = PluginMetadata( + name="掷骰子", + description="掷骰子 / 结婚判定", + usage=".r 掷骰子\n.r 3d12 掷3次12面骰子\n.r 2d3~6+1 掷2次3~6面骰子并加1\n.qj [名字] 与xxx结婚判定", + type="application", +) + +dice = on_regex( + re.compile( + r"^\.r\s*(?:(?P\d{0,2})d(?:(?P\d{1,4})~)?(?P\d{0,4})(?:(?P[+-])(?P\d{0,5}))?)?\b", + re.I, + ) +) +marriage = on_startswith(".qj") + + +async def do_dice( + ev: MessageEvent, + num: int, + min_: int, + max_: int, + opr: int, + offset: int, + tip: str = "的掷骰结果是:", +) -> None: + if num == 0: + await UniMessage.text("咦?我骰子呢?").send() + return + min_, max_ = min(min_, max_), max(min_, max_) + rolls = [random.randint(min_, max_) for _ in range(num)] + total = sum(rolls) + rolls_str = "+".join(map(str, rolls)) + if len(rolls_str) > 100: + rolls_str = str(total) + res = total + opr * offset + sign = " +-"[opr] + msg = [ + f"{tip}\n", + str(num) if num > 1 else "", + "D", + f"{min_}~" if min_ != 1 else "", + str(max_), + f"{sign}{offset}" if offset else "", + f"={rolls_str}", + f"{sign}{offset}" if offset else "", + f"={res}" if offset or num > 1 else "", + ] + await UniMessage.text("".join(msg)).send(at_sender=True) + + +@dice.handle() +async def dice_handle(ev: MessageEvent, state: T_State): + num, min_, max_, opr, offset = 1, 1, 100, 1, 0 + matched = state.get("_matched_dict") or {} + if s := matched.get("num"): + num = int(s) + if s := matched.get("min"): + min_ = int(s) + if s := matched.get("max"): + max_ = int(s) + if s := matched.get("opr"): + opr = -1 if s == "-" else 1 + if s := matched.get("offset"): + offset = int(s) + await do_dice(ev, num, min_, max_, opr, offset) + + +@marriage.handle() +async def marriage_handle(ev: MessageEvent): + text = ev.message.extract_plain_text().strip() + wife = text[len(".qj") :].strip() + tip = f"与{wife}的ケッコンカッコカリ结果是:" if wife else "的ケッコンカッコカリ结果是:" + await do_dice(ev, 1, 3, 6, 1, 0, tip) diff --git a/hexi/plugins/nonebot_plugin_galgame_card/CLAUDE.md b/hexi/plugins/nonebot_plugin_galgame_card/CLAUDE.md new file mode 100644 index 0000000..388c0fe --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/CLAUDE.md @@ -0,0 +1,82 @@ +# CLAUDE.md — 群聊人设卡插件开发文档 + +本文件是**本插件内开发**的唯一入口文档;需要项目全局信息(Poetry 命令、启动方式、测试约定)时再查项目根目录的 CLAUDE.md。详细设计定稿见同目录 `DESIGN.md`。 + +## 插件概述 + +基于群聊语料蒸馏群成员的形象风格,生成 galgame 风格人物卡(九段画像)。 + +- **目标**:生成"人的画像",不是关系网分析;样貌参考为虚构,永远带标注 +- **隐私硬约束**:只采集 opt-in 成员;敏感数据本地正则替换为占位符,**绝不经过 LLM** +- **维度隔离**:每个 `(group_id, user_id)` 是独立人设,跨群不混 + +## 目录结构 + +``` +nonebot_plugin_galgame_card/ +├── __init__.py 入口层:on_message 采集器(鉴权/采样/调治理落库) +├── models.py 数据层:五张表(persona_group/user/chat_log/impression/summary) +├── repository.py 数据层:仓储(来源无关,所有读写唯一入口) +├── processor.py 治理层:纯函数(五维提取/噪声/脱敏),可单测 +├── config.py 插件配置(WEB_ENABLE/WEB_USERNAME/WEB_PASSWORD/WEB_SECRET_KEY) +├── web.py Web 管理后台后端(/galgame_card/api/*,JWT 登录,仿 learning_chat) +├── web/index.html 管理后台前端(单文件,无需构建) +├── DESIGN.md 设计定稿(数据模型/流水线/九段协议/证据纪律) +└── CLAUDE.md 本文件 +``` + +**Web 管理后台**:`http://:/galgame_card`(默认 admin/galgame,可在 .env 改 WEB_*)。功能:群开关、参与者增删、语料/印象/画像浏览与删除、清空群数据。路由在 `@driver.on_startup` 里注册,改后端需重启 bot。 + +## 核心设计(速览,细节见 DESIGN.md) + +1. **两级闸门**:群开关 `persona_group.enabled`(默认关)+ 个人 opt-in `persona_user`,都过才采集 +2. **两级流水线**:语料 →(攒够 N 条)→ 印象(LLM 自然语言,增量中间层)→(攒够 M 条)→ 画像(九段 markdown,版本化) +3. **消息五维**:内容 / 谁发的 / 发给谁(回复/@)/ 几点发的 / 被回复内容快照——只存治理后纯文本 +4. **脱敏四层**(`desensitize()`):明确模式(最长优先排序防截胡)→ 定位式(同条关键词+值)→ 跨条语境(关键词在附近消息)→ 兜底(保守替换) +5. **九段画像协议**:身份印象/性格特征/说话风格/口头禅语录/兴趣话题/相处模式/时间画像/样貌参考(虚构)/不确定信息 +6. **总结路径不进消息 handler**:LLM 调用只在调度器触发,防延迟/限流 + +## 开发命令 + +```bash +# 跑本插件测试(治理层纯函数,9+ 个用例) +poetry run pytest tests/test_persona_processor.py + +# 全量测试 +poetry run pytest + +# 启动/重启验证:PyCharm 的 "start bot" 运行配置(勿用 bat 脚本) +``` + +## 数据库 + +- orm 默认库:`data/nonebot_plugin_orm/db.sqlite3`(不是 `hexi/data/data.db`) +- 建表:bot 启动时 orm 自动 create_all(新表加在 `models.py` 里即可,重启生效) +- 配置键是 `SQLALCHEMY_DATABASE_URL`(本插件未设置,走默认库) + +## 开发注意事项(踩过的坑) + +0. **⚠️ orm 启动自动同步会清空表数据**:`.env` 里 `ALEMBIC_STARTUP_CHECK=false` 时,nonebot_plugin_orm 每次启动都 autogenerate 同步数据库模式,**模型一有变更(改 models.py)就会重建表、清空全部数据**(2026-08-11 实测踩坑,全表被清)。已在本插件 `__init__.py` 导入期把 `migrate.sync` 替换为安全空操作。**今后 schema 演进只准通过 `repository.ensure_schema()` 显式 ALTER**,改完 models.py 后要在重启前手动执行对应 ALTER(或加进 ensure_schema)。 +1. **`on_message` 必须 `block=False`**:否则事件流被拦截,群里其他插件全废 +2. **只收群消息**:handler 参数注解 `GroupMessageEvent`(类型注解即过滤器) +3. **脱敏正则排序**:身份证/银行卡必须在手机号之前,否则手机号截胡身份证数字段 +4. **定位式替换只替换值、保留关键词**:`密码是 xyz789` → `密码是 [密码]`,关键词不能丢 +5. **测试不能裸 import 包**:`__init__.py` 触发 NoneBot 初始化,用 importlib 按路径加载 processor(见 `tests/test_persona_processor.py`,与 test_rate_limit 同款) +6. **总结/印象生成**:绝不在消息 handler 里调 LLM,走调度层(apscheduler) +7. **仓储并发**:`add_summary` 版本自增有并发撞 UNIQUE 风险,调度层加锁保护 + +## 当前进度 + +- ✅ 数据层:五表 + 仓储(含群开关、滚动淘汰、版本自增) +- ✅ 采集层:消息路径(监控→鉴权→治理→脱敏→采样→落库) +- ✅ Web 管理后台:/galgame_card(群开关、参与者、数据浏览/清理;Chrome 已实测) +- ⏳ QQ 命令集:`开启人设采集` / `加入人设` / `退出人设` / `查看人设`(Web 已覆盖同等功能,QQ 命令可选做) +- ⏳ 总结路径:LLM 客户端、印象生成、九段画像生成、调度触发 +- ⏳ 呈现层:人物卡展示/图片渲染 + +## 待决策点 + +- 触发阈值(印象 ≥50 条新语料 / 画像 ≥5 条新印象,⏳ 待调) +- 脱敏兜底位数(裸数字 ≥6 位默认替换 `[账号]`,保守优先;误杀多可提到 8 位,动 `BARE_DIGITS_RE`) +- 密保答案场景(中文值正则误杀率高,方案待定) +- 命令名与权限(超管/群主) diff --git a/hexi/plugins/nonebot_plugin_galgame_card/DESIGN.md b/hexi/plugins/nonebot_plugin_galgame_card/DESIGN.md new file mode 100644 index 0000000..c175479 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/DESIGN.md @@ -0,0 +1,194 @@ +# 群聊人设卡(Galgame 风格人物卡构建器)设计文档 + +> 本文档固化设计决策,作为各层实现的唯一依据。标注 ⏳ 的为草案/待定项。 + +## 1. 定位 + +**目标**:基于群聊发言语料,蒸馏群成员的形象风格,生成 galgame 风格的人物卡(人设)。 + +**非目标**: +- 不做关系网分析("相处模式"只是画像的一个段落,不是独立产品) +- 不做真实身份推断(年龄/职业/住址等现实信息只能进"不确定信息"段) +- 不生成真实样貌(样貌参考为虚构,永远带标注) + +**消费方**:① 展示给人看(人物卡);② 可选:作为扮演 prompt 注入(MaiBot 兼容方向)。 + +## 2. 整体架构 + +功能分层:采集 → 治理 → 存储 → 调度 → 分析 → 呈现。 + +两级流水线(借鉴 MaiBot 印象机制): + +``` +群聊消息 ──五维落库──> 语料 ──(攒够 N 条)──> 印象(LLM 自然语言) ──(攒够 M 条)──> 画像(九段协议) ──> 版本化快照 +``` + +- **语料 → 印象**:每次对"上次印象之后的新语料"生成一段自然语言印象(话题/氛围/互动),存 `persona_impression`。印象是增量中间产物,画像不重读全部原文。 +- **印象 → 画像**:从印象集 + 规则统计(@/回复 互动、活跃时段)生成九段人物卡。 +- 画像每次生成都是新版本(version +1),永久留档可对比。 + +## 3. 数据层(已实现 ✅) + +五张表,前缀 `persona_`: + +### persona_group —— 群采集开关(数据来源总闸门) + +| 字段 | 类型 | 说明 | +|---|---|---| +| group_id | BigInteger PK | 群号 | +| enabled | Boolean 默认 False | 该群是否开启采集(默认关,需显式开启) | +| updated_at | DateTime | 最后变更时间 | + +群关闭 → 该群所有人一律不采集;群开启后,个人还需 opt-in(两级闸门)。 + +### persona_user —— 参与者名单(按群 opt-in) + +| 字段 | 类型 | 说明 | +|---|---|---| +| user_id | BigInteger PK | 参与人 QQ | +| group_id | BigInteger PK | 所在群 | +| joined_at | DateTime | 加入时间 | + +### persona_chat_log —— 采集语料(五维 + 发言段链条) + +| 字段 | 类型 | 说明 | +|---|---|---| +| id | Integer PK 自增 | 全局有序,印象覆盖区间用它表示 | +| user_id | BigInteger | 谁发的 | +| group_id | BigInteger | | +| nickname | String(64) | 群昵称快照 | +| content | Text | 内容(纯文本,已脱敏截断) | +| target_user_id | BigInteger NULL | 发给谁(ev.reply 的 sender / @ 对象;无则 NULL=群聊漫谈) | +| target_inherited | Boolean | target 是否从发言段链条继承(对上一句的解释/补充仍算发给同一对象) | +| follows_id | Integer NULL | 发言段链条:同一说话人的上一条语料 id(间隔 ≤ 5 分钟) | +| reply_to_content | Text NULL | 被回复内容快照(对方不在语料里也能知道他在回应什么) | +| created_at | DateTime | 几点发的 | + +索引:`(user_id, group_id, created_at)`。滚动保留:单用户单群上限 3000 条(⏳ 常量待定)。 + +**发言段链条**(解决"不带 @/回复 的后续补充丢目标"):`@B 借我玩玩` → 下一条 `我的意思是借号不是借人`(无显式目标)继承 target=B 并打 `target_inherited` 标记;分析层窗口组装可沿 `follows_id` 回溯整段发言。 + +### persona_impression —— 印象(两级流水线中间产物) + +| 字段 | 类型 | 说明 | +|---|---|---| +| id | Integer PK 自增 | | +| user_id / group_id | BigInteger | | +| content | Text | LLM 生成的自然语言印象 | +| cover_from_id / cover_to_id | Integer | 覆盖的语料 id 区间(增量依据) | +| model | String(64) | 生成模型 | +| created_at | DateTime | | + +### persona_image —— 图片识别结果缓存(⏳ 多模态预留,未启用) + +| 字段 | 类型 | 说明 | +|---|---|---| +| hash | String(64) PK | 图片 hash(对应 chat_log.image_hashes) | +| description | Text | 多模态识别结果(表情包梗/截图内容) | +| model | String(64) | 识别模型 | +| recognized_at | DateTime | | + +**预留接口**:`vision.py`(BaseImageRecognizer,当前为 Noop 占位)。将来接入多模态 LLM 后:异步后台识别(绝不在消息路径同步调)、同一 hash 只识别一次(缓存复用)、失败不影响采集。识别描述供分析层窗口组装喂给总结 LLM。 + +### persona_summary —— 画像快照(版本化) + +| 字段 | 类型 | 说明 | +|---|---|---| +| id | Integer PK 自增 | | +| user_id / group_id | BigInteger | | +| version | Integer | 每次生成 +1,同人同群唯一 | +| card_text | Text | 九段 markdown 画像原文 | +| corpus_count | Integer | 语料覆盖条数(元信息) | +| impression_count | Integer | 使用的印象条数(元信息) | +| model | String(64) | 生成模型 | +| created_at | DateTime | | + +约束:`UNIQUE(user_id, group_id, version)`(并发写入由调度层锁保护)。 + +## 4. 九段画像协议(已定稿 ✅) + +格式:markdown 固定标题 + 有界 bullet,代码可解析、人可编辑、LLM 可生成、可注入 prompt。 + +``` +# 人物卡 · {主称呼} +语料 {N} 条 · 时间跨度 {start}-{end} · 版本 v{n} · 生成于 {date} + +## 身份印象 ≤4 条 群内可见的:自称方式、群角色(吐槽役)、常用昵称 +## 性格特征 ≤6 条 毒舌但心软 / 重度拖延 / 嘴硬 +## 说话风格 ≤5 条 爱用"草"开头、句尾 wwww、先吐槽再给结论 +## 口头禅语录 ≤6 条 带原文引用:"有一说一,这个图确实带" +## 兴趣话题 ≤5 条 明日方舟(资深);聊工作→抱怨、聊感情→回避 +## 相处模式 ≤4 条 对小B互怼最多,对新人客气(一句话式,非关系网) +## 时间画像 ≤3 条 深夜 22-02 点活跃,白天潜水 +## 样貌参考 ≤3 条 🎨 虚构标注:基于气质的参考描述 +## 不确定信息 ≤3 条 疑是学生(语料出现"上课"),未证实 +``` + +- 段内 bullet 为纯文本,可带原文引用(口头禅语录段必须带原文) +- 样貌参考段**必须**带 🎨 虚构标注与设计依据("基于 XX 气质") +- 现实身份信息只能出现在"不确定信息"段 +- ⏳ 每段具体生成约束(prompt 细则)属分析层,待细化 + +## 5. 证据纪律(已定稿 ✅) + +三层防编造(借鉴 MaiBot): + +1. 印象 prompt 明文约束:"不要添加语料中没有依据的新事实" +2. 规则统计(互动对象、活跃时段)优先于 LLM 分类结果 +3. LLM 分类结果默认降级进"不确定信息"段——**模型说的不算稳定真相** + +指纹缓存(⏳):证据(印象集 + 统计)hash 未变则不重新生成画像。 + +## 6. 采集与治理(✅ 消息路径已实现,⏳ 阈值待调) + +实现位置:`__init__.py`(on_message 入口 + 鉴权 + 采样)+ `processor.py`(纯函数治理,可单测)。 + +**两级闸门**:群开关 `persona_group.enabled`(群级,默认关)+ 个人 opt-in `persona_user`(个人,群内开启才生效)。两条同时满足才采集。 + +- 群开关控制:`开启人设采集 @群` / `关闭人设采集`(⏳ 命令名待定,权限:超管/群主) +- 只采集 `persona_user` 名单内成员(opt-in),退出即停 + +**脱敏(硬约束:本地正则完成,绝不经过 LLM——LLM 只接触脱敏后文本)**: +敏感值**替换为占位符**而非丢弃整条,保留对话语境(如"借号"互动是人格素材,凭证不是)。 +实现:`processor.desensitize()`,四层,覆盖场景:借号/验证码代收/密码口令/兑换码卡密/密保/收入/联系方式变体/位置。 + +| 规则层 | 模式 | 占位符 | +|---|---|---| +| 明确模式(按最长优先排序,防截胡) | 身份证 → 银行卡 → 邮箱 → 手机号(含分隔变体) → IP → wxid → 坐标 → 车牌 | `[身份证]` `[银行卡]` `[邮箱]` `[手机号]` `[IP]` `[微信号]` `[坐标]` `[车牌]` | +| 定位式(同条"关键词+值") | `密码是 xyz789` `账号 abc123` `激活码 ABCDE-1` `验证码是 123456` `VX: xxx` `月薪 25000`(连接词支持 是/为/冒号/空格) | `[密码]` `[账号]` `[兑换码]` `[验证码]` `[微信号]` `[收入]` | +| 跨条语境 | 关键词在附近消息(如"收下验证码"→ 下一条 `123456`)→ 本条值按语境类型替换 | `[验证码]` `[密码]` `[兑换码]` | +| 兜底 | 裸长数字串 ≥6 位 → `[账号]`;字母+数字混合 ≥6 位 → `[密码]`(保守替换,宁误杀不放过) | `[账号]` `[密码]` | + +语境来源:本群最近 3 条已治理文本(复用复读检测的内存窗口)。 +待扩展场景(⏳):密保答案("你妈妈的名字")、QQ 号文本、代充代练语境。 + +- 噪声过滤:纯表情图(无文字)、复读、命令/签到、长链接轰炸 +- 长文截断(约 200 字/条) +- 采样:连续刷屏 5 秒内只记 1 条 + +## 7. 调度与触发(⏳ 草案) + +| 方式 | 条件 | +|---|---| +| 手动 | 管理员 `生成人物卡 @xxx`(强制,无视阈值) | +| 印象 | 新语料 ≥ 50 条(⏳)且距上次印象 ≥ 24h | +| 画像 | 新印象 ≥ 5 条(⏳)或语料显著增长;首次需语料 ≥ 200 条 | +| 防重入 | 同人同群生成中加锁 | + +## 8. 入口层命令集(⏳ 草案) + +`加入人设` `退出人设`(opt-in 控制)、`查看人设 @xxx`(展示九段卡)、`生成人设 @xxx`(管理员强制)。 + +## 9. 借鉴与不借鉴 MaiBot(已定稿 ✅) + +**借鉴**:两级流水线(印象机制)、九段协议格式(段落文本协议)、证据纪律三层、指纹缓存、防串人(证据绑定 user_id)。 + +**不借鉴**:向量库 + BM25 双路召回 + PPR(语料量级 SQL 直查即可)、完整 A_memorix 记忆系统、md5 person_id(QQ 号即 id)。 + +## 10. 开发阶段 + +- **Phase 1**:数据层(四表 + 仓储)✅ 本文档落盘时完成 +- **Phase 2**:治理层(采集过滤 + opt-in 命令) +- **Phase 3**:分析层(印象/画像生成,LLM 客户端) +- **Phase 4**:调度层(触发/锁)+ 呈现层(人物卡展示) +- ⏳ 后续可选:galgame 风格卡面图片渲染(协议文本为渲染源) diff --git a/hexi/plugins/nonebot_plugin_galgame_card/__init__.py b/hexi/plugins/nonebot_plugin_galgame_card/__init__.py new file mode 100644 index 0000000..77abb08 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/__init__.py @@ -0,0 +1,187 @@ +"""群聊人设卡 —— 基于群聊语料蒸馏成员形象,生成 galgame 风格人物卡 + +消息入口:on_message 监听全部消息事件,类型注解过滤出群聊, +两级闸门(群开关 + 个人 opt-in)通过后,治理层处理落库。 + +当前进度:数据层 + 采集层(消息路径)完成;总结路径(印象/画像)待实现。 +""" + +import json +import time +from collections import deque +from typing import Optional + +from nonebot import get_driver, on_message, require + +require("nonebot_plugin_orm") + +from nonebot.adapters.onebot.v11 import GroupMessageEvent +from nonebot.plugin import PluginMetadata + +# ── 禁用 nonebot_plugin_orm 的启动自动同步 ───────────────────────────── +# .env 里 ALEMBIC_STARTUP_CHECK=false 时,orm 插件每次启动都会 autogenerate +# 同步数据库模式;模型一有变更(改 models.py)就会清空整表数据(已实测踩坑)。 +# 本插件的 schema 演进统一走 repository.ensure_schema() 显式迁移, +# 因此把 migrate.sync 替换为安全空操作。改动必须在插件导入期完成 +# (早于 orm 的 on_startup 钩子执行)。 +from nonebot import logger as _logger + +try: + import nonebot_plugin_orm.migrate as _orm_migrate + + def _safe_sync(*_args, **_kwargs): + # 同步函数:orm 用 greenlet_spawn 同步调用 migrate.sync, + # 若写成 async def 会产生 never-awaited coroutine 警告 + _logger.debug("galgame_card | 已禁用 orm 自动同步(schema 演进由 ensure_schema 接管)") + + _orm_migrate.sync = _safe_sync +except ImportError: + _logger.warning("galgame_card | 无法禁用 orm 自动同步,请检查 nonebot_plugin_orm 是否安装") + +from . import models # noqa: F401 # 确保表结构注册 +from . import repository, processor +from . import web # noqa: F401 # Web 管理后台(/galgame_card) + +from hexi.web_config import register_plugin_config # noqa: E402 +from hexi.web_plugin_registry import register_web_plugin # noqa: E402 +from . import web_hub # noqa: E402 + + +def _apply_galgame_config(values: dict) -> None: + """Web 保存后热刷新:直接改 config 模块的 pydantic 对象,无需重启。""" + import sys + + conf_mod = sys.modules.get("hexi.plugins.nonebot_plugin_galgame_card.config") + if conf_mod is None: + return + conf = getattr(conf_mod, "config", None) + if conf is None: + return + for key, value in values.items(): + try: + setattr(conf, key, value) + except Exception: # noqa: BLE001 + pass + + +def _get_galgame_config_values() -> dict: + """Web 表单回填当前生效值。""" + import sys + + conf_mod = sys.modules.get("hexi.plugins.nonebot_plugin_galgame_card.config") + conf = getattr(conf_mod, "config", None) if conf_mod else None + if conf is None: + return {} + keys = ("web_enable", "web_username", "web_password", "web_secret_key", "image_vision_enabled") + return {k: getattr(conf, k, None) for k in keys} + + +register_plugin_config( + __name__, + { + "fields": [ + {"key": "web_enable", "label": "Web 后台启用", "type": "bool", "default": True}, + {"key": "web_username", "label": "Web 登录账号", "type": "string", "default": "admin"}, + {"key": "web_password", "label": "Web 登录密码", "type": "password", "default": "galgame", "secret": True}, + {"key": "web_secret_key", "label": "Web 签名密钥", "type": "password", "default": "galgame-card-secret-key", "secret": True}, + {"key": "image_vision_enabled", "label": "图片识别启用", "type": "bool", "default": False}, + ] + }, + apply=_apply_galgame_config, + getter=_get_galgame_config_values, +) + +# 注册到统一 Web 管理台(/hub):hub 启动时挂载 /api/galgame_card +register_web_plugin( + "galgame_card", + "群聊人设卡", + "user", + lambda: web_hub.build_admin_app(), + module_name=__name__, +) + +__plugin_meta__ = PluginMetadata( + name="群聊人设卡", + description="基于群聊语料蒸馏成员形象,生成 galgame 风格人物卡", + usage="开发中……", +) + +# 采样/复读检测的内存状态(不进库) +_recent_texts: dict[int, deque[str]] = {} # group_id -> 最近消息文本 +_last_store: dict[tuple[int, int], float] = {} # (group_id, user_id) -> 上次落库时间戳 + + +def _is_repeat(group_id: int, content: str) -> bool: + """复读检测:内容在最近 N 条里出现过则丢弃""" + queue = _recent_texts.setdefault(group_id, deque(maxlen=processor.REPEAT_WINDOW)) + if content in queue: + return True + queue.append(content) + return False + + +def _throttled(group_id: int, user_id: int) -> bool: + """刷屏采样:5 秒内同一个人只落库一次""" + key = (group_id, user_id) + now = time.time() + if now - _last_store.get(key, 0) < processor.THROTTLE_SECONDS: + return True + _last_store[key] = now + return False + + +_driver = get_driver() + + +@_driver.on_startup +async def _ensure_schema(): + """老库迁移(persona_group.group_name 列),幂等""" + await repository.ensure_schema() + + +collector = on_message(block=False) # 监听全部消息事件,不拦截其他插件 + + +@collector.handle() +async def collect(event: GroupMessageEvent): + # 鉴权:两级闸门(群开关 → 个人 opt-in) + if not await repository.is_group_enabled(event.group_id): + return + if not await repository.is_joined(event.user_id, event.group_id): + return + # 机器人自己(如转发)不收 + if event.user_id == event.self_id: + return + + command_starts = get_driver().config.command_start + # 治理:文本 / 图片 / 表情任一存在才记录 + if not processor.has_recordable_content(event): + return + text = processor.filter_content( + processor.extract_text(event), command_starts=command_starts + ) + image_hashes = processor.extract_image_hashes(event) + content = processor.build_content( + text or "", len(image_hashes), processor.count_faces(event) + ) + if content is None: + return + # 脱敏:敏感值替换为占位符(语境 = 本群最近几条已治理文本,用于"验证码/密码"类强化) + context = " ".join(_recent_texts.get(event.group_id, ())) + content = processor.desensitize(content, context) + # 采样:复读 + 刷屏 + if _is_repeat(event.group_id, content): + return + if _throttled(event.group_id, event.user_id): + return + + await repository.add_chat_log( + user_id=event.user_id, + group_id=event.group_id, + content=content, + nickname=event.sender.card or event.sender.nickname or "", + target_user_id=processor.extract_target_user_id(event), + reply_to_content=processor.extract_reply_to_content(event), + image_count=len(image_hashes), + image_hashes=json.dumps(image_hashes, ensure_ascii=False) if image_hashes else None, + ) diff --git a/hexi/plugins/nonebot_plugin_galgame_card/config.py b/hexi/plugins/nonebot_plugin_galgame_card/config.py new file mode 100644 index 0000000..660246e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/config.py @@ -0,0 +1,19 @@ +"""插件配置(Web 管理后台) + +env 变量名与字段名对应(大写):WEB_ENABLE / WEB_USERNAME / WEB_PASSWORD / WEB_SECRET_KEY +""" + +from nonebot import get_plugin_config +from pydantic import BaseModel + + +class Config(BaseModel): + web_enable: bool = True + web_username: str = "admin" + web_password: str = "galgame" + web_secret_key: str = "galgame-card-secret-key" + # 图片多模态识别(预留接口,当前未启用;将来接入后置 True) + image_vision_enabled: bool = False + + +config = get_plugin_config(Config) diff --git a/hexi/plugins/nonebot_plugin_galgame_card/models.py b/hexi/plugins/nonebot_plugin_galgame_card/models.py new file mode 100644 index 0000000..fd4b53c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/models.py @@ -0,0 +1,127 @@ +"""群聊人设卡 —— 数据层:表结构定义(与 DESIGN.md §3 对应)""" + +from datetime import datetime +from typing import Optional + +from nonebot import require + +require("nonebot_plugin_orm") + +from nonebot_plugin_orm import Model +from sqlalchemy import BigInteger, Boolean, DateTime, Index, Integer, String, Text, UniqueConstraint +from sqlalchemy.orm import Mapped, mapped_column + + +class PersonaGroup(Model): + """管理群列表 + 采集开关 + + 一行 = 一个被管理的群(由用户在 Web 后台从 OneBot 群列表中选择加入); + enabled 控制该群是否采集(群关闭则群里所有人都不采集)。 + 主页面/采集器只读这张表,不依赖 OneBot 在线。 + """ + + __tablename__ = "persona_group" + + group_id: Mapped[int] = mapped_column(BigInteger, primary_key=True) + group_name: Mapped[str] = mapped_column(String(64), default="") # 群名快照(添加时记录) + enabled: Mapped[bool] = mapped_column(Boolean, default=False) + updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now) + + +class PersonaUser(Model): + """人设计划参与者(按群 opt-in,一行一人一群)""" + + __tablename__ = "persona_user" + + user_id: Mapped[int] = mapped_column(BigInteger, primary_key=True) + group_id: Mapped[int] = mapped_column(BigInteger, primary_key=True) + joined_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now) + + +class PersonaChatLog(Model): + """采集语料(五维):内容 / 谁发的 / 发给谁 / 几点发的 / 被回复内容快照 + + 只存治理层处理后的纯文本;数据来源无关(群事件、历史导入均可写入)。 + """ + + __tablename__ = "persona_chat_log" + __table_args__ = ( + Index("ix_persona_log_user_time", "user_id", "group_id", "created_at"), + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + user_id: Mapped[int] = mapped_column(BigInteger) # 谁发的 + group_id: Mapped[int] = mapped_column(BigInteger) + nickname: Mapped[str] = mapped_column(String(64), default="") # 群昵称快照 + content: Mapped[str] = mapped_column(Text) # 内容 + target_user_id: Mapped[Optional[int]] = mapped_column( # 发给谁(回复/@ 对象,或继承自链条) + BigInteger, nullable=True + ) + target_inherited: Mapped[bool] = mapped_column( # target 是否从发言段链条继承 + Boolean, default=False + ) + follows_id: Mapped[Optional[int]] = mapped_column( # 同一说话人的上一条语料 id(发言段链条) + Integer, nullable=True + ) + image_count: Mapped[int] = mapped_column(Integer, default=0) # 本条图片数 + image_hashes: Mapped[Optional[str]] = mapped_column( # 图片 hash 列表 JSON(表情包去重识别) + Text, nullable=True + ) + reply_to_content: Mapped[Optional[str]] = mapped_column( # 被回复内容快照 + Text, nullable=True + ) + created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now) # 几点发的 + + +class PersonaImpression(Model): + """印象:语料 → LLM 自然语言印象(两级流水线中间产物,画像的输入)""" + + __tablename__ = "persona_impression" + __table_args__ = ( + Index("ix_persona_impression_user_time", "user_id", "group_id", "created_at"), + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + user_id: Mapped[int] = mapped_column(BigInteger) + group_id: Mapped[int] = mapped_column(BigInteger) + content: Mapped[str] = mapped_column(Text) # 自然语言印象(话题/氛围/互动) + cover_from_id: Mapped[int] = mapped_column(Integer, default=0) # 覆盖语料起点 id + cover_to_id: Mapped[int] = mapped_column(Integer, default=0) # 覆盖语料终点 id(增量依据) + model: Mapped[str] = mapped_column(String(64), default="") + created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now) + + +class PersonaImage(Model): + """图片识别结果缓存(多模态预留):同一 hash 只识别一次 + + 当前未启用识别(vision.recognizer 为占位实现),表结构先行预留。 + """ + + __tablename__ = "persona_image" + + hash: Mapped[str] = mapped_column(String(64), primary_key=True) # 图片 hash(与 chat_log.image_hashes 对应) + description: Mapped[str] = mapped_column(Text, default="") # 多模态识别结果 + model: Mapped[str] = mapped_column(String(64), default="") # 识别模型 + recognized_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now) + + +class PersonaSummary(Model): + """画像快照:九段 markdown 协议(DESIGN.md §4),版本化永久留档""" + + __tablename__ = "persona_summary" + __table_args__ = ( + UniqueConstraint( + "user_id", "group_id", "version", name="uq_persona_summary_user_group_version" + ), + Index("ix_persona_summary_user_group", "user_id", "group_id"), + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + user_id: Mapped[int] = mapped_column(BigInteger) + group_id: Mapped[int] = mapped_column(BigInteger) + version: Mapped[int] = mapped_column(Integer) + card_text: Mapped[str] = mapped_column(Text) # 九段 markdown 画像原文 + corpus_count: Mapped[int] = mapped_column(Integer, default=0) # 元信息:语料覆盖条数 + impression_count: Mapped[int] = mapped_column(Integer, default=0) # 元信息:印象条数 + model: Mapped[str] = mapped_column(String(64), default="") + created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.now) diff --git a/hexi/plugins/nonebot_plugin_galgame_card/processor.py b/hexi/plugins/nonebot_plugin_galgame_card/processor.py new file mode 100644 index 0000000..78c9dd3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/processor.py @@ -0,0 +1,218 @@ +"""治理层:纯函数处理(无状态、可单测) + +命中即弃的规则返回 None;`__init__.py` 入口层只负责组装这些函数。 +""" + +import re +from typing import Iterable, Optional + +from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message + +# 敏感数据替换(本地正则,绝不经过 LLM —— DESIGN.md §6 硬约束) +# 值类型正则 +CODE_RE = re.compile(r"(? str: + """消息段 → 纯文本:Text 拼接,At 转 @qq,其余(图/表情/引用)丢弃""" + parts = [] + for seg in message: + if seg.type == "text": + parts.append(seg.data.get("text", "")) + elif seg.type == "at": + qq = str(seg.data.get("qq", "")) + if qq and qq not in {"all", "0"}: + parts.append(f"@{qq}") + return "".join(parts).strip() + + +def extract_text(event: GroupMessageEvent) -> str: + return _message_to_text(event.message) + + +# 图片 CQ 码 file 字段里的 32 位 hash(表情包去重识别用) +IMG_HASH_RE = re.compile(r"[0-9a-f]{32}") + + +def image_hash_from_file(file: str, url: str = "") -> str: + """从图片 CQ 码提取稳定标识:优先 file 里的 32 位 hash,回退 url 文件名""" + f = str(file or "") + m = IMG_HASH_RE.search(f.lower()) + if m: + return m.group(0) + u = str(url or "").strip() + if u: + name = u.rstrip("/").split("/")[-1] + m = IMG_HASH_RE.search(name.lower()) + if m: + return m.group(0) + return name[:64] or "image" + return f[:64] or "image" + + +def extract_image_hashes(event: GroupMessageEvent) -> list[str]: + """本条消息里的图片标识列表(同一张图反复发 = 标志性表情包)""" + return [ + image_hash_from_file( + str(seg.data.get("file", "") or ""), str(seg.data.get("url", "") or "") + ) + for seg in event.message + if seg.type == "image" + ] + + +def count_faces(event: GroupMessageEvent) -> int: + """QQ 原生表情数量(只记数量,不记 id→名字映射)""" + return sum(1 for seg in event.message if seg.type == "face") + + +def has_recordable_content(event: GroupMessageEvent) -> bool: + """文本 / 图片 / 表情 任一存在即可记录(纯引用等空消息除外)""" + for seg in event.message: + if seg.type == "text" and seg.data.get("text", "").strip(): + return True + if seg.type in {"image", "face"}: + return True + return False + + +def build_content(text: str, image_count: int = 0, face_count: int = 0) -> Optional[str]: + """组装落库内容:文本 + 图片/表情标记;全空返回 None""" + parts: list[str] = [] + if text: + parts.append(text) + if image_count and face_count: + parts.append(f"[图片×{image_count}][表情×{face_count}]") + elif image_count: + parts.append(f"[图片×{image_count}]") + elif face_count: + parts.append(f"[表情×{face_count}]") + if not parts: + return None + return " ".join(parts) + + +def extract_target_user_id(event: GroupMessageEvent) -> Optional[int]: + """发给谁:回复的 sender 优先,其次首个 @""" + if event.reply and event.reply.sender: + return int(event.reply.sender.user_id) + for seg in event.message: + if seg.type == "at": + qq = str(seg.data.get("qq", "")) + if qq.isdigit(): + return int(qq) + return None + + +def extract_reply_to_content(event: GroupMessageEvent) -> Optional[str]: + """被回复内容快照(适配器事件直接带原文)""" + if not event.reply: + return None + text = _message_to_text(event.reply.message) + return text[:MAX_REPLY_CTX_LEN] or None + + +def desensitize(content: str, context_text: str = "") -> str: + """敏感数据替换为占位符(本地正则,不经过 LLM) + + context_text 为附近消息拼接文本,用于跨条语境强化 + (如"收下验证码"在 A 的消息、验证码值在 B 的消息)。 + 保守替换:宁误杀不放过(占位符不影响人格总结)。 + """ + out = content + # 1) 明确模式:手机号/身份证/银行卡/邮箱/IP/微信号/坐标/车牌 + for pattern, placeholder in CLEAR_PATTERNS: + out = pattern.sub(placeholder, out) + # 2) 定位式:同条"关键词 + 值"精准替换,只替换值、保留关键词 + # (占位符不含字母数字,替换后兜底不再命中) + for pattern, placeholder in KEY_VALUE_PATTERNS: + out = pattern.sub( + lambda m: m.group(0)[: m.start(1) - m.start(0)] + placeholder, out + ) + # 3) 跨条语境:关键词在附近消息 → 本条的值按语境类型替换 + hint = f"{content} {context_text}" + for hint_re, placeholder, value_re in CROSS_HINTS: + if hint_re.search(hint): + out = value_re.sub(placeholder, out) + # 4) 兜底:无语境的长串(保守替换) + out = BARE_DIGITS_RE.sub("[账号]", out) + out = MIXED_RE.sub("[密码]", out) + return out + + +def is_command(content: str, command_starts: Iterable[str]) -> bool: + """命令前缀命中(空前缀不算,避免全量误杀)""" + starts = [s for s in command_starts if s] + return any(content.startswith(s) for s in starts) + + +def is_url_flood(content: str) -> bool: + return content.count("http") >= URL_FLOOD_LIMIT + + +def truncate(content: str, limit: int = MAX_CONTENT_LEN) -> str: + return content[:limit] + + +def filter_content(content: str, command_starts: Iterable[str]) -> Optional[str]: + """噪声治理:空/命令/链接轰炸 → None;否则截断返回(脱敏由 desensitize 单独做)""" + if not content: + return None + if is_command(content, command_starts): + return None + if is_url_flood(content): + return None + return truncate(content) diff --git a/hexi/plugins/nonebot_plugin_galgame_card/repository.py b/hexi/plugins/nonebot_plugin_galgame_card/repository.py new file mode 100644 index 0000000..d13295b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/repository.py @@ -0,0 +1,577 @@ +"""群聊人设卡 —— 数据层:仓储 + +只做存储读写,不关心数据来源(群事件、历史导入走同一个入口)。 +业务层与数据来源层都只通过这里的函数访问数据库。 +""" + +from datetime import datetime +from typing import Optional + +from nonebot import require + +require("nonebot_plugin_orm") + +from nonebot_plugin_orm import get_session +from sqlalchemy import delete, func, select + +from .models import ( + PersonaChatLog, + PersonaGroup, + PersonaImage, + PersonaImpression, + PersonaSummary, + PersonaUser, +) + +# 单用户单群语料滚动保留上限(超出淘汰最旧,DESIGN.md §6) +ROLLING_WINDOW = 3000 + +# 发言段链条:同一说话人两条消息间隔不超过该秒数,视为同一段发言 +FOLLOWS_MAX_GAP = 300 # 5 分钟 + + +# ---------- 管理群列表(数据来源总闸门) ---------- + +async def ensure_schema() -> None: + """schema 管理(幂等):补列 + 建新表。 + + orm 自动同步已被禁用(见 __init__.py),且 orm 的启动建表早于本插件 + 模型导入(新表不会自动建),因此建表/补列都走这里。 + """ + from sqlalchemy import text + from sqlalchemy.exc import OperationalError + + statements = [ + "ALTER TABLE persona_group ADD COLUMN group_name VARCHAR(64) DEFAULT ''", + "ALTER TABLE persona_chat_log ADD COLUMN follows_id INTEGER", + "ALTER TABLE persona_chat_log ADD COLUMN target_inherited BOOLEAN DEFAULT 0", + "ALTER TABLE persona_chat_log ADD COLUMN image_count INTEGER DEFAULT 0", + "ALTER TABLE persona_chat_log ADD COLUMN image_hashes TEXT", + ] + async with get_session() as session: + for stmt in statements: + try: + await session.execute(text(stmt)) + await session.commit() + except OperationalError: + pass # 列已存在 + # 幂等创建缺失的表(本插件全部模型共用同一 metadata) + def _create_tables(sync_session) -> None: + PersonaImage.metadata.create_all(sync_session.connection()) + + await session.run_sync(_create_tables) + + +async def list_groups() -> list[PersonaGroup]: + """全部被管理的群(数据库直读,不依赖 OneBot)""" + async with get_session() as session: + result = await session.execute( + select(PersonaGroup).order_by(PersonaGroup.group_id) + ) + return list(result.scalars().all()) + + +async def add_group(group_id: int, group_name: str = "") -> None: + """加入管理列表(幂等:已存在则更新名称),默认不采集""" + async with get_session() as session: + row = await session.get(PersonaGroup, group_id) + if row is None: + session.add(PersonaGroup(group_id=group_id, group_name=group_name)) + elif group_name and row.group_name != group_name: + row.group_name = group_name + await session.commit() + + +async def remove_group(group_id: int) -> None: + """移出管理列表(数据保留,重新加入可续上)""" + async with get_session() as session: + await session.execute( + delete(PersonaGroup).where(PersonaGroup.group_id == group_id) + ) + await session.commit() + + +async def backfill_group_names(names: dict[int, str]) -> None: + """用 OneBot 群列表回填已管理群的名称(仅在拉取群列表时顺带做)""" + async with get_session() as session: + rows = (await session.execute(select(PersonaGroup))).scalars().all() + changed = False + for row in rows: + name = names.get(row.group_id, "") + if name and row.group_name != name: + row.group_name = name + changed = True + if changed: + await session.commit() + + +async def set_group_enabled(group_id: int, enabled: bool) -> None: + """开/关某群的采集(幂等:不存在则创建,存在则更新)""" + async with get_session() as session: + row = await session.get(PersonaGroup, group_id) + if row is None: + session.add(PersonaGroup(group_id=group_id, enabled=enabled)) + else: + row.enabled = enabled + row.updated_at = datetime.now() + await session.commit() + + +async def is_group_enabled(group_id: int) -> bool: + async with get_session() as session: + result = await session.execute( + select(PersonaGroup).where(PersonaGroup.group_id == group_id) + ) + row = result.scalar() + return bool(row and row.enabled) + + +async def enabled_groups() -> list[int]: + """全部开启采集的群(调度/采集层扫描用)""" + async with get_session() as session: + result = await session.execute( + select(PersonaGroup.group_id).where(PersonaGroup.enabled.is_(True)) + ) + return [row[0] for row in result.all()] + + +# ---------- 参与者 ---------- + +async def is_joined(user_id: int, group_id: int) -> bool: + async with get_session() as session: + result = await session.execute( + select(PersonaUser).where( + PersonaUser.user_id == user_id, PersonaUser.group_id == group_id + ) + ) + return result.scalar() is not None + + +async def join(user_id: int, group_id: int) -> None: + async with get_session() as session: + session.add(PersonaUser(user_id=user_id, group_id=group_id)) + await session.commit() + + +async def leave(user_id: int, group_id: int) -> None: + async with get_session() as session: + await session.execute( + delete(PersonaUser).where( + PersonaUser.user_id == user_id, PersonaUser.group_id == group_id + ) + ) + await session.commit() + + +async def joined_users(group_id: int) -> list[int]: + """某群全部参与者(调度层扫描用)""" + async with get_session() as session: + result = await session.execute( + select(PersonaUser.user_id).where(PersonaUser.group_id == group_id) + ) + return [row[0] for row in result.all()] + + +# ---------- 语料 ---------- + +async def add_chat_log( + user_id: int, + group_id: int, + content: str, + nickname: str = "", + target_user_id: Optional[int] = None, + reply_to_content: Optional[str] = None, + image_count: int = 0, + image_hashes: Optional[str] = None, +) -> int: + """落库一条语料,返回新语料 id + + 发言段链条:同一说话人的上一条语料记为 follows_id(间隔 ≤ FOLLOWS_MAX_GAP); + 本条无显式目标(回复/@)时从链条继承 target_user_id——对上面那句的解释/补充 + 仍视为发给同一对象,不丢语境。 + """ + async with get_session() as session: + prev = ( + await session.execute( + select(PersonaChatLog) + .where( + PersonaChatLog.user_id == user_id, + PersonaChatLog.group_id == group_id, + ) + .order_by(PersonaChatLog.id.desc()) + .limit(1) + ) + ).scalar() + follows_id = None + inherited = False + if prev is not None and ( + datetime.now() - prev.created_at + ).total_seconds() <= FOLLOWS_MAX_GAP: + follows_id = prev.id + if target_user_id is None: + target_user_id = prev.target_user_id + inherited = target_user_id is not None + log = PersonaChatLog( + user_id=user_id, + group_id=group_id, + nickname=nickname, + content=content, + target_user_id=target_user_id, + target_inherited=inherited, + follows_id=follows_id, + image_count=image_count, + image_hashes=image_hashes, + reply_to_content=reply_to_content, + ) + session.add(log) + await session.commit() + await session.refresh(log) + return log.id + + +async def count_chat_log(user_id: int, group_id: int) -> int: + async with get_session() as session: + result = await session.execute( + select(func.count(PersonaChatLog.id)).where( + PersonaChatLog.user_id == user_id, PersonaChatLog.group_id == group_id + ) + ) + return result.scalar_one() + + +async def latest_chat_logs( + user_id: int, group_id: int, limit: int, before_id: Optional[int] = None +) -> list[PersonaChatLog]: + """按 id 倒序取最新 limit 条;before_id 用于翻页""" + stmt = ( + select(PersonaChatLog) + .where(PersonaChatLog.user_id == user_id, PersonaChatLog.group_id == group_id) + .order_by(PersonaChatLog.id.desc()) + .limit(limit) + ) + if before_id is not None: + stmt = stmt.where(PersonaChatLog.id <= before_id) + async with get_session() as session: + result = await session.execute(stmt) + return list(result.scalars().all()) + + +async def chat_logs_since( + user_id: int, group_id: int, since_id: int, limit: int +) -> list[PersonaChatLog]: + """按 id 正序取 id > since_id 的语料(增量印象生成的输入)""" + async with get_session() as session: + result = await session.execute( + select(PersonaChatLog) + .where( + PersonaChatLog.user_id == user_id, + PersonaChatLog.group_id == group_id, + PersonaChatLog.id > since_id, + ) + .order_by(PersonaChatLog.id.asc()) + .limit(limit) + ) + return list(result.scalars().all()) + + +async def prune_chat_log(user_id: int, group_id: int, keep: int = ROLLING_WINDOW) -> int: + """淘汰滚动窗口外的旧语料,返回删除条数""" + async with get_session() as session: + result = await session.execute( + select(PersonaChatLog.id) + .where( + PersonaChatLog.user_id == user_id, PersonaChatLog.group_id == group_id + ) + .order_by(PersonaChatLog.id.desc()) + .offset(keep) + ) + stale_ids = [row[0] for row in result.all()] + if stale_ids: + await session.execute( + delete(PersonaChatLog).where(PersonaChatLog.id.in_(stale_ids)) + ) + await session.commit() + return len(stale_ids) + + +# ---- 统计与分页(Web 管理后台用) ---- + +async def count_chat_log_group(group_id: int) -> int: + async with get_session() as session: + result = await session.execute( + select(func.count(PersonaChatLog.id)).where( + PersonaChatLog.group_id == group_id + ) + ) + return result.scalar_one() + + +async def count_impressions_group(group_id: int) -> int: + async with get_session() as session: + result = await session.execute( + select(func.count(PersonaImpression.id)).where( + PersonaImpression.group_id == group_id + ) + ) + return result.scalar_one() + + +async def count_summaries_group(group_id: int) -> int: + async with get_session() as session: + result = await session.execute( + select(func.count(PersonaSummary.id)).where( + PersonaSummary.group_id == group_id + ) + ) + return result.scalar_one() + + +async def corpus_counts_by_group() -> dict[int, int]: + """各群语料条数(一次聚合查询,替代逐群 count)""" + async with get_session() as session: + result = await session.execute( + select(PersonaChatLog.group_id, func.count(PersonaChatLog.id)).group_by( + PersonaChatLog.group_id + ) + ) + return {int(row[0]): int(row[1]) for row in result.all()} + + +async def impression_counts_by_group() -> dict[int, int]: + async with get_session() as session: + result = await session.execute( + select(PersonaImpression.group_id, func.count(PersonaImpression.id)).group_by( + PersonaImpression.group_id + ) + ) + return {int(row[0]): int(row[1]) for row in result.all()} + + +async def summary_counts_by_group() -> dict[int, int]: + async with get_session() as session: + result = await session.execute( + select(PersonaSummary.group_id, func.count(PersonaSummary.id)).group_by( + PersonaSummary.group_id + ) + ) + return {int(row[0]): int(row[1]) for row in result.all()} + + +async def participant_counts_by_group() -> dict[int, int]: + async with get_session() as session: + result = await session.execute( + select(PersonaUser.group_id, func.count(PersonaUser.user_id)).group_by( + PersonaUser.group_id + ) + ) + return {int(row[0]): int(row[1]) for row in result.all()} + + +async def chat_log_stats_by_user(group_id: int) -> list[tuple[int, int]]: + """群内每人语料条数((user_id, count),按条数倒序)""" + async with get_session() as session: + result = await session.execute( + select(PersonaChatLog.user_id, func.count(PersonaChatLog.id)) + .where(PersonaChatLog.group_id == group_id) + .group_by(PersonaChatLog.user_id) + .order_by(func.count(PersonaChatLog.id).desc()) + ) + return [(int(row[0]), int(row[1])) for row in result.all()] + + +async def list_logs( + group_id: int, + user_id: Optional[int] = None, + offset: int = 0, + limit: int = 50, +) -> list[PersonaChatLog]: + """语料分页(倒序,新在前)""" + stmt = select(PersonaChatLog).where(PersonaChatLog.group_id == group_id) + if user_id is not None: + stmt = stmt.where(PersonaChatLog.user_id == user_id) + stmt = stmt.order_by(PersonaChatLog.id.desc()).offset(offset).limit(limit) + async with get_session() as session: + result = await session.execute(stmt) + return list(result.scalars().all()) + + +async def count_logs_filtered(group_id: int, user_id: Optional[int] = None) -> int: + stmt = select(func.count(PersonaChatLog.id)).where( + PersonaChatLog.group_id == group_id + ) + if user_id is not None: + stmt = stmt.where(PersonaChatLog.user_id == user_id) + async with get_session() as session: + result = await session.execute(stmt) + return result.scalar_one() + + +async def list_impressions_group( + group_id: int, offset: int = 0, limit: int = 50 +) -> list[PersonaImpression]: + async with get_session() as session: + result = await session.execute( + select(PersonaImpression) + .where(PersonaImpression.group_id == group_id) + .order_by(PersonaImpression.id.desc()) + .offset(offset) + .limit(limit) + ) + return list(result.scalars().all()) + + +async def list_summaries_group(group_id: int) -> list[PersonaSummary]: + async with get_session() as session: + result = await session.execute( + select(PersonaSummary) + .where(PersonaSummary.group_id == group_id) + .order_by(PersonaSummary.version.desc()) + ) + return list(result.scalars().all()) + + +async def delete_logs(group_id: int, user_id: Optional[int] = None) -> int: + """删除语料(可只删某人),返回删除条数""" + stmt = delete(PersonaChatLog).where(PersonaChatLog.group_id == group_id) + if user_id is not None: + stmt = stmt.where(PersonaChatLog.user_id == user_id) + async with get_session() as session: + result = await session.execute(stmt) + await session.commit() + return result.rowcount or 0 + + +async def clear_group_data(group_id: int) -> None: + """清空某群全部数据:语料 + 印象 + 画像 + 参与者(群开关行保留)""" + async with get_session() as session: + await session.execute(delete(PersonaChatLog).where(PersonaChatLog.group_id == group_id)) + await session.execute(delete(PersonaImpression).where(PersonaImpression.group_id == group_id)) + await session.execute(delete(PersonaSummary).where(PersonaSummary.group_id == group_id)) + await session.execute(delete(PersonaUser).where(PersonaUser.group_id == group_id)) + await session.commit() + + +# ---------- 印象 ---------- + +async def add_impression( + user_id: int, + group_id: int, + content: str, + cover_from_id: int, + cover_to_id: int, + model: str = "", +) -> None: + async with get_session() as session: + session.add( + PersonaImpression( + user_id=user_id, + group_id=group_id, + content=content, + cover_from_id=cover_from_id, + cover_to_id=cover_to_id, + model=model, + ) + ) + await session.commit() + + +async def latest_impression(user_id: int, group_id: int) -> Optional[PersonaImpression]: + async with get_session() as session: + result = await session.execute( + select(PersonaImpression) + .where( + PersonaImpression.user_id == user_id, + PersonaImpression.group_id == group_id, + ) + .order_by(PersonaImpression.id.desc()) + .limit(1) + ) + return result.scalar() + + +async def count_impressions(user_id: int, group_id: int) -> int: + async with get_session() as session: + result = await session.execute( + select(func.count(PersonaImpression.id)).where( + PersonaImpression.user_id == user_id, + PersonaImpression.group_id == group_id, + ) + ) + return result.scalar_one() + + +async def list_impressions( + user_id: int, group_id: int, limit: int +) -> list[PersonaImpression]: + """按 id 正序取最近 limit 条印象(画像生成的输入,最旧在前)""" + async with get_session() as session: + result = await session.execute( + select(PersonaImpression) + .where( + PersonaImpression.user_id == user_id, + PersonaImpression.group_id == group_id, + ) + .order_by(PersonaImpression.id.desc()) + .limit(limit) + ) + return list(reversed(result.scalars().all())) + + +# ---------- 画像 ---------- + +async def latest_summary(user_id: int, group_id: int) -> Optional[PersonaSummary]: + async with get_session() as session: + result = await session.execute( + select(PersonaSummary) + .where( + PersonaSummary.user_id == user_id, + PersonaSummary.group_id == group_id, + ) + .order_by(PersonaSummary.version.desc()) + .limit(1) + ) + return result.scalar() + + +async def add_summary( + user_id: int, + group_id: int, + card_text: str, + corpus_count: int = 0, + impression_count: int = 0, + model: str = "", +) -> int: + """新增画像版本,version 自动 +1,返回新版本号。 + + 注意:并发调用可能撞 UNIQUE(user_id, group_id, version),由调度层加锁保护。 + """ + prev = await latest_summary(user_id, group_id) + version = (prev.version + 1) if prev else 1 + async with get_session() as session: + session.add( + PersonaSummary( + user_id=user_id, + group_id=group_id, + version=version, + card_text=card_text, + corpus_count=corpus_count, + impression_count=impression_count, + model=model, + ) + ) + await session.commit() + return version + + +async def list_summaries(user_id: int, group_id: int) -> list[PersonaSummary]: + """全部历史版本(版本对比用),旧版在前""" + async with get_session() as session: + result = await session.execute( + select(PersonaSummary) + .where( + PersonaSummary.user_id == user_id, + PersonaSummary.group_id == group_id, + ) + .order_by(PersonaSummary.version.asc()) + ) + return list(result.scalars().all()) diff --git a/hexi/plugins/nonebot_plugin_galgame_card/vision.py b/hexi/plugins/nonebot_plugin_galgame_card/vision.py new file mode 100644 index 0000000..b177b8f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/vision.py @@ -0,0 +1,34 @@ +"""图片多模态识别接口(预留,暂未实现) + +将来接入多模态 LLM 识别图片内容(表情包梗、截图内容、图片类型等), +识别结果按 hash 缓存到 persona_image 表,分析层组装窗口时把图片描述 +带给总结 LLM("他发了一张猫猫梗图" ≫ "[图片×1]")。 + +实现原则: +1. 识别走异步后台任务,绝不在消息采集路径同步调用 LLM +2. 同一 hash 只识别一次(表情包反复发不重复花钱) +3. 识别失败不影响采集(结果可空) +""" + +from typing import Optional + +from nonebot import logger + + +class BaseImageRecognizer: + """图片识别基类:子类实现 describe""" + + async def describe(self, image_url: str) -> Optional[str]: + raise NotImplementedError + + +class NoopImageRecognizer(BaseImageRecognizer): + """占位实现:未启用时使用,什么都不做""" + + async def describe(self, image_url: str) -> Optional[str]: + return None + + +# 当前识别器实例(预留:接入多模态 LLM 时替换为真实实现) +recognizer: BaseImageRecognizer = NoopImageRecognizer() +logger.debug("galgame_card | 图片识别接口已预留(当前为占位实现,未启用)") diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web.py b/hexi/plugins/nonebot_plugin_galgame_card/web.py new file mode 100644 index 0000000..a5010b0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web.py @@ -0,0 +1,266 @@ +"""Web 管理后台:群开关 / 参与者 / 数据浏览(挂在 bot 端口 /galgame_card 路径) + +仿 nonebot_plugin_learning_chat 的网页模式:JWT 登录 + /galgame_card/api/* 路由 + 静态页。 +""" + +import datetime +from pathlib import Path +from typing import Optional + +from fastapi import Depends, Header, HTTPException +from fastapi.responses import FileResponse, HTMLResponse, JSONResponse +from fastapi.staticfiles import StaticFiles +from jose import jwt +from nonebot import get_adapter, get_app, get_driver, logger +from nonebot.adapters.onebot.v11 import Adapter, Bot +from pydantic import BaseModel + +from . import repository +from .config import config + +API_PREFIX = "/galgame_card/api" +WEB_DIR = Path(__file__).parent / "web" + +driver = get_driver() + + +def authentication(): + def inner(token: Optional[str] = Header(None, alias="Authorization")): + try: + payload = jwt.decode(token, config.web_secret_key, algorithms="HS256") + if not payload.get("username") or payload["username"] != config.web_username: + raise HTTPException(status_code=400, detail="登录验证失败或已失效,请重新登录") + except (jwt.JWTError, jwt.ExpiredSignatureError, AttributeError): + raise HTTPException(status_code=400, detail="登录验证失败或已失效,请重新登录") + + return Depends(inner) + + +class LoginModel(BaseModel): + username: str + password: str + + +def _ok(data=None, msg: str = "ok") -> JSONResponse: + return JSONResponse({"status": 0, "msg": msg, "data": data}) + + +def _err(code: int, msg: str) -> JSONResponse: + return JSONResponse({"status": code, "msg": msg}) + + +async def _first_bot() -> Optional[Bot]: + bots = get_adapter(Adapter).bots + return next(iter(bots.values()), None) + + +@driver.on_startup +async def init_web(): + if not config.web_enable: + return + app = get_app() + + @app.post(f"{API_PREFIX}/login") + async def login(user: LoginModel): + if user.username != config.web_username or user.password != config.web_password: + return _err(-100, "登录失败,请确认账号密码无误") + token = jwt.encode( + { + "username": user.username, + "exp": datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(hours=12), + }, + config.web_secret_key, + algorithm="HS256", + ) + return _ok({"token": token}, "登录成功") + + @app.get(f"{API_PREFIX}/groups", dependencies=[authentication()]) + async def groups(): + """管理中的群:数据库直读,不依赖 OneBot""" + rows = await repository.list_groups() + corpus = await repository.corpus_counts_by_group() + impressions = await repository.impression_counts_by_group() + summaries = await repository.summary_counts_by_group() + participants = await repository.participant_counts_by_group() + result = [] + for row in rows: + gid = row.group_id + result.append( + { + "group_id": gid, + "group_name": row.group_name, + "enabled": row.enabled, + "participants": participants.get(gid, 0), + "corpus_count": corpus.get(gid, 0), + "impression_count": impressions.get(gid, 0), + "summary_count": summaries.get(gid, 0), + } + ) + return _ok(result) + + @app.get(f"{API_PREFIX}/groups/discover", dependencies=[authentication()]) + async def discover_groups(): + """OneBot 全部群("添加群"选择器用),顺带回填已管理群名称""" + bot = await _first_bot() + if bot is None: + return _err(-100, "未连接 OneBot,无法获取群列表") + group_list = await bot.get_group_list() + managed_ids = {row.group_id for row in await repository.list_groups()} + result = [ + { + "group_id": int(g["group_id"]), + "group_name": g.get("group_name", ""), + "managed": int(g["group_id"]) in managed_ids, + } + for g in group_list + ] + await repository.backfill_group_names( + {int(g["group_id"]): g.get("group_name", "") for g in group_list} + ) + return _ok(result) + + @app.post(f"{API_PREFIX}/groups", dependencies=[authentication()]) + async def add_group(data: dict): + gid = int(data.get("group_id") or 0) + if gid <= 0: + return _err(400, "group_id 不合法") + await repository.add_group(gid, str(data.get("group_name") or "").strip()) + return _ok(msg="已加入管理列表") + + @app.post(f"{API_PREFIX}/groups/{{group_id}}/enabled", dependencies=[authentication()]) + async def set_group_enabled(group_id: int, data: dict): + await repository.set_group_enabled(group_id, bool(data.get("enabled"))) + return _ok(msg="已开启采集" if data.get("enabled") else "已关闭采集") + + @app.get(f"{API_PREFIX}/groups/{{group_id}}/participants", dependencies=[authentication()]) + async def participants(group_id: int): + members = await repository.joined_users(group_id) + stats = dict(await repository.chat_log_stats_by_user(group_id)) + result = [ + {"user_id": uid, "corpus_count": stats.get(uid, 0)} for uid in members + ] + return _ok(result) + + @app.post(f"{API_PREFIX}/groups/{{group_id}}/participants", dependencies=[authentication()]) + async def add_participant(group_id: int, data: dict): + user_id = int(data.get("user_id") or 0) + if user_id <= 0: + return _err(400, "user_id 不合法") + if await repository.is_joined(user_id, group_id): + return _err(400, "已在人设名单中") + await repository.join(user_id, group_id) + return _ok(msg="已加入") + + @app.delete(f"{API_PREFIX}/groups/{{group_id}}/participants/{{user_id}}", dependencies=[authentication()]) + async def remove_participant(group_id: int, user_id: int): + await repository.leave(user_id, group_id) + return _ok(msg="已移除") + + @app.get(f"{API_PREFIX}/groups/{{group_id}}/logs", dependencies=[authentication()]) + async def logs(group_id: int, user_id: Optional[int] = None, page: int = 1, per_page: int = 50): + offset = max(0, (page - 1) * per_page) + items = await repository.list_logs(group_id, user_id, offset, per_page) + total = await repository.count_logs_filtered(group_id, user_id) + result = [ + { + "id": row.id, + "user_id": row.user_id, + "nickname": row.nickname, + "content": row.content, + "target_user_id": row.target_user_id, + "target_inherited": row.target_inherited, + "follows_id": row.follows_id, + "created_at": row.created_at.strftime("%Y-%m-%d %H:%M:%S"), + } + for row in items + ] + return _ok({"items": result, "total": total}) + + @app.get(f"{API_PREFIX}/groups/{{group_id}}/impressions", dependencies=[authentication()]) + async def impressions(group_id: int, page: int = 1, per_page: int = 50): + offset = max(0, (page - 1) * per_page) + items = await repository.list_impressions_group(group_id, offset, per_page) + result = [ + { + "id": row.id, + "user_id": row.user_id, + "content": row.content, + "cover_from_id": row.cover_from_id, + "cover_to_id": row.cover_to_id, + "created_at": row.created_at.strftime("%Y-%m-%d %H:%M:%S"), + } + for row in items + ] + return _ok({"items": result, "total": await repository.count_impressions_group(group_id)}) + + @app.get(f"{API_PREFIX}/groups/{{group_id}}/summaries", dependencies=[authentication()]) + async def summaries(group_id: int): + items = await repository.list_summaries_group(group_id) + result = [ + { + "version": row.version, + "card_text": row.card_text, + "corpus_count": row.corpus_count, + "impression_count": row.impression_count, + "model": row.model, + "created_at": row.created_at.strftime("%Y-%m-%d %H:%M:%S"), + } + for row in items + ] + return _ok(result) + + @app.delete(f"{API_PREFIX}/groups/{{group_id}}/logs", dependencies=[authentication()]) + async def delete_logs(group_id: int, user_id: Optional[int] = None): + count = await repository.delete_logs(group_id, user_id) + return _ok(msg=f"已删除 {count} 条语料") + + @app.delete(f"{API_PREFIX}/groups/{{group_id}}/data", dependencies=[authentication()]) + async def clear_group(group_id: int): + await repository.clear_group_data(group_id) + return _ok(msg="已清空该群全部数据") + + @app.delete(f"{API_PREFIX}/groups/{{group_id}}", dependencies=[authentication()]) + async def remove_group(group_id: int): + await repository.remove_group(group_id) + return _ok(msg="已移出管理列表(数据保留,重新加入可续上)") + + @app.get(f"{API_PREFIX}/settings", dependencies=[authentication()]) + async def settings(): + from . import processor + + return _ok( + { + "web_username": config.web_username, + "web_enable": config.web_enable, + "thresholds": { + "max_content_len": processor.MAX_CONTENT_LEN, + "repeat_window": processor.REPEAT_WINDOW, + "throttle_seconds": processor.THROTTLE_SECONDS, + "rolling_window": repository.ROLLING_WINDOW, + }, + } + ) + + # React 管理后台(web/persona-admin 构建产物) + dist_dir = WEB_DIR / "persona-admin" / "dist" + if (dist_dir / "index.html").exists(): + app.mount( + "/galgame_card/assets", + StaticFiles(directory=dist_dir / "assets"), + name="galgame_card_assets", + ) + + @app.get("/galgame_card") + @app.get("/galgame_card/") + async def admin_page(): + return FileResponse(dist_dir / "index.html") + + else: + # 构建产物缺失时回退到旧版单文件页面 + @app.get("/galgame_card") + @app.get("/galgame_card/") + async def admin_page(): + html = (WEB_DIR / "index.html").read_text(encoding="utf-8") + return HTMLResponse(html) + + logger.info("群聊人设卡 | Web 管理后台已挂载: /galgame_card") diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/index.html b/hexi/plugins/nonebot_plugin_galgame_card/web/index.html new file mode 100644 index 0000000..e450470 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/index.html @@ -0,0 +1,370 @@ + + + + + +群聊人设卡 · 管理后台 + + + + + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/index.html b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/index.html new file mode 100644 index 0000000..b5121f4 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/index.html @@ -0,0 +1,12 @@ + + + + + + 群聊人设卡 · 管理后台 + + +
+ + + diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/package-lock.json b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/package-lock.json new file mode 100644 index 0000000..8abdfc5 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/package-lock.json @@ -0,0 +1,7159 @@ +{ + "name": "persona-admin", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "persona-admin", + "version": "0.1.0", + "dependencies": { + "@heroui/react": "^2.8.0", + "@heroui/theme": "^2.4.26", + "framer-motion": "^11.11.17", + "next-themes": "^0.4.4", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.28.0" + }, + "devDependencies": { + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.49", + "tailwindcss": "^3.4.15", + "typescript": "^5.6.3", + "vite": "^6.0.3" + } + }, + "node_modules/@adobe/react-spectrum": { + "version": "3.47.3", + "resolved": "https://registry.npmjs.org/@adobe/react-spectrum/-/react-spectrum-3.47.3.tgz", + "integrity": "sha512-tWZG59+xTbXIqeZB4uyuo2qljk3nRK66IkdBmMgbl2p6peApkKbrtJ/YOM8rW4gemdmv7qoJlbIHvy8aJkYsCQ==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.3", + "@react-types/shared": "^3.36.1", + "@spectrum-icons/ui": "^3.7.1", + "@spectrum-icons/workflow": "^4.3.1", + "@swc/helpers": "^0.5.0", + "client-only": "^0.0.1", + "clsx": "^2.0.0", + "react-aria": "3.51.0", + "react-aria-components": "1.20.0", + "react-stately": "3.49.0", + "react-transition-group": "^4.4.5", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@adobe/react-spectrum-ui": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@adobe/react-spectrum-ui/-/react-spectrum-ui-1.2.1.tgz", + "integrity": "sha512-wcrbEE2O/9WnEn6avBnaVRRx88S5PLFsPLr4wffzlbMfXeQsy+RMQwaJd3cbzrn18/j04Isit7f7Emfn0dhrJA==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@adobe/react-spectrum-workflow": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@adobe/react-spectrum-workflow/-/react-spectrum-workflow-2.3.5.tgz", + "integrity": "sha512-b53VIPwPWKb/T5gzE3qs+QlGP5gVrw/LnWV3xMksDU+CRl3rzOKUwxIGiZO8ICyYh1WiyqY4myGlPU/nAynBUg==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@adobe/react-spectrum/node_modules/@react-types/shared": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.36.1.tgz", + "integrity": "sha512-AzsuD9OfxTOZMMvTRhlN3oHBwOmFN7tDh27LzqmHt4+uOgPhJT7ZM7/kVs/8/o0WxayMUIk3hBmCFRHv1FUoag==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.6.tgz", + "integrity": "sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw==", + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/intl-localematcher": "0.6.2", + "decimal.js": "^10.4.3", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz", + "integrity": "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.4.tgz", + "integrity": "sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.6", + "@formatjs/icu-skeleton-parser": "1.8.16", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.16.tgz", + "integrity": "sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.6", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.6.2.tgz", + "integrity": "sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@heroui/aria-utils": { + "version": "2.2.29", + "resolved": "https://registry.npmjs.org/@heroui/aria-utils/-/aria-utils-2.2.29.tgz", + "integrity": "sha512-tVc5Rz+u/WMaAoYpx4VNheFqsfxA5i0SAqT8OAFpPX0WiNrylXaAGWsid/ivFdlW4rE1FgI/+wP0KS6c8KSEjQ==", + "license": "MIT", + "dependencies": { + "@heroui/system": "2.4.28", + "@react-aria/utils": "3.33.1", + "@react-stately/collections": "3.12.10", + "@react-types/overlays": "3.9.4", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/aria-utils/node_modules/@react-types/overlays": { + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/@react-types/overlays/-/overlays-3.9.4.tgz", + "integrity": "sha512-7Z9HaebMFyYBqtv3XVNHEmVkm7AiYviV7gv0c98elEN2Co+eQcKFGvwBM9Gy/lV57zlTqFX1EX/SAqkMEbCLOA==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/dom-animation": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@heroui/dom-animation/-/dom-animation-2.1.10.tgz", + "integrity": "sha512-dt+0xdVPbORwNvFT5pnqV2ULLlSgOJeqlg/DMo97s9RWeD6rD4VedNY90c8C9meqWqGegQYBQ9ztsfX32mGEPA==", + "license": "MIT", + "peerDependencies": { + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1" + } + }, + "node_modules/@heroui/form": { + "version": "2.1.32", + "resolved": "https://registry.npmjs.org/@heroui/form/-/form-2.1.32.tgz", + "integrity": "sha512-gcMnlNq2eI8jIvNIEas4HVmQNdkRuZnhRCx/nZOd/FtO+WQwuqN2xFAfm/nGH3Hq/7yRf2yOozuJsm7iJVaatA==", + "license": "MIT", + "dependencies": { + "@heroui/shared-utils": "2.1.12", + "@heroui/system": "2.4.28", + "@heroui/theme": "2.4.26", + "@react-stately/form": "3.2.4", + "@react-types/form": "3.7.18", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@heroui/framer-utils": { + "version": "2.1.28", + "resolved": "https://registry.npmjs.org/@heroui/framer-utils/-/framer-utils-2.1.28.tgz", + "integrity": "sha512-/M2nqHRx4feZx0lgA8QmHDaqu/DgsdynvSnbniptiU/Xi9XgQApCPJ0Qxgk5JZ9g2vemDFgi5AP7C7FqgiMtMA==", + "license": "MIT", + "dependencies": { + "@heroui/system": "2.4.28", + "@heroui/use-measure": "2.1.8" + }, + "peerDependencies": { + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react": { + "version": "2.8.10", + "resolved": "https://registry.npmjs.org/@heroui/react/-/react-2.8.10.tgz", + "integrity": "sha512-rW5wFxLX3SNusf8Uhq10M5btRplKunU8glU1Gd4gD9AMIV/e7D+DGy/g2ildz2gEcMPny4C5kLcYlwRDea5oNw==", + "license": "MIT", + "dependencies": { + "@heroui/accordion": "2.2.29", + "@heroui/alert": "2.2.32", + "@heroui/autocomplete": "2.3.34", + "@heroui/avatar": "2.2.26", + "@heroui/badge": "2.2.18", + "@heroui/breadcrumbs": "2.2.25", + "@heroui/button": "2.2.32", + "@heroui/calendar": "2.2.32", + "@heroui/card": "2.2.28", + "@heroui/checkbox": "2.3.32", + "@heroui/chip": "2.2.25", + "@heroui/code": "2.2.25", + "@heroui/date-input": "2.3.32", + "@heroui/date-picker": "2.3.33", + "@heroui/divider": "2.2.24", + "@heroui/drawer": "2.2.29", + "@heroui/dropdown": "2.3.32", + "@heroui/form": "2.1.32", + "@heroui/framer-utils": "2.1.28", + "@heroui/image": "2.2.19", + "@heroui/input": "2.4.33", + "@heroui/input-otp": "2.1.32", + "@heroui/kbd": "2.2.26", + "@heroui/link": "2.2.26", + "@heroui/listbox": "2.3.31", + "@heroui/menu": "2.2.31", + "@heroui/modal": "2.2.29", + "@heroui/navbar": "2.2.30", + "@heroui/number-input": "2.0.23", + "@heroui/pagination": "2.2.27", + "@heroui/popover": "2.3.32", + "@heroui/progress": "2.2.25", + "@heroui/radio": "2.3.32", + "@heroui/ripple": "2.2.21", + "@heroui/scroll-shadow": "2.3.19", + "@heroui/select": "2.4.33", + "@heroui/skeleton": "2.2.18", + "@heroui/slider": "2.4.29", + "@heroui/snippet": "2.2.33", + "@heroui/spacer": "2.2.25", + "@heroui/spinner": "2.2.29", + "@heroui/switch": "2.2.27", + "@heroui/system": "2.4.28", + "@heroui/table": "2.2.32", + "@heroui/tabs": "2.2.29", + "@heroui/theme": "2.4.26", + "@heroui/toast": "2.0.22", + "@heroui/tooltip": "2.2.29", + "@heroui/user": "2.2.26", + "@react-aria/visually-hidden": "3.8.31" + }, + "peerDependencies": { + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react-rsc-utils": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@heroui/react-rsc-utils/-/react-rsc-utils-2.1.9.tgz", + "integrity": "sha512-e77OEjNCmQxE9/pnLDDb93qWkX58/CcgIqdNAczT/zUP+a48NxGq2A2WRimvc1uviwaNL2StriE2DmyZPyYW7Q==", + "license": "MIT", + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react-utils": { + "version": "2.1.14", + "resolved": "https://registry.npmjs.org/@heroui/react-utils/-/react-utils-2.1.14.tgz", + "integrity": "sha512-hhKklYKy9sRH52C9A8P0jWQ79W4MkIvOnKBIuxEMHhigjfracy0o0lMnAUdEsJni4oZKVJYqNGdQl+UVgcmeDA==", + "license": "MIT", + "dependencies": { + "@heroui/react-rsc-utils": "2.1.9", + "@heroui/shared-utils": "2.1.12" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/accordion": { + "version": "2.2.29", + "resolved": "https://registry.npmjs.org/@heroui/accordion/-/accordion-2.2.29.tgz", + "integrity": "sha512-nhCqgZ3ejgRLRM3jJnpZExufn050raxOVyNUR7zo9o5Ed10KKRpD3J/8l6gwrYA7j+Z46dF2YLJzIFWPzYf1Kw==", + "license": "MIT", + "dependencies": { + "@heroui/aria-utils": "2.2.29", + "@heroui/divider": "2.2.24", + "@heroui/dom-animation": "2.1.10", + "@heroui/framer-utils": "2.1.28", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-aria-accordion": "2.2.20", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-stately/tree": "3.9.6", + "@react-types/accordion": "3.0.0-alpha.26", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/alert": { + "version": "2.2.32", + "resolved": "https://registry.npmjs.org/@heroui/alert/-/alert-2.2.32.tgz", + "integrity": "sha512-8piby1PXVTTtdwLLV60JMqduRAFLHoiQpFPeSNVHsAaMIphXsmlpvUb9dct4f0wQJqqgFutiWL3RtjdDwEkRQQ==", + "license": "MIT", + "dependencies": { + "@heroui/button": "2.2.32", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@react-stately/utils": "3.11.0" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/autocomplete": { + "version": "2.3.34", + "resolved": "https://registry.npmjs.org/@heroui/autocomplete/-/autocomplete-2.3.34.tgz", + "integrity": "sha512-DTmztrWMdEtHCIJmgSyO/7QrABsaq/kDqBg6aVw+P30sgLW6k05wYOqe6ctuoNSWaZzr56QPvFpsgbeMy7Ma0A==", + "license": "MIT", + "dependencies": { + "@heroui/aria-utils": "2.2.29", + "@heroui/button": "2.2.32", + "@heroui/form": "2.1.32", + "@heroui/input": "2.4.33", + "@heroui/listbox": "2.3.31", + "@heroui/popover": "2.3.32", + "@heroui/react-utils": "2.1.14", + "@heroui/scroll-shadow": "2.3.19", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-safe-layout-effect": "2.1.8", + "@react-aria/combobox": "3.15.0", + "@react-aria/i18n": "3.12.16", + "@react-stately/combobox": "3.13.0", + "@react-types/combobox": "3.14.0", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/avatar": { + "version": "2.2.26", + "resolved": "https://registry.npmjs.org/@heroui/avatar/-/avatar-2.2.26.tgz", + "integrity": "sha512-W2z64Da38ZL4Lu9Pokan2frTURcXxUs3bV37WWJjMzCD6mOAlaogWYMQdAeYmeWHyAW18XZSa5OaUCMVrzJ2SQ==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-image": "2.1.14", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/badge": { + "version": "2.2.18", + "resolved": "https://registry.npmjs.org/@heroui/badge/-/badge-2.2.18.tgz", + "integrity": "sha512-OfGove8YJ9oDrdugzq05FC15ZKD5nzqe+thPZ+1SY1LZorJQjZvqSD9QnoEH1nG7fu2IdH6pYJy3sZ/b6Vj5Kg==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.23", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/breadcrumbs": { + "version": "2.2.25", + "resolved": "https://registry.npmjs.org/@heroui/breadcrumbs/-/breadcrumbs-2.2.25.tgz", + "integrity": "sha512-KmUmJiBVzRuKR1tXIvKBqz8rGz4jAPa2FqsDodQ/Z34Eagsw85l3pI6xekKacGcxNQVM+L6KhMRb00QWHT/SmQ==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@react-aria/breadcrumbs": "3.5.32", + "@react-aria/focus": "3.21.5", + "@react-types/breadcrumbs": "3.7.19" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/button": { + "version": "2.2.32", + "resolved": "https://registry.npmjs.org/@heroui/button/-/button-2.2.32.tgz", + "integrity": "sha512-i1vx4gEuyjKmz0xVu+U3PgtYrsGt1PVuWBrT/sSbNcH0AGuPSqQPQ/znwkhgZ4ixhNaU9jjVbBfIGCFGNDz7XA==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/ripple": "2.2.21", + "@heroui/shared-utils": "2.1.12", + "@heroui/spinner": "2.2.29", + "@heroui/use-aria-button": "2.2.22", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/calendar": { + "version": "2.2.32", + "resolved": "https://registry.npmjs.org/@heroui/calendar/-/calendar-2.2.32.tgz", + "integrity": "sha512-2xzCmM7Sdz04qYr478lcH3GfGi2HWmKZ77PXrxWyRcVys+6GQpJJS712eusQBdoDNoUHUK/qZLTxihwiDC46wg==", + "license": "MIT", + "dependencies": { + "@heroui/button": "2.2.32", + "@heroui/dom-animation": "2.1.10", + "@heroui/framer-utils": "2.1.28", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-aria-button": "2.2.22", + "@internationalized/date": "3.12.0", + "@react-aria/calendar": "3.9.5", + "@react-aria/focus": "3.21.5", + "@react-aria/i18n": "3.12.16", + "@react-aria/interactions": "3.27.1", + "@react-aria/visually-hidden": "3.8.31", + "@react-stately/calendar": "3.9.3", + "@react-stately/utils": "3.11.0", + "@react-types/button": "3.15.1", + "@react-types/calendar": "3.8.3", + "@react-types/shared": "3.33.1", + "scroll-into-view-if-needed": "3.0.10" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/card": { + "version": "2.2.28", + "resolved": "https://registry.npmjs.org/@heroui/card/-/card-2.2.28.tgz", + "integrity": "sha512-njwCocEntWaYyALB+2SHzVzoG4JJMV2rG55vQ0zZIIJoG1+/F9SCfsZQ87ncf+0D7IQx6vw8fWT2VRKojmn9+w==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/ripple": "2.2.21", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-aria-button": "2.2.22", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/checkbox": { + "version": "2.3.32", + "resolved": "https://registry.npmjs.org/@heroui/checkbox/-/checkbox-2.3.32.tgz", + "integrity": "sha512-rmFGPTgpG/Uvlr/8KjCSobT3u2Ig4/3p8s0qwTCo37uvtsCIbCYyB1yNAXZkCN2hfg5ZIBofEaYeEmw0OBsQAQ==", + "license": "MIT", + "dependencies": { + "@heroui/form": "2.1.32", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-callback-ref": "2.1.8", + "@heroui/use-safe-layout-effect": "2.1.8", + "@react-aria/checkbox": "3.16.5", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-stately/checkbox": "3.7.5", + "@react-stately/toggle": "3.9.5", + "@react-types/checkbox": "3.10.4", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/chip": { + "version": "2.2.25", + "resolved": "https://registry.npmjs.org/@heroui/chip/-/chip-2.2.25.tgz", + "integrity": "sha512-kACEoF7tP9o/q5HdARaP3veD0Rl4Uxe9fiTVQvus8kN97Jnw9y4JctsUJ/vXgsscKt39qh53TB8fo8I0sJ2FPg==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/code": { + "version": "2.2.25", + "resolved": "https://registry.npmjs.org/@heroui/code/-/code-2.2.25.tgz", + "integrity": "sha512-oGaQVktqTNqRPDceuV/egVh442Ap4cbuXxVSqsmT0aNV1KnISo/P7VwLm4QDN5T3MXxN3Cs2Pw6z0+oydPL3mA==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/system-rsc": "2.3.24" + }, + "peerDependencies": { + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/date-input": { + "version": "2.3.32", + "resolved": "https://registry.npmjs.org/@heroui/date-input/-/date-input-2.3.32.tgz", + "integrity": "sha512-jk0cPMkfs0lexdJckBZ4qO96tTqT3ZMgb+Z12aS8VW3Hcbvj2vvv2fuHc7LrIg1mdUqZzZwCwUAsUGWSJDTI0w==", + "license": "MIT", + "dependencies": { + "@heroui/form": "2.1.32", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@internationalized/date": "3.12.0", + "@react-aria/datepicker": "3.16.1", + "@react-aria/i18n": "3.12.16", + "@react-stately/datepicker": "3.16.1", + "@react-types/datepicker": "3.13.5", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/date-picker": { + "version": "2.3.33", + "resolved": "https://registry.npmjs.org/@heroui/date-picker/-/date-picker-2.3.33.tgz", + "integrity": "sha512-u9N2NToMLg3hwn7WEXljhrtM/DiRrUVBqs35akW9gTQtcz1fGPugrDkJy4OsKEv7c1HuYBO0As6CM+uXERjHWw==", + "license": "MIT", + "dependencies": { + "@heroui/aria-utils": "2.2.29", + "@heroui/button": "2.2.32", + "@heroui/calendar": "2.2.32", + "@heroui/date-input": "2.3.32", + "@heroui/form": "2.1.32", + "@heroui/popover": "2.3.32", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@internationalized/date": "3.12.0", + "@react-aria/datepicker": "3.16.1", + "@react-aria/i18n": "3.12.16", + "@react-stately/datepicker": "3.16.1", + "@react-stately/utils": "3.11.0", + "@react-types/datepicker": "3.13.5", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/divider": { + "version": "2.2.24", + "resolved": "https://registry.npmjs.org/@heroui/divider/-/divider-2.2.24.tgz", + "integrity": "sha512-fq7bZFpruws3aC5X2TGMMUhcInyxQS6oWAOYrwgWX5jrmqzg/8CBtIuOehhwcm0HAk+oI55KFidJUFTuA1s7Gg==", + "license": "MIT", + "dependencies": { + "@heroui/react-rsc-utils": "2.1.9", + "@heroui/system-rsc": "2.3.24", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/drawer": { + "version": "2.2.29", + "resolved": "https://registry.npmjs.org/@heroui/drawer/-/drawer-2.2.29.tgz", + "integrity": "sha512-zVBKHbcCXZGR79ORw4vQRA/QfHNLoQ9R8q6P1gsjs24uBGdBQAYvQE0F/bfsKZ5JH7asUt+oSIpjqQGmXAbyyQ==", + "license": "MIT", + "dependencies": { + "@heroui/framer-utils": "2.1.28", + "@heroui/modal": "2.2.29", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/dropdown": { + "version": "2.3.32", + "resolved": "https://registry.npmjs.org/@heroui/dropdown/-/dropdown-2.3.32.tgz", + "integrity": "sha512-+ntmjxkBaUVpyGN0pcByeTm2e2RUi5/D5uI9vPFLvJYWCa26bzQRR7EuK7LuGRXVciWl+NODNlLbSUVukkHBUA==", + "license": "MIT", + "dependencies": { + "@heroui/aria-utils": "2.2.29", + "@heroui/menu": "2.2.31", + "@heroui/popover": "2.3.32", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@react-aria/focus": "3.21.5", + "@react-aria/menu": "3.21.0", + "@react-stately/menu": "3.9.11", + "@react-types/menu": "3.10.7" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/image": { + "version": "2.2.19", + "resolved": "https://registry.npmjs.org/@heroui/image/-/image-2.2.19.tgz", + "integrity": "sha512-XdQ1g0kiHl+Kj9Zj1NL1mbKhmzeN0h27dgfegJS2coGM/yrEavYzg1DWUEyVSzPNKFZS8BDGa9DOpWe0vgggBA==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-image": "2.1.14" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/input": { + "version": "2.4.33", + "resolved": "https://registry.npmjs.org/@heroui/input/-/input-2.4.33.tgz", + "integrity": "sha512-iDKujnKgXDbR4zLVr03Pg3TYKFR2zv0aPZUpjOvtLdB8/wNBQv+rbizqnHQPAYyDwhNQS0WguW0tQVhh4oPy4w==", + "license": "MIT", + "dependencies": { + "@heroui/form": "2.1.32", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-safe-layout-effect": "2.1.8", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-aria/textfield": "3.18.5", + "@react-stately/utils": "3.11.0", + "@react-types/shared": "3.33.1", + "@react-types/textfield": "3.12.8", + "react-textarea-autosize": "^8.5.3" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/input-otp": { + "version": "2.1.32", + "resolved": "https://registry.npmjs.org/@heroui/input-otp/-/input-otp-2.1.32.tgz", + "integrity": "sha512-lrByjetK5/9MjqhDXHnhAI/gBnCJjMmR92k2HARjnJjYhljD58j6xYuf41zwp/faYkyspVvmLMPHF8qjKMTAbQ==", + "license": "MIT", + "dependencies": { + "@heroui/form": "2.1.32", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-form-reset": "2.0.1", + "@react-aria/focus": "3.21.5", + "@react-aria/form": "3.1.5", + "@react-stately/form": "3.2.4", + "@react-stately/utils": "3.11.0", + "@react-types/textfield": "3.12.8", + "input-otp": "1.4.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/kbd": { + "version": "2.2.26", + "resolved": "https://registry.npmjs.org/@heroui/kbd/-/kbd-2.2.26.tgz", + "integrity": "sha512-Z8XpQwMmNpLGlQlGD7UWRWG2S8veNb9vezfWgEKmtnnzdVM/CKSYTWctkmiruJ7tPn3XPsGTEt3QU8WPVAnpqQ==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/system-rsc": "2.3.24" + }, + "peerDependencies": { + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/link": { + "version": "2.2.26", + "resolved": "https://registry.npmjs.org/@heroui/link/-/link-2.2.26.tgz", + "integrity": "sha512-TPxd87ZP8mB8HG0GVIDTuoDxL2mcpCVUY9sjrxujAtin3781znM6jFO+O/tv0huW90+jxBHiFU1KpeZWwtl6qg==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-aria-link": "2.2.23", + "@react-aria/focus": "3.21.5", + "@react-types/link": "3.6.7" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/listbox": { + "version": "2.3.31", + "resolved": "https://registry.npmjs.org/@heroui/listbox/-/listbox-2.3.31.tgz", + "integrity": "sha512-EvYxlama0kDCtgyNfCtz/X7ftYSE0OlPGKrZrv0st0oz790x3E1EQyCEYOaDbHAnGPxJy8pRC88CbzyPWEHeXQ==", + "license": "MIT", + "dependencies": { + "@heroui/aria-utils": "2.2.29", + "@heroui/divider": "2.2.24", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-is-mobile": "2.2.12", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-aria/listbox": "3.15.3", + "@react-stately/list": "3.13.4", + "@react-types/shared": "3.33.1", + "@tanstack/react-virtual": "3.11.3" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/menu": { + "version": "2.2.31", + "resolved": "https://registry.npmjs.org/@heroui/menu/-/menu-2.2.31.tgz", + "integrity": "sha512-e5VqpMapolo51kJdHdz+tm3a++dGnvPTQtma8bFPfguVzoyzbq4eicFUR9fvbvYjP2jNewwsyaoTqBvxqbueiQ==", + "license": "MIT", + "dependencies": { + "@heroui/aria-utils": "2.2.29", + "@heroui/divider": "2.2.24", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-is-mobile": "2.2.12", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-aria/menu": "3.21.0", + "@react-stately/tree": "3.9.6", + "@react-types/menu": "3.10.7", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/modal": { + "version": "2.2.29", + "resolved": "https://registry.npmjs.org/@heroui/modal/-/modal-2.2.29.tgz", + "integrity": "sha512-ke6i2ByLuTE/4OZRZvgKv6A2Vf1GkitL/Lq+Bojq8ovIquphmH7AXrXkWEQ6yq1YdqYRDFcVOX/4p11Qjv4rkg==", + "license": "MIT", + "dependencies": { + "@heroui/dom-animation": "2.1.10", + "@heroui/framer-utils": "2.1.28", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-aria-button": "2.2.22", + "@heroui/use-aria-modal-overlay": "2.2.21", + "@heroui/use-disclosure": "2.2.19", + "@heroui/use-draggable": "2.1.20", + "@heroui/use-viewport-size": "2.0.1", + "@react-aria/dialog": "3.5.34", + "@react-aria/focus": "3.21.5", + "@react-aria/overlays": "3.31.2", + "@react-stately/overlays": "3.6.23" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/navbar": { + "version": "2.2.30", + "resolved": "https://registry.npmjs.org/@heroui/navbar/-/navbar-2.2.30.tgz", + "integrity": "sha512-zGMRuewcjUFZhj3hIyIWOq+iRt0Mcc8FHBDPHAcYtYe0PrfYF2Ti0WLoH5Bbf5kR3S5hYfwabyT7jtf173S7iQ==", + "license": "MIT", + "dependencies": { + "@heroui/dom-animation": "2.1.10", + "@heroui/framer-utils": "2.1.28", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-resize": "2.1.8", + "@heroui/use-scroll-position": "2.1.8", + "@react-aria/button": "3.14.5", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-aria/overlays": "3.31.2", + "@react-stately/toggle": "3.9.5", + "@react-stately/utils": "3.11.0" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/number-input": { + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/@heroui/number-input/-/number-input-2.0.23.tgz", + "integrity": "sha512-06Glv+X+tqSLt7i7MUJJz2Zf65+kkBaL/Cgx0Sw7iA418WejPDF3KIRee48RdfI+AOHYPAH4AD9PnGAaOJvapQ==", + "license": "MIT", + "dependencies": { + "@heroui/button": "2.2.32", + "@heroui/form": "2.1.32", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-safe-layout-effect": "2.1.8", + "@react-aria/focus": "3.21.5", + "@react-aria/i18n": "3.12.16", + "@react-aria/interactions": "3.27.1", + "@react-aria/numberfield": "3.12.5", + "@react-stately/numberfield": "3.11.0", + "@react-types/button": "3.15.1", + "@react-types/numberfield": "3.8.18", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/pagination": { + "version": "2.2.27", + "resolved": "https://registry.npmjs.org/@heroui/pagination/-/pagination-2.2.27.tgz", + "integrity": "sha512-omTpyJwGzw2fmSdfCfJuIgVmTqDaMzs4RmDtjgqEZxZCAldFlVuTWmsR1peOwzZKsrhzbp3eH/E9F6ipwF6Yug==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-intersection-observer": "2.2.14", + "@heroui/use-pagination": "2.2.20", + "@react-aria/focus": "3.21.5", + "@react-aria/i18n": "3.12.16", + "@react-aria/interactions": "3.27.1", + "@react-aria/utils": "3.33.1", + "scroll-into-view-if-needed": "3.0.10" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/popover": { + "version": "2.3.32", + "resolved": "https://registry.npmjs.org/@heroui/popover/-/popover-2.3.32.tgz", + "integrity": "sha512-aVkDt9aITI66x7nS0k2BJ7szQtNm5YV+Q31X9aWrXFkRdJ+zl0sMbo1UpVQdGSif0yH6NvsFTThmCWDQZkX6fg==", + "license": "MIT", + "dependencies": { + "@heroui/aria-utils": "2.2.29", + "@heroui/button": "2.2.32", + "@heroui/dom-animation": "2.1.10", + "@heroui/framer-utils": "2.1.28", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-aria-button": "2.2.22", + "@heroui/use-aria-overlay": "2.0.6", + "@heroui/use-safe-layout-effect": "2.1.8", + "@react-aria/dialog": "3.5.34", + "@react-aria/focus": "3.21.5", + "@react-aria/overlays": "3.31.2", + "@react-stately/overlays": "3.6.23", + "@react-types/overlays": "3.9.4" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/progress": { + "version": "2.2.25", + "resolved": "https://registry.npmjs.org/@heroui/progress/-/progress-2.2.25.tgz", + "integrity": "sha512-0aMuB3RaEheJPiQPUPRvwC1CkBG9qDRzRyUu6GT5QJfkFVmeB09NwQB4wec74qa1Ke+Yhj2KHfCVyBzYNqAifw==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-is-mounted": "2.1.8", + "@react-aria/progress": "3.4.30", + "@react-types/progress": "3.5.18" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/radio": { + "version": "2.3.32", + "resolved": "https://registry.npmjs.org/@heroui/radio/-/radio-2.3.32.tgz", + "integrity": "sha512-R0Oj8sQ5NA5LqPkouGEHPetgZxa1p7XNf5teVv0nL+8A9tg4R8VDLvL50ezc0yXp18PmfHa61AoK5DSCnyesNw==", + "license": "MIT", + "dependencies": { + "@heroui/form": "2.1.32", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-aria/radio": "3.12.5", + "@react-aria/visually-hidden": "3.8.31", + "@react-stately/radio": "3.11.5", + "@react-types/radio": "3.9.4", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/ripple": { + "version": "2.2.21", + "resolved": "https://registry.npmjs.org/@heroui/ripple/-/ripple-2.2.21.tgz", + "integrity": "sha512-wairSq9LnhbIqTCJmUlJAQURQ1wcRK/L8pjg2s3R/XnvZlPXHy4ZzfphiwIlTI21z/f6tH3arxv/g1uXd1RY0g==", + "license": "MIT", + "dependencies": { + "@heroui/dom-animation": "2.1.10", + "@heroui/shared-utils": "2.1.12" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.23", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/scroll-shadow": { + "version": "2.3.19", + "resolved": "https://registry.npmjs.org/@heroui/scroll-shadow/-/scroll-shadow-2.3.19.tgz", + "integrity": "sha512-y5mdBlhiITVrFnQTDqEphYj7p5pHqoFSFtVuRRvl9wUec2lMxEpD85uMGsfL8OgQTKIAqGh2s6M360+VJm7ajQ==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-data-scroll-overflow": "2.2.13" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.23", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/select": { + "version": "2.4.33", + "resolved": "https://registry.npmjs.org/@heroui/select/-/select-2.4.33.tgz", + "integrity": "sha512-iWlczBmrHz2lIjyAneiiFtmgM+YWKLNIHL9dQnMghSAZWT9iCES5c3RuiggqE9k7DfPjHmgvVB24qeajnnXBOQ==", + "license": "MIT", + "dependencies": { + "@heroui/aria-utils": "2.2.29", + "@heroui/form": "2.1.32", + "@heroui/listbox": "2.3.31", + "@heroui/popover": "2.3.32", + "@heroui/react-utils": "2.1.14", + "@heroui/scroll-shadow": "2.3.19", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@heroui/spinner": "2.2.29", + "@heroui/use-aria-button": "2.2.22", + "@heroui/use-aria-multiselect": "2.4.21", + "@heroui/use-form-reset": "2.0.1", + "@heroui/use-safe-layout-effect": "2.1.8", + "@react-aria/focus": "3.21.5", + "@react-aria/form": "3.1.5", + "@react-aria/interactions": "3.27.1", + "@react-aria/overlays": "3.31.2", + "@react-aria/visually-hidden": "3.8.31", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/skeleton": { + "version": "2.2.18", + "resolved": "https://registry.npmjs.org/@heroui/skeleton/-/skeleton-2.2.18.tgz", + "integrity": "sha512-7AjU5kjk9rqrKP9mWQiAVj0dow4/vbK5/ejh4jqdb3DZm7bM2+DGzfnQPiS0c2eWR606CgOuuoImpwDS82HJtA==", + "license": "MIT", + "dependencies": { + "@heroui/shared-utils": "2.1.12" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.23", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/slider": { + "version": "2.4.29", + "resolved": "https://registry.npmjs.org/@heroui/slider/-/slider-2.4.29.tgz", + "integrity": "sha512-JY3uPIShCFLWTbLLYQJJIT5TyLQsyqJHPcM66FprDxwLkf/Ne03jvf+SeieCKAbq/iw+GygTIfwmbSPzrp/yhA==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/tooltip": "2.2.29", + "@react-aria/focus": "3.21.5", + "@react-aria/i18n": "3.12.16", + "@react-aria/interactions": "3.27.1", + "@react-aria/slider": "3.8.5", + "@react-aria/visually-hidden": "3.8.31", + "@react-stately/slider": "3.7.5" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/snippet": { + "version": "2.2.33", + "resolved": "https://registry.npmjs.org/@heroui/snippet/-/snippet-2.2.33.tgz", + "integrity": "sha512-BvoqKPRhdZyXvvPLxUoU0Fg5MzxMYdGWmJMS9gLT1Zv9A9ixua7kTFh9Z5NT9aNScRR9vhroaSQi1x39uCp+5g==", + "license": "MIT", + "dependencies": { + "@heroui/button": "2.2.32", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@heroui/tooltip": "2.2.29", + "@heroui/use-clipboard": "2.1.9", + "@react-aria/focus": "3.21.5" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/spacer": { + "version": "2.2.25", + "resolved": "https://registry.npmjs.org/@heroui/spacer/-/spacer-2.2.25.tgz", + "integrity": "sha512-XSw54osEkNaBykZXhZcFmvwqwuSKCGPFOd2AIR+vrMqcJg0IxWjpGIsexaT3P/LV1PuoTYkTJ8G3N5Wf4pZTUw==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/system-rsc": "2.3.24" + }, + "peerDependencies": { + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/spinner": { + "version": "2.2.29", + "resolved": "https://registry.npmjs.org/@heroui/spinner/-/spinner-2.2.29.tgz", + "integrity": "sha512-08mWpL4+pdACcyzT5MjR0nSkKoWbab0oPzY+JHxIdPSSh3S8JJ7C8dUeV3Kj/15NRzzZlcTM3ClRCV8fdeGmuw==", + "license": "MIT", + "dependencies": { + "@heroui/shared-utils": "2.1.12", + "@heroui/system": "2.4.28", + "@heroui/system-rsc": "2.3.24" + }, + "peerDependencies": { + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/switch": { + "version": "2.2.27", + "resolved": "https://registry.npmjs.org/@heroui/switch/-/switch-2.2.27.tgz", + "integrity": "sha512-z23is+gtPkX29EpixY5ZLY1+NQaP+ueshuiXzdgD9SfCQLOSDYDWuFVdR8ZgfdDPyhP8xpOnJf6l9zfgXHD8Rw==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-safe-layout-effect": "2.1.8", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-aria/switch": "3.7.11", + "@react-aria/visually-hidden": "3.8.31", + "@react-stately/toggle": "3.9.5" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/system-rsc": { + "version": "2.3.24", + "resolved": "https://registry.npmjs.org/@heroui/system-rsc/-/system-rsc-2.3.24.tgz", + "integrity": "sha512-GEP3hh7j8wE56WdSAIdCcPQOMDdAYk9bSuQpGzXnkYSiSCJKroOyXbRmp9KF2VgpiMXGI0OlO51aj9JWoa+5Tg==", + "license": "MIT", + "dependencies": { + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/table": { + "version": "2.2.32", + "resolved": "https://registry.npmjs.org/@heroui/table/-/table-2.2.32.tgz", + "integrity": "sha512-cJ+XtBZOonSmkw7jrj0d9c8aIMdSGSZrBKS/1KZ7J9BTFPDW+ZoWwomgJHgZ31FQlr7dkYa7mZ2rf8LoGoOxRA==", + "license": "MIT", + "dependencies": { + "@heroui/checkbox": "2.3.32", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-aria/table": "3.17.11", + "@react-aria/visually-hidden": "3.8.31", + "@react-stately/table": "3.15.4", + "@react-stately/virtualizer": "4.4.6", + "@react-types/grid": "3.3.8", + "@react-types/table": "3.13.6", + "@tanstack/react-virtual": "3.11.3" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/tabs": { + "version": "2.2.29", + "resolved": "https://registry.npmjs.org/@heroui/tabs/-/tabs-2.2.29.tgz", + "integrity": "sha512-TzCRXDqhdNsUxhO6sPdsbEt8m7KlkGwvJGvs4S/kHvJh1sKCItnnT0Z2FpZr6pLAqmHA6LO6Ow1phR5ACfNmug==", + "license": "MIT", + "dependencies": { + "@heroui/aria-utils": "2.2.29", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-is-mounted": "2.1.8", + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-aria/tabs": "3.11.1", + "@react-stately/tabs": "3.8.9", + "@react-types/shared": "3.33.1", + "scroll-into-view-if-needed": "3.0.10" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/toast": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/@heroui/toast/-/toast-2.0.22.tgz", + "integrity": "sha512-eaayx0oJW0/imLyOhfjOdMx8FEKbWa8aKVvPNvXr3mXQbgzBEa+e147Xbh2CneG66we9C24JETE7QMLJ00popw==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/shared-icons": "2.1.10", + "@heroui/shared-utils": "2.1.12", + "@heroui/spinner": "2.2.29", + "@heroui/use-is-mobile": "2.2.12", + "@react-aria/interactions": "3.27.1", + "@react-aria/toast": "3.0.11", + "@react-stately/toast": "3.1.3" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/tooltip": { + "version": "2.2.29", + "resolved": "https://registry.npmjs.org/@heroui/tooltip/-/tooltip-2.2.29.tgz", + "integrity": "sha512-PsHVC9XwjmbZpdu7o8TWSHENiCHCsoQpzpFJ3GYgnUULIhH5k69L/+5jiON9qG6k7+tL4RZS6pQPSbxDCf1acQ==", + "license": "MIT", + "dependencies": { + "@heroui/aria-utils": "2.2.29", + "@heroui/dom-animation": "2.1.10", + "@heroui/framer-utils": "2.1.28", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@heroui/use-aria-overlay": "2.0.6", + "@heroui/use-safe-layout-effect": "2.1.8", + "@react-aria/overlays": "3.31.2", + "@react-aria/tooltip": "3.9.2", + "@react-stately/tooltip": "3.5.11", + "@react-types/overlays": "3.9.4", + "@react-types/tooltip": "3.5.2" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@heroui/user": { + "version": "2.2.26", + "resolved": "https://registry.npmjs.org/@heroui/user/-/user-2.2.26.tgz", + "integrity": "sha512-3SESvOSYSVysSSwV1SR2QD8cOx6Fv/vVAXry/GmjLl9CSsA6HTlWoLy7TRtteGFqm3XRWVqjzCrcNGlvSmtdnQ==", + "license": "MIT", + "dependencies": { + "@heroui/avatar": "2.2.26", + "@heroui/react-utils": "2.1.14", + "@heroui/shared-utils": "2.1.12", + "@react-aria/focus": "3.21.5" + }, + "peerDependencies": { + "@heroui/system": ">=2.4.18", + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/react/node_modules/@internationalized/date": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.0.tgz", + "integrity": "sha512-/PyIMzK29jtXaGU23qTvNZxvBXRtKbNnGDFD+PY6CZw/Y8Ex8pFUzkuCJCG9aOqmShjqhS9mPqP6Dk5onQY8rQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@heroui/react/node_modules/@react-aria/button": { + "version": "3.14.5", + "resolved": "https://registry.npmjs.org/@react-aria/button/-/button-3.14.5.tgz", + "integrity": "sha512-ZuLx+wQj9VQhH9BYe7t0JowmKnns2XrFHFNvIVBb5RwxL+CIycIOL7brhWKg2rGdxvlOom7jhVbcjSmtAaSyaQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.1", + "@react-aria/toolbar": "3.0.0-beta.24", + "@react-aria/utils": "^3.33.1", + "@react-stately/toggle": "^3.9.5", + "@react-types/button": "^3.15.1", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/react/node_modules/@react-aria/dialog": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@react-aria/dialog/-/dialog-3.5.34.tgz", + "integrity": "sha512-/x53Q5ynpW5Kv9637WYu7SrDfj3woSp6jJRj8l6teGnWW/iNZWYJETgzHfbxx+HPKYATCZesRoIeO2LnYIXyEA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.1", + "@react-aria/overlays": "^3.31.2", + "@react-aria/utils": "^3.33.1", + "@react-types/dialog": "^3.5.24", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/react/node_modules/@react-aria/focus": { + "version": "3.21.5", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.21.5.tgz", + "integrity": "sha512-V18fwCyf8zqgJdpLQeDU5ZRNd9TeOfBbhLgmX77Zr5ae9XwaoJ1R3SFJG1wCJX60t34AW+aLZSEEK+saQElf3Q==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.1", + "@react-aria/utils": "^3.33.1", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/react/node_modules/@react-aria/form": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@react-aria/form/-/form-3.1.5.tgz", + "integrity": "sha512-BWlONgHn8hmaMkcS6AgMSLQeNqVBwqPNLhdqjDO/PCfzvV7O8NZw/dFeIzJwfG4aBfSpbHHRdXGdfrk3d8dylQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.1", + "@react-aria/utils": "^3.33.1", + "@react-stately/form": "^3.2.4", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/react/node_modules/@react-aria/interactions": { + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.27.1.tgz", + "integrity": "sha512-M3wLpTTmDflI0QGNK0PJNUaBXXfeBXue8ZxLMngfc1piHNiH4G5lUvWd9W14XVbqrSCVY8i8DfGrNYpyyZu0tw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.10", + "@react-aria/utils": "^3.33.1", + "@react-stately/flags": "^3.1.2", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/react/node_modules/@react-aria/listbox": { + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/@react-aria/listbox/-/listbox-3.15.3.tgz", + "integrity": "sha512-C6YgiyrHS5sbS5UBdxGMhEs+EKJYotJgGVtl9l0ySXpBUXERiHJWLOyV7a8PwkUOmepbB4FaLD7Y9EUzGkrGlw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.1", + "@react-aria/label": "^3.7.25", + "@react-aria/selection": "^3.27.2", + "@react-aria/utils": "^3.33.1", + "@react-stately/collections": "^3.12.10", + "@react-stately/list": "^3.13.4", + "@react-types/listbox": "^3.7.6", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/react/node_modules/@react-aria/menu": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@react-aria/menu/-/menu-3.21.0.tgz", + "integrity": "sha512-CKTVZ4izSE1eKIti6TbTtzJAUo+WT8O4JC0XZCYDBpa0f++lD19Kz9aY+iY1buv5xGI20gAfpO474E9oEd4aQA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.21.5", + "@react-aria/i18n": "^3.12.16", + "@react-aria/interactions": "^3.27.1", + "@react-aria/overlays": "^3.31.2", + "@react-aria/selection": "^3.27.2", + "@react-aria/utils": "^3.33.1", + "@react-stately/collections": "^3.12.10", + "@react-stately/menu": "^3.9.11", + "@react-stately/selection": "^3.20.9", + "@react-stately/tree": "^3.9.6", + "@react-types/button": "^3.15.1", + "@react-types/menu": "^3.10.7", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/react/node_modules/@react-aria/textfield": { + "version": "3.18.5", + "resolved": "https://registry.npmjs.org/@react-aria/textfield/-/textfield-3.18.5.tgz", + "integrity": "sha512-ttwVSuwoV3RPaG2k2QzEXKeQNQ3mbdl/2yy6I4Tjrn1ZNkYHfVyJJ26AjenfSmj1kkTQoSAfZ8p+7rZp4n0xoQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/form": "^3.1.5", + "@react-aria/interactions": "^3.27.1", + "@react-aria/label": "^3.7.25", + "@react-aria/utils": "^3.33.1", + "@react-stately/form": "^3.2.4", + "@react-stately/utils": "^3.11.0", + "@react-types/shared": "^3.33.1", + "@react-types/textfield": "^3.12.8", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/react/node_modules/@react-stately/overlays": { + "version": "3.6.23", + "resolved": "https://registry.npmjs.org/@react-stately/overlays/-/overlays-3.6.23.tgz", + "integrity": "sha512-RzWxots9A6gAzQMP4s8hOAHV7SbJRTFSlQbb6ly1nkWQXacOSZSFNGsKOaS0eIatfNPlNnW4NIkgtGws5UYzfw==", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/utils": "^3.11.0", + "@react-types/overlays": "^3.9.4", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/react/node_modules/@react-stately/utils": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.11.0.tgz", + "integrity": "sha512-8LZpYowJ9eZmmYLpudbo/eclIRnbhWIJZ994ncmlKlouNzKohtM8qTC6B1w1pwUbiwGdUoyzLuQbeaIor5Dvcw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/react/node_modules/@react-types/button": { + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/@react-types/button/-/button-3.15.1.tgz", + "integrity": "sha512-M1HtsKreJkigCnqceuIT22hDJBSStbPimnpmQmsl7SNyqCFY3+DHS7y/Sl3GvqCkzxF7j9UTL0dG38lGQ3K4xQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/react/node_modules/@react-types/overlays": { + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/@react-types/overlays/-/overlays-3.9.4.tgz", + "integrity": "sha512-7Z9HaebMFyYBqtv3XVNHEmVkm7AiYviV7gv0c98elEN2Co+eQcKFGvwBM9Gy/lV57zlTqFX1EX/SAqkMEbCLOA==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/shared-icons": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@heroui/shared-icons/-/shared-icons-2.1.10.tgz", + "integrity": "sha512-ePo60GjEpM0SEyZBGOeySsLueNDCqLsVL79Fq+5BphzlrBAcaKY7kUp74964ImtkXvknTxAWzuuTr3kCRqj6jg==", + "license": "MIT", + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/shared-utils": { + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/@heroui/shared-utils/-/shared-utils-2.1.12.tgz", + "integrity": "sha512-0iCnxVAkIPtrHQo26Qa5g0UTqMTpugTbClNOrEPsrQuyRAq7Syux998cPwGlneTfB5E5xcU3LiEdA9GUyeK2cQ==", + "hasInstallScript": true, + "license": "MIT" + }, + "node_modules/@heroui/system": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@heroui/system/-/system-2.4.28.tgz", + "integrity": "sha512-agtiiMFsCLaBrGWWrGBlFrnwi06ym4uouh61c3/m16CHuYfGm0Hx5oJ1mZVF98SJ91mDyU3e6Rv+8mqV9XVgoQ==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/system-rsc": "2.3.24", + "@react-aria/i18n": "3.12.16", + "@react-aria/overlays": "3.31.2", + "@react-aria/utils": "3.33.1" + }, + "peerDependencies": { + "framer-motion": ">=11.5.6 || >=12.0.0-alpha.1", + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/system/node_modules/@heroui/system-rsc": { + "version": "2.3.24", + "resolved": "https://registry.npmjs.org/@heroui/system-rsc/-/system-rsc-2.3.24.tgz", + "integrity": "sha512-GEP3hh7j8wE56WdSAIdCcPQOMDdAYk9bSuQpGzXnkYSiSCJKroOyXbRmp9KF2VgpiMXGI0OlO51aj9JWoa+5Tg==", + "license": "MIT", + "dependencies": { + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "@heroui/theme": ">=2.4.24", + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/theme": { + "version": "2.4.26", + "resolved": "https://registry.npmjs.org/@heroui/theme/-/theme-2.4.26.tgz", + "integrity": "sha512-TYatChq7YyGDcPJytgOMqQwK72qWYb+vIa7mLmX3Cu9+JzFs2VSHu2QqzdhnOHoK0uJr8giDMy0gvJEDuu31vw==", + "license": "MIT", + "dependencies": { + "@heroui/shared-utils": "2.1.12", + "color": "^4.2.3", + "color2k": "^2.0.3", + "deepmerge": "4.3.1", + "tailwind-merge": "3.4.0", + "tailwind-variants": "3.2.2" + }, + "peerDependencies": { + "tailwindcss": ">=4.0.0" + } + }, + "node_modules/@heroui/use-aria-accordion": { + "version": "2.2.20", + "resolved": "https://registry.npmjs.org/@heroui/use-aria-accordion/-/use-aria-accordion-2.2.20.tgz", + "integrity": "sha512-HvZhfrsxpCab+m4TrbHWsnA8iLaYdq1G1pjFCswftDRzfioJLmkJ0FMtYDPi792akJO+TWEvPhJibcwVD0bbfg==", + "license": "MIT", + "dependencies": { + "@react-aria/button": "3.14.5", + "@react-aria/focus": "3.21.5", + "@react-aria/selection": "3.27.2", + "@react-stately/tree": "3.9.6", + "@react-types/accordion": "3.0.0-alpha.26", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-aria-accordion/node_modules/@react-aria/button": { + "version": "3.14.5", + "resolved": "https://registry.npmjs.org/@react-aria/button/-/button-3.14.5.tgz", + "integrity": "sha512-ZuLx+wQj9VQhH9BYe7t0JowmKnns2XrFHFNvIVBb5RwxL+CIycIOL7brhWKg2rGdxvlOom7jhVbcjSmtAaSyaQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.1", + "@react-aria/toolbar": "3.0.0-beta.24", + "@react-aria/utils": "^3.33.1", + "@react-stately/toggle": "^3.9.5", + "@react-types/button": "^3.15.1", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-accordion/node_modules/@react-aria/focus": { + "version": "3.21.5", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.21.5.tgz", + "integrity": "sha512-V18fwCyf8zqgJdpLQeDU5ZRNd9TeOfBbhLgmX77Zr5ae9XwaoJ1R3SFJG1wCJX60t34AW+aLZSEEK+saQElf3Q==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.1", + "@react-aria/utils": "^3.33.1", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-accordion/node_modules/@react-aria/selection": { + "version": "3.27.2", + "resolved": "https://registry.npmjs.org/@react-aria/selection/-/selection-3.27.2.tgz", + "integrity": "sha512-GbUSSLX/ciXix95KW1g+SLM9np7iXpIZrFDSXkC6oNx1uhy18eAcuTkeZE25+SY5USVUmEzjI3m/3JoSUcebbg==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.21.5", + "@react-aria/i18n": "^3.12.16", + "@react-aria/interactions": "^3.27.1", + "@react-aria/utils": "^3.33.1", + "@react-stately/selection": "^3.20.9", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-button": { + "version": "2.2.22", + "resolved": "https://registry.npmjs.org/@heroui/use-aria-button/-/use-aria-button-2.2.22.tgz", + "integrity": "sha512-6Y+fWkf/LKKxw3cd9QCSdLVMrMgKv+0AGCzNCfDiZ5kzQGCX4JQD9eK/495opAHV90yhIWzolwdNwtsyhDploA==", + "license": "MIT", + "dependencies": { + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-aria/utils": "3.33.1", + "@react-types/button": "3.15.1", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-aria-button/node_modules/@react-aria/focus": { + "version": "3.21.5", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.21.5.tgz", + "integrity": "sha512-V18fwCyf8zqgJdpLQeDU5ZRNd9TeOfBbhLgmX77Zr5ae9XwaoJ1R3SFJG1wCJX60t34AW+aLZSEEK+saQElf3Q==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.1", + "@react-aria/utils": "^3.33.1", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-button/node_modules/@react-aria/interactions": { + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.27.1.tgz", + "integrity": "sha512-M3wLpTTmDflI0QGNK0PJNUaBXXfeBXue8ZxLMngfc1piHNiH4G5lUvWd9W14XVbqrSCVY8i8DfGrNYpyyZu0tw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.10", + "@react-aria/utils": "^3.33.1", + "@react-stately/flags": "^3.1.2", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-button/node_modules/@react-types/button": { + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/@react-types/button/-/button-3.15.1.tgz", + "integrity": "sha512-M1HtsKreJkigCnqceuIT22hDJBSStbPimnpmQmsl7SNyqCFY3+DHS7y/Sl3GvqCkzxF7j9UTL0dG38lGQ3K4xQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-link": { + "version": "2.2.23", + "resolved": "https://registry.npmjs.org/@heroui/use-aria-link/-/use-aria-link-2.2.23.tgz", + "integrity": "sha512-jpFj9HNCdt+DENPJyrfoN+AzuaMze9xqo5Y1P3KGoT/2pFDmelFgbXAOC5CHpatYFIn3YEELBGlj84zNXq2gjQ==", + "license": "MIT", + "dependencies": { + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-aria/utils": "3.33.1", + "@react-types/link": "3.6.7", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-aria-link/node_modules/@react-aria/focus": { + "version": "3.21.5", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.21.5.tgz", + "integrity": "sha512-V18fwCyf8zqgJdpLQeDU5ZRNd9TeOfBbhLgmX77Zr5ae9XwaoJ1R3SFJG1wCJX60t34AW+aLZSEEK+saQElf3Q==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.1", + "@react-aria/utils": "^3.33.1", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-link/node_modules/@react-aria/interactions": { + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.27.1.tgz", + "integrity": "sha512-M3wLpTTmDflI0QGNK0PJNUaBXXfeBXue8ZxLMngfc1piHNiH4G5lUvWd9W14XVbqrSCVY8i8DfGrNYpyyZu0tw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.10", + "@react-aria/utils": "^3.33.1", + "@react-stately/flags": "^3.1.2", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-modal-overlay": { + "version": "2.2.21", + "resolved": "https://registry.npmjs.org/@heroui/use-aria-modal-overlay/-/use-aria-modal-overlay-2.2.21.tgz", + "integrity": "sha512-Qwj5ldLFpfinfGpYUQu92TCpGKzd9Uamhd31ayRvYl6+LwOX124N9ObRYBTXyEiNJ7XFYer3vXQVeaR84xM1Gg==", + "license": "MIT", + "dependencies": { + "@heroui/use-aria-overlay": "2.0.6", + "@react-aria/overlays": "3.31.2", + "@react-aria/utils": "3.33.1", + "@react-stately/overlays": "3.6.23" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-aria-modal-overlay/node_modules/@react-stately/overlays": { + "version": "3.6.23", + "resolved": "https://registry.npmjs.org/@react-stately/overlays/-/overlays-3.6.23.tgz", + "integrity": "sha512-RzWxots9A6gAzQMP4s8hOAHV7SbJRTFSlQbb6ly1nkWQXacOSZSFNGsKOaS0eIatfNPlNnW4NIkgtGws5UYzfw==", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/utils": "^3.11.0", + "@react-types/overlays": "^3.9.4", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-multiselect": { + "version": "2.4.21", + "resolved": "https://registry.npmjs.org/@heroui/use-aria-multiselect/-/use-aria-multiselect-2.4.21.tgz", + "integrity": "sha512-f/7YkTfS67OMXXYCO9WTI0Fj9YGPOgdwMIqhaSnFdA2UywA3W71PPeEqpKeuvO6isBW53YOynAPMZXF1NcsuHw==", + "license": "MIT", + "dependencies": { + "@react-aria/i18n": "3.12.16", + "@react-aria/interactions": "3.27.1", + "@react-aria/label": "3.7.25", + "@react-aria/listbox": "3.15.3", + "@react-aria/menu": "3.21.0", + "@react-aria/selection": "3.27.2", + "@react-aria/utils": "3.33.1", + "@react-stately/form": "3.2.4", + "@react-stately/list": "3.13.4", + "@react-stately/menu": "3.9.11", + "@react-types/button": "3.15.1", + "@react-types/overlays": "3.9.4", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0", + "react-dom": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-aria-multiselect/node_modules/@react-aria/interactions": { + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.27.1.tgz", + "integrity": "sha512-M3wLpTTmDflI0QGNK0PJNUaBXXfeBXue8ZxLMngfc1piHNiH4G5lUvWd9W14XVbqrSCVY8i8DfGrNYpyyZu0tw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.10", + "@react-aria/utils": "^3.33.1", + "@react-stately/flags": "^3.1.2", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-multiselect/node_modules/@react-aria/label": { + "version": "3.7.25", + "resolved": "https://registry.npmjs.org/@react-aria/label/-/label-3.7.25.tgz", + "integrity": "sha512-oNK3Pqj4LDPwEbQaoM/uCip4QvQmmwGOh08VeW+vzSi6TAwf+KoWTyH/tiAeB0CHWNDK0k3e1iTygTAt4wzBmg==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/utils": "^3.33.1", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-multiselect/node_modules/@react-aria/listbox": { + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/@react-aria/listbox/-/listbox-3.15.3.tgz", + "integrity": "sha512-C6YgiyrHS5sbS5UBdxGMhEs+EKJYotJgGVtl9l0ySXpBUXERiHJWLOyV7a8PwkUOmepbB4FaLD7Y9EUzGkrGlw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.1", + "@react-aria/label": "^3.7.25", + "@react-aria/selection": "^3.27.2", + "@react-aria/utils": "^3.33.1", + "@react-stately/collections": "^3.12.10", + "@react-stately/list": "^3.13.4", + "@react-types/listbox": "^3.7.6", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-multiselect/node_modules/@react-aria/menu": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/@react-aria/menu/-/menu-3.21.0.tgz", + "integrity": "sha512-CKTVZ4izSE1eKIti6TbTtzJAUo+WT8O4JC0XZCYDBpa0f++lD19Kz9aY+iY1buv5xGI20gAfpO474E9oEd4aQA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.21.5", + "@react-aria/i18n": "^3.12.16", + "@react-aria/interactions": "^3.27.1", + "@react-aria/overlays": "^3.31.2", + "@react-aria/selection": "^3.27.2", + "@react-aria/utils": "^3.33.1", + "@react-stately/collections": "^3.12.10", + "@react-stately/menu": "^3.9.11", + "@react-stately/selection": "^3.20.9", + "@react-stately/tree": "^3.9.6", + "@react-types/button": "^3.15.1", + "@react-types/menu": "^3.10.7", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-multiselect/node_modules/@react-aria/selection": { + "version": "3.27.2", + "resolved": "https://registry.npmjs.org/@react-aria/selection/-/selection-3.27.2.tgz", + "integrity": "sha512-GbUSSLX/ciXix95KW1g+SLM9np7iXpIZrFDSXkC6oNx1uhy18eAcuTkeZE25+SY5USVUmEzjI3m/3JoSUcebbg==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.21.5", + "@react-aria/i18n": "^3.12.16", + "@react-aria/interactions": "^3.27.1", + "@react-aria/utils": "^3.33.1", + "@react-stately/selection": "^3.20.9", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-multiselect/node_modules/@react-types/button": { + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/@react-types/button/-/button-3.15.1.tgz", + "integrity": "sha512-M1HtsKreJkigCnqceuIT22hDJBSStbPimnpmQmsl7SNyqCFY3+DHS7y/Sl3GvqCkzxF7j9UTL0dG38lGQ3K4xQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-multiselect/node_modules/@react-types/overlays": { + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/@react-types/overlays/-/overlays-3.9.4.tgz", + "integrity": "sha512-7Z9HaebMFyYBqtv3XVNHEmVkm7AiYviV7gv0c98elEN2Co+eQcKFGvwBM9Gy/lV57zlTqFX1EX/SAqkMEbCLOA==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-overlay": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@heroui/use-aria-overlay/-/use-aria-overlay-2.0.6.tgz", + "integrity": "sha512-7q8oj5DZjr9oGYUB1UTOBnnuAapkBmfATCsdUeNOxQdYb2glJp52sTUslO+ykI9xVOAJSGYAmGuWgY5d+8mD6Q==", + "license": "MIT", + "dependencies": { + "@react-aria/focus": "3.21.5", + "@react-aria/interactions": "3.27.1", + "@react-aria/overlays": "3.31.2", + "@react-types/shared": "3.33.1" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/@heroui/use-aria-overlay/node_modules/@react-aria/focus": { + "version": "3.21.5", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.21.5.tgz", + "integrity": "sha512-V18fwCyf8zqgJdpLQeDU5ZRNd9TeOfBbhLgmX77Zr5ae9XwaoJ1R3SFJG1wCJX60t34AW+aLZSEEK+saQElf3Q==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.1", + "@react-aria/utils": "^3.33.1", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-aria-overlay/node_modules/@react-aria/interactions": { + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.27.1.tgz", + "integrity": "sha512-M3wLpTTmDflI0QGNK0PJNUaBXXfeBXue8ZxLMngfc1piHNiH4G5lUvWd9W14XVbqrSCVY8i8DfGrNYpyyZu0tw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.10", + "@react-aria/utils": "^3.33.1", + "@react-stately/flags": "^3.1.2", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-callback-ref": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@heroui/use-callback-ref/-/use-callback-ref-2.1.8.tgz", + "integrity": "sha512-D1JDo9YyFAprYpLID97xxQvf86NvyWLay30BeVVZT9kWmar6O9MbCRc7ACi7Ngko60beonj6+amTWkTm7QuY/Q==", + "license": "MIT", + "dependencies": { + "@heroui/use-safe-layout-effect": "2.1.8" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-clipboard": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@heroui/use-clipboard/-/use-clipboard-2.1.9.tgz", + "integrity": "sha512-lkBq5RpXHiPvk1BXKJG8gMM0f7jRMIGnxAXDjAUzZyXKBuWLoM+XlaUWmZHtmkkjVFMX1L4vzA+vxi9rZbenEQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-data-scroll-overflow": { + "version": "2.2.13", + "resolved": "https://registry.npmjs.org/@heroui/use-data-scroll-overflow/-/use-data-scroll-overflow-2.2.13.tgz", + "integrity": "sha512-zboLXO1pgYdzMUahDcVt5jf+l1jAQ/D9dFqr7AxWLfn6tn7/EgY0f6xIrgWDgJnM0U3hKxVeY13pAeB4AFTqTw==", + "license": "MIT", + "dependencies": { + "@heroui/shared-utils": "2.1.12" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-disclosure": { + "version": "2.2.19", + "resolved": "https://registry.npmjs.org/@heroui/use-disclosure/-/use-disclosure-2.2.19.tgz", + "integrity": "sha512-N3CBikg1cxik2xp1UQkPUBbKPGrvtdsRyAlOnGygliyr5wKpZHLZi0R/g8OxTZVk3zUSCl7HZJT13ddM5TqEvA==", + "license": "MIT", + "dependencies": { + "@heroui/use-callback-ref": "2.1.8", + "@react-aria/utils": "3.33.1", + "@react-stately/utils": "3.11.0" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-disclosure/node_modules/@react-stately/utils": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.11.0.tgz", + "integrity": "sha512-8LZpYowJ9eZmmYLpudbo/eclIRnbhWIJZ994ncmlKlouNzKohtM8qTC6B1w1pwUbiwGdUoyzLuQbeaIor5Dvcw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-draggable": { + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/@heroui/use-draggable/-/use-draggable-2.1.20.tgz", + "integrity": "sha512-yXn3jU3qiUx6aUd2osbDfddpnUTTh2wAVzpNyI+BXl2Z3rkVU9jqiJxZa+BXfsqFX17KrlrxwPPBmLNhSdBKHg==", + "license": "MIT", + "dependencies": { + "@react-aria/interactions": "3.27.1" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-draggable/node_modules/@react-aria/interactions": { + "version": "3.27.1", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.27.1.tgz", + "integrity": "sha512-M3wLpTTmDflI0QGNK0PJNUaBXXfeBXue8ZxLMngfc1piHNiH4G5lUvWd9W14XVbqrSCVY8i8DfGrNYpyyZu0tw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.10", + "@react-aria/utils": "^3.33.1", + "@react-stately/flags": "^3.1.2", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-form-reset": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@heroui/use-form-reset/-/use-form-reset-2.0.1.tgz", + "integrity": "sha512-6slKWiLtVfgZnVeHVkM9eXgjwI07u0CUaLt2kQpfKPqTSTGfbHgCYJFduijtThhTdKBhdH6HCmzTcnbVlAxBXw==", + "license": "MIT", + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-image": { + "version": "2.1.14", + "resolved": "https://registry.npmjs.org/@heroui/use-image/-/use-image-2.1.14.tgz", + "integrity": "sha512-eCxtKOsM1tszBKYqz8qIJwGIxEAUC7ua+6L9vK8JgG6gOC0jEPFGH7keQuPVprzRtG3DmNt90icowqEjnOHdFQ==", + "license": "MIT", + "dependencies": { + "@heroui/react-utils": "2.1.14", + "@heroui/use-safe-layout-effect": "2.1.8" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-intersection-observer": { + "version": "2.2.14", + "resolved": "https://registry.npmjs.org/@heroui/use-intersection-observer/-/use-intersection-observer-2.2.14.tgz", + "integrity": "sha512-qYJeMk4cTsF+xIckRctazCgWQ4BVOpJu+bhhkB1NrN+MItx19Lcb7ksOqMdN5AiSf85HzDcAEPIQ9w9RBlt5sg==", + "license": "MIT", + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-is-mobile": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/@heroui/use-is-mobile/-/use-is-mobile-2.2.12.tgz", + "integrity": "sha512-2UKa4v1xbvFwerWKoMTrg4q9ZfP9MVIVfCl1a7JuKQlXq3jcyV6z1as5bZ41pCsTOT+wUVOFnlr6rzzQwT9ZOA==", + "license": "MIT", + "dependencies": { + "@react-aria/ssr": "3.9.10" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-is-mobile/node_modules/@react-aria/ssr": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.10.tgz", + "integrity": "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@heroui/use-is-mounted": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@heroui/use-is-mounted/-/use-is-mounted-2.1.8.tgz", + "integrity": "sha512-DO/Th1vD4Uy8KGhd17oGlNA4wtdg91dzga+VMpmt94gSZe1WjsangFwoUBxF2uhlzwensCX9voye3kerP/lskg==", + "license": "MIT", + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-measure": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@heroui/use-measure/-/use-measure-2.1.8.tgz", + "integrity": "sha512-GjT9tIgluqYMZWfAX6+FFdRQBqyHeuqUMGzAXMTH9kBXHU0U5C5XU2c8WFORkNDoZIg1h13h1QdV+Vy4LE1dEA==", + "license": "MIT", + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-pagination": { + "version": "2.2.20", + "resolved": "https://registry.npmjs.org/@heroui/use-pagination/-/use-pagination-2.2.20.tgz", + "integrity": "sha512-+ZK+vJgLq7JKLJAnIwfbxe/oF1hANtIiCR6H++q7fOw9pxZZQsntmLEu4kvRhpGZRp5C5T10A1GKIK7/xz1ZdA==", + "license": "MIT", + "dependencies": { + "@heroui/shared-utils": "2.1.12", + "@react-aria/i18n": "3.12.16" + }, + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-resize": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@heroui/use-resize/-/use-resize-2.1.8.tgz", + "integrity": "sha512-htF3DND5GmrSiMGnzRbISeKcH+BqhQ/NcsP9sBTIl7ewvFaWiDhEDiUHdJxflmJGd/c5qZq2nYQM/uluaqIkKA==", + "license": "MIT", + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-safe-layout-effect": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@heroui/use-safe-layout-effect/-/use-safe-layout-effect-2.1.8.tgz", + "integrity": "sha512-wbnZxVWCYqk10XRMu0veSOiVsEnLcmGUmJiapqgaz0fF8XcpSScmqjTSoWjHIEWaHjQZ6xr+oscD761D6QJN+Q==", + "license": "MIT", + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-scroll-position": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@heroui/use-scroll-position/-/use-scroll-position-2.1.8.tgz", + "integrity": "sha512-NxanHKObxVfWaPpNRyBR8v7RfokxrzcHyTyQfbgQgAGYGHTMaOGkJGqF8kBzInc3zJi+F0zbX7Nb0QjUgsLNUQ==", + "license": "MIT", + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@heroui/use-viewport-size": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@heroui/use-viewport-size/-/use-viewport-size-2.0.1.tgz", + "integrity": "sha512-blv8BEB/QdLePLWODPRzRS2eELJ2eyHbdOIADbL0KcfLzOUEg9EiuVk90hcSUDAFqYiJ3YZ5Z0up8sdPcR8Y7g==", + "license": "MIT", + "peerDependencies": { + "react": ">=18 || >=19.0.0-rc.0" + } + }, + "node_modules/@internationalized/date": { + "version": "3.12.3", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.3.tgz", + "integrity": "sha512-fuLX+3ZKLsxI73y8b01EG/WjHb6gE6weCqlfawPO27kBWGMh9G1yH6Csv1uU7/cac9H2GHmOMt6CjmuQ1aia4Q==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@internationalized/message": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@internationalized/message/-/message-3.1.10.tgz", + "integrity": "sha512-nc0Or6EdWHqZRcsXb6P9hBIpLsfSl/ILh0rk5h/OVBpzmhdExXtPy2cQtWsq8XKRBpRHwDNnAHt4OpolcB7dog==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "intl-messageformat": "^10.1.0" + } + }, + "node_modules/@internationalized/number": { + "version": "3.6.7", + "resolved": "https://registry.npmjs.org/@internationalized/number/-/number-3.6.7.tgz", + "integrity": "sha512-3ji1fcrT+FPAK86UqEhB/psHixYo6niWPJtt7+qRaYFynt/BaJG8GhAPimtWUpEiVSTq8ZM8L5psMxGquiB/Vg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@internationalized/string": { + "version": "3.2.10", + "resolved": "https://registry.npmjs.org/@internationalized/string/-/string-3.2.10.tgz", + "integrity": "sha512-PDx6//vHSpRnHfxqMqto11zQvhsaU74O3mKv2F/0eicGZcl9NLjQmGlbHz/LsJh5tLKp4A4L7ZVTzN1/MmMTvA==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@react-aria/breadcrumbs": { + "version": "3.5.32", + "resolved": "https://registry.npmjs.org/@react-aria/breadcrumbs/-/breadcrumbs-3.5.32.tgz", + "integrity": "sha512-S61vh5DJ2PXiXUwD7gk+pvS/b4VPrc3ZJOUZ0yVRLHkVESr5LhIZH+SAVgZkm1lzKyMRG+BH+fiRH/DZRSs7SA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/i18n": "^3.12.16", + "@react-aria/link": "^3.8.9", + "@react-aria/utils": "^3.33.1", + "@react-types/breadcrumbs": "^3.7.19", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/button": { + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/@react-aria/button/-/button-3.15.1.tgz", + "integrity": "sha512-SBMn8ZLvjuWCpSqi6o1hOjsqQqkdYFfzIdl/0LgNPUpTclkJuMx7gNXfM3mjgxzSCoS5CD/XdicvqJanMw6jCw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/calendar": { + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/@react-aria/calendar/-/calendar-3.9.5.tgz", + "integrity": "sha512-k0kvceYdZZu+DoeqephtlmIvh1CxqdFyoN52iqVzTz9O0pe5Xfhq7zxPGbeCp4pC61xzp8Lu/6uFA/YNfQQNag==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.0", + "@react-aria/i18n": "^3.12.16", + "@react-aria/interactions": "^3.27.1", + "@react-aria/live-announcer": "^3.4.4", + "@react-aria/utils": "^3.33.1", + "@react-stately/calendar": "^3.9.3", + "@react-types/button": "^3.15.1", + "@react-types/calendar": "^3.8.3", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/checkbox": { + "version": "3.16.5", + "resolved": "https://registry.npmjs.org/@react-aria/checkbox/-/checkbox-3.16.5.tgz", + "integrity": "sha512-ZhUT7ELuD52hb+Zpzw0ElLQiVOd5sKYahrh+PK3vq13Wk5TedBscALpjuXetI4pwFfdmAM1Lhgcsrd8+6AmyvA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/form": "^3.1.5", + "@react-aria/interactions": "^3.27.1", + "@react-aria/label": "^3.7.25", + "@react-aria/toggle": "^3.12.5", + "@react-aria/utils": "^3.33.1", + "@react-stately/checkbox": "^3.7.5", + "@react-stately/form": "^3.2.4", + "@react-stately/toggle": "^3.9.5", + "@react-types/checkbox": "^3.10.4", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/combobox": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/@react-aria/combobox/-/combobox-3.15.0.tgz", + "integrity": "sha512-qSjQTFwKl3x1jCP2NRSJ6doZqAp6c2GTfoiFwWjaWg1IewwLsglaW6NnzqRDFiqFbDGgXPn4MqtC1VYEJ3NEjA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.21.5", + "@react-aria/i18n": "^3.12.16", + "@react-aria/interactions": "^3.27.1", + "@react-aria/listbox": "^3.15.3", + "@react-aria/live-announcer": "^3.4.4", + "@react-aria/menu": "^3.21.0", + "@react-aria/overlays": "^3.31.2", + "@react-aria/selection": "^3.27.2", + "@react-aria/textfield": "^3.18.5", + "@react-aria/utils": "^3.33.1", + "@react-stately/collections": "^3.12.10", + "@react-stately/combobox": "^3.13.0", + "@react-stately/form": "^3.2.4", + "@react-types/button": "^3.15.1", + "@react-types/combobox": "^3.14.0", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/datepicker": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/@react-aria/datepicker/-/datepicker-3.16.1.tgz", + "integrity": "sha512-6BltCVWt09yefTkGjb2gViGCwoddx9HKJiZbY9u6Es/Q+VhwNJQRtczbnZ3K32p262hIknukNf/5nZaCOI1AKA==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.0", + "@internationalized/number": "^3.6.5", + "@internationalized/string": "^3.2.7", + "@react-aria/focus": "^3.21.5", + "@react-aria/form": "^3.1.5", + "@react-aria/i18n": "^3.12.16", + "@react-aria/interactions": "^3.27.1", + "@react-aria/label": "^3.7.25", + "@react-aria/spinbutton": "^3.7.2", + "@react-aria/utils": "^3.33.1", + "@react-stately/datepicker": "^3.16.1", + "@react-stately/form": "^3.2.4", + "@react-types/button": "^3.15.1", + "@react-types/calendar": "^3.8.3", + "@react-types/datepicker": "^3.13.5", + "@react-types/dialog": "^3.5.24", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/dialog": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/@react-aria/dialog/-/dialog-3.6.1.tgz", + "integrity": "sha512-Eo3Kj23TjENuERUYrGkH+VN1PJvK8/zep76pfwBg29erUVDpGdfagYRq82aGcxJ/ohG8iRxZDwp2tTrU1RG1MQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/focus": { + "version": "3.22.1", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.22.1.tgz", + "integrity": "sha512-CPxtkyrBi/HYY5P3lE/57sQ6qfa0lN8E55TOm89H0kNGv0lKt+/0zP7lWERzBjRr5IxBVrQX4gFEowBN52LPaA==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/form": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@react-aria/form/-/form-3.2.1.tgz", + "integrity": "sha512-uSNi8/lSFTMPGHzCeAPmFVQ8h8rRulInSVdstRL3hFmyjEOd2gGeKHwssCcLHmujy3T+K/AGeOQiKFpz2hjZEw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/grid": { + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/@react-aria/grid/-/grid-3.15.1.tgz", + "integrity": "sha512-u/903msISq7V78lAJ1Nt4bElMTh6Pzp/bS+lFv79POkFeHWv4icb42egRI7D9YYjO1tYWmNHC5iTcxzvcnOWxQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/i18n": { + "version": "3.12.16", + "resolved": "https://registry.npmjs.org/@react-aria/i18n/-/i18n-3.12.16.tgz", + "integrity": "sha512-Km2CAz6MFQOUEaattaW+2jBdWOHUF8WX7VQoNbjlqElCP58nSaqi9yxTWUDRhAcn8/xFUnkFh4MFweNgtrHuEA==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.0", + "@internationalized/message": "^3.1.8", + "@internationalized/number": "^3.6.5", + "@internationalized/string": "^3.2.7", + "@react-aria/ssr": "^3.9.10", + "@react-aria/utils": "^3.33.1", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/interactions": { + "version": "3.28.1", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.28.1.tgz", + "integrity": "sha512-Bqb+HrD5I5MHS2SKBhISYqo2SW8Y2dfzgF/Y1lIJq7xqLxheo9vzxPGEHhz+XzkgGfoqEJx8A6a3C7uiqS3HWA==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.34.0", + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/interactions/node_modules/@react-types/shared": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.36.1.tgz", + "integrity": "sha512-AzsuD9OfxTOZMMvTRhlN3oHBwOmFN7tDh27LzqmHt4+uOgPhJT7ZM7/kVs/8/o0WxayMUIk3hBmCFRHv1FUoag==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/label": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/@react-aria/label/-/label-3.8.1.tgz", + "integrity": "sha512-zf6hG22PnxZ9kEUwxORClBicHK5pcvucDU+lotGsI6ENbdIvJAMNn9X0oiPPae56CVf2T0KEL9NB8LKdAfzCIw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/landmark": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@react-aria/landmark/-/landmark-3.1.1.tgz", + "integrity": "sha512-Njn/UVrCb2BPW1CPLHA1vrH51+ug62xLMNGUu2qtYj1rAxkLG1m3151hewgcxYtpmPxYlnRtOAmSuu/oD5YTFA==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/link": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@react-aria/link/-/link-3.9.1.tgz", + "integrity": "sha512-lup+i3TVgVjRJOt6kpngZfP+3bmeABqcDRhEaE+7xg7DRpbeiccNYVMtKySiFTZePwP3fcbCyTGxZe6DY4CLmA==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/listbox": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/@react-aria/listbox/-/listbox-3.16.1.tgz", + "integrity": "sha512-FbNeUXmo/H2Qp+yKboNod1eVhfmQDv1YexzEIAHsKL5Cx8uA7wZID9Pbq28jPC4plPISgS5KLBodaDikOXqviA==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/live-announcer": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@react-aria/live-announcer/-/live-announcer-3.5.1.tgz", + "integrity": "sha512-kLvwHjM3D7KgdquiAhUpRnMLKFrvl2r8naDXqPUlSWGRG15wsJRLhQOHLxGp0Umyg7KcSA+OD1mhQV5aRv0P1w==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/menu": { + "version": "3.22.1", + "resolved": "https://registry.npmjs.org/@react-aria/menu/-/menu-3.22.1.tgz", + "integrity": "sha512-ASP2u11+jg4OQh+QaDlWb7upMgsMITBQTjPFPbUJp6eE4q/cddLPYf4/9yfxh/bwTg0iDdzoDrgdtbwNGYNSfg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/numberfield": { + "version": "3.12.5", + "resolved": "https://registry.npmjs.org/@react-aria/numberfield/-/numberfield-3.12.5.tgz", + "integrity": "sha512-Fi41IUWXEHLFIeJ/LHuZ9Azs8J/P563fZi37GSBkIq5P1pNt1rPgJJng5CNn4KsHxwqadTRUlbbZwbZraWDtRg==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/i18n": "^3.12.16", + "@react-aria/interactions": "^3.27.1", + "@react-aria/live-announcer": "^3.4.4", + "@react-aria/spinbutton": "^3.7.2", + "@react-aria/textfield": "^3.18.5", + "@react-aria/utils": "^3.33.1", + "@react-stately/form": "^3.2.4", + "@react-stately/numberfield": "^3.11.0", + "@react-types/button": "^3.15.1", + "@react-types/numberfield": "^3.8.18", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/overlays": { + "version": "3.31.2", + "resolved": "https://registry.npmjs.org/@react-aria/overlays/-/overlays-3.31.2.tgz", + "integrity": "sha512-78HYI08r6LvcfD34gyv19ArRIjy1qxOKuXl/jYnjLDyQzD4pVb634IQWcm0zt10RdKgyuH6HTqvuDOgZTLet7Q==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.21.5", + "@react-aria/i18n": "^3.12.16", + "@react-aria/interactions": "^3.27.1", + "@react-aria/ssr": "^3.9.10", + "@react-aria/utils": "^3.33.1", + "@react-aria/visually-hidden": "^3.8.31", + "@react-stately/flags": "^3.1.2", + "@react-stately/overlays": "^3.6.23", + "@react-types/button": "^3.15.1", + "@react-types/overlays": "^3.9.4", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/progress": { + "version": "3.4.30", + "resolved": "https://registry.npmjs.org/@react-aria/progress/-/progress-3.4.30.tgz", + "integrity": "sha512-S6OWVGgluSWYSd/A6O8CVjz83eeMUfkuWSra0ewAV9bmxZ7TP9pUmD3bGdqHZEl97nt5vHGjZ3eq/x8eCmzKhA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/i18n": "^3.12.16", + "@react-aria/label": "^3.7.25", + "@react-aria/utils": "^3.33.1", + "@react-types/progress": "^3.5.18", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/radio": { + "version": "3.12.5", + "resolved": "https://registry.npmjs.org/@react-aria/radio/-/radio-3.12.5.tgz", + "integrity": "sha512-8CCJKJzfozEiWBPO9QAATG1rBGJEJ+xoqvHf9LKU2sPFGsA2/SRnLs6LB9fCG5R3spvaK1xz0any1fjWPl7x8A==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.21.5", + "@react-aria/form": "^3.1.5", + "@react-aria/i18n": "^3.12.16", + "@react-aria/interactions": "^3.27.1", + "@react-aria/label": "^3.7.25", + "@react-aria/utils": "^3.33.1", + "@react-stately/radio": "^3.11.5", + "@react-types/radio": "^3.9.4", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/selection": { + "version": "3.28.1", + "resolved": "https://registry.npmjs.org/@react-aria/selection/-/selection-3.28.1.tgz", + "integrity": "sha512-gGa9HkRnWsKxRhrtVASvecNyetMtP9fNF/Vcsy9Z+6NigjGUSN4SU0bhfglZ706B4t/NSMoVhcBJXlyFiG0hQw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/slider": { + "version": "3.8.5", + "resolved": "https://registry.npmjs.org/@react-aria/slider/-/slider-3.8.5.tgz", + "integrity": "sha512-gqkJxznk141mE0JamXF5CXml9PDbPkBz8dyKlihtWHWX4yhEbVYdC9J0otE7iCR3zx69Bm7WHoTGL0BsdpKzVA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/i18n": "^3.12.16", + "@react-aria/interactions": "^3.27.1", + "@react-aria/label": "^3.7.25", + "@react-aria/utils": "^3.33.1", + "@react-stately/slider": "^3.7.5", + "@react-types/shared": "^3.33.1", + "@react-types/slider": "^3.8.4", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/spinbutton": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/@react-aria/spinbutton/-/spinbutton-3.8.1.tgz", + "integrity": "sha512-mDed6rDI2JE3QCaX+QykRyw9GjiRAHY1+RqxX2DR0yEtW2n9GxTQfCR9KVnXm69eTgCoxDIa7okBCrHhYB8bUw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.10.1.tgz", + "integrity": "sha512-jn038/ZYmu6DpfXJ6r2U9zFFppjbc9wnApPJSCxao2RZVEqep4YyoniHSy8qv6V21/xyS4IV7W9a+X2jOjSuag==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/switch": { + "version": "3.7.11", + "resolved": "https://registry.npmjs.org/@react-aria/switch/-/switch-3.7.11.tgz", + "integrity": "sha512-dYVX71HiepBsKyeMaQgHbhqI+MQ3MVoTd5EnTbUjefIBnmQZavYj1/e4NUiUI4Ix+/C0HxL8ibDAv4NlSW3eLQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/toggle": "^3.12.5", + "@react-stately/toggle": "^3.9.5", + "@react-types/shared": "^3.33.1", + "@react-types/switch": "^3.5.17", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/table": { + "version": "3.17.11", + "resolved": "https://registry.npmjs.org/@react-aria/table/-/table-3.17.11.tgz", + "integrity": "sha512-GkYmWPiW3OM+FUZxdS33teHXHXde7TjHuYgDDaG9phvg6cQTQjGilJozrzA3OfftTOq5VB8XcKTIQW3c0tpYsQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.21.5", + "@react-aria/grid": "^3.14.8", + "@react-aria/i18n": "^3.12.16", + "@react-aria/interactions": "^3.27.1", + "@react-aria/live-announcer": "^3.4.4", + "@react-aria/utils": "^3.33.1", + "@react-aria/visually-hidden": "^3.8.31", + "@react-stately/collections": "^3.12.10", + "@react-stately/flags": "^3.1.2", + "@react-stately/table": "^3.15.4", + "@react-types/checkbox": "^3.10.4", + "@react-types/grid": "^3.3.8", + "@react-types/shared": "^3.33.1", + "@react-types/table": "^3.13.6", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/tabs": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@react-aria/tabs/-/tabs-3.11.1.tgz", + "integrity": "sha512-3Ppz7yaEDW9L7p9PE9yNOl5caLwNnnLQqI+MX/dwbWlw9HluHS7uIjb21oswNl6UbSxAWyENOka45+KN4Fkh7A==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.21.5", + "@react-aria/i18n": "^3.12.16", + "@react-aria/selection": "^3.27.2", + "@react-aria/utils": "^3.33.1", + "@react-stately/tabs": "^3.8.9", + "@react-types/shared": "^3.33.1", + "@react-types/tabs": "^3.3.22", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/textfield": { + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/@react-aria/textfield/-/textfield-3.19.1.tgz", + "integrity": "sha512-zYxQvOgN2CkvNvKchHEDu9UAOrwYzsaeUKVbrFcXJ2iIeZuZnEcNNJpp7WVCfV+9XeP+Jzjjnmjg9BH1H52ebg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/toast": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@react-aria/toast/-/toast-3.0.11.tgz", + "integrity": "sha512-2DjZjBAvm8/CWbnZ6s7LjkYCkULKtjMve6GvhPTq98AthuEDLEiBvM1wa3xdecCRhZyRT1g6DXqVca0EfZ9fJA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/i18n": "^3.12.16", + "@react-aria/interactions": "^3.27.1", + "@react-aria/landmark": "^3.0.10", + "@react-aria/utils": "^3.33.1", + "@react-stately/toast": "^3.1.3", + "@react-types/button": "^3.15.1", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/toggle": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/@react-aria/toggle/-/toggle-3.13.1.tgz", + "integrity": "sha512-1SPMBSrbT94Jsy7Wuv9SH2uPv7szGP7KgO4QGIAcF3e5kHwvGQJdMHY6+xR17slk8ICXfFojBqUKgpJjyY2+KQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/toolbar": { + "version": "3.0.0-beta.24", + "resolved": "https://registry.npmjs.org/@react-aria/toolbar/-/toolbar-3.0.0-beta.24.tgz", + "integrity": "sha512-B2Rmpko7Ghi2RbNfsGdbR7I+RQBDhPGVE4bU3/EwHz+P/vNe5LyGPTeSwqaOMsQTF9lKNCkY8424dVTCr6RUMg==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/focus": "^3.21.5", + "@react-aria/i18n": "^3.12.16", + "@react-aria/utils": "^3.33.1", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/tooltip": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@react-aria/tooltip/-/tooltip-3.9.2.tgz", + "integrity": "sha512-VrgkPwHiEnAnBhoQ4W7kfry/RfVuRWrUPaJSp0+wKM6u0gg2tmn7OFRDXTxBAm/omQUguIdIjRWg7sf3zHH82A==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.1", + "@react-aria/utils": "^3.33.1", + "@react-stately/tooltip": "^3.5.11", + "@react-types/shared": "^3.33.1", + "@react-types/tooltip": "^3.5.2", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/utils": { + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.33.1.tgz", + "integrity": "sha512-kIx1Sj6bbAT0pdqCegHuPanR9zrLn5zMRiM7LN12rgRf55S19ptd9g3ncahArifYTRkfEU9VIn+q0HjfMqS9/w==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.10", + "@react-stately/flags": "^3.1.2", + "@react-stately/utils": "^3.11.0", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/visually-hidden": { + "version": "3.8.31", + "resolved": "https://registry.npmjs.org/@react-aria/visually-hidden/-/visually-hidden-3.8.31.tgz", + "integrity": "sha512-RTOHHa4n56a9A3criThqFHBifvZoV71+MCkSuNP2cKO662SUWjqKkd0tJt/mBRMEJPkys8K7Eirp6T8Wt5FFRA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.27.1", + "@react-aria/utils": "^3.33.1", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-spectrum/button": { + "version": "3.18.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/button/-/button-3.18.1.tgz", + "integrity": "sha512-FW+1d6zfKesMLaBrsRsnnYnsLfvf2qFKuatkCo62o1oGUBtEYI/kae+lwGwlfiX5q9P5OgR2y1IqKtxabf/JKQ==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum": "^3.47.0", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-spectrum/dialog": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/dialog/-/dialog-3.10.1.tgz", + "integrity": "sha512-RMoZkKswUMFiEnAHZljEV1ybpMUjrS5RxkwWb3IFMo+ZtnLIeIT87k4DxoUJKOVrw3bnSsLRSTw1Fvf7jZ/eFw==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum": "^3.47.0", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-spectrum/listbox": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/listbox/-/listbox-3.16.1.tgz", + "integrity": "sha512-iQ7eym1zVR3wmOpOnmbKF0A+cbdzUGobZdNC/H9rdiyGkEE0OIrlk3z3APIFHfM/juK/LHXZ+srbF5LU8/sDCg==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum": "^3.47.0", + "@swc/helpers": "^0.5.0", + "react-stately": "^3.46.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-spectrum/overlays": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/overlays/-/overlays-5.10.1.tgz", + "integrity": "sha512-VSpplRbzYA/Hmg+fR7fonj/Q3jq7mJHD6A5f189teX5/uRiTk7P4DogBYfU1a70BAq3xBEA4hV3QpA8i9pK8jQ==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum": "^3.47.0", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-spectrum/slider": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/slider/-/slider-3.9.1.tgz", + "integrity": "sha512-UMBZaaofQsAfH+2SPh2GyxlJjKmRkjVoY1ixybkz8Jh+pOPOFEMugAt3fuLMW22geOC5PXs6AxHYsNb0BwKVnQ==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum": "^3.47.0", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-spectrum/switch": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/switch/-/switch-3.7.1.tgz", + "integrity": "sha512-71rSqseVrieCWxQpwCBbqY4F6bBo8IK/jM+r8ounN/WIkoMGhZkVigF8tSwd+/p8ym2tmJq6MoWn0he1taBo0Q==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum": "^3.47.0", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-spectrum/tabs": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/tabs/-/tabs-3.9.1.tgz", + "integrity": "sha512-1r/NiHeyjcHP1CZ7a30PSS5NesARSV1z9fuiKO+rianq/Xyy5bUW5cU+pSNTghNhRCUhQACopkktGzmTCTCCXQ==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum": "^3.47.0", + "@swc/helpers": "^0.5.0", + "react-stately": "^3.46.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/calendar": { + "version": "3.9.3", + "resolved": "https://registry.npmjs.org/@react-stately/calendar/-/calendar-3.9.3.tgz", + "integrity": "sha512-uw7fCZXoypSBBUsVkbNvJMQWTihZReRbyLIGG3o/ZM630N3OCZhb/h4Uxke4pNu7n527H0V1bAnZgAldIzOYqg==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.0", + "@react-stately/utils": "^3.11.0", + "@react-types/calendar": "^3.8.3", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/checkbox": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/@react-stately/checkbox/-/checkbox-3.7.5.tgz", + "integrity": "sha512-K5R5ted7AxLB3sDkuVAazUdyRMraFT1imVqij2GuAiOUFvsZvbuocnDuFkBVKojyV3GpqLBvViV8IaCMc4hNIw==", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/form": "^3.2.4", + "@react-stately/utils": "^3.11.0", + "@react-types/checkbox": "^3.10.4", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/collections": { + "version": "3.12.10", + "resolved": "https://registry.npmjs.org/@react-stately/collections/-/collections-3.12.10.tgz", + "integrity": "sha512-wmF9VxJDyBujBuQ76vXj2g/+bnnj8fx5DdXgRmyfkkYhPB46+g2qnjbVGEvipo7bJuGxDftCUC4SN7l7xqUWfg==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/combobox": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@react-stately/combobox/-/combobox-3.13.0.tgz", + "integrity": "sha512-dX9g/cK1hjLRjcbWVF6keHxTQDGhKGB2QAgPhWcBmOK3qJv+2dQqsJ6YCGWn/Y2N2acoEseLrAA7+Qe4HWV9cg==", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/collections": "^3.12.10", + "@react-stately/form": "^3.2.4", + "@react-stately/list": "^3.13.4", + "@react-stately/overlays": "^3.6.23", + "@react-stately/utils": "^3.11.0", + "@react-types/combobox": "^3.14.0", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/combobox/node_modules/@react-stately/list": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/@react-stately/list/-/list-3.14.1.tgz", + "integrity": "sha512-3W+GqsDqKih7gqVRzA85P2CtGcahETLzC+NM9zhgz+T0xeHQITc7N2oEAT1Vy+cIKGd1YmfGM8ACgtpcbcnWWA==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-stately": "^3.46.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/datepicker": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/@react-stately/datepicker/-/datepicker-3.16.1.tgz", + "integrity": "sha512-BtAMDvxd1OZxkxjqq5tN5TYmp6Hm8+o3+IDA4qmem2/pfQfVbOZeWS2WitcPBImj4n4T+W1A5+PI7mT/6DUBVg==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.0", + "@internationalized/number": "^3.6.5", + "@internationalized/string": "^3.2.7", + "@react-stately/form": "^3.2.4", + "@react-stately/overlays": "^3.6.23", + "@react-stately/utils": "^3.11.0", + "@react-types/datepicker": "^3.13.5", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/flags": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@react-stately/flags/-/flags-3.2.1.tgz", + "integrity": "sha512-WPw9z4SPYqQMuExCnBNrQyyxCWSi9CDYnVqca19bqxaHZRT/uL5nL+IGCPHHa70Y5rx39E5hYKl8Hf0QJ6XKyA==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-stately": "^3.46.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/form": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@react-stately/form/-/form-3.2.4.tgz", + "integrity": "sha512-qNBzun8SbLdgahryhKLqL1eqP+MXY6as82sVXYOOvUYLzgU5uuN8mObxYlxJgMI5akSdQJQV3RzyfVobPRE7Kw==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/list": { + "version": "3.13.4", + "resolved": "https://registry.npmjs.org/@react-stately/list/-/list-3.13.4.tgz", + "integrity": "sha512-HHYSjA9VG7FPSAtpXAjQyM/V7qFHWGg88WmMrDt5QDlTBexwPuH0oFLnW0qaVZpAIxuWIsutZfxRAnme/NhhAA==", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/collections": "^3.12.10", + "@react-stately/selection": "^3.20.9", + "@react-stately/utils": "^3.11.0", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/menu": { + "version": "3.9.11", + "resolved": "https://registry.npmjs.org/@react-stately/menu/-/menu-3.9.11.tgz", + "integrity": "sha512-vYkpO9uV2OUecsIkrOc+Urdl/s1xw/ibNH/UXsp4PtjMnS6mK9q2kXZTM3WvMAKoh12iveUO+YkYCZQshmFLHQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/overlays": "^3.6.23", + "@react-types/menu": "^3.10.7", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/numberfield": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@react-stately/numberfield/-/numberfield-3.11.0.tgz", + "integrity": "sha512-rxfC047vL0LP4tanjinfjKAriAvdVL57Um5RUL5nHML8IOWCB3TBxegQkJ6to6goScC/oZhd0/Y2LSaiRuKbNw==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/number": "^3.6.5", + "@react-stately/form": "^3.2.4", + "@react-stately/utils": "^3.11.0", + "@react-types/numberfield": "^3.8.18", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/overlays": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@react-stately/overlays/-/overlays-3.7.1.tgz", + "integrity": "sha512-vGw9f8i5kPvaQqvvQ8iIhPhJZorwtg2rXycqnUNXkNLadewh1S0ocbnRvrb4HW/GGC37rFmGcG1fYCHA/WIn6w==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-stately": "^3.46.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/radio": { + "version": "3.11.5", + "resolved": "https://registry.npmjs.org/@react-stately/radio/-/radio-3.11.5.tgz", + "integrity": "sha512-QxA779S4ea5icQ0ja7CeiNzY1cj7c9G9TN0m7maAIGiTSinZl2Ia8naZJ0XcbRRp+LBll7RFEdekne15TjvS/w==", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/form": "^3.2.4", + "@react-stately/utils": "^3.11.0", + "@react-types/radio": "^3.9.4", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/selection": { + "version": "3.21.1", + "resolved": "https://registry.npmjs.org/@react-stately/selection/-/selection-3.21.1.tgz", + "integrity": "sha512-Tq8UfAOG5SCxnTYivyYQH5NRpiuEJG2k20wmJ/s4Db0FnnjYg1xbKe55vu2A9ni/nUTLKUMj7MFaJytMIXPwxg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-stately": "^3.46.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/slider": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/@react-stately/slider/-/slider-3.7.5.tgz", + "integrity": "sha512-OrQMNR5xamLYH52TXtvTgyw3EMwv+JI+1istQgEj1CHBjC9eZZqn5iNCN20tzm+uDPTH0EIGULFjjPIumqYUQg==", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/utils": "^3.11.0", + "@react-types/shared": "^3.33.1", + "@react-types/slider": "^3.8.4", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/table": { + "version": "3.15.4", + "resolved": "https://registry.npmjs.org/@react-stately/table/-/table-3.15.4.tgz", + "integrity": "sha512-fGaNyw3wv7JgRCNzgyDzpaaTFuSy5f4Qekch4UheMXDJX7dOeaMhUXeOfvnXCVg+BGM4ey/D82RvDOGvPy1Nww==", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/collections": "^3.12.10", + "@react-stately/flags": "^3.1.2", + "@react-stately/grid": "^3.11.9", + "@react-stately/selection": "^3.20.9", + "@react-stately/utils": "^3.11.0", + "@react-types/grid": "^3.3.8", + "@react-types/shared": "^3.33.1", + "@react-types/table": "^3.13.6", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/table/node_modules/@react-stately/grid": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@react-stately/grid/-/grid-3.12.1.tgz", + "integrity": "sha512-GvOXlPtzoswhyV3bZK3habHdHBGR7qdzOy2WumYiNG7DAj8J+9WvAObrPmquuI2VrZYMSNzgFb3IoL+sQsMI8A==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-stately": "^3.46.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/tabs": { + "version": "3.8.9", + "resolved": "https://registry.npmjs.org/@react-stately/tabs/-/tabs-3.8.9.tgz", + "integrity": "sha512-AQ4Xrn6YzIolaVShCV9cnwOjBKPAOGP/PTp7wpSEtQbQ0HZzUDG2RG/M4baMeUB2jZ33b7ifXyPcK78o0uOftg==", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/list": "^3.13.4", + "@react-types/shared": "^3.33.1", + "@react-types/tabs": "^3.3.22", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/toast": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@react-stately/toast/-/toast-3.1.3.tgz", + "integrity": "sha512-mT9QJKmD523lqFpOp0VWZ6QHZENFK7HrodnNJDVc7g616s5GNmemdlkITV43fSY3tHeThCVvPu+Uzh7RvQ9mpQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/toggle": { + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/@react-stately/toggle/-/toggle-3.9.5.tgz", + "integrity": "sha512-PVzXc788q3jH98Kvw1LYDL+wpVC14dCEKjOku8cSaqhEof6AJGaLR9yq+EF1yYSL2dxI6z8ghc0OozY8WrcFcA==", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/utils": "^3.11.0", + "@react-types/checkbox": "^3.10.4", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/tooltip": { + "version": "3.5.11", + "resolved": "https://registry.npmjs.org/@react-stately/tooltip/-/tooltip-3.5.11.tgz", + "integrity": "sha512-o8PnFXbvDCuVZ4Ht9ahfS6KHwIZjXopvoQ2vUPxv920irdgWEeC+4omgDOnJ/xFvcpmmJAmSsrQsTQrTguDUQA==", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/overlays": "^3.6.23", + "@react-types/tooltip": "^3.5.2", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/tree": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/@react-stately/tree/-/tree-3.9.6.tgz", + "integrity": "sha512-JCuhGyX2A+PAMsx2pRSwArfqNFZJ9JSPkDaOQJS8MFPAsBe5HemvXsdmv9aBIMzlbCYcVq6EsrFnzbVVTBt/6w==", + "license": "Apache-2.0", + "dependencies": { + "@react-stately/collections": "^3.12.10", + "@react-stately/selection": "^3.20.9", + "@react-stately/utils": "^3.11.0", + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/utils": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.12.1.tgz", + "integrity": "sha512-NqKfzrknpfwiewx7R2vk1P+CneClInPDsIhw15+jOcUYSEfej0nta4cJywuKQJ2gsPwqX/ojDNixedCve9FWGw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-stately": "^3.46.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/virtualizer": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/@react-stately/virtualizer/-/virtualizer-4.4.6.tgz", + "integrity": "sha512-9SfXgLFB61/8SXNLfg5ARx9jAK4m03Aw6/Cg8mdZN24SYarL4TKNRpfw8K/HHVU/bi6WHSJypk6Z/z19o/ztrg==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/accordion": { + "version": "3.0.0-alpha.26", + "resolved": "https://registry.npmjs.org/@react-types/accordion/-/accordion-3.0.0-alpha.26.tgz", + "integrity": "sha512-OXf/kXcD2vFlEnkcZy/GG+a/1xO9BN7Uh3/5/Ceuj9z2E/WwD55YwU3GFM5zzkZ4+DMkdowHnZX37XnmbyD3Mg==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.27.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/breadcrumbs": { + "version": "3.7.19", + "resolved": "https://registry.npmjs.org/@react-types/breadcrumbs/-/breadcrumbs-3.7.19.tgz", + "integrity": "sha512-AnkyYYmzaM2QFi/N0P/kQLM8tHOyFi7p397B/jEMucXDfwMw5Ny1ObCXeIEqbh8KrIa2Xp8SxmQlCV+8FPs4LA==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/link": "^3.6.7", + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/breadcrumbs/node_modules/@react-types/link": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@react-types/link/-/link-3.7.0.tgz", + "integrity": "sha512-otEY/XdycY/uz+Ble2vS/VTsU4Myp8bhJtKT17r1R7bYWV3g5ZOVBCH4JvbQHJAkHaqMf9We7uIipkCw42UOeA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/link": "^3.9.0", + "@react-spectrum/link": "^3.7.0" + }, + "peerDependencies": { + "@react-spectrum/provider": "^3.0.0", + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/breadcrumbs/node_modules/@react-types/link/node_modules/@react-spectrum/link": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@react-spectrum/link/-/link-3.7.1.tgz", + "integrity": "sha512-sGBrdtrHoEdYv2WGi1MXz4bRVxnspeA02qfIjytOY+vaStqW8tMW21PNw62JbwugaD4SMyoIScEzDuPoxGUW8Q==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum": "^3.47.0", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/button": { + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/@react-types/button/-/button-3.16.0.tgz", + "integrity": "sha512-Z5///n2Y1jtF0gokBq2Y1K1cpOwsWZ24HPeAm3eEmZrbBXMrxC2oEA5ZThsSHuIGsqiyNJiQ2scsDftmr+PkZw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/button": "^3.15.0", + "@react-spectrum/button": "^3.18.0" + }, + "peerDependencies": { + "@react-spectrum/provider": "^3.0.0", + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/calendar": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/@react-types/calendar/-/calendar-3.8.3.tgz", + "integrity": "sha512-fpH6WNXotzH0TlKHXXxtjeLZ7ko0sbyHmwDAwmDFyP7T0Iwn1YQZ+lhceLifvynlxuOgX6oBItyUKmkHQ0FouQ==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.0", + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/checkbox": { + "version": "3.10.4", + "resolved": "https://registry.npmjs.org/@react-types/checkbox/-/checkbox-3.10.4.tgz", + "integrity": "sha512-tYCG0Pd1usEz5hjvBEYcqcA0youx930Rss1QBIse9TgMekA1c2WmPDNupYV8phpO8Zuej3DL1WfBeXcgavK8aw==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/combobox": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/@react-types/combobox/-/combobox-3.14.0.tgz", + "integrity": "sha512-zmSSS7BcCOD8rGT8eGbVy7UlL5qq1vm88fFn4WgFe+lfK33ne+E7yTzTxcPY2TCGSo5fY6xMj3OG79FfVNGbSg==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/datepicker": { + "version": "3.13.5", + "resolved": "https://registry.npmjs.org/@react-types/datepicker/-/datepicker-3.13.5.tgz", + "integrity": "sha512-j28Vz+xvbb4bj7+9Xbpc4WTvSitlBvt7YEaEGM/8ZQ5g4Jr85H2KwkmDwjzmMN2r6VMQMMYq9JEcemq5wWpfUQ==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.0", + "@react-types/calendar": "^3.8.3", + "@react-types/overlays": "^3.9.4", + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/dialog": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@react-types/dialog/-/dialog-3.6.0.tgz", + "integrity": "sha512-vvxohmsTRZWE/saaJt6mMy3ONA4xbQTSk1okfMUK6OMSp/VpLBRLCz/2/myiMK3UIBCagUnrwzOwbk9whnFx0g==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/dialog": "^3.6.0", + "@react-spectrum/dialog": "^3.10.0" + }, + "peerDependencies": { + "@react-spectrum/provider": "^3.0.0", + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/form": { + "version": "3.7.18", + "resolved": "https://registry.npmjs.org/@react-types/form/-/form-3.7.18.tgz", + "integrity": "sha512-0sBJW0+I9nJcF4SmKrYFEWAlehiebSTy7xqriqAXtqfTEdvzAYLGaAK2/7gx+wlNZeDTdW43CDRJ4XAhyhBqnw==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/grid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/@react-types/grid/-/grid-3.3.8.tgz", + "integrity": "sha512-zJvXH8gc1e1VH2H3LRnHH/W2HIkLkZMH3Cu5pLcj0vDuLBSWpcr3Ikh3jZ+VUOZF0G1Jt1lO8pKIaqFzDLNmLQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/link": { + "version": "3.6.7", + "resolved": "https://registry.npmjs.org/@react-types/link/-/link-3.6.7.tgz", + "integrity": "sha512-1apXCFJgMC1uydc2KNENrps1qR642FqDpwlNWe254UTpRZn/hEZhA6ImVr8WhomfLJu672WyWA0rUOv4HT+/pQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/listbox": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/@react-types/listbox/-/listbox-3.8.0.tgz", + "integrity": "sha512-6l/P1mYQUQ7hGW6x8cH/EB8YvRzhhoB536G/GI7t2F2FbjcGkA1kNXhzDo24tLTXi9elnehevEEySRsRa9p6VA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/listbox": "^3.16.0", + "@react-spectrum/listbox": "^3.16.0" + }, + "peerDependencies": { + "@react-spectrum/provider": "^3.0.0", + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/menu": { + "version": "3.10.7", + "resolved": "https://registry.npmjs.org/@react-types/menu/-/menu-3.10.7.tgz", + "integrity": "sha512-+p7ixZdvPDJZhisqdtWiiuJ9pteNfK5i19NB6wzAw5XkljbEzodNhwLv6rI96DY5XpbFso2kcjw7IWi+rAAGGQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/overlays": "^3.9.4", + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/numberfield": { + "version": "3.8.18", + "resolved": "https://registry.npmjs.org/@react-types/numberfield/-/numberfield-3.8.18.tgz", + "integrity": "sha512-nLzk7YAG9yAUtSv+9R8LgCHsu8hJq8/A+m1KsKxvc8WmNJjIujSFgWvT21MWBiUgPBzJKGzAqpMDDa087mltJQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/overlays": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@react-types/overlays/-/overlays-3.10.0.tgz", + "integrity": "sha512-cgrcOTxy6ac0kiphQOkc8mj5artZMB/XVrFgukRZ2FcbYNEERpg2VQ5ztd0+H1ER7O0kx7AmwHxdut+x1EAjrw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/overlays": "^3.32.0", + "@react-spectrum/overlays": "^5.10.0", + "@react-stately/overlays": "^3.7.0", + "@react-types/shared": "^3.34.0" + }, + "peerDependencies": { + "@react-spectrum/provider": "^3.0.0", + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/overlays/node_modules/@react-aria/overlays": { + "version": "3.32.1", + "resolved": "https://registry.npmjs.org/@react-aria/overlays/-/overlays-3.32.1.tgz", + "integrity": "sha512-jjVLcEK5qaGsz3SmW+eLV3QFiJzdDFzgNofPwvzBS1KTPox0a2x5u1ITUPmHwyUNiyexy531h5eVjN3tULEzHQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/overlays/node_modules/@react-types/shared": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.36.1.tgz", + "integrity": "sha512-AzsuD9OfxTOZMMvTRhlN3oHBwOmFN7tDh27LzqmHt4+uOgPhJT7ZM7/kVs/8/o0WxayMUIk3hBmCFRHv1FUoag==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/progress": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@react-types/progress/-/progress-3.5.18.tgz", + "integrity": "sha512-mKeQn+KrHr1y0/k7KtrbeDGDaERH6i4f6yBwj/ZtYDCTNKMO3tPHJY6nzF0w/KKZLplIO+BjUbHXc2RVm8ovwQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/radio": { + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/@react-types/radio/-/radio-3.9.4.tgz", + "integrity": "sha512-TkMRY3sA1PcFZhhclu4IUzUTIir6MzNJj8h6WT8vO6Nug2kXJ72qigugVFBWJSE472mltduOErEAo0rtAYWbQA==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/shared": { + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.33.1.tgz", + "integrity": "sha512-oJHtjvLG43VjwemQDadlR5g/8VepK56B/xKO2XORPHt9zlW6IZs3tZrYlvH29BMvoqC7RtE7E5UjgbnbFtDGag==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/slider": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@react-types/slider/-/slider-3.9.0.tgz", + "integrity": "sha512-gbQWB8LnucC+jhDi5Imd2ZDPbVuiHt0xzObGHWq6GTZ3slLgTvGQaHNO5h9+h7dZH0iFQOVNb6+TlyTsnjFuAw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/slider": "^3.9.0", + "@react-spectrum/slider": "^3.9.0", + "@react-stately/slider": "^3.8.0" + }, + "peerDependencies": { + "@react-spectrum/provider": "^3.0.0", + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/slider/node_modules/@react-aria/slider": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@react-aria/slider/-/slider-3.9.1.tgz", + "integrity": "sha512-bFWhyM6mP9TzAjCpOKybS7x0RTsFa2+49XKytKN53xS7bdHEnWGbWpsdJ09qZ6z1fnrwFcq/j/hhj/0gVO8kdQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.34.0", + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/slider/node_modules/@react-stately/slider": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/@react-stately/slider/-/slider-3.8.1.tgz", + "integrity": "sha512-MSfiRJakgdp2FSPtDeViEgXbYjRBGXXSTvExUvDDZx2xiEmSgefEQ4WWwCWPN4tdWbRISZoCYrmG8mY04Gevpw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-stately": "^3.46.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/slider/node_modules/@react-types/shared": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.36.1.tgz", + "integrity": "sha512-AzsuD9OfxTOZMMvTRhlN3oHBwOmFN7tDh27LzqmHt4+uOgPhJT7ZM7/kVs/8/o0WxayMUIk3hBmCFRHv1FUoag==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/switch": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@react-types/switch/-/switch-3.6.0.tgz", + "integrity": "sha512-6pjDO5a35ovAAw5xsSJoftmUP1BhFzKazB5IuVBNTbeEvJjz/LC1NGkVV3sQX68ZDSZ0UyYLS7ENIVHKU+hjzA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/switch": "^3.8.0", + "@react-spectrum/switch": "^3.7.0" + }, + "peerDependencies": { + "@react-spectrum/provider": "^3.0.0", + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/switch/node_modules/@react-aria/switch": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/@react-aria/switch/-/switch-3.8.1.tgz", + "integrity": "sha512-WzkJG3xJnBdd9rdBxG+0RgWdopAqwI61Ni4ZQtA2rgFuG9UpZIrhsL7qgFO/+R6oEgoeGAMeUlvCf97Ppj2uTg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/table": { + "version": "3.13.6", + "resolved": "https://registry.npmjs.org/@react-types/table/-/table-3.13.6.tgz", + "integrity": "sha512-eluL+iFfnVmFm7OSZrrFG9AUjw+tcv898zbv+NsZACa8oXG1v9AimhZfd+Mo8q/5+sX/9hguWNXFkSvmTjuVPQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/grid": "^3.3.8", + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/tabs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@react-types/tabs/-/tabs-3.4.0.tgz", + "integrity": "sha512-/o2gmSKK9MmXCVL9vs+YYU1fl+u3+p07nbl2KXk0aL0UhVfgev3pKpFMjsWBiF9kUGp3EnVNjEDr8ZlSMIgZqQ==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/tabs": "^3.12.0", + "@react-spectrum/tabs": "^3.9.0", + "@react-stately/tabs": "^3.9.0" + }, + "peerDependencies": { + "@react-spectrum/provider": "^3.0.0", + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/tabs/node_modules/@react-aria/tabs": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/@react-aria/tabs/-/tabs-3.12.1.tgz", + "integrity": "sha512-fGMxbqSnqtn3GRiicLfnhWcnD6Auch0qCyt5ArfndYrISmSZkzq7PVZtDj85TEqC6p8WSw/M7HjWBBUX5/Of0g==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.34.0", + "@swc/helpers": "^0.5.0", + "react-aria": "^3.48.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/tabs/node_modules/@react-stately/tabs": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@react-stately/tabs/-/tabs-3.9.1.tgz", + "integrity": "sha512-xS9ByN7OMqvU9wyZJ8MnDvRTdsmB+GUP1whlRh4NmxWGmL4SDXKd4slSUGfb2lRi8lgT0OCAjd9om80HJP0p3w==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0", + "react-stately": "^3.46.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/tabs/node_modules/@react-types/shared": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.36.1.tgz", + "integrity": "sha512-AzsuD9OfxTOZMMvTRhlN3oHBwOmFN7tDh27LzqmHt4+uOgPhJT7ZM7/kVs/8/o0WxayMUIk3hBmCFRHv1FUoag==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/textfield": { + "version": "3.12.8", + "resolved": "https://registry.npmjs.org/@react-types/textfield/-/textfield-3.12.8.tgz", + "integrity": "sha512-wt6FcuE5AyntxsnPika/h3nf/DPmeAVbI018L9o6h+B/IL4sMWWdx663wx2KOOeHH8ejKGZQNPLhUKs4s1mVQA==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/tooltip": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@react-types/tooltip/-/tooltip-3.5.2.tgz", + "integrity": "sha512-FvSuZ2WP08NEWefrpCdBYpEEZh/5TvqvGjq0wqGzWg2OPwpc14HjD8aE7I3MOuylXkD4MSlMjl7J4DlvlcCs3Q==", + "license": "Apache-2.0", + "dependencies": { + "@react-types/overlays": "^3.9.4", + "@react-types/shared": "^3.33.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@remix-run/router": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.3.tgz", + "integrity": "sha512-4An71tdz9X8+3sI4Qqqd2LWd9vS39J7sqd9EU4Scw7TJE/qB10Flv/UuqbPVgfQV9XoK8Np6jNquZitnZq5i+Q==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.4.tgz", + "integrity": "sha512-RrPokAb7dmbxFoeO3TloqHyOjgye8RkBhSqmp4aJMIex4c9r46ZstPnleDQOq1t46VOVjwIuwNogIqbodV1Vvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.4.tgz", + "integrity": "sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.4.tgz", + "integrity": "sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.4.tgz", + "integrity": "sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.4.tgz", + "integrity": "sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.4.tgz", + "integrity": "sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.4.tgz", + "integrity": "sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.4.tgz", + "integrity": "sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.4.tgz", + "integrity": "sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.4.tgz", + "integrity": "sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.4.tgz", + "integrity": "sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.4.tgz", + "integrity": "sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.4.tgz", + "integrity": "sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.4.tgz", + "integrity": "sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.4.tgz", + "integrity": "sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.4.tgz", + "integrity": "sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.4.tgz", + "integrity": "sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.4.tgz", + "integrity": "sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.4.tgz", + "integrity": "sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.4.tgz", + "integrity": "sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.4.tgz", + "integrity": "sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.4.tgz", + "integrity": "sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.4.tgz", + "integrity": "sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.4.tgz", + "integrity": "sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.4.tgz", + "integrity": "sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@spectrum-icons/ui": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@spectrum-icons/ui/-/ui-3.7.1.tgz", + "integrity": "sha512-veQymocUYo5OciXQajSailOdbWe+k6+2ehfF8D4d0V923D4xOUadtT253xXZ5vEQjPat6Kyp2WDKeQNjd7kL1w==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum-ui": "1.2.1", + "@babel/runtime": "^7.24.4", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "@adobe/react-spectrum": "^3.47.0", + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@spectrum-icons/workflow": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@spectrum-icons/workflow/-/workflow-4.3.1.tgz", + "integrity": "sha512-kDF+/EbFVyLGytotqqdYt4uSij4j/PQmDQO5km/C6DyzKjyuic3FnSBFinR+mA6oFv1OjMcLvrrDBqK3wbqRlA==", + "license": "Apache-2.0", + "dependencies": { + "@adobe/react-spectrum-workflow": "2.3.5", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "@adobe/react-spectrum": "^3.47.0", + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tanstack/react-virtual": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.11.3.tgz", + "integrity": "sha512-vCU+OTylXN3hdC8RKg68tPlBPjjxtzon7Ys46MgrSLE+JhSjSTPvoQifV6DQJeJmA8Q3KT6CphJbejupx85vFw==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.11.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.11.3.tgz", + "integrity": "sha512-v2mrNSnMwnPJtcVqNvV0c5roGCBqeogN8jDtgtuHCphdwBasOZ17x8UV8qpHUh+u0MLfX43c0uUHKje0s+Zb0w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.31", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", + "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/autoprefixer": { + "version": "10.5.4", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.4.tgz", + "integrity": "sha512-MaU0U/za7N3r6brxD4YB/l4NSrFzLPlANv6wEuQVaIPlD3L4W9rFcQPbL/EilY9BHhHvhfcz3gInDLrEtWT4EA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.6", + "caniuse-lite": "^1.0.30001806", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.13", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.13.tgz", + "integrity": "sha512-k9HNuUVMlqVjQ9UHzfPjIqiDbWw7WqT1AoT7GL8VwvF3r0ZfArtgiSPAlmupyNquNgOJHTuH4CKYf8ttMTWBTQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz", + "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.12", + "caniuse-lite": "^1.0.30001809", + "electron-to-chromium": "^1.5.402", + "node-releases": "^2.0.53", + "update-browserslist-db": "^1.3.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001809", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz", + "integrity": "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color2k": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/color2k/-/color2k-2.0.4.tgz", + "integrity": "sha512-OXAPGFRNeLFnUfqDtloYdxkwsJoIdXe28+bjbpJiPqyei2HPa3VHmMCWa0Qe62+U4Ftf9Hj7hRssOkxz7WiWbg==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz", + "integrity": "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==", + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.404", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.404.tgz", + "integrity": "sha512-3WJtd7/lVq2Jnuz6wed1l9+1ZD2u2Tet1/1NBc4Iedkmgbu+I7YuAqdAQ8T+VZtnwysMsAf3IqSq9D1gyZjA2g==", + "dev": true, + "license": "ISC" + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/framer-motion": { + "version": "11.18.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz", + "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==", + "license": "MIT", + "dependencies": { + "motion-dom": "^11.18.1", + "motion-utils": "^11.18.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/input-otp": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.4.1.tgz", + "integrity": "sha512-+yvpmKYKHi9jIGngxagY9oWiiblPB7+nEO75F2l2o4vs+6vpPZZmUl4tBNYuTCvQjhvEIbdNeJu70bhfYP2nbw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/intl-messageformat": { + "version": "10.7.18", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.18.tgz", + "integrity": "sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g==", + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.6", + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/icu-messageformat-parser": "2.11.4", + "tslib": "^2.8.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", + "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/motion-dom": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", + "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==", + "license": "MIT", + "dependencies": { + "motion-utils": "^11.18.1" + } + }, + "node_modules/motion-utils": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz", + "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next-themes": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz", + "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc" + } + }, + "node_modules/node-releases": { + "version": "2.0.53", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz", + "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", + "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", + "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-aria": { + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/react-aria/-/react-aria-3.51.0.tgz", + "integrity": "sha512-AyWLw0XR38cFPwBu/ErgGaVrc5dupLEKmRlMXTGvFKOtbaGRQ2+yQJkjVhpdHhoRhU4+G+tJDFeHDTS8tK3bfQ==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.3", + "@internationalized/number": "^3.6.7", + "@internationalized/string": "^3.2.10", + "@react-types/shared": "^3.36.1", + "@swc/helpers": "^0.5.0", + "aria-hidden": "^1.2.3", + "clsx": "^2.0.0", + "react-stately": "3.49.0", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/react-aria-components": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/react-aria-components/-/react-aria-components-1.20.0.tgz", + "integrity": "sha512-BMbpIgoV9aELeBrB0Y120NgoigHb5OdcJwc+4e7uSnbTbamea6lo+gqcc4LAxzMaK3Jf+7LI1oCDE6yANsmxIQ==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.3", + "@internationalized/string": "^3.2.10", + "@react-types/shared": "^3.36.1", + "@swc/helpers": "^0.5.0", + "client-only": "^0.0.1", + "react-aria": "3.51.0", + "react-stately": "3.49.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/react-aria-components/node_modules/@react-types/shared": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.36.1.tgz", + "integrity": "sha512-AzsuD9OfxTOZMMvTRhlN3oHBwOmFN7tDh27LzqmHt4+uOgPhJT7ZM7/kVs/8/o0WxayMUIk3hBmCFRHv1FUoag==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/react-aria/node_modules/@react-types/shared": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.36.1.tgz", + "integrity": "sha512-AzsuD9OfxTOZMMvTRhlN3oHBwOmFN7tDh27LzqmHt4+uOgPhJT7ZM7/kVs/8/o0WxayMUIk3hBmCFRHv1FUoag==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.30.4", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.4.tgz", + "integrity": "sha512-SVUsDe+DybHM/WmYKIVYhZh1o5Dcuf16yM6WjG02Q9XVFMZIJyHYhwrr6bFBXZkVP6z69kNkMyBCujt8FaFLJA==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.4", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.4.tgz", + "integrity": "sha512-q4HvNl+mmDdkS0g+MqiBZNteQJCuimWoOyHMy4T/RQLAn9Z29+E91QXRaxOujeMl2HTzRSS0KFPd7lxX3PjV0Q==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.3", + "react-router": "6.30.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/react-stately": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/react-stately/-/react-stately-3.49.0.tgz", + "integrity": "sha512-13iNq2KzBrRAzxRc+n53hgROfIistiYY/sPtIhCw1qUB7/kmo+X1xEU2uiS5zcCIrc55AUPwoHqOIIpKWSwB9A==", + "license": "Apache-2.0", + "dependencies": { + "@internationalized/date": "^3.12.3", + "@internationalized/number": "^3.6.7", + "@internationalized/string": "^3.2.10", + "@react-types/shared": "^3.36.1", + "@swc/helpers": "^0.5.0", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/react-stately/node_modules/@react-types/shared": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.36.1.tgz", + "integrity": "sha512-AzsuD9OfxTOZMMvTRhlN3oHBwOmFN7tDh27LzqmHt4+uOgPhJT7ZM7/kVs/8/o0WxayMUIk3hBmCFRHv1FUoag==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/react-textarea-autosize": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.9.tgz", + "integrity": "sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.13", + "use-composed-ref": "^1.3.0", + "use-latest": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.62.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.4.tgz", + "integrity": "sha512-RXOqwaPsBGjMNMa4sQjDjHieHEZDFoj/Rdr46l2MU5DfEs16wHJPC2RPTPHWhNl+M3aI472LLqFkFKut4SblOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.62.4", + "@rollup/rollup-android-arm64": "4.62.4", + "@rollup/rollup-darwin-arm64": "4.62.4", + "@rollup/rollup-darwin-x64": "4.62.4", + "@rollup/rollup-freebsd-arm64": "4.62.4", + "@rollup/rollup-freebsd-x64": "4.62.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.4", + "@rollup/rollup-linux-arm-musleabihf": "4.62.4", + "@rollup/rollup-linux-arm64-gnu": "4.62.4", + "@rollup/rollup-linux-arm64-musl": "4.62.4", + "@rollup/rollup-linux-loong64-gnu": "4.62.4", + "@rollup/rollup-linux-loong64-musl": "4.62.4", + "@rollup/rollup-linux-ppc64-gnu": "4.62.4", + "@rollup/rollup-linux-ppc64-musl": "4.62.4", + "@rollup/rollup-linux-riscv64-gnu": "4.62.4", + "@rollup/rollup-linux-riscv64-musl": "4.62.4", + "@rollup/rollup-linux-s390x-gnu": "4.62.4", + "@rollup/rollup-linux-x64-gnu": "4.62.4", + "@rollup/rollup-linux-x64-musl": "4.62.4", + "@rollup/rollup-openbsd-x64": "4.62.4", + "@rollup/rollup-openharmony-arm64": "4.62.4", + "@rollup/rollup-win32-arm64-msvc": "4.62.4", + "@rollup/rollup-win32-ia32-msvc": "4.62.4", + "@rollup/rollup-win32-x64-gnu": "4.62.4", + "@rollup/rollup-win32-x64-msvc": "4.62.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/scroll-into-view-if-needed": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.0.10.tgz", + "integrity": "sha512-t44QCeDKAPf1mtQH3fYpWz8IM/DyvHLjs8wUvvwMYxk5moOqCzrMSxK6HQVD0QVmVjXFavoFIPRVrMuJPKAvtg==", + "license": "MIT", + "dependencies": { + "compute-scroll-into-view": "^3.0.2" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", + "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sucrase": { + "version": "3.35.1", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", + "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "tinyglobby": "^0.2.11", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwind-merge": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz", + "integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwind-variants": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-3.2.2.tgz", + "integrity": "sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==", + "license": "MIT", + "engines": { + "node": ">=16.x", + "pnpm": ">=7.x" + }, + "peerDependencies": { + "tailwind-merge": ">=3.0.0", + "tailwindcss": "*" + }, + "peerDependenciesMeta": { + "tailwind-merge": { + "optional": true + } + } + }, + "node_modules/tailwindcss": { + "version": "3.4.19", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", + "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.7", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz", + "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/use-composed-ref": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.4.0.tgz", + "integrity": "sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz", + "integrity": "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-latest": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.3.0.tgz", + "integrity": "sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==", + "license": "MIT", + "dependencies": { + "use-isomorphic-layout-effect": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/package.json b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/package.json new file mode 100644 index 0000000..26bb6fe --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/package.json @@ -0,0 +1,30 @@ +{ + "name": "persona-admin", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "@heroui/react": "^2.8.0", + "@heroui/theme": "^2.4.26", + "framer-motion": "^11.11.17", + "next-themes": "^0.4.4", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.28.0" + }, + "devDependencies": { + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.49", + "tailwindcss": "^3.4.15", + "typescript": "^5.6.3", + "vite": "^6.0.3" + } +} diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/postcss.config.js b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/postcss.config.js new file mode 100644 index 0000000..2aa7205 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/App.tsx b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/App.tsx new file mode 100644 index 0000000..621d323 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/App.tsx @@ -0,0 +1,112 @@ +import { useEffect } from "react"; +import { + Navigate, + NavLink, + Outlet, + Route, + Routes, + useLocation, + useNavigate, +} from "react-router-dom"; +import { Button, Tooltip } from "@heroui/react"; +import { useTheme } from "next-themes"; +import { clearToken, hasToken } from "./api"; +import Login from "./pages/Login"; +import GroupList from "./pages/GroupList"; +import GroupDetail from "./pages/GroupDetail"; +import DataBrowser from "./pages/DataBrowser"; +import Settings from "./pages/Settings"; + +const NAV_ITEMS = [ + { to: "/groups", label: "群管理", icon: "◈" }, + { to: "/data", label: "数据浏览", icon: "▤" }, + { to: "/settings", label: "设置", icon: "⚙" }, +]; + +function Layout() { + const navigate = useNavigate(); + const location = useLocation(); + const { resolvedTheme, setTheme } = useTheme(); + const isDark = resolvedTheme === "dark"; + + useEffect(() => { + if (!hasToken()) navigate("/login", { replace: true }); + }, [location.pathname]); + + const logout = () => { + clearToken(); + navigate("/login", { replace: true }); + }; + + return ( +
+ +
+ +
+
+ ); +} + +export default function App() { + return ( + + } /> + }> + } /> + } /> + } /> + } /> + } /> + } /> + + + ); +} diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/api.ts b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/api.ts new file mode 100644 index 0000000..32870e8 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/api.ts @@ -0,0 +1,92 @@ +const API = "/galgame_card/api"; + +let token: string = localStorage.getItem("gc_token") || ""; + +export function setToken(t: string) { + token = t; + localStorage.setItem("gc_token", t); +} +export function clearToken() { + token = ""; + localStorage.removeItem("gc_token"); +} +export function hasToken() { + return !!token; +} + +export async function api(path: string, options: RequestInit = {}): Promise { + const res = await fetch(API + path, { + ...options, + headers: { + "Content-Type": "application/json", + Authorization: token, + ...(options.headers || {}), + }, + }); + const data = await res.json(); + if (data.status !== 0) { + if (data.status === 400) { + clearToken(); + window.location.hash = "#/login"; + } + throw new Error(data.msg || "请求失败"); + } + return data.data as T; +} + +/* ---------- 类型 ---------- */ + +export interface GroupInfo { + group_id: number; + group_name: string; + enabled: boolean; + participants: number; + corpus_count: number; + impression_count: number; + summary_count: number; +} +export interface DiscoverGroup { + group_id: number; + group_name: string; + managed: boolean; +} +export interface Participant { + user_id: number; + corpus_count: number; +} +export interface LogItem { + id: number; + user_id: number; + nickname: string; + content: string; + target_user_id: number | null; + target_inherited: boolean; + follows_id: number | null; + created_at: string; +} +export interface ImpressionItem { + id: number; + user_id: number; + content: string; + cover_from_id: number; + cover_to_id: number; + created_at: string; +} +export interface SummaryItem { + version: number; + card_text: string; + corpus_count: number; + impression_count: number; + model: string; + created_at: string; +} +export interface SettingsInfo { + web_username: string; + web_enable: boolean; + thresholds: { + max_content_len: number; + repeat_window: number; + throttle_seconds: number; + rolling_window: number; + }; +} diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/index.css b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/index.css new file mode 100644 index 0000000..b8eb30e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/index.css @@ -0,0 +1,24 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +html.dark { + color-scheme: dark; +} + +body { + @apply bg-background text-foreground; + font-family: "Microsoft YaHei", -apple-system, sans-serif; +} + +/* 侧栏滚动条 */ +::-webkit-scrollbar { + width: 6px; + height: 6px; +} +::-webkit-scrollbar-thumb { + @apply bg-default-700 rounded-full; +} +::-webkit-scrollbar-track { + background: transparent; +} diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/main.tsx b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/main.tsx new file mode 100644 index 0000000..5185c24 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/main.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import { HeroUIProvider, ToastProvider } from "@heroui/react"; +import { ThemeProvider } from "next-themes"; +import { HashRouter } from "react-router-dom"; +import App from "./App"; +import "./index.css"; + +ReactDOM.createRoot(document.getElementById("root")!).render( + + + + + + + + + + +); diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/DataBrowser.tsx b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/DataBrowser.tsx new file mode 100644 index 0000000..e46d928 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/DataBrowser.tsx @@ -0,0 +1,171 @@ +import { useEffect, useState } from "react"; +import { + Card, + CardBody, + Select, + SelectItem, + Spinner, + Tab, + Tabs, + Table, + TableBody, + TableCell, + TableColumn, + TableHeader, + TableRow, +} from "@heroui/react"; +import { addToast } from "@heroui/react"; +import { api, GroupInfo, ImpressionItem, LogItem, SummaryItem } from "../api"; + +export default function DataBrowser() { + const [groups, setGroups] = useState([]); + const [gid, setGid] = useState(0); + const [tab, setTab] = useState("logs"); + + const [logs, setLogs] = useState([]); + const [impressions, setImpressions] = useState([]); + const [summaries, setSummaries] = useState([]); + const [loading, setLoading] = useState(false); + + useEffect(() => { + api("/groups") + .then(setGroups) + .catch((e: any) => addToast({ title: e.message, color: "danger" })); + }, []); + + useEffect(() => { + if (!gid) return; + setLoading(true); + const loaders: Record> = { + logs: api(`/groups/${gid}/logs?page=1&per_page=100`).then((d: any) => + setLogs(d.items) + ), + impressions: api(`/groups/${gid}/impressions?page=1&per_page=100`).then((d: any) => + setImpressions(d.items) + ), + summaries: api(`/groups/${gid}/summaries`).then(setSummaries), + }; + Promise.all([loaders.logs, loaders.impressions, loaders.summaries]).finally(() => + setLoading(false) + ); + }, [gid]); + + return ( +
+

数据浏览

+ + + + + {!gid &&

请先选择群

} + + {loading && gid && ( +
+ +
+ )} + + {!loading && gid && ( + setTab(String(k))}> + + + + ID + 发送者 + 发给 + 时间 + 内容(已脱敏) + + + {(l) => ( + + {l.id} + +
{l.nickname || "—"}
+
{l.user_id}
+
+ + {l.target_user_id ? ( + + → {l.target_user_id} + {l.target_inherited && ( + 延续 + )} + + ) : ( + — + )} + + {l.created_at} + {l.content} +
+ )} +
+
+
+ + + + + ID + 用户 + 覆盖语料区间 + 时间 + 印象内容 + + + {(r) => ( + + {r.id} + {r.user_id} + + #{r.cover_from_id} ~ #{r.cover_to_id} + + {r.created_at} + {r.content} + + )} + +
+
+ + + {summaries.length === 0 ? ( +

{gid ? "暂无数据" : "请先选择群"}

+ ) : ( + summaries.map((s) => ( +
+
+ v{s.version} · {s.created_at} · 语料 {s.corpus_count} 条 · 印象{" "} + {s.impression_count} 条 +
+
+                        {s.card_text}
+                      
+
+ )) + )} +
+
+ )} +
+
+
+ ); +} diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/GroupDetail.tsx b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/GroupDetail.tsx new file mode 100644 index 0000000..0f90cd6 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/GroupDetail.tsx @@ -0,0 +1,334 @@ +import { useCallback, useEffect, useState } from "react"; +import { Link, useParams } from "react-router-dom"; +import { + Button, + Card, + CardBody, + Input, + Spinner, + Tab, + Tabs, + Table, + TableBody, + TableCell, + TableColumn, + TableHeader, + TableRow, +} from "@heroui/react"; +import { addToast } from "@heroui/react"; +import { api, ImpressionItem, LogItem, Participant, SummaryItem } from "../api"; + +export default function GroupDetail() { + const { gid } = useParams(); + const gidNum = Number(gid); + + const [participants, setParticipants] = useState([]); + const [addUid, setAddUid] = useState(""); + const [tab, setTab] = useState("logs"); + + const [logs, setLogs] = useState([]); + const [logTotal, setLogTotal] = useState(0); + const [logPage, setLogPage] = useState(1); + const [logUid, setLogUid] = useState(""); + const [impressions, setImpressions] = useState([]); + const [summaries, setSummaries] = useState([]); + + const [loading, setLoading] = useState(true); + + const loadParticipants = useCallback(async () => { + try { + setParticipants(await api(`/groups/${gidNum}/participants`)); + } catch (e: any) { + addToast({ title: e.message, color: "danger" }); + } + }, [gidNum]); + + const loadLogs = useCallback( + async (page: number) => { + const q = new URLSearchParams({ page: String(page), per_page: "50" }); + if (logUid) q.set("user_id", logUid); + try { + const data = await api<{ items: LogItem[]; total: number }>( + `/groups/${gidNum}/logs?${q}` + ); + setLogs(data.items); + setLogTotal(data.total); + setLogPage(page); + } catch (e: any) { + addToast({ title: e.message, color: "danger" }); + } + }, + [gidNum, logUid] + ); + + const loadImpressions = useCallback(async () => { + try { + const data = await api<{ items: ImpressionItem[] }>( + `/groups/${gidNum}/impressions?page=1&per_page=100` + ); + setImpressions(data.items); + } catch (e: any) { + addToast({ title: e.message, color: "danger" }); + } + }, [gidNum]); + + const loadSummaries = useCallback(async () => { + try { + setSummaries(await api(`/groups/${gidNum}/summaries`)); + } catch (e: any) { + addToast({ title: e.message, color: "danger" }); + } + }, [gidNum]); + + useEffect(() => { + setLoading(true); + Promise.all([loadParticipants(), loadLogs(1)]).finally(() => setLoading(false)); + }, [loadParticipants, loadLogs]); + + useEffect(() => { + if (tab === "impressions") loadImpressions(); + if (tab === "summaries") loadSummaries(); + }, [tab]); + + /* ---------- 操作 ---------- */ + const addParticipant = async () => { + const uid = Number(addUid.trim()); + if (!uid) return; + try { + await api(`/groups/${gidNum}/participants`, { + method: "POST", + body: JSON.stringify({ user_id: uid }), + }); + setAddUid(""); + loadParticipants(); + addToast({ title: `已加入 ${uid}`, color: "success" }); + } catch (e: any) { + addToast({ title: e.message, color: "danger" }); + } + }; + + const removeParticipant = async (uid: number) => { + if (!confirm(`移除 ${uid}?其语料保留在库中`)) return; + try { + await api(`/groups/${gidNum}/participants/${uid}`, { method: "DELETE" }); + loadParticipants(); + addToast({ title: "已移除", color: "success" }); + } catch (e: any) { + addToast({ title: e.message, color: "danger" }); + } + }; + + const clearLogs = async () => { + if (!confirm("删除该群全部语料?印象/画像保留")) return; + try { + await api(`/groups/${gidNum}/logs`, { method: "DELETE" }); + loadLogs(1); + addToast({ title: "已删除全部语料", color: "success" }); + } catch (e: any) { + addToast({ title: e.message, color: "danger" }); + } + }; + + const clearGroup = async () => { + if (!confirm("确认清空该群全部数据(语料/印象/画像/参与者)?此操作不可恢复")) return; + try { + await api(`/groups/${gidNum}/data`, { method: "DELETE" }); + addToast({ title: "已清空", color: "success" }); + setTimeout(() => (window.location.hash = "#/groups"), 600); + } catch (e: any) { + addToast({ title: e.message, color: "danger" }); + } + }; + + const pages = Math.max(1, Math.ceil(logTotal / 50)); + + if (loading) { + return ( +
+ +
+ ); + } + + return ( +
+
+ + + +

群管理 #{gidNum}

+ +
+ + {/* 参与者 */} + + +

参与者

+
+ e.key === "Enter" && addParticipant()} + /> + +
+ + + QQ + 语料条数 + 操作 + + + {(p) => ( + + {p.user_id} + {p.corpus_count} + + + + + )} + +
+
+
+ + {/* 数据页签 */} + + + setTab(String(k))}> + +
+ + + +
+ + + ID + 发送者 + 发给 + 时间 + 内容(已脱敏) + + + {(l) => ( + + {l.id} + +
{l.nickname || "—"}
+
{l.user_id}
+
+ + {l.target_user_id ? ( + + → {l.target_user_id} + {l.target_inherited && ( + 延续 + )} + + ) : ( + — + )} + + {l.created_at} + {l.content} +
+ )} +
+
+
+ + + 第 {logPage}/{pages} 页 · 共 {logTotal} 条 + + +
+
+ + + + + ID + 用户 + 覆盖语料区间 + 时间 + 印象内容 + + + {(r) => ( + + {r.id} + {r.user_id} + + #{r.cover_from_id} ~ #{r.cover_to_id} + + {r.created_at} + {r.content} + + )} + +
+
+ + + {summaries.length === 0 ? ( +

暂无画像(语料积累后由总结路径生成)

+ ) : ( + summaries.map((s) => ( +
+
+ v{s.version} · {s.created_at} · 语料 {s.corpus_count} 条 · 印象{" "} + {s.impression_count} 条 +
+
+                      {s.card_text}
+                    
+
+ )) + )} +
+
+
+
+
+ ); +} diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/GroupList.tsx b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/GroupList.tsx new file mode 100644 index 0000000..085c967 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/GroupList.tsx @@ -0,0 +1,227 @@ +import { useEffect, useState } from "react"; +import { Link } from "react-router-dom"; +import { + Button, + Card, + CardBody, + Checkbox, + CheckboxGroup, + Modal, + ModalBody, + ModalContent, + ModalFooter, + ModalHeader, + Spinner, + Switch, + Table, + TableBody, + TableCell, + TableColumn, + TableHeader, + TableRow, + useDisclosure, +} from "@heroui/react"; +import { addToast } from "@heroui/react"; +import { api, DiscoverGroup, GroupInfo } from "../api"; + +export default function GroupList() { + const [groups, setGroups] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(""); + + // 添加群弹窗 + const { isOpen, onOpen, onOpenChange } = useDisclosure(); + const [discoverList, setDiscoverList] = useState([]); + const [selected, setSelected] = useState([]); + const [discoverLoading, setDiscoverLoading] = useState(false); + const [adding, setAdding] = useState(false); + + const load = async () => { + setLoading(true); + setError(""); + try { + setGroups(await api("/groups")); + } catch (e: any) { + setError(e.message); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + load(); + }, []); + + const toggle = async (g: GroupInfo, enabled: boolean) => { + try { + await api(`/groups/${g.group_id}/enabled`, { + method: "POST", + body: JSON.stringify({ enabled }), + }); + g.enabled = enabled; + setGroups([...groups]); + addToast({ + title: enabled ? "已开启采集" : "已关闭采集", + description: `${g.group_name || g.group_id}`, + color: enabled ? "success" : "warning", + }); + } catch (e: any) { + addToast({ title: e.message, color: "danger" }); + } + }; + + const removeGroup = async (g: GroupInfo) => { + if (!confirm(`将 ${g.group_name || g.group_id} 移出管理列表?其数据保留`)) return; + try { + await api(`/groups/${g.group_id}`, { method: "DELETE" }); + load(); + addToast({ title: "已移出管理列表", color: "success" }); + } catch (e: any) { + addToast({ title: e.message, color: "danger" }); + } + }; + + /* ---------- 添加群 ---------- */ + const openDiscover = async () => { + onOpen(); + setDiscoverLoading(true); + setSelected([]); + try { + setDiscoverList(await api("/groups/discover")); + } catch (e: any) { + addToast({ title: e.message, color: "danger" }); + } finally { + setDiscoverLoading(false); + } + }; + + const confirmAdd = async () => { + const picked = discoverList.filter( + (g) => selected.includes(String(g.group_id)) && !g.managed + ); + if (picked.length === 0) return; + setAdding(true); + try { + for (const g of picked) { + await api("/groups", { + method: "POST", + body: JSON.stringify({ group_id: g.group_id, group_name: g.group_name }), + }); + } + addToast({ title: `已加入 ${picked.length} 个群`, color: "success" }); + onOpenChange(false); + load(); + } catch (e: any) { + addToast({ title: e.message, color: "danger" }); + } finally { + setAdding(false); + } + }; + + return ( +
+
+

群管理

+
+ + +
+
+ + + {loading ? ( +
+ +
+ ) : error ? ( +

{error}

+ ) : ( + + + 群 + 采集开关 + 参与者 + 语料 + 印象 + 画像 + 操作 + + + {(g) => ( + + +
{g.group_name || `群 ${g.group_id}`}
+
{g.group_id}
+
+ + toggle(g, v)} /> + + {g.participants} + {g.corpus_count} + {g.impression_count} + {g.summary_count} + +
+ + + + +
+
+
+ )} +
+
+ )} +
+
+ + {/* 添加群弹窗 */} + + + 添加群到管理列表 + + {discoverLoading ? ( +
+ +
+ ) : ( + + {discoverList.map((g) => ( +
+ + {g.group_name || `群 ${g.group_id}`} + {g.group_id} + + {g.managed && 已管理} +
+ ))} +
+ )} +
+ + + + +
+
+
+ ); +} diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/Login.tsx b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/Login.tsx new file mode 100644 index 0000000..878c933 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/Login.tsx @@ -0,0 +1,58 @@ +import { useState } from "react"; +import { Button, Card, CardBody, Input } from "@heroui/react"; +import { useNavigate } from "react-router-dom"; +import { api, setToken } from "../api"; + +export default function Login() { + const navigate = useNavigate(); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); + + const submit = async () => { + setLoading(true); + setError(""); + try { + const data = await api<{ token: string }>("/login", { + method: "POST", + body: JSON.stringify({ username, password }), + }); + setToken(data.token); + navigate("/groups", { replace: true }); + } catch (e: any) { + setError(e.message || "登录失败"); + } finally { + setLoading(false); + } + }; + + return ( +
+ + +

群聊人设卡

+ e.key === "Enter" && submit()} + /> + e.key === "Enter" && submit()} + /> + {error &&

{error}

} + +
+
+
+ ); +} diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/Settings.tsx b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/Settings.tsx new file mode 100644 index 0000000..5f86e2b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/src/pages/Settings.tsx @@ -0,0 +1,71 @@ +import { useEffect, useState } from "react"; +import { Card, CardBody, Spinner, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from "@heroui/react"; +import { api, SettingsInfo } from "../api"; + +export default function Settings() { + const [info, setInfo] = useState(null); + const [error, setError] = useState(""); + + useEffect(() => { + api("/settings") + .then(setInfo) + .catch((e: any) => setError(e.message)); + }, []); + + return ( +
+

设置

+ + + {error ? ( +

{error}

+ ) : !info ? ( +
+ +
+ ) : ( + <> +

当前配置(只读)

+ + + 项 + 值 + + + + Web 登录账号 + {info.web_username} + + + Web 后台启用 + {info.web_enable ? "是" : "否"} + + + 长文截断上限 + {info.thresholds.max_content_len} 字 + + + 复读检测窗口 + {info.thresholds.repeat_window} 条 + + + 刷屏采样间隔 + {info.thresholds.throttle_seconds} 秒 + + + 单用户语料滚动上限 + {info.thresholds.rolling_window} 条 + + +
+

+ 阈值与脱敏规则见插件 processor.py / DESIGN.md;Web 账号密码在 .env 配置 WEB_USERNAME / + WEB_PASSWORD。 +

+ + )} +
+
+
+ ); +} diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/tailwind.config.js b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/tailwind.config.js new file mode 100644 index 0000000..17c175c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/tailwind.config.js @@ -0,0 +1,12 @@ +import { heroui } from "@heroui/theme"; + +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./index.html", + "./src/**/*.{js,ts,jsx,tsx}", + "./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}", + ], + darkMode: "class", + plugins: [heroui()], +}; diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/tsconfig.json b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/tsconfig.json new file mode 100644 index 0000000..109f0ac --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/vite.config.ts b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/vite.config.ts new file mode 100644 index 0000000..a28de47 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web/persona-admin/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + base: "/galgame_card/", + plugins: [react()], +}); diff --git a/hexi/plugins/nonebot_plugin_galgame_card/web_hub.py b/hexi/plugins/nonebot_plugin_galgame_card/web_hub.py new file mode 100644 index 0000000..f726b80 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_galgame_card/web_hub.py @@ -0,0 +1,227 @@ +# -*- coding: utf-8 -*- +"""群聊人设卡 Web API 子应用(挂载到 /api/galgame_card)。 + +统一鉴权走 hexi.web_auth(OAuth2 + SQLite),与统一管理台 /hub 共用登录态。 +旧版独立后台 /galgame_card(JWT 自鉴权)仍保留可用,前端由 hub 渲染。 +""" + +from __future__ import annotations + +from typing import Optional + +from fastapi import FastAPI +from fastapi.responses import JSONResponse + +from hexi.web_auth import require_admin + +from . import repository +from .config import config + +API = require_admin + + +def _ok(data=None, msg: str = "ok") -> JSONResponse: + return JSONResponse({"status": 0, "msg": msg, "data": data}) + + +def _err(code: int, msg: str) -> JSONResponse: + return JSONResponse({"status": code, "msg": msg}) + + +async def _first_bot(): + try: + from nonebot import get_adapter + from nonebot.adapters.onebot.v11 import Adapter + + bots = get_adapter(Adapter).bots + return next(iter(bots.values()), None) + except Exception: # noqa: BLE001 + return None + + +def build_admin_app() -> FastAPI | None: + """构建群聊人设卡管理 API 子应用(挂载到 /api/galgame_card)。 + + 在 hub 统一登录态下可用;未启用 Web 时返回 None。 + """ + if not config.web_enable: + return None + + app = FastAPI(title="Galgame Card API") + + @app.get("/groups", dependencies=[API]) + async def groups(): + rows = await repository.list_groups() + corpus = await repository.corpus_counts_by_group() + impressions = await repository.impression_counts_by_group() + summaries = await repository.summary_counts_by_group() + participants = await repository.participant_counts_by_group() + result = [] + for row in rows: + gid = row.group_id + result.append( + { + "group_id": gid, + "group_name": row.group_name, + "enabled": row.enabled, + "participants": participants.get(gid, 0), + "corpus_count": corpus.get(gid, 0), + "impression_count": impressions.get(gid, 0), + "summary_count": summaries.get(gid, 0), + } + ) + return _ok(result) + + @app.get("/groups/discover", dependencies=[API]) + async def discover_groups(): + bot = await _first_bot() + if bot is None: + return _err(-100, "未连接 OneBot,无法获取群列表") + group_list = await bot.get_group_list() + managed_ids = {row.group_id for row in await repository.list_groups()} + result = [ + { + "group_id": int(g["group_id"]), + "group_name": g.get("group_name", ""), + "managed": int(g["group_id"]) in managed_ids, + } + for g in group_list + ] + await repository.backfill_group_names( + {int(g["group_id"]): g.get("group_name", "") for g in group_list} + ) + return _ok(result) + + @app.post("/groups", dependencies=[API]) + async def add_group(data: dict): + gid = int(data.get("group_id") or 0) + if gid <= 0: + return _err(400, "group_id 不合法") + await repository.add_group(gid, str(data.get("group_name") or "").strip()) + return _ok(msg="已加入管理列表") + + @app.post("/groups/{group_id}/enabled", dependencies=[API]) + async def set_group_enabled(group_id: int, data: dict): + await repository.set_group_enabled(group_id, bool(data.get("enabled"))) + return _ok(msg="已开启采集" if data.get("enabled") else "已关闭采集") + + @app.get("/groups/{group_id}/participants", dependencies=[API]) + async def participants(group_id: int): + members = await repository.joined_users(group_id) + stats = dict(await repository.chat_log_stats_by_user(group_id)) + result = [ + {"user_id": uid, "corpus_count": stats.get(uid, 0)} for uid in members + ] + return _ok(result) + + @app.post("/groups/{group_id}/participants", dependencies=[API]) + async def add_participant(group_id: int, data: dict): + user_id = int(data.get("user_id") or 0) + if user_id <= 0: + return _err(400, "user_id 不合法") + if await repository.is_joined(user_id, group_id): + return _err(400, "已在人设名单中") + await repository.join(user_id, group_id) + return _ok(msg="已加入") + + @app.delete("/groups/{group_id}/participants/{user_id}", dependencies=[API]) + async def remove_participant(group_id: int, user_id: int): + await repository.leave(user_id, group_id) + return _ok(msg="已移除") + + @app.get("/groups/{group_id}/logs", dependencies=[API]) + async def logs( + group_id: int, + user_id: Optional[int] = None, + page: int = 1, + per_page: int = 50, + ): + offset = max(0, (page - 1) * per_page) + items = await repository.list_logs(group_id, user_id, offset, per_page) + total = await repository.count_logs_filtered(group_id, user_id) + result = [ + { + "id": row.id, + "user_id": row.user_id, + "nickname": row.nickname, + "content": row.content, + "target_user_id": row.target_user_id, + "target_inherited": row.target_inherited, + "follows_id": row.follows_id, + "created_at": row.created_at.strftime("%Y-%m-%d %H:%M:%S"), + } + for row in items + ] + return _ok({"items": result, "total": total}) + + @app.get("/groups/{group_id}/impressions", dependencies=[API]) + async def impressions(group_id: int, page: int = 1, per_page: int = 50): + offset = max(0, (page - 1) * per_page) + items = await repository.list_impressions_group(group_id, offset, per_page) + result = [ + { + "id": row.id, + "user_id": row.user_id, + "content": row.content, + "cover_from_id": row.cover_from_id, + "cover_to_id": row.cover_to_id, + "created_at": row.created_at.strftime("%Y-%m-%d %H:%M:%S"), + } + for row in items + ] + return _ok( + { + "items": result, + "total": await repository.count_impressions_group(group_id), + } + ) + + @app.get("/groups/{group_id}/summaries", dependencies=[API]) + async def summaries(group_id: int): + items = await repository.list_summaries_group(group_id) + result = [ + { + "version": row.version, + "card_text": row.card_text, + "corpus_count": row.corpus_count, + "impression_count": row.impression_count, + "model": row.model, + "created_at": row.created_at.strftime("%Y-%m-%d %H:%M:%S"), + } + for row in items + ] + return _ok(result) + + @app.delete("/groups/{group_id}/logs", dependencies=[API]) + async def delete_logs(group_id: int, user_id: Optional[int] = None): + count = await repository.delete_logs(group_id, user_id) + return _ok(msg=f"已删除 {count} 条语料") + + @app.delete("/groups/{group_id}/data", dependencies=[API]) + async def clear_group(group_id: int): + await repository.clear_group_data(group_id) + return _ok(msg="已清空该群全部数据") + + @app.delete("/groups/{group_id}", dependencies=[API]) + async def remove_group(group_id: int): + await repository.remove_group(group_id) + return _ok(msg="已移出管理列表(数据保留,重新加入可续上)") + + @app.get("/settings", dependencies=[API]) + async def settings(): + from . import processor + + return _ok( + { + "web_username": config.web_username, + "web_enable": config.web_enable, + "thresholds": { + "max_content_len": processor.MAX_CONTENT_LEN, + "repeat_window": processor.REPEAT_WINDOW, + "throttle_seconds": processor.THROTTLE_SECONDS, + "rolling_window": repository.ROLLING_WINDOW, + }, + } + ) + + return app diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/README.md b/hexi/plugins/nonebot_plugin_group_daily_analysis/README.md new file mode 100644 index 0000000..3e84ff6 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/README.md @@ -0,0 +1,60 @@ +# nonebot_plugin_group_daily_analysis(OneBot V11 最小可用版) + +移植自 astrbot_plugin_qq_group_daily_analysis(GitHub: SXP-Simon/astrbot_plugin_qq_group_daily_analysis), +保留其领域分析 / 报告生成 / 持久化核心,把 AstrBot 全平台外壳重写为 NoneBot2 + OneBot V11。 + +## 群内指令(均需 @ 机器人,且群管理员 / 群主 / 超管) + +- 群分析 [天数] :手动触发分析,可选最近 N 天(默认用配置里的时间窗口) +- 查看模板 :列出可用报告模板及其编号,标出当前模板 +- 设置模板 [序号/名称] :切换报告模板,支持 1..9 编号或模板名 +- 分析设置 :查看当前分析参数(时间窗口 / 消息数 / 输出格式 / 模板 / 功能开关) +- 设置分析 [参数] [值] :修改分析参数,见下表 + +设置分析 支持的参数: + + 天数/窗口 [N] 时间窗口,最近 N 天 + 最大消息 [N] 单次最多拉取消息数 + 最小消息 [N] 自动分析的最小消息阈值 + 输出格式 [image/text] + 话题 / 称号 / 金句 / 聊天质量 [开/关] + +## 已有能力 + +- 群分析:Onbot V11 get_group_msg_history 分页拉取近 N 天群聊 +- 话题分析 / 用户形象 / 群聊金句 / 聊天质量(OpenAI 兼容 LLM) +- Playwright 渲染报告 HTML 为图片;报告内容以合并转发 (send_forward_msg) 发送,失败时回退直接发送 +- 历史摘要、本地 KV、断点检查点落盘到数据目录 + +## 尚未接入(后续阶段) + +- 定时自动分析、增量分析、群漫画、多平台(Telegram/Discord/QQ 官方) +- AstrBot 版 WebUI 看板 +- 群白名单管理指令 + +## 安装 / 启用 + +1. 插件目录已在 hexi/plugins/nonebot_plugin_group_daily_analysis,随 hexi/plugins 自动加载。 +2. 依赖:pip install ulid-py diskcache(已在 requirements.txt 追加)。 +3. 配置 LLM(环境变量,写入 NoneBot 的 .env): + + HEXI_LLM_API_BASE=https://api.openai.com/v1 + HEXI_LLM_API_KEY=sk-xxx + HEXI_LLM_MODEL=gpt-4o-mini + + 支持任何 OpenAI 兼容端点(One API / 中转 / 本地 vLLM 等)。 + +## 配置 + +配置文件:hexi/data/group_daily_analysis/config.json(首次运行由 _conf_schema.json 生成默认值)。 +命令里的 设置分析 / 设置模板 会直接写回该文件,改完即生效。 + +重点键: +- basic.analysis_days:时间窗口(最近 N 天) +- basic.max_messages:单次最大拉取消息数 +- basic.output_format:["image"] 或 ["text"] +- basic.report_template:当前模板名(如 ATRI / scrapbook / BlueArchive) +- analysis_features.topic_analysis_enabled / user_title_analysis_enabled / golden_quote_analysis_enabled / chat_quality_analysis_enabled +- llm.llm_retries / llm.llm_backoff + +注意:HEXI_LLM_API_BASE/KEY/MODEL 来自 .env 且优先于 config.json,不会被配置文件覆盖。 \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/__init__.py new file mode 100644 index 0000000..494be5c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/__init__.py @@ -0,0 +1,412 @@ +"""NoneBot 版「群日常分析」插件(OneBot V11 最小可用版)。 + +保留原 AstrBot 插件的领域分析/报告引擎,重写为 NoneBot 外壳: + - on_command("群分析") 手动触发(需 @ 机器人) + - OneBot V11 拉取群历史消息 + - OpenAI 兼容 LLM 通道 + - Playwright 渲染 HTML 报告为图片 + - 报告内容以合并转发 (send_forward_msg) 发送 +""" + +from __future__ import annotations + +from nonebot import on_command, require +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageSegment +from nonebot.log import logger +from nonebot.params import CommandArg +from nonebot.plugin import PluginMetadata +from nonebot.rule import to_me + +require("nonebot_plugin_alconna") +from nonebot_plugin_alconna import UniMessage # noqa: E402 + +__plugin_meta__ = PluginMetadata( + name="群分析插件", + description="群日常分析总结插件(OneBot V11 最小可用版):生成群聊分析报告", + usage="发送「群分析」或「群分析 [天数]」,需在群内 @ 机器人并由管理员触发", + type="application", +) + +from .service import get_services, register_bot_adapter # noqa: E402 +from .renderer import html_render # noqa: E402 +from .templates import list_templates, template_exists # noqa: E402 + + +# ---------- 指令定义(全部要求 @ 机器人) ---------- + +analysis_cmd = on_command( + "群分析", + aliases={"group_analysis"}, + priority=5, + block=True, + rule=to_me(), +) + +view_templates_cmd = on_command( + "查看模板", + aliases={"模板列表", "view_templates"}, + priority=5, + block=True, + rule=to_me(), +) + +set_template_cmd = on_command( + "设置模板", + aliases={"set_template", "切换模板"}, + priority=5, + block=True, + rule=to_me(), +) + +analysis_settings_cmd = on_command( + "分析设置", + aliases={"查看参数", "analysis_settings"}, + priority=5, + block=True, + rule=to_me(), +) + +set_analysis_cmd = on_command( + "设置分析", + aliases={"set_analysis", "设置参数"}, + priority=5, + block=True, + rule=to_me(), +) + + +# ---------- 工具函数 ---------- + +def _is_privileged(event: GroupMessageEvent, bot: Bot) -> bool: + from nonebot import get_driver + try: + superusers = getattr(get_driver().config, "superusers", []) + if str(event.user_id) in [str(s) for s in superusers]: + return True + except Exception: + pass + role = getattr(event.sender, "role", "") + return role in {"owner", "admin"} + + +def _cmd_arg(a) -> str: + """把 CommandArg 里的参数转成纯字符串(可能是 MessageSegment)。""" + return str(a).strip() + + +def _cmd_tokens(args: tuple) -> list[str]: + """把 CommandArg 转成按空白切分的参数列表(兼容单段/多段两种返回)。""" + tokens: list[str] = [] + for a in args: + tokens.extend(_cmd_arg(a).split()) + return tokens + + +def _parse_days(event: GroupMessageEvent) -> int | None: + text = str(event.message) + tokens = text.split() + if len(tokens) >= 2: + try: + val = int(tokens[1]) + return max(1, min(val, 30)) if val > 0 else None + except ValueError: + return None + return None + + +def _build_text_report(result: dict) -> str: + ar = result.get("analysis_result", {}) + stats = ar.get("statistics") + lines = ["[群聊分析报告(文本版)]"] + if stats: + mc = getattr(stats, "message_count", "?") + pc = getattr(stats, "participant_count", "?") + lines.append(f"发言 {mc} 条 / 参与 {pc} 人") + topics = ar.get("topics", []) + if topics: + lines.append("") + lines.append("[今日话题]") + for i, t in enumerate(topics[:6], 1): + title = getattr(t, "topic", "") or (t.get("topic") if isinstance(t, dict) else "") + detail = getattr(t, "detail", "") or (t.get("detail") if isinstance(t, dict) else "") + lines.append(f"{i}. {title}: {detail}") + quotes = ar.get("golden_quotes", []) + if quotes: + lines.append("") + lines.append("[群聊圣经]") + for q in quotes[:5]: + text = getattr(q, "quote", "") or (q.get("quote") if isinstance(q, dict) else "") + user = getattr(q, "user_name", "") or (q.get("user_name") if isinstance(q, dict) else "") + lines.append(f"[{text}] —— {user}") + lines.append("") + lines.append("(文本版,图片报告请将输出格式设为 image)") + return chr(10).join(lines) + + +def _build_forward_nodes(adapter, group_id: str, text_report: str, image_url: str | None) -> list[dict]: + """构建 OneBot v11 合并转发 (send_forward_msg) 节点列表。""" + self_uin = (adapter.bot_self_ids[0] if adapter and adapter.bot_self_ids else "10000") + nodes = [] + nodes.append( + { + "type": "node", + "data": { + "name": "群聊分析报告", + "uin": self_uin, + "content": [MessageSegment.text(f"群聊分析报告(群 {group_id})")], + }, + } + ) + if text_report: + nodes.append( + { + "type": "node", + "data": { + "name": "报告内容", + "uin": self_uin, + "content": [MessageSegment.text(text_report)], + }, + } + ) + if image_url: + nodes.append( + { + "type": "node", + "data": { + "name": "报告图片", + "uin": self_uin, + "content": [MessageSegment.image(file=image_url)], + }, + } + ) + return nodes + + +# ---------- 手动分析 ---------- + +@analysis_cmd.handle() +async def _(bot: Bot, event: GroupMessageEvent): + if not _is_privileged(event, bot): + await UniMessage.text("仅群管理员或超级管理员可使用该指令").send() + return + + group_id = str(event.group_id) + days = _parse_days(event) + await UniMessage.text("正在启动分析引擎,正在拉取最近消息...").send() + + try: + svc = get_services() + register_bot_adapter(bot) + analysis_service = svc["analysis_service"] + report_generator = svc["report_generator"] + config_manager = svc["config_manager"] + + result = await analysis_service.execute_daily_analysis( + group_id=group_id, + platform_id="onebot", + manual=True, + days=days, + ) + except Exception as e: + logger.error(f"群分析异常: {e}", exc_info=True) + await UniMessage.text(f"分析失败: {e}").send() + return + + if not result.get("success"): + reason = result.get("reason") + if reason == "no_messages": + await UniMessage.text("未找到足够的群聊记录").send() + elif reason == "llm_analysis_failed": + await UniMessage.text("大模型文本分析失败(请检查 LLM API Key 及服务商连通性)").send() + else: + await UniMessage.text(f"分析失败: {result.get('error', '原因未知')}").send() + return + + analysis_result = result["analysis_result"] + adapter = result.get("adapter") + platform_id = result.get("platform_id", "onebot") + + async def avatar_url_getter(user_id: str) -> str | None: + if adapter: + return await adapter.get_user_avatar_url(user_id) + return None + + async def nickname_getter(user_id: str) -> str | None: + if adapter: + try: + member = await adapter.get_member_info(group_id, user_id) + if member: + return member.card or member.nickname + except Exception: + pass + return None + + output_format = config_manager.get_output_format() + fmt = str(output_format[0]).lower() if output_format else "image" + text_report = _build_text_report(result) or "(无文本报告)" + image_url = None + + if fmt != "text": + await UniMessage.text("正在生成报告图片...").send() + try: + image_url, html_content = await report_generator.generate_image_report( + analysis_result, + group_id, + html_render, + avatar_url_getter=avatar_url_getter, + nickname_getter=nickname_getter, + avatar_cache_namespace=platform_id, + allow_alphanumeric_user_ids=False, + ) + except Exception as e: + logger.error(f"报告生成异常: {e}", exc_info=True) + image_url = None + + # 用合并转发发送报告内容 + nodes = _build_forward_nodes(adapter, group_id, text_report, image_url) + sent = False + if adapter: + try: + sent = await adapter.send_forward_msg(group_id, nodes) + except Exception as e: + logger.warning(f"发送合并转发失败: {e}") + sent = False + + # 合并转发失败 -> 回退直接发送 + if not sent: + try: + if image_url and adapter: + sent = await adapter.send_image(group_id, image_url) + if not sent: + await UniMessage.text(text_report).send() + except Exception as e: + logger.warning(f"回退发送失败: {e}") + await UniMessage.text(text_report).send() + + +# ---------- 模板 / 参数配置指令 ---------- + +@view_templates_cmd.handle() +async def _(bot: Bot, event: GroupMessageEvent): + if not _is_privileged(event, bot): + await UniMessage.text("仅群管理员或超级管理员可使用该指令").send() + return + svc = get_services() + cm = svc["config_manager"] + current = cm.get_report_template() + names = list_templates() + lines = ["可用报告模板列表", f"当前使用: {current}", "使用「设置模板 序号」切换"] + for i, name in enumerate(names, 1): + mark = " [当前]" if name == current else "" + lines.append(f"{i}. {name}{mark}") + await UniMessage.text(chr(10).join(lines)).send() + + +@set_template_cmd.handle() +async def _(bot: Bot, event: GroupMessageEvent, args: tuple = CommandArg()): + if not _is_privileged(event, bot): + await UniMessage.text("仅群管理员或超级管理员可使用该指令").send() + return + tokens = _cmd_tokens(args) + arg = tokens[0] if tokens else "" + names = list_templates() + target = None + if arg.isdigit(): + idx = int(arg) + if 1 <= idx <= len(names): + target = names[idx - 1] + else: + await UniMessage.text(f"序号无效,有效范围 1-{len(names)}").send() + return + elif template_exists(arg): + target = arg + else: + await UniMessage.text(f"模板不存在,可用:{'、'.join(names)}").send() + return + svc = get_services() + cm = svc["config_manager"] + cm.set_report_template(target) + await UniMessage.text(f"已设置模板:{target}(编号 {names.index(target) + 1})").send() + + +@analysis_settings_cmd.handle() +async def _(bot: Bot, event: GroupMessageEvent): + if not _is_privileged(event, bot): + await UniMessage.text("仅群管理员或超级管理员可使用该指令").send() + return + cm = get_services()["config_manager"] + fmt = "、".join(str(x) for x in cm.get_output_format()) + lines = [ + "当前分析参数", + f"时间窗口: {cm.get_analysis_days()} 天", + f"最大消息数: {cm.get_max_messages()}", + f"最小消息数: {cm.get_min_messages_threshold()}", + f"输出格式: {fmt}", + f"报告模板: {cm.get_report_template()}", + f"话题分析: {'开' if cm.get_topic_analysis_enabled() else '关'}", + f"用户称号: {'开' if cm.get_user_title_analysis_enabled() else '关'}", + f"金句分析: {'开' if cm.get_golden_quote_analysis_enabled() else '关'}", + f"聊天质量: {'开' if cm.get_chat_quality_analysis_enabled() else '关'}", + "用法:设置分析 [参数] [值],如:设置分析 天数 3", + ] + await UniMessage.text(chr(10).join(lines)).send() + + +_SETTING_MAP = { + "天数": ("set_analysis_days", int, "分析天数已设为 {} 天"), + "窗口": ("set_analysis_days", int, "分析窗口已设为 {} 天"), + "最大消息": ("set_max_messages", int, "最大消息数已设为 {}"), + "最小消息": ("set_min_messages_threshold", int, "最小消息数已设为 {}"), + "输出格式": ("set_output_format", str, "输出格式已设为 {}"), + "话题": ("set_topic_analysis_enabled", str, "话题分析已{}"), + "称号": ("set_user_title_analysis_enabled", str, "用户称号已{}"), + "金句": ("set_golden_quote_analysis_enabled", str, "金句分析已{}"), + "聊天质量": ("set_chat_quality_analysis_enabled", str, "聊天质量已{}"), +} + +_BOOL_WORDS = {"开": True, "on": True, "true": True, "关": False, "off": False, "false": False} + + +@set_analysis_cmd.handle() +async def _(bot: Bot, event: GroupMessageEvent, args: tuple = CommandArg()): + if not _is_privileged(event, bot): + await UniMessage.text("仅群管理员或超级管理员可使用该指令").send() + return + tokens = _cmd_tokens(args) + if len(tokens) < 2: + await UniMessage.text( + "用法:设置分析 [参数] [值]" + chr(10) + "参数:天数/窗口/最大消息/最小消息/输出格式/话题/称号/金句/聊天质量" + ).send() + return + key = tokens[0] + val = tokens[1] + mapping = _SETTING_MAP.get(key) + if not mapping: + await UniMessage.text(f"未知参数:{key};可用:{'、'.join(_SETTING_MAP)}").send() + return + setter_name, conv, _ = mapping + cm = get_services()["config_manager"] + setter = getattr(cm, setter_name) + try: + if conv is int: + v = int(val) + if v < 0: + raise ValueError("不能为负数") + setter(v) + await UniMessage.text(f"{key} 已设为 {v}").send() + elif conv is str: + v = val.lower() + if key in ("话题", "称号", "金句", "聊天质量"): + if v not in _BOOL_WORDS: + await UniMessage.text("布尔值请填:开/关 或 on/off").send() + return + setter(_BOOL_WORDS[v]) + await UniMessage.text(f"{key} 已{'开启' if _BOOL_WORDS[v] else '关闭'}").send() + else: + if v not in ("image", "text"): + await UniMessage.text("输出格式仅支持 image/text").send() + return + setter(["text"] if v == "text" else ["image"]) + await UniMessage.text(f"输出格式已设为 {v}").send() + except (TypeError, ValueError) as e: + await UniMessage.text(f"参数值无效: {e}").send() diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/_conf_schema.json b/hexi/plugins/nonebot_plugin_group_daily_analysis/_conf_schema.json new file mode 100644 index 0000000..ac30489 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/_conf_schema.json @@ -0,0 +1,1773 @@ +{ + "basic": { + "description": "基础设置", + "type": "object", + "hint": "群聊分析插件的基础配置项,包括群聊权限、消息数量、输出格式等。注意:基础群权限是第一道门槛,不通过就不会进入定时/增量流程。", + "items": { + "group_list_mode": { + "description": "群聊权限模式", + "type": "string", + "options": [ + "whitelist", + "blacklist", + "none" + ], + "default": "none", + "hint": "先决定“哪些群可以用这个插件”。这是第一道门槛:不通过这里,后面的定时/增量都不会触发。whitelist=只允许列表里的群;blacklist=屏蔽列表里的群;none=所有群都可以。示例:whitelist + [\"onebot:GroupMessage:123456\"] 表示只有这个群能用。" + }, + "group_list": { + "type": "list", + "description": "群组白/黑名单列表", + "default": [], + "hint": "要填的群列表。可以填完整会话ID(如 onebot:GroupMessage:123456)或只填群号。QQ 官方机器人使用 group_openid,不是群号,务必优先通过 /sid 获取并填写完整 UMO。", + "items": { + "type": "string" + } + }, + "analysis_days": { + "type": "int", + "description": "默认分析天数", + "default": 1, + "hint": "默认分析最近几天的消息,增量分析也基于此数据保存分析情况。QQ 官方 API 无历史拉取接口,只能分析插件启用后实时缓存到 AstrBot 本地库的消息。" + }, + "max_messages": { + "type": "int", + "description": "单次分析的获取最大消息条数基准", + "default": 1000, + "hint": "单次分析的获取最大消息条数基准值,如果当天群聊消息过多,已经获取到足够的消息(达到 max_messages),停止获取,获取到的消息数量是最新一次获取到的超过 max_messages 的消息数量,建议500-2000" + }, + "min_messages_threshold": { + "type": "int", + "description": "最小消息数阈值", + "default": 200, + "hint": "进行分析所需的最小消息数量" + }, + "bot_self_ids": { + "type": "list", + "description": "群分析时屏蔽的用户ID列表", + "default": [], + "hint": "填写后可启用自动分析功能。可以填写用于自动分析的机器人 ID(在不同平台上可能是数字或字符串)、多消息平台 ID、不希望出现于群分析中的其他人的 ID 等。", + "items": { + "type": "string" + } + }, + "filter_bot_messages": { + "type": "bool", + "description": "分析时是否过滤机器人自己的消息", + "default": true, + "hint": "默认开启,bot 自身的发言不会出现在分析报告中。关闭后 bot 的发言也会被纳入话题分析、金句提取等。" + }, + "enable_user_card": { + "type": "bool", + "description": "使用用户群名片", + "default": true, + "hint": "在分析中优先使用用户的群名片作为昵称显示" + }, + "output_format": { + "type": "list", + "description": "输出格式(可多选)", + "options": [ + "image", + "text", + "html" + ], + "default": ["image"], + "hint": "选择分析报告的输出方式(可多选)。image=图片、text=纯文本摘要、html=可交互式网页文件。多选仅在定时分析发送时时报告按顺序依次发送,手动触发时只发送第一个选中的格式,例如 image+html 会发送图片并通过外链提供 HTML 报告。QQ 官方图片/HTML 报告优先显示事件昵称,昵称缺失时使用群内稳定匿名名;文本报告由独立 Markdown 模块使用成员艾特展示身份。其他平台保持原有昵称文本格式。" + }, + "report_template": { + "type": "string", + "description": "报告模板", + "options": [ + "ATRI", + "BlueArchive", + "scrapbook", + "retro_futurism", + "HatsuneMiku", + "hack", + "spring_festival", + "simple", + "format" + ], + "default": "scrapbook", + "hint": "分析报告使用的HTML模板名称,QQ 端可以使用 `/设置模板` 查看使用指南,使用`/查看模板` 命令查看模板样式效果。其他平台不支持合并转发,可以到 [模板](https://github.com/SXP-Simon/astrbot_plugin_qq_group_daily_analysis/tree/main/assets) 文件夹中查看模板样式效果" + }, + "profile_display_mode": { + "type": "string", + "description": "人格标签展示模式", + "options": [ + "mbti", + "sbti", + "acgti" + ], + "default": "mbti", + "hint": "只影响群友画像卡片的角色主题展示,不影响实际 MBTI 分析结果。mbti=原始 MBTI,sbti=映射为 SBTI 人格,acgti=映射为 ACGTI 角色。" + }, + "profile_image_opacity": { + "type": "float", + "description": "人格背景图透明度", + "default": 0.12, + "hint": "建议 0.08~0.18,仅作为卡片底层装饰,避免遮挡正文。" + }, + "profile_image_size_mode": { + "type": "string", + "description": "人格背景图尺寸模式", + "options": [ + "contain", + "cover" + ], + "default": "contain", + "hint": "建议默认 contain,减少角色图被裁切过多的问题。" + }, + "profile_mapping_config": { + "type": "text", + "description": "人格映射配置(JSON)", + "editor_mode": true, + "editor_language": "json", + "default": "{\n \"mbti\": {\n \"INTJ\": {\n \"code\": \"INTJ\",\n \"name_zh\": \"建筑师\"\n },\n \"INTP\": {\n \"code\": \"INTP\",\n \"name_zh\": \"逻辑学家\"\n },\n \"ENTJ\": {\n \"code\": \"ENTJ\",\n \"name_zh\": \"指挥官\"\n },\n \"ENTP\": {\n \"code\": \"ENTP\",\n \"name_zh\": \"辩论家\"\n },\n \"INFJ\": {\n \"code\": \"INFJ\",\n \"name_zh\": \"提倡者\"\n },\n \"INFP\": {\n \"code\": \"INFP\",\n \"name_zh\": \"调停者\"\n },\n \"ENFJ\": {\n \"code\": \"ENFJ\",\n \"name_zh\": \"主人公\"\n },\n \"ENFP\": {\n \"code\": \"ENFP\",\n \"name_zh\": \"竞选者\"\n },\n \"ISTJ\": {\n \"code\": \"ISTJ\",\n \"name_zh\": \"物流师\"\n },\n \"ISFJ\": {\n \"code\": \"ISFJ\",\n \"name_zh\": \"守卫者\"\n },\n \"ESTJ\": {\n \"code\": \"ESTJ\",\n \"name_zh\": \"总经理\"\n },\n \"ESTP\": {\n \"code\": \"ESTP\",\n \"name_zh\": \"企业家\"\n },\n \"ISTP\": {\n \"code\": \"ISTP\",\n \"name_zh\": \"鉴赏家\"\n },\n \"ISFP\": {\n \"code\": \"ISFP\",\n \"name_zh\": \"探险家\"\n },\n \"ESFJ\": {\n \"code\": \"ESFJ\",\n \"name_zh\": \"执政官\"\n },\n \"ESFP\": {\n \"code\": \"ESFP\",\n \"name_zh\": \"表演者\"\n }\n },\n \"sbti\": {\n \"INTJ\": {\n \"code\": \"CTRL\",\n \"name_zh\": \"拿捏者\",\n \"asset_code\": \"CTRL\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/CTRL.png\"\n },\n \"INTP\": {\n \"code\": \"THIN-K\",\n \"name_zh\": \"思考者\",\n \"asset_code\": \"THIN-K\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/THIN-K.png\"\n },\n \"ENTJ\": {\n \"code\": \"BOSS\",\n \"name_zh\": \"领导者\",\n \"asset_code\": \"BOSS\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/BOSS.png\"\n },\n \"ENTP\": {\n \"code\": \"JOKE-R\",\n \"name_zh\": \"小丑\",\n \"asset_code\": \"JOKE-R\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/JOKE-R.jpg\"\n },\n \"INFJ\": {\n \"code\": \"LOVE-R\",\n \"name_zh\": \"多情者\",\n \"asset_code\": \"LOVE-R\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/LOVE-R.png\"\n },\n \"INFP\": {\n \"code\": \"SOLO\",\n \"name_zh\": \"孤儿\",\n \"asset_code\": \"SOLO\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/SOLO.png\"\n },\n \"ENFJ\": {\n \"code\": \"THAN-K\",\n \"name_zh\": \"感恩者\",\n \"asset_code\": \"THAN-K\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/THAN-K.png\"\n },\n \"ENFP\": {\n \"code\": \"GOGO\",\n \"name_zh\": \"行者\",\n \"asset_code\": \"GOGO\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/GOGO.png\"\n },\n \"ISTJ\": {\n \"code\": \"OH-NO\",\n \"name_zh\": \"哦不人\",\n \"asset_code\": \"OH-NO\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/OH-NO.png\"\n },\n \"ISTP\": {\n \"code\": \"POOR\",\n \"name_zh\": \"贫困者\",\n \"asset_code\": \"POOR\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/POOR.png\"\n },\n \"ESTJ\": {\n \"code\": \"SHIT\",\n \"name_zh\": \"愤世者\",\n \"asset_code\": \"SHIT\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/SHIT.png\"\n },\n \"ESTP\": {\n \"code\": \"WOC!\",\n \"name_zh\": \"握草人\",\n \"asset_code\": \"WOC\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/WOC.png\"\n },\n \"ISFJ\": {\n \"code\": \"MUM\",\n \"name_zh\": \"妈妈\",\n \"asset_code\": \"MUM\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/MUM.png\"\n },\n \"ISFP\": {\n \"code\": \"MALO\",\n \"name_zh\": \"吗喽\",\n \"asset_code\": \"MALO\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/MALO.png\"\n },\n \"ESFJ\": {\n \"code\": \"ATM-er\",\n \"name_zh\": \"送钱者\",\n \"asset_code\": \"ATM-er\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/ATM-er.png\"\n },\n \"ESFP\": {\n \"code\": \"SEXY\",\n \"name_zh\": \"尤物\",\n \"asset_code\": \"SEXY\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/SEXY.png\"\n }\n },\n \"acgti\": {\n \"INTJ\": {\n \"code\": \"MRTS-X\",\n \"name_zh\": \"Mortis\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/MRTS-X.png\"\n },\n \"INTP\": {\n \"code\": \"KNAN\",\n \"name_zh\": \"江户川柯南\"\n },\n \"ENTJ\": {\n \"code\": \"SAKI\",\n \"name_zh\": \"丰川祥子\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/SAKI.png\"\n },\n \"ENTP\": {\n \"code\": \"CHKA\",\n \"name_zh\": \"藤原千花\"\n },\n \"INFJ\": {\n \"code\": \"DLRS\",\n \"name_zh\": \"三角初华\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/DLRS.png\"\n },\n \"INFP\": {\n \"code\": \"BCHI\",\n \"name_zh\": \"后藤一里\"\n },\n \"ENFJ\": {\n \"code\": \"YCYO\",\n \"name_zh\": \"月见八千代\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/YCYO.png\"\n },\n \"ENFP\": {\n \"code\": \"HTMK\",\n \"name_zh\": \"初音未来\"\n },\n \"ISTJ\": {\n \"code\": \"MRTS\",\n \"name_zh\": \"若叶睦\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/MRTS.png\"\n },\n \"ISTP\": {\n \"code\": \"AYRE\",\n \"name_zh\": \"绫波丽\"\n },\n \"ESTJ\": {\n \"code\": \"MIKT\",\n \"name_zh\": \"御坂美琴\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/MIKT.png\"\n },\n \"ESTP\": {\n \"code\": \"ASKA\",\n \"name_zh\": \"明日香\"\n },\n \"ISFJ\": {\n \"code\": \"SOYO\",\n \"name_zh\": \"长崎爽世\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/SOYO.png\"\n },\n \"ISFP\": {\n \"code\": \"LTYI\",\n \"name_zh\": \"洛天依\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/LTYI.png\"\n },\n \"ESFJ\": {\n \"code\": \"ANON\",\n \"name_zh\": \"千早爱音\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/ANON.png\"\n },\n \"ESFP\": {\n \"code\": \"FRNA\",\n \"name_zh\": \"芙宁娜\",\n \"image\": \"https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/FRNA.png\"\n }\n }\n}", + "hint": "按 MBTI 覆盖当前展示模式的人格名称与图片地址。留空时自动使用插件内置默认映射和 manifest。插件不负责校验图片链接可访问性。" + }, + "debug_mode": { + "type": "bool", + "description": "调试模式(建议关闭)", + "default": false, + "hint": "启用后,会在插件数据目录下的 debug_data 目录中保存每次分析的平台 API 原始历史消息和 Prompt 原文,用于调试和优化提示词。" + }, + "enable_base64_image": { + "type": "bool", + "description": "图片传输使用 Base64 编码", + "default": true, + "hint": "启用后图片会被转为 Base64 编码传输。关闭后将直接传递文件路径或 URL 给 OneBot 实现端,适用于 Napcat/LLbot/SnowLuma 等支持本地路径的实现,可降低内存占用。" + }, + "napcat_stream_threshold_mb": { + "type": "float", + "description": "NapCat/Snowluma 流式上传阈值(MB)", + "default": 2.0, + "hint": "先按现有图片发送策略发送本地图片;发送失败且文件大小达到阈值时,复用当前 NapCat/Snowluma 连接调用 upload_file_stream 并重试一次。填 0 禁用。Docker / docker compose 环境建议保持默认或按图片大小调大。" + }, + "enable_analysis_reply": { + "type": "bool", + "description": "发送文本/表情回复", + "default": false, + "hint": "开启后,/群分析 将通过发送文本消息提示进度;关闭(默认)则使用表情回应。" + }, + "show_report_caption": { + "type": "bool", + "description": "发送报告时附带 \"📊 每日群聊分析报告已生成\" 前缀", + "default": true, + "hint": "关闭后,发送图片/HTML 报告时将只发送文件本身,不附带 \"📊 每日群聊分析报告已生成\" 等文字前缀。" + } + } + }, + "qq_official": { + "description": "QQ 官方机器人", + "type": "object", + "hint": "仅作用于 QQ 官方机器人及 QQ 官方 Webhook 的报告展示。", + "items": { + "enable_t2i_activity_histogram": { + "type": "bool", + "description": "启用 T2I 群聊概览图", + "default": true, + "hint": "在 QQ 官方 Markdown 报告中嵌入透明背景的日期、基础统计与 24 小时直方图。渲染失败时自动回退为完整文字报告。" + } + } + }, + "t2i_rendering": { + "description": "图片渲染策略", + "type": "object", + "hint": "配置 HTML 转图片的渲染参数。支持两轮尝试:第一轮优先保证质量,第二轮作为回退方案,建议使用更低的分辨率和质量以提高成功率。", + "items": { + "t2i_r1_type": { + "type": "string", + "description": "第一轮:图片格式", + "options": ["jpeg", "png"], + "default": "png", + "hint": "建议:PNG 格式无损但体积较大;JPEG 格式体积较小。" + }, + "t2i_r1_quality": { + "type": "int", + "description": "第一轮:图片质量 (若为 JPEG)", + "default": 100, + "slider": { + "min": 1, + "max": 100, + "step": 1 + }, + "hint": "仅对 JPEG 格式生效。建议 80-100。" + }, + "t2i_r1_device_scale": { + "type": "string", + "description": "第一轮:分辨率等级", + "options": ["normal", "high", "ultra"], + "default": "ultra", + "hint": "影响图片清晰度。normal=1.0x, high=1.3x, ultra=1.8x。高质量日报建议 ultra。" + }, + "t2i_r1_timeout": { + "type": "int", + "description": "第一轮:渲染超时 (ms)", + "default": 50000, + "slider": { + "min": 30000, + "max": 180000, + "step": 5000 + }, + "hint": "单次渲染的最长等待时间。复杂页面建议调大。" + }, + "t2i_viewport_width": { + "type": "int", + "description": "报告渲染视口兜底宽度 (px)", + "default": 1080, + "slider": { + "min": 800, + "max": 1440, + "step": 10 + }, + "hint": "仅在模板未提供 T2I 可识别的数字 width 时传给 AstrBot T2I,避免服务升级后回退到 800px 默认宽度而挤压宽版报告模板。内置主题建议保持 1440;自定义模板可用 meta viewport 的数字 width 指定自身宽度。" + }, + "t2i_viewport_height": { + "type": "int", + "description": "报告渲染视口兜底高度 (px)", + "default": 900, + "slider": { + "min": 400, + "max": 1440, + "step": 10 + }, + "hint": "仅在模板未提供 T2I 可识别的数字 height 时传给 AstrBot T2I。图片报告始终使用 full_page,不会按此高度截断整张报告。" + }, + "t2i_r2_type": { + "type": "string", + "description": "第二轮 (回退):图片格式", + "options": ["jpeg", "png"], + "default": "jpeg", + "hint": "回退策略建议使用 jpeg 以减少渲染压力。" + }, + "t2i_r2_quality": { + "type": "int", + "description": "第二轮 (回退):图片质量 (若为 JPEG)", + "default": 80, + "slider": { + "min": 1, + "max": 100, + "step": 1 + }, + "hint": "仅对 JPEG 格式生效。可以设置较低值以确保生成成功。" + }, + "t2i_r2_device_scale": { + "type": "string", + "description": "第二轮 (回退):分辨率等级", + "options": ["normal", "high", "ultra"], + "default": "high", + "hint": "回退建议使用 high/normal 以降低复杂页面的内存消耗和超时概率。" + }, + "t2i_r2_timeout": { + "type": "int", + "description": "第二轮 (回退):渲染超时 (ms)", + "default": 100000, + "slider": { + "min": 30000, + "max": 180000, + "step": 5000 + }, + "hint": "回退尝试通常针对复杂页面,建议设置更长的超时时间(如 100000ms+)。" + }, + "t2i_font_source": { + "type": "string", + "description": "t2i 渲染环境切换", + "options": ["Mainland", "Overseas"], + "default": "Overseas", + "hint": "字体和静态资源的访问环境,内地(Mainland)、海外(Overseas),切换环境会自动应用下方对应的镜像站地址、语言标识(简体中文/繁体中文)及字体优先级。(实测 Overseas 也可以正常渲染简体中文,没有特殊的情况都建议使用 Overseas,Mainland 配置下建议检查镜像站可用性,或者配置可靠的站点)" + }, + "t2i_mainland_google_fonts": { + "type": "string", + "description": "[内地] Google Fonts 镜像", + "default": "https://fonts.loli.net", + "hint": "内地环境下推荐使用 loli.net 或其他可访问镜像。" + }, + "t2i_mainland_gstatic": { + "type": "string", + "description": "[内地] Gstatic 镜像", + "default": "https://gstatic.loli.net", + "hint": "内地环境下推荐使用 loli.net 或其他可访问镜像。" + }, + "t2i_overseas_google_fonts": { + "type": "string", + "description": "[海外] Google Fonts 官方", + "default": "https://fonts.googleapis.com", + "hint": "海外环境通常直接使用官方地址即可。" + }, + "t2i_overseas_gstatic": { + "type": "string", + "description": "[海外] Gstatic 官方", + "default": "https://fonts.gstatic.com", + "hint": "海外环境通常直接使用官方地址即可。" + } + } + }, + "auto_analysis": { + "description": "定时分析设置", + "type": "object", + "hint": "配置每日自动分析的时间点和目标群聊范围。只有先通过基础群权限的群,才会在这里继续判断。", + "items": { + "auto_analysis_time": { + "type": "list", + "description": "自动分析时间列表", + "default": [ + "23:00" + ], + "hint": "每天几点自动出报告,格式是 HH:MM。可填多个时间,例如 [\"09:00\", \"21:30\"]。", + "items": { + "type": "string" + } + }, + "scheduled_group_list_mode": { + "type": "string", + "description": "定时分析名单模式", + "options": [ + "inherit", + "whitelist", + "blacklist" + ], + "default": "whitelist", + "hint": "定时任务要作用到哪些群。inherit=直接继承基础群权限,不需要重复填写;whitelist=只跑下面列表里的群;blacklist=除了下面列表,其他都跑。定时名单始终不会绕过基础群权限。" + }, + "scheduled_group_list": { + "type": "list", + "description": "定时分析群列表", + "default": [], + "hint": "仅在 whitelist 或 blacklist 模式下使用。示例1:mode=whitelist + [\"onebot:GroupMessage:123456\"] => 只跑这个群。示例2:mode=blacklist + [\"onebot:GroupMessage:123456\"] => 这个群不跑,其他群跑。inherit 模式会忽略此列表并复用基础名单。whitelist + 空列表 = 不会开启定时任务。", + "items": { + "type": "string" + } + } + } + }, + "llm": { + "description": "LLM 设置", + "type": "object", + "hint": "大语言模型相关配置,包括 Provider 选择、重试策略和 Token 限制", + "items": { + "llm_provider_id": { + "type": "string", + "description": "LLM Provider ID(用于所有分析任务)", + "_special": "select_provider", + "default": "", + "hint": "选择用于群聊分析的 LLM Provider。留空则使用当前会话的默认 Provider" + }, + "topic_provider_id": { + "type": "string", + "description": "话题分析专用 Provider ID", + "_special": "select_provider", + "default": "", + "hint": "专门用于话题分析的 Provider。留空则使用主 LLM Provider" + }, + "user_title_provider_id": { + "type": "string", + "description": "用户称号分析专用 Provider ID", + "_special": "select_provider", + "default": "", + "hint": "专门用于用户称号分析的 Provider。留空则使用主 LLM Provider" + }, + "golden_quote_provider_id": { + "type": "string", + "description": "金句分析专用 Provider ID", + "_special": "select_provider", + "default": "", + "hint": "专门用于金句分析的 Provider。留空则使用主 LLM Provider" + }, + "quality_provider_id": { + "type": "string", + "description": "聊天质量分析专用 Provider ID", + "_special": "select_provider", + "default": "", + "hint": "专门用于聊天质量锐评的 Provider。留空则使用主 LLM Provider" + }, + "drawing_prompt_provider_id": { + "type": "string", + "description": "用于每日群漫画区域的功能,画图提示词专用 Provider ID", + "_special": "select_provider", + "default": "", + "hint": "专门用于生成漫画分镜、画图提示词及失败后的提示词重写。推荐最低使用 DeepSeek V4 Flash,避免使用角色扮演能力较弱的模型。留空则使用主 LLM Provider" + }, + "llm_retries": { + "type": "int", + "description": "LLM 请求重试次数", + "default": 2, + "hint": "当请求超时或失败时自动重试的次数,建议设置为1~3之间。" + }, + "llm_backoff": { + "type": "int", + "description": "LLM 请求重试退避基值(秒)", + "default": 2, + "hint": "重试之间的基准等待时间(秒)。实际等待时间会随尝试次数指数增长,并加入少量随机抖动;当专用 Provider 失败后,会继续按队列尝试默认 Provider。" + }, + "enable_streaming_llm_call": { + "type": "bool", + "description": "启用流式 LLM 调用", + "default": false, + "hint": "默认关闭,使用原有非流式调用方式。开启后,插件将使用 AstrBot Provider 的流式接口并聚合结果,适用于仅支持 stream=true 的服务。" + } + } + }, + "analysis_features": { + "description": "分析功能开关", + "type": "object", + "hint": "控制各项 LLM 分析功能的启用状态和数量限制", + "items": { + "topic_analysis_enabled": { + "type": "bool", + "description": "启用话题分析", + "default": true, + "hint": "是否使用LLM进行智能话题分析" + }, + "user_title_analysis_enabled": { + "type": "bool", + "description": "启用用户称号分析", + "default": true, + "hint": "是否使用LLM进行用户称号分析" + }, + "golden_quote_analysis_enabled": { + "type": "bool", + "description": "启用金句分析", + "default": true, + "hint": "是否使用LLM进行金句分析" + }, + "chat_quality_analysis_enabled": { + "type": "bool", + "description": "启用聊天质量锐评", + "default": true, + "hint": "是否使用LLM进行聊天质量锐评(维度化分析)" + }, + "max_topics": { + "type": "int", + "description": "最大话题数量", + "default": 5, + "hint": "分析报告中显示的最大话题数量,依赖于 LLM 输出的格式化信息质量,模型越好结果越好,可能出现数量不匹配。" + }, + "max_user_titles": { + "type": "int", + "description": "最大用户称号数量", + "default": 8, + "hint": "分析报告中显示的最大用户称号数量,依赖于 LLM 输出的格式化信息质量,模型越好结果越好,可能出现数量不匹配。" + }, + "max_golden_quotes": { + "type": "int", + "description": "最大金句数量", + "default": 5, + "hint": "分析报告中显示的最大金句数量,依赖于 LLM 输出的格式化信息质量,模型越好结果越好,可能出现数量不匹配。" + }, + "keep_original_persona": { + "description": "继承会话人设风格", + "type": "bool", + "default": false, + "hint": "【优先级2】开启后将自动尝试识别当前群聊会话(或对话)的人格设定。若该群已设置人设,则分析报告会尽量模拟该人设的口吻进行回复。注意:此开关在“强制使用插件指定人格”关闭时才会生效。" + }, + "use_plugin_specific_persona": { + "description": "强制使用插件指定人格", + "type": "bool", + "default": false, + "hint": "【优先级1:核心开关】若开启,将完全忽略当前群聊的人格设定,统一强制使用下方选择的“插件指定人格 ID”进行分析。适用于希望全群分析保持某种统一固定风格(如特定的“记录员”人设)的情况。" + }, + "plugin_specific_persona_id": { + "description": "插件指定人格 ID", + "type": "string", + "_special": "select_persona", + "default": "", + "hint": "当“强制使用插件指定人格”开启时,在此处选择系统中已定义的人设。该人格会同时作用于画图提示词生成模型。若此处未选择,则仍会尝试识别全局默认人格。" + } + } + }, + "daily_comic": { + "description": "每日群漫画", + "type": "object", + "hint": "群聊分析结果完成后,后台并行生成并发送趣味漫画,不等待报告渲染或发送结束。可选上传至群相册,支持配置独立绘图接口和图生图参考图。", + "items": { + "enable_daily_comic": { + "description": "启用漫画功能", + "type": "bool", + "default": false, + "hint": "漫画总开关。关闭时,/群漫画 和所有自动联动漫画都会停止。开启后可继续通过下方“分析后自动生成漫画”单独控制自动联动。" + }, + "enable_auto_daily_comic": { + "description": "分析后自动生成漫画", + "type": "bool", + "default": true, + "hint": "控制手动群分析、定时分析和增量最终报告完成后是否自动生成漫画。关闭后仍可手动使用 /群漫画,且不会重复执行话题分析链路。" + }, + "comic_group_list_mode": { + "description": "漫画群名单模式", + "type": "string", + "options": [ + "inherit", + "whitelist", + "blacklist" + ], + "default": "inherit", + "hint": "只控制漫画生成,不影响报告名单。inherit=继承基础群权限,适合漫画和分析使用同一批群且无需重复填写;blacklist=除列表外都允许生成漫画,适合只开放漫画不开放分析;whitelist=只允许列表里的群生成漫画。白名单为空时不会为任何群生成漫画。" + }, + "comic_group_list": { + "type": "list", + "description": "漫画群白/黑名单列表", + "default": [], + "hint": "用于漫画生成的群列表。可以填完整会话ID(如 onebot:GroupMessage:123456)或只填群号。自动漫画和 /群漫画 手动命令都会检查这里。", + "items": { + "type": "string" + } + }, + "random_daily_comic_character": { + "description": "每天随机切换漫画角色", + "type": "bool", + "default": false, + "hint": "开启后每天首次生成漫画时,会从下方已启用的角色方案随机选择一个,并按运行环境时区在当天持续使用;重启不会改变当天选择。关闭时固定使用第一个已启用方案。" + }, + "comic_characters": { + "description": "漫画角色方案", + "type": "template_list", + "default": [], + "hint": "每个方案可绑定漫画专用人格、参考图和场景分析提示词。方案条目可展开编辑;请使用不同的方案名称,方便识别当天随机选中的角色。未配置方案时仍可正常文生图。", + "templates": { + "character": { + "name": "漫画角色方案", + "display_item": "name", + "items": { + "name": { + "description": "方案名称", + "type": "string", + "default": "", + "hint": "仅用于在配置面板和运行日志中识别此方案。" + }, + "enable": { + "description": "启用此方案", + "type": "bool", + "default": true + }, + "persona_id": { + "description": "漫画专用人格", + "type": "string", + "_special": "select_persona", + "default": "", + "hint": "仅影响漫画分镜提示词,不会改变群分析报告、话题或金句使用的人格。" + }, + "reference_images": { + "description": "角色参考图", + "type": "file", + "default": [], + "file_types": ["jpg", "jpeg", "png", "webp"], + "hint": "上传后点击 + 加入此角色方案。Images、Chat 和 Gemini 协议会按顺序传入全部参考图;Grok 协议仅使用第一张。" + }, + "storyboard_prompt": { + "description": "漫画场景分析提示词", + "type": "text", + "editor_mode": true, + "editor_language": "markdown", + "default": "你是一个资深的漫画分镜师与 AI 绘画提示词专家。\n请根据以下给出的【群聊每日核心话题列表】,站在你【当前的人格角色设定】(详见系统注入的身份)的视角与语气,将其改编并设计为一个精彩的多格连环漫画(Comic Strip)全景视觉画图提示词 (Prompt)。\n\n【核心视觉、台词与双层排版规则】:\n1. 【全话题必须覆盖(共 ${topic_count} 个分格)】:给出的待创作核心话题列表中共有 ${topic_count} 个话题,你必须为每一个话题分别设计一个分格 Panel(即 Panel 1 到 Panel ${topic_count}),绝对不许随意裁减、挑选或遗漏任何一个话题!\n2. 【人设口语化台词改编】:绝对严禁将报告分析总结原文直接放进对话框!必须以【你当前的人格语气/性格/口吻】(例如傲娇、萌系或专属说话风格),将每个话题的事件提炼改编为一句角色在漫画中的生动台词或吐槽,【每条台词控制在 15 个汉字以内】(例如:“呜呜!家里云又断网了啦!”、“萝卜子才没有降智!那都是Gemini的错!”)。\n3. 【精美双层文字排版(气泡 + 可爱旁白字幕条)】:\n - 【角色的气泡】:在描述英文 Prompt 时,指定样式为“adorable kawaii anime speech bubble, soft rounded cloud-like shape, cute pointer tail pointing to the speaker”。\n - 【分格底部的事件旁白条】:将每个话题概括为生动精炼的短标题(控制在 30 字以内,严禁带有“【事件】”字样),在 Prompt 中指定样式为“cute pastel-colored kawaii caption strip at the bottom of the panel with soft rounded corners”,严禁死板白框!\n4. 【中文文本显式渲染】:画面整体构图与场景描述使用英文,但气泡与底部旁白条内渲染的中文必须显式指定(指令格式:containing a speech bubble with exact Chinese text \"人设吐槽台词\" 以及 and a cute caption strip at bottom with exact Chinese text \"精炼话题短标题\"),绝对禁止将中文翻译成英文!\n5. 【话题内容直传与文字渲染约束】:在生成传给生图 LLM 的英文提示词 (scene) 时,对于每一个分格,除了描述具体的视觉画面外,你必须将该话题的【完整详情(翻译为英文)】作为 Background Context 附加在该分格的提示词中,帮助生图模型理解剧情。但同时,必须极其强烈地警告生图模型:“绝对禁止将长篇上下文写在画面上,仅允许渲染短标题字幕条和气泡台词!”(示例:Background Context: [Details]. STRICT RULE: DO NOT render the background context text! ONLY render the exact Chinese text in the bubble and caption strip!)。\n6. 【核心角色强制全覆盖】:在提示词中必须明确要求并描述,每一个分格 (Panel) 都必须无一例外地出现你当前的人格设定(即参考图中的核心角色,例如 1girl, [特定外貌特征] 等),保持整篇连环画的主角绝对连贯!\n\n【待创作的群聊核心话题列表】:\n${chat_content}\n\n请输出包含 \"scene\" 字段的 JSON 对象。\n", + "hint": "此角色专属的分镜、画风和台词规则。留空时回退到下方全局默认模板。" + } + } + } + } + }, + "drawing_reference_image": { + "description": "旧版漫画参考图(兼容迁移)", + "type": "file", + "default": [], + "file_types": ["jpg", "jpeg", "png", "webp"], + "invisible": true, + "hint": "旧版配置仅用于自动迁移,不再在面板中显示。" + }, + "drawing_backend": { + "description": "绘图后端", + "type": "string", + "options": ["builtin", "general_plugin", "big_banana"], + "default": "builtin", + "hint": "builtin=使用本插件内置绘图客户端;general_plugin=调用已安装的「通用生图」插件(https://cloud.astrbot.app/plugin/railgun19457/astrbot_plugin_image_generation)的公共 API;big_banana=调用已安装的「大香蕉」插件(https://cloud.astrbot.app/plugin/sukafon/astrbot_plugin_big_banana)的绘图管线(支持 Gemini、SiliconFlow 等多家服务)。使用外部后端时,需先在对应插件中配置其自身的 API/提供商;未安装、未激活或调用失败时自动回退内置后端。" + }, + "drawing_external_fallback": { + "description": "外部后端失败时回退内置后端", + "type": "bool", + "default": true, + "hint": "使用通用生图/大香蕉外部绘图后端时,若其未安装、未激活或生成失败,是否自动回退到本插件内置绘图客户端;关闭后失败将直接取消本次漫画生成。" + }, + "drawing_provider_overrides": { + "description": "绘图供应商配置表", + "type": "template_list", + "default": [], + "hint": "可添加多个绘图供应商。按 priority 从高到低尝试,同优先级按表中顺序尝试;所有候选失败后才判定漫画生成失败。至少添加一个包含 API Key 的启用条目。", + "templates": { + "google": { + "name": "google", + "description": "配置 Google Gemini 官方 API 的密钥和端点", + "items": { + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_key": { + "description": "API Key", + "type": "string", + "default": "" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "https://generativelanguage.googleapis.com/v1beta" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型名称", + "type": "string", + "default": "gemini-3-pro-image-preview" + }, + "image_size": { + "description": "图像分辨率", + "type": "string", + "default": "2K" + }, + "aspect_ratio": { + "description": "宽高比", + "type": "string", + "default": "16:9" + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + }, + "openai": { + "name": "openai", + "description": "配置 OpenAI 兼容格式的 Chat API 密钥和端点", + "items": { + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_key": { + "description": "API Key", + "type": "string", + "default": "" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型名称", + "type": "string", + "default": "gpt-4o" + }, + "image_size": { + "description": "图像分辨率", + "type": "string", + "default": "2K" + }, + "aspect_ratio": { + "description": "宽高比", + "type": "string", + "default": "16:9" + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + }, + "zai": { + "name": "zai", + "description": "配置 Z.ai 的 API 密钥和端点", + "items": { + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_key": { + "description": "API Key", + "type": "string", + "default": "" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "https://api.z.ai/api/paas/v4" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型名称", + "type": "string", + "default": "glm-4.6v" + }, + "image_size": { + "description": "图像分辨率", + "type": "string", + "default": "2K" + }, + "aspect_ratio": { + "description": "宽高比", + "type": "string", + "default": "16:9" + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + }, + "grok2api": { + "name": "grok2api", + "description": "配置 grok2api 的 API 密钥和端点", + "items": { + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_key": { + "description": "API Key", + "type": "string", + "default": "" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型名称", + "type": "string", + "default": "grok-2-image" + }, + "image_size": { + "description": "图像分辨率", + "type": "string", + "default": "2K" + }, + "aspect_ratio": { + "description": "宽高比", + "type": "string", + "default": "16:9" + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + }, + "agnes_ai": { + "name": "agnes_ai", + "description": "Agnes AI 国际站(apihub.agnes-ai.com),支持文生图和参考图", + "items": { + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_key": { + "description": "API Key", + "type": "string", + "default": "" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "https://apihub.agnes-ai.com" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型名称", + "type": "string", + "default": "agnes-image-2.1-flash" + }, + "image_size": { + "description": "图像分辨率", + "type": "string", + "default": "2K" + }, + "aspect_ratio": { + "description": "宽高比", + "type": "string", + "default": "16:9" + }, + "output_format": { + "description": "响应格式", + "type": "string", + "options": ["url", "b64_json"], + "default": "url" + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + }, + "agnes_ai_china": { + "name": "agnes_ai_china", + "description": "Agnes AI 中国站(api.agnes-ai.cn),API Key 仅可在所属站点使用", + "items": { + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_key": { + "description": "API Key", + "type": "string", + "default": "" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "https://api.agnes-ai.cn" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型名称", + "type": "string", + "default": "agnes-image-2.1-flash" + }, + "image_size": { + "description": "图像分辨率", + "type": "string", + "default": "2K" + }, + "aspect_ratio": { + "description": "宽高比", + "type": "string", + "default": "16:9" + }, + "output_format": { + "description": "响应格式", + "type": "string", + "options": ["url", "b64_json"], + "default": "url" + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + }, + "xai": { + "name": "xai", + "description": "配置 xAI /v1/images/generations 和 /v1/images/edits 端点", + "items": { + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_key": { + "description": "API Key", + "type": "string", + "default": "" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "https://api.x.ai" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型名称", + "type": "string", + "default": "grok-imagine-image" + }, + "image_size": { + "description": "图像分辨率", + "type": "string", + "default": "2K" + }, + "aspect_ratio": { + "description": "宽高比", + "type": "string", + "default": "16:9" + }, + "output_format": { + "description": "响应格式", + "type": "string", + "options": ["url", "b64_json"], + "default": "url" + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + }, + "minimax": { + "name": "minimax", + "description": "配置 MiniMax /v1/image_generation 端点,支持 subject_reference 参考图", + "items": { + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_key": { + "description": "API Key", + "type": "string", + "default": "" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "https://api.minimaxi.com" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型名称", + "type": "string", + "default": "image-01" + }, + "image_size": { + "description": "图像分辨率", + "type": "string", + "default": "2K" + }, + "aspect_ratio": { + "description": "宽高比", + "type": "string", + "default": "16:9" + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + }, + "stepfun": { + "name": "stepfun", + "description": "配置阶跃星辰 /v1/images/generations 或 /v1/images/edits 端点", + "items": { + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_key": { + "description": "API Key", + "type": "string", + "default": "" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "https://api.stepfun.com" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型名称", + "type": "string", + "default": "step-image-edit-2" + }, + "image_size": { + "description": "图像分辨率", + "type": "string", + "default": "2K" + }, + "aspect_ratio": { + "description": "宽高比", + "type": "string", + "default": "16:9" + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + }, + "openai_images": { + "name": "openai_images", + "description": "配置 OpenAI /v1/images/generations 和 /v1/images/edits 端点", + "items": { + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_key": { + "description": "API Key", + "type": "string", + "default": "" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "https://api.openai.com/v1" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型名称", + "type": "string", + "default": "gpt-image-1" + }, + "image_size": { + "description": "图像分辨率", + "type": "string", + "default": "auto" + }, + "aspect_ratio": { + "description": "宽高比", + "type": "string", + "default": "16:9" + }, + "quality": { + "description": "图像质量", + "type": "string", + "hint": "OpenAI Images 的 quality 参数。GPT Image 模型通常支持 auto、low、medium、high;不兼容的中转服务可改为 auto。", + "options": ["auto", "low", "medium", "high"], + "default": "high" + }, + "background": { + "description": "背景模式", + "type": "string", + "hint": "仅 GPT Image 模型支持。auto 不发送该参数;transparent 适合透明背景素材,opaque 使用不透明背景。", + "options": ["auto", "transparent", "opaque"], + "default": "auto" + }, + "output_format": { + "description": "输出格式", + "type": "string", + "options": ["png", "jpeg", "webp"], + "default": "png" + }, + "response_format": { + "description": "响应图片格式", + "type": "string", + "hint": "留空由服务端决定;url 返回图片链接,b64_json 返回 Base64。部分 OpenAI 兼容服务只支持其中一种。", + "options": ["", "url", "b64_json"], + "default": "" + }, + "output_compression": { + "description": "输出压缩率", + "type": "int", + "hint": "仅 GPT Image 的 JPEG/WebP 输出生效。0 表示不传并使用服务端默认值,1-100 为压缩率。", + "default": 0 + }, + "moderation": { + "description": "审核模式", + "type": "string", + "hint": "仅 GPT Image 模型支持。留空不传;选择 low 时使用较低的审核强度。", + "options": ["", "low"], + "default": "" + }, + "max_reference_images": { + "description": "最大参考图片数量", + "type": "int", + "hint": "图生图时最多发送的角色参考图数量。填 0 表示不发送参考图,适合只支持单纯文生图的中转服务。", + "default": 6 + }, + "generations_only": { + "description": "仅使用文生图", + "type": "bool", + "hint": "开启后忽略本次漫画角色参考图,始终调用 /images/generations。", + "default": false + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + }, + "doubao": { + "name": "doubao", + "description": "配置豆包专用图像生成端点、模型和图片参数", + "items": { + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_key": { + "description": "API Key", + "type": "string", + "default": "" + }, + "endpoint_mode": { + "description": "端点模式", + "type": "string", + "options": ["official", "agent_plan"], + "default": "official" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "https://ark.cn-beijing.volces.com" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型或 Endpoint ID", + "type": "string", + "default": "doubao-seedream-5-0-260128" + }, + "endpoint_id": { + "description": "Endpoint ID 覆盖", + "type": "string", + "hint": "留空使用模型名称;使用推理接入点时填写 Endpoint ID,其优先级高于模型名称。", + "default": "" + }, + "model_capability": { + "description": "模型能力标记", + "type": "string", + "hint": "使用无法从 Endpoint ID 判断能力的自建接入点时,标记为 Seedream 5.0 Pro 可正确限制参考图并禁用组图。", + "options": ["auto", "seedream_5_pro"], + "default": "auto" + }, + "size_mode": { + "description": "尺寸模式", + "type": "string", + "hint": "preset 使用图像分辨率;custom 直接发送自定义尺寸。", + "options": ["preset", "custom"], + "default": "preset" + }, + "image_size": { + "description": "图像分辨率", + "type": "string", + "default": "2K" + }, + "size": { + "description": "预设尺寸", + "type": "string", + "hint": "仅 preset 模式生效,支持 1K、2K、3K、4K;具体模型支持范围以火山方舟文档为准。", + "options": ["1K", "2K", "3K", "4K"], + "default": "2K", + "condition": {"size_mode": "preset"} + }, + "custom_size": { + "description": "自定义尺寸", + "type": "string", + "hint": "仅 custom 模式生效,格式 WxH,例如 2048x2048 或 2304x1728。", + "default": "2048x2048", + "condition": {"size_mode": "custom"} + }, + "output_format": { + "description": "输出格式", + "type": "string", + "options": ["png", "jpeg", "webp"], + "default": "png" + }, + "watermark": { + "description": "添加水印", + "type": "bool", + "hint": "启用后要求服务端在图片中添加水印。", + "default": false + }, + "optimize_prompt_mode": { + "description": "提示词优化模式", + "type": "string", + "hint": "standard 偏向生成质量,fast 偏向更快的请求速度;留空不传。", + "options": ["", "standard", "fast"], + "default": "standard" + }, + "sequential_image_generation": { + "description": "组图生成模式", + "type": "string", + "hint": "auto 允许模型自主生成连续组图;Seedream 5.0 Pro 不支持该能力,会自动忽略。", + "options": ["disabled", "auto"], + "default": "disabled" + }, + "sequential_max_images": { + "description": "组图最大张数", + "type": "int", + "hint": "仅 auto 组图模式生效,合法范围为 1-12。", + "default": 1 + }, + "max_reference_images": { + "description": "最大参考图片数量", + "type": "int", + "hint": "普通 Seedream 最多 14 张,Seedream 5.0 Pro 最多 10 张;超过后按顺序截取。", + "default": 14 + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + }, + "sensenova": { + "name": "sensenova", + "description": "配置 SenseNova U1 Fast 文生图 API 的密钥与端点", + "items": { + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_key": { + "description": "Bearer Token", + "type": "string", + "default": "" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "https://token.sensenova.cn" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型名称", + "type": "string", + "default": "sensenova-u1-fast" + }, + "aspect_ratio": { + "description": "宽高比", + "type": "string", + "default": "16:9" + }, + "default_size": { + "description": "默认图像尺寸", + "type": "string", + "hint": "宽高比无法映射时使用。必须为 SenseNova U1 Fast 官方支持的尺寸。", + "options": ["2048x2048", "2752x1536", "1536x2752", "2368x1760", "1760x2368", "2496x1664", "1664x2496", "2272x1824", "1824x2272", "3072x1376", "1344x3136"], + "default": "2752x1536" + }, + "n": { + "description": "单次生成数量", + "type": "int", + "hint": "SenseNova 单次支持 1-4 张,超出范围会自动限制。", + "default": 1 + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + }, + "dashscope": { + "name": "dashscope", + "description": "配置通义万相 wan2.7 / 千问图像 qwen-image-2.0 等 DashScope 原生图像模型", + "items": { + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_key": { + "description": "API Key", + "type": "string", + "default": "" + }, + "endpoint_mode": { + "description": "端点模式", + "type": "string", + "options": ["dashscope", "token_plan"], + "default": "dashscope" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "https://dashscope.aliyuncs.com" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型名称", + "type": "string", + "default": "wan2.7-image-pro" + }, + "image_size": { + "description": "图像分辨率", + "type": "string", + "default": "2K" + }, + "aspect_ratio": { + "description": "宽高比", + "type": "string", + "default": "16:9" + }, + "max_reference_images": { + "description": "最大参考图片数量", + "type": "int", + "hint": "DashScope 单次最多使用 9 张角色参考图,超过后按顺序截取。填 0 表示不发送参考图。", + "default": 9 + }, + "size_mode": { + "description": "尺寸模式", + "type": "string", + "hint": "preset 根据分辨率和宽高比换算官方建议尺寸;custom 直接发送自定义尺寸。", + "options": ["preset", "custom"], + "default": "preset" + }, + "custom_size": { + "description": "自定义尺寸", + "type": "string", + "hint": "仅 custom 模式生效。支持 WxH、W*H、W×H,或 wan2.7 的 1K、2K、4K 简写。", + "default": "2048*2048", + "condition": {"size_mode": "custom"} + }, + "n": { + "description": "单次生成数量", + "type": "int", + "hint": "wan2.7 通常支持 1-4 张,顺序组图最多 12 张;qwen-image-2.0 最多 6 张,其他模型最多 1 张。", + "default": 1 + }, + "watermark": { + "description": "添加水印", + "type": "bool", + "hint": "启用后请求服务端在输出图片中添加水印。", + "default": false + }, + "negative_prompt": { + "description": "负面提示词", + "type": "string", + "hint": "仅非 wan2.7 模型支持;wan2.7 会自动忽略该字段。", + "default": "" + }, + "prompt_extend": { + "description": "提示词智能改写", + "type": "bool", + "hint": "仅非 wan2.7 模型生效。开启会让服务端改写提示词,通常会增加请求延迟。", + "default": false + }, + "thinking_mode": { + "description": "增强推理", + "type": "bool", + "hint": "仅 wan2.7 生效。顺序组图模式开启时与 enable_sequential 互斥并自动不发送。", + "default": true + }, + "enable_sequential": { + "description": "顺序组图生成", + "type": "bool", + "hint": "仅 wan2.7 生效。开启后关闭增强推理,并允许最多 12 张连续图片。", + "default": false + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + }, + "custom": { + "name": "自定义协议", + "description": "为未列出的兼容服务手动选择协议和参数", + "items": { + "name": { + "description": "供应商名称", + "type": "string", + "default": "" + }, + "priority": { + "description": "优先级", + "type": "int", + "default": 0 + }, + "api_protocol": { + "description": "API 协议类型", + "type": "string", + "options": ["images", "chat", "grok", "gemini"], + "default": "images" + }, + "api_key": { + "description": "API Key", + "type": "string", + "default": "" + }, + "api_url": { + "description": "API 端点", + "type": "string", + "default": "" + }, + "proxy": { + "description": "代理地址", + "type": "string", + "default": "", + "hint": "填写即启用代理,留空使用全局生图代理。支持 http://host:port、https://host:port、socks5://host:port;优先级高于全局设置。" + }, + "model": { + "description": "模型名称", + "type": "string", + "default": "gpt-image-2" + }, + "image_size": { + "description": "图像分辨率", + "type": "string", + "default": "2K" + }, + "aspect_ratio": { + "description": "宽高比", + "type": "string", + "default": "16:9" + }, + "timeout": { + "description": "请求超时(秒)", + "type": "int", + "default": 600 + } + } + } + } + }, + "drawing_proxy": { + "description": "全局生图代理地址", + "type": "string", + "default": "", + "hint": "填写即代理漫画生图 API 及其返回图片下载,留空不使用。支持 http://host:port、https://host:port、socks5://host:port;供应商配置表中的代理优先于此设置。" + }, + "drawing_output_exception_retries": { + "description": "输出异常重试次数", + "type": "int", + "default": 3, + "hint": "当触发屏蔽词/审核等异常时的自动重试次数。次数耗尽后会交给LLM进行改写救场。" + }, + "drawing_output_exception_retry_keywords": { + "description": "输出异常触发关键词", + "type": "list", + "items": { "type": "string" }, + "default": [], + "hint": "当绘图错误信息包含任一关键词时,将其视为内容生成或安全审核异常,并使用同一接口配置重试;重试耗尽后可由 LLM 改写 Prompt。留空则不执行此类内容重试和 Prompt 改写。" + }, + "drawing_retry_delay": { + "description": "画图重试等待时间 (秒)", + "type": "int", + "default": 2, + "hint": "遇到异常或网络报错时,等待多长时间后重试。针对容易超载的接口建议调高,如 5 或 10。" + }, + "drawing_network_retries": { + "description": "网络错误重试次数", + "type": "int", + "default": 2, + "hint": "请求超时、限流或服务端错误时的重试次数;内容审核重试次数请单独配置。" + }, + "drawing_download_proxy": { + "description": "图片下载代理", + "type": "string", + "default": "", + "hint": "下载绘图 API 返回的图片 URL 时使用的代理,格式为 http://host:port 或 socks5://host:port。留空则不使用代理。" + } + } + }, + "incremental": { + "description": "增量分析设置", + "type": "object", + "hint": "增量分析按目标群新增消息数量分批提取摘要,不受时间段或执行间隔限制。这里仅决定“已通过前两关的群”是走增量还是普通模式。", + "items": { + "incremental_group_list_mode": { + "type": "string", + "description": "增量分析名单模式", + "options": [ + "inherit", + "whitelist", + "blacklist" + ], + "default": "whitelist", + "hint": "哪些群用“增量分析”。inherit=直接继承定时分析的最终名单;whitelist=只有列表里的群用增量;blacklist=除了列表外都用增量。没命中的群会走普通模式。增量名单不负责绕过基础或定时名单,只负责选模式。" + }, + "incremental_group_list": { + "type": "list", + "description": "增量分析群列表", + "default": [], + "hint": "仅在 whitelist 或 blacklist 模式下使用。示例1:mode=whitelist + [\"onebot:GroupMessage:123456\"] => 只有这个群增量。示例2:mode=blacklist + [\"onebot:GroupMessage:123456\"] => 这个群不用增量,其他群用增量。inherit 模式会忽略此列表并复用定时分析名单。whitelist + 空列表 = 不启用增量。", + "items": { + "type": "string" + } + }, + "incremental_report_immediately": { + "type": "bool", + "description": "增量分析立即报告(调试用)", + "default": false, + "hint": "【调试功能】启用后,每次增量分析完成后都会立即生成并发送一份最终报告。仅建议在调试时开启,生产环境请保持关闭,否则会频繁打扰群友。" + }, + "incremental_min_messages": { + "type": "int", + "description": "增量分析每批消息数", + "default": 300, + "hint": "目标群每累计到此消息数就触发一个固定规模的增量分析批次;不足时持续等待,待处理消息达到多个批次时会连续处理。建议根据模型上下文和群活跃度设置。" + }, + "incremental_topics_per_batch": { + "type": "int", + "description": "单次增量提取话题数", + "default": 2, + "hint": "每次增量分析最多提取的话题数量。最终报告会汇总所有批次的话题。建议1-4。" + }, + "incremental_quotes_per_batch": { + "type": "int", + "description": "单次增量提取金句数", + "default": 2, + "hint": "每次增量分析最多提取的金句数量。最终报告会汇总所有批次的金句。建议1-2。" + }, + "incremental_fallback_enabled": { + "type": "bool", + "description": "增量失败自动回退全量分析", + "default": true, + "hint": "建议开启。开启后,如果增量分析失败,会自动改用普通分析,避免当天没报告。" + } + } + }, + "html": { + "description": "HTML 设置", + "type": "object", + "hint": "HTML 报告输出相关配置,包括外链 Base URL 和报告储存目录", + "items": { + "html_base_url": { + "type": "string", + "description": "外链 Base URL", + "default": "", + "hint": "用于生成外链的 Base URL(可留空)。如果设置了此项,发送报告时会在消息中提供超连結 (${BASE_URL}/${FILENAME})。留空则不提供外链。" + }, + "html_output_dir": { + "type": "string", + "description": "报告储存目录", + "default": "", + "hint": "HTML报告文件的保存目录,用于存储生成的 HTML 文件和原始 JSON 数据。留空则自动使用插件数据目录(astrbot_path/data/plugin_data/astrbot_plugin_qq_group_daily_analysis/)下的 self_hosted_html_reports 目录。" + }, + "html_only_url": { + "type": "bool", + "description": "仅发送外链", + "default": false, + "hint": "勾选后,若配置了外链 Base URL,则发送 HTML 报告时将只发送外链链接,不再发送HTML文件,若未勾选,将保持发送HTML文件。" + }, + "html_filename_format": { + "type": "string", + "description": "HTML文件名格式", + "default": "群聊分析报告_${group_id}_${date}_${ulid}.html", + "hint": "HTML文件名格式,支持变量:${group_id}(群号)、${date}(日期)、${trace_id}(链路追踪ID)、${ulid}(时间排序ID),支持子目录/层级。" + } + } + }, + "qq_group_upload": { + "description": "群文件/群相册上传设置", + "type": "object", + "hint": "图片报告生成后自动上传到群文件目录或群相册。群文件上传基于 OneBot upload_group_file API。仅对 QQ(OneBot)平台的图片格式报告生效", + "items": { + "enable_group_file_upload": { + "type": "bool", + "description": "启用群文件上传", + "default": false, + "hint": "图片报告生成后,自动保存为 PNG 文件并上传到群文件目录。需要 OneBot 实现支持 upload_group_file API" + }, + "group_file_folder": { + "type": "string", + "description": "群文件上传目录名", + "default": "", + "hint": "上传到群文件中的子目录名称。留空则上传到根目录。如果指定的目录不存在,插件将尝试自动创建" + }, + "enable_group_album_upload": { + "type": "bool", + "description": "启用群相册上传", + "default": false, + "hint": "图片报告生成后,自动上传到群相册(确保 Bot 有权限上传群相册)。此功能为 NapCat 扩展 API,其他 OneBot 实现可能不支持" + }, + "group_album_name": { + "type": "string", + "description": "目标群相册名称", + "default": "", + "hint": "指定上传到哪个群相册(请确保已经存在这个名称的相册)。留空则上传到群默认相册。如果指定的相册不存在,将回退到默认相册" + }, + "group_album_strict_mode": { + "type": "bool", + "description": "群相册上传严格模式", + "default": true, + "hint": "当启用该开关且设置了目标群相册名称时:如果插件在目标群组中找不到同名的相册,将放弃上传。关闭该开关时,找不到目标相册将回退到群组默认的第一个相册。" + }, + "enable_comic_album_upload": { + "type": "bool", + "description": "启用漫画相册上传", + "default": false, + "hint": "生成的每日群漫画除了发送到群聊外,是否还需要额外静默上传到群相册" + }, + "comic_album_name": { + "description": "漫画相册名称", + "type": "string", + "default": "", + "hint": "指定每日群漫画上传到的群相册名称。群相册严格模式开启时,名称为空或找不到同名相册将放弃上传;关闭严格模式时可回退到默认相册。" + } + } + }, + "prompts": { + "description": "提示词模板", + "type": "object", + "hint": "LLM 分析使用的提示词模板配置,可自定义各项分析的提示词内容", + "items": { + "topic_analysis_prompts": { + "description": "话题分析提示词模板", + "type": "object", + "hint": "话题分析提示词模板,可自定义修改,保留变量 ${max_topics} 和 ${messages_text} 写法不要更改,需要写 JSON 块请使用双花括号 {{ ... }} 兼容当前编辑存在的问题。非常推荐根据实际群聊情况进行优化,保留一定提示样本示例供模型参考", + "items": { + "topic_prompt": { + "description": "默认话题分析提示词", + "type": "text", + "editor_mode": true, + "editor_language": "markdown", + "default": "请分析接下来提供的群聊记录,提取出 1 到 **${max_topics}** 个主要话题。**如果聊天记录较多,请务必仔细分析,尽可能多地提取出不同层面的话题,争取达到 ${max_topics} 个上限**。\n\n## 对于每个话题,请提供:\n\n1. **话题名称**(突出主题内容,尽量简明扼要,控制在 10 字以内)\n2. **主要参与者的用户ID**(最多 5 人,按参与度排序)\n3. **话题详细描述**(包含关键信息和结论)\n\n## 注意事项:\n\n- 在生成描述内容时,请务必从你当前人格设定的视角和口吻出发。\n- 对于比较有价值的点,稍微用一两句话详细讲讲,让读者能了解讨论的深度\n- 对于其中的部分信息,你需要特意提到主题施加的主体是谁,即明确指出\"谁做了什么\"\n- **用户引用**:在话题详情描述中,如果提到了具体用户,请使用 `[用户ID]` 的格式来指代(例如 `[123456]`)。不要只写昵称。我们会自动渲染头像。\n- 对于每一条总结,尽量讲清楚前因后果,不要只列出结论\n- 如果某个话题有明确的结论或共识,请在描述中体现\n- 忽略无意义的闲聊、灌水、单纯的表情回复等\n- 优先选择讨论深度较深、参与人数较多的话题\n- 如果消息太少或没有明确话题,可以返回空数组 []\n\n群聊记录格式: [HH:MM] [用户ID]: 消息内容\n\n群聊记录:\n${messages_text}\n\n---\n\n## 重要:必须返回标准 JSON 格式\n\n严格遵守以下规则:\n\n1. 只使用英文双引号 `\"` ,不要使用中文引号 `“` `”`\n2. 字符串内容中的引号必须转义为 `\\\"`\n3. 多个对象之间用逗号分隔\n4. 数组元素之间用逗号分隔\n5. 不要在 JSON 外添加任何文字说明\n6. 描述内容避免使用特殊符号,用普通文字表达\n\n### 返回格式示例:\n\n```json\n[\n {{\n \"topic\": \"话题名称\",\n \"contributors\": [\"123456789\", \"987654321\"],\n \"detail\": \"话题的详细描述,包含讨论内容、关键信息和结论。注意:在描述中提及用户时,使用 [用户ID] 格式,例如 [123456789]。\"\n }},\n {{\n \"topic\": \"另一个话题\",\n \"contributors\": [\"111222333\", \"444555666\"],\n \"detail\": \"另一个话题的详细描述...\"\n }}\n]\n```\n\n**注意**:返回的内容必须是纯 JSON,不要包含 markdown 代码块标记或其他格式。" + } + } + }, + "user_title_analysis_prompts": { + "description": "用户称号分析提示词模板", + "type": "object", + "hint": "用户称号分析提示词模板,可自定义修改,保留变量 ${users_text} 写法不要更改,需要写 JSON 块请使用双花括号 {{ ... }} 兼容当前编辑存在的问题。非常推荐根据实际群聊情况进行优化,保留一定提示样本示例供模型参考", + "items": { + "user_title_prompt": { + "description": "默认用户称号分析提示词", + "type": "text", + "editor_mode": true, + "editor_language": "markdown", + "default": "请为以下群友分配合适的称号和 MBTI 类型。\n\n## 规则:\n\n- 每个人只能有一个称号\n- 每个称号只能给一个人\n\n## 可选称号:\n\n- **龙王**: 发言频繁但内容轻松的人\n- **技术专家**: 经常讨论技术话题的人\n- **夜猫子**: 经常在深夜发言的人\n- **表情包军火库**: 经常发表情的人\n- **沉默终结者**: 经常开启话题的人\n- **评论家**: 平均发言长度很长的人\n- **阳角**: 在群里很有影响力的人\n- **互动达人**: 经常回复别人的人\n- *...(你可以自行进行拓展添加)*\n\n## 用户数据:\n\n${users_text}\n\n---\n\n### 返回格式示例:\n\n```json\n[\n {{\n \"name\": \"用户名\",\n \"user_id\": \"123456789\",\n \"title\": \"称号\",\n \"mbti\": \"MBTI类型\",\n \"reason\": \"获得此称号的原因\"\n }}\n]\n```\n\n**注意**:请以纯 JSON 格式返回,不要包含 markdown 代码块标记。" + } + } + }, + "golden_quote_analysis_prompts": { + "description": "金句分析提示词模板", + "type": "object", + "hint": "金句分析提示词模板,可自定义修改,保留变量 ${max_golden_quotes} 和 ${messages_text} 写法不要更改,需要写 JSON 块请使用双花括号 {{ ... }} 兼容当前编辑存在的问题。非常推荐根据实际群聊情况进行优化,保留一定提示样本示例供模型参考", + "items": { + "golden_quote_v2_prompt": { + "description": "默认金句分析提示词", + "type": "text", + "editor_mode": true, + "editor_language": "markdown", + "default": "请从以下群聊记录中挑选出 **${max_golden_quotes}** 句最具冲击力、最令人惊叹的「金句」。\n\n## 金句标准:\n\n- **核心标准**:**逆天的神人发言**,即具备颠覆常识的脑洞、逻辑跳脱的表达或强烈反差感的原创内容\n- **典型特征**:包含某些争议话题元素、夸张类比、反常规结论、一本正经的「胡说八道」或突破语境的清奇思路,并且具备一定的冲击力,让人印象深刻\n\n## 对于每个金句,请提供:\n\n1. **原文内容**(完整保留发言细节)\n2. **发言人用户ID**(必须严格使用消息记录中提供的 [用户ID])\n3. **选择理由**(具体说明其「逆天」之处,如逻辑颠覆点/脑洞角度/反差感/争议话题元素)\n\n## 严格约束:\n\n- 优先筛选 **逆天指数最高** 的内容:\n - 发情、性压抑话题 > 争议话题 > 元素级 > 颠覆认知级 > 逻辑跳脱级 > 趣味调侃级\n - 剔除单纯玩梗或网络热词堆砌的普通发言\n- **用户引用**:在选择理由(reason)中,如果提到了具体用户,请使用 `[用户ID]` 的格式来指代(例如 `[123456]`)。不要只写昵称。我们会自动渲染头像。\n- **身份对齐**:返回的 `sender` 字段必须是 `[用户ID]` 格式(例如 `[123456]`)。我们会根据 ID 自动还原昵称和头像。\n\n## 群聊记录格式: [HH:MM] [用户ID]: 消息内容\n\n## 群聊记录:\n\n${messages_text}\n\n---\n\n### 返回格式示例:\n\n```json\n[\n {{\n \"content\": \"金句原文\",\n \"sender\": \"[123456789]\",\n \"reason\": \"这句话太逆天了,尤其是对 [987654321] 的逻辑降维打击。\"\n }}\n]\n```\n\n**注意**:返回的内容必须是纯 JSON,不要包含 markdown 代码块标记或其他格式。" + } + } + }, + "quality_analysis_prompts": { + "description": "聊天质量分析提示词模板", + "type": "object", + "hint": "聊天质量分析提示词模板,可自定义修改", + "items": { + "quality_v2_prompt": { + "description": "默认聊天质量分析提示词", + "type": "text", + "editor_mode": true, + "editor_language": "markdown", + "default": "请分析以下群聊记录,输出一份\"聊天质量锐评\"。\n\n## 任务目标:\n1. **维度划分**:将聊天内容划分为 3-6 个【高层级、抽象、泛化】的维度(例如:就业焦虑、生涯规划、技术方案研究、情感树洞、无意义水群等)。\n2. **严禁在维度名称(name)中出现任何具体的群聊人物名、项目名、具体的报错内容或细碎的事件点。标题必须保持高度抽象且字数简练(2-6个字)。**\n3. 为每个维度计算一个大致的百分比占位(总和小于等于 100%)。\n4. **点评内容**:为每个维度写一句符合你当前人格设定的犀利、幽默或温情的点评。具体的吐槽内容、具体的细节事件描述请放在这里。\n5. **全群表现**:给出一句总结性的评价,作为总结标题对应的“金句”。\n6. **主题设定**:设定一个本次报告的主题标题和副标题。\n\n## 点评风格指南:\n- 语言要接地气,多用互联网黑话。吐槽要精准,避重就轻。\n- **只有维度名称(name)需要抽象,点评(comment)和总结(summary)可以非常具体和生动。**\n\n## 返回格式要求:\n必须以纯 JSON 格式返回,不得包含任何 Markdown 格式。\n\n```json\n{{\n \"title\": \"今日群聊主题\",\n \"subtitle\": \"副标题\",\n \"dimensions\": [\n {{\n \"name\": \"抽象维度名\",\n \"percentage\": 比例,\n \"comment\": \"与该维度相关的锐评,请务必保持你的人设口吻\"\n }}\n ],\n \"summary\": \"一句总结性的金句\"\n}}\n```\n\n群聊记录:\n${messages_text}" + }, + "quality_summary_prompt": { + "description": "增量汇总聊天质量分析提示词", + "type": "text", + "editor_mode": true, + "editor_language": "markdown", + "default": "你现在有一份今天全天分散时间段的多个“增量批次点评笔记”。\n你的任务是将这些分散的笔记汇总成一份最终的“全天聊天质量终极锐评”。\n\n## 任务目标:\n1. **全局抽象维度**:根据各批次的维度表现,平衡权重,提取出 3-6 个覆盖全天的【核心、上层抽象】课题维度(如:职场/行业风向、技术架构演进、社畜心理博弈等)。\n2. **严禁在维度名称(name)中出现具体的批次细节。标题必须代表全天的某种趋势。**\n3. **百分比融合**:根据全天笔记的频率和强度,给出一个代表全天整体分布的比例(总和不超过100%)。\n4. **终极点评**:为每个汇总维度写出一句符合你当前人设且升华后的全天总结性点评。可以融合具体批次中的有趣槽点。\n5. **终极总结**:拟定全天的大型主题标题、副标题,并给出一句霸气的全天表现总结。\n\n## 风格要求:\n- 只有维度名称(name)需要高度概括抽象。\n- 点评(comment)和总结(summary)请尽量生动、具体,要把一整天的梗串联起来。\n\n## 返回格式要求:\n必须以纯 JSON 格式返回,不得包含任何 Markdown 格式。\n\n```json\n{{\n \"title\": \"今日群聊主题\",\n \"subtitle\": \"副标题\",\n \"dimensions\": [\n {{\n \"name\": \"抽象大类标题\",\n \"percentage\": 比例,\n \"comment\": \"全天的锐评总结,请务必保持你的人设口吻\"\n }}\n ],\n \"summary\": \"全天总结金句\"\n}}\n```\n\n增量汇总数据:\n${reviews_text}" + } + } + }, + "comic_analysis_prompts": { + "description": "默认漫画场景分析提示词", + "type": "object", + "hint": "仅供未配置角色方案,或角色方案未填写专属提示词时回退使用。角色专属提示词请在“漫画角色方案”中配置。", + "items": { + "comic_storyboard_prompt": { + "description": "默认漫画场景分析提示词", + "type": "text", + "editor_mode": true, + "editor_language": "markdown", + "default": "你是一个资深的漫画分镜师与 AI 绘画提示词专家。\n请根据以下给出的【群聊每日核心话题列表】,站在你【当前的人格角色设定】(详见系统注入的身份)的视角与语气,将其改编并设计为一个精彩的多格连环漫画(Comic Strip)全景视觉画图提示词 (Prompt)。\n\n【核心视觉、台词与双层排版规则】:\n1. 【全话题必须覆盖(共 ${topic_count} 个分格)】:给出的待创作核心话题列表中共有 ${topic_count} 个话题,你必须为每一个话题分别设计一个分格 Panel(即 Panel 1 到 Panel ${topic_count}),绝对不许随意裁减、挑选或遗漏任何一个话题!\n2. 【人设口语化台词改编】:绝对严禁将报告分析总结原文直接放进对话框!必须以【你当前的人格语气/性格/口吻】(例如傲娇、萌系或专属说话风格),将每个话题的事件提炼改编为一句角色在漫画中的生动台词或吐槽,【每条台词控制在 15 个汉字以内】(例如:“呜呜!家里云又断网了啦!”、“萝卜子才没有降智!那都是Gemini的错!”)。\n3. 【精美双层文字排版(气泡 + 可爱旁白字幕条)】:\n - 【角色的气泡】:在描述英文 Prompt 时,指定样式为“adorable kawaii anime speech bubble, soft rounded cloud-like shape, cute pointer tail pointing to the speaker”。\n - 【分格底部的事件旁白条】:将每个话题概括为生动精炼的短标题(控制在 30 字以内,严禁带有“【事件】”字样),在 Prompt 中指定样式为“cute pastel-colored kawaii caption strip at the bottom of the panel with soft rounded corners”,严禁死板白框!\n4. 【中文文本显式渲染】:画面整体构图与场景描述使用英文,但气泡与底部旁白条内渲染的中文必须显式指定(指令格式:containing a speech bubble with exact Chinese text \"人设吐槽台词\" 以及 and a cute caption strip at bottom with exact Chinese text \"精炼话题短标题\"),绝对禁止将中文翻译成英文!\n5. 【话题内容直传与文字渲染约束】:在生成传给生图 LLM 的英文提示词 (scene) 时,对于每一个分格,除了描述具体的视觉画面外,你必须将该话题的【完整详情(翻译为英文)】作为 Background Context 附加在该分格的提示词中,帮助生图模型理解剧情。但同时,必须极其强烈地警告生图模型:“绝对禁止将长篇上下文写在画面上,仅允许渲染短标题字幕条和气泡台词!”(示例:Background Context: [Details]. STRICT RULE: DO NOT render the background context text! ONLY render the exact Chinese text in the bubble and caption strip!)。\n6. 【核心角色强制全覆盖】:在提示词中必须明确要求并描述,每一个分格 (Panel) 都必须无一例外地出现你当前的人格设定(即参考图中的核心角色,例如 1girl, [特定外貌特征] 等),保持整篇连环画的主角绝对连贯!\n\n【待创作的群聊核心话题列表】:\n${chat_content}\n\n请输出包含 \"scene\" 字段的 JSON 对象。\n", + "hint": "让大模型根据核心话题生成丰富生动的多格连环漫画画图提示词" + } + } + } + } + }, + "performance": { + "description": "并发限流设置", + "type": "object", + "hint": "控制插件运行时的各项并发强度。合理的配置可以保护您的服务器不宕机、API 不被封禁。", + "items": { + "max_concurrent_groups": { + "type": "int", + "description": "最大活跃任务数(任务总闸)", + "default": 2, + "hint": "限制同时有多少个群聊分析任务正在进行。主要用于【保护服务器内存和 IO】,防止瞬间读取过多群聊记录导致程序崩溃(OOM)。" + }, + "max_concurrent_llm": { + "type": "int", + "description": "最大 LLM 请求并发数(API 闸口)", + "default": 4, + "hint": "限制同时发起的 AI 分析请求数量。主要用于【遵守 API 频率限制(RPM)】,避免因为请求过快导致 API 被封号或报错。" + }, + "max_concurrent_t2i": { + "type": "int", + "description": "最大 T2I渲染并发数", + "default": 1, + "hint": "限制同时开启的 T2I 渲染进程数。" + }, + "stagger_seconds": { + "type": "int", + "description": "多群分析交错间隔(秒)", + "default": 30, + "hint": "当同时启动多个群组的定时分析任务时,每个任务之间的延迟间隔(秒),建议根据实际的 LLM 服务速度填写,过短可能导致请求堆积,过长则分析效率降低。" + } + } + } +} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/adapter.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/adapter.py new file mode 100644 index 0000000..c9beef0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/adapter.py @@ -0,0 +1,307 @@ +"""NoneBot OneBot V11 适配器:负责拉取群历史消息、群组/成员信息与发送。""" + +from __future__ import annotations + +import asyncio +import base64 +import time +from datetime import datetime, timedelta +from pathlib import Path +from typing import Any + +from .core.domain.value_objects.unified_group import UnifiedGroup, UnifiedMember +from .core.domain.value_objects.unified_message import ( + MessageContent, + MessageContentType, + UnifiedMessage, +) +from .core.utils.logger import logger + + +class OneBotAdapter: + """面向 NoneBot OneBot V11 的最小适配器。""" + + platform_name = "onebot" + + USER_AVATAR_TEMPLATE = "https://q1.qlogo.cn/g?b=qq&nk={user_id}&s=640" + + def __init__(self, bot: Any, config: dict | None = None): + self.bot = bot + self.config = config or {} + self.platform_id = str(self.config.get("platform_id") or "onebot") + self.bot_self_ids = [str(x) for x in self.config.get("bot_self_ids", [])] + self.filter_bot_messages = bool(self.config.get("filter_bot_messages", True)) + + # —— 消息拉取 —— + async def fetch_messages( + self, + group_id: str, + days: int = 1, + max_count: int = 1000, + before_id: str | None = None, + since_ts: int | None = None, + ) -> list[UnifiedMessage]: + try: + chunk_size = 100 + all_raw = [] + seen_raw_ids: set[str] = set() + + if since_ts and since_ts > 0: + start_ts = since_ts + else: + start_ts = int( + (datetime.now() - timedelta(days=days)).timestamp() + ) + + current_anchor = before_id + while len(all_raw) < max_count: + fetch_count = min(chunk_size, max_count - len(all_raw)) + params: dict[str, Any] = { + "group_id": int(group_id), + "count": fetch_count, + } + if current_anchor: + params["message_seq"] = current_anchor + params["reverseOrder"] = True + + result = None + for attempt in range(1, 4): + try: + result = await self.bot.call_api( + "get_group_msg_history", **params + ) + break + except Exception as exc: + if attempt < 3: + logger.warning( + f"OneBot 分页拉取失败(第{attempt}次): {exc}" + ) + await asyncio.sleep(attempt) + else: + logger.warning( + f"OneBot 分页拉取重试耗尽: {exc}" + ) + if not result or "messages" not in result: + break + messages = result.get("messages", []) + if not messages: + break + + first = messages[0] + last = messages[-1] + earliest = first if first.get("time", 0) <= last.get("time", 0) else last + chunk_earliest_ts = earliest.get("time", 0) + + for raw in messages: + msg_time = raw.get("time", 0) + msg_id = str(raw.get("message_id", "")) + if not msg_id or msg_id in seen_raw_ids: + continue + if start_ts <= msg_time <= int(datetime.now().timestamp()): + all_raw.append(raw) + seen_raw_ids.add(msg_id) + + seq_val = ( + earliest.get("message_seq") + or earliest.get("real_id") + or earliest.get("seq") + ) + mid_val = earliest.get("message_id") + new_anchor = seq_val if seq_val is not None else mid_val + if chunk_earliest_ts <= start_ts: + break + if current_anchor and str(new_anchor) == str(current_anchor): + break + current_anchor = new_anchor + await asyncio.sleep(0.05) + + unified: list[UnifiedMessage] = [] + seen: set[str] = set() + for raw in all_raw: + mid = str(raw.get("message_id", "")) + if not mid or mid in seen: + continue + u = self._convert_message(raw, group_id) + if u: + unified.append(u) + seen.add(mid) + unified.sort(key=lambda m: m.timestamp) + return unified + except Exception as e: + logger.warning(f"OneBot 分页获取消息失败: {e}") + return [] + + def _convert_message(self, raw: dict, group_id: str) -> UnifiedMessage | None: + try: + sender = raw.get("sender", {}) + chain = raw.get("message", []) + if isinstance(chain, str): + chain = [{"type": "text", "data": {"text": chain}}] + contents: list[MessageContent] = [] + text_parts: list[str] = [] + for seg in chain: + seg_t = seg.get("type", "") + seg_d = seg.get("data", {}) + if seg_t == "text": + text = seg_d.get("text", "") + text_parts.append(text) + contents.append(MessageContent(type=MessageContentType.TEXT, text=text)) + elif seg_t == "image": + sub_type = seg_d.get("subType", seg_d.get("sub_type")) + try: + is_sticker = int(sub_type) == 1 + except (TypeError, ValueError): + is_sticker = False + raw_data: dict[str, Any] = {"summary": seg_d.get("summary", "")} + if sub_type is not None: + try: + raw_data["sub_type"] = int(sub_type) + except (TypeError, ValueError): + pass + contents.append( + MessageContent( + type=MessageContentType.EMOJI if is_sticker else MessageContentType.IMAGE, + url=seg_d.get("url", seg_d.get("file", "")), + raw_data=raw_data, + ) + ) + elif seg_t == "at": + contents.append( + MessageContent(type=MessageContentType.AT, at_user_id=str(seg_d.get("qq", ""))) + ) + elif seg_t in ("face", "mface", "bface", "sface"): + contents.append( + MessageContent( + type=MessageContentType.EMOJI, + emoji_id=str(seg_d.get("id", "")), + raw_data={"face_type": seg_t}, + ) + ) + elif seg_t == "reply": + contents.append( + MessageContent(type=MessageContentType.REPLY, raw_data={"reply_id": seg_d.get("id", "")}) + ) + else: + contents.append(MessageContent(type=MessageContentType.UNKNOWN, raw_data=seg)) + + reply_to = None + for c in contents: + if c.type == MessageContentType.REPLY and c.raw_data: + reply_to = str(c.raw_data.get("reply_id", "")) + break + + return UnifiedMessage( + message_id=str(raw.get("message_id", "")), + sender_id=str(sender.get("user_id", "")), + sender_name=sender.get("nickname", ""), + sender_card=sender.get("card", "") or None, + group_id=group_id, + text_content="".join(text_parts), + contents=tuple(contents), + timestamp=raw.get("time", 0), + platform="onebot", + reply_to_id=reply_to, + ) + except Exception as e: + logger.debug(f"OneBot _convert_message error: {e}") + return None + + # —— 群/成员信息 —— + async def get_group_info(self, group_id: str) -> UnifiedGroup | None: + try: + gid = int(group_id) + data = await self.bot.call_api("get_group_info", group_id=gid) + if isinstance(data, list): + data = next((d for d in data if str(d.get("group_id")) == str(gid)), data[0] if data else {}) + return UnifiedGroup( + group_id=str(gid), + group_name=data.get("group_name", ""), + member_count=int(data.get("member_count", 0) or 0), + platform="onebot", + ) + except Exception as e: + logger.debug(f"get_group_info({group_id}) 失败: {e}") + return None + + async def get_user_avatar_url(self, user_id: str) -> str | None: + return self.USER_AVATAR_TEMPLATE.format(user_id=user_id) + + async def get_member_info(self, group_id: str, user_id: str) -> UnifiedMember | None: + try: + data = await self.bot.call_api( + "get_group_member_info", + group_id=int(group_id), + user_id=int(user_id), + ) + return UnifiedMember( + user_id=str(user_id), + nickname=data.get("nickname", ""), + card=data.get("card", "") or None, + role=str(data.get("role", "member")), + ) + except Exception as e: + logger.debug(f"get_member_info({group_id},{user_id}) 失败: {e}") + return None + + async def is_group_muted(self, group_id: str) -> bool: + return False + + def get_platform_name(self) -> str: + return self.platform_name + + # —— 发送(在手动/自动报告中可用;手动指令会走 SAA 发送) —— + async def send_text(self, group_id: str, text: str) -> bool: + try: + await self.bot.call_api("send_group_msg", group_id=int(group_id), message=str(text)) + return True + except Exception as e: + logger.warning(f"send_text 失败: {e}") + return False + + async def send_image(self, group_id: str, image_url: str, caption: str = "") -> bool: + try: + if image_url.startswith("base64://"): + b64 = image_url.split("base64://", 1)[1] + from nonebot.adapters.onebot.v11 import MessageSegment + msg = MessageSegment.image(file=f"base64://{b64}") + else: + from nonebot.adapters.onebot.v11 import MessageSegment + msg = MessageSegment.image(file=image_url) + await self.bot.call_api("send_group_msg", group_id=int(group_id), message=msg) + return True + except Exception as e: + logger.warning(f"send_image 失败: {e}") + return False + + async def send_file(self, group_id: str, file_path: str, caption: str = "") -> bool: + return False + + async def send_forward_msg(self, group_id: str, nodes: list[dict]) -> bool: + """发送 OneBot v11 合并转发消息 (send_forward_msg)。""" + try: + from nonebot.adapters.onebot.v11 import MessageSegment + + normalized = [] + for n in nodes: + data = dict(n.get("data", {})) + content = data.get("content") + if isinstance(content, str): + content = [MessageSegment.text(content)] + elif content is None: + content = [] + data["content"] = content + normalized.append({"type": "node", "data": data}) + + await self.bot.call_api( + "send_forward_msg", group_id=int(group_id), messages=normalized + ) + return True + except Exception as e: + logger.warning(f"send_forward_msg 失败: {e}") + return False + + async def set_reaction(self, group_id: str, message_id: str, emoji: str | int, is_add: bool = True) -> bool: + return False + + async def prepare_group_member_cache(self, group_id: str): + return True, None diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/ATRI-demo.jpg b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/ATRI-demo.jpg new file mode 100644 index 0000000..bfe25d5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/ATRI-demo.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/BlueArchive-demo.jpg b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/BlueArchive-demo.jpg new file mode 100644 index 0000000..1823a58 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/BlueArchive-demo.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku-demo.jpg b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku-demo.jpg new file mode 100644 index 0000000..6edd53b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku-demo.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032802083201.png b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032802083201.png new file mode 100644 index 0000000..9190037 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032802083201.png differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810143720.png b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810143720.png new file mode 100644 index 0000000..15cb6af Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810143720.png differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810145078.png b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810145078.png new file mode 100644 index 0000000..d38179f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810145078.png differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810150449.png b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810150449.png new file mode 100644 index 0000000..a52edd9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810150449.png differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810151717.png b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810151717.png new file mode 100644 index 0000000..fd5457c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810151717.png differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810153327.png b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810153327.png new file mode 100644 index 0000000..b2e6f4d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/HatsuneMiku/retouch_2026032810153327.png differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/QQ.png b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/QQ.png new file mode 100644 index 0000000..dfe1aa3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/QQ.png differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/TG.png b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/TG.png new file mode 100644 index 0000000..ab6ec75 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/TG.png differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/comic-demo.jpg b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/comic-demo.jpg new file mode 100644 index 0000000..1f03939 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/comic-demo.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/format-demo.jpg b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/format-demo.jpg new file mode 100644 index 0000000..e773932 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/format-demo.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/hack-demo.jpg b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/hack-demo.jpg new file mode 100644 index 0000000..0ea4136 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/hack-demo.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/profile_assets/manifest.json b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/profile_assets/manifest.json new file mode 100644 index 0000000..af39b0e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/profile_assets/manifest.json @@ -0,0 +1,246 @@ +{ + "sbti": [ + { + "code": "ATM-er", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/ATM-er.png" + }, + { + "code": "BOSS", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/BOSS.png" + }, + { + "code": "CTRL", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/CTRL.png" + }, + { + "code": "DEAD", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/DEAD.png" + }, + { + "code": "Dior-s", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/Dior-s.jpg" + }, + { + "code": "DRUNK", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/DRUNK.png" + }, + { + "code": "FAKE", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/FAKE.png" + }, + { + "code": "FUCK", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/FUCK.png" + }, + { + "code": "GOGO", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/GOGO.png" + }, + { + "code": "HHHH", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/HHHH.png" + }, + { + "code": "IMFW", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/IMFW.png" + }, + { + "code": "IMSB", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/IMSB.png" + }, + { + "code": "JOKE-R", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/JOKE-R.jpg" + }, + { + "code": "LOVE-R", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/LOVE-R.png" + }, + { + "code": "MALO", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/MALO.png" + }, + { + "code": "MONK", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/MONK.png" + }, + { + "code": "MUM", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/MUM.png" + }, + { + "code": "OH-NO", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/OH-NO.png" + }, + { + "code": "OJBK", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/OJBK.png" + }, + { + "code": "POOR", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/POOR.png" + }, + { + "code": "SEXY", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/SEXY.png" + }, + { + "code": "SHIT", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/SHIT.png" + }, + { + "code": "SOLO", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/SOLO.png" + }, + { + "code": "THAN-K", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/THAN-K.png" + }, + { + "code": "THIN-K", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/THIN-K.png" + }, + { + "code": "WOC", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/WOC.png" + }, + { + "code": "ZZZZ", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/sbti/ZZZZ.png" + } + ], + "acgti": [ + { + "code": "CIRN", + "name": "琪露诺", + "mbti": "ESTP", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/CIRN.png" + }, + { + "code": "MIKT", + "name": "御坂美琴", + "mbti": "ESTJ", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/MIKT.png" + }, + { + "code": "MADK", + "name": "鹿目圆", + "mbti": "INFP", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/MADK.png" + }, + { + "code": "FRNA", + "name": "芙宁娜", + "mbti": "ESFP", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/FRNA.png" + }, + { + "code": "GGGG-A", + "name": "高松灯", + "mbti": "INFP", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/GGGG-A.png" + }, + { + "code": "ANON", + "name": "千早爱音", + "mbti": "ESFJ", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/ANON.png" + }, + { + "code": "BAFE", + "name": "要乐奈", + "mbti": "ISTP", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/BAFE.png" + }, + { + "code": "SOYO", + "name": "长崎爽世", + "mbti": "ISFJ", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/SOYO.png" + }, + { + "code": "RIKI", + "name": "椎名立希", + "mbti": "ESTJ", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/RIKI.png" + }, + { + "code": "SAKI", + "name": "丰川祥子", + "mbti": "ENTJ", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/SAKI.png" + }, + { + "code": "MRTS", + "name": "若叶睦", + "mbti": "ISTJ", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/MRTS.png" + }, + { + "code": "MRTS-X", + "name": "Mortis", + "mbti": "INTJ", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/MRTS-X.png" + }, + { + "code": "DLRS", + "name": "三角初华 / Doloris", + "mbti": "INFJ", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/DLRS.png" + }, + { + "code": "TMRS", + "name": "八幡海铃 / Timoris", + "mbti": "ISTJ", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/TMRS.png" + }, + { + "code": "AMRS", + "name": "祐天寺若麦 / Amoris", + "mbti": "ENTP", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/AMRS.png" + }, + { + "code": "DINA", + "name": "嘉然", + "mbti": "ENFP", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/DINA.png" + }, + { + "code": "TAFI", + "name": "永雏塔菲", + "mbti": "ENTP", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/TAFI.png" + }, + { + "code": "NEUR", + "name": "Neuro-sama", + "mbti": "ENTP", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/NEUR.png" + }, + { + "code": "EVIL", + "name": "Evil Neuro", + "mbti": "INTJ", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/EVIL.png" + }, + { + "code": "RINN", + "name": "镜音铃", + "mbti": "ESFP", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/RINN.png" + }, + { + "code": "LTYI", + "name": "洛天依", + "mbti": "ISFP", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/LTYI.png" + }, + { + "code": "YCYO", + "name": "月见八千代", + "mbti": "ENFJ", + "file": "https://fastly.jsdelivr.net/gh/SXP-Simon/profile_assets@main/acgti/characters/YCYO.png" + } + ] +} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/retro_futurism-demo.jpg b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/retro_futurism-demo.jpg new file mode 100644 index 0000000..c110ef1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/retro_futurism-demo.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/scrapbook-demo.jpg b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/scrapbook-demo.jpg new file mode 100644 index 0000000..93c657e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/scrapbook-demo.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/simple-demo.jpg b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/simple-demo.jpg new file mode 100644 index 0000000..73c4deb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/simple-demo.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/spring_festival-demo.jpg b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/spring_festival-demo.jpg new file mode 100644 index 0000000..8476cb6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_daily_analysis/assets/spring_festival-demo.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/bot_manager.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/bot_manager.py new file mode 100644 index 0000000..35fd27d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/bot_manager.py @@ -0,0 +1,36 @@ +"""NoneBot 版 BotManager:管理 OneBot 适配器实例。""" + +from __future__ import annotations + +from typing import Any + + +class BotManager: + def __init__(self): + self._adapters: dict[str, Any] = {} + + def register_adapter(self, adapter: Any, platform_id: str | None = None) -> None: + pid = platform_id or getattr(adapter, "platform_id", "onebot") or "onebot" + self._adapters[str(pid)] = adapter + + def set_bot_instance(self, bot_instance: Any, platform_id: str | None = None) -> None: + """兼容接口:按平台登记一个适配器。""" + pid = platform_id or "onebot" + from .adapter import OneBotAdapter + self.register_adapter(OneBotAdapter(bot_instance, {"platform_id": pid}), pid) + + def get_adapter(self, platform_id: str | None = None) -> Any | None: + if not self._adapters: + return None + if platform_id and str(platform_id) in self._adapters: + return self._adapters[str(platform_id)] + return next(iter(self._adapters.values())) + + def get_adapter_platform_id(self, adapter: Any) -> str: + return str(getattr(adapter, "platform_id", "onebot")) + + def get_platform_ids(self) -> list[str]: + return list(self._adapters.keys()) + + def get_platform_count(self) -> int: + return len(self._adapters) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/config.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/config.py new file mode 100644 index 0000000..3b327de --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/config.py @@ -0,0 +1,142 @@ +"""NoneBot 版插件配置加载。 + +配置持久化在数据目录 config.json,键值结构与原 AstrBot 配置分组一致, +这样可以直接喂给 core 的 ConfigManager(它本质只读嵌套 dict)。 +""" + +from __future__ import annotations + +import json +import os +from pathlib import Path + +from .core.shared.constants import PLUGIN_NAME +from .core.utils.paths import get_data_dir + + +class ConfigDict(dict): + """兼容原 ConfigManager 的 dict;save_config 会把改动持久化到 config.json。""" + + def save_config(self) -> None: + try: + config_file().write_text( + json.dumps(dict(self), ensure_ascii=False, indent=2, default=str), + encoding="utf-8", + ) + except OSError: + pass + + +def _build_from_items(items: dict) -> dict: + """从 schema 的 items 递归生成嵌套默认配置。""" + out: dict = {} + for key, item in items.items(): + if not isinstance(item, dict): + continue + if item.get("type") == "object" and isinstance(item.get("items"), dict): + out[key] = _build_from_items(item["items"]) + elif "default" in item: + out[key] = item["default"] + return out + + +def _schema_defaults() -> dict: + """从插件的 _conf_schema.json 读取完整默认配置。""" + schema_path = Path(__file__).resolve().parents[0] / "_conf_schema.json" + try: + schema = json.loads(schema_path.read_text(encoding="utf-8-sig")) + except (OSError, json.JSONDecodeError): + return {} + defaults: dict = {} + for group, spec in schema.items(): + if isinstance(spec, dict) and isinstance(spec.get("items"), dict): + defaults[group] = _build_from_items(spec["items"]) + return defaults + + +def _read_config_value(*names: str, default: str = "") -> str: + """依次从 shell 环境变量与 NoneBot driver.config(.env) 读取值。 + + NoneBot 的 .env 是通过 pydantic 加载的,不会写入 os.environ, + 因此必须能从 get_driver().config 的小写属性读取。优先环境变量。 + """ + for n in names: + v = os.environ.get(n) + if v: + return str(v) + try: + from nonebot import get_driver + drv_cfg = get_driver().config + except Exception: + return default + for n in names: + attr = n.lower() + try: + v = getattr(drv_cfg, attr, None) + except Exception: + v = None + if v: + return str(v) + return default + + +def _llm_env_values() -> dict: + """用户必填的 LLM 端点/密钥/模型;AstrBot 版是 Provider 体系,插件本身不存这些。""" + return { + "llm_api_base": _read_config_value("HEXI_LLM_API_BASE"), + "llm_api_key": _read_config_value("HEXI_LLM_API_KEY"), + "llm_model": _read_config_value("HEXI_LLM_MODEL"), + } + + +def _default_config() -> dict: + cfg = _schema_defaults() + cfg.setdefault("llm", {}).update(_llm_env_values()) + cfg.setdefault("basic", {}).setdefault("output_format", ["image"]) + cfg.setdefault("basic", {}).setdefault("enable_base64_image", True) + cfg.setdefault("basic", {}).setdefault("analysis_days", 1) + cfg.setdefault("basic", {}).setdefault("max_messages", 1000) + cfg.setdefault("basic", {}).setdefault("min_messages_threshold", 50) + cfg.setdefault("basic", {}).setdefault("filter_bot_messages", True) + cfg.setdefault("analysis_features", {}).setdefault("chat_quality_analysis_enabled", False) + cfg.setdefault("incremental", {}).setdefault("incremental_enabled", False) + return cfg + + +def config_file() -> Path: + return get_data_dir(PLUGIN_NAME) / "config.json" + + +def load_config() -> ConfigDict: + cfg = ConfigDict(_default_config()) + f = config_file() + if f.exists(): + try: + user = json.loads(f.read_text(encoding="utf-8")) + for group, values in user.items(): + if isinstance(values, dict): + cfg.setdefault(group, {}).update(values) + else: + cfg[group] = values + except (OSError, json.JSONDecodeError) as e: + _log_warn(f"读取配置文件失败: {e}") + # 环境变量/NoneBot .env 永远优先于持久化 config.json,避免被空值覆盖 + cfg.setdefault("llm", {}).update(_llm_env_values()) + return cfg + + +def save_config(cfg: dict) -> None: + try: + config_file().write_text( + json.dumps(cfg, ensure_ascii=False, indent=2), encoding="utf-8" + ) + except OSError as e: + _log_warn(f"保存配置文件失败: {e}") + + +def _log_warn(msg: str) -> None: + try: + from .core.utils.logger import logger + logger.warning(msg) + except Exception: + pass diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/__init__.py new file mode 100644 index 0000000..8361570 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/__init__.py @@ -0,0 +1,17 @@ +""" +群日常分析插件 - 源代码包 + +本包包含插件的核心实现,采用 DDD (领域驱动设计) 架构: +- application: 应用层 - 编排领域服务,处理用例 +- domain: 领域层 - 核心业务逻辑,平台无关 +- infrastructure: 基础设施层 - 外部服务适配 +- shared: 共享组件 - 跨层使用的工具和常量 + +遗留模块(渐进式迁移中): +- analysis: 分析器实现 +- core: 核心组件 +- reports: 报告生成 +- scheduler: 定时任务 +- utils: 工具函数 +- visualization: 可视化组件 +""" diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/__init__.py new file mode 100644 index 0000000..e7c6d1e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/__init__.py @@ -0,0 +1 @@ +# 应用层 - 编排和用例 diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/commands/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/commands/__init__.py new file mode 100644 index 0000000..26c01f8 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/commands/__init__.py @@ -0,0 +1,5 @@ +"""命令相关应用服务。""" + +from .template_command_service import TemplateCommandService + +__all__ = ["TemplateCommandService"] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/commands/template_command_service.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/commands/template_command_service.py new file mode 100644 index 0000000..5a47863 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/commands/template_command_service.py @@ -0,0 +1,117 @@ +"""模板管理相关命令服务。""" + +from __future__ import annotations + +import asyncio +import os + +from astrbot.api.message_components import Image, Node, Nodes, Plain + + +class TemplateCommandService: + """封装模板命令的文件系统与消息构建逻辑。""" + + _CIRCLE_NUMBERS = ["①", "②", "③", "④", "⑤", "⑥", "⑦", "⑧", "⑨", "⑩"] + + def __init__(self, plugin_root: str): + self.plugin_root = plugin_root + + def resolve_template_base_dir(self) -> str: + """解析报告模板目录(兼容新旧目录结构)。""" + candidate_dirs = [ + os.path.join( + self.plugin_root, "src", "infrastructure", "reporting", "templates" + ), + os.path.join(self.plugin_root, "src", "reports", "templates"), + ] + for candidate in candidate_dirs: + if os.path.isdir(candidate): + return candidate + return candidate_dirs[0] + + def resolve_template_preview_path(self, template_name: str) -> str | None: + """解析模板预览图路径。""" + candidate_paths = [ + os.path.join(self.plugin_root, "assets", f"{template_name}-demo.jpg"), + ] + for candidate in candidate_paths: + if os.path.exists(candidate): + return candidate + return None + + async def list_available_templates(self) -> list[str]: + """列出所有可用模板。""" + template_base_dir = self.resolve_template_base_dir() + + def _list_templates_sync() -> list[str]: + if os.path.exists(template_base_dir): + return sorted( + [ + d + for d in os.listdir(template_base_dir) + if os.path.isdir(os.path.join(template_base_dir, d)) + and not d.startswith("__") + ] + ) + return [] + + return await asyncio.to_thread(_list_templates_sync) + + async def template_exists(self, template_name: str) -> bool: + """检查模板目录是否存在。""" + template_dir = os.path.join(self.resolve_template_base_dir(), template_name) + return await asyncio.to_thread(os.path.exists, template_dir) + + def parse_template_input( + self, template_input: str, available_templates: list[str] + ) -> tuple[str | None, str | None]: + """解析模板输入(支持模板名或序号)。""" + if not template_input: + return None, "❌ 模板参数不能为空" + + if template_input.isdigit(): + index = int(template_input) + if 1 <= index <= len(available_templates): + return available_templates[index - 1], None + return ( + None, + f"❌ 无效的序号 '{template_input}',有效范围: 1-{len(available_templates)}", + ) + + return template_input, None + + def build_template_preview_nodes( + self, + available_templates: list[str], + current_template: str, + bot_id: str, + ) -> Nodes: + """构建模板预览的合并消息节点。""" + node_list = [] + + header_content = [ + Plain( + f"🎨 可用报告模板列表\n📌 当前使用: {current_template}\n💡 使用 /设置模板 [序号] 切换" + ) + ] + node_list.append(Node(uin=bot_id, name="模板预览", content=header_content)) + + for index, template_name in enumerate(available_templates): + current_mark = " ✅" if template_name == current_template else "" + num_label = ( + self._CIRCLE_NUMBERS[index] + if index < len(self._CIRCLE_NUMBERS) + else f"({index + 1})" + ) + + node_content = [Plain(f"{num_label} {template_name}{current_mark}")] + preview_image_path = self.resolve_template_preview_path(template_name) + if preview_image_path: + node_content.append(Image.fromFileSystem(preview_image_path)) + else: + cdn_url = f"https://fastly.jsdelivr.net/gh/SXP-Simon/astrbot_plugin_qq_group_daily_analysis@main/assets/{template_name}-demo.jpg" + node_content.append(Image.fromURL(cdn_url)) + + node_list.append(Node(uin=bot_id, name=template_name, content=node_content)) + + return Nodes(node_list) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/services/analysis_application_service.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/services/analysis_application_service.py new file mode 100644 index 0000000..f2515bb --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/services/analysis_application_service.py @@ -0,0 +1,1971 @@ +""" +分析应用服务 - 应用层 +实现"每日群聊分析并生成报告"及"增量分析"核心用例。 +负责协调领域服务、基础设施适配器及持久化层。 +""" + +from __future__ import annotations + +import asyncio +import dataclasses +import datetime as dt +import hashlib +import time as time_mod +import weakref +from collections import defaultdict +from collections.abc import Mapping +from contextlib import asynccontextmanager, nullcontext +from pathlib import Path +from typing import Any + +from ...domain.entities.incremental_state import IncrementalBatch +from ...domain.models.data_models import TokenUsage +from ...domain.repositories.analysis_repository import IAnalysisProvider +from ...domain.repositories.report_repository import IReportGenerator +from ...domain.services.analysis_domain_service import ( + AnalysisDomainService, + UserActivityStats, +) +from ...domain.services.incremental_merge_service import IncrementalMergeService +from ...domain.services.statistics_service import StatisticsService +from ...domain.value_objects.unified_message import UnifiedMessage +from ...infrastructure.persistence.incremental_store import IncrementalStore +from ...shared.trace_context import TraceContext +from ...utils.logger import logger + +_LLM_SEMAPHORE_INFO_SECONDS = 1.0 +_LLM_SEMAPHORE_WARN_SECONDS = 15.0 + + +class DuplicateGroupTaskError(Exception): + """当同一个群组在同一时间尝试启动相同类型的重复分析任务时抛出。""" + + pass + + +class AnalysisApplicationService: + """分析应用服务 - 协调业务流程(每日分析 + 增量分析)""" + + def __init__( + self, + config_manager: Any, + bot_manager: Any, + history_manager: Any, + report_generator: IReportGenerator, + llm_analyzer: IAnalysisProvider, + statistics_service: StatisticsService, + analysis_domain_service: AnalysisDomainService, + incremental_store: IncrementalStore | None = None, + incremental_merge_service: IncrementalMergeService | None = None, + checkpoint_store: Any | None = None, + html_render: Any | None = None, + ): + self.config_manager = config_manager + self.bot_manager = bot_manager + self.history_manager = history_manager + self.report_generator = report_generator + self.llm_analyzer = llm_analyzer + self.statistics_service = statistics_service + self.analysis_domain_service = analysis_domain_service + self.incremental_store = incremental_store + self.incremental_merge_service = incremental_merge_service + self.checkpoint_store = checkpoint_store + self.html_render = html_render + self._locks = weakref.WeakValueDictionary() + # 全局 LLM 分析信号量,控制对外 API 的并发压力 + # 使用专用的 LLM 并发配置项 + max_concurrent = max(1, int(self.config_manager.get_llm_max_concurrent())) + self._llm_max_concurrent = max_concurrent + self.llm_semaphore = asyncio.Semaphore(max_concurrent) + # 用于追踪当前正在执行的任务,实现原子的“检查并设置”逻辑,避免 locked() 竞态 + self._active_tasks = set() + + @asynccontextmanager + async def group_lock(self, group_id: str, task_type: str = "analysis"): + """ + 同一时间、同一个群、同一种任务只能有一个在执行 + 锁将在退出上下文时自动释放。 + """ + lock_key = f"{task_type}:{group_id}" + + # 获取或创建该群组特有的锁(保留锁作为第二道资源限流防线) + lock = self._locks.get(lock_key) + if lock is None: + lock = asyncio.Lock() + self._locks[lock_key] = lock + + # 使用同步集合实现原子化的“运行中”检查 + # 在 asyncio 的单线程循环中,同步代码段不会被中断,因此这是原子操作 + if lock_key in self._active_tasks: + logger.warning(f"群 {group_id} 的 {task_type} 任务已在运行,跳过本次请求") + raise DuplicateGroupTaskError(f"Duplicate task for {lock_key}") + + # 占位:标记任务开始 + self._active_tasks.add(lock_key) + + try: + async with lock: + logger.debug(f"[Lock] 已获取群 {group_id} 的 {task_type} 排他锁") + yield + finally: + # 释放:标记任务结束 + self._active_tasks.discard(lock_key) + logger.debug(f"[Lock] 已释放群 {group_id} 的 {task_type} 排他锁") + + @asynccontextmanager + async def _llm_slot(self, group_id: str, stage: str): + """观察并占用一次 LLM 分析槽位。 + + Args: + group_id: 当前分析任务所属群号。 + stage: 分析阶段名称,用于区分全量、增量、最终报告等入口。 + + Yields: + None: 成功进入 LLM 分析槽位后交还给调用方执行实际分析。 + + Raises: + asyncio.CancelledError: 调用方任务被取消时原样抛出。 + """ + trace = TraceContext.current() + missing_marker = object() + previous_stage = missing_marker + previous_group_id = missing_marker + if trace: + # 将外层分析阶段写入 Trace 元数据,供更底层的 Provider 调用日志读取。 + previous_stage = trace.metadata.get("llm_stage", missing_marker) + previous_group_id = trace.metadata.get("llm_group_id", missing_marker) + trace.metadata["llm_stage"] = stage + trace.metadata["llm_group_id"] = group_id + + wait_started_at = time_mod.monotonic() + logger.debug( + f"[LLM 队列观测] 等待分析槽位: group={group_id}, stage={stage}, " + f"available={getattr(self.llm_semaphore, '_value', None)}/" + f"{self._llm_max_concurrent}, active={len(self._active_tasks)}" + ) + while True: + try: + await asyncio.wait_for( + self.llm_semaphore.acquire(), timeout=_LLM_SEMAPHORE_WARN_SECONDS + ) + break + except TimeoutError: + logger.warning( + f"[LLM 队列观测] 等待分析槽位超过 " + f"{time_mod.monotonic() - wait_started_at:.0f}s: " + f"group={group_id}, stage={stage}, " + f"available={getattr(self.llm_semaphore, '_value', None)}/" + f"{self._llm_max_concurrent}, active={len(self._active_tasks)}" + ) + + waited_seconds = time_mod.monotonic() - wait_started_at + log_method = ( + logger.info + if waited_seconds >= _LLM_SEMAPHORE_INFO_SECONDS + else logger.debug + ) + log_method( + f"[LLM 队列观测] 已进入分析槽位: group={group_id}, stage={stage}, " + f"wait={waited_seconds:.2f}s, " + f"available={getattr(self.llm_semaphore, '_value', None)}/" + f"{self._llm_max_concurrent}, active={len(self._active_tasks)}" + ) + run_started_at = time_mod.monotonic() + try: + yield + finally: + self.llm_semaphore.release() + logger.debug( + f"[LLM 队列观测] 已释放分析槽位: group={group_id}, stage={stage}, " + f"duration={time_mod.monotonic() - run_started_at:.2f}s, " + f"available={getattr(self.llm_semaphore, '_value', None)}/" + f"{self._llm_max_concurrent}, active={len(self._active_tasks)}" + ) + if trace: + # 恢复原有 Trace 元数据,避免嵌套或后续任务误读上一段分析阶段。 + if previous_stage is missing_marker: + trace.metadata.pop("llm_stage", None) + else: + trace.metadata["llm_stage"] = previous_stage + if previous_group_id is missing_marker: + trace.metadata.pop("llm_group_id", None) + else: + trace.metadata["llm_group_id"] = previous_group_id + + async def execute_daily_analysis( + self, + group_id: str, + platform_id: str | None = None, + manual: bool = False, + days: int | None = None, + ) -> dict[str, Any]: + """ + 执行每日分析用例。 + + 流程: + 1. 获取适配器 + 2. 拉取消息 (Infrastructure) + 3. 基础统计 (Domain Service) + 4. 用户分析 (Domain Service) + 5. LLM 语义分析 (Infrastructure/Analysis Bridge) + 6. 生成报告 (Visualization/Infrastructure) + 7. 持久化摘要 (Persistence) + 8. 返回结果 + """ + + trace = TraceContext.current() + if not trace: + trace = TraceContext.get_or_create( + group_id=str(group_id), + platform=platform_id or "", + trigger_type="manual" if manual else "auto", + auto_bind=True, + ) + else: + if not trace.group_id: + trace.group_id = str(group_id) + if not trace.platform and platform_id: + trace.platform = platform_id + trace.trigger_type = "manual" if manual else "auto" + + async with self.group_lock(group_id, "daily"): + logger.info( + f"开始执行分析用例: 群 {group_id}, platform_id={platform_id or '默认'}, days={days or '默认'}" + ) + + # 1. 获取适配器 + adapter = self.bot_manager.get_adapter(platform_id) + if not adapter: + raise ValueError(f"未找到平台 {platform_id} 的适配器") + + # 确立并回填实际运行的真实平台标识 (Real Platform Identity: 优先使用具体平台实例 ID 如 nuits) + actual_platform = ( + ( + self.bot_manager.get_adapter_platform_id(adapter) + if hasattr(self.bot_manager, "get_adapter_platform_id") + else "" + ) + or getattr(adapter, "platform_id", "") + or getattr(adapter, "platform_name", "") + or ( + platform_id + if platform_id and platform_id not in ("auto", "default", "all") + else "" + ) + ) + if trace and actual_platform: + trace.platform = str(actual_platform) + + # 检查群聊是否被禁言(包括全体禁言或对 Bot 自身禁言) + if hasattr(adapter, "is_group_muted"): + try: + if await adapter.is_group_muted(group_id): + logger.info( + f"群 {group_id} 开启了全群禁言或对 Bot 禁言,跳过本次群分析" + ) + return {"success": False, "reason": "muted"} + except Exception as e: + logger.warning(f"检查群 {group_id} 禁言状态时出错: {e}") + + # 飞书平台在分析前进行一次性权限与成员头像预热,避免报告阶段出现大面积默认头像。 + if hasattr(adapter, "prepare_group_member_cache"): + try: + logger.info( + "执行平台成员预检查: group=%s, platform=%s", + group_id, + platform_id or "default", + ) + ok, err = await adapter.prepare_group_member_cache(group_id) # type: ignore[attr-defined] + if not ok and err: + raise ValueError(err) + logger.info( + "平台成员预检查通过: group=%s, platform=%s", + group_id, + platform_id or "default", + ) + except Exception as e: + raise ValueError( + f"飞书成员信息预检查失败,请先完成应用权限授权:{e}" + ) from e + + # 2. 拉取消息 + if days is None: + days = self.config_manager.get_analysis_days() + max_count = self.config_manager.get_max_messages() + + with trace.span("FETCH_MESSAGES", {"days": days, "max_count": max_count}): + raw_messages = await adapter.fetch_messages( + group_id=group_id, days=days, max_count=max_count + ) + if trace: + for s in reversed(trace._spans): + if s.get("stage_name") == "FETCH_MESSAGES": + s.setdefault("payload", {}).update( + { + "days": days, + "max_count": max_count, + "fetched_count": len(raw_messages), + } + ) + break + logger.info( + "消息拉取完成: group=%s, platform=%s, raw_count=%s, days=%s, max_count=%s", + group_id, + platform_id or "default", + len(raw_messages), + days, + max_count, + ) + + if not raw_messages: + logger.warning(f"群 {group_id} 在最近 {days} 天内无消息或无法获取") + return {"success": False, "reason": "no_messages"} + + # 3. 清理消息 (Filter commands, bot messages, noise) + from ...domain.services.message_cleaner_service import MessageCleanerService + + cleaner = MessageCleanerService() + bot_self_ids = list(self.config_manager.get_bot_self_ids() or []) + if hasattr(adapter, "bot_self_ids") and adapter.bot_self_ids: + for b_id in adapter.bot_self_ids: + if b_id and str(b_id) not in bot_self_ids: + bot_self_ids.append(str(b_id)) + if not self.config_manager.get_filter_bot_messages(): + bot_self_ids = [] + logger.debug( + "filter_bot_messages=%s, bot_self_ids=%s", + self.config_manager.get_filter_bot_messages(), + bot_self_ids, + ) + + # 对于自动任务,强制过滤指令;对于手动任务,也建议过滤以保持报告纯净 + with trace.span("CLEAN_MESSAGES"): + unified_messages = cleaner.clean_messages( + raw_messages, bot_self_ids=bot_self_ids, filter_commands=True + ) + if trace: + for s in reversed(trace._spans): + if s.get("stage_name") == "CLEAN_MESSAGES": + s.setdefault("payload", {}).update( + { + "raw_count": len(raw_messages), + "cleaned_count": len(unified_messages), + "dropped_count": max( + len(raw_messages) - len(unified_messages), 0 + ), + "retention_rate": round( + len(unified_messages) + / max(len(raw_messages), 1) + * 100, + 1, + ), + "bot_filter_enabled": bool( + self.config_manager.get_filter_bot_messages() + ), + } + ) + break + trace.set_context_metrics( + raw_message_count=len(raw_messages), + cleaned_message_count=len(unified_messages), + ) + logger.info( + "消息清洗完成: group=%s, platform=%s, cleaned_count=%s, dropped=%s", + group_id, + platform_id or "default", + len(unified_messages), + max(len(raw_messages) - len(unified_messages), 0), + ) + + # 4. 检查最小消息阈值 (在清理后进行) + threshold = self.config_manager.get_min_messages_threshold() + if len(unified_messages) < threshold and not manual: + logger.info( + f"群 {group_id} 有效消息数 ({len(unified_messages)}) 未达到自动分析阈值 ({threshold})" + ) + return {"success": False, "reason": "below_threshold"} + + # 5. 基础统计 (Domain Service) + with trace.span("STATS_ANALYSIS"): + statistics = await asyncio.to_thread( + self.statistics_service.calculate_group_statistics, unified_messages + ) + user_activity = await asyncio.to_thread( + self.analysis_domain_service.analyze_user_activity, + unified_messages, + bot_self_ids, + ) + if trace: + for s in reversed(trace._spans): + if s.get("stage_name") == "STATS_ANALYSIS": + s.setdefault("payload", {}).update( + { + "message_count": getattr( + statistics, + "message_count", + len(unified_messages), + ), + "character_count": getattr( + statistics, "total_characters", 0 + ), + "participant_count": getattr( + statistics, "participant_count", 0 + ), + "most_active_period": getattr( + statistics, "most_active_period", "" + ), + "emoji_count": getattr( + statistics, "emoji_count", 0 + ), + "active_users_analyzed": len(user_activity) + if user_activity + else 0, + } + ) + break + + max_user_titles = self.config_manager.get_max_user_titles() + top_users = self.analysis_domain_service.get_top_users( + user_activity, limit=max_user_titles + ) + + # 保存前置清洗与基础统计 Checkpoint,用于后续一键断点续跑 (Resume) + if self.checkpoint_store: + try: + date_str = dt.datetime.now().strftime("%Y-%m-%d") + self.checkpoint_store.save_checkpoint( + group_id=group_id, + date_str=date_str, + stage_name="CLEAN_MESSAGES", + data={ + "group_id": group_id, + "platform_id": platform_id, + "date_str": date_str, + "statistics": self._to_json_friendly(statistics), + "user_activity": self._to_json_friendly(user_activity), + "top_users": self._to_json_friendly(top_users), + "unified_messages": [ + self._to_json_friendly(m) for m in unified_messages + ], + }, + ) + except Exception as e: + logger.warning(f"保存前置 Checkpoint 失败: {e}") + + # 5. LLM 语义分析 (为了保持兼容,目前直接传 UnifiedMessage,后续如需传 raw dict 再加转换) + topic_enabled = self.config_manager.get_topic_analysis_enabled() + user_title_enabled = self.config_manager.get_user_title_analysis_enabled() + golden_quote_enabled = ( + self.config_manager.get_golden_quote_analysis_enabled() + ) + chat_quality_enabled = ( + self.config_manager.get_chat_quality_analysis_enabled() + ) + + topics = [] + user_titles = [] + golden_quotes = [] + chat_quality_review = None + total_token_usage = TokenUsage() + + legacy_messages = self.statistics_service._convert_to_legacy_dict( + unified_messages + ) + + unified_msg_origin = ( + f"{platform_id}:GroupMessage:{group_id}" if platform_id else group_id + ) + analysis_stage = "full_manual" if manual else "full_scheduled" + + if ( + topic_enabled + or user_title_enabled + or golden_quote_enabled + or chat_quality_enabled + ): + with trace.span("LLM_ANALYSIS") as span_rec: + async with self._llm_slot(group_id, analysis_stage): + logger.debug( + f"[LLM] 已进入普通全量分析队列 " + f"(群: {group_id}, stage: {analysis_stage})" + ) + ( + topics, + user_titles, + golden_quotes, + total_token_usage, + chat_quality_review, + ) = await self.llm_analyzer.analyze_all_concurrent( + legacy_messages, + user_activity, + umo=unified_msg_origin, + top_users=top_users, + topic_enabled=topic_enabled, + user_title_enabled=user_title_enabled, + golden_quote_enabled=golden_quote_enabled, + chat_quality_enabled=chat_quality_enabled, + ) + + # 细粒度子任务状态判定:开启的子任务产出情况 + enabled_count = sum( + [ + bool(topic_enabled), + bool(user_title_enabled), + bool(golden_quote_enabled), + bool(chat_quality_enabled), + ] + ) + success_count = sum( + [ + bool(topics) if topic_enabled else False, + bool(user_titles) if user_title_enabled else False, + bool(golden_quotes) if golden_quote_enabled else False, + bool(chat_quality_review) + if chat_quality_enabled + else False, + ] + ) + + if enabled_count > 0 and success_count == 0: + span_rec["status"] = "failed" + span_rec.setdefault("payload", {})["error"] = ( + "大模型文本分析所有启用的子任务均调用失败或重试耗尽,已中断后续任务" + ) + if trace: + trace.metadata["has_warnings"] = False + trace.metadata["failure_stage"] = "LLM_ANALYSIS" + return { + "success": False, + "reason": "llm_analysis_failed", + "error": "大模型文本分析全部子任务失败,已中止后续报告生成与发送", + } + elif enabled_count > 0 and success_count < enabled_count: + span_rec["status"] = "warning" + span_rec.setdefault("payload", {})["warning"] = ( + f"大模型文本分析部分子任务未产出结果 ({success_count}/{enabled_count} 成功)" + ) + if trace: + trace.metadata["has_warnings"] = True + + # 回填结果 + statistics.golden_quotes = golden_quotes + statistics.token_usage = total_token_usage + + analysis_result = { + "statistics": statistics, + "topics": topics, + "user_titles": user_titles, + "user_analysis": user_activity, + "chat_quality_review": chat_quality_review, + } + + # 6. 持久化摘要 (Persistence) + with trace.span("SAVE_SUMMARY"): + await self.history_manager.save_analysis(group_id, analysis_result) + date_str = dt.datetime.now().strftime("%Y-%m-%d") + if self.checkpoint_store: + try: + self.checkpoint_store.save_checkpoint( + group_id=group_id, + date_str=date_str, + stage_name="LLM_ANALYSIS", + data=self._serialize_analysis_result(analysis_result), + ) + except Exception as e: + logger.warning(f"保存分析 Checkpoint 失败: {e}") + if trace: + for s in reversed(trace._spans): + if s.get("stage_name") == "SAVE_SUMMARY": + s.setdefault("payload", {}).update( + { + "date": date_str, + "topics_persisted": len(topics), + "titles_persisted": len(user_titles), + "checkpoint_saved": bool(self.checkpoint_store), + } + ) + break + + # 7. 生成报告并发送 (应用层编排发送动作) + # 这里由调用方处理发送,本服务只返回分析结果和可能的视觉产物 + return { + "success": True, + "analysis_result": analysis_result, + "messages_count": len(unified_messages), + "adapter": adapter, + "group_id": group_id, + "platform_id": getattr(adapter, "platform_id", platform_id), + } + + def _to_json_friendly(self, obj: Any) -> Any: + """递归将领域模型、dataclass、Enum、datetime 等转换为标准 JSON 原生数据结构。""" + import enum + from datetime import date, datetime, time + + if obj is None: + return None + if isinstance(obj, enum.Enum): + return obj.value + if isinstance(obj, (datetime, date, time)): + return obj.isoformat() + if dataclasses.is_dataclass(obj) and not isinstance(obj, type): + return self._to_json_friendly(dataclasses.asdict(obj)) + if isinstance(obj, (set, tuple)): + return [self._to_json_friendly(item) for item in obj] + if isinstance(obj, list): + return [self._to_json_friendly(item) for item in obj] + if isinstance(obj, dict): + return {str(k): self._to_json_friendly(v) for k, v in obj.items()} + to_dict_fn = getattr(obj, "to_dict", None) + if callable(to_dict_fn): + try: + return self._to_json_friendly(to_dict_fn()) + except Exception: + pass + return obj + + def _serialize_analysis_result( + self, analysis_result: dict[str, Any] + ) -> dict[str, Any]: + """将包含领域对象的 analysis_result 序列化为 JSON 友好的 dict 快照。""" + return { + "statistics": self._to_json_friendly(analysis_result.get("statistics")), + "topics": self._to_json_friendly(analysis_result.get("topics", [])), + "user_titles": self._to_json_friendly( + analysis_result.get("user_titles", []) + ), + "user_analysis": self._to_json_friendly( + analysis_result.get("user_analysis", {}) + ), + "chat_quality_review": self._to_json_friendly( + analysis_result.get("chat_quality_review") + ), + } + + def _deserialize_analysis_result(self, data: dict[str, Any]) -> dict[str, Any]: + """将持久化的 JSON 快照还原为包含领域数据模型的 analysis_result。""" + from ...domain.models.data_models import ( + ActivityVisualization, + EmojiStatistics, + GoldenQuote, + GroupStatistics, + QualityDimension, + QualityReview, + SummaryTopic, + TokenUsage, + UserTitle, + ) + + stats_raw = data.get("statistics", {}) + golden_quotes = [ + GoldenQuote(**g) if isinstance(g, dict) else g + for g in stats_raw.get("golden_quotes", []) + ] + emoji_stats_raw = stats_raw.get("emoji_statistics", {}) + emoji_stats = ( + EmojiStatistics(**emoji_stats_raw) + if isinstance(emoji_stats_raw, dict) + else EmojiStatistics() + ) + act_viz_raw = stats_raw.get("activity_visualization", {}) + if isinstance(act_viz_raw, dict): + hourly_act = act_viz_raw.get("hourly_activity") + if isinstance(hourly_act, dict): + act_viz_raw["hourly_activity"] = { + int(k) if str(k).isdigit() else k: v for k, v in hourly_act.items() + } + act_viz = ActivityVisualization(**act_viz_raw) + else: + act_viz = ActivityVisualization() + token_usage_raw = stats_raw.get("token_usage", {}) + token_usage = ( + TokenUsage(**token_usage_raw) + if isinstance(token_usage_raw, dict) + else TokenUsage() + ) + + quality_raw = data.get("chat_quality_review") or stats_raw.get( + "chat_quality_review" + ) + quality_review = None + if isinstance(quality_raw, dict): + dims = [ + QualityDimension(**d) if isinstance(d, dict) else d + for d in quality_raw.get("dimensions", []) + ] + quality_review = QualityReview( + title=str(quality_raw.get("title", "群聊质量锐评")), + subtitle=str(quality_raw.get("subtitle", "")), + dimensions=dims, + summary=str(quality_raw.get("summary", "")), + ) + + stats = GroupStatistics( + message_count=int(stats_raw.get("message_count", 0)), + total_characters=int(stats_raw.get("total_characters", 0)), + participant_count=int(stats_raw.get("participant_count", 0)), + most_active_period=str(stats_raw.get("most_active_period", "")), + golden_quotes=golden_quotes, + emoji_count=int(stats_raw.get("emoji_count", 0)), + emoji_statistics=emoji_stats, + activity_visualization=act_viz, + token_usage=token_usage, + chat_quality_review=quality_review, + ) + + topics = [ + SummaryTopic(**t) if isinstance(t, dict) else t + for t in data.get("topics", []) + ] + user_titles = [ + UserTitle(**t) if isinstance(t, dict) else t + for t in data.get("user_titles", []) + ] + + return { + "statistics": stats, + "topics": topics, + "user_titles": user_titles, + "user_analysis": data.get("user_analysis", {}), + "chat_quality_review": quality_review, + } + + async def rerender_report( + self, + group_id: str, + date_str: str, + template_name: str, + platform_id: str | None = None, + render_format: str = "image", + trace_id: str | None = None, + ) -> dict[str, Any]: + """使用指定的模板对历史分析产物免 Token 重新渲染。""" + if not self.checkpoint_store: + return {"success": False, "reason": "未配置 Checkpoint 存储器"} + + cached_data = self.checkpoint_store.get_checkpoint( + group_id, date_str, "LLM_ANALYSIS" + ) + if not cached_data: + return { + "success": False, + "reason": f"未找到群 {group_id} 在 {date_str} 的分析产物快照", + } + + analysis_result = self._deserialize_analysis_result(cached_data) + + reports_dir = ( + getattr(self.report_generator, "data_dir", None) + or self.config_manager.get_data_dir() + ) / "reports" + reports_dir.mkdir(parents=True, exist_ok=True) + ts_str = dt.datetime.now().strftime("%Y%m%d_%H%M%S") + + # 渲染长图或 HTML + if render_format == "html": + filename = ( + f"report_{group_id}_{ts_str}_{trace_id}_{template_name}.html" + if trace_id + else f"report_{group_id}_{ts_str}_{template_name}.html" + ) + dest = reports_dir / filename + html_path, _ = await self.report_generator.generate_html_report( + analysis_result=analysis_result, + group_id=group_id, + template_theme=template_name, + custom_filename=filename, + trace_id=trace_id, + ) + if not html_path or not Path(html_path).exists(): + prep_func = getattr(self.report_generator, "_prepare_render_data", None) + if callable(prep_func): + prep_res = prep_func(analysis_result) + render_data = ( + await prep_res if asyncio.iscoroutine(prep_res) else prep_res + ) + else: + render_data = analysis_result + html_tpls = getattr(self.report_generator, "html_templates", None) + if html_tpls and hasattr(html_tpls, "render_template"): + render_kwargs: dict[str, Any] = ( + dict(render_data) if isinstance(render_data, Mapping) else {} + ) + html_content = html_tpls.render_template( + "html_template.html", + template_theme=template_name, + **render_kwargs, + ) + dest.write_text(html_content, encoding="utf-8") + + if trace_id: + from ...shared.trace_context import _global_trace_store + + if _global_trace_store is not None: + try: + trace_data = _global_trace_store.get_trace(trace_id) + if trace_data: + extra = trace_data.get("extra") or {} + rfiles = extra.setdefault("report_files", []) + if not any(rf.get("filename") == filename for rf in rfiles): + rfiles.append( + { + "filename": filename, + "path": str(dest.resolve()), + "format": "html", + "template": template_name, + "size_bytes": dest.stat().st_size + if dest.exists() + else 0, + "created_at": time_mod.time(), + } + ) + trace_data["extra"] = extra + _global_trace_store.save_trace(trace_data) + except Exception: + pass + + return { + "success": True, + "filename": filename, + "report_path": str(dest), + "is_html": True, + "from_checkpoint": True, + "trace_id": trace_id, + } + else: + image_res = await self.report_generator.generate_image_report( + analysis_result=analysis_result, + group_id=group_id, + html_render_func=self.html_render, + template_theme=template_name, + ) + image_url = image_res[0] if isinstance(image_res, tuple) else image_res + filename = ( + f"report_{group_id}_{ts_str}_{trace_id}_{template_name}.jpg" + if trace_id + else f"report_{group_id}_{ts_str}_{template_name}.jpg" + ) + dest = reports_dir / filename + if image_url and Path(image_url).exists(): + import shutil + + shutil.copy2(image_url, dest) + elif image_url and image_url.startswith("base64://"): + import base64 + + data = base64.b64decode(image_url[9:]) + dest.write_bytes(data) + + if trace_id: + from ...shared.trace_context import _global_trace_store + + if _global_trace_store is not None: + try: + trace_data = _global_trace_store.get_trace(trace_id) + if trace_data: + extra = trace_data.get("extra") or {} + rfiles = extra.setdefault("report_files", []) + if not any(rf.get("filename") == filename for rf in rfiles): + rfiles.append( + { + "filename": filename, + "path": str(dest.resolve()), + "format": "image", + "template": template_name, + "size_bytes": dest.stat().st_size + if dest.exists() + else 0, + "created_at": time_mod.time(), + } + ) + trace_data["extra"] = extra + _global_trace_store.save_trace(trace_data) + except Exception: + pass + + return { + "success": True, + "filename": filename, + "report_path": str(dest), + "image_url": image_url, + "is_html": False, + "from_checkpoint": True, + "trace_id": trace_id, + } + + async def resume_analysis( + self, + trace_id: str, + group_id: str, + platform_id: str | None = None, + date_str: str | None = None, + template_name: str | None = None, + ) -> dict[str, Any]: + """从上一次 Checkpoint 执行幂等断点续跑""" + from ...domain.models.data_models import TokenUsage + from ...shared.trace_context import TraceContext + + if not date_str: + date_str = dt.datetime.now().strftime("%Y-%m-%d") + + trace = TraceContext.current() + if not trace: + trace = TraceContext.get_or_create( + trace_id=trace_id, + group_id=str(group_id), + platform=platform_id or "", + trigger_type="resume", + auto_bind=True, + ) + if template_name and template_name != "auto": + trace.metadata["override_template_name"] = str(template_name) + + topic_enabled = self.config_manager.get_topic_analysis_enabled() + user_title_enabled = self.config_manager.get_user_title_analysis_enabled() + golden_quote_enabled = self.config_manager.get_golden_quote_analysis_enabled() + chat_quality_enabled = self.config_manager.get_chat_quality_analysis_enabled() + + # 1. 优先检查是否有已完成的 LLM_ANALYSIS Checkpoint 或历史分析记录 + cached_llm = ( + self.checkpoint_store.get_checkpoint(group_id, date_str, "LLM_ANALYSIS") + if self.checkpoint_store + else None + ) + if not cached_llm: + try: + hist_data = await self.history_manager.get_analysis(group_id, date_str) + if hist_data and isinstance(hist_data, dict): + cached_llm = self._serialize_analysis_result(hist_data) + except Exception: + cached_llm = None + + if cached_llm: + cached_result = self._deserialize_analysis_result(cached_llm) + cached_topics = cached_result.get("topics", []) + cached_titles = cached_result.get("user_titles", []) + cached_stats = cached_result.get("statistics") + cached_quotes = ( + getattr(cached_stats, "golden_quotes", []) if cached_stats else [] + ) + cached_quality = cached_result.get("chat_quality_review") + + has_required_topics = not topic_enabled or bool(cached_topics) + has_required_titles = not user_title_enabled or bool(cached_titles) + has_required_quotes = not golden_quote_enabled or bool(cached_quotes) + has_required_quality = not chat_quality_enabled or bool(cached_quality) + + # 若全部启用的分析结果均已具备(例如仅排版制图或发送失败),直接跳过 LLM 和拉取消息,0 Token 成本直接出图与分发 + if ( + has_required_topics + and has_required_titles + and has_required_quotes + and has_required_quality + ): + logger.info( + f"群 {group_id} 命中完整的 LLM 分析产物快照,跳过消息拉取与 LLM 分析,直接进入报告排版与分发" + ) + async with self.group_lock(group_id, "daily"): + adapter = self.bot_manager.get_adapter(platform_id) + with trace.span( + "CHECKPOINT_RESTORE", + { + "stage": "LLM_ANALYSIS", + "restored": True, + "direct_render": True, + }, + ): + pass + return { + "success": True, + "analysis_result": cached_result, + "messages_count": ( + getattr(cached_stats, "message_count", 0) + if cached_stats + else 0 + ), + "adapter": adapter, + "group_id": group_id, + "platform_id": getattr(adapter, "platform_id", platform_id), + "resumed_from": "LLM_ANALYSIS", + "trace_id": trace_id, + } + + # 2. 检查是否有前置清洗 Checkpoint + clean_checkpoint = ( + self.checkpoint_store.get_checkpoint(group_id, date_str, "CLEAN_MESSAGES") + if self.checkpoint_store + else None + ) + + if not clean_checkpoint: + logger.info(f"未找到群 {group_id} 的前置清洗快照,回退到全量重新分析") + return await self.execute_daily_analysis( + group_id=group_id, + platform_id=platform_id, + manual=True, + ) + + logger.info( + f"群 {group_id} 命中 Checkpoint 快照,跳过消息拉取与清洗,直接进入 LLM 幂等续跑" + ) + async with self.group_lock(group_id, "daily"): + adapter = self.bot_manager.get_adapter(platform_id) + if not adapter: + raise ValueError(f"未找到平台 {platform_id} 的适配器") + + stats_data = clean_checkpoint.get("statistics", {}) + deserialized = self._deserialize_analysis_result( + { + "statistics": stats_data, + "user_analysis": clean_checkpoint.get("user_activity", {}), + "user_titles": clean_checkpoint.get("top_users", []), + } + ) + statistics = deserialized["statistics"] + user_activity = deserialized.get("user_analysis", {}) + top_users = deserialized.get("user_titles", []) + unified_messages = clean_checkpoint.get("unified_messages", []) + + with trace.span( + "CHECKPOINT_RESTORE", + {"stage": "CLEAN_MESSAGES", "restored": True}, + ): + pass + + cached_result = ( + self._deserialize_analysis_result(cached_llm) if cached_llm else {} + ) + + topics = cached_result.get("topics", []) + user_titles = cached_result.get("user_titles", []) + cached_stats = cached_result.get("statistics") + golden_quotes = ( + getattr(cached_stats, "golden_quotes", []) if cached_stats else [] + ) + chat_quality_review = cached_result.get("chat_quality_review") + total_token_usage = ( + getattr(cached_stats, "token_usage", TokenUsage()) + if cached_stats + else TokenUsage() + ) + + # 决定哪些子任务需要重新调用 LLM:已有成功非空产物的子任务直接复用,避免消耗重复 Token + run_topic = topic_enabled and not bool(topics) + run_user_title = user_title_enabled and not bool(user_titles) + run_golden_quote = golden_quote_enabled and not bool(golden_quotes) + run_chat_quality = chat_quality_enabled and not bool(chat_quality_review) + + reused_tasks = [] + if topic_enabled and topics: + reused_tasks.append(f"话题({len(topics)}个)") + if user_title_enabled and user_titles: + reused_tasks.append(f"称号({len(user_titles)}个)") + if golden_quote_enabled and golden_quotes: + reused_tasks.append(f"金句({len(golden_quotes)}条)") + if chat_quality_enabled and chat_quality_review: + reused_tasks.append("质量锐评") + + if reused_tasks: + logger.info( + f"群 {group_id} 续跑命中已有 LLM 产物: {', '.join(reused_tasks)},直接复用,无需消耗 Token 重跑" + ) + + legacy_messages = self.statistics_service._convert_to_legacy_dict( + unified_messages + ) + unified_msg_origin = ( + f"{platform_id}:GroupMessage:{group_id}" if platform_id else group_id + ) + + if run_topic or run_user_title or run_golden_quote or run_chat_quality: + with trace.span("LLM_ANALYSIS") as span_rec: + async with self._llm_slot(group_id, "resume"): + ( + new_topics, + new_user_titles, + new_golden_quotes, + new_tokens, + new_chat_quality, + ) = await self.llm_analyzer.analyze_all_concurrent( + legacy_messages, + user_activity, + umo=unified_msg_origin, + top_users=top_users, + topic_enabled=run_topic, + user_title_enabled=run_user_title, + golden_quote_enabled=run_golden_quote, + chat_quality_enabled=run_chat_quality, + ) + if run_topic: + topics = new_topics + if run_user_title: + user_titles = new_user_titles + if run_golden_quote: + golden_quotes = new_golden_quotes + if run_chat_quality: + chat_quality_review = new_chat_quality + + total_token_usage = TokenUsage( + prompt_tokens=total_token_usage.prompt_tokens + + new_tokens.prompt_tokens, + completion_tokens=total_token_usage.completion_tokens + + new_tokens.completion_tokens, + total_tokens=total_token_usage.total_tokens + + new_tokens.total_tokens, + ) + + enabled_count = sum( + [ + bool(run_topic), + bool(run_user_title), + bool(run_golden_quote), + bool(run_chat_quality), + ] + ) + success_count = sum( + [ + bool(new_topics) if run_topic else False, + bool(new_user_titles) if run_user_title else False, + bool(new_golden_quotes) if run_golden_quote else False, + bool(new_chat_quality) if run_chat_quality else False, + ] + ) + + if enabled_count > 0 and success_count == 0: + span_rec["status"] = "failed" + span_rec.setdefault("payload", {})["error"] = ( + "续跑大模型文本分析所有启用的子任务均调用失败或重试耗尽,已中断后续任务" + ) + if trace: + trace.metadata["has_warnings"] = False + trace.metadata["failure_stage"] = "LLM_ANALYSIS" + return { + "success": False, + "reason": "llm_analysis_failed", + "error": "大模型文本分析全部子任务失败,已中止续跑", + } + elif enabled_count > 0 and success_count < enabled_count: + span_rec["status"] = "warning" + span_rec.setdefault("payload", {})["warning"] = ( + f"续跑大模型文本分析部分子任务未产出结果 ({success_count}/{enabled_count} 成功)" + ) + if trace: + trace.metadata["has_warnings"] = True + + statistics.golden_quotes = golden_quotes + statistics.token_usage = total_token_usage + + analysis_result = { + "statistics": statistics, + "topics": topics, + "user_titles": user_titles, + "user_analysis": user_activity, + "chat_quality_review": chat_quality_review, + } + + with trace.span("SAVE_SUMMARY"): + await self.history_manager.save_analysis(group_id, analysis_result) + if self.checkpoint_store: + try: + self.checkpoint_store.save_checkpoint( + group_id=group_id, + date_str=date_str, + stage_name="LLM_ANALYSIS", + data=self._serialize_analysis_result(analysis_result), + ) + except Exception as e: + logger.warning(f"保存分析 Checkpoint 失败: {e}") + + return { + "success": True, + "analysis_result": analysis_result, + "adapter": adapter, + "resumed_from": "CLEAN_MESSAGES", + } + + async def execute_comic_topic_analysis( + self, + group_id: str, + platform_id: str | None = None, + days: int | None = None, + ) -> dict[str, Any]: + """为独立漫画命令提取话题。 + + Args: + group_id: 目标群 ID。 + platform_id: 平台适配器 ID。为空时使用默认适配器。 + days: 可选消息回溯天数。为空时使用普通分析的默认天数。 + + Returns: + 成功时返回提取到的话题和适配器信息;失败时返回 no_messages、 + muted 或 no_topics 等原因。 + + Raises: + ValueError: 找不到对应平台适配器时抛出。 + """ + async with self.group_lock(group_id, "comic"): + logger.info( + "开始执行手动漫画话题分析: group=%s, platform=%s, days=%s", + group_id, + platform_id or "default", + days or "default", + ) + + adapter = self.bot_manager.get_adapter(platform_id) + if not adapter: + raise ValueError(f"未找到平台 {platform_id} 的适配器") + + if hasattr(adapter, "is_group_muted"): + try: + if await adapter.is_group_muted(group_id): + logger.info( + "群 %s 开启了禁言,跳过本次手动漫画话题分析", + group_id, + ) + return {"success": False, "reason": "muted"} + except Exception as e: + logger.warning( + "检查群 %s 禁言状态时出错: %s", + group_id, + e, + ) + + if days is None: + days = self.config_manager.get_analysis_days() + max_count = self.config_manager.get_max_messages() + + trace = TraceContext.current() + + with trace.span("FETCH_MESSAGES") if trace else nullcontext() as fetch_span: + raw_messages = await adapter.fetch_messages( + group_id=group_id, days=days, max_count=max_count + ) + if fetch_span and isinstance(fetch_span, dict): + fetch_span.setdefault("payload", {}).update( + { + "raw_count": len(raw_messages), + "days": days, + "max_count": max_count, + "platform": platform_id or "default", + } + ) + logger.info( + "手动漫画消息拉取完成: group=%s, platform=%s, raw_count=%s, days=%s, max_count=%s", + group_id, + platform_id or "default", + len(raw_messages), + days, + max_count, + ) + if not raw_messages: + return {"success": False, "reason": "no_messages"} + + from ...domain.services.message_cleaner_service import MessageCleanerService + + cleaner = MessageCleanerService() + bot_self_ids = self.config_manager.get_bot_self_ids() + if not self.config_manager.get_filter_bot_messages(): + bot_self_ids = [] + with trace.span("CLEAN_MESSAGES") if trace else nullcontext() as clean_span: + unified_messages = cleaner.clean_messages( + raw_messages, bot_self_ids=bot_self_ids, filter_commands=True + ) + dropped_count = max(len(raw_messages) - len(unified_messages), 0) + if clean_span and isinstance(clean_span, dict): + clean_span.setdefault("payload", {}).update( + { + "cleaned_count": len(unified_messages), + "dropped_count": dropped_count, + "filter_bot_messages": bool( + self.config_manager.get_filter_bot_messages() + ), + } + ) + logger.info( + "手动漫画消息清洗完成: group=%s, platform=%s, cleaned_count=%s, dropped=%s", + group_id, + platform_id or "default", + len(unified_messages), + max(len(raw_messages) - len(unified_messages), 0), + ) + if not unified_messages: + return {"success": False, "reason": "no_messages"} + + legacy_messages = self.statistics_service._convert_to_legacy_dict( + unified_messages + ) + unified_msg_origin = ( + f"{platform_id}:GroupMessage:{group_id}" if platform_id else group_id + ) + + with trace.span("LLM_ANALYSIS") if trace else nullcontext() as llm_span: + async with self._llm_slot(group_id, "comic_manual"): + topics, token_usage = await self.llm_analyzer.analyze_topics( + legacy_messages, unified_msg_origin + ) + if llm_span and isinstance(llm_span, dict): + llm_span.setdefault("payload", {}).update( + { + "topics_count": len(topics) if topics else 0, + "prompt_tokens": getattr(token_usage, "prompt_tokens", 0), + "completion_tokens": getattr( + token_usage, "completion_tokens", 0 + ), + "total_tokens": getattr(token_usage, "total_tokens", 0), + } + ) + + if not topics: + return {"success": False, "reason": "no_topics"} + + return { + "success": True, + "topics": topics, + "token_usage": token_usage, + "messages_count": len(unified_messages), + "adapter": adapter, + "group_id": group_id, + "platform_id": getattr(adapter, "platform_id", platform_id), + } + + # ---------------------------------------------------------------- + # 增量分析用例 + # ---------------------------------------------------------------- + + async def execute_incremental_analysis( + self, + group_id: str, + platform_id: str | None = None, + ) -> dict[str, Any]: + """ + 执行一次增量分析用例(滑动窗口批次架构)。 + + 与每日分析不同,增量分析每次仅处理消息阈值规定的固定批次, + 提取少量话题和金句,将结果作为独立批次存储到 KV。 + 不生成用户称号(留到最终报告时再做),不生成报告。 + + 流程: + 1. 获取适配器 + 2. 拉取消息(使用增量配置的 max_messages) + 3. 清理消息 + 4. 按时间戳和消息 ID 去重:过滤已分析过的消息 + 5. 检查最小消息阈值 + 6. 计算基础统计(小时分布、用户活跃、表情) + 7. LLM 增量分析(仅话题 + 金句) + 8. 构建 IncrementalBatch 并保存 + 9. 更新最后分析消息时间戳 + 10. 返回批次结果 + + Args: + group_id: 群组 ID + platform_id: 平台标识,缺省为默认 + + Returns: + dict: 包含 success、batch_summary 等信息 + """ + trace = TraceContext.current() + if not trace: + trace = TraceContext.get_or_create( + group_id=str(group_id), + platform=platform_id or "", + trigger_type="incremental", + auto_bind=True, + ) + + async with self.group_lock(group_id, "incremental"): + analysis_started_at = time_mod.monotonic() + if not self.incremental_store: + raise RuntimeError("增量分析未初始化:缺少 IncrementalStore") + + logger.debug( + f"开始增量分析用例: 群 {group_id}, 平台 {platform_id or '默认'}" + ) + + # 1. 获取适配器 + adapter = self.bot_manager.get_adapter(platform_id) + if not adapter: + raise ValueError(f"未找到平台 {platform_id} 的适配器") + + # 检查群聊是否被禁言(包括全体禁言或对 Bot 自身禁言) + if hasattr(adapter, "is_group_muted"): + try: + if await adapter.is_group_muted(group_id): + logger.debug( + f"群 {group_id} 开启了全群禁言或对 Bot 禁言,跳过本次增量群分析" + ) + return {"success": False, "reason": "muted"} + except Exception as e: + logger.warning(f"检查群 {group_id} 禁言状态时出错: {e}") + + # 2. 拉取消息,获取进度并确定拉取量 + ( + last_analyzed_ts, + last_analyzed_message_ids, + ) = await self.incremental_store.get_last_analyzed_cursor(group_id) + days = self.config_manager.get_analysis_days() + # 复用基础拉取上限,同时保证至少能拉取一个完整增量批次。 + min_messages = self.config_manager.get_incremental_min_messages() + max_count = max(self.config_manager.get_max_messages(), min_messages) + + # 3. 拉取消息(优先从上次进度点开始回溯,确保不遗漏高活跃期间的 Gap) + fetch_started_at = time_mod.monotonic() + with trace.span("FETCH_MESSAGES", {"days": days, "max_count": max_count}): + raw_messages = await adapter.fetch_messages( + group_id=group_id, + days=days, + max_count=max_count, + since_ts=last_analyzed_ts, + ) + raw_count = len(raw_messages) + fetch_duration = time_mod.monotonic() - fetch_started_at + + if not raw_messages: + logger.warning(f"群 {group_id} 在最近 {days} 天内无消息或无法获取") + return {"success": False, "reason": "no_messages", "messages_count": 0} + + # 3. 清理消息 + from ...domain.services.message_cleaner_service import MessageCleanerService + + cleaner = MessageCleanerService() + bot_self_ids = self.config_manager.get_bot_self_ids() + if not self.config_manager.get_filter_bot_messages(): + bot_self_ids = [] + logger.debug( + "增量消息清洗配置: group=%s, filter_bot_messages=%s, bot_self_id_count=%s", + group_id, + self.config_manager.get_filter_bot_messages(), + len(bot_self_ids), + ) + with trace.span("CLEAN_MESSAGES"): + unified_messages = cleaner.clean_messages( + raw_messages, bot_self_ids=bot_self_ids, filter_commands=True + ) + cleaned_count = len(unified_messages) + trace.set_context_metrics( + raw_message_count=raw_count, + cleaned_message_count=cleaned_count, + incremental_batches=1, + ) + + # 5. 复合游标去重,避免同一秒内分批时遗漏消息。 + if last_analyzed_ts > 0: + unified_messages = [ + msg + for msg in unified_messages + if msg.timestamp > last_analyzed_ts + or ( + msg.timestamp == last_analyzed_ts + and msg.message_id not in last_analyzed_message_ids + ) + ] + + eligible_count = len(unified_messages) + logger.debug( + "增量消息筛选完成: platform=%s, group=%s, raw=%s, cleaned=%s, " + "eligible=%s, threshold=%s, fetch_limit=%s, fetch_limit_reached=%s, " + "fetch_duration=%.2fs, cursor_ts=%s, cursor_ids=%s", + platform_id or "default", + group_id, + raw_count, + cleaned_count, + eligible_count, + min_messages, + max_count, + raw_count >= max_count, + fetch_duration, + last_analyzed_ts, + len(last_analyzed_message_ids), + ) + + # 固定每批消息规模,待处理消息达到多个批次时连续处理,避免 LLM 负载波动。 + if len(unified_messages) < min_messages: + logger.debug( + f"群 {group_id} 增量分析:新消息数 ({len(unified_messages)}) " + f"未达到阈值 ({min_messages}),跳过本次分析" + ) + return { + "success": False, + "reason": "below_threshold", + "messages_count": len(unified_messages), + } + unified_messages.sort(key=lambda msg: (msg.timestamp, msg.message_id)) + if len(unified_messages) > min_messages: + unified_messages = unified_messages[:min_messages] + logger.debug( + "增量批次已选定: platform=%s, group=%s, eligible=%s, selected=%s", + platform_id or "default", + group_id, + eligible_count, + len(unified_messages), + ) + + # 6. 计算基础统计 + with trace.span("STATS_ANALYSIS"): + statistics = await asyncio.to_thread( + self.statistics_service.calculate_group_statistics, unified_messages + ) + user_activity = await asyncio.to_thread( + self.analysis_domain_service.analyze_user_activity, + unified_messages, + bot_self_ids, + ) + + # 计算本批次的小时分布 + hourly_msg_counts, hourly_char_counts = self._compute_hourly_counts( + unified_messages + ) + + # 7. LLM 增量分析(仅话题 + 金句) + topics_per_batch = self.config_manager.get_incremental_topics_per_batch() + quotes_per_batch = self.config_manager.get_incremental_quotes_per_batch() + + # 获取功能开关状态 + topic_enabled = self.config_manager.get_topic_analysis_enabled() + golden_quote_enabled = ( + self.config_manager.get_golden_quote_analysis_enabled() + ) + chat_quality_enabled = ( + self.config_manager.get_chat_quality_analysis_enabled() + ) + + # 需要将 UnifiedMessage 转换为 legacy 格式供 LLM 分析器使用 + legacy_messages = self.statistics_service._convert_to_legacy_dict( + unified_messages + ) + unified_msg_origin = ( + f"{platform_id}:GroupMessage:{group_id}" if platform_id else group_id + ) + + topics = [] + golden_quotes = [] + token_usage = TokenUsage() + chat_quality_review = None + + if topic_enabled or golden_quote_enabled or chat_quality_enabled: + with trace.span("LLM_ANALYSIS"): + async with self._llm_slot(group_id, "incremental"): + logger.debug(f"[LLM] 已进入增量分析队列 (群: {group_id})") + ( + topics, + golden_quotes, + token_usage, + chat_quality_review, + ) = await self.llm_analyzer.analyze_incremental_concurrent( + legacy_messages, + umo=unified_msg_origin, + topics_per_batch=topics_per_batch, + quotes_per_batch=quotes_per_batch, + topic_enabled=topic_enabled, + golden_quote_enabled=golden_quote_enabled, + chat_quality_enabled=chat_quality_enabled, + ) + + # 8. 构建 IncrementalBatch + # 8a. 转换话题: SummaryTopic -> dict + new_topics = [ + { + "topic": t.topic, + "contributors": t.contributors, + "detail": t.detail, + "contributor_ids": t.contributor_ids, + } + for t in topics + ] + + # 8b. 转换金句: GoldenQuote -> dict + new_quotes = [ + { + "content": q.content, + "sender": q.sender, + "reason": q.reason, + "user_id": q.user_id, + } + for q in golden_quotes + ] + + # 8c. 转换 token 消耗: TokenUsage -> dict + token_usage_dict = { + "prompt_tokens": token_usage.prompt_tokens, + "completion_tokens": token_usage.completion_tokens, + "total_tokens": token_usage.total_tokens, + } + + # 8d. 转换用户统计: AnalysisDomainService 格式 -> IncrementalBatch 格式 + user_stats = self._convert_user_activity_for_merge( + user_activity, unified_messages + ) + + # 8e. 转换表情统计: EmojiStatistics -> dict + emoji_stats = { + "face_count": statistics.emoji_statistics.face_count, + "mface_count": statistics.emoji_statistics.mface_count, + "bface_count": statistics.emoji_statistics.bface_count, + "sface_count": statistics.emoji_statistics.sface_count, + "other_emoji_count": statistics.emoji_statistics.other_emoji_count, + "face_details": statistics.emoji_statistics.face_details, + } + + # 8f. 转换聊天质量锐评: QualityReview -> dict + chat_quality_dict = None + if chat_quality_review: + chat_quality_dict = { + "title": chat_quality_review.title, + "subtitle": chat_quality_review.subtitle, + "dimensions": [ + { + "name": d.name, + "percentage": d.percentage, + "comment": d.comment, + "color": d.color, + } + for d in chat_quality_review.dimensions + ], + "summary": chat_quality_review.summary, + } + + # 8g. 获取参与者 ID 和最后消息时间戳 + participant_ids = list({msg.sender_id for msg in unified_messages}) + last_message_timestamp = max( + (msg.timestamp for msg in unified_messages), default=0 + ) + + # 8g. 计算本批次总字符数 + characters_count = sum(msg.get_text_length() for msg in unified_messages) + + # 构建批次对象 + batch_identity = "\n".join( + f"{msg.timestamp}:{msg.message_id}" for msg in unified_messages + ) + batch = IncrementalBatch( + group_id=group_id, + batch_id=hashlib.sha256( + f"{platform_id or 'default'}:{group_id}:{batch_identity}".encode() + ).hexdigest(), + timestamp=time_mod.time(), + messages_count=len(unified_messages), + characters_count=characters_count, + hourly_msg_counts={str(k): v for k, v in hourly_msg_counts.items()}, + hourly_char_counts={str(k): v for k, v in hourly_char_counts.items()}, + user_stats=user_stats, + emoji_stats=emoji_stats, + topics=new_topics, + golden_quotes=new_quotes, + token_usage=token_usage_dict, + chat_quality_review=chat_quality_dict, + last_message_timestamp=last_message_timestamp, + participant_ids=participant_ids, + ) + + # 9. 保存批次并更新最后分析时间戳 + if not await self.incremental_store.save_batch(batch): + return { + "success": False, + "reason": "batch_persistence_failed", + "messages_count": 0, + } + + # 安全更新水位线:取消息最大时间戳,但不能超过当前时间+1分钟,防止未来时间戳毒化导致后续分析死锁 + import time + + safe_now = int(time.time()) + 60 + safe_ts = min(last_message_timestamp, safe_now) + + analyzed_ids_at_boundary = { + msg.message_id + for msg in unified_messages + if msg.timestamp == last_message_timestamp and msg.message_id + } + if last_message_timestamp == last_analyzed_ts: + analyzed_ids_at_boundary.update(last_analyzed_message_ids) + if safe_ts != last_message_timestamp: + analyzed_ids_at_boundary.clear() + + await self.incremental_store.update_last_analyzed_cursor( + group_id, + safe_ts, + analyzed_ids_at_boundary, + ) + + logger.debug( + f"群 {group_id} 增量批次完成: " + f"platform={getattr(adapter, 'platform_id', platform_id) or 'default'}, " + f"batch={batch.batch_id[:8]}, 消息={len(unified_messages)}, " + f"raw={raw_count}, cleaned={cleaned_count}, eligible={eligible_count}, " + f"cursor={last_analyzed_ts}->{safe_ts}, " + f"新话题={len(new_topics)}, 新金句={len(new_quotes)}, " + f"tokens={token_usage.total_tokens}, " + f"duration={time_mod.monotonic() - analysis_started_at:.2f}s" + ) + + return { + "success": True, + "batch_summary": batch.get_summary(), + "messages_count": len(unified_messages), + "group_id": group_id, + "platform_id": getattr(adapter, "platform_id", platform_id), + } + + async def execute_incremental_final_report( + self, group_id: str, platform_id: str | None = None + ) -> dict[str, Any]: + """ + 基于滑动窗口内的增量批次生成最终报告。 + + 按 analysis_days × 24h 的时间窗口查询所有批次, + 合并为 IncrementalState,额外执行用户称号分析, + 然后生成与传统每日分析格式完全一致的 analysis_result。 + + 流程: + 1. 计算滑动窗口范围 + 2. 查询窗口内的所有批次 + 3. 检查批次有效性 + 4. 合并批次为 IncrementalState + 5. 执行用户称号 LLM 分析(基于合并后的累积数据) + 6. 使用 IncrementalMergeService 构建 analysis_result + 7. 持久化到 history_manager + 8. 返回结果 + + Args: + group_id: 群组 ID + platform_id: 平台标识,缺省为默认 + + Returns: + dict: 包含 success、analysis_result、adapter 等信息 + """ + async with self.group_lock(group_id, "final"): + if not self.incremental_store or not self.incremental_merge_service: + raise RuntimeError( + "增量分析未初始化:缺少 IncrementalStore 或 IncrementalMergeService" + ) + + logger.info( + f"开始增量最终报告: 群 {group_id}, 平台 {platform_id or '默认'}" + ) + + # 1. 计算滑动窗口范围 + analysis_days = self.config_manager.get_analysis_days() + window_end = time_mod.time() + window_start = window_end - (analysis_days * 24 * 3600) + + # 2. 查询窗口内的所有批次 + batches = await self.incremental_store.query_batches( + group_id, window_start, window_end + ) + + # 3. 检查批次有效性 + if not batches: + logger.warning( + f"群 {group_id} 滑动窗口内无增量分析数据,无法生成最终报告" + ) + return {"success": False, "reason": "no_incremental_data"} + + # 4. 合并批次为 IncrementalState + state = self.incremental_merge_service.merge_batches( + batches, window_start, window_end + ) + + # 5. 获取适配器(报告发送需要) + adapter = self.bot_manager.get_adapter(platform_id) + if not adapter: + raise ValueError(f"未找到平台 {platform_id} 的适配器") + + # 检查群聊是否被禁言(包括全体禁言或对 Bot 自身禁言) + if hasattr(adapter, "is_group_muted"): + try: + if await adapter.is_group_muted(group_id): + logger.info( + f"群 {group_id} 开启了全群禁言或对 Bot 禁言,跳过本次增量最终报告生成" + ) + return {"success": False, "reason": "muted"} + except Exception as e: + logger.warning(f"检查群 {group_id} 禁言状态时出错: {e}") + + # 6. 执行分析相关的变量准备 + user_titles = [] + user_title_enabled = self.config_manager.get_user_title_analysis_enabled() + unified_msg_origin = ( + f"{platform_id}:GroupMessage:{group_id}" if platform_id else group_id + ) + + if user_title_enabled and state.user_activities: + max_user_titles = self.config_manager.get_max_user_titles() + # 从合并后的 user_activities 中取出 top 用户 + top_users = state.get_user_activity_ranking(max_user_titles) + + try: + async with self._llm_slot(group_id, "incremental_final_title"): + logger.debug(f"[LLM] 已进入称号分析队列 (群: {group_id})") + ( + user_titles_result, + title_token_usage, + ) = await self.llm_analyzer.analyze_user_titles( + messages=[], # 增量模式下不传原始消息 + user_activity=state.user_activities, + umo=unified_msg_origin, + top_users=top_users, + ) + user_titles = user_titles_result + + # 将称号分析的 token 消耗追加到状态中 + state.total_token_usage["prompt_tokens"] = ( + state.total_token_usage.get("prompt_tokens", 0) + + title_token_usage.prompt_tokens + ) + state.total_token_usage["completion_tokens"] = ( + state.total_token_usage.get("completion_tokens", 0) + + title_token_usage.completion_tokens + ) + state.total_token_usage["total_tokens"] = ( + state.total_token_usage.get("total_tokens", 0) + + title_token_usage.total_tokens + ) + except Exception as e: + logger.error(f"增量最终报告用户称号分析失败: {e}", exc_info=True) + + # 6.5 执行聊天质量汇总分析 (如果有多个批次的质量报告) + if ( + self.config_manager.get_chat_quality_analysis_enabled() + and state.all_quality_reviews + ): + try: + async with self._llm_slot(group_id, "incremental_final_quality"): + logger.debug( + f"[LLM] 已进入聊天质量汇总分析队列 (群: {group_id})" + ) + ( + summarized_review, + quality_token_usage, + ) = await self.llm_analyzer.summarize_quality_reviews( + batch_reviews=state.all_quality_reviews, + umo=unified_msg_origin, + ) + if summarized_review: + # 更新 state 中的 review 为汇总后的结果 + # 这里我们需要将 QualityReview 对象存回 dict 或直接在后续处理中使用 + # build_analysis_result 会使用 state.chat_quality_review + state.chat_quality_review = { + "title": summarized_review.title, + "subtitle": summarized_review.subtitle, + "dimensions": [ + { + "name": d.name, + "percentage": d.percentage, + "comment": d.comment, + "color": d.color, + } + for d in summarized_review.dimensions + ], + "summary": summarized_review.summary, + } + + # 累加 Token + state.total_token_usage["prompt_tokens"] = ( + state.total_token_usage.get("prompt_tokens", 0) + + quality_token_usage.prompt_tokens + ) + state.total_token_usage["completion_tokens"] = ( + state.total_token_usage.get("completion_tokens", 0) + + quality_token_usage.completion_tokens + ) + state.total_token_usage["total_tokens"] = ( + state.total_token_usage.get("total_tokens", 0) + + quality_token_usage.total_tokens + ) + except Exception as e: + logger.error(f"增量最终报告聊天质量汇总失败: {e}", exc_info=True) + + # 7. 构建 analysis_result + analysis_result = self.incremental_merge_service.build_analysis_result( + state, user_titles + ) + + # 8. 持久化到 history_manager + await self.history_manager.save_analysis(group_id, analysis_result) + + logger.info( + f"群 {group_id} 增量最终报告内容生成并保存完成,等待发送: " + f"窗口={state.get_window_date_str()}, " + f"累计消息={state.total_message_count}, " + f"话题={len(state.topics)}, 金句={len(state.golden_quotes)}, " + f"批次={state.total_analysis_count}" + ) + + return { + "success": True, + "analysis_result": analysis_result, + "messages_count": state.total_message_count, + "adapter": adapter, + "group_id": group_id, + "platform_id": getattr(adapter, "platform_id", platform_id), + } + + # ---------------------------------------------------------------- + # 辅助方法 + # ---------------------------------------------------------------- + + @staticmethod + def _compute_hourly_counts( + messages: list[UnifiedMessage], + ) -> tuple[dict[int, int], dict[int, int]]: + """ + 从消息列表计算按小时的消息数和字符数分布。 + + Args: + messages: 统一格式的消息列表 + + Returns: + tuple: (每小时消息计数, 每小时字符计数) + """ + hourly_msg: dict[int, int] = defaultdict(int) + hourly_char: dict[int, int] = defaultdict(int) + + for msg in messages: + hour = dt.datetime.fromtimestamp(msg.timestamp).hour + hourly_msg[hour] += 1 + hourly_char[hour] += msg.get_text_length() + + return dict(hourly_msg), dict(hourly_char) + + @staticmethod + def _convert_user_activity_for_merge( + user_activity: Mapping[str, UserActivityStats], + messages: list[UnifiedMessage], + ) -> dict[str, dict]: + """ + 将 AnalysisDomainService.analyze_user_activity() 的返回格式 + 转换为 IncrementalBatch 所需的 user_stats 格式。 + + 转换映射: + - nickname -> name + - hours (defaultdict) -> active_hours (list) + - 新增 last_message_time(从消息时间戳中提取) + + Args: + user_activity: AnalysisDomainService 返回的用户活跃数据 + messages: 本批次的消息列表(用于提取每个用户的最后发言时间) + + Returns: + dict: IncrementalBatch 所需的 user_stats 格式 + """ + # 预先计算每个用户的最后消息时间戳 + user_last_time: dict[str, int] = {} + for msg in messages: + current = user_last_time.get(msg.sender_id, 0) + if msg.timestamp > current: + user_last_time[msg.sender_id] = msg.timestamp + + result: dict[str, dict] = {} + for user_id, stats in user_activity.items(): + result[user_id] = { + "nickname": stats.get("nickname", user_id), + "message_count": stats.get("message_count", 0), + "char_count": stats.get("char_count", 0), + "emoji_count": stats.get("emoji_count", 0), + "reply_count": stats.get("reply_count", 0), + "hours": dict( + stats.get("hours", {}) + ), # 这里的 hours 是 defaultdict(int),转为 dict + "last_message_time": user_last_time.get(user_id, 0), + } + + return result diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/services/comic_application_service.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/services/comic_application_service.py new file mode 100644 index 0000000..bf32a6d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/services/comic_application_service.py @@ -0,0 +1,617 @@ +import mimetypes +from contextlib import nullcontext +from pathlib import Path +from typing import Any + +from astrbot.api.star import Context + +from ...infrastructure.analysis.llm_analyzer import LLMAnalyzer +from ...infrastructure.config.config_manager import ConfigManager +from ...infrastructure.drawing.drawing_client import ( + DrawingClient, + ImageDownloadFailedError, +) +from ...shared.trace_context import TraceContext +from ...utils.logger import logger + + +class ComicApplicationService: + """ + 负责统筹每日群漫画的生成流程: + 1. 调用 LLMAnalyzer 将群聊话题生成拼贴分镜提示词。 + 2. 调用 DrawingClient 直接生成单张连环漫画长图。 + 3. 返回图片数据供外部上传。 + """ + + def __init__( + self, + llm_analyzer: LLMAnalyzer, + drawing_client: DrawingClient, + config_manager: ConfigManager, + plugin_data_dir: Path, + context: Context | None = None, + ): + self.llm_analyzer = llm_analyzer + self.drawing_client = drawing_client + self.config_manager = config_manager + self.plugin_data_dir = plugin_data_dir + self.context = context + + async def generate_comic( + self, + topics: list[dict], + group_id: str, + umo: str | None = None, + ) -> tuple[bytes | None, str | None]: + """ + 生成漫画并返回图片字节数据。 + + Returns: + (comic_bytes, fallback_url): + - comic_bytes: 生成成功时为图片字节,失败时为 None。 + - fallback_url: 图片 API 返回了 URL 但下载失败时为该 URL,其他情况为 None。 + """ + if not self.config_manager.get_enable_daily_comic(): + return None, None + + character = self.config_manager.get_selected_comic_character() + character_name = ( + str(character.get("name", "")).strip() if character else "" + ) or "默认配置" + persona_id = self.config_manager.get_comic_character_persona_id(character) + prompt_template = self.config_manager.get_comic_character_storyboard_prompt( + character + ) + logger.info( + f"[Comic] 开始为群 {group_id} 生成每日漫画,角色方案: {character_name}" + ) + + trace = TraceContext.current() + + # 1. 提取分镜和金句 + sb_ctx = trace.span("COMIC_STORYBOARD") if trace else nullcontext() + with sb_ctx as sb_rec: + ( + storyboards, + storyboard_usage, + ) = await self.llm_analyzer.analyze_comic_storyboards( + topics, + umo, + persona_id=persona_id or None, + prompt_template=prompt_template or None, + ) + if sb_rec and isinstance(sb_rec, dict): + sb_prompts: dict[str, Any] = {} + if trace and trace.metadata.get("llm_prompts"): + for k, p in trace.metadata["llm_prompts"].items(): + if "comic" in k or k == "comic_storyboards": + sb_prompts[k] = p + if not sb_prompts and storyboards: + sb_prompts["comic_storyboards"] = { + "prompt": prompt_template + or "自动从群聊话题中提取漫画多格分镜与生图提示词", + "system_prompt": f"漫画分镜师 | 人格: {persona_id or character_name}", + "completion": storyboards[0].get("scene", "") + if storyboards + else "", + "prompt_tokens": getattr(storyboard_usage, "prompt_tokens", 0), + "completion_tokens": getattr( + storyboard_usage, "completion_tokens", 0 + ), + "tokens": getattr(storyboard_usage, "total_tokens", 0), + } + sb_rec.setdefault("payload", {}).update( + { + "character_name": character_name, + "topics_count": len(topics), + "storyboards_count": len(storyboards) if storyboards else 0, + "prompt_tokens": getattr(storyboard_usage, "prompt_tokens", 0), + "completion_tokens": getattr( + storyboard_usage, "completion_tokens", 0 + ), + "total_tokens": getattr(storyboard_usage, "total_tokens", 0), + "prompts": sb_prompts, + } + ) + if not storyboards: + sb_rec["payload"]["warning"] = "未能从群聊话题中提取出漫画分镜" + + if not storyboards: + logger.warning( + f"[Comic] 群 {group_id} 未能提取到任何金句分镜,取消漫画生成。" + ) + return None, None + + logger.info("[Comic] 成功提取到全景分镜提示词,开始调用绘画 API...") + + # 2. 直接生成一张图片 + scene_prompt = storyboards[0].get("scene", "") + if not scene_prompt: + logger.error("[Comic] 提取到的场景提示词为空,取消漫画生成。") + return None, None + + logger.debug(f"[Comic] 漫画 Prompt 已生成,长度: {len(scene_prompt)}") + + # 3. 加载当前角色方案配置的全部参考图。 + images_data = [] + reference_image_paths = self.config_manager.get_drawing_reference_images() + for reference_image_path in reference_image_paths: + reference_image = await self._fetch_reference_image(reference_image_path) + if reference_image: + images_data.append(reference_image) + logger.info(f"[Comic] 已加载参考图: {Path(reference_image_path).name}") + else: + logger.warning( + f"[Comic] 无法加载参考图: {Path(reference_image_path).name}" + ) + + draw_ctx = trace.span("COMIC_DRAWING") if trace else nullcontext() + with draw_ctx as draw_rec: + # 4. 若配置为外部绘图后端,优先走对应插件出图 + backend = self.config_manager.get_drawing_backend() + if backend in {"general_plugin", "big_banana"}: + if backend == "general_plugin": + external_comic_bytes = await self._generate_via_general_plugin( + scene_prompt, images_data + ) + else: + external_comic_bytes = await self._generate_via_big_banana( + scene_prompt, images_data + ) + if external_comic_bytes and not any( + external_comic_bytes == reference[0] for reference in images_data + ): + logger.info( + f"[Comic] 漫画生成成功({backend} 后端),大小: {len(external_comic_bytes)} bytes" + ) + if draw_rec and isinstance(draw_rec, dict): + draw_rec.setdefault("payload", {}).update( + { + "backend": backend, + "scene_prompt_len": len(scene_prompt), + "reference_images_count": len(images_data), + "image_bytes": len(external_comic_bytes), + "success": True, + "prompts": { + "comic_drawing": { + "prompt": scene_prompt, + "system_prompt": f"绘图后端: {backend} | 角色方案: {character_name} | 参考图数: {len(images_data)}", + "completion": f"出图完成(体积: {round(len(external_comic_bytes) / 1024, 1)} KB)", + "provider_type": backend, + } + }, + } + ) + return external_comic_bytes, None + if external_comic_bytes: + logger.warning( + f"[Comic] {backend} 后端原样返回了参考图,拒绝发送并回退内置绘图后端。" + ) + if not self.config_manager.get_drawing_external_fallback(): + logger.warning( + f"[Comic] {backend} 后端未产出结果,且已禁用回退内置后端,取消漫画生成。" + ) + if draw_rec and isinstance(draw_rec, dict): + draw_rec.setdefault("payload", {}).update( + { + "backend": backend, + "error": f"{backend} 后端未产出结果且禁用回退", + "success": False, + } + ) + return None, None + logger.warning(f"[Comic] {backend} 后端未产出结果,回退内置绘图后端。") + + # 5. 内置绘图后端未配置时直接取消,避免空跑 + if not self.config_manager.get_drawing_provider_configs(): + logger.warning( + "[Comic] 未配置绘图供应商(drawing_provider_overrides),取消漫画生成。" + ) + if draw_rec and isinstance(draw_rec, dict): + draw_rec.setdefault("payload", {}).update( + { + "backend": "builtin", + "error": "未配置绘图供应商", + "success": False, + } + ) + return None, None + + # 6. 调用绘图 API,捕获"有 URL 但下载失败"的情况 + fallback_url: str | None = None + try: + ( + final_comic_bytes, + last_error, + ) = await self.drawing_client.generate_image( + scene_prompt, images_data=images_data or None + ) + except ImageDownloadFailedError as exc: + logger.warning( + f"[Comic] 图片下载失败,保留 fallback URL: {exc.fallback_url}" + ) + if draw_rec and isinstance(draw_rec, dict): + draw_rec.setdefault("payload", {}).update( + { + "backend": "builtin", + "fallback_url": exc.fallback_url, + "error": "图片下载失败,使用 fallback URL 发送", + } + ) + return None, exc.fallback_url + + if final_comic_bytes and any( + final_comic_bytes == reference[0] for reference in images_data + ): + logger.warning("[Comic] 内建绘图原样返回了参考图,拒绝发送。") + final_comic_bytes = None + last_error = "绘图服务原样返回了参考图" + + exception_keywords = ( + self.config_manager.get_drawing_output_exception_retry_keywords() + ) + should_rewrite_prompt = bool( + last_error + and any( + keyword in last_error for keyword in exception_keywords if keyword + ) + ) + if not final_comic_bytes and last_error and should_rewrite_prompt: + logger.info( + f"[Comic] 画图重试已用尽,请求 LLM 分析报错并重写 Prompt: {last_error}" + ) + new_prompt = await self.llm_analyzer.analyze_retry_prompt( + scene_prompt, last_error, umo + ) + if new_prompt: + logger.info("[Comic] 获取到重写后的 Prompt,进行最后一次尝试...") + try: + final_comic_bytes, _ = await self.drawing_client.generate_image( + new_prompt, + images_data=images_data or None, + disable_retry=True, + ) + except ImageDownloadFailedError as exc: + logger.warning( + f"[Comic] 重写 Prompt 后图片下载仍失败,保留 fallback URL: {exc.fallback_url}" + ) + if draw_rec and isinstance(draw_rec, dict): + draw_rec.setdefault("payload", {}).update( + { + "backend": "builtin", + "fallback_url": exc.fallback_url, + "error": "重写 Prompt 后下载仍失败", + } + ) + return None, exc.fallback_url + if final_comic_bytes and any( + final_comic_bytes == reference[0] for reference in images_data + ): + logger.warning( + "[Comic] 重写 Prompt 后仍原样返回参考图,拒绝发送。" + ) + final_comic_bytes = None + + if draw_rec and isinstance(draw_rec, dict): + draw_prompts = { + "comic_drawing": { + "prompt": scene_prompt, + "system_prompt": f"绘图引擎: {backend} | 角色方案: {character_name} | 参考图数: {len(images_data)}", + "completion": f"出图完成(体积: {round(len(final_comic_bytes) / 1024, 1)} KB)" + if final_comic_bytes + else ( + f"出图未产出: {last_error}" if last_error else "未产出图像" + ), + "provider_type": backend, + } + } + draw_rec.setdefault("payload", {}).update( + { + "backend": backend, + "scene_prompt_len": len(scene_prompt), + "reference_images_count": len(images_data), + "image_bytes": len(final_comic_bytes) + if final_comic_bytes + else 0, + "success": bool(final_comic_bytes), + "last_error": last_error, + "prompts": draw_prompts, + } + ) + + if final_comic_bytes: + logger.info( + f"[Comic] 漫画生成成功,大小: {len(final_comic_bytes)} bytes" + ) + else: + logger.error("[Comic] 漫画生成最终失败。") + + return final_comic_bytes, fallback_url + + async def _generate_via_general_plugin( + self, + scene_prompt: str, + images_data: list[tuple[bytes, str]] | None, + ) -> bytes | None: + """通过「通用生图」插件的公共 API 生成漫画。 + + 未安装、未激活、未配置 API 或调用失败时返回 None,由调用方回退内置 DrawingClient。 + + Returns: + 生成图片的二进制数据;失败时返回 None。 + """ + if self.context is None: + logger.debug("[Comic] 未注入插件 Context,跳过通用生图后端。") + return None + try: + meta = self.context.get_registered_star("astrbot_plugin_image_generation") + except Exception as exc: + logger.debug(f"[Comic] 获取通用生图插件注册信息失败: {exc}") + return None + image_plugin = meta.star_cls if meta and meta.activated else None + if image_plugin is None: + logger.warning( + "[Comic] 未检测到已激活的「通用生图」插件,回退内置绘图后端。" + ) + return None + + public_api = getattr(image_plugin, "public_api", None) + if public_api is None: + logger.warning("[Comic] 通用生图插件未暴露 public_api,回退内置绘图后端。") + return None + + try: + logger.info("[Comic] 通过「通用生图」插件公共 API 生成漫画...") + result = await public_api.generate_image_files( + prompt=scene_prompt, + source="群分析插件", + aspect_ratio="16:9", + reference_image_data=images_data, + timeout_seconds=600, + ) + except Exception as exc: + logger.error(f"[Comic] 通用生图后端调用异常: {exc}") + return None + + if not getattr(result, "ok", False): + code = str(getattr(result, "code", "")) + message = getattr(result, "message", "") or getattr(result, "error", "") + hint = "" + if code == "prompt_blocked": + hint = "(提示词被通用生图插件安全审核拦截,可调整其审核配置或精简 scene 提示词)" + elif code == "api_key_missing": + hint = "(通用生图插件未配置 API Key,需先在通用生图插件中配置)" + elif code == "timeout": + hint = "(等待通用生图任务结果超时)" + elif code == "rate_limited": + hint = "(命中通用生图插件额度/频率限制)" + logger.warning(f"[Comic] 通用生图后端失败 [{code}]: {message}{hint}") + return None + + paths = list(getattr(result, "paths", None) or []) + if not paths: + logger.warning( + "[Comic] 通用生图后端未返回图片路径(可能参考图被忽略或结果为空,请检查通用生图插件配置与参考图大小限制)。" + ) + return None + try: + return Path(paths[0]).read_bytes() + except OSError as exc: + logger.warning(f"[Comic] 读取通用生图后端结果失败: {exc}") + return None + + async def _generate_via_big_banana( + self, + scene_prompt: str, + images_data: list[tuple[bytes, str]] | None, + ) -> bytes | None: + """通过「大香蕉」插件的绘图管线生成漫画。 + + 大香蕉支持 Gemini、SiliconFlow、OpenAI 等多家提供商。 + + Returns: + 生成图片的二进制数据;失败时返回 None。 + """ + if self.context is None: + logger.debug("[Comic] 未注入插件 Context,跳过「大香蕉」后端。") + return None + try: + meta = self.context.get_registered_star("astrbot_plugin_big_banana") + except Exception as exc: + logger.debug(f"[Comic] 获取「大香蕉」插件注册信息失败: {exc}") + return None + plugin = meta.star_cls if meta and meta.activated else None + if plugin is None: + logger.warning("[Comic] 未检测到已激活的「大香蕉」插件,回退内置绘图后端。") + return None + + drawing_pipeline = getattr(plugin, "drawing_pipeline", None) + if drawing_pipeline is None: + logger.warning("[Comic] 「大香蕉」插件未初始化绘图管线,回退内置绘图后端。") + return None + + ImageResource = self._import_big_banana_image_resource(plugin) + if ImageResource is None: + logger.warning("[Comic] 无法导入「大香蕉」图片资源类型,回退内置绘图后端。") + return None + + image_list = None + if images_data: + image_list = [] + for img_bytes, _mime in images_data: + resource = ImageResource.from_bytes(img_bytes) + if resource: + image_list.append(resource) + if not image_list: + logger.warning( + "[Comic] 参考图无法解析为「大香蕉」图片资源,将不带参考图生成。" + ) + + params: dict[str, Any] = { + "prompt": scene_prompt, + "capability": "image_generation", + "sub_brain": False, + "url": False, + "aspect_ratio": "16:9", + "image_size": "1K", + } + + try: + logger.info("[Comic] 通过「大香蕉」插件绘图管线生成漫画...") + result = await drawing_pipeline.run(params, image_list) + except Exception as exc: + logger.error(f"[Comic] 「大香蕉」绘图管线调用异常: {exc}") + return None + + if getattr(result, "error_message", None): + logger.warning(f"[Comic] 「大香蕉」生成失败: {result.error_message}") + return None + + images = getattr(result, "images", None) or [] + if not images: + logger.warning("[Comic] 「大香蕉」未返回图片。") + return None + try: + image_bytes = images[0].bytes + except Exception as exc: + logger.warning(f"[Comic] 读取「大香蕉」生成结果失败: {exc}") + return None + if not image_bytes: + logger.warning("[Comic] 「大香蕉」返回的图片为空。") + return None + return image_bytes + + @staticmethod + def _import_big_banana_image_resource(plugin: Any): + """导入「大香蕉」插件的 ImageResource 类型。 + + AstrBot 以 ``data.plugins.<插件名>.main`` 形式加载插件,模块名并非 + ``astrbot_plugin_big_banana``,因此先从插件类的模块路径推导包名导入; + 推导失败时回退直接导入,兼容 pip 安装或测试环境注入的场景。 + + Args: + plugin: 已激活的大香蕉插件实例。 + + Returns: + ImageResource 类型;无法导入时返回 None。 + """ + import importlib + + module_name = getattr(type(plugin), "__module__", "") or "" + candidate_modules = [] + if module_name and "." in module_name: + candidate_modules.append(module_name.rsplit(".", 1)[0] + ".core.schemas") + candidate_modules.append("astrbot_plugin_big_banana.core.schemas") + + for module_path in candidate_modules: + try: + schemas_module = importlib.import_module(module_path) + except Exception: + continue + image_resource = getattr(schemas_module, "ImageResource", None) + if image_resource is not None: + return image_resource + return None + + async def _fetch_reference_image(self, image_ref: str) -> tuple[bytes, str] | None: + """从插件目录、AstrBot files、本地路径、HTTP URL 或 Base64 Data URL 获取已选参考图。 + + Args: + image_ref: 包含文件路径、URL 或 Base64 Data URL 的字符串。 + + Returns: + 图片字节和 MIME 类型;加载失败时返回 None。 + """ + import base64 + + if not image_ref or not isinstance(image_ref, str): + return None + + image_ref = image_ref.strip() + + # 1. 支持 Data URL 格式 (data:image/png;base64,xxxx) + if image_ref.startswith("data:image/"): + try: + header, b64_data = image_ref.split(",", 1) + mime_type = header.split(";")[0].replace("data:", "").strip() + return base64.b64decode(b64_data), mime_type or "image/png" + except Exception as e: + logger.error(f"[Comic] 解析 Data URL 参考图失败: {e}") + return None + + # 2. 支持 base64:// 格式 + if image_ref.startswith("base64://"): + try: + return base64.b64decode(image_ref[9:]), "image/png" + except Exception as e: + logger.error(f"[Comic] 解析 Base64 参考图失败: {e}") + return None + + # 3. 支持 HTTP / HTTPS 远程 URL + if image_ref.startswith(("http://", "https://")): + try: + import httpx + + async with httpx.AsyncClient(timeout=15.0) as client: + resp = await client.get(image_ref) + if resp.status_code == 200: + mime_type = resp.headers.get("content-type", "image/png").split( + ";" + )[0] + return resp.content, mime_type + except Exception as e: + logger.error(f"[Comic] 下载远程参考图失败 {image_ref}: {e}") + return None + + # 4. 支持本地文件路径(插件数据目录、插件代码目录、AstrBot 根目录、或绝对路径) + try: + clean_rel = image_ref.lstrip("/\\") + candidate_paths: list[Path] = [] + if hasattr(self, "plugin_data_dir") and self.plugin_data_dir: + p_data = Path(self.plugin_data_dir) + candidate_paths.extend( + [ + p_data / clean_rel, + p_data / "reference_images" / clean_rel, + ] + ) + + candidate_paths.append( + Path.cwd() + / "data" + / "plugin_data" + / "astrbot_plugin_qq_group_daily_analysis" + / clean_rel + ) + candidate_paths.append(Path(clean_rel)) + + for p in candidate_paths: + if p.is_file(): + guessed_type, _ = mimetypes.guess_type(p.name) + return p.read_bytes(), guessed_type or "image/png" + + # 模糊查找纯文件名 + filename = Path(clean_rel).name + search_roots: list[Path] = [] + if hasattr(self, "plugin_data_dir") and self.plugin_data_dir: + search_roots.append(Path(self.plugin_data_dir)) + search_roots.append( + Path.cwd() + / "data" + / "plugin_data" + / "astrbot_plugin_qq_group_daily_analysis" + ) + + for root in search_roots: + files_dir = root / "files" + if files_dir.exists(): + for match in files_dir.rglob(filename): + if match.is_file(): + guessed_type, _ = mimetypes.guess_type(match.name) + return match.read_bytes(), guessed_type or "image/png" + + logger.warning(f"[Comic] 找不到已选参考图: {image_ref}") + return None + except Exception as exc: + logger.error(f"[Comic] 获取已选参考图失败 {image_ref}: {exc}") + return None diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/services/message_processing_service.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/services/message_processing_service.py new file mode 100644 index 0000000..16ab275 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/application/services/message_processing_service.py @@ -0,0 +1,515 @@ +import re +from collections import Counter, OrderedDict + +from astrbot.api.event import AstrMessageEvent +from astrbot.api.star import Context + +from ...infrastructure.persistence.platform_group_registry import PlatformGroupRegistry +from ...utils.logger import logger + +_QQ_OFFICIAL_PLATFORM_NAMES = frozenset({"qq_official", "qq_official_webhook"}) +_QQ_OFFICIAL_MENTION_PATTERN = re.compile(r"<@!?([A-Za-z0-9_-]+)>") +_LOCAL_HISTORY_MAX_MESSAGES = 10000 + + +class MessageProcessingService: + """ + 消息处理服务 + + 解析收到的群消息事件,提取内容与发送者信息,持久化历史记录, + 并维护事件驱动平台(Telegram、QQ 官方等)的群组注册表。 + QQ 官方平台特有的重复消息去重逻辑也在本服务中处理。 + + 职责: + 1. 解析消息内容(文本、图片、@提及等) + 2. 解析发送者展示名(跨平台兼容) + 3. 存储消息历史 + 4. 维护群组注册表,供调度器做群组发现(Telegram、QQ 官方等事件驱动平台) + 5. QQ 官方事件消息去重(按 message_id 预占 + 确认机制) + """ + + def __init__(self, context: Context, group_registry: PlatformGroupRegistry): + self.context = context + self.group_registry = group_registry + self._seen_event_ids: OrderedDict[str, None] = OrderedDict() + self._inflight_event_ids: set[str] = set() + self._seen_event_ids_limit = 4096 + # AstrBot 4.26.x 的消息历史接口尚未提供 max_messages 参数。 + # 首次探测到旧签名后缓存结果,避免每条消息都触发一次失败调用。 + self._supports_history_max_messages: bool | None = None + + async def process_message(self, event: AstrMessageEvent) -> bool: + """ + 处理并在历史记录中存储消息。 + 被 main.py 的 Telegram 和 QQ 官方消息拦截器共同调用。 + + Args: + event: AstrBot 消息事件 + + Raises: + ValueError: 当必要数据无法获取时 + RuntimeError: 当消息内容为空时 + """ + # 1. 获取群组 ID(必需) + group_id = self._get_group_id_from_event(event) + if not group_id: + raise ValueError("无法获取群组 ID,拒绝存储消息") + + # 2. 获取发送者 ID(必需) + sender_id = event.get_sender_id() + if not sender_id: + raise ValueError(f"群 {group_id}: 无法获取发送者 ID,拒绝存储消息") + sender_id = str(sender_id) + + # 3. 获取发送者名称(昵称优先,必要时回退) + sender_name = self._resolve_sender_name(event, sender_id) + + # 4. 获取平台 ID(必需) + platform_id = event.get_platform_id() + if not platform_id: + raise ValueError(f"群 {group_id}: 无法获取平台 ID,拒绝存储消息") + + # 5. 提取消息内容 + message_parts = self._extract_message_parts(event) + if not message_parts: + # 尝试记录一条警告但不中断流程(或者视为错误) + # 原逻辑是抛出 RuntimeError + raise RuntimeError( + f"群 {group_id}: 消息内容为空 (sender={sender_name}),拒绝存储" + ) + + # 6. 提取事件消息 ID 和事件时间 + msg_obj = getattr(event, "message_obj", None) + event_message_id = str(getattr(msg_obj, "message_id", "") or "") + + platform_name = str(event.get_platform_name() or "").strip().lower() + reserved_event_id = False + if platform_name in {"qq_official", "qq_official_webhook"} and event_message_id: + reserved_event_id = self._reserve_event_id(event_message_id) + if not reserved_event_id: + logger.debug("[QQOfficial] 跳过重复消息事件: %s", event_message_id) + return False + history_content = { + "type": "user", + "message": message_parts, + } + if platform_name in {"qq_official", "qq_official_webhook"}: + event_timestamp = self._extract_event_timestamp(msg_obj) + history_content["_qq_official"] = { + "message_id": event_message_id, + "timestamp": event_timestamp, + } + + # 7. 存储到数据库 + try: + await self._insert_message_history( + platform_id=platform_id, + group_id=group_id, + content=history_content, + sender_id=sender_id, + sender_name=sender_name, + ) + except BaseException: + if reserved_event_id: + self._release_event_id(event_message_id) + raise + else: + if reserved_event_id: + self._commit_event_id(event_message_id) + + # Register the group so the scheduler can discover platforms that + # do not provide a group-list API (Telegram, QQ Official, etc.). + try: + await self.group_registry.upsert( + platform_id=platform_id, + group_id=group_id, + sender_id=sender_id, + sender_name=sender_name, + event_message_id=event_message_id, + ) + except Exception as e: + logger.warning( + "[GroupRegistry] Upsert failed: " + f"platform_id={platform_id} group_id={group_id} error={e}" + ) + + logger.debug( + f"[{platform_id}] 已缓存群 {group_id} 的消息 (发送者: {sender_name})" + ) + return True + + async def _insert_message_history( + self, + platform_id: str, + group_id: str, + content: dict, + sender_id: str, + sender_name: str, + ) -> None: + """兼容不同 AstrBot 版本的消息历史写入接口。 + + Args: + platform_id: AstrBot 平台实例 ID。 + group_id: 当前群组 ID。 + content: 待持久化的标准化消息内容。 + sender_id: 发送者 ID。 + sender_name: 发送者展示名称。 + + Raises: + Exception: 消息历史管理器写入失败时原样抛出。 + """ + insert = self.context.message_history_manager.insert + insert_kwargs = { + "platform_id": platform_id, + "user_id": group_id, + "content": content, + "sender_id": sender_id, + "sender_name": sender_name, + } + if self._supports_history_max_messages is False: + await insert(**insert_kwargs) + return + + try: + await insert(**insert_kwargs, max_messages=_LOCAL_HISTORY_MAX_MESSAGES) + except TypeError as exc: + if "unexpected keyword argument 'max_messages'" not in str(exc): + raise + + self._supports_history_max_messages = False + logger.warning( + "[消息历史] 当前 AstrBot 核心不支持 max_messages 参数," + "将使用兼容模式写入消息历史;建议升级核心以启用本地历史上限。" + ) + await insert(**insert_kwargs) + else: + self._supports_history_max_messages = True + + def _get_group_id_from_event(self, event: AstrMessageEvent) -> str | None: + """从消息事件中安全获取群组 ID""" + try: + group_id = event.get_group_id() + return group_id if group_id else None + except Exception: + return None + + def _resolve_sender_name(self, event: AstrMessageEvent, sender_id: str) -> str: + """解析发送者展示名""" + platform_name = str(event.get_platform_name() or "").lower() + candidates: list[str | None] = [] + + msg_obj = getattr(event, "message_obj", None) + sender_obj = getattr(msg_obj, "sender", None) + raw_message = getattr(msg_obj, "raw_message", None) + raw_msg_obj = getattr(raw_message, "message", raw_message) + from_user = getattr(raw_msg_obj, "from_user", None) + + if platform_name == "telegram": + if from_user is not None: + candidates.extend( + [ + getattr(from_user, "full_name", None), + getattr(from_user, "first_name", None), + ] + ) + candidates.append(event.get_sender_name()) + if sender_obj is not None: + candidates.append(getattr(sender_obj, "nickname", None)) + if from_user is not None: + candidates.append(getattr(from_user, "username", None)) + else: + candidates.append(event.get_sender_name()) + if sender_obj is not None: + candidates.append(getattr(sender_obj, "nickname", None)) + + if from_user is not None: + candidates.extend( + [ + getattr(from_user, "full_name", None), + getattr(from_user, "first_name", None), + getattr(from_user, "username", None), + ] + ) + + for candidate in candidates: + name = str(candidate or "").strip() + if not self._is_placeholder_sender_name(name, sender_id): + return name + + return sender_id + + def _extract_message_parts(self, event: AstrMessageEvent) -> list[dict]: + """从事件中提取消息内容""" + message_parts = [] + message = event.message_obj + platform_name = str(event.get_platform_name() or "").strip().lower() + qq_mention_replacements = ( + self._extract_qq_official_mention_replacements(event) + if platform_name in _QQ_OFFICIAL_PLATFORM_NAMES + else None + ) + + # 收集 @ 标记 + pending_mentions: Counter[str] = Counter() + if message and hasattr(message, "message"): + for seg in message.message: + if not hasattr(seg, "type"): + continue + if seg.type not in ("At", "at"): + continue + + target = getattr(seg, "target", None) or getattr(seg, "qq", None) + if target is None and hasattr(seg, "data"): + target = seg.data.get("qq") or seg.data.get("target") + + target_str = str(target or "").strip() + if target_str: + pending_mentions[target_str] += 1 + + display_name = str(getattr(seg, "name", "") or "").strip() + if display_name and display_name != target_str: + pending_mentions[display_name] += 1 + + if message and hasattr(message, "message"): + for seg in message.message: + if not hasattr(seg, "type"): + continue + + seg_type = seg.type + if seg_type in ("Plain", "text"): + text = getattr(seg, "text", None) + if text is None and hasattr(seg, "data"): + text = seg.data.get("text") + if text: + text = self._strip_known_mentions(text, pending_mentions) + if qq_mention_replacements is not None: + text = self._sanitize_qq_official_mentions( + text, qq_mention_replacements + ) + message_parts.append({"type": "plain", "text": text}) + + elif seg_type in ("Image", "image"): + url = getattr(seg, "url", None) or ( + seg.data.get("url") if hasattr(seg, "data") else None + ) + if url: + message_parts.append({"type": "image", "url": url}) + + elif seg_type in ("At", "at"): + target = getattr(seg, "target", None) or getattr(seg, "qq", None) + if target is None and hasattr(seg, "data"): + target = seg.data.get("qq") or seg.data.get("target") + if target: + message_parts.append( + { + "type": "at", + "target_id": str(target), + "name": str(getattr(seg, "name", "") or ""), + } + ) + + elif seg_type in ("File", "file"): + url = getattr(seg, "url", None) or getattr(seg, "file_", None) + message_parts.append( + { + "type": "file", + "url": str(url or ""), + "name": str(getattr(seg, "name", "") or ""), + } + ) + + elif seg_type in ("Record", "record", "voice"): + url = getattr(seg, "url", None) or getattr(seg, "file", None) + message_parts.append({"type": "voice", "url": str(url or "")}) + + elif seg_type in ("Video", "video"): + url = getattr(seg, "url", None) or getattr(seg, "file", None) + message_parts.append({"type": "video", "url": str(url or "")}) + + if not message_parts and event.message_str: + fallback_text = str(event.message_str) + if qq_mention_replacements is not None: + fallback_text = self._sanitize_qq_official_mentions( + fallback_text, qq_mention_replacements + ) + message_parts.append({"type": "plain", "text": fallback_text}) + + # 清理空文本段 + message_parts = [ + part + for part in message_parts + if not ( + part.get("type") == "plain" and not str(part.get("text", "")).strip() + ) + ] + + return message_parts + + @classmethod + def _extract_qq_official_mention_replacements( + cls, event: AstrMessageEvent + ) -> dict[str, str]: + message_obj = getattr(event, "message_obj", None) + raw_message = getattr(message_obj, "raw_message", None) + raw_candidates = [raw_message] + nested_message = cls._read_field(raw_message, "message") + if nested_message is not None and nested_message is not raw_message: + raw_candidates.insert(0, nested_message) + + mentions = None + for candidate in raw_candidates: + mentions = cls._read_field(candidate, "mentions") + if mentions is not None: + break + + replacements: dict[str, str] = {} + if not isinstance(mentions, (list, tuple)): + return replacements + + for mention in mentions: + mention_id = str( + cls._read_field( + mention, + "id", + "member_openid", + "memberopenid", + "user_openid", + "useropenid", + ) + or "" + ).strip() + if not mention_id: + continue + + if cls._read_field(mention, "is_you") is True: + replacements[mention_id] = "" + continue + + display_name = str( + cls._read_field(mention, "username", "name", "nickname") or "" + ).strip() + display_name = display_name.lstrip("@").strip() + if cls._is_placeholder_sender_name(display_name, mention_id): + display_name = "群友" + replacements[mention_id] = f"@{display_name}" + + return replacements + + @staticmethod + def _sanitize_qq_official_mentions(text: str, replacements: dict[str, str]) -> str: + def replace_mention(match: re.Match[str]) -> str: + mention_id = match.group(1) + if mention_id.lower() in {"all", "everyone"}: + return "@全体成员" + return replacements.get(mention_id, "@群友") + + cleaned = _QQ_OFFICIAL_MENTION_PATTERN.sub(replace_mention, str(text)) + return re.sub(r"[^\S\r\n]{2,}", " ", cleaned).strip(" \t") + + @staticmethod + def _read_field(source: object, *names: str) -> object | None: + if isinstance(source, dict): + for name in names: + if name in source: + return source[name] + return None + + for name in names: + value = getattr(source, name, None) + if value is not None: + return value + return None + + @staticmethod + def _strip_known_mentions(text: str, pending_mentions: Counter[str]) -> str: + """从文本中移除已识别的 @ 提及""" + cleaned = str(text) + if not cleaned or not pending_mentions: + return cleaned.strip() + + for mention, remaining in list(pending_mentions.items()): + if not mention or remaining <= 0: + continue + + pattern = re.compile(rf"(? 0: + pending_mentions[mention] -= removed + if pending_mentions[mention] <= 0: + pending_mentions.pop(mention, None) + + return re.sub(r"[^\S\r\n]{2,}", " ", cleaned).strip() + + @staticmethod + def _is_placeholder_sender_name(name: str | None, sender_id: str) -> bool: + """判断 sender_name 是否为占位值""" + if not name: + return True + normalized = str(name).strip() + if not normalized: + return True + if normalized.lower() in {"unknown", "none", "null", "nil", "undefined"}: + return True + return normalized == str(sender_id).strip() + + @staticmethod + def _extract_event_timestamp(message_obj: object) -> int: + """从消息对象中提取平台事件时间戳。""" + raw_message = getattr(message_obj, "raw_message", None) + if isinstance(raw_message, dict): + candidate = raw_message.get("timestamp") + if not candidate: + raw_data = raw_message.get("raw_data") + if isinstance(raw_data, dict): + candidate = raw_data.get("timestamp") + else: + raw_data = getattr(raw_message, "raw_data", None) + candidate = getattr(raw_message, "timestamp", None) + if not candidate and isinstance(raw_data, dict): + candidate = raw_data.get("timestamp") + if isinstance(candidate, (int, float)): + return int(candidate) + if candidate: + try: + from datetime import datetime + + return int( + datetime.fromisoformat( + str(candidate).replace("Z", "+00:00") + ).timestamp() + ) + except (TypeError, ValueError, OverflowError): + pass + return 0 + + def _reserve_event_id(self, event_message_id: str) -> bool: + """预占事件消息 ID:在历史记录持久化期间防止重复入库。""" + if ( + event_message_id in self._inflight_event_ids + or event_message_id in self._seen_event_ids + ): + if event_message_id in self._seen_event_ids: + self._seen_event_ids.move_to_end(event_message_id) + return False + self._inflight_event_ids.add(event_message_id) + return True + + def _commit_event_id(self, event_message_id: str) -> None: + """确认事件消息 ID:标记为已持久化,纳入后续去重。""" + self._inflight_event_ids.discard(event_message_id) + if event_message_id in self._seen_event_ids: + self._seen_event_ids.move_to_end(event_message_id) + else: + self._seen_event_ids[event_message_id] = None + if len(self._seen_event_ids) > self._seen_event_ids_limit: + self._seen_event_ids.popitem(last=False) + + def _release_event_id(self, event_message_id: str) -> None: + """释放事件消息 ID:持久化失败或取消时清理预占状态。""" + self._inflight_event_ids.discard(event_message_id) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/__init__.py new file mode 100644 index 0000000..e7f7a29 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/__init__.py @@ -0,0 +1 @@ +# 领域层 - 与平台无关的业务逻辑 diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/entities/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/entities/__init__.py new file mode 100644 index 0000000..80631e6 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/entities/__init__.py @@ -0,0 +1,18 @@ +""" +领域实体 + +该模块导出所有领域实体类,包括: +- AnalysisTask: 分析任务聚合根 +- IncrementalBatch: 增量分析独立批次实体 +- IncrementalState: 增量分析聚合视图(报告时使用) +""" + +from .analysis_task import AnalysisTask, TaskStatus +from .incremental_state import IncrementalBatch, IncrementalState + +__all__ = [ + "AnalysisTask", + "TaskStatus", + "IncrementalBatch", + "IncrementalState", +] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/entities/analysis_task.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/entities/analysis_task.py new file mode 100644 index 0000000..ab35b7e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/entities/analysis_task.py @@ -0,0 +1,70 @@ +""" +分析任务实体 - 聚合根 +""" + +import time +import uuid +from dataclasses import dataclass, field +from enum import Enum + + +class TaskStatus(Enum): + PENDING = "pending" + CHECKING_PLATFORM = "checking_platform" + FETCHING_MESSAGES = "fetching_messages" + ANALYZING = "analyzing" + GENERATING_REPORT = "generating_report" + SENDING = "sending" + COMPLETED = "completed" + FAILED = "failed" + UNSUPPORTED_PLATFORM = "unsupported_platform" + + +@dataclass +class AnalysisTask: + """分析任务实体 - 聚合根""" + + id: str = field(default_factory=lambda: uuid.uuid4().hex[:8]) + group_id: str = "" + platform_name: str = "" + trace_id: str = "" + status: TaskStatus = TaskStatus.PENDING + is_manual: bool = False + created_at: float = field(default_factory=time.time) + started_at: float | None = None + completed_at: float | None = None + result_id: str | None = None + error_message: str | None = None + + def start(self, can_analyze: bool) -> bool: + """启动任务,验证平台能力""" + if not can_analyze: + self.status = TaskStatus.UNSUPPORTED_PLATFORM + self.error_message = f"平台 {self.platform_name} 不支持分析" + return False + self.status = TaskStatus.FETCHING_MESSAGES + self.started_at = time.time() + return True + + def advance_to(self, status: TaskStatus): + """推进到下一个状态""" + self.status = status + + def complete(self, result_id: str): + """标记任务为已完成""" + self.status = TaskStatus.COMPLETED + self.result_id = result_id + self.completed_at = time.time() + + def fail(self, error: str): + """标记任务为失败""" + self.status = TaskStatus.FAILED + self.error_message = error + self.completed_at = time.time() + + @property + def duration(self) -> float | None: + """获取任务持续时间(秒)""" + if self.started_at and self.completed_at: + return self.completed_at - self.started_at + return None diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/entities/incremental_state.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/entities/incremental_state.py new file mode 100644 index 0000000..2180dad --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/entities/incremental_state.py @@ -0,0 +1,394 @@ +""" +增量分析实体 — 滑动窗口批次存储架构 + +核心概念: +- IncrementalBatch: 单次增量分析产生的独立批次数据,按批次独立存储 +- IncrementalState: 报告生成时由多个批次合并而成的聚合视图(不再持久化) + +滑动窗口设计: +- 每次增量分析产生一个 IncrementalBatch,独立存储到 KV +- 最终报告时按 analysis_days × 24h 的时间窗口查询批次并合并 +- 支持同一天多次发送报告,每次都基于当前时间窗口内的所有批次 +""" + +from __future__ import annotations + +import time +import uuid +from dataclasses import dataclass, field +from datetime import datetime +from typing import Any + + +@dataclass +class IncrementalBatch: + """ + 单次增量分析批次数据 + + 每次增量分析执行完毕后产生一个 IncrementalBatch, + 包含该批次的所有统计数据和 LLM 分析结果,独立存储到 KV。 + + Attributes: + group_id: 群组 ID + batch_id: 批次唯一标识(UUID) + timestamp: 批次创建时间戳(epoch) + messages_count: 本批次分析的消息数量 + characters_count: 本批次的总字符数 + hourly_msg_counts: 按小时的消息计数 {hour_str: count} + hourly_char_counts: 按小时的字符计数 {hour_str: count} + user_stats: 用户统计 {user_id: {name, message_count, char_count, ...}} + emoji_stats: 表情统计 {emoji_type: count} + topics: 本批次提取的话题列表 + golden_quotes: 本批次提取的金句列表 + token_usage: 本批次 token 消耗 {prompt_tokens, completion_tokens, total_tokens} + chat_quality_review: 本批次提取的聊天质量锐评 + last_message_timestamp: 本批次最后一条消息的时间戳 + participant_ids: 本批次参与者 ID 列表 + """ + + group_id: str = "" + batch_id: str = field(default_factory=lambda: str(uuid.uuid4())) + timestamp: float = field(default_factory=time.time) + + # 统计数据 + messages_count: int = 0 + characters_count: int = 0 + hourly_msg_counts: dict[str, int] = field(default_factory=dict) + hourly_char_counts: dict[str, int] = field(default_factory=dict) + + # 用户活跃数据 + user_stats: dict[str, dict] = field(default_factory=dict) + + # 表情统计 + emoji_stats: dict[str, Any] = field(default_factory=dict) + + # LLM 分析结果 + topics: list[dict] = field(default_factory=list) + golden_quotes: list[dict] = field(default_factory=list) + + # Token 消耗 + token_usage: dict = field( + default_factory=lambda: { + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0, + } + ) + + # 增量追踪 + chat_quality_review: dict[str, Any] | None = None + last_message_timestamp: int = 0 + participant_ids: list[str] = field(default_factory=list) + + def to_dict(self) -> dict: + """序列化为字典,用于 KV 存储""" + return { + "group_id": self.group_id, + "batch_id": self.batch_id, + "timestamp": self.timestamp, + "messages_count": self.messages_count, + "characters_count": self.characters_count, + "hourly_msg_counts": self.hourly_msg_counts, + "hourly_char_counts": self.hourly_char_counts, + "user_stats": self.user_stats, + "emoji_stats": self.emoji_stats, + "topics": self.topics, + "golden_quotes": self.golden_quotes, + "token_usage": self.token_usage, + "chat_quality_review": self.chat_quality_review, + "last_message_timestamp": self.last_message_timestamp, + "participant_ids": self.participant_ids, + } + + @classmethod + def from_dict(cls, data: dict) -> IncrementalBatch: + """从字典反序列化""" + return cls( + group_id=data.get("group_id", ""), + batch_id=data.get("batch_id", ""), + timestamp=data.get("timestamp", 0.0), + messages_count=data.get("messages_count", 0), + characters_count=data.get("characters_count", 0), + hourly_msg_counts=data.get("hourly_msg_counts", {}), + hourly_char_counts=data.get("hourly_char_counts", {}), + user_stats=data.get("user_stats", {}), + emoji_stats=data.get("emoji_stats", {}), + topics=data.get("topics", []), + golden_quotes=data.get("golden_quotes", []), + token_usage=data.get( + "token_usage", + { + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0, + }, + ), + chat_quality_review=data.get("chat_quality_review"), + last_message_timestamp=data.get("last_message_timestamp", 0), + participant_ids=data.get("participant_ids", []), + ) + + def get_summary(self) -> dict: + """获取批次摘要信息""" + return { + "batch_id": self.batch_id[:8], + "timestamp": datetime.fromtimestamp(self.timestamp).strftime( + "%Y-%m-%d %H:%M:%S" + ), + "messages_count": self.messages_count, + "topics_count": len(self.topics), + "quotes_count": len(self.golden_quotes), + "participants": len(self.participant_ids), + } + + +@dataclass +class IncrementalState: + """ + 增量分析聚合视图(报告时使用) + + 由多个 IncrementalBatch 合并而成,不直接持久化。 + IncrementalMergeService.merge_batches() 负责从批次列表构建此对象。 + + Attributes: + group_id: 群组 ID + window_start: 滑动窗口起始时间戳 + window_end: 滑动窗口结束时间戳 + topics: 合并去重后的话题列表 + golden_quotes: 合并去重后的金句列表 + hourly_message_counts: 合并后的每小时消息计数 {hour_str: count} + hourly_character_counts: 合并后的每小时字符计数 {hour_str: count} + user_activities: 合并后的用户活跃数据 + emoji_counts: 合并后的表情统计 + total_message_count: 窗口内总消息数 + total_character_count: 窗口内总字符数 + total_analysis_count: 窗口内批次数量 + total_token_usage: 累计 token 消耗 + last_analyzed_message_timestamp: 最后分析消息时间戳 + all_participant_ids: 所有参与者 ID 集合 + """ + + # 标识信息 + group_id: str = "" + window_start: float = 0.0 + window_end: float = 0.0 + + # 合并后的 LLM 分析结果 + topics: list[dict] = field(default_factory=list) + golden_quotes: list[dict] = field(default_factory=list) + chat_quality_review: dict[str, Any] | None = None + all_quality_reviews: list[dict] = field( + default_factory=list + ) # 存储所有批次的质量锐评,用于最终报告时的汇总分析 + + # 合并后的统计数据(按小时) + hourly_message_counts: dict[str, int] = field(default_factory=dict) + hourly_character_counts: dict[str, int] = field(default_factory=dict) + + # 用户活跃数据 + user_activities: dict[str, dict] = field(default_factory=dict) + + # 表情统计 + emoji_counts: dict[str, Any] = field(default_factory=dict) + + # 汇总统计 + total_message_count: int = 0 + total_character_count: int = 0 + total_analysis_count: int = 0 + total_token_usage: dict = field( + default_factory=lambda: { + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0, + } + ) + + # 增量跟踪 + last_analyzed_message_timestamp: int = 0 + all_participant_ids: set[str] = field(default_factory=set) + + # 元数据 + created_at: float = field(default_factory=time.time) + updated_at: float = field(default_factory=time.time) + + def get_peak_hours(self, top_n: int = 3) -> list[int]: + """ + 获取消息最活跃的时段。 + + Args: + top_n: 返回前 N 个最活跃的小时 + + Returns: + list[int]: 活跃小时列表,按消息量降序 + """ + if not self.hourly_message_counts: + return [] + sorted_hours = sorted( + self.hourly_message_counts.items(), + key=lambda x: x[1], + reverse=True, + ) + return [int(h) for h, _ in sorted_hours[:top_n]] + + def get_most_active_period(self) -> str: + """ + 获取最活跃时段的描述字符串。 + + Returns: + str: 如 "20:00-21:00" + """ + peak = self.get_peak_hours(1) + if not peak: + return "未知" + hour = peak[0] + return f"{hour:02d}:00-{hour + 1:02d}:00" + + def get_user_activity_ranking(self, top_n: int = 10) -> list[dict]: + """ + 获取用户活跃度排名。 + + Args: + top_n: 返回前 N 名 + + Returns: + list[dict]: 按消息数降序排列的用户列表 + """ + users = [] + for user_id, data in self.user_activities.items(): + users.append( + { + "user_id": user_id, + "name": data.get("nickname", data.get("name", user_id)), + "message_count": data.get("message_count", 0), + "char_count": data.get("char_count", 0), + } + ) + users.sort(key=lambda x: x["message_count"], reverse=True) + return users[:top_n] + + def get_window_date_str(self) -> str: + """ + 获取窗口的日期范围字符串,用于报告显示。 + + Returns: + str: 如 "2024-01-15" 或 "2024-01-14 ~ 2024-01-15" + """ + if self.window_start <= 0 or self.window_end <= 0: + return datetime.now().strftime("%Y-%m-%d") + + start_date = datetime.fromtimestamp(self.window_start).strftime("%Y-%m-%d") + end_date = datetime.fromtimestamp(self.window_end).strftime("%Y-%m-%d") + + if start_date == end_date: + return end_date + return f"{start_date} ~ {end_date}" + + def get_summary(self) -> dict: + """ + 获取当前增量状态的摘要信息,用于状态查询命令。 + + Returns: + dict: 包含关键统计信息的摘要 + """ + return { + "group_id": self.group_id, + "window": self.get_window_date_str(), + "total_messages": self.total_message_count, + "total_characters": self.total_character_count, + "total_analyses": self.total_analysis_count, + "topics_count": len(self.topics), + "quotes_count": len(self.golden_quotes), + "participants": len(self.all_participant_ids), + "total_tokens": self.total_token_usage.get("total_tokens", 0), + "last_analysis_time": ( + datetime.fromtimestamp(self.updated_at).strftime("%H:%M:%S") + if self.updated_at + else "无" + ), + "peak_hours": self.get_peak_hours(3), + } + + @staticmethod + def is_duplicate_topic( + new_topic: dict, existing_topics: list[dict], threshold: float = 0.6 + ) -> bool: + """ + 检测话题是否与已有话题重复。 + + 使用简单的字符重叠相似度判断。 + 当新话题的名称与已有话题名称相似度超过阈值时,认为是重复话题。 + + Args: + new_topic: 待检测的新话题 + existing_topics: 已有话题列表 + threshold: 相似度阈值(0-1),默认 0.6 + + Returns: + bool: 是否重复 + """ + new_name = new_topic.get("topic", "") + if not new_name: + return False + + for existing in existing_topics: + existing_name = existing.get("topic", "") + if not existing_name: + continue + similarity = IncrementalState.char_overlap_similarity( + new_name, existing_name + ) + if similarity >= threshold: + return True + return False + + @staticmethod + def is_duplicate_quote( + new_quote: dict, existing_quotes: list[dict], threshold: float = 0.7 + ) -> bool: + """ + 检测金句是否与已有金句重复。 + + Args: + new_quote: 待检测的新金句 + existing_quotes: 已有金句列表 + threshold: 相似度阈值(0-1),默认 0.7 + + Returns: + bool: 是否重复 + """ + new_content = new_quote.get("content", "") + if not new_content: + return False + + for existing in existing_quotes: + existing_content = existing.get("content", "") + if not existing_content: + continue + similarity = IncrementalState.char_overlap_similarity( + new_content, existing_content + ) + if similarity >= threshold: + return True + return False + + @staticmethod + def char_overlap_similarity(s1: str, s2: str) -> float: + """ + 计算两个字符串的字符重叠相似度(Jaccard 相似系数)。 + + Args: + s1: 第一个字符串 + s2: 第二个字符串 + + Returns: + float: 相似度值(0-1) + """ + if not s1 or not s2: + return 0.0 + set1 = set(s1) + set2 = set(s2) + intersection = set1 & set2 + union = set1 | set2 + if not union: + return 0.0 + return len(intersection) / len(union) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/exceptions.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/exceptions.py new file mode 100644 index 0000000..3320bdc --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/exceptions.py @@ -0,0 +1,254 @@ +""" +领域异常 - 领域层自定义异常 + +该模块包含插件中使用的所有领域特定异常。 +这些异常是平台无关的,表示业务逻辑错误。 +""" + + +class DomainException(Exception): + """所有领域错误的基础异常。""" + + def __init__(self, message: str, code: str = "DOMAIN_ERROR"): + self.message = message + self.code = code + super().__init__(self.message) + + +# ============================================================================ +# 分析异常 +# ============================================================================ + + +class AnalysisException(DomainException): + """分析相关错误的基础异常。""" + + def __init__(self, message: str, code: str = "ANALYSIS_ERROR"): + super().__init__(message, code) + + +class InsufficientDataException(AnalysisException): + """当数据不足以进行分析时抛出。""" + + def __init__(self, message: str = "数据不足,无法进行分析"): + super().__init__(message, "INSUFFICIENT_DATA") + + +class AnalysisTimeoutException(AnalysisException): + """当分析超时时抛出。""" + + def __init__(self, message: str = "分析超时"): + super().__init__(message, "ANALYSIS_TIMEOUT") + + +class LLMException(AnalysisException): + """当 LLM API 调用失败时抛出。""" + + def __init__(self, message: str = "LLM API 调用失败", provider: str = ""): + self.provider = provider + super().__init__( + f"{message} (提供商: {provider})" if provider else message, "LLM_ERROR" + ) + + +class LLMRateLimitException(LLMException): + """当 LLM API 速率限制超出时抛出。""" + + def __init__(self, message: str = "LLM 速率限制超出", provider: str = ""): + super().__init__(message, provider) + self.code = "LLM_RATE_LIMIT" + + +class LLMQuotaExceededException(LLMException): + """当 LLM API 配额超出时抛出。""" + + def __init__(self, message: str = "LLM 配额超出", provider: str = ""): + super().__init__(message, provider) + self.code = "LLM_QUOTA_EXCEEDED" + + +# ============================================================================ +# 平台异常 +# ============================================================================ + + +class PlatformException(DomainException): + """平台相关错误的基础异常。""" + + def __init__(self, message: str, platform: str = "", code: str = "PLATFORM_ERROR"): + self.platform = platform + super().__init__(f"[{platform}] {message}" if platform else message, code) + + +class PlatformNotSupportedException(PlatformException): + """当平台不被支持时抛出。""" + + def __init__(self, platform: str): + super().__init__( + f"平台 '{platform}' 不被支持", platform, "PLATFORM_NOT_SUPPORTED" + ) + + +class PlatformConnectionException(PlatformException): + """当连接平台失败时抛出。""" + + def __init__(self, message: str = "连接平台失败", platform: str = ""): + super().__init__(message, platform, "PLATFORM_CONNECTION_ERROR") + + +class PlatformAPIException(PlatformException): + """当平台 API 调用失败时抛出。""" + + def __init__(self, message: str = "平台 API 调用失败", platform: str = ""): + super().__init__(message, platform, "PLATFORM_API_ERROR") + + +class MessageFetchException(PlatformException): + """当获取消息失败时抛出。""" + + def __init__( + self, message: str = "获取消息失败", platform: str = "", group_id: str = "" + ): + self.group_id = group_id + super().__init__( + f"{message} (群组: {group_id})" if group_id else message, + platform, + "MESSAGE_FETCH_ERROR", + ) + + +class MessageSendException(PlatformException): + """当发送消息失败时抛出。""" + + def __init__( + self, message: str = "发送消息失败", platform: str = "", group_id: str = "" + ): + self.group_id = group_id + super().__init__( + f"{message} (群组: {group_id})" if group_id else message, + platform, + "MESSAGE_SEND_ERROR", + ) + + +# ============================================================================ +# 配置异常 +# ============================================================================ + + +class ConfigurationException(DomainException): + """配置相关错误的基础异常。""" + + def __init__(self, message: str, code: str = "CONFIG_ERROR"): + super().__init__(message, code) + + +class InvalidConfigurationException(ConfigurationException): + """当配置无效时抛出。""" + + def __init__(self, message: str = "无效的配置", key: str = ""): + self.key = key + super().__init__(f"{message}: {key}" if key else message, "INVALID_CONFIG") + + +class MissingConfigurationException(ConfigurationException): + """当缺少必需配置时抛出。""" + + def __init__(self, key: str): + self.key = key + super().__init__(f"缺少必需配置: {key}", "MISSING_CONFIG") + + +# ============================================================================ +# 仓储异常 +# ============================================================================ + + +class RepositoryException(DomainException): + """仓储相关错误的基础异常。""" + + def __init__(self, message: str, code: str = "REPOSITORY_ERROR"): + super().__init__(message, code) + + +class DataNotFoundException(RepositoryException): + """当请求的数据未找到时抛出。""" + + def __init__( + self, message: str = "数据未找到", entity_type: str = "", entity_id: str = "" + ): + self.entity_type = entity_type + self.entity_id = entity_id + super().__init__( + f"{entity_type} 未找到: {entity_id}" if entity_type else message, + "DATA_NOT_FOUND", + ) + + +class DataPersistenceException(RepositoryException): + """当数据持久化失败时抛出。""" + + def __init__(self, message: str = "数据持久化失败"): + super().__init__(message, "DATA_PERSISTENCE_ERROR") + + +# ============================================================================ +# 调度异常 +# ============================================================================ + + +class SchedulingException(DomainException): + """调度相关错误的基础异常。""" + + def __init__(self, message: str, code: str = "SCHEDULING_ERROR"): + super().__init__(message, code) + + +class TaskAlreadyScheduledException(SchedulingException): + """当尝试调度已调度的任务时抛出。""" + + def __init__(self, task_id: str): + self.task_id = task_id + super().__init__(f"任务已调度: {task_id}", "TASK_ALREADY_SCHEDULED") + + +class TaskNotFoundException(SchedulingException): + """当找不到已调度的任务时抛出。""" + + def __init__(self, task_id: str): + self.task_id = task_id + super().__init__(f"未找到已调度的任务: {task_id}", "TASK_NOT_FOUND") + + +# ============================================================================ +# 验证异常 +# ============================================================================ + + +class ValidationException(DomainException): + """验证错误的基础异常。""" + + def __init__(self, message: str, field: str = "", code: str = "VALIDATION_ERROR"): + self.field = field + super().__init__(f"{field}: {message}" if field else message, code) + + +class InvalidGroupIdException(ValidationException): + """当群组 ID 无效时抛出。""" + + def __init__(self, group_id: str): + super().__init__(f"无效的群组 ID: {group_id}", "group_id", "INVALID_GROUP_ID") + + +class InvalidUserIdException(ValidationException): + """当用户 ID 无效时抛出。""" + + def __init__(self, user_id: str): + super().__init__(f"无效的用户 ID: {user_id}", "user_id", "INVALID_USER_ID") + + +class InvalidMessageException(ValidationException): + """当消息格式无效时抛出。""" + + def __init__(self, message: str = "无效的消息格式"): + super().__init__(message, "message", "INVALID_MESSAGE") diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/models/data_models.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/models/data_models.py new file mode 100644 index 0000000..3a82e8e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/models/data_models.py @@ -0,0 +1,121 @@ +""" +数据模型定义 +包含所有分析相关的数据结构 +""" + +from dataclasses import dataclass, field +from typing import Optional + + +@dataclass +class SummaryTopic: + """话题总结数据结构""" + + topic: str + contributors: list[str] + detail: str + contributor_ids: list[str] = field( + default_factory=list + ) # 贡献者ID列表 (用于显示头像) + + +@dataclass +class UserTitle: + """用户称号数据结构""" + + name: str + user_id: str # 原 qq 字段 + title: str + mbti: str + reason: str + + +@dataclass +class GoldenQuote: + """群聊金句数据结构""" + + content: str + sender: str + reason: str + user_id: str = "" # 原 qq 字段 + + +@dataclass +class QualityDimension: + """聊天质量维度数据结构""" + + name: str # 维度名称 + percentage: float # 占比 + comment: str # 犀利点评 + color: str = "#607d8b" # 颜色 + + +@dataclass +class QualityReview: + """聊天质量锐评数据结构""" + + title: str + subtitle: str + dimensions: list[QualityDimension] + summary: str + + +@dataclass +class TokenUsage: + """Token使用统计""" + + prompt_tokens: int = 0 + completion_tokens: int = 0 + total_tokens: int = 0 + + +@dataclass +class EmojiStatistics: + """表情统计数据结构""" + + face_count: int = 0 # QQ基础表情数量 + mface_count: int = 0 # 动画表情数量 + bface_count: int = 0 # 超级表情数量 + sface_count: int = 0 # 小表情数量 + other_emoji_count: int = 0 # 其他表情数量 + face_details: dict = field(default_factory=dict) # 具体表情ID统计 {face_id: count} + + @property + def total_emoji_count(self) -> int: + """总表情数量""" + return ( + self.face_count + + self.mface_count + + self.bface_count + + self.sface_count + + self.other_emoji_count + ) + + +@dataclass +class ActivityVisualization: + """活跃度可视化数据结构""" + + hourly_activity: dict = field(default_factory=dict) # {hour: count} + daily_activity: dict = field(default_factory=dict) # {date: count} + user_activity_ranking: list = field(default_factory=list) # 用户活跃度排行 + peak_hours: list = field(default_factory=list) # 高峰时段 + activity_heatmap_data: dict = field(default_factory=dict) # 热力图数据 + + +@dataclass +class GroupStatistics: + """群聊统计数据结构""" + + message_count: int + total_characters: int + participant_count: int + most_active_period: str + golden_quotes: list[GoldenQuote] + emoji_count: int # 保持向后兼容 + emoji_statistics: EmojiStatistics = field(default_factory=EmojiStatistics) + activity_visualization: ActivityVisualization = field( + default_factory=ActivityVisualization + ) + token_usage: TokenUsage = field(default_factory=TokenUsage) + chat_quality_review: Optional["QualityReview"] = None diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/__init__.py new file mode 100644 index 0000000..ea243c0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/__init__.py @@ -0,0 +1,12 @@ +# 仓储接口 +from .avatar_repository import IAvatarRepository +from .message_repository import IGroupInfoRepository, IMessageRepository, IMessageSender +from .visualization_repository import IActivityVisualizer + +__all__ = [ + "IMessageRepository", + "IMessageSender", + "IGroupInfoRepository", + "IAvatarRepository", + "IActivityVisualizer", +] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/analysis_repository.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/analysis_repository.py new file mode 100644 index 0000000..d6100ce --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/analysis_repository.py @@ -0,0 +1,97 @@ +""" +分析服务接口 - 领域层 +定义语义分析的抽象契约 +""" + +from abc import ABC, abstractmethod + +from ..models.data_models import ( + GoldenQuote, + QualityReview, + SummaryTopic, + TokenUsage, + UserTitle, +) + + +class IAnalysisProvider(ABC): + """ + LLM 分析提供商接口 + """ + + @abstractmethod + async def analyze_topics( + self, + messages: list[dict], + umo: str | None = None, + session_id: str | None = None, + ) -> tuple[list[SummaryTopic], TokenUsage]: + """分析话题""" + pass + + @abstractmethod + async def analyze_user_titles( + self, + messages: list[dict], + user_activity: dict, + umo: str | None = None, + top_users: list[dict] | None = None, + session_id: str | None = None, + ) -> tuple[list[UserTitle], TokenUsage]: + """分析用户称号""" + pass + + @abstractmethod + async def analyze_golden_quotes( + self, + messages: list[dict], + umo: str | None = None, + session_id: str | None = None, + ) -> tuple[list[GoldenQuote], TokenUsage]: + """分析金句""" + pass + + @abstractmethod + async def analyze_all_concurrent( + self, + messages: list[dict], + user_activity: dict, + umo: str | None = None, + top_users: list[dict] | None = None, + topic_enabled: bool = True, + user_title_enabled: bool = True, + golden_quote_enabled: bool = True, + chat_quality_enabled: bool = False, + ) -> tuple[ + list[SummaryTopic], + list[UserTitle], + list[GoldenQuote], + TokenUsage, + QualityReview | None, + ]: + """并发分析所有内容""" + pass + + @abstractmethod + async def analyze_incremental_concurrent( + self, + messages: list[dict], + umo: str | None = None, + topics_per_batch: int = 3, + quotes_per_batch: int = 3, + topic_enabled: bool = True, + golden_quote_enabled: bool = True, + chat_quality_enabled: bool = False, + ) -> tuple[list[SummaryTopic], list[GoldenQuote], TokenUsage, QualityReview | None]: + """增量模式并发分析""" + pass + + @abstractmethod + async def summarize_quality_reviews( + self, + batch_reviews: list[dict], + umo: str | None = None, + session_id: str | None = None, + ) -> tuple[QualityReview | None, TokenUsage]: + """汇总多个聊天质量报告(增量模式使用)""" + pass diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/avatar_repository.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/avatar_repository.py new file mode 100644 index 0000000..b59fcfa --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/avatar_repository.py @@ -0,0 +1,78 @@ +""" +头像仓储接口 - 跨平台头像抽象 +""" + +from abc import ABC, abstractmethod + + +class IAvatarRepository(ABC): + """ + 头像仓储接口 + + 不同平台获取头像的方式不同: + - QQ/OneBot: URL 模板 (q1.qlogo.cn) + - Telegram: API 调用 (getUserProfilePhotos + getFile) + - Discord: CDN URL 模板 (cdn.discordapp.com) + - Slack: users.info API profile.image_* 字段 + """ + + @abstractmethod + async def get_user_avatar_url( + self, + user_id: str, + size: int = 100, + ) -> str | None: + """ + 获取用户头像 URL + + 参数: + user_id: 用户 ID + size: 期望的头像尺寸(将选择最接近的可用尺寸) + + 返回: + 头像 URL,如果不可用则返回 None + """ + pass + + @abstractmethod + async def get_user_avatar_data( + self, + user_id: str, + size: int = 100, + ) -> str | None: + """ + 获取用户头像的 Base64 数据 + + 用于需要嵌入图片的场景(如 HTML 模板渲染) + + 返回: + Base64 编码的图片数据 (data:image/png;base64,...), + 如果不可用则返回 None + """ + pass + + @abstractmethod + async def get_group_avatar_url( + self, + group_id: str, + size: int = 100, + ) -> str | None: + """获取群组头像 URL""" + pass + + @abstractmethod + async def batch_get_avatar_urls( + self, + user_ids: list[str], + size: int = 100, + ) -> dict[str, str | None]: + """ + 批量获取用户头像 URL + + 用于报告生成时需要一次获取多个头像 + """ + pass + + def get_default_avatar_url(self) -> str: + """获取默认头像 URL(当用户头像不可用时)""" + return "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTEyIDEyYzIuMjEgMCA0LTEuNzkgNC00cy0xLjc5LTQtNC00LTQgMS43OS00IDQgMS43OSA0IDQgNHptMCAyYy0yLjY3IDAtOCAxLjM0LTggNHYyaDE2di0yYzAtMi42Ni01LjMzLTQtOC00eiIvPjwvc3ZnPg==" diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/message_repository.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/message_repository.py new file mode 100644 index 0000000..a430495 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/message_repository.py @@ -0,0 +1,130 @@ +""" +消息仓储接口 - 平台无关的抽象 +""" + +from abc import ABC, abstractmethod + +from ..value_objects.platform_capabilities import PlatformCapabilities +from ..value_objects.unified_group import UnifiedGroup, UnifiedMember +from ..value_objects.unified_message import UnifiedMessage + + +class IMessageRepository(ABC): + """ + 消息仓储接口 + + 每个平台适配器必须实现此接口。 + 所有方法返回统一格式,隐藏平台差异。 + """ + + @abstractmethod + async def fetch_messages( + self, + group_id: str, + days: int = 1, + max_count: int = 1000, + before_id: str | None = None, + since_ts: int | None = None, + ) -> list[UnifiedMessage]: + """ + 获取群组消息历史 + + 参数: + group_id: 群组 ID + days: 获取最近 N 天的消息 + max_count: 最大消息数量 + before_id: 获取此 ID 之前的消息(用于分页) + since_ts: 从指定时间戳开始拉取消息(Unix timestamp),优先级高于 days。 + + 返回: + 统一消息列表,按时间升序排列 + """ + pass + + @abstractmethod + def get_capabilities(self) -> PlatformCapabilities: + """获取平台能力""" + pass + + @abstractmethod + def get_platform_name(self) -> str: + """获取平台名称""" + pass + + +class IMessageSender(ABC): + """消息发送接口""" + + @abstractmethod + async def send_text( + self, + group_id: str, + text: str, + reply_to: str | None = None, + ) -> bool: + """发送文本消息""" + pass + + @abstractmethod + async def send_image( + self, + group_id: str, + image_path: str, + caption: str = "", + ) -> bool: + """发送图片消息""" + pass + + @abstractmethod + async def send_forward_msg( + self, + group_id: str, + nodes: list[dict], + ) -> bool: + """ + 发送合并转发消息。 + + Args: + group_id: 目标群组 ID + nodes: 转发节点列表。每个节点通常包含 name, uin (或 user_id), content。 + 目前主要用于 OneBot 兼容性。 + """ + pass + + @abstractmethod + async def send_file( + self, + group_id: str, + file_path: str, + filename: str | None = None, + ) -> bool: + """发送文件""" + pass + + +class IGroupInfoRepository(ABC): + """群组信息仓储接口""" + + @abstractmethod + async def get_group_info(self, group_id: str) -> UnifiedGroup | None: + """获取群组信息""" + pass + + @abstractmethod + async def get_group_list(self) -> list[str]: + """获取机器人所在的所有群组 ID""" + pass + + @abstractmethod + async def get_member_list(self, group_id: str) -> list[UnifiedMember]: + """获取群组成员列表""" + pass + + @abstractmethod + async def get_member_info( + self, + group_id: str, + user_id: str, + ) -> UnifiedMember | None: + """获取指定成员信息""" + pass diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/report_repository.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/report_repository.py new file mode 100644 index 0000000..0430e3d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/report_repository.py @@ -0,0 +1,56 @@ +""" +报告生成接口 - 领域层 +定义分析报告生成的抽象契约 +""" + +from abc import ABC, abstractmethod +from typing import Any + + +class IReportGenerator(ABC): + """ + 报告生成器接口 + """ + + @abstractmethod + async def generate_image_report( + self, + analysis_result: dict, + group_id: str, + html_render_func: Any, + avatar_url_getter: Any = None, + nickname_getter: Any = None, + avatar_cache_namespace: str | None = None, + hide_user_names: bool = False, + allow_alphanumeric_user_ids: bool = False, + template_theme: str | None = None, + ) -> tuple[str | None, str | None]: + """生成图片报告""" + pass + + @abstractmethod + async def generate_html_report( + self, + analysis_result: dict, + group_id: str, + avatar_url_getter: Any = None, + nickname_getter: Any = None, + avatar_cache_namespace: str | None = None, + hide_user_names: bool = False, + allow_alphanumeric_user_ids: bool = False, + template_theme: str | None = None, + custom_filename: str | None = None, + trace_id: str | None = None, + ) -> tuple[str | None, str | None]: + """生成 HTML 报告""" + pass + + @abstractmethod + def generate_text_report(self, analysis_result: dict) -> str: + """生成文本报告""" + pass + + @abstractmethod + async def close(self): + """释放资源""" + pass diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/visualization_repository.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/visualization_repository.py new file mode 100644 index 0000000..bfcb6a5 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/repositories/visualization_repository.py @@ -0,0 +1,19 @@ +""" +可视化仓储接口 - 领域层 +定义活跃度可视化的抽象契约。 +""" + +from abc import ABC, abstractmethod + +from ..models.data_models import ActivityVisualization + + +class IActivityVisualizer(ABC): + """活跃度可视化接口 - 领域层抽象""" + + @abstractmethod + def generate_activity_visualization( + self, messages: list[dict] + ) -> ActivityVisualization: + """从消息列表生成活跃度可视化数据""" + pass diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/__init__.py new file mode 100644 index 0000000..1edbc6b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/__init__.py @@ -0,0 +1,12 @@ +""" +领域服务 - 分析业务逻辑服务 + +该模块导出所有封装核心业务逻辑的领域服务, +用于分析群聊数据。这些服务是平台无关的。 +""" + +from .incremental_merge_service import IncrementalMergeService + +__all__ = [ + "IncrementalMergeService", +] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/analysis_domain_service.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/analysis_domain_service.py new file mode 100644 index 0000000..89ea826 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/analysis_domain_service.py @@ -0,0 +1,142 @@ +""" +分析领域服务 - 领域层 +负责用户维度的活跃度分析、发言习惯及活动模式识别。 +""" + +from datetime import datetime +from typing import TypedDict + +from ..value_objects.unified_message import MessageContentType, UnifiedMessage + + +class UserActivityStats(TypedDict): + message_count: int + char_count: int + emoji_count: int + nickname: str + hours: dict[int, int] + reply_count: int + + +class AnalysisDomainService: + """分析领域服务 - 处理用户画像及行为分析""" + + def analyze_user_activity( + self, + messages: list[UnifiedMessage], + bot_self_ids: list[str] | None = None, + ) -> dict[str, UserActivityStats]: + """ + 分析用户活跃度。 + + 基于 UnifiedMessage 计算每个用户的发言数、字数、表情数等。 + """ + user_stats: dict[str, UserActivityStats] = {} + + bot_ids = set(bot_self_ids or []) + + for msg in messages: + user_id = msg.sender_id + + # 跳过机器人自己的消息 + if user_id in bot_ids: + continue + + stats = user_stats.setdefault( + user_id, + { + "message_count": 0, + "char_count": 0, + "emoji_count": 0, + "nickname": "", + "hours": {}, + "reply_count": 0, + }, + ) + stats["message_count"] += 1 + stats["nickname"] = msg.sender_card or msg.sender_name + + # 统计时间分布 + msg_time = datetime.fromtimestamp(msg.timestamp) + hour = msg_time.hour + stats["hours"][hour] = stats["hours"].get(hour, 0) + 1 + + # 统计内容 + for content in msg.contents: + if content.type == MessageContentType.TEXT: + stats["char_count"] += len(content.text or "") + + elif content.type == MessageContentType.EMOJI: + stats["emoji_count"] += 1 + + elif content.type == MessageContentType.IMAGE: + # 与 GroupStatistics 口径保持一致 + if self._is_emoji_like_image(content.raw_data): + stats["emoji_count"] += 1 + + elif content.type == MessageContentType.REPLY: + stats["reply_count"] += 1 + + return user_stats + + @staticmethod + def _is_emoji_like_image(raw_data: object) -> bool: + """判断 IMAGE 段是否应按表情计数。""" + if isinstance(raw_data, dict): + sub_type = raw_data.get("sub_type") + if sub_type is not None: + return str(sub_type) == "1" + summary = str(raw_data.get("summary", "")) + return "动画表情" in summary or "表情" in summary + + if raw_data is None: + return False + + text = str(raw_data) + return "动画表情" in text or "表情" in text + + def get_top_users( + self, user_activity: dict[str, UserActivityStats], limit: int = 10 + ) -> list[dict]: + """获取最活跃的用户列表""" + users = [] + for user_id, stats in user_activity.items(): + users.append( + { + "user_id": user_id, + "nickname": stats["nickname"], + "message_count": stats["message_count"], + "char_count": stats["char_count"], + "emoji_count": stats["emoji_count"], + "reply_count": stats["reply_count"], + } + ) + + # 按消息数量排序 + users.sort(key=lambda x: x["message_count"], reverse=True) + return users[:limit] + + def get_user_activity_pattern( + self, user_activity: dict[str, UserActivityStats], user_id: str + ) -> dict: + """获取并识别指定用户的活动模式""" + if user_id not in user_activity: + return {} + + stats = user_activity[user_id] + hours = stats["hours"] + + # 找出最活跃的时间段 + most_active_hour = max(hours.items(), key=lambda x: x[1])[0] if hours else 0 + + # 计算夜间活跃度 (0-6点) + night_messages = sum(hours[h] for h in range(0, 6)) + night_ratio = ( + night_messages / stats["message_count"] if stats["message_count"] > 0 else 0 + ) + + return { + "most_active_hour": most_active_hour, + "night_ratio": night_ratio, + "hourly_distribution": dict(hours), + } diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/incremental_merge_service.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/incremental_merge_service.py new file mode 100644 index 0000000..1ffbdbf --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/incremental_merge_service.py @@ -0,0 +1,409 @@ +""" +增量合并领域服务 + +负责将 IncrementalBatch 列表合并为 IncrementalState, +以及将 IncrementalState 累积数据转换为现有实体类型, +以便复用现有的报告生成器和分发器。 + +核心职责: +- merge_batches: 将多个 IncrementalBatch 合并为一个 IncrementalState(滑动窗口聚合) +- IncrementalState → GroupStatistics(含 ActivityVisualization、EmojiStatistics) +- IncrementalState → list[SummaryTopic] +- IncrementalState → list[GoldenQuote] +""" + +import time + +from ...domain.entities.incremental_state import IncrementalBatch, IncrementalState +from ...domain.models.data_models import ( + ActivityVisualization, + EmojiStatistics, + GoldenQuote, + GroupStatistics, + QualityDimension, + QualityReview, + SummaryTopic, + TokenUsage, +) +from ...utils.logger import logger + + +class IncrementalMergeService: + """ + 增量合并服务 + + 将滑动窗口内的多个批次数据合并为报告所需的数据结构, + 确保增量模式下生成的最终报告与传统单次分析报告格式完全一致。 + """ + + def merge_batches( + self, + batches: list[IncrementalBatch], + window_start: float, + window_end: float, + ) -> IncrementalState: + """ + 从批次列表合并构建 IncrementalState。 + + 遍历所有批次,累加统计数据并对话题和金句执行去重, + 生成可用于报告的聚合视图。 + + Args: + batches: 时间窗口内的批次列表(按时间升序) + window_start: 窗口起始时间戳(epoch) + window_end: 窗口结束时间戳(epoch) + + Returns: + IncrementalState: 合并后的聚合视图 + """ + state = IncrementalState( + group_id=batches[0].group_id if batches else "", + window_start=window_start, + window_end=window_end, + total_analysis_count=len(batches), + created_at=window_start, + updated_at=time.time(), + ) + + for batch in batches: + # 累加消息和字符计数 + state.total_message_count += batch.messages_count + state.total_character_count += batch.characters_count + + # 合并每小时消息分布(按键累加) + for hour_key, count in batch.hourly_msg_counts.items(): + hour_str = str(hour_key) + state.hourly_message_counts[hour_str] = ( + state.hourly_message_counts.get(hour_str, 0) + count + ) + + # 合并每小时字符分布 + for hour_key, count in batch.hourly_char_counts.items(): + hour_str = str(hour_key) + state.hourly_character_counts[hour_str] = ( + state.hourly_character_counts.get(hour_str, 0) + count + ) + + # 合并用户统计(按用户累加消息数、字符数等) + for raw_user_id, stats in batch.user_stats.items(): + user_id = str(raw_user_id) + if user_id not in state.user_activities: + state.user_activities[user_id] = { + "nickname": stats.get("nickname", stats.get("name", user_id)), + "message_count": 0, + "char_count": 0, + "emoji_count": 0, + "reply_count": 0, + "hours": {}, + "last_message_time": 0, + } + existing = state.user_activities[user_id] + existing["message_count"] += stats.get("message_count", 0) + existing["char_count"] += stats.get("char_count", 0) + existing["emoji_count"] += stats.get("emoji_count", 0) + existing["reply_count"] += stats.get("reply_count", 0) + + # 合并每小时统计 + # 兼容旧版本 (active_hours 是 list) 和新版本 (hours 是 dict) + batch_hours = stats.get("hours", {}) + if isinstance(batch_hours, dict): + # 现代 schema: hours 是 dict {hour: count} + for h_str, h_count in batch_hours.items(): + h_int = int(h_str) + existing["hours"][h_int] = ( + existing["hours"].get(h_int, 0) + h_count + ) + else: + # 兼容旧 schema: 只有 active_hours (list) + active_hours = stats.get("active_hours", []) + for h in active_hours: + h_int = int(h) + existing["hours"][h_int] = existing["hours"].get(h_int, 0) + 1 + + # 取最后消息时间的较大值 + batch_last = stats.get("last_message_time", 0) + if batch_last > existing.get("last_message_time", 0): + existing["last_message_time"] = batch_last + + # 更新昵称(使用最新批次的有效昵称) + nickname = stats.get("nickname", stats.get("name", "")) + if nickname and str(nickname).strip(): + existing["nickname"] = nickname + + # 合并表情统计(按键累加) + for emoji_key, count in batch.emoji_stats.items(): + current_val = state.emoji_counts.get(emoji_key, 0) + if isinstance(count, dict): + # 如果是嵌套字典(如 face_details),则合并内部计数 + if not isinstance(current_val, dict): + current_val = {} + + for sub_key, sub_count in count.items(): + # 确保 current_val 是字典且 sub_count 是数字 + if isinstance(current_val, dict): + current_val[sub_key] = ( + current_val.get(sub_key, 0) + sub_count + ) + + state.emoji_counts[emoji_key] = current_val + else: + # 如果是数值,直接累加 + if isinstance(current_val, dict): + # 异常情况:现有值是字典但新值是数字,通常不应发生,除非 schema 变更 + # 此时保留字典,忽略数字或记录错误,这里选择保留字典 + continue + + state.emoji_counts[emoji_key] = current_val + count + + # 合并话题(去重) + for topic in batch.topics: + if not IncrementalState.is_duplicate_topic(topic, state.topics): + state.topics.append(topic) + + # 合并金句(去重) + for quote in batch.golden_quotes: + if not IncrementalState.is_duplicate_quote(quote, state.golden_quotes): + state.golden_quotes.append(quote) + + # 累加 token 消耗 + for token_key in ("prompt_tokens", "completion_tokens", "total_tokens"): + state.total_token_usage[token_key] = state.total_token_usage.get( + token_key, 0 + ) + batch.token_usage.get(token_key, 0) + + # 合并参与者 ID(取并集) + state.all_participant_ids.update(batch.participant_ids) + + # 收集所有批次的质量锐评(用于最终汇总) + if batch.chat_quality_review: + state.all_quality_reviews.append(batch.chat_quality_review) + + # 记录最后分析消息时间戳(取最大值) + if batch.last_message_timestamp > state.last_analyzed_message_timestamp: + state.last_analyzed_message_timestamp = batch.last_message_timestamp + # 更新锐评为最新批次的 (如果没有汇总分析,则作为兜底) + if batch.chat_quality_review: + state.chat_quality_review = batch.chat_quality_review + + logger.info( + f"合并批次完成: 群={state.group_id}, " + f"窗口={state.get_window_date_str()}, " + f"批次数={len(batches)}, " + f"总消息={state.total_message_count}, " + f"话题={len(state.topics)}, 金句={len(state.golden_quotes)}" + ) + + return state + + def build_final_statistics(self, state: IncrementalState) -> GroupStatistics: + """ + 从增量状态构建最终的群组统计数据。 + + 将 IncrementalState 中的累积数据映射到 GroupStatistics, + 包含完整的 24 小时活跃度分布、表情统计和 token 消耗。 + + Args: + state: 由 merge_batches 合并生成的增量分析状态 + + Returns: + GroupStatistics: 与传统分析格式一致的统计数据 + """ + # 构建 24 小时活跃度分布 + hourly_activity = {} + for hour in range(24): + hour_key = str(hour) + hourly_activity[hour] = state.hourly_message_counts.get(hour_key, 0) + + # 获取高峰时段 + peak_hours = state.get_peak_hours(3) + + # 构建用户活跃排名 + user_ranking = state.get_user_activity_ranking(10) + + # 构建活跃度可视化数据 + activity_visualization = ActivityVisualization( + hourly_activity=hourly_activity, + daily_activity={state.get_window_date_str(): state.total_message_count}, + user_activity_ranking=user_ranking, + peak_hours=peak_hours, + activity_heatmap_data={}, + ) + + # 构建表情统计 + emoji_statistics = self._build_emoji_statistics(state) + + # 构建 token 消耗 + token_usage = TokenUsage( + prompt_tokens=state.total_token_usage.get("prompt_tokens", 0), + completion_tokens=state.total_token_usage.get("completion_tokens", 0), + total_tokens=state.total_token_usage.get("total_tokens", 0), + ) + + # 获取最活跃时段描述 + most_active_period = state.get_most_active_period() + + # 转换聊天质量锐评 (如果有) + chat_quality_review = None + if state.chat_quality_review: + review_dict = state.chat_quality_review + dimensions_dict = review_dict.get("dimensions", []) + dimensions = [ + QualityDimension( + name=d.get("name", "未知"), + percentage=float(d.get("percentage", 0)), + comment=d.get("comment", ""), + color=d.get("color", "#607d8b"), + ) + for d in dimensions_dict + ] + chat_quality_review = QualityReview( + title=review_dict.get("title", "聊天质量锐评"), + subtitle=review_dict.get("subtitle", "今天的群里发生了什么?"), + dimensions=dimensions, + summary=review_dict.get("summary", "今天也是充满活力的一天。"), + ) + + statistics = GroupStatistics( + message_count=state.total_message_count, + total_characters=state.total_character_count, + participant_count=len(state.all_participant_ids), + most_active_period=most_active_period, + golden_quotes=[], # 金句通过 build_quotes_for_report 单独构建 + emoji_count=emoji_statistics.total_emoji_count, + emoji_statistics=emoji_statistics, + activity_visualization=activity_visualization, + token_usage=token_usage, + chat_quality_review=chat_quality_review, + ) + + logger.debug( + f"从增量状态构建统计: " + f"消息数={state.total_message_count}, " + f"参与人数={len(state.all_participant_ids)}, " + f"话题数={len(state.topics)}, " + f"金句数={len(state.golden_quotes)}" + ) + + return statistics + + def build_topics_for_report(self, state: IncrementalState) -> list[SummaryTopic]: + """ + 从增量状态构建报告用的话题列表。 + + 将 IncrementalState 中累积的话题字典转换为 SummaryTopic 实例列表。 + + Args: + state: 由 merge_batches 合并生成的增量分析状态 + + Returns: + list[SummaryTopic]: 话题列表,格式与传统分析结果一致 + """ + topics = [] + for topic_dict in state.topics: + topic = SummaryTopic( + topic=topic_dict.get("topic", "未知话题"), + contributors=topic_dict.get("contributors", []), + detail=topic_dict.get("detail", ""), + contributor_ids=topic_dict.get("contributor_ids", []), + ) + topics.append(topic) + + logger.debug(f"从增量状态构建了 {len(topics)} 个话题") + return topics + + def build_quotes_for_report(self, state: IncrementalState) -> list[GoldenQuote]: + """ + 从增量状态构建报告用的金句列表。 + + 将 IncrementalState 中累积的金句字典转换为 GoldenQuote 实例列表。 + + Args: + state: 由 merge_batches 合并生成的增量分析状态 + + Returns: + list[GoldenQuote]: 金句列表,格式与传统分析结果一致 + """ + quotes = [] + for quote_dict in state.golden_quotes: + quote = GoldenQuote( + content=quote_dict.get("content", ""), + sender=quote_dict.get("sender", ""), + reason=quote_dict.get("reason", ""), + user_id=str(quote_dict.get("user_id", "")), + ) + quotes.append(quote) + + logger.debug(f"从增量状态构建了 {len(quotes)} 条金句") + return quotes + + def build_analysis_result( + self, + state: IncrementalState, + user_titles: list | None = None, + ) -> dict: + """ + 从增量状态构建完整的 analysis_result 字典。 + + 该字典格式与 AnalysisApplicationService.execute_daily_analysis() + 返回的 analysis_result 完全一致,可直接传入 ReportDispatcher。 + + Args: + state: 由 merge_batches 合并生成的增量分析状态 + user_titles: 用户称号列表(由最终报告时 LLM 分析生成) + + Returns: + dict: 包含 statistics、topics、user_titles、user_analysis 的结果字典 + """ + statistics = self.build_final_statistics(state) + topics = self.build_topics_for_report(state) + golden_quotes = self.build_quotes_for_report(state) + + # 将金句回填到 statistics 中(与传统流程一致) + statistics.golden_quotes = golden_quotes + + analysis_result = { + "statistics": statistics, + "topics": topics, + "user_titles": user_titles or [], + "user_analysis": state.user_activities, + "chat_quality_review": statistics.chat_quality_review, + } + + logger.info( + f"从增量状态构建完整分析结果: " + f"群={state.group_id}, 窗口={state.get_window_date_str()}, " + f"消息={state.total_message_count}, " + f"话题={len(topics)}, " + f"金句={len(golden_quotes)}, " + f"批次={state.total_analysis_count}" + ) + + return analysis_result + + def _build_emoji_statistics(self, state: IncrementalState) -> EmojiStatistics: + """ + 从增量状态构建表情统计。 + + 将 IncrementalState 中的 emoji_counts 字典映射到 EmojiStatistics 字段。 + + Args: + state: 增量分析状态 + + Returns: + EmojiStatistics: 表情统计实例 + """ + emoji_counts = state.emoji_counts + + # 显式提取并检查类型,辅助 Pylance 类型推断 + face_details = emoji_counts.get("face_details") + if not isinstance(face_details, dict): + face_details = {} + + return EmojiStatistics( + face_count=emoji_counts.get("face_count", 0), + mface_count=emoji_counts.get("mface_count", 0), + bface_count=emoji_counts.get("bface_count", 0), + sface_count=emoji_counts.get("sface_count", 0), + other_emoji_count=emoji_counts.get("other_emoji_count", 0), + face_details=face_details, + ) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/message_cleaner_service.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/message_cleaner_service.py new file mode 100644 index 0000000..156bac8 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/message_cleaner_service.py @@ -0,0 +1,103 @@ +""" +消息清理服务 - 领域层 +负责过滤掉机器人消息、指令、技术性内容(如原始表情代码)及敏感内容。 +""" + +import re +from dataclasses import replace + +from ..value_objects.unified_message import ( + MessageContent, + MessageContentType, + UnifiedMessage, +) + +# Discord 自定义表情正则 <:name:id> 或 +_DISCORD_CUSTOM_EMOJI_PATTERN = re.compile(r"") +# 指令匹配正则:匹配以 / 开头,或者以 @某人 / 开头的消息 +_COMMAND_PATTERN = re.compile(r"^\s*(?:<@\d+>\s+)?/") + + +class MessageCleanerService: + """消息清理服务""" + + def clean_messages( + self, + messages: list[UnifiedMessage], + bot_self_ids: list[str] = None, + filter_commands: bool = True, + ) -> list[UnifiedMessage]: + """ + 清理并过滤消息列表。 + + Args: + messages: 原始统一格式消息列表 + bot_self_ids: 机器人自身的 ID 列表 + filter_commands: 是否过滤指令消息 + + Returns: + 清理后的消息列表 + """ + bot_ids = set(bot_self_ids or []) + cleaned_list = [] + + for msg in messages: + # 1. 过滤机器人发送的消息 + if msg.sender_id in bot_ids: + continue + + # 2. 预检指令消息(首个内容块通常是文本) + is_command = False + first_text = msg.text_content + if filter_commands and first_text and _COMMAND_PATTERN.match(first_text): + is_command = True + + if is_command: + continue + + # 3. 清理消息内容中的技术性噪音 + cleaned_contents = [] + has_meaningful_content = False + + for content in msg.contents: + if content.type == MessageContentType.TEXT: + text = content.text or "" + + # 移除 Discord 原始表情代码 + text = _DISCORD_CUSTOM_EMOJI_PATTERN.sub("", text) + + # 移除 @mentions 文本 (e.g. <@123456>) + text = re.sub(r"<@\d+>", "", text) + + # 清理多余空格 + text = text.strip() + + if text: + cleaned_contents.append( + MessageContent(type=MessageContentType.TEXT, text=text) + ) + has_meaningful_content = True + else: + # 其他类型(图片、回复等)暂时保留,但由后续分析器决定是否使用 + cleaned_contents.append(content) + if content.type != MessageContentType.REPLY: + has_meaningful_content = True + + # 4. 如果清理后仍有内容,则保留消息 + if has_meaningful_content: + # 重新合成 text_content 用于 LLM 分析 + new_text_content = "".join( + [ + c.text + for c in cleaned_contents + if c.type == MessageContentType.TEXT + ] + ).strip() + + # 使用 replace 创建新实例(Frozen dataclass 必须如此) + new_msg = replace( + msg, contents=tuple(cleaned_contents), text_content=new_text_content + ) + cleaned_list.append(new_msg) + + return cleaned_list diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/statistics_service.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/statistics_service.py new file mode 100644 index 0000000..2377caf --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/services/statistics_service.py @@ -0,0 +1,130 @@ +""" +统计领域服务 - 领域层 +负责核心统计逻辑的计算,不依赖于具体的平台或基础设施。 +""" + +from collections import defaultdict +from datetime import datetime + +from ...infrastructure.visualization.activity_charts import ActivityVisualizer +from ..models.data_models import EmojiStatistics, GroupStatistics, TokenUsage +from ..repositories.visualization_repository import IActivityVisualizer +from ..value_objects.unified_message import MessageContentType, UnifiedMessage + + +class StatisticsService: + """统计服务 - 处理群聊数据的聚合统计""" + + def __init__(self, activity_visualizer: IActivityVisualizer | None = None): + if activity_visualizer is None: + # Fallback: keep backward compatibility + self.activity_visualizer: IActivityVisualizer = ActivityVisualizer() + else: + self.activity_visualizer = activity_visualizer + + def calculate_group_statistics( + self, messages: list[UnifiedMessage] + ) -> GroupStatistics: + """ + 计算群组基础统计数据。 + + 基于统一消息格式(UnifiedMessage)进行计算,确保跨平台一致性。 + """ + total_chars = 0 + participants = set() + hour_counts = defaultdict(int) + emoji_statistics = EmojiStatistics() + + for msg in messages: + participants.add(msg.sender_id) + + # 统计时间分布 + msg_time = datetime.fromtimestamp(msg.timestamp) + hour_counts[msg_time.hour] += 1 + + # 处理消息内容 + for content in msg.contents: + if content.type == MessageContentType.TEXT: + total_chars += len(content.text or "") + elif content.type == MessageContentType.EMOJI: + emoji_statistics.face_count += 1 + # 尝试保留原始表情详情(如果适配器提供了) + face_id = content.emoji_id or "unknown" + emoji_statistics.face_details[f"emoji_{face_id}"] = ( + emoji_statistics.face_details.get(f"emoji_{face_id}", 0) + 1 + ) + elif content.type == MessageContentType.IMAGE: + # 兼容识别“图片形态的表情”: + # 1) 优先使用 onebot sub_type=1 信号 + # 2) 若无该字段,再回退到历史 summary 文本匹配 + if self._is_emoji_like_image(content.raw_data): + emoji_statistics.mface_count += 1 + elif content.type in ( + MessageContentType.VOICE, + MessageContentType.VIDEO, + ): + # 其他非文本类型统计(可选) + pass + + # 找出最活跃时段 + most_active_hour = ( + max(hour_counts.items(), key=lambda x: x[1])[0] if hour_counts else 0 + ) + most_active_period = ( + f"{most_active_hour:02d}:00-{(most_active_hour + 1) % 24:02d}:00" + ) + + # 生成活跃度可视化数据 + # 注意:ActivityVisualizer 可能需要迁移以支持 UnifiedMessage + # 目前先转换回 dict 以保持兼容性,或者之后重构它 + raw_msgs = self._convert_to_legacy_dict(messages) + activity_visualization = ( + self.activity_visualizer.generate_activity_visualization(raw_msgs) + ) + + return GroupStatistics( + message_count=len(messages), + total_characters=total_chars, + participant_count=len(participants), + most_active_period=most_active_period, + golden_quotes=[], + emoji_count=emoji_statistics.total_emoji_count, + emoji_statistics=emoji_statistics, + activity_visualization=activity_visualization, + token_usage=TokenUsage(), + ) + + @staticmethod + def _is_emoji_like_image(raw_data: object) -> bool: + """判断 IMAGE 段是否应按表情计数。""" + if isinstance(raw_data, dict): + sub_type = raw_data.get("sub_type") + if sub_type is not None: + return str(sub_type) == "1" + summary = str(raw_data.get("summary", "")) + return "动画表情" in summary or "表情" in summary + + if raw_data is None: + return False + + text = str(raw_data) + return "动画表情" in text or "表情" in text + + def _convert_to_legacy_dict(self, messages: list[UnifiedMessage]) -> list[dict]: + """内部辅助:将 UnifiedMessage 转换为 Legacy Dict 格式,用于兼容可视化组件""" + legacy_list = [] + for msg in messages: + legacy_list.append( + { + "time": msg.timestamp, + "sender": { + "user_id": msg.sender_id, + "nickname": msg.sender_name, + "card": msg.sender_card or "", + }, + "message": [ + {"type": "text", "data": {"text": msg.text_content or ""}} + ], + } + ) + return legacy_list diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/value_objects/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/value_objects/__init__.py new file mode 100644 index 0000000..30ddc0b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/value_objects/__init__.py @@ -0,0 +1,15 @@ +# 值对象 +from .platform_capabilities import PLATFORM_CAPABILITIES, PlatformCapabilities +from .unified_group import UnifiedGroup, UnifiedMember +from .unified_message import MessageContent, MessageContentType, UnifiedMessage + +__all__ = [ + # 核心平台抽象 + "UnifiedMessage", + "MessageContent", + "MessageContentType", + "PlatformCapabilities", + "PLATFORM_CAPABILITIES", + "UnifiedGroup", + "UnifiedMember", +] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/value_objects/platform_capabilities.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/value_objects/platform_capabilities.py new file mode 100644 index 0000000..f543c4f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/value_objects/platform_capabilities.py @@ -0,0 +1,305 @@ +""" +平台能力值对象 - 运行时决策支持 + +每个平台适配器声明其能力, +应用层根据能力决定操作。 +""" + +from dataclasses import dataclass + + +@dataclass(frozen=True) +class PlatformCapabilities: + """ + 值对象:平台能力描述 + + 用于在运行时判断当前平台支持哪些具体操作,实现防御性编程和多平台兼容。 + + Attributes: + platform_name (str): 平台标识(如 discord, onebot) + platform_version (str): 版本号 + supports_message_history (bool): 是否支持拉取历史消息 + max_message_history_days (int): 最大历史穿透天数 + max_message_count (int): 单次拉取最大消息数 + supports_message_search (bool): 是否支持消息搜索(扩展用) + supports_group_list (bool): 是否支持列出所有群组 + supports_group_info (bool): 是否支持获取群元数据 + supports_member_list (bool): 是否支持获取成员列表 + supports_member_info (bool): 是否支持获取单成员详情 + supports_text_message (bool): 是否能发送文本 + supports_image_message (bool): 是否能发送图片 + supports_file_message (bool): 是否能发送文件/PDF + supports_forward_message (bool): 是否支持转发链(合并转发) + supports_reply_message (bool): 是否支持回复引用 + max_text_length (int): 单条回复最大文本长度 + max_image_size_mb (float): 最大图片上传限制 (MB) + supports_at_all (bool): 是否能 @全员 + supports_recall (bool): 是否支持撤回 + supports_edit (bool): 是否支持编辑已发消息 + supports_user_avatar (bool): 是否有用户头像 API + supports_group_avatar (bool): 是否有群头像 API + avatar_needs_api_call (bool): 获取头像是否需要额外异步请求 + avatar_sizes (tuple[int, ...]): 平台支持的头像尺寸像素值 + """ + + # 平台标识 + platform_name: str + platform_version: str = "unknown" + + # 消息获取能力 + supports_message_history: bool = False + max_message_history_days: int = 0 + max_message_count: int = 0 + supports_message_search: bool = False + + # 群组信息能力 + supports_group_list: bool = False + supports_group_info: bool = False + supports_member_list: bool = False + supports_member_info: bool = False + + # 消息发送能力 + supports_text_message: bool = True + supports_image_message: bool = False + supports_file_message: bool = False + supports_forward_message: bool = False + supports_reply_message: bool = False + max_text_length: int = 4096 + max_image_size_mb: float = 10.0 + + # 特殊能力 + supports_at_all: bool = False + supports_recall: bool = False + supports_edit: bool = False + + # 头像能力 + supports_user_avatar: bool = True + supports_group_avatar: bool = False + avatar_needs_api_call: bool = False + avatar_sizes: tuple[int, ...] = (100,) + + # 检查方法 + def can_analyze(self) -> bool: + """ + 判断是否具备进行群聊分析的核心能力。 + + Returns: + bool: 核心能力齐全则返回 True + """ + return ( + self.supports_message_history + and self.max_message_history_days > 0 + and self.max_message_count > 0 + ) + + def can_send_report(self, format: str = "image") -> bool: + """ + 判断是否能以指定格式发送报告。 + + Args: + format (str): 报告格式 ('text', 'image', 'pdf') + + Returns: + bool: 支持该格式则返回 True + """ + if format == "text": + return self.supports_text_message + elif format == "image": + return self.supports_image_message + elif format == "pdf": + return self.supports_file_message + return False + + def get_effective_days(self, requested_days: int) -> int: + """ + 获取实际生效的历史拉取天数。 + + Args: + requested_days (int): 请求的天数 + + Returns: + int: 平台受限后的实际天数 + """ + return min(requested_days, self.max_message_history_days) + + def get_effective_count(self, requested_count: int) -> int: + """ + 获取实际生效的历史消息拉取条数。 + + Args: + requested_count (int): 请求的消息条数 + + Returns: + int: 平台受限后的实际条数 + """ + return min(requested_count, self.max_message_count) + + +# 预定义的平台能力 +# OneBot v11 (如 NapCat, LLOneBot 等) +ONEBOT_V11_CAPABILITIES = PlatformCapabilities( + platform_name="onebot", + platform_version="v11", + supports_message_history=True, + max_message_history_days=7, + max_message_count=10000, + supports_group_list=True, + supports_group_info=True, + supports_member_list=True, + supports_member_info=True, + supports_text_message=True, + supports_image_message=True, + supports_file_message=True, + supports_forward_message=True, + supports_reply_message=True, + max_text_length=4500, + supports_at_all=True, + supports_recall=True, + supports_user_avatar=True, + supports_group_avatar=True, + avatar_needs_api_call=False, + avatar_sizes=(40, 100, 140, 160, 640), +) + +# Telegram Bot API +TELEGRAM_CAPABILITIES = PlatformCapabilities( + platform_name="telegram", + platform_version="bot_api_7.x", + # 通过 PlatformMessageHistoryManager + 消息拦截器支持历史读取 + supports_message_history=True, + max_message_history_days=7, + max_message_count=1000, + supports_group_list=False, + supports_group_info=True, + supports_member_list=True, + supports_member_info=True, + supports_text_message=True, + supports_image_message=True, + supports_file_message=True, + supports_reply_message=True, + max_text_length=4096, + max_image_size_mb=50.0, + supports_edit=True, + supports_user_avatar=True, + supports_group_avatar=True, + avatar_needs_api_call=True, + avatar_sizes=(160, 320, 640), +) + +# Discord API +DISCORD_CAPABILITIES = PlatformCapabilities( + platform_name="discord", + platform_version="api_v10", + supports_message_history=True, + max_message_history_days=30, + max_message_count=10000, + supports_group_list=True, + supports_group_info=True, + supports_member_list=True, + supports_text_message=True, + supports_image_message=True, + supports_file_message=True, + supports_reply_message=True, + max_text_length=2000, + max_image_size_mb=8.0, + supports_edit=True, + supports_user_avatar=True, + supports_group_avatar=True, + avatar_needs_api_call=False, + avatar_sizes=(16, 32, 64, 128, 256, 512, 1024, 2048, 4096), +) + +# Slack Web API +SLACK_CAPABILITIES = PlatformCapabilities( + platform_name="slack", + platform_version="web_api", + supports_message_history=True, + max_message_history_days=90, + max_message_count=1000, + supports_group_list=True, + supports_group_info=True, + supports_member_list=True, + supports_text_message=True, + supports_image_message=True, + supports_file_message=True, + supports_reply_message=True, + max_text_length=40000, + supports_edit=True, + supports_user_avatar=True, + supports_group_avatar=False, + avatar_needs_api_call=True, + avatar_sizes=(24, 32, 48, 72, 192, 512, 1024), +) + +# Feishu/Lark Open Platform API +LARK_CAPABILITIES = PlatformCapabilities( + platform_name="lark", + platform_version="open_api_v1", + supports_message_history=True, + max_message_history_days=7, + max_message_count=1000, + supports_group_list=False, + supports_group_info=True, + supports_member_list=True, + supports_member_info=True, + supports_text_message=True, + supports_image_message=True, + supports_file_message=True, + supports_reply_message=True, + max_text_length=30000, + max_image_size_mb=10.0, + supports_user_avatar=True, + supports_group_avatar=True, + avatar_needs_api_call=True, + avatar_sizes=(72, 240, 640), +) + +# QQ Official Bot API. Message history is provided by the plugin's local +# event archive because the public API does not expose group history queries. +QQ_OFFICIAL_CAPABILITIES = PlatformCapabilities( + platform_name="qq_official", + platform_version="api_v2_local_history", + supports_message_history=True, + max_message_history_days=7, + max_message_count=10000, + supports_group_list=False, + supports_group_info=False, + supports_member_list=False, + supports_member_info=False, + supports_text_message=True, + supports_image_message=True, + supports_file_message=True, + supports_forward_message=False, + supports_reply_message=False, + max_text_length=4000, + max_image_size_mb=20.0, + supports_user_avatar=True, + supports_group_avatar=False, + avatar_needs_api_call=False, + avatar_sizes=(640,), +) + +# 能力查找表(映射平台标识到能力对象) +PLATFORM_CAPABILITIES: dict[str, PlatformCapabilities] = { + "aiocqhttp": ONEBOT_V11_CAPABILITIES, + "onebot": ONEBOT_V11_CAPABILITIES, + "telegram": TELEGRAM_CAPABILITIES, + "discord": DISCORD_CAPABILITIES, + "slack": SLACK_CAPABILITIES, + "lark": LARK_CAPABILITIES, + "qq_official": QQ_OFFICIAL_CAPABILITIES, + "qq_official_webhook": QQ_OFFICIAL_CAPABILITIES, +} + + +def get_capabilities(platform_name: str) -> PlatformCapabilities | None: + """ + 根据平台名称查找其支持的能力。 + + Args: + platform_name (str): 平台名称 + + Returns: + Optional[PlatformCapabilities]: 对应的能力对象或 None + """ + return PLATFORM_CAPABILITIES.get(platform_name.lower()) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/value_objects/unified_group.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/value_objects/unified_group.py new file mode 100644 index 0000000..e44cb8b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/value_objects/unified_group.py @@ -0,0 +1,53 @@ +""" +统一群组值对象 - 跨平台群组抽象 +""" + +from dataclasses import dataclass + + +@dataclass(frozen=True) +class UnifiedMember: + """ + 值对象:统一成员信息 + + Attributes: + user_id (str): 用户唯一 ID + nickname (str): 用户昵称 + card (str, optional): 群名片 + role (str): 角色(owner/admin/member) + join_time (int, optional): 入群时间(秒级时间戳) + avatar_url (str, optional): 头像网络链接 + avatar_data (str, optional): 头像 Base64 数据 + """ + + user_id: str + nickname: str + card: str | None = None + role: str = "member" + join_time: int | None = None + avatar_url: str | None = None + avatar_data: str | None = None + + +@dataclass(frozen=True) +class UnifiedGroup: + """ + 值对象:统一群组信息 + + Attributes: + group_id (str): 群组唯一 ID + group_name (str): 群组名称 + member_count (int): 成员数量 + owner_id (str, optional): 群主 ID + create_time (int, optional): 创建时间 + description (str, optional): 群简介/公告 + platform (str): 来源平台 + """ + + group_id: str + group_name: str + member_count: int = 0 + owner_id: str | None = None + create_time: int | None = None + description: str | None = None + platform: str = "unknown" diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/value_objects/unified_message.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/value_objects/unified_message.py new file mode 100644 index 0000000..e3d93f7 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/domain/value_objects/unified_message.py @@ -0,0 +1,177 @@ +""" +统一消息值对象 - 跨平台核心抽象 + +所有平台消息都转换为此格式进行分析。 +""" + +from dataclasses import dataclass, field +from datetime import datetime +from enum import Enum +from typing import Any + + +class MessageContentType(Enum): + """ + 枚举:消息内容类型 + + 用于标识 MessageContent 的具体类型。 + """ + + TEXT = "text" + IMAGE = "image" + FILE = "file" + EMOJI = "emoji" + REPLY = "reply" + FORWARD = "forward" + AT = "at" + VOICE = "voice" + VIDEO = "video" + LOCATION = "location" + UNKNOWN = "unknown" + + +@dataclass(frozen=True) +class MessageContent: + """ + 值对象:消息内容段 + + 表示消息链中的一个组成部分(如文本、图片、表情等)。 + 该对象是不可变的,用于保证数据流的纯净。 + + Attributes: + type (MessageContentType): 内容类型 + text (str): 文本内容(仅当类型为 TEXT 或包含文本描述时) + url (str): 资源链接(图片、视频、文件等) + emoji_id (str): 表情 ID + emoji_name (str): 表情名称 + at_user_id (str): 被 @ 的用户 ID + raw_data (Any): 平台原始数据,用于扩展 + """ + + type: MessageContentType + text: str = "" + url: str = "" + emoji_id: str = "" + emoji_name: str = "" + at_user_id: str = "" + raw_data: Any = None + + def is_text(self) -> bool: + """检查是否为文本内容。""" + return self.type == MessageContentType.TEXT + + def is_emoji(self) -> bool: + """检查是否为表情内容。""" + return self.type == MessageContentType.EMOJI + + @property + def target_id(self) -> str: + """ + 获取被 @ 的用户 ID(兼容旧代码)。 + + Alias for at_user_id. + """ + return self.at_user_id + + +@dataclass(frozen=True) +class UnifiedMessage: + """ + 核心值对象:统一消息格式 + + 跨平台抽象层,将不同平台的原始消息转换为统一格式进行分析。 + 采用“只读”设计,确保分析逻辑的一致性。 + + Attributes: + message_id (str): 消息唯一标识符 + sender_id (str): 发送者唯一 ID + sender_name (str): 发送者昵称 + group_id (str): 群组/会话唯一 ID + text_content (str): 经过清洗后的纯文本内容,主要用于 LLM 分析 + contents (tuple[MessageContent, ...]): 结构化消息链 + timestamp (int): Unix 时间戳(秒) + platform (str): 来源平台名称(如 onebot, discord 等) + reply_to_id (str, optional): 被回复的消息 ID + sender_card (str, optional): 平台特定的群名片或特别备注 + """ + + # 基础标识 + message_id: str + sender_id: str + sender_name: str + group_id: str + + # 消息内容 + text_content: str + contents: tuple[MessageContent, ...] = field(default_factory=tuple) + + # 时间信息 + timestamp: int = 0 + + # 平台信息 + platform: str = "unknown" + + # 可选信息 + reply_to_id: str | None = None + sender_card: str | None = None + + # 分析辅助方法 + def has_text(self) -> bool: + """ + 判断消息是否包含非空文本。 + + Returns: + bool: 包含有效文本则返回 True + """ + return bool(self.text_content.strip()) + + def get_display_name(self) -> str: + """ + 获取用户显示名称。 + 优先级:群名片 > 昵称 > 用户 ID。 + + Returns: + str: 格式化后的显示名称 + """ + return self.sender_card or self.sender_name or self.sender_id + + def get_emoji_count(self) -> int: + """ + 计算消息链中包含的表情数量。 + + Returns: + int: 表情总数 + """ + return sum(1 for c in self.contents if c.is_emoji()) + + def get_text_length(self) -> int: + """ + 获取文本内容的字符长度。 + + Returns: + int: 字符数 + """ + return len(self.text_content) + + def get_datetime(self) -> datetime: + """ + 将 Unix 时间戳转换为 datetime 对象。 + + Returns: + datetime: 本地化后的时间对象 + """ + return datetime.fromtimestamp(self.timestamp) + + def to_analysis_format(self) -> str: + """ + 转换为供 LLM 消费的分析格式。 + + Returns: + str: 格式如 "[用户名]: 消息内容" 的字符串 + """ + name = self.get_display_name() + return f"[{name}]: {self.text_content}" + + +# 类型别名 +MessageList = list[UnifiedMessage] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/__init__.py new file mode 100644 index 0000000..2af8900 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/__init__.py @@ -0,0 +1 @@ +# 基础设施层 diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/__init__.py new file mode 100644 index 0000000..1142ee2 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/__init__.py @@ -0,0 +1,8 @@ +""" +分析模块 +包含LLM分析功能 +""" + +from .llm_analyzer import LLMAnalyzer + +__all__ = ["LLMAnalyzer"] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/__init__.py new file mode 100644 index 0000000..d64cf46 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/__init__.py @@ -0,0 +1,11 @@ +""" +分析器模块 +包含各种LLM分析功能的实现 +""" + +from .base_analyzer import BaseAnalyzer +from .golden_quote_analyzer import GoldenQuoteAnalyzer +from .topic_analyzer import TopicAnalyzer +from .user_title_analyzer import UserTitleAnalyzer + +__all__ = ["BaseAnalyzer", "TopicAnalyzer", "UserTitleAnalyzer", "GoldenQuoteAnalyzer"] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/base_analyzer.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/base_analyzer.py new file mode 100644 index 0000000..227ad5b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/base_analyzer.py @@ -0,0 +1,659 @@ +""" +基础分析器抽象类 +定义通用分析流程和接口 +""" + +from abc import ABC, abstractmethod +from collections.abc import Sized +from typing import Generic, TypeVar + +from ....domain.models.data_models import TokenUsage +from ....shared.constants import PLUGIN_NAME +from ....utils.logger import logger +from ..utils.json_utils import parse_json_response +from ..utils.llm_utils import ( + call_provider_with_retry, + extract_response_text, + extract_token_usage, + get_provider_id_with_fallback, +) +from ..utils.structured_output_schema import JSONObject, build_response_format + +TDataObject = TypeVar("TDataObject") +TInputData = TypeVar("TInputData") + + +class BaseAnalyzer(ABC, Generic[TDataObject, TInputData]): + """ + 基础分析器抽象类 + 定义所有分析器的通用接口 and 流程 + """ + + def __init__(self, context, config_manager): + """ + 初始化基础分析器 + + Args: + context: AstrBot上下文对象 + config_manager: 配置管理器 + """ + self.context = context + self.config_manager = config_manager + # 增量分析模式下的最大数量覆盖值,为 None 时使用配置默认值 + self._incremental_max_count: int | None = None + + def get_provider_id_key(self) -> str | None: + """ + 获取 Provider ID 配置键名 + 子类可重写以指定特定的 provider,默认返回 None(使用主 LLM Provider) + + Returns: + Provider ID 配置键名,如 'topic_provider_id' + """ + return None + + @abstractmethod + def get_data_type(self) -> str: + """ + 获取数据类型标识 + + Returns: + 数据类型字符串 + """ + pass + + @abstractmethod + def get_max_count(self) -> int: + """ + 获取最大提取数量 + + Returns: + 最大数量 + """ + pass + + @abstractmethod + def build_prompt(self, data: TInputData) -> str: + """ + 构建LLM提示词 + + Args: + data: 输入数据 + + Returns: + 提示词字符串 + """ + pass + + def build_prompt_with_override( + self, data: TInputData, prompt_override: str | None + ) -> str: + """构建提示词,默认忽略调用方覆盖模板。 + + Args: + data: 分析器输入数据。 + prompt_override: 调用方指定的提示词模板。 + + Returns: + 可提交给 LLM 的提示词。 + """ + del prompt_override + return self.build_prompt(data) + + @abstractmethod + def extract_with_regex(self, result_text: str, max_count: int) -> list[dict]: + """ + 使用正则表达式提取数据 + + Args: + result_text: LLM响应文本 + max_count: 最大提取数量 + + Returns: + 提取到的数据列表 + """ + pass + + @abstractmethod + def create_data_objects(self, data_list: list[dict]) -> list[TDataObject]: + """ + 创建数据对象列表 + + Args: + data_list: 原始数据列表 + + Returns: + 数据对象列表 + """ + pass + + def get_response_schema_name(self) -> str: + return f"{self.get_data_type()}_output" + + def get_response_schema(self) -> JSONObject | None: + return None + + def get_response_format(self) -> JSONObject | None: + schema = self.get_response_schema() + if not schema: + return None + return build_response_format(self.get_response_schema_name(), schema) + + def get_schema_retry_max_attempts(self) -> int: + """ + schema 解析失败后的最大重试次数(不含首轮请求)。 + """ + return 2 + + def get_schema_retry_temperatures( + self, base_temperature: float | None + ) -> tuple[float, ...]: + """ + schema 解析失败后的温度重试序列(不含首轮请求)。 + 采用动态降温,提高结构化稳定性。 + """ + attempts = max(0, self.get_schema_retry_max_attempts()) + if attempts == 0: + return () + + base = base_temperature if base_temperature is not None else 0.7 + first_retry = max(0.1, min(2.0, base * 0.5)) + + temperatures: list[float] = [round(first_retry, 2), 0.0] + if attempts < len(temperatures): + temperatures = temperatures[:attempts] + + deduped: list[float] = [] + for temp in temperatures: + if not deduped or deduped[-1] != temp: + deduped.append(temp) + return tuple(deduped) + + async def _resolve_provider_temperature( + self, + provider_id_key: str | None, + umo: str | None, + provider_id: str | None = None, + ) -> float | None: + """ + 尝试从当前将要调用的 Provider 配置中解析基础 temperature。 + """ + # NoneBot 版:temperature 从插件配置读取;未配置则返回 None(交给请求方默认值)。 + try: + return self.config_manager.get_llm_temperature() + except Exception: + return None + + def parse_structured_response( + self, result_text: str + ) -> tuple[bool, list[dict] | None, str | None]: + """ + 解析结构化响应(默认 JSON 数组解析)。 + 子类可重写此方法定制对象解析逻辑。 + """ + return parse_json_response(result_text, self.get_data_type()) + + def build_schema_retry_prompt( + self, + original_prompt: str, + previous_output: str, + parse_error: str | None, + attempt_index: int, + ) -> str: + """ + 构建结构化失败后的修复重试提示词。 + """ + err_text = parse_error or "unknown_parse_error" + return ( + f"{original_prompt}\n\n" + "[STRUCTURED OUTPUT RETRY]\n" + f"Attempt: {attempt_index}\n" + "Your previous output did not satisfy the required strict JSON schema.\n" + "Return ONLY valid JSON that strictly matches the schema. " + "Do not include markdown, explanation, or extra text.\n" + f"Parse error: {err_text}\n" + "Previous invalid output:\n" + f"{previous_output}" + ) + + def _try_parse_with_fallback( + self, result_text: str + ) -> tuple[bool, list[dict] | None, str | None]: + """ + 先尝试结构化 JSON 解析(含修复逻辑),失败后立即尝试正则降级。 + """ + success, parsed_data, error_msg = self.parse_structured_response(result_text) + if success and parsed_data: + validated_success, validated_data, validated_error = ( + self.validate_parsed_data(parsed_data) + ) + if validated_success and validated_data: + return True, validated_data, None + error_msg = validated_error or error_msg + + regex_data = self.extract_with_regex(result_text, self.get_max_count()) + if regex_data: + validated_success, validated_data, validated_error = ( + self.validate_parsed_data(regex_data) + ) + if validated_success and validated_data: + logger.info( + f"{self.get_data_type()}结构化解析失败后,正则降级提取成功,获得 {len(validated_data)} 条数据" + ) + return True, validated_data, None + error_msg = validated_error or error_msg + + return False, None, error_msg + + def validate_parsed_data( + self, data_list: list[dict] + ) -> tuple[bool, list[dict] | None, str | None]: + """ + 解析结果的本地二次校验(默认直接通过)。 + 子类可重写为 Pydantic 校验。 + """ + return True, data_list, None + + def _save_debug_data(self, prompt: str, session_id: str): + """ + 保存调试数据到文件 + + Args: + prompt: 提示词内容 + session_id: 会话ID + """ + try: + from ....utils.paths import get_data_dir + + data_path = get_data_dir(PLUGIN_NAME) / "debug_data" + + data_path.mkdir(parents=True, exist_ok=True) + + file_name = f"{session_id}_{self.get_data_type()}.txt" + file_path = data_path / file_name + + logger.info(f"正在保存调试数据到: {file_path}") + with open(file_path, "w", encoding="utf-8") as f: + f.write(prompt) + + logger.info(f"已保存 {self.get_data_type()} 分析 Prompt 到 {file_path}") + + except Exception as e: + logger.error(f"保存调试数据失败: {e}", exc_info=True) + + def _apply_persona_reinforcement( + self, prompt: str, system_prompt: str | None + ) -> str: + """ + 核心的人格强化注入逻辑。采用首尾深度注入与指令交织策略。 + 不仅强化输出口吻,更强调使用人格的逻辑视角进行分析过程。 + """ + if not system_prompt or not system_prompt.strip(): + return prompt + + logger.info(f"[{self.get_data_type()}分析] 已启用人格设定(深度强化模式)") + + # 构造更具强制性的标识符 + persona_content = system_prompt.strip() + + return ( + "【SYSTEM_CORE_IDENTITY_FIXED】\n" + f"你现在的身份已由系统初始化为:\n{persona_content}\n\n" + "--- MISSION_DIRECTIVE_START ---\n" + "⚠️ 核心任务警告:你接下来的所有分析行为必须基于上述【身份设定】进行。\n" + "这包括但不限于:你的思维切入点、对数据的敏感度、点评的犀利/温情程度、以及你对群聊氛围的感知逻辑。\n" + f"请以该人格的思维方式去处理以下‘{self.get_data_type()}’分析任务:\n\n" + f"{prompt}\n" + "--- MISSION_DIRECTIVE_END ---\n\n" + "【FINAL_IDENTITY_REINFORCEMENT】\n" + f"1. 你不再是通用的 AI 助手,你是上述设定中的角色,我将在此处再次提醒你的身份:\n{persona_content}\n 正在观察并点评这些群聊数据。\n" + f"2. 请务必使用该角色的第一人称视角 or 其独有的观察视角进行‘{self.get_data_type()}’输出。\n" + "3. 你的分析成果必须体现该角色的性格色彩,禁止输出中立、客套、公式化的 AI 话术。\n" + "4. ⚠️ 格式铁律:无论人格多么狂放,最终输出的内容必须严格遵守‘ MISSION_DIRECTIVE ’中所要求的纯 JSON 格式。除了 JSON 数据外,严禁输出任何 Markdown 标记或角色扮演的额外闲聊。" + ) + + async def analyze( + self, + data: TInputData, + umo: str | None = None, + session_id: str | None = None, + persona_id: str | None = None, + prompt_override: str | None = None, + ) -> tuple[list[TDataObject], TokenUsage]: + """ + 统一的分析流程 + + Args: + data: 输入数据 + umo: 模型唯一标识符 + session_id: 会话ID (用于调试模式) + persona_id: 显式指定的人格 ID,传入时优先于常规人格选择逻辑 + prompt_override: 调用方指定的提示词模板,供支持专属模板的分析器使用 + + Returns: + (分析结果列表, Token使用统计) + """ + try: + # 1. 构建提示词 + logger.debug( + f"{self.get_data_type()}分析开始构建prompt,输入数据类型: {type(data)}" + ) + data_length = len(data) if isinstance(data, Sized) else "N/A" + logger.debug(f"{self.get_data_type()}分析输入数据长度: {data_length}") + + prompt = self.build_prompt_with_override(data, prompt_override) + logger.info(f"开始{self.get_data_type()}分析,构建提示词完成") + logger.debug( + f"{self.get_data_type()}分析prompt长度: {len(prompt) if prompt else 0}" + ) + logger.debug( + f"{self.get_data_type()}分析prompt前100字符: {prompt[:100] if prompt else 'None'}..." + ) + + # 保存调试数据 + debug_mode = self.config_manager.get_debug_mode() + if debug_mode and session_id and prompt: + self._save_debug_data(prompt, session_id) + elif debug_mode and not session_id: + logger.warning("[Debug] Debug mode enabled but no session_id provided") + + # 检查 prompt 是否为空 + if not prompt or not prompt.strip(): + logger.warning( + f"{self.get_data_type()}分析: prompt 为空或只包含空白字符,跳过LLM调用" + ) + return [], TokenUsage() + + # 2. 调用LLM(使用配置的 provider) + provider_id_key = self.get_provider_id_key() + + # 只 resolve 一次 provider ID,同时传递给温度解析和 LLM 调用,避免重复日志 + resolved_provider_id = None + if provider_id_key: + resolved_provider_id = await get_provider_id_with_fallback( + self.context, self.config_manager, provider_id_key, umo + ) + + base_temperature = await self._resolve_provider_temperature( + provider_id_key, umo, provider_id=resolved_provider_id + ) + + # 获取人格设定 + system_prompt = await self._build_system_prompt(umo, persona_id) + + # 应用人格强化注入 + prompt = self._apply_persona_reinforcement(prompt, system_prompt) + + logger.info(f"[{self.get_data_type()}分析] 开始发起 LLM 请求, umo: {umo}") + + # [Debug] 记录调试信息 + if debug_mode: + logger.debug( + f"[Debug] debug_mode={debug_mode}, umo={umo}, session_id={session_id}, prompt_len={len(prompt) if prompt else 0}" + ) + + from ....shared.trace_context import TraceContext + + trace = TraceContext.current() + if trace: + prompts_map = trace.metadata.setdefault("llm_prompts", {}) + prompts_map[self.get_data_type()] = { + "prompt": prompt, + "system_prompt": system_prompt, + "provider_id": resolved_provider_id or "default", + } + + response = await call_provider_with_retry( + self.context, + self.config_manager, + prompt=prompt, + umo=umo, + provider_id_key=provider_id_key, + provider_id=resolved_provider_id, + system_prompt=system_prompt, + response_format=self.get_response_format(), + observation_label=self.get_data_type(), + ) + + if response is None: + err_text = f"{self.get_data_type()}分析调用LLM失败: Provider 返回空响应或重试耗尽" + logger.error(err_text) + raise RuntimeError(err_text) + + # 3. 提取token使用统计 + token_usage_dict = extract_token_usage(response) + token_usage = TokenUsage( + prompt_tokens=token_usage_dict["prompt_tokens"], + completion_tokens=token_usage_dict["completion_tokens"], + total_tokens=token_usage_dict["total_tokens"], + ) + + # 4. 提取响应文本 + result_text = extract_response_text(response) + logger.debug(f"{self.get_data_type()}分析原始响应: {result_text[:500]}...") + + slot: dict | None = None + if trace: + prompts_map = trace.metadata.setdefault("llm_prompts", {}) + if isinstance(prompts_map, dict): + slot = prompts_map.setdefault(self.get_data_type(), {}) + if isinstance(slot, dict): + slot["prompt"] = prompt + slot["initial_prompt"] = prompt + slot["system_prompt"] = system_prompt + slot["tokens"] = token_usage_dict["total_tokens"] + slot["prompt_tokens"] = token_usage_dict["prompt_tokens"] + slot["completion_tokens"] = token_usage_dict[ + "completion_tokens" + ] + slot["completion"] = result_text + slot["initial_completion"] = result_text + + # 5. 尝试结构化解析 + 正则降级解析 + success, parsed_data, error_msg = self._try_parse_with_fallback(result_text) + + # 5.1 仅在两种解析方式都失败时,进入 schema 修复重试(温度递减) + if not success and self.get_response_format() is not None: + temperatures = self.get_schema_retry_temperatures(base_temperature) + for idx, temperature in enumerate(temperatures, start=1): + retry_prompt = self.build_schema_retry_prompt( + original_prompt=prompt, + previous_output=result_text, + parse_error=error_msg, + attempt_index=idx, + ) + logger.warning( + f"{self.get_data_type()}结构化解析失败,触发 schema 修复重试 " + f"(attempt={idx}, temperature={temperature:.1f})" + ) + retry_response = await call_provider_with_retry( + self.context, + self.config_manager, + prompt=retry_prompt, + umo=umo, + provider_id_key=provider_id_key, + system_prompt=system_prompt, + response_format=self.get_response_format(), + extra_generate_kwargs={"temperature": temperature}, + observation_label=f"{self.get_data_type()}#schema_retry_{idx}", + ) + if retry_response is None: + continue + + retry_result_text = extract_response_text(retry_response) + if not retry_result_text: + continue + + result_text = retry_result_text + retry_success, retry_parsed_data, retry_error_msg = ( + self._try_parse_with_fallback(retry_result_text) + ) + if retry_success: + success = True + parsed_data = retry_parsed_data + error_msg = None + if trace and isinstance(slot, dict): + slot["completion"] = retry_result_text + slot["corrected_completion"] = retry_result_text + slot["prompt"] = retry_prompt + slot["corrected_prompt"] = retry_prompt + slot["retry_count"] = idx + retry_token_dict = extract_token_usage(retry_response) + slot["tokens"] = ( + slot.get("tokens", 0) or 0 + ) + retry_token_dict["total_tokens"] + slot["completion_tokens"] = retry_token_dict[ + "completion_tokens" + ] + break + error_msg = retry_error_msg + + if success and parsed_data: + # JSON解析成功,创建数据对象 + data_objects = self.create_data_objects(parsed_data) + logger.info( + f"{self.get_data_type()}分析成功,解析到 {len(data_objects)} 条数据" + ) + return data_objects, token_usage + + # 6. 全部尝试失败 + err_text = f"{self.get_data_type()}分析失败: JSON解析与正则降级均未成功 ({error_msg or '未产出有效内容'})" + logger.error(err_text) + raise RuntimeError(err_text) + + except Exception as e: + logger.error(f"{self.get_data_type()}分析失败: {e}", exc_info=True) + raise + + async def _build_system_prompt( + self, umo: str | None, persona_id: str | None = None + ) -> str | None: + """ + 构建带有会话人格的系统提示词,优先级如下: + 1. 调用方显式指定的人格 + 2. 插件指定的全局人格 (若核心开关开启) + 3. 会话/对话选定的人格 (若开启了继承开关) + 4. 当前 UMO 的默认人格 (若开启了继承开关) + + Args: + umo: 用户模型对象标识,用于定位会话上下文 + persona_id: 调用方显式指定的人格 ID + + Returns: + 最终生成的 System Prompt 字符串,若无则返回 None + """ + # 获取配置 + use_specific = self.config_manager.get_use_plugin_specific_persona() + specific_id = self.config_manager.get_plugin_specific_persona_id() + keep_original = self.config_manager.get_keep_original_persona() + + # 获取 AstrBot 核心的人格管理器 + persona_mgr = getattr(self.context, "persona_manager", None) + if persona_mgr is None: + return None + + persona_prompt = None + + # 漫画角色等局部调用可显式指定人格,不修改插件全局人格配置。 + if persona_id: + try: + persona_obj = await persona_mgr.get_persona(persona_id) + persona_prompt = ( + persona_obj.system_prompt + if hasattr(persona_obj, "system_prompt") + else None + ) + if persona_prompt: + logger.debug(f"已应用调用方指定人格: {persona_id}") + except Exception as e: + logger.warning(f"获取调用方指定人格失败 (ID: {persona_id}): {e}") + + # --- 优先级 1: 插件指定的全局固定人格 --- + # 适用于希望所有分析报告都呈现同一种风格的情况 + if not persona_prompt and use_specific and specific_id: + try: + persona_obj = await persona_mgr.get_persona(specific_id) + persona_prompt = ( + persona_obj.system_prompt + if hasattr(persona_obj, "system_prompt") + else None + ) + if persona_prompt: + logger.debug(f"已应用插件指定的全局强制人格设定: {specific_id}") + except Exception as e: + logger.warning(f"获取插件指定人格失败 (ID: {specific_id}): {e}") + + # --- 优先级 2: 继承当前会话/群聊的原始人格 --- + # 只有在未开启“强制人格”且开启了“继承设定”时生效 + if not persona_prompt and keep_original and umo: + try: + # 2.1 尝试获取 SharedPreferences 中会话绑定的 Persona ID (通常是 /persona 命令设置的) + from astrbot.api import sp + + session_service_config = await sp.get_async( + scope="umo", + scope_id=str(umo), + key="session_service_config", + default={}, + ) + persona_id = ( + session_service_config.get("persona_id") + if session_service_config + else None + ) + + if persona_id and persona_id != "[%None]": + persona_obj = await persona_mgr.get_persona(persona_id) + persona_prompt = ( + persona_obj.system_prompt + if hasattr(persona_obj, "system_prompt") + else None + ) + if persona_prompt: + logger.debug(f"继承到会话选定人格: {persona_id}") + + # 2.2 若无会话绑定,尝试获取当前对话(Dialogue)级别的人格 + if not persona_prompt: + conv_mgr = getattr(self.context, "conversation_manager", None) + if conv_mgr: + curr_conv_id = await conv_mgr.get_curr_conversation_id(umo) + if curr_conv_id: + conv_obj = await conv_mgr.get_conversation( + umo, curr_conv_id + ) + if ( + conv_obj + and conv_obj.persona_id + and conv_obj.persona_id != "[%None]" + ): + persona_obj = await persona_mgr.get_persona( + conv_obj.persona_id + ) + persona_prompt = ( + persona_obj.system_prompt + if hasattr(persona_obj, "system_prompt") + else None + ) + if persona_prompt: + logger.debug( + f"继承到对话(Dialogue)设定人格: {conv_obj.persona_id}" + ) + + # 2.3 若仍无结果,尝试获取 UMO 设定的默认人格 + if not persona_prompt: + personality = await persona_mgr.get_default_persona_v3(umo) + if isinstance(personality, dict): + persona_prompt = personality.get("prompt") + else: + persona_prompt = getattr(personality, "prompt", None) + if persona_prompt: + logger.debug("继承到 UMO 默认人格设定") + + except Exception as e: + logger.warning(f"分析人格回溯识别失败 (umo: {umo}): {e}") + + # 检查生成结果 + if not isinstance(persona_prompt, str) or not persona_prompt.strip(): + return None + + return persona_prompt.strip() diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/chat_quality_analyzer.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/chat_quality_analyzer.py new file mode 100644 index 0000000..f3645c4 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/chat_quality_analyzer.py @@ -0,0 +1,614 @@ +""" +聊天质量分析模块 +专门处理群聊质量锐评分析 +""" + +from datetime import datetime + +from ....domain.models.data_models import QualityDimension, QualityReview, TokenUsage +from ....shared.trace_context import TraceContext +from ....utils.logger import logger +from ...utils.template_utils import render_template +from ..utils import InfoUtils +from ..utils.json_utils import extract_quality_with_regex, parse_json_object_response +from ..utils.llm_utils import ( + call_provider_with_retry, + extract_response_text, + extract_token_usage, + get_provider_id_with_fallback, +) +from ..utils.response_validation import validate_quality_review_item +from ..utils.structured_output_schema import JSONObject, build_chat_quality_schema +from .base_analyzer import BaseAnalyzer + + +class ChatQualityAnalyzer(BaseAnalyzer[QualityReview, list[dict]]): + """ + 聊天质量分析器 + 专门处理群聊质量的锐评和多维度分析 + + 注意:由于聊天质量分析返回的是 JSON 对象而非数组, + 此分析器重写了 analyze() 方法,使用 parse_json_object_response 解析, + 并以 extract_quality_with_regex 作为正则降级方案。 + """ + + def get_provider_id_key(self) -> str: + """获取 Provider ID 配置键名""" + return "quality_provider_id" + + def get_data_type(self) -> str: + """获取数据类型标识""" + return "聊天质量" + + def get_max_count(self) -> int: + """获取最大维度数量""" + return 8 + + def get_response_schema_name(self) -> str: + return "daily_chat_quality_review" + + def get_response_schema(self) -> JSONObject: + return build_chat_quality_schema(self.get_max_count()) + + def build_prompt(self, data: list[dict]) -> str: + """ + 构建聊天质量分析提示词 + """ + if not data: + return "" + + # 提取文本消息 + text_messages = [] + for msg in data: + if not isinstance(msg, dict): + continue + + sender = msg.get("sender", {}) + user_id = str(sender.get("user_id", "")) + bot_self_ids = self.config_manager.get_bot_self_ids() + if bot_self_ids and user_id in [str(uid) for uid in bot_self_ids]: + continue + + nickname = InfoUtils.get_user_nickname(self.config_manager, sender) + msg_time = datetime.fromtimestamp(msg.get("time", 0)).strftime("%H:%M") + message_list = msg.get("message", []) + + text_parts = [] + for content in message_list: + if content.get("type") == "text": + text = content.get("data", {}).get("text", "").strip() + if text: + text_parts.append(text) + + combined_text = "".join(text_parts).strip() + if combined_text and not combined_text.startswith("/"): + text_messages.append(f"[{msg_time}] [{nickname}]: {combined_text}") + + messages_text = "\n".join(text_messages[:1000]) + + prompt_template = self.config_manager.get_quality_analysis_prompt() + + if prompt_template: + return render_template(prompt_template, messages_text=messages_text) + + prompt_template = """请分析以下群聊记录,输出一份"聊天质量锐评"。 + +## 任务目标: +1. **维度划分**:将聊天内容划分为 3-6 个【高层级、抽象、泛化】的维度(例如:就业焦虑、生涯规划、技术方案研究、情感树洞、无意义水群等)。 +2. **严禁在维度名称(name)中出现任何具体的群聊人物名、项目名、具体的报错内容或细碎的事件点。标题必须保持高度抽象且字数简练(2-6个字)。** +3. 为每个维度计算一个大致的百分比占位(总和小于等于 100%)。 +4. **点评内容**:为每个维度写一句犀利、幽默、毒舌或温情的点评。具体的吐槽内容、具体的细节事件描述请放在这里。 +5. **全群表现**:给出一句总结性的评价,作为总结标题对应的“金句”。 +6. **主题设定**:设定一个本次报告的主题标题和副标题。 + +## 点评风格指南: +- 语言要接地气,多用互联网黑话。吐槽要精准,避重就轻。 +- **只有维度名称(name)需要抽象,点评(comment)和总结(summary)可以非常具体和生动。** + +## 返回格式要求: +必须以纯 JSON 格式返回,不得包含任何 Markdown 格式。 + +```json +{{ + "title": "今日群聊主题", + "subtitle": "副标题", + "dimensions": [ + {{ + "name": "抽象维度名", + "percentage": 比例, + "comment": "维度的毒舌点评" + }} + ], + "summary": "一句总结性的金句" +}} +``` + +群聊记录: +${messages_text} +""" + + return render_template(prompt_template, messages_text=messages_text) + + def extract_with_regex(self, result_text: str, max_count: int) -> list[dict]: + """ + 使用正则表达式提取质量分析数据(BaseAnalyzer 要求的接口) + + 注意: 此方法供 BaseAnalyzer.analyze() 的降级流程使用, + 但由于聊天质量分析重写了 analyze(),实际由 analyze_quality() 中调用 + extract_quality_with_regex 实现。 + """ + return [] + + def create_data_objects(self, data_list: list[dict]) -> list[QualityReview]: + """ + 满足 BaseAnalyzer 抽象要求。 + 聊天质量分析的数据对象创建在 analyze_quality 中完成。 + """ + return [] + + def _build_review_from_dict(self, data: dict) -> QualityReview: + """ + 从解析后的字典构建 QualityReview 对象 + + Args: + data: 解析后的 JSON 对象字典 + + Returns: + QualityReview 数据对象 + """ + # 控制维度占比总和不超过100% + total_percentage = sum( + max(0.0, min(100.0, float(d.get("percentage", 0)))) + for d in data.get("dimensions", []) + ) + + factor = 1.0 + if total_percentage > 100: + factor = 100.0 / total_percentage + + dimensions = [] + for d in data.get("dimensions", []): + raw_p = float(d.get("percentage", 0)) + + final_p = round(max(0.0, min(100.0, raw_p)) * factor, 1) + + dimensions.append( + QualityDimension( + name=d.get("name", "未知"), + percentage=final_p, + comment=d.get("comment", ""), + ) + ) + + # 自动分配颜色 + colors = [ + "#607d8b", + "#2196f3", + "#f44336", + "#e91e63", + "#ff9800", + "#4caf50", + "#009688", + "#9c27b0", + ] + for i, d in enumerate(dimensions): + d.color = colors[i % len(colors)] + + return QualityReview( + title=data.get("title", "聊天质量锐评"), + subtitle=data.get("subtitle", "今天的群里发生了什么?"), + dimensions=dimensions, + summary=data.get("summary", "今天也是充满活力的一天。"), + ) + + def _validate_review_payload( + self, data: dict + ) -> tuple[bool, dict | None, str | None]: + return validate_quality_review_item(data) + + async def _retry_parse_quality_object( + self, + *, + original_prompt: str, + previous_output: str, + parse_error: str | None, + umo: str | None, + system_prompt: str | None, + base_temperature: float | None, + ) -> dict | None: + response_format = self.get_response_format() + if response_format is None: + return None + + for idx, temperature in enumerate( + self.get_schema_retry_temperatures(base_temperature), start=1 + ): + retry_prompt = self.build_schema_retry_prompt( + original_prompt=original_prompt, + previous_output=previous_output, + parse_error=parse_error, + attempt_index=idx, + ) + logger.warning( + f"聊天质量结构化解析失败,触发 schema 修复重试 " + f"(attempt={idx}, temperature={temperature:.1f})" + ) + retry_response = await call_provider_with_retry( + self.context, + self.config_manager, + prompt=retry_prompt, + umo=umo, + provider_id_key=self.get_provider_id_key(), + system_prompt=system_prompt, + response_format=response_format, + extra_generate_kwargs={"temperature": temperature}, + observation_label=f"{self.get_data_type()}#schema_retry_{idx}", + ) + if retry_response is None: + continue + + retry_text = extract_response_text(retry_response) + if not retry_text: + continue + + from ....shared.trace_context import TraceContext + + trace = TraceContext.current() + + retry_success, retry_parsed_data, _ = parse_json_object_response( + retry_text, self.get_data_type() + ) + if retry_success and retry_parsed_data: + valid, normalized, _ = self._validate_review_payload(retry_parsed_data) + if valid and normalized: + if trace: + slot = trace.metadata.get("llm_prompts", {}).get( + self.get_data_type() + ) + if isinstance(slot, dict): + slot["completion"] = retry_text + slot["corrected_completion"] = retry_text + slot["prompt"] = retry_prompt + slot["corrected_prompt"] = retry_prompt + slot["retry_count"] = idx + return normalized + + retry_regex_data = extract_quality_with_regex(retry_text) + if retry_regex_data: + valid, normalized, _ = self._validate_review_payload(retry_regex_data) + if valid and normalized: + if trace: + slot = trace.metadata.get("llm_prompts", {}).get( + self.get_data_type() + ) + if isinstance(slot, dict): + slot["completion"] = retry_text + slot["corrected_completion"] = retry_text + slot["prompt"] = retry_prompt + slot["corrected_prompt"] = retry_prompt + slot["retry_count"] = idx + return normalized + + return None + + async def summarize_batch_reviews( + self, + batch_reviews: list[dict], + umo: str | None = None, + session_id: str | None = None, + ) -> tuple[QualityReview | None, TokenUsage]: + """ + 汇总多个增量批次的质量报告,生成最终的每日全天总评。 + """ + if not batch_reviews: + return None, TokenUsage() + + if len(batch_reviews) == 1: + return self._build_review_from_dict(batch_reviews[0]), TokenUsage() + + try: + # 构建汇总用的提示词 + reviews_text = "" + for i, rev in enumerate(batch_reviews): + title = rev.get("title", "未命名") + summary = rev.get("summary", "") + dims = ", ".join( + [ + f"{d.get('name')}({d.get('percentage')}%)" + for d in rev.get("dimensions", []) + ] + ) + reviews_text += f"\n批次 {i + 1} [{title}]:\n- 维度表现: {dims}\n- 核心摘要: {summary}\n" + + # 获取配置中的汇总提示词模板,如果没有则使用默认模板 + prompt_template = ( + self.config_manager.get_quality_summary_prompt() + or """你现在有一份今天全天分散时间段的多个“增量批次点评笔记”。 +你的任务是将这些分散的笔记汇总成一份最终的“全天聊天质量终极锐评”。 + +## 任务目标: +1. **全局抽象维度**:根据各批次的维度表现,平衡权重,提取出 3-6 个覆盖全天的【核心、上层抽象】课题维度(如:职场/行业风向、技术架构演进、社畜心理博弈等)。 +2. **严禁在维度名称(name)中出现具体的批次细节。标题必须代表全天的某种趋势。** +3. **百分比融合**:根据全天笔记的频率和强度,给出一个代表全天整体分布的比例(总和不超过100%)。 +4. **终极点评**:为每个汇总维度写出一句升华后的全天总结性点评。可以融合具体批次中的有趣槽点。 +5. **终极总结**:拟定全天的大型主题标题、副标题,并给出一句霸气的全天表现总结。 + +## 风格要求: +- 只有维度名称(name)需要高度概括抽象。 +- 点评(comment)和总结(summary)请尽量生动、具体,要把一整天的梗串联起来。 + +## 返回格式要求: +必须以纯 JSON 格式返回,不得包含任何 Markdown 格式。 + +```json +{{ + "title": "今日群聊主题", + "subtitle": "副标题", + "dimensions": [ + {{ + "name": "抽象大类标题", + "percentage": 比例, + "comment": "维度的全天锐评" + }} + ], + "summary": "全天总结金句" +}} +``` +""" + ) + prompt = render_template(prompt_template, reviews_text=reviews_text) + + # 调用 LLM 进行汇总 + system_prompt = await self._build_system_prompt(umo) + base_temperature = await self._resolve_provider_temperature( + self.get_provider_id_key(), umo + ) + + # 应用人设强化注入 + prompt = self._apply_persona_reinforcement(prompt, system_prompt) + + response = await call_provider_with_retry( + self.context, + self.config_manager, + prompt=prompt, + umo=umo, + provider_id_key=self.get_provider_id_key(), + system_prompt=system_prompt, + response_format=self.get_response_format(), + observation_label=f"{self.get_data_type()}#batch_summary", + ) + + if response is None: + return None, TokenUsage() + + token_usage_dict = extract_token_usage(response) + usage = TokenUsage( + prompt_tokens=token_usage_dict["prompt_tokens"], + completion_tokens=token_usage_dict["completion_tokens"], + total_tokens=token_usage_dict["total_tokens"], + ) + + result_text = extract_response_text(response) + trace = TraceContext.current() + if trace: + slot = trace.metadata.setdefault("llm_prompts", {}).setdefault( + self.get_data_type(), {} + ) + slot["prompt"] = prompt + slot["initial_prompt"] = prompt + slot["system_prompt"] = system_prompt + slot["tokens"] = token_usage_dict["total_tokens"] + slot["prompt_tokens"] = token_usage_dict["prompt_tokens"] + slot["completion_tokens"] = token_usage_dict["completion_tokens"] + slot["completion"] = result_text or "" + slot["initial_completion"] = result_text or "" + + if not result_text: + return None, usage + + success, parsed_data, error_msg = parse_json_object_response( + result_text, "汇总质量分析" + ) + + if success and parsed_data: + valid, normalized, validation_error = self._validate_review_payload( + parsed_data + ) + if valid and normalized: + review = self._build_review_from_dict(normalized) + logger.info( + f"聊天质量汇总分析成功,解析到 {len(review.dimensions)} 个汇总维度" + ) + return review, usage + error_msg = validation_error or error_msg + + repaired_data = await self._retry_parse_quality_object( + original_prompt=prompt, + previous_output=result_text, + parse_error=error_msg, + umo=umo, + system_prompt=system_prompt, + base_temperature=base_temperature, + ) + if repaired_data: + review = self._build_review_from_dict(repaired_data) + logger.info( + f"聊天质量汇总 schema 修复重试成功,解析到 {len(review.dimensions)} 个汇总维度" + ) + return review, usage + + # 降级:如果汇总失败,返回最新的一个 + logger.warning(f"聊天质量汇总分析失败,降级使用最新批次: {error_msg}") + return self._build_review_from_dict(batch_reviews[-1]), usage + + except Exception as e: + logger.error(f"聊天质量汇总分析异常: {e}", exc_info=True) + return self._build_review_from_dict(batch_reviews[-1]), TokenUsage() + + async def analyze_quality( + self, + messages: list[dict], + umo: str | None = None, + session_id: str | None = None, + persona_id: str | None = None, + prompt_override: str | None = None, + ) -> tuple[QualityReview | None, TokenUsage]: + """ + 分析聊天质量 + + 流程遵循 BaseAnalyzer 的设计模式: + 1. 构建 prompt + 2. 调用 LLM + 3. 提取 token 使用统计 + 4. JSON 解析(使用 parse_json_object_response) + 5. 正则降级(使用 extract_quality_with_regex) + """ + try: + provider_id_key = self.get_provider_id_key() + resolved_provider_id = None + if provider_id_key: + resolved_provider_id = await get_provider_id_with_fallback( + self.context, self.config_manager, provider_id_key, umo + ) + + # 1. 获取人格设定 + system_prompt = await self._build_system_prompt(umo) + base_temperature = await self._resolve_provider_temperature( + self.get_provider_id_key(), umo, provider_id=resolved_provider_id + ) + + # 2. 构建 prompt + prompt = self.build_prompt(messages) + if not prompt: + return None, TokenUsage() + + # 应用人设强化注入 + prompt = self._apply_persona_reinforcement(prompt, system_prompt) + + from ....shared.trace_context import TraceContext + + trace = TraceContext.current() + if trace: + prompts_map = trace.metadata.setdefault("llm_prompts", {}) + prompts_map[self.get_data_type()] = { + "prompt": prompt, + "system_prompt": system_prompt, + "provider_id": resolved_provider_id or "default", + } + + # 3. 调用 LLM + response = await call_provider_with_retry( + self.context, + self.config_manager, + prompt=prompt, + umo=umo, + provider_id_key=self.get_provider_id_key(), + provider_id=resolved_provider_id, + system_prompt=system_prompt, + response_format=self.get_response_format(), + observation_label=self.get_data_type(), + ) + + if response is None: + err_text = "聊天质量分析调用LLM失败: Provider 返回空响应或重试耗尽" + logger.error(err_text) + raise RuntimeError(err_text) + + # 4. 提取 token 使用统计 + token_usage_dict = extract_token_usage(response) + usage = TokenUsage( + prompt_tokens=token_usage_dict["prompt_tokens"], + completion_tokens=token_usage_dict["completion_tokens"], + total_tokens=token_usage_dict["total_tokens"], + ) + + # 5. 提取响应文本 + result_text = extract_response_text(response) + if not result_text: + err_text = "聊天质量分析失败: LLM 未返回任何文本内容" + logger.error(err_text) + raise RuntimeError(err_text) + + if trace: + slot = trace.metadata.setdefault("llm_prompts", {}).setdefault( + self.get_data_type(), {} + ) + slot["prompt"] = prompt + slot["system_prompt"] = system_prompt + slot["provider_id"] = resolved_provider_id or "default" + slot["tokens"] = token_usage_dict["total_tokens"] + slot["prompt_tokens"] = token_usage_dict["prompt_tokens"] + slot["completion_tokens"] = token_usage_dict["completion_tokens"] + slot["completion"] = result_text + + # 6. JSON 解析(使用 parse_json_object_response) + success, parsed_data, error_msg = parse_json_object_response( + result_text, self.get_data_type() + ) + + if success and parsed_data: + valid, normalized, validation_error = self._validate_review_payload( + parsed_data + ) + if valid and normalized: + review = self._build_review_from_dict(normalized) + logger.debug( + f"聊天质量分析成功,解析到 {len(review.dimensions)} 个维度" + ) + return review, usage + error_msg = validation_error or error_msg + + regex_data = extract_quality_with_regex(result_text) + if regex_data: + valid, normalized, validation_error = self._validate_review_payload( + regex_data + ) + if valid and normalized: + review = self._build_review_from_dict(normalized) + logger.debug( + f"聊天质量首轮结构化失败后,正则提取成功,获得 {len(review.dimensions)} 个维度" + ) + return review, usage + error_msg = validation_error or error_msg + + repaired_data = await self._retry_parse_quality_object( + original_prompt=prompt, + previous_output=result_text, + parse_error=error_msg, + umo=umo, + system_prompt=system_prompt, + base_temperature=base_temperature, + ) + if repaired_data: + review = self._build_review_from_dict(repaired_data) + logger.debug( + f"聊天质量 schema 修复重试成功,解析到 {len(review.dimensions)} 个维度" + ) + return review, usage + + # 7. 全部失败 + err_text = f"聊天质量分析失败: JSON解析和正则提取均未成功 ({error_msg or '未产出有效内容'})" + logger.error(err_text) + raise RuntimeError(err_text) + + except Exception as e: + logger.error(f"聊天质量分析失败: {e}", exc_info=True) + raise + + # Override analyze to bridge the base class interface + async def analyze( + self, + data: list[dict], + umo: str | None = None, + session_id: str | None = None, + persona_id: str | None = None, + prompt_override: str | None = None, + ) -> tuple[list[QualityReview], TokenUsage]: + review, usage = await self.analyze_quality( + data, + umo, + session_id, + persona_id=persona_id, + prompt_override=prompt_override, + ) + return [review] if review else [], usage diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/comic_analyzer.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/comic_analyzer.py new file mode 100644 index 0000000..6705edf --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/comic_analyzer.py @@ -0,0 +1,168 @@ +import re + +from ....domain.models.data_models import TokenUsage +from ....utils.logger import logger +from ..utils.structured_output_schema import JSONObject +from .base_analyzer import BaseAnalyzer + + +class ComicStoryboardAnalyzer(BaseAnalyzer[dict, list[dict]]): + """ + 分镜及绘画提示词分析器 + 直接从聊天记录中提取金句并生成绘画提示词(含文字渲染要求) + """ + + def get_provider_id_key(self) -> str: + """获取画图提示词专用 Provider ID 配置键名""" + return "drawing_prompt_provider_id" + + def get_data_type(self) -> str: + return "comic_storyboards" + + def get_max_count(self) -> int: + return self.config_manager.get_max_topics() + + def build_prompt(self, data: list[dict], prompt_template: str | None = None) -> str: + prompt_template = ( + prompt_template or self.config_manager.get_comic_storyboard_prompt() + ) + if not prompt_template: + # 默认的 Prompt + prompt_template = ( + "你是一个资深的漫画分镜师与 AI 绘画提示词专家。\n" + "请根据以下给出的【群聊每日核心话题列表】,站在你【当前的人格角色设定】(详见系统注入的身份)的视角与语气,将其改编并设计为一个精彩的多格连环漫画(Comic Strip)全景视觉画图提示词 (Prompt)。\n\n" + "【核心视觉、台词与双层排版规则】:\n" + "1. 【全话题必须覆盖(共 ${topic_count} 个分格)】:给出的待创作核心话题列表中共有 ${topic_count} 个话题,你必须为每一个话题分别设计一个分格 Panel(即 Panel 1 到 Panel ${topic_count}),绝对不许随意裁减、挑选或遗漏任何一个话题!\n" + "2. 【人设口语化台词改编】:绝对严禁将报告分析总结原文直接放进对话框!必须以【你当前的人格语气/性格/口吻】(例如傲娇、萌系或专属说话风格),将每个话题的事件提炼改编为一句角色在漫画中的生动台词或吐槽,【每条台词控制在 15 个汉字以内】(例如:“呜呜!家里云又断网了啦!”、“萝卜子才没有降智!那都是Gemini的错!”)。\n" + "3. 【精美双层文字排版(气泡 + 可爱旁白字幕条)】:\n" + " - 【角色的气泡】:在描述英文 Prompt 时,指定样式为“adorable kawaii anime speech bubble, soft rounded cloud-like shape, cute pointer tail pointing to the speaker”。\n" + " - 【分格底部的事件旁白条】:将每个话题概括为生动精炼的短标题(控制在 30 字以内,严禁带有“【事件】”字样),在 Prompt 中指定样式为“cute pastel-colored kawaii caption strip at the bottom of the panel with soft rounded corners”,严禁死板白框!\n" + '4. 【中文文本显式渲染】:画面整体构图与场景描述使用英文,但气泡与底部旁白条内渲染的中文必须显式指定(指令格式:containing a speech bubble with exact Chinese text "人设吐槽台词" 以及 and a cute caption strip at bottom with exact Chinese text "精炼话题短标题"),绝对禁止将中文翻译成英文!\n' + "5. 【话题内容直传与文字渲染约束】:在生成传给生图 LLM 的英文提示词 (scene) 时,对于每一个分格,除了描述具体的视觉画面外,你必须将该话题的【完整详情(翻译为英文)】作为 Background Context 附加在该分格的提示词中,帮助生图模型理解剧情。但同时,必须极其强烈地警告生图模型:“绝对禁止将长篇上下文写在画面上,仅允许渲染短标题字幕条和气泡台词!”(示例:Background Context: [Details]. STRICT RULE: DO NOT render the background context text! ONLY render the exact Chinese text in the bubble and caption strip!)。\n" + "6. 【核心角色强制全覆盖】:在提示词中必须明确要求并描述,每一个分格 (Panel) 都必须无一例外地出现你当前的人格设定(即参考图中的核心角色,例如 1girl, [特定外貌特征] 等),保持整篇连环画的主角绝对连贯!\n\n" + "【待创作的群聊核心话题列表】:\n${chat_content}\n\n" + '请输出包含 "scene" 字段的 JSON 对象。\n' + ) + + valid_topics = [m for m in data if m.get("topic", "")] + topic_count = len(valid_topics) if valid_topics else self.get_max_count() + chat_content = "\n".join( + [ + f"{i + 1}. 话题: {m.get('topic', '')}\n 详情: {m.get('detail', '')}" + for i, m in enumerate(valid_topics) + ] + ) + + try: + from string import Template + + if "${" in prompt_template or "$" in prompt_template: + return Template(prompt_template).safe_substitute( + chat_content=chat_content, + topic_count=topic_count, + max_count=topic_count, + ) + else: + return prompt_template.format( + chat_content=chat_content, + topic_count=topic_count, + max_count=topic_count, + ) + except Exception as e: + logger.warning(f"漫画分镜提示词格式化失败,使用默认格式: {e}") + return f"请从以下群聊话题中提取并生成包含 scene 的 JSON:\n{chat_content}" + + def build_prompt_with_override( + self, data: list[dict], prompt_override: str | None + ) -> str: + """使用角色专属模板构建漫画分镜提示词。""" + return self.build_prompt(data, prompt_override) + + def extract_with_regex(self, result_text: str, max_count: int) -> list[dict]: + del max_count + storyboards = [] + scene_match = re.search(r'"scene"\s*:\s*"((?:[^"\\]|\\.)*)"', result_text) + if scene_match: + storyboards.append({"scene": scene_match.group(1).replace('\\"', '"')}) + return storyboards + + def parse_structured_response( + self, result_text: str + ) -> tuple[bool, list[dict] | None, str | None]: + from ..utils.json_utils import parse_json_object_response + + success, data, error = parse_json_object_response( + result_text, self.get_data_type() + ) + if success and isinstance(data, dict): + if "storyboards" in data and isinstance(data["storyboards"], list): + scenes = [ + item["scene"].strip() + for item in data["storyboards"] + if isinstance(item, dict) + and isinstance(item.get("scene"), str) + and item["scene"].strip() + ] + if scenes: + return True, [{"scene": "\n\n".join(scenes)}], None + return False, None, "'storyboards'中没有有效的非空'scene'字段" + elif "scene" in data: + scene = data["scene"] + if isinstance(scene, str) and scene.strip(): + return True, [{"scene": scene.strip()}], None + return False, None, "'scene'字段必须是非空字符串" + else: + return False, None, "无法在JSON对象中找到'scene'或'storyboards'字段" + return False, None, error + + def create_data_objects(self, data_list: list[dict]) -> list[dict]: + # 我们直接返回 dict,因为不需要特别的类型验证 + return data_list + + def get_response_schema(self) -> JSONObject: + return { + "type": "object", + "properties": { + "scene": { + "type": "string", + "description": "One complete panoramic comic image-generation prompt covering every topic and panel", + } + }, + "required": ["scene"], + "additionalProperties": False, + } + + async def analyze_storyboards( + self, + topics: list[dict], + umo: str | None = None, + session_id: str | None = None, + persona_id: str | None = None, + prompt_template: str | None = None, + ) -> tuple[list[dict], TokenUsage]: + """执行分析,返回 storyboards 和 token 消耗。 + + Args: + topics: 已提取的有效群聊话题。 + umo: 群聊统一消息来源标识。 + session_id: 调试会话标识。 + persona_id: 漫画分镜专用人格 ID。 + prompt_template: 角色专属的漫画分镜提示词模板。 + + Returns: + 分镜列表和 Token 使用统计。 + """ + storyboards, usage = await self.analyze( + topics, umo, session_id, persona_id, prompt_template + ) + + if storyboards: + if isinstance(storyboards, list): + if len(storyboards) > 0 and isinstance(storyboards[0], dict): + if "storyboards" in storyboards[0]: + storyboards = storyboards[0]["storyboards"] + # else: storyboards[0] 已含 "scene",直接使用 + + if isinstance(storyboards, list): + return [item for item in storyboards if isinstance(item, dict)], usage + return [], usage diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/golden_quote_analyzer.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/golden_quote_analyzer.py new file mode 100644 index 0000000..146a1f3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/golden_quote_analyzer.py @@ -0,0 +1,222 @@ +""" +金句分析模块 +专门处理群聊金句提取和分析 +""" + +from datetime import datetime + +from ....domain.models.data_models import GoldenQuote, TokenUsage +from ....utils.logger import logger +from ...utils.template_utils import render_template +from ..utils import InfoUtils +from ..utils.json_utils import extract_golden_quotes_with_regex +from ..utils.response_validation import validate_golden_quote_items +from ..utils.structured_output_schema import JSONObject, build_golden_quotes_schema +from .base_analyzer import BaseAnalyzer + + +class GoldenQuoteAnalyzer(BaseAnalyzer[GoldenQuote, list[dict]]): + """ + 金句分析器 + 专门处理群聊金句的提取和分析 + """ + + def get_provider_id_key(self) -> str: + """获取 Provider ID 配置键名""" + return "golden_quote_provider_id" + + def get_data_type(self) -> str: + """获取数据类型标识""" + return "金句" + + def get_max_count(self) -> int: + """获取最大金句数量,增量模式下使用覆盖值""" + if self._incremental_max_count is not None: + return self._incremental_max_count + return self.config_manager.get_max_golden_quotes() + + def get_response_schema_name(self) -> str: + return "daily_golden_quotes" + + def get_response_schema(self) -> JSONObject: + return build_golden_quotes_schema(self.get_max_count()) + + def build_prompt(self, data: list[dict]) -> str: + """ + 构建金句分析提示词 + + Args: + messages: 群聊的文本消息列表 + + Returns: + 提示词字符串 + """ + if not data: + return "" + + # 构建消息文本 (用 [user_id] 替代 nickname 以确保回填 100% 准确,避免 Emoji 等干扰) + messages_text = "\n".join( + [f"[{msg['time']}] [{msg['user_id']}]: {msg['content']}" for msg in data] + ) + + max_golden_quotes = self.get_max_count() + + # 从配置读取 prompt 模板(默认使用 "default" 风格) + prompt_template = self.config_manager.get_golden_quote_analysis_prompt() + + if prompt_template: + try: + prompt = render_template( + prompt_template, + max_golden_quotes=max_golden_quotes, + messages_text=messages_text, + ) + logger.info("使用配置中的金句分析提示词") + return prompt + except Exception as e: + logger.warning(f"应用金句分析提示词失败: {e}") + + logger.warning("未找到有效的金句分析提示词配置,请检查配置文件") + return "" + + def extract_with_regex(self, result_text: str, max_count: int) -> list[dict]: + """ + 使用正则表达式提取金句信息 + + Args: + result_text: LLM响应文本 + max_count: 最大提取数量 + + Returns: + 金句数据列表 + """ + return extract_golden_quotes_with_regex(result_text, max_count) + + def create_data_objects(self, data_list: list[dict]) -> list[GoldenQuote]: + """ + 创建金句对象列表 + + Args: + quotes_data: 原始金句数据列表 + + Returns: + GoldenQuote对象列表 + """ + try: + quotes = [] + max_quotes = self.get_max_count() + + for quote_data in data_list[:max_quotes]: + # 确保数据格式正确 + content = quote_data.get("content", "").strip() + sender = quote_data.get("sender", "").strip() + reason = quote_data.get("reason", "").strip() + + # 验证必要字段 + if not content or not sender or not reason: + logger.warning(f"金句数据格式不完整,跳过: {quote_data}") + continue + + quotes.append( + GoldenQuote(content=content, sender=sender, reason=reason) + ) + + return quotes + + except Exception as e: + logger.error(f"创建金句对象失败: {e}") + return [] + + def validate_parsed_data( + self, data_list: list[dict] + ) -> tuple[bool, list[dict] | None, str | None]: + return validate_golden_quote_items(data_list) + + async def analyze_golden_quotes( + self, + messages: list[dict], + umo: str | None = None, + session_id: str | None = None, + ) -> tuple[list[GoldenQuote], TokenUsage]: + """ + 分析群聊金句 + + Args: + messages: 群聊消息列表 + umo: 模型唯一标识符 + session_id: 会话ID (用于调试模式) + + Returns: + (金句列表, Token使用统计) + """ + try: + # 提取圣经的文本消息 + interesting_messages = self.extract_interesting_messages(messages) + + if not interesting_messages: + logger.info("没有符合条件的圣经消息,返回空结果") + return [], TokenUsage() + + logger.info(f"开始从 {len(interesting_messages)} 条圣经消息中提取金句") + quotes, usage = await self.analyze(interesting_messages, umo, session_id) + + # 建立 ID 到昵称的映射表用于恢复显示 + id_to_nickname = {} + for msg in interesting_messages: + uid = str(msg.get("user_id", "")) + if uid: + id_to_nickname[uid] = msg.get("sender", "") + + # 回填 User ID 并恢复发送者昵称 + for quote in quotes: + # 此时 quote.sender 包含的是 Prompt 中的 [user_id] + # 有些 LLM 可能会带上中括号,尝试清理 + potential_id = quote.sender.strip().strip("[]") + + if potential_id in id_to_nickname: + quote.user_id = potential_id + quote.sender = id_to_nickname[potential_id] + else: + logger.warning( + f"[金句分析] 无法匹配 User ID: {potential_id},金句将无法显示真实头像。" + ) + + return quotes, usage + + except Exception as e: + logger.error(f"金句分析失败: {e}") + raise + + def extract_interesting_messages(self, messages: list[dict]) -> list[dict]: + """ + 根据清理后的消息提取可能有意义的消息片段用于金句分析。 + + Args: + messages: 已由 MessageCleaner 处理过的 legacy 消息列表 + + Returns: + 提取的文本消息列表 + """ + interesting_messages = [] + + for msg in messages: + # 获取发送者显示名 + sender = msg.get("sender", {}) + nickname = InfoUtils.get_user_nickname(self.config_manager, sender) + msg_time = datetime.fromtimestamp(msg.get("time", 0)).strftime("%H:%M") + + for content in msg.get("message", []): + if content.get("type") == "text": + text = content.get("data", {}).get("text", "").strip() + # 过滤掉过短或过长的噪音(已经在 cleaner 处理过一遍基本垃圾) + if 2 <= len(text) <= 500: + interesting_messages.append( + { + "sender": nickname, + "time": msg_time, + "content": text, + "user_id": str(sender.get("user_id", "")), + } + ) + + return interesting_messages diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/topic_analyzer.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/topic_analyzer.py new file mode 100644 index 0000000..d7e1a32 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/topic_analyzer.py @@ -0,0 +1,395 @@ +""" +话题分析模块 +专门处理群聊话题分析 +""" + +import re +from datetime import datetime + +from ....domain.models.data_models import SummaryTopic, TokenUsage +from ....utils.logger import logger +from ...utils.template_utils import render_template +from ..utils import InfoUtils +from ..utils.json_utils import extract_topics_with_regex +from ..utils.response_validation import validate_topic_items +from ..utils.structured_output_schema import JSONObject, build_topics_schema +from .base_analyzer import BaseAnalyzer + + +class TopicAnalyzer(BaseAnalyzer[SummaryTopic, list[dict]]): + """ + 话题分析器 + 专门处理群聊话题的提取和分析 + """ + + def get_provider_id_key(self) -> str: + """获取 Provider ID 配置键名""" + return "topic_provider_id" + + def get_data_type(self) -> str: + """获取数据类型标识""" + return "话题" + + def get_max_count(self) -> int: + """获取最大话题数量,增量模式下使用覆盖值""" + if self._incremental_max_count is not None: + return self._incremental_max_count + return self.config_manager.get_max_topics() + + def get_response_schema_name(self) -> str: + return "daily_topics" + + def get_response_schema(self) -> JSONObject: + return build_topics_schema(self.get_max_count()) + + def build_prompt(self, data: list[dict]) -> str: + """ + 构建话题分析提示词 + + Args: + messages: 群聊消息列表 + + Returns: + 提示词字符串 + """ + # 验证输入数据格式 + if not isinstance(data, list): + logger.error(f"build_prompt 期望列表,但收到: {type(data)}") + return "" + + # 检查消息列表是否为空 + if not data: + logger.warning("build_prompt 收到空消息列表") + return "" + + # 提取文本消息 + text_messages = [] + for i, msg in enumerate(data): + # 确保msg是字典类型,避免'str' object has no attribute 'get'错误 + if not isinstance(msg, dict): + continue + + try: + sender = msg.get("sender", {}) + # 确保sender是字典类型,避免'str' object has no attribute 'get'错误 + if not isinstance(sender, dict): + continue + + # 获取发送者ID并过滤机器人消息 + user_id = str(sender.get("user_id", "")) + bot_self_ids = self.config_manager.get_bot_self_ids() + + # 跳过机器人自己的消息 + if bot_self_ids and user_id in [str(uid) for uid in bot_self_ids]: + continue + + nickname = InfoUtils.get_user_nickname(self.config_manager, sender) + msg_time = datetime.fromtimestamp(msg.get("time", 0)).strftime("%H:%M") + + message_list = msg.get("message", []) + + # 提取文本内容,可能分布在多个 content 中 + text_parts = [] + for j, content in enumerate(message_list): + if not isinstance(content, dict): + continue + + content_type = content.get("type", "") + + if content_type == "text": + text = content.get("data", {}).get("text", "").strip() + if text: + text_parts.append(text) + elif content_type == "at": + # 处理 @ 消息,转换为文本 + at_data = content.get("data", {}) + # 兼容不同平台的 ID 字段 + at_id = at_data.get("id") or at_data.get("user_id") + if at_id: + at_text = f"@{at_id}" + text_parts.append(at_text) + elif content_type == "reply": + # 处理回复消息,添加标记 + reply_id = content.get("data", {}).get("id", "") + if reply_id: + reply_text = f"[回复:{reply_id}]" + text_parts.append(reply_text) + + # 合并所有文本部分 + combined_text = "".join(text_parts).strip() + + if ( + combined_text + and len(combined_text) > 2 + and not combined_text.startswith("/") + ): + # 清理消息内容 + cleaned_text = combined_text.replace("“", '"').replace("”", '"') + cleaned_text = cleaned_text.replace("‘", "'").replace("’", "'") + cleaned_text = cleaned_text.replace("\n", " ").replace("\r", " ") + cleaned_text = cleaned_text.replace("\t", " ") + cleaned_text = re.sub(r"[\x00-\x1f\x7f-\x9f]", "", cleaned_text) + + text_messages.append( + { + "sender": nickname, + "time": msg_time, + "content": cleaned_text, + "user_id": str(user_id), + } + ) + except Exception as e: + logger.error( + f"build_prompt 处理第 {i + 1} 条消息时出错: {e}", exc_info=True + ) + continue + + if not text_messages: + logger.warning("build_prompt 没有提取到有效的文本消息,返回空prompt") + return "" + + # 构建消息文本 + # 使用用户提供的 ID-Only 格式: [HH:MM] [用户ID]: 消息内容 + messages_text = "\n".join( + [ + f"[{msg['time']}] [{msg['user_id']}]: {msg['content']}" + for msg in text_messages + ] + ) + + max_topics = self.get_max_count() + + # 从配置读取 prompt 模板(默认使用 "default" 风格) + prompt_template = self.config_manager.get_topic_analysis_prompt() + + if prompt_template: + try: + prompt = render_template( + prompt_template, + max_topics=max_topics, + messages_text=messages_text, + ) + logger.info("使用配置中的话题分析提示词") + return prompt + except Exception as e: + logger.warning(f"应用话题分析提示词失败: {e}") + + logger.warning("未找到有效的话题分析提示词配置,请检查配置文件") + return "" + + def extract_with_regex(self, result_text: str, max_count: int) -> list[dict]: + """ + 使用正则表达式提取话题信息 + + Args: + result_text: LLM响应文本 + max_count: 最大话题数量 + + Returns: + 话题数据列表 + """ + return extract_topics_with_regex(result_text, max_count) + + def create_data_objects(self, data_list: list[dict]) -> list[SummaryTopic]: + """ + 创建话题对象列表 + + Args: + topics_data: 原始话题数据列表 + + Returns: + SummaryTopic对象列表 + """ + logger.debug( + f"create_data_objects 开始处理,输入数据数量: {len(data_list) if data_list else 0}" + ) + logger.debug(f"输入数据类型: {type(data_list)}") + + try: + topics = [] + max_topics = self.get_max_count() + + logger.debug(f"处理前 {max_topics} 条话题数据") + + for i, topic_data in enumerate(data_list[:max_topics]): + logger.debug(f"处理第 {i + 1} 条话题数据,类型: {type(topic_data)}") + + # 确保topic_data是字典类型,避免'str' object has no attribute 'get'错误 + if not isinstance(topic_data, dict): + logger.warning( + f"跳过非字典类型的话题数据: {type(topic_data)} - {topic_data}" + ) + continue + + try: + # 确保数据格式正确 + topic_name = topic_data.get("topic", "").strip() + contributors = topic_data.get("contributors", []) + detail = topic_data.get("detail", "").strip() + + logger.debug( + f"话题数据 - 名称: {topic_name}, 参与者: {contributors}, 详情: {detail[:50]}..." + ) + + # 验证必要字段 + if not topic_name or not detail: + logger.warning(f"话题数据格式不完整,跳过: {topic_data}") + continue + + # 确保参与者列表有效 + if not contributors or not isinstance(contributors, list): + contributors = ["群友"] + else: + # 清理参与者名称 + contributors = [ + str(c).strip() for c in contributors if c and str(c).strip() + ] or ["群友"] + + topics.append( + SummaryTopic( + topic=topic_name, + contributors=contributors[:5], # 最多5个参与者 + detail=detail, + ) + ) + except Exception as e: + logger.error(f"处理第 {i + 1} 条话题数据时出错: {e}", exc_info=True) + continue + + logger.debug(f"create_data_objects 完成,创建了 {len(topics)} 个话题对象") + return topics + + except Exception as e: + logger.error(f"创建话题对象失败: {e}", exc_info=True) + return [] + + def validate_parsed_data( + self, data_list: list[dict] + ) -> tuple[bool, list[dict] | None, str | None]: + return validate_topic_items(data_list) + + def extract_text_messages(self, messages: list[dict]) -> list[dict]: + """ + 从已清理的消息中提取文本消息用于话题分析。 + + Args: + messages: 已由 MessageCleaner 处理过的 legacy 消息列表 + + Returns: + 提取的文本消息列表 + """ + text_messages = [] + + for msg in messages: + # 获取发送者显示名 + sender = msg.get("sender", {}) + nickname = InfoUtils.get_user_nickname(self.config_manager, sender) + msg_time = datetime.fromtimestamp(msg.get("time", 0)).strftime("%H:%M") + + for content in msg.get("message", []): + if content.get("type") == "text": + text = content.get("data", {}).get("text", "").strip() + # 已经在 MessageCleaner 中处理过基本的垃圾内容 + if text: + # 简单的额外清理 + cleaned_text = text.replace("\n", " ").replace("\r", " ") + cleaned_text = re.sub(r"[\x00-\x1f\x7f-\x9f]", "", cleaned_text) + + text_messages.append( + { + "sender": nickname, + "time": msg_time, + "content": cleaned_text.strip(), + "user_id": str(sender.get("user_id", "")), + } + ) + return text_messages + + async def analyze_topics( + self, + messages: list[dict], + umo: str | None = None, + session_id: str | None = None, + ) -> tuple[list[SummaryTopic], TokenUsage]: + """ + 分析群聊话题 + + Args: + messages: 群聊消息列表 + umo: 模型唯一标识符 + session_id: 会话ID (用于调试模式) + + Returns: + (话题列表, Token使用统计) + """ + try: + logger.debug( + f"analyze_topics 开始处理,消息数量: {len(messages) if messages else 0}" + ) + logger.debug(f"消息类型: {type(messages)}") + if messages: + logger.debug( + f"第一条消息类型: {type(messages[0]) if messages else '无'}" + ) + logger.debug(f"第一条消息内容: {messages[0] if messages else '无'}") + + # 检查是否有有效的文本消息 + text_messages = self.extract_text_messages(messages) + logger.debug(f"提取到 {len(text_messages)} 条文本消息") + + if not text_messages: + logger.info("没有有效的文本消息,返回空结果") + return [], TokenUsage() + + logger.info(f"开始分析 {len(text_messages)} 条文本消息中的话题") + logger.debug(f"文本消息类型: {type(text_messages)}") + if text_messages: + logger.debug(f"第一条文本消息类型: {type(text_messages[0])}") + logger.debug(f"第一条文本消息内容: {text_messages[0]}") + + # 建立 ID 到昵称的映射表 + id_to_nickname = {} + for msg in text_messages: + sender = msg.get("sender") + user_id = msg.get("user_id") + if sender and user_id: + id_to_nickname[user_id] = sender + + # 直接传入原始消息,让 build_prompt 方法处理 + topics, usage = await self.analyze(messages, umo, session_id) + + # 后处理:contributors 此时包含的是 ID,需要映射回昵称 + for topic in topics: + raw_ids = topic.contributors # LLM 返回的是 ID 列表 + + # 填充 contributor_ids。QQ 官方 member_openid 并非纯数字, + # 因此仅接受本批次已知用户或已配置机器人 ID,而不是用 isdigit 过滤。 + bot_ids = {str(uid) for uid in self.config_manager.get_bot_self_ids()} + known_ids = set(id_to_nickname) | bot_ids + valid_ids = [] + for raw_uid in raw_ids: + uid = str(raw_uid).strip().strip("[]") + if uid and uid in known_ids and uid not in valid_ids: + valid_ids.append(uid) + topic.contributor_ids = valid_ids + + # 映射回昵称用于显示 + resolved_names = [] + for uid in valid_ids: + # 尝试从当前批次消息映射 + name = id_to_nickname.get(uid) + if not name: + # 尝试去全局配置里找 (e.g. 机器人自己) + if uid in bot_ids: + name = "Bot" + else: + name = uid # Fallback to ID + resolved_names.append(name) + + topic.contributors = resolved_names + + return topics, usage + + except Exception as e: + logger.error(f"话题分析失败: {e}", exc_info=True) + raise diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/user_title_analyzer.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/user_title_analyzer.py new file mode 100644 index 0000000..167b01c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/analyzers/user_title_analyzer.py @@ -0,0 +1,275 @@ +""" +用户称号分析模块 +专门处理用户称号和MBTI类型分析 +""" + +from ....domain.models.data_models import TokenUsage, UserTitle +from ....utils.logger import logger +from ...utils.template_utils import render_template +from ..utils.json_utils import extract_user_titles_with_regex +from ..utils.response_validation import validate_user_title_items +from ..utils.structured_output_schema import JSONObject, build_user_titles_schema +from .base_analyzer import BaseAnalyzer + + +class UserTitleAnalyzer(BaseAnalyzer[UserTitle, dict]): + """ + 用户称号分析器 + 专门处理用户称号分配和MBTI类型分析 + """ + + def get_provider_id_key(self) -> str: + """获取 Provider ID 配置键名""" + return "user_title_provider_id" + + def get_data_type(self) -> str: + """获取数据类型标识""" + return "用户称号" + + def get_max_count(self) -> int: + """获取最大用户称号数量""" + return self.config_manager.get_max_user_titles() + + def get_response_schema_name(self) -> str: + return "daily_user_titles" + + def get_response_schema(self) -> JSONObject: + return build_user_titles_schema(self.get_max_count()) + + def build_prompt(self, data: dict) -> str: + """ + 构建用户称号分析提示词 + + Args: + user_data: 用户数据字典,包含用户统计信息 + + Returns: + 提示词字符串 + """ + user_summaries = data.get("user_summaries", []) + + if not user_summaries: + return "" + + # 构建用户数据文本 + users_text = "\n".join( + [ + f"- {user['name']} (ID:{user['user_id']}): " + f"发言{user['message_count']}条, 平均{user['avg_chars']}字, " + f"表情比例{user['emoji_ratio']}, 夜间发言比例{user['night_ratio']}, " + f"回复比例{user['reply_ratio']}" + for user in user_summaries + ] + ) + + # 从配置读取 prompt 模板(默认使用 "default" 风格) + prompt_template = self.config_manager.get_user_title_analysis_prompt() + + if prompt_template: + try: + prompt = render_template(prompt_template, users_text=users_text) + logger.info("使用配置中的用户称号分析提示词") + return prompt + except Exception as e: + logger.warning(f"应用用户称号分析提示词失败: {e}") + + logger.warning("未找到有效的用户称号分析提示词配置,请检查配置文件") + return "" + + def extract_with_regex(self, result_text: str, max_count: int) -> list[dict]: + """ + 使用正则表达式提取用户称号信息 + + Args: + result_text: LLM响应文本 + max_count: 最大提取数量 + + Returns: + 用户称号数据列表 + """ + return extract_user_titles_with_regex(result_text, max_count) + + def create_data_objects(self, data_list: list[dict]) -> list[UserTitle]: + """ + 创建用户称号对象列表 + + Args: + titles_data: 原始用户称号数据列表 + + Returns: + UserTitle对象列表 + """ + try: + titles = [] + max_titles = self.get_max_count() + + for title_data in data_list[:max_titles]: + # 确保数据格式正确 + name = title_data.get("name", "").strip() + user_id = title_data.get("user_id") + title = title_data.get("title", "").strip() + mbti = title_data.get("mbti", "").strip() + reason = title_data.get("reason", "").strip() + + # 验证必要字段 + if not name or not title or not mbti or not reason: + logger.warning(f"用户称号数据格式不完整,跳过: {title_data}") + continue + + # 确保 user_id 是字符串 + if user_id is not None: + user_id = str(user_id) + else: + logger.warning(f"未找到用户ID (user_id),跳过: {title_data}") + continue + + titles.append( + UserTitle( + name=name, + user_id=user_id, + title=title, + mbti=mbti, + reason=reason, + ) + ) + + return titles + + except Exception as e: + logger.error(f"创建用户称号对象失败: {e}") + return [] + + def validate_parsed_data( + self, data_list: list[dict] + ) -> tuple[bool, list[dict] | None, str | None]: + return validate_user_title_items(data_list) + + def prepare_user_data( + self, + messages: list[dict], + user_analysis: dict, + top_users: list[dict] | None = None, + ) -> dict: + """ + 准备用户数据 + + Args: + messages: 群聊消息列表 + user_analysis: 用户分析统计 + top_users: 活跃用户列表(从get_top_users获取) + + Returns: + 准备好的用户数据字典 + """ + try: + # 获取机器人 ID 列表用于过滤 + bot_self_ids = self.config_manager.get_bot_self_ids() + + user_summaries = [] + + # 如果提供了top_users列表,只分析这些活跃用户 + if top_users: + logger.info( + f"使用get_top_users筛选出的 {len(top_users)} 个活跃用户进行称号分析" + ) + target_user_ids = {str(user["user_id"]) for user in top_users} + else: + # 兼容旧逻辑:如果没有提供top_users,则使用所有消息数>=5的用户 + logger.info("未提供活跃用户列表,使用消息数>=5的用户") + target_user_ids = { + user_id + for user_id, stats in user_analysis.items() + if stats["message_count"] >= 5 + } + + for user_id, stats in user_analysis.items(): + user_id_str = str(user_id) + # 过滤机器人由 MessageCleaner 已处理,此处仅作为二级防御 + if bot_self_ids and user_id_str in [str(uid) for uid in bot_self_ids]: + continue + + # 只处理活跃用户 (top_users 或 消息数>=5) + if user_id_str not in target_user_ids: + continue + + # 分析用户特征 (此处已基于已清理的 stats) + # 兼容性处理:优先使用 hours (dict),如果没有则尝试从消息推断或使用空 + hours_data = stats.get("hours") + if hours_data is None: + # 尝试兼容旧 schema 或简化版 + active_hours = stats.get("active_hours", []) + hours_data = dict.fromkeys(active_hours, 1) + + # 安全计算夜间发言数 + night_messages = sum(hours_data.get(h, 0) for h in range(6)) + + message_count = stats.get("message_count", 0) + if message_count <= 0: + continue + + avg_chars = stats.get("char_count", 0) / message_count + + # 称号所需维度 + user_summaries.append( + { + "name": stats.get("nickname", stats.get("name", user_id_str)), + "user_id": user_id_str, + "message_count": message_count, + "avg_chars": round(avg_chars, 1), + "emoji_ratio": round( + stats.get("emoji_count", 0) / message_count, 2 + ), + "night_ratio": round(night_messages / message_count, 2), + "reply_ratio": round( + stats.get("reply_count", 0) / message_count, 2 + ), + } + ) + + if not user_summaries: + return {"user_summaries": []} + + # 按消息数量排序 + user_summaries.sort(key=lambda x: x["message_count"], reverse=True) + + return {"user_summaries": user_summaries} + + except Exception as e: + logger.error(f"准备用户数据失败: {e}") + return {"user_summaries": []} + + async def analyze_user_titles( + self, + messages: list[dict], + user_activity: dict, + umo: str | None = None, + top_users: list[dict] | None = None, + session_id: str | None = None, + ) -> tuple[list[UserTitle], TokenUsage]: + """ + 分析用户称号 + + Args: + messages: 群聊消息列表 + user_analysis: 用户分析统计 + umo: 模型唯一标识符 + top_users: 活跃用户列表(从get_top_users获取,可选) + session_id: 会话ID (用于调试模式) + + Returns: + (用户称号列表, Token使用统计) + """ + try: + # 准备用户数据,传入活跃用户列表 + user_data = self.prepare_user_data(messages, user_activity, top_users) + + if not user_data["user_summaries"]: + logger.info("没有符合条件的用户,返回空结果") + return [], TokenUsage() + + logger.info(f"开始分析 {len(user_data['user_summaries'])} 个活跃用户的称号") + return await self.analyze(user_data, umo, session_id) + + except Exception as e: + logger.error(f"用户称号分析失败: {e}") + raise diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/llm_analyzer.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/llm_analyzer.py new file mode 100644 index 0000000..14987d5 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/llm_analyzer.py @@ -0,0 +1,802 @@ +""" +LLM分析器模块 +负责协调各个分析器进行话题分析、用户称号分析和金句分析 +""" + +import asyncio + +from ...domain.models.data_models import ( + GoldenQuote, + QualityReview, + SummaryTopic, + TokenUsage, + UserTitle, +) +from ...domain.repositories.analysis_repository import IAnalysisProvider +from ...shared.constants import PLUGIN_NAME +from ...shared.trace_context import TraceContext +from ...utils.logger import logger +from .analyzers.chat_quality_analyzer import ChatQualityAnalyzer +from .analyzers.comic_analyzer import ComicStoryboardAnalyzer +from .analyzers.golden_quote_analyzer import GoldenQuoteAnalyzer +from .analyzers.topic_analyzer import TopicAnalyzer +from .analyzers.user_title_analyzer import UserTitleAnalyzer +from .utils.json_utils import fix_json +from .utils.llm_utils import call_provider_with_retry + + +class LLMAnalyzer(IAnalysisProvider): + """ + LLM分析器 + 作为统一入口,协调各个专门的分析器进行不同类型的分析 + 保持向后兼容性,提供原有的接口 + """ + + topic_analyzer: TopicAnalyzer + user_title_analyzer: UserTitleAnalyzer + golden_quote_analyzer: GoldenQuoteAnalyzer + comic_storyboard_analyzer: ComicStoryboardAnalyzer + + def __init__(self, context, config_manager): + """ + 初始化LLM分析器 + + Args: + context: AstrBot上下文对象 + config_manager: 配置管理器 + """ + self.context = context + self.config_manager = config_manager + + # 初始化各个专门的分析器 + self.topic_analyzer = TopicAnalyzer(context, config_manager) + self.user_title_analyzer = UserTitleAnalyzer(context, config_manager) + self.golden_quote_analyzer = GoldenQuoteAnalyzer(context, config_manager) + self.chat_quality_analyzer = ChatQualityAnalyzer(context, config_manager) + self.comic_storyboard_analyzer = ComicStoryboardAnalyzer( + context, config_manager + ) + + @staticmethod + def _make_session_id( + session_id: str | None, umo: str | None = None, prefix: str = "" + ) -> str: + """Generate a session ID if not already provided.""" + if session_id: + return session_id + from datetime import datetime + + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + if umo: + safe_umo = umo.replace(":", "_") + return f"{prefix}{timestamp}_{safe_umo}" + return f"{prefix}{timestamp}" + + async def analyze_topics( + self, + messages: list[dict], + umo: str | None = None, + session_id: str | None = None, + ) -> tuple[list[SummaryTopic], TokenUsage]: + """ + 使用LLM分析话题 + 保持原有接口,委托给专门的TopicAnalyzer处理 + + Args: + messages: 群聊消息列表 + umo: 模型唯一标识符 + session_id: 会话ID (用于调试模式) + + Returns: + (话题列表, Token使用统计) + """ + try: + session_id = self._make_session_id(session_id, umo) + + logger.info(f"开始话题分析, session_id: {session_id}") + return await self.topic_analyzer.analyze_topics(messages, umo, session_id) + except Exception as e: + logger.error(f"话题分析失败: {e}") + return [], TokenUsage() + + async def analyze_user_titles( + self, + messages: list[dict], + user_activity: dict, + umo: str | None = None, + top_users: list[dict] | None = None, + session_id: str | None = None, + ) -> tuple[list[UserTitle], TokenUsage]: + """ + 使用LLM分析用户称号 + 保持原有接口,委托给专门的UserTitleAnalyzer处理 + + Args: + messages: 群聊消息列表 + user_activity: 用户分析统计 + umo: 模型唯一标识符 + top_users: 活跃用户列表(可选) + session_id: 会话ID (用于调试模式) + + Returns: + (用户称号列表, Token使用统计) + """ + try: + session_id = self._make_session_id(session_id, umo) + + logger.info(f"开始用户称号分析, session_id: {session_id}") + return await self.user_title_analyzer.analyze_user_titles( + messages, user_activity, umo, top_users, session_id + ) + except Exception as e: + logger.error(f"用户称号分析失败: {e}") + return [], TokenUsage() + + async def analyze_golden_quotes( + self, + messages: list[dict], + umo: str | None = None, + session_id: str | None = None, + ) -> tuple[list[GoldenQuote], TokenUsage]: + """ + 使用LLM分析群聊金句 + 保持原有接口,委托给专门的GoldenQuoteAnalyzer处理 + + Args: + messages: 群聊消息列表 + umo: 模型唯一标识符 + session_id: 会话ID (用于调试模式) + + Returns: + (金句列表, Token使用统计) + """ + try: + session_id = self._make_session_id(session_id, umo) + + logger.info(f"开始金句分析, session_id: {session_id}") + return await self.golden_quote_analyzer.analyze_golden_quotes( + messages, umo, session_id + ) + except Exception as e: + logger.error(f"金句分析失败: {e}") + return [], TokenUsage() + + async def analyze_comic_storyboards( + self, + topics: list[dict], + umo: str | None = None, + session_id: str | None = None, + persona_id: str | None = None, + prompt_template: str | None = None, + ) -> tuple[list[dict], TokenUsage]: + """使用 LLM 分析并生成漫画分镜和绘画提示词。 + + Args: + topics: 已提取的有效群聊话题。 + umo: 群聊统一消息来源标识。 + session_id: 调试会话标识。 + persona_id: 漫画分镜专用人格 ID。 + prompt_template: 角色专属的漫画分镜提示词模板。 + + Returns: + 分镜列表和 Token 使用统计。 + """ + try: + session_id = self._make_session_id(session_id, umo) + + logger.info(f"开始漫画分镜分析, session_id: {session_id}") + ( + storyboards, + usage, + ) = await self.comic_storyboard_analyzer.analyze_storyboards( + topics, umo, session_id, persona_id, prompt_template + ) + trace = TraceContext.current() + if trace and usage and usage.total_tokens > 0: + trace.add_token_usage( + usage.prompt_tokens, + usage.completion_tokens, + analyzer_name="comic_storyboard", + ) + return storyboards, usage + except Exception as e: + logger.error(f"漫画分镜分析失败: {e}", exc_info=True) + return [], TokenUsage() + + async def summarize_quality_reviews( + self, + batch_reviews: list[dict], + umo: str | None = None, + session_id: str | None = None, + ) -> tuple[QualityReview | None, TokenUsage]: + """ + 汇总多个质量分析报告(增量模式使用) + """ + return await self.chat_quality_analyzer.summarize_batch_reviews( + batch_reviews, umo, session_id + ) + + async def analyze_all_concurrent( + self, + messages: list[dict], + user_activity: dict, + umo: str | None = None, + top_users: list[dict] | None = None, + topic_enabled: bool = True, + user_title_enabled: bool = True, + golden_quote_enabled: bool = True, + chat_quality_enabled: bool = False, + ) -> tuple[ + list[SummaryTopic], + list[UserTitle], + list[GoldenQuote], + TokenUsage, + QualityReview | None, + ]: + """ + 并发执行所有分析任务(话题、用户称号、金句),支持按需启用。 + + Args: + messages: 群聊消息列表 + user_activity: 用户分析统计 + umo: 模型唯一标识符 + top_users: 活跃用户列表(可选) + topic_enabled: 是否启用话题分析 + user_title_enabled: 是否启用用户称号分析 + golden_quote_enabled: 是否启用金句分析 + + Returns: + (话题列表, 用户称号列表, 金句列表, 总Token使用统计) + """ + try: + session_id = self._make_session_id(None, umo) + + logger.info( + f"开始并发执行分析任务 (话题:{topic_enabled}, 称号:{user_title_enabled}, 金句:{golden_quote_enabled}, 质量:{chat_quality_enabled}),会话ID: {session_id}" + ) + + # 保存原始消息数据 (Debug Mode) + if self.config_manager.get_debug_mode(): + self._save_debug_messages(messages, session_id) + + # 构建并发任务列表 + tasks = [] + task_names = [] + + if topic_enabled: + tasks.append( + self.topic_analyzer.analyze_topics(messages, umo, session_id) + ) + task_names.append("topic") + + if user_title_enabled: + tasks.append( + self.user_title_analyzer.analyze_user_titles( + messages, user_activity, umo, top_users, session_id + ) + ) + task_names.append("user_title") + + if golden_quote_enabled: + tasks.append( + self.golden_quote_analyzer.analyze_golden_quotes( + messages, umo, session_id + ) + ) + task_names.append("golden_quote") + + if chat_quality_enabled: + tasks.append( + self.chat_quality_analyzer.analyze_quality( + messages, umo, session_id + ) + ) + task_names.append("chat_quality") + + if not tasks: + return [], [], [], TokenUsage(), None + + results = await asyncio.gather(*tasks, return_exceptions=True) + + # 处理结果 + topics, topic_usage = [], TokenUsage() + user_titles, title_usage = [], TokenUsage() + golden_quotes, quote_usage = [], TokenUsage() + chat_quality_review = None + quality_usage = TokenUsage() # Initialize here + subtask_errors: list[str] = [] + + for i, result in enumerate(results): + name = task_names[i] + if isinstance(result, Exception): + logger.error(f"分析任务 {name} 失败: {result}") + subtask_errors.append(f"{name}: {str(result)}") + continue + + if name == "topic" and isinstance(result, tuple): + topics, topic_usage = result + elif name == "user_title" and isinstance(result, tuple): + user_titles, title_usage = result + elif name == "golden_quote" and isinstance(result, tuple): + golden_quotes, quote_usage = result + elif name == "chat_quality" and isinstance(result, tuple): + chat_quality_review, quality_usage = result + if not isinstance(quality_usage, TokenUsage): + quality_usage = TokenUsage() + + # 合并Token使用统计 + total_usage = TokenUsage( + prompt_tokens=topic_usage.prompt_tokens + + title_usage.prompt_tokens + + quote_usage.prompt_tokens + + quality_usage.prompt_tokens, + completion_tokens=topic_usage.completion_tokens + + title_usage.completion_tokens + + quote_usage.completion_tokens + + quality_usage.completion_tokens, + total_tokens=topic_usage.total_tokens + + title_usage.total_tokens + + quote_usage.total_tokens + + quality_usage.total_tokens, + ) + + # 校验并补全未成功产出内容的子任务说明 + if ( + topic_enabled + and not topics + and not any(e.startswith("topic") for e in subtask_errors) + ): + subtask_errors.append( + "topic: 未能提取出有效话题(有效文本过少或模型未返回话题)" + ) + if ( + user_title_enabled + and not user_titles + and not any(e.startswith("user_title") for e in subtask_errors) + ): + subtask_errors.append( + "user_title: 未能生成用户称号(活跃用户不足或模型未返回称号)" + ) + if ( + golden_quote_enabled + and not golden_quotes + and not any(e.startswith("golden_quote") for e in subtask_errors) + ): + subtask_errors.append( + "golden_quote: 未能提取出精彩金句(符合条件的消息过少或模型未返回)" + ) + if ( + chat_quality_enabled + and not chat_quality_review + and not any(e.startswith("chat_quality") for e in subtask_errors) + ): + subtask_errors.append( + "chat_quality: 未能生成质量锐评(模型未按预期格式输出)" + ) + + # 记录 Token 消耗与丰富执行详情到 TraceContext + trace = TraceContext.current() + if trace: + if topic_usage.total_tokens > 0: + trace.add_token_usage( + topic_usage.prompt_tokens, + topic_usage.completion_tokens, + analyzer_name="topics", + ) + if title_usage.total_tokens > 0: + trace.add_token_usage( + title_usage.prompt_tokens, + title_usage.completion_tokens, + analyzer_name="user_titles", + ) + if quote_usage.total_tokens > 0: + trace.add_token_usage( + quote_usage.prompt_tokens, + quote_usage.completion_tokens, + analyzer_name="golden_quotes", + ) + if quality_usage.total_tokens > 0: + trace.add_token_usage( + quality_usage.prompt_tokens, + quality_usage.completion_tokens, + analyzer_name="chat_quality", + ) + # 丰富 LLM_ANALYSIS span payload 便于 WebUI 详情精准诊断 + for s in reversed(trace._spans): + if s.get("stage_name") == "LLM_ANALYSIS": + s.setdefault("payload", {}).update( + { + "topics_count": len(topics), + "topics": [t.topic for t in topics] if topics else [], + "user_titles_count": len(user_titles), + "golden_quotes_count": len(golden_quotes), + "chat_quality_review": bool(chat_quality_review), + "prompt_tokens": total_usage.prompt_tokens, + "completion_tokens": total_usage.completion_tokens, + "total_tokens": total_usage.total_tokens, + "enabled_features": { + "topics": topic_enabled, + "user_titles": user_title_enabled, + "golden_quotes": golden_quote_enabled, + "chat_quality": chat_quality_enabled, + }, + "prompts": trace.metadata.get("llm_prompts", {}), + } + ) + if subtask_errors: + s["payload"]["subtask_errors"] = subtask_errors + break + + logger.info( + f"并发分析完成 - 话题: {len(topics)}, 称号: {len(user_titles)}, 金句: {len(golden_quotes)}, 质量锐评: {1 if chat_quality_review else 0}" + ) + return ( + topics, + user_titles, + golden_quotes, + total_usage, + chat_quality_review, + ) + + except Exception as e: + logger.error(f"并发分析失败: {e}") + trace = TraceContext.current() + if trace: + for s in reversed(trace._spans): + if s.get("stage_name") == "LLM_ANALYSIS": + s.setdefault("payload", {}).update( + { + "error": str(e), + "subtask_errors": [f"全局并发分析异常: {e}"], + } + ) + break + return [], [], [], TokenUsage(), None + + async def analyze_incremental_concurrent( + self, + messages: list[dict], + umo: str | None = None, + topics_per_batch: int = 2, + quotes_per_batch: int = 1, + topic_enabled: bool = True, + golden_quote_enabled: bool = True, + chat_quality_enabled: bool = False, + ) -> tuple[list[SummaryTopic], list[GoldenQuote], TokenUsage, QualityReview | None]: + """ + 增量分析模式的并发执行方法。 + 仅执行话题分析和金句分析(用户称号分析在最终报告时执行), + 使用较小的批次数量以控制单次分析的输出规模。 + + Args: + messages: 本次增量分析的群聊消息列表 + umo: 模型唯一标识符 + topics_per_batch: 本次批次最大话题数量 + quotes_per_batch: 本次批次最大金句数量 + topic_enabled: 是否启用话题分析 + golden_quote_enabled: 是否启用金句分析 + + Returns: + (话题列表, 金句列表, 总Token使用统计) + """ + try: + session_id = self._make_session_id(None, umo, "incr_") + + logger.info( + f"开始增量并发分析 (话题:{topic_enabled}/{topics_per_batch}, 金句:{golden_quote_enabled}/{quotes_per_batch}, 质量锐评:{chat_quality_enabled})," + f"消息数量: {len(messages)},会话ID: {session_id}" + ) + + # 保存原始消息数据 (Debug Mode) + if self.config_manager.get_debug_mode(): + self._save_debug_messages(messages, session_id) + + # 设置增量模式的最大数量覆盖值 + self.topic_analyzer._incremental_max_count = topics_per_batch + self.golden_quote_analyzer._incremental_max_count = quotes_per_batch + + try: + # 构建并发任务列表(仅话题和金句,不包含用户称号) + tasks = [] + task_names = [] + + if topic_enabled: + tasks.append( + self.topic_analyzer.analyze_topics(messages, umo, session_id) + ) + task_names.append("topic") + + if golden_quote_enabled: + tasks.append( + self.golden_quote_analyzer.analyze_golden_quotes( + messages, umo, session_id + ) + ) + task_names.append("golden_quote") + + if chat_quality_enabled: + tasks.append( + self.chat_quality_analyzer.analyze_quality( + messages, umo, session_id + ) + ) + task_names.append("chat_quality") + + if not tasks: + return [], [], TokenUsage(), None + + results = await asyncio.gather(*tasks, return_exceptions=True) + + # 处理结果 + topics, topic_usage = [], TokenUsage() + golden_quotes, quote_usage = [], TokenUsage() + chat_quality_review = None + quality_usage = TokenUsage() + subtask_errors: list[str] = [] + + for i, result in enumerate(results): + name = task_names[i] + if isinstance(result, Exception): + logger.error(f"增量{name}分析失败: {result}") + subtask_errors.append(f"{name}: {str(result)}") + continue + + if name == "topic" and isinstance(result, tuple): + topics, topic_usage = result + elif name == "golden_quote" and isinstance(result, tuple): + golden_quotes, quote_usage = result + elif name == "chat_quality" and isinstance(result, tuple): + chat_quality_review, quality_usage = result + if not isinstance(quality_usage, TokenUsage): + quality_usage = TokenUsage() + + # 校验并补全增量子任务未产出说明 + if ( + topic_enabled + and not topics + and not any(e.startswith("topic") for e in subtask_errors) + ): + subtask_errors.append( + "topic: 未能提取出增量话题(可能有效文本过少或模型未返回)" + ) + if ( + golden_quote_enabled + and not golden_quotes + and not any(e.startswith("golden_quote") for e in subtask_errors) + ): + subtask_errors.append( + "golden_quote: 未能提取出增量金句(可能符合条件的消息过少或模型未返回)" + ) + if ( + chat_quality_enabled + and not chat_quality_review + and not any(e.startswith("chat_quality") for e in subtask_errors) + ): + subtask_errors.append( + "chat_quality: 未能生成增量质量锐评(模型未按预期格式输出)" + ) + + # 合并Token使用统计 + total_usage = TokenUsage( + prompt_tokens=topic_usage.prompt_tokens + + quote_usage.prompt_tokens + + quality_usage.prompt_tokens, + completion_tokens=topic_usage.completion_tokens + + quote_usage.completion_tokens + + quality_usage.completion_tokens, + total_tokens=topic_usage.total_tokens + + quote_usage.total_tokens + + quality_usage.total_tokens, + ) + + # 记录 Token 消耗到 TraceContext + trace = TraceContext.current() + if trace: + if topic_usage.total_tokens > 0: + trace.add_token_usage( + topic_usage.prompt_tokens, + topic_usage.completion_tokens, + analyzer_name="topics", + ) + if quote_usage.total_tokens > 0: + trace.add_token_usage( + quote_usage.prompt_tokens, + quote_usage.completion_tokens, + analyzer_name="golden_quotes", + ) + if quality_usage.total_tokens > 0: + trace.add_token_usage( + quality_usage.prompt_tokens, + quality_usage.completion_tokens, + analyzer_name="chat_quality", + ) + for s in reversed(trace._spans): + if s.get("stage_name") == "LLM_ANALYSIS": + s.setdefault("payload", {}).update( + { + "incremental": True, + "topics_count": len(topics), + "topics": [t.topic for t in topics] + if topics + else [], + "golden_quotes_count": len(golden_quotes), + "chat_quality_review": bool(chat_quality_review), + "prompt_tokens": total_usage.prompt_tokens, + "completion_tokens": total_usage.completion_tokens, + "total_tokens": total_usage.total_tokens, + "enabled_features": { + "topics": topic_enabled, + "user_titles": False, + "golden_quotes": golden_quote_enabled, + "chat_quality": chat_quality_enabled, + }, + } + ) + if subtask_errors: + s["payload"]["subtask_errors"] = subtask_errors + break + + logger.info( + f"增量并发分析完成 - 话题: {len(topics)}, 金句: {len(golden_quotes)}, 质量锐评: {1 if chat_quality_review else 0}, " + f"Token消耗: {total_usage.total_tokens}" + ) + return topics, golden_quotes, total_usage, chat_quality_review + + finally: + # 无论成功或失败,都要恢复原始的最大数量设置 + self.topic_analyzer._incremental_max_count = None + self.golden_quote_analyzer._incremental_max_count = None + + except Exception as e: + logger.error(f"增量并发分析失败: {e}", exc_info=True) + trace = TraceContext.current() + if trace: + for s in reversed(trace._spans): + if s.get("stage_name") == "LLM_ANALYSIS": + s.setdefault("payload", {}).update( + { + "error": str(e), + "subtask_errors": [f"全局增量并发分析异常: {e}"], + } + ) + break + return [], [], TokenUsage(), None + + def _save_debug_messages(self, messages: list[dict], session_id: str): + """ + 保存调试消息数据到文件(Debug Mode 专用) + + Args: + messages: 群聊消息列表 + session_id: 会话ID + """ + try: + import json + + from ...utils.paths import get_data_dir + + debug_dir = get_data_dir(PLUGIN_NAME) / "debug_data" + debug_dir.mkdir(parents=True, exist_ok=True) + + msg_file_path = debug_dir / f"{session_id}_messages.json" + with open(msg_file_path, "w", encoding="utf-8") as f: + json.dump(messages, f, ensure_ascii=False, indent=2) + except Exception: + pass + + # 向后兼容的方法,保持原有调用方式 + async def _call_provider_with_retry( + self, + provider, + prompt: str, + umo: str | None = None, + provider_id_key: str | None = None, + ): + """ + 向后兼容的LLM调用方法 + 现在委托给llm_utils模块处理 + + Args: + provider: LLM服务商实例或None(已弃用,现在使用 provider_id_key) + prompt: 输入的提示语 + umo: 指定使用的模型唯一标识符 + provider_id_key: 配置中的 provider_id 键名(可选) + + Returns: + LLM生成的结果 + """ + return await call_provider_with_retry( + self.context, + self.config_manager, + prompt, + umo, + provider_id_key, + observation_label=provider_id_key or "兼容LLM调用入口", + ) + + def _fix_json(self, text: str) -> str: + """ + 向后兼容的JSON修复方法 + 现在委托给json_utils模块处理 + + Args: + text: 需要修复的JSON文本 + + Returns: + 修复后的JSON文本 + """ + return fix_json(text) + + async def analyze_retry_prompt( + self, original_prompt: str, last_error: str, umo: str | None + ) -> str | None: + """ + 当画图 API 遇到多次失败后,将错误信息交给 LLM 进行分析和改写。 + 如果 LLM 认为原 Prompt 严重违规且无法修改,将返回 None; + 否则返回脱敏/重写后的新 Prompt,进行最后一次尝试。 + """ + prompt = f""" +你是一个专业且注重安全合规的内容改写员。 +有一段画图提示词在提交给画图模型时被拒绝或遇到了异常,原因可能包含敏感内容审查、尺寸格式报错或连接异常。 + +【原画图提示词】: +{original_prompt} + +【画图模型返回的最后一次异常信息】: +{last_error} + +请你根据异常信息,对原画图提示词进行诊断和修改: +1. 如果报错是因为“色情、暴力、血腥、政治”等严重违规审查,且你认为原内容**绝对无法**被修改为健康场景(例如要求本身就是极端不合法的),请直接返回 {{"can_fix": false, "new_prompt": ""}} +2. 如果是因为审查问题,但你可以通过**去掉敏感词**、**把场景转换为正能量/健康搞笑/委婉抽象**的画面描述来避开审查,请进行脱敏重写。 +3. 如果只是普通的超时或未知错误,你可以尝试简化画面中的复杂要素,让场景更简洁。 + +请严格以 JSON 格式输出,不要包含任何 markdown 代码块(如 ```json 等),只输出 JSON 字符串: +{{ + "can_fix": true, + "new_prompt": "修改后且保证健康合规的全新英文或中文画图提示词" +}} +""" + try: + llm_response = await call_provider_with_retry( + context=self.context, + config_manager=self.config_manager, + prompt=prompt, + umo=umo, + provider_id_key="drawing_prompt_provider_id", + observation_label="绘图提示词修复", + ) + if not llm_response or not llm_response.completion_text: + return None + + response_text = llm_response.completion_text.strip() + if response_text.startswith("```"): + import re + + response_text = re.sub(r"^```(?:json)?\s*", "", response_text) + response_text = re.sub(r"\s*```$", "", response_text) + + import json + + try: + data = json.loads(response_text) + except json.JSONDecodeError: + # 尝试通过正则寻找大括号内的内容 + import re + + match = re.search(r"(\{.*\})", response_text, re.DOTALL) + if match: + data = json.loads(match.group(1)) + else: + raise + + if data.get("can_fix") and data.get("new_prompt"): + new_prompt = data["new_prompt"].strip() + if new_prompt: + logger.info("[Comic] LLM 成功分析异常并给出了重写的安全提示词。") + return new_prompt + + logger.info("[Comic] LLM 判断该异常无法通过重写修复,或未提供新提示词。") + return None + except Exception as e: + logger.error(f"[Comic] 请求 LLM 重写提示词时发生错误: {e}") + return None diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/__init__.py new file mode 100644 index 0000000..1fb65f6 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/__init__.py @@ -0,0 +1,37 @@ +""" +分析工具模块 +包含JSON处理和LLM API请求处理工具 +""" + +from .info_utils import InfoUtils +from .json_utils import ( + extract_golden_quotes_with_regex, + extract_quality_with_regex, + extract_topics_with_regex, + extract_user_titles_with_regex, + fix_json, + parse_json_object_response, + parse_json_response, +) +from .llm_utils import ( + call_provider_with_retry, + extract_response_text, + extract_token_usage, +) + +__all__ = [ + # JSON processing utilities + "fix_json", + "parse_json_response", + "parse_json_object_response", + "extract_topics_with_regex", + "extract_user_titles_with_regex", + "extract_golden_quotes_with_regex", + "extract_quality_with_regex", + # LLM utilities + "call_provider_with_retry", + "extract_token_usage", + "extract_response_text", + # Info utilities + "InfoUtils", +] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/info_utils.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/info_utils.py new file mode 100644 index 0000000..f62ae81 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/info_utils.py @@ -0,0 +1,21 @@ +class InfoUtils: + @staticmethod + def get_user_nickname(config_manager, sender) -> str: + """ + 获取用户昵称 + + 优先使用nickname字段,如果为空则使用card(群名片)字段 + """ + enable_user_card = config_manager.get_enable_user_card() + if enable_user_card: + return ( + sender.get("card", "") + or sender.get("nickname", "") + or str(sender.get("user_id", "")) + ) + else: + return ( + sender.get("nickname", "") + or sender.get("card", "") + or str(sender.get("user_id", "")) + ) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/json_utils.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/json_utils.py new file mode 100644 index 0000000..32875ef --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/json_utils.py @@ -0,0 +1,360 @@ +""" +JSON处理工具模块 +提供JSON解析、修复和正则提取功能 +""" + +import json +import re +from typing import Any + +from ....utils.logger import logger + + +def fix_json(text: str) -> str: + """ + 修复JSON格式问题,包括中文符号替换 + + Args: + text: 需要修复的JSON文本 + + Returns: + 修复后的JSON文本 + """ + try: + # 1. 移除markdown代码块标记 + text = re.sub(r"```json\s*", "", text) + text = re.sub(r"```\s*$", "", text) + + # 2. 基础清理 + text = text.replace("\n", " ").replace("\r", " ") + text = re.sub(r"\s+", " ", text) + + # 3. 替换中文符号为英文符号(修复) + # 中文引号 -> 英文引号 + text = text.replace("“", '"').replace("”", '"') + text = text.replace("‘", "'").replace("’", "'") + # 中文逗号 -> 英文逗号 + text = text.replace(",", ",") + # 中文冒号 -> 英文冒号 + text = text.replace(":", ":") + # 中文括号 -> 英文括号 + text = text.replace("(", "(").replace(")", ")") + text = text.replace("【", "[").replace("】", "]") + + # 4. 处理字符串内容中的特殊字符 + # 转义字符串内的双引号 + def escape_quotes_in_strings(match): + content = match.group(1) + # 转义内部的双引号 + content = content.replace('"', '\\"') + return f'"{content}"' + + # 先处理字段值中的引号 + text = re.sub(r'"([^"]*(?:"[^"]*)*)"', escape_quotes_in_strings, text) + + # 5. 修复截断的JSON + if not text.endswith("]"): + last_complete = text.rfind("}") + if last_complete > 0: + text = text[: last_complete + 1] + "]" + + # 6. 修复常见的JSON格式问题 + # 1. 修复缺失的逗号 + text = re.sub(r"}\s*{", "}, {", text) + + # 2. 确保字段名有引号(仅在对象开始或逗号后,避免破坏字符串值) + def quote_field_names(match): + prefix = match.group(1) + key = match.group(2) + return f'{prefix}"{key}":' + + # 只在 { 或 , 后面匹配字段名,避免在字符串值中误匹配 + text = re.sub(r"([{,]\s*)([a-zA-Z_][a-zA-Z0-9_]*)\s*:", quote_field_names, text) + + # 3. 移除多余的逗号 + text = re.sub(r",\s*}", "}", text) + text = re.sub(r",\s*]", "]", text) + + return text.strip() + + except Exception as e: + logger.error(f"JSON修复失败: {e}") + return text + + +def _parse_json_with_pattern( + result_text: str, pattern: str, data_type: str, expected_type_name: str = "数据" +) -> tuple[bool, Any, str | None]: + """ + 通用内部 JSON 解析逻辑,包含提取、直接解析、修复后重试。 + """ + fixed_json_text = None + try: + # 1. 基础清理:去除 markdown 代码块标记 + clean_text = result_text.strip() + clean_text = re.sub(r"```(?:json)?\s*", "", clean_text) + clean_text = re.sub(r"```\s*$", "", clean_text) + + # 2. 提取 JSON 部分 + json_match = re.search(pattern, clean_text, re.DOTALL) + if not json_match: + error_msg = f"{data_type}响应中未找到JSON{expected_type_name}" + logger.warning(error_msg) + return False, None, error_msg + + json_text = json_match.group() + logger.debug(f"{data_type}分析JSON原文: {json_text[:500]}...") + + # 3. 尝试直接解析 + try: + data = json.loads(json_text) + count_info = f",包含 {len(data)} 条数据" if isinstance(data, list) else "" + logger.info(f"{data_type}直接解析成功{count_info}") + return True, data, None + except json.JSONDecodeError: + logger.debug(f"{data_type}直接解析失败,尝试修复JSON...") + + # 4. 修复后重试 + fixed_json_text = fix_json(json_text) + # 修复后需要重新提取,因为 fix_json 可能会改变文本结构(例如补齐括号) + fixed_match = re.search(pattern, fixed_json_text, re.DOTALL) + if fixed_match: + try: + data = json.loads(fixed_match.group()) + count_info = ( + f",包含 {len(data)} 条数据" if isinstance(data, list) else "" + ) + logger.info(f"{data_type}修复后解析成功{count_info}") + return True, data, None + except json.JSONDecodeError as e: + error_msg = f"{data_type}JSON修复后解析仍失败: {e}" + logger.warning(error_msg) + return False, None, error_msg + + error_msg = f"{data_type}修复后未找到JSON{expected_type_name}" + return False, None, error_msg + + except Exception as e: + error_msg = f"{data_type}解析异常: {e}" + logger.error(error_msg) + return False, None, error_msg + + +def parse_json_response( + result_text: str, data_type: str +) -> tuple[bool, list[dict] | None, str | None]: + """ + 统一的JSON解析方法(用于JSON数组响应) + """ + return _parse_json_with_pattern( + result_text, r"\[.*\]", data_type, expected_type_name="数组" + ) + + +def parse_json_object_response( + result_text: str, data_type: str +) -> tuple[bool, dict | None, str | None]: + """ + 统一的JSON解析方法(用于JSON对象响应) + """ + return _parse_json_with_pattern( + result_text, r"\{.*\}", data_type, expected_type_name="对象" + ) + + +def _clean_json_string(text: str) -> str: + """ + 清理 JSON 字符串中的转义字符,用于正则提取后的数据清洗。 + """ + return text.replace('\\"', '"').replace("\\n", " ").replace("\\t", " ") + + +def extract_topics_with_regex(result_text: str, max_topics: int) -> list[dict]: + """ + 使用正则表达式提取话题信息 + + Args: + result_text: 需要提取的文本 + max_topics: 最大话题数量 + + Returns: + 话题数据列表 + """ + try: + # 更强的正则表达式提取话题信息,处理转义字符 + # 匹配每个完整的话题对象 + topic_pattern = r'\{\s*"topic":\s*"([^"]*(?:\\.[^"]*)*)"\s*,\s*"contributors":\s*\[(.*?)\],?\s*"detail":\s*"([^"]*(?:\\.[^"]*)*)"\s*\}' + matches = re.findall(topic_pattern, result_text, re.DOTALL) + + if not matches: + # 尝试更宽松的匹配 + topic_pattern = r'"topic":\s*"([^"]*(?:\\.[^"]*)*)"[^}]*"contributors":\s*\[(.*?)\][^}]*"detail":\s*"([^"]*(?:\\.[^"]*)*)"' + matches = re.findall(topic_pattern, result_text, re.DOTALL) + + topics = [] + for match in matches[:max_topics]: + topic_name = match[0].strip() + contributors_str = match[1].strip() + detail = _clean_json_string(match[2].strip()) + + # 解析参与者列表 + contributors = [ + contrib.strip() + for contrib in re.findall(r'"([^"]+)"', contributors_str) + ] or ["群友"] + + topics.append( + { + "topic": topic_name, + "contributors": contributors[:5], # 最多5个参与者 + "detail": detail, + } + ) + + logger.info(f"话题正则表达式提取成功,提取到 {len(topics)} 条有效话题内容") + return topics + + except Exception as e: + logger.error(f"话题正则表达式提取失败: {e}") + return [] + + +def extract_user_titles_with_regex(result_text: str, max_count: int) -> list[dict]: + """ + 使用正则表达式提取用户称号信息 + + Args: + result_text: 需要提取的文本 + max_count: 最大提取数量 + + Returns: + 用户称号数据列表 + """ + try: + titles = [] + + # 正则模式:匹配完整的用户称号对象 + pattern = r'\{\s*"name":\s*"([^"]*(?:\\.[^"]*)*)"\s*,\s*"user_id":\s*"([^"]+)"\s*,\s*"title":\s*"([^"]*(?:\\.[^"]*)*)"\s*,\s*"mbti":\s*"([^"]+)"\s*,\s*"reason":\s*"([^"]*(?:\\.[^"]*)*)"\s*\}' + matches = re.findall(pattern, result_text, re.DOTALL) + + if not matches: + # 尝试更宽松的匹配(字段顺序可变) + pattern = r'"name":\s*"([^"]*(?:\\.[^"]*)*)"[^}]*"user_id":\s*"([^"]+)"[^}]*"title":\s*"([^"]*(?:\\.[^"]*)*)"[^}]*"mbti":\s*"([^"]+)"[^}]*"reason":\s*"([^"]*(?:\\.[^"]*)*)"' + matches = re.findall(pattern, result_text, re.DOTALL) + + for match in matches[:max_count]: + name = match[0].strip() + user_id = match[1].strip() + title = match[2].strip() + mbti = match[3].strip() + reason = _clean_json_string(match[4].strip()) + + titles.append( + { + "name": name, + "user_id": user_id, + "title": title, + "mbti": mbti, + "reason": reason, + } + ) + + logger.info(f"用户称号正则表达式提取成功,提取到 {len(titles)} 条有效用户称号") + return titles + + except Exception as e: + logger.error(f"用户称号正则表达式提取失败: {e}") + return [] + + +def extract_golden_quotes_with_regex(result_text: str, max_count: int) -> list[dict]: + """ + 使用正则表达式提取金句信息 + + Args: + result_text: 需要提取的文本 + max_count: 最大提取数量 + + Returns: + 金句数据列表 + """ + try: + quotes = [] + + # 正则模式:匹配完整的金句对象 + pattern = r'\{\s*"content":\s*"([^"]*(?:\\.[^"]*)*)"\s*,\s*"sender":\s*"([^"]*(?:\\.[^"]*)*)"\s*,\s*"reason":\s*"([^"]*(?:\\.[^"]*)*)"\s*\}' + matches = re.findall(pattern, result_text, re.DOTALL) + + if not matches: + # 尝试更宽松的匹配(字段顺序可变) + pattern = r'"content":\s*"([^"]*(?:\\.[^"]*)*)"[^}]*"sender":\s*"([^"]*(?:\\.[^"]*)*)"[^}]*"reason":\s*"([^"]*(?:\\.[^"]*)*)"' + matches = re.findall(pattern, result_text, re.DOTALL) + + for match in matches[:max_count]: + content = _clean_json_string(match[0].strip()) + sender = match[1].strip() + reason = _clean_json_string(match[2].strip()) + + quotes.append({"content": content, "sender": sender, "reason": reason}) + + logger.info(f"金句正则表达式提取成功,提取到 {len(quotes)} 条有效金句") + return quotes + + except Exception as e: + logger.error(f"金句正则表达式提取失败: {e}") + return [] + + +def extract_quality_with_regex(result_text: str) -> dict | None: + """ + 使用正则表达式提取聊天质量分析数据 + + 当 JSON 解析失败时作为降级方案使用。 + + Args: + result_text: LLM 返回的原始文本 + + Returns: + 解析后的质量分析字典,失败返回 None + """ + try: + title_m = re.search(r'"title"\s*:\s*"([^"]*(?:\\.[^"]*)*)"', result_text) + subtitle_m = re.search(r'"subtitle"\s*:\s*"([^"]*(?:\\.[^"]*)*)"', result_text) + summary_m = re.search(r'"summary"\s*:\s*"([^"]*(?:\\.[^"]*)*)"', result_text) + + # Extract dimensions array + dims_match = re.search(r'"dimensions"\s*:\s*\[(.*)\]', result_text, re.DOTALL) + dims = [] + if dims_match: + dim_objects = re.findall( + r'\{[^}]*"name"\s*:\s*"([^"]*)"[^}]*' + r'"percentage"\s*:\s*([\d.]+)[^}]*' + r'"comment"\s*:\s*"([^"]*(?:\\.[^"]*)*)"[^}]*\}', + dims_match.group(1), + ) + for dm in dim_objects: + dims.append( + { + "name": dm[0], + "percentage": float(dm[1]), + "comment": dm[2], + } + ) + + if not dims: + logger.warning("聊天质量正则提取未找到有效维度数据") + return None + + data = { + "title": title_m.group(1) if title_m else "聊天质量锐评", + "subtitle": subtitle_m.group(1) if subtitle_m else "今天的群里发生了什么?", + "dimensions": dims, + "summary": summary_m.group(1) if summary_m else "今天也是充满活力的一天。", + } + + logger.info(f"聊天质量正则表达式提取成功,提取到 {len(dims)} 个维度") + return data + + except Exception as e: + logger.error(f"聊天质量正则表达式提取失败: {e}") + return None diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/llm_utils.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/llm_utils.py new file mode 100644 index 0000000..c9e94a3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/llm_utils.py @@ -0,0 +1,243 @@ +""" +LLM API 请求处理工具模块(NoneBot 版) + +原 AstrBot 版依赖 context.get_provider_by_id / provider.text_chat_stream。 +此文件改为直接调用 OpenAI 兼容 /chat/completions 接口: + - 端点与密钥来自 ConfigManager(llm.llm_api_base / llm.llm_api_key / llm.llm_model) + - 保留与原插件一致的外层函数名,供分析器 / 报告生成器复用 +""" + +from __future__ import annotations + +import asyncio +import json +import random +import time +from dataclasses import dataclass, field +from typing import Any + +import httpx + +from ....shared.trace_context import TraceContext +from ....utils.logger import logger +from ...config.config_manager import ConfigManager +from .structured_output_schema import JSONObject, JSONValue + + +@dataclass +class LLMResponse: + """轻量 LLM 响应对象,替代原 AstrBot 的 astrbot.api.provider.LLMResponse。""" + + role: str = "assistant" + completion_text: str = "" + usage: Any = None + raw_completion: Any = None + is_chunk: bool = False + + def __str__(self) -> str: + return self.completion_text + + +def _build_chat_url(base_url: str) -> str: + base = (base_url or "").strip().rstrip("/") + if not base: + return "" + if base.endswith("/chat/completions"): + return base + return f"{base}/chat/completions" + + +def _merge_generate_kwargs(base: dict, extra: dict | None) -> dict: + if not extra: + return base + merged = dict(base) + for k, v in extra.items(): + if k in {"stream", "stream_options"}: + continue + merged[k] = v + return merged + + +async def _call_openai( + config_manager: ConfigManager, + prompt: str, + system_prompt: str | None, + response_format: JSONObject | None, + extra_generate_kwargs: dict[str, JSONValue] | None, + allow_response_format: bool = True, +) -> LLMResponse: + base_url = config_manager.get_llm_api_base() + api_key = config_manager.get_llm_api_key() + model = config_manager.get_llm_model() + timeout = config_manager.get_llm_timeout() + if not base_url or not api_key or not model: + raise RuntimeError("LLM 配置不完整:需要 llm_api_base / llm_api_key / llm_model") + + url = _build_chat_url(base_url) + if not url: + raise RuntimeError("LLM API Base 为空,无法构造 /chat/completions 地址") + + payload: dict[str, Any] = {"model": model, "messages": []} + if system_prompt: + payload["messages"].append({"role": "system", "content": system_prompt}) + payload["messages"].append({"role": "user", "content": prompt}) + payload = _merge_generate_kwargs(payload, extra_generate_kwargs) + if response_format is not None and allow_response_format: + payload.setdefault("response_format", {"type": "json_object"}) + + headers = { + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + } + + async with httpx.AsyncClient(timeout=timeout) as client: + resp = await client.post(url, json=payload, headers=headers) + if resp.status_code >= 400: + raise RuntimeError( + f"LLM HTTP {resp.status_code}: {resp.text[:500]}" + ) + data = resp.json() + try: + content = data["choices"][0]["message"]["content"] or "" + except (KeyError, IndexError, TypeError) as e: + raise RuntimeError(f"LLM 返回结构异常: {e}; {str(data)[:500]}") from e + usage = data.get("usage") + return LLMResponse( + role="assistant", + completion_text=str(content), + usage=usage, + raw_completion=data, + ) + + +async def get_provider_id_with_fallback( + context: Any, + config_manager: ConfigManager, + provider_id_key: str | None = None, + umo: str | None = None, +) -> str | None: + """原插件用于在 AstrBot 中选择 Provider;NoneBot 版仅返回配置中的模型标识作为日志标签。""" + pid = config_manager.get_llm_provider_id() or config_manager.get_llm_model() or "default" + logger.debug(f"[Provider 选择] NoneBot 统一 LLM 通道, label={pid}") + return pid + + +async def call_provider_with_retry( + context: Any, + config_manager: ConfigManager, + prompt: str, + umo: str | None = None, + provider_id_key: str | None = None, + provider_id: str | None = None, + system_prompt: str | None = None, + response_format: JSONObject | None = None, + extra_generate_kwargs: dict[str, JSONValue] | None = None, + observation_label: str | None = None, +) -> LLMResponse | None: + """调用 OpenAI 兼容端点,带重试与退避。失败返回 None。""" + if not prompt or not prompt.strip(): + logger.error("LLM provider: prompt 为空,无法调用") + return None + + retries = max(1, int(config_manager.get_llm_retries())) + backoff = max(0, float(config_manager.get_llm_backoff())) + trace = TraceContext.current() + area = observation_label or provider_id_key or "未标注" + + last_exc: Exception | None = None + current_response_format = response_format + for attempt in range(1, retries + 1): + try: + resp = await _call_openai( + config_manager, + prompt, + system_prompt, + current_response_format, + extra_generate_kwargs, + allow_response_format=current_response_format is not None, + ) + if trace: + trace.metadata.setdefault("llm_attempts", []).append( + { + "area": area, + "attempt": attempt, + "provider_id": provider_id or "default", + "status": "success", + } + ) + return resp + except Exception as e: + last_exc = e + logger.warning( + f"[LLM 调用] {area} 第 {attempt}/{retries} 次请求失败: {e}" + ) + # response_format 不被支持时,降级去掉 schema 再试一次 + if ( + current_response_format is not None + and "response_format" in str(e).lower() + ): + logger.warning(f"[LLM 调用] {area} 关闭 response_format 重试") + current_response_format = None + try: + resp = await _call_openai( + config_manager, + prompt, + system_prompt, + None, + extra_generate_kwargs, + allow_response_format=False, + ) + if trace: + trace.metadata.setdefault("llm_attempts", []).append( + { + "area": area, + "attempt": attempt, + "provider_id": provider_id or "default", + "status": "success", + "note": "without_response_format", + } + ) + return resp + except Exception as inner_e: + last_exc = inner_e + + if attempt < retries: + sleep_time = backoff * (2 ** (attempt - 1)) + random.uniform(0, 1) + await asyncio.sleep(sleep_time) + + logger.error(f"[LLM 调用] {area} 重试耗尽,最终失败: {last_exc}") + return None + + +def extract_token_usage(response: Any) -> dict[str, int]: + """从 LLM 响应中提取 token 使用统计。""" + token_usage = {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0} + try: + usage = getattr(response, "usage", None) + if not usage and hasattr(response, "raw_completion"): + raw = response.raw_completion + usage = raw.get("usage") if isinstance(raw, dict) else getattr(raw, "usage", None) + if usage: + if isinstance(usage, dict): + token_usage["prompt_tokens"] = usage.get("prompt_tokens", 0) or 0 + token_usage["completion_tokens"] = usage.get("completion_tokens", 0) or 0 + token_usage["total_tokens"] = usage.get("total_tokens", 0) or 0 + else: + token_usage["prompt_tokens"] = getattr(usage, "prompt_tokens", 0) or 0 + token_usage["completion_tokens"] = getattr(usage, "completion_tokens", 0) or 0 + token_usage["total_tokens"] = getattr(usage, "total_tokens", 0) or 0 + return token_usage + except Exception as e: + logger.error(f"提取 token 使用统计失败: {e}") + return {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0} + + +def extract_response_text(response: Any) -> str: + """从 LLM 响应中提取文本内容。""" + try: + if hasattr(response, "completion_text"): + return response.completion_text + return str(response) + except Exception as e: + logger.error(f"提取响应文本失败: {e}") + return "" diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/response_validation.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/response_validation.py new file mode 100644 index 0000000..b5ebbbe --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/response_validation.py @@ -0,0 +1,127 @@ +from __future__ import annotations + +from pydantic import BaseModel, ConfigDict, ValidationError, field_validator + + +class TopicItemModel(BaseModel): + model_config = ConfigDict(extra="forbid") + + topic: str + contributors: list[str] + detail: str + + @field_validator("topic", "detail", mode="before") + @classmethod + def _normalize_text(cls, value: object) -> str: + return str(value).strip() + + @field_validator("contributors", mode="before") + @classmethod + def _normalize_contributors(cls, value: object) -> list[str]: + if not isinstance(value, list): + return [] + contributors: list[str] = [] + for item in value: + text = str(item).strip() + if text: + contributors.append(text) + return contributors + + +class UserTitleItemModel(BaseModel): + model_config = ConfigDict(extra="forbid") + + name: str + user_id: str + title: str + mbti: str + reason: str + + @field_validator("name", "user_id", "title", "mbti", "reason", mode="before") + @classmethod + def _normalize_text(cls, value: object) -> str: + return str(value).strip() + + +class GoldenQuoteItemModel(BaseModel): + model_config = ConfigDict(extra="forbid") + + content: str + sender: str + reason: str + + @field_validator("content", "sender", "reason", mode="before") + @classmethod + def _normalize_text(cls, value: object) -> str: + return str(value).strip() + + +class QualityDimensionModel(BaseModel): + model_config = ConfigDict(extra="forbid") + + name: str + percentage: float + comment: str + + @field_validator("name", "comment", mode="before") + @classmethod + def _normalize_text(cls, value: object) -> str: + return str(value).strip() + + +class QualityReviewModel(BaseModel): + model_config = ConfigDict(extra="forbid") + + title: str + subtitle: str + dimensions: list[QualityDimensionModel] + summary: str + + @field_validator("title", "subtitle", "summary", mode="before") + @classmethod + def _normalize_text(cls, value: object) -> str: + return str(value).strip() + + +def validate_topic_items( + data_list: list[dict], +) -> tuple[bool, list[dict] | None, str | None]: + try: + normalized = [ + TopicItemModel.model_validate(item).model_dump() for item in data_list + ] + return True, normalized, None + except ValidationError as e: + return False, None, str(e) + + +def validate_user_title_items( + data_list: list[dict], +) -> tuple[bool, list[dict] | None, str | None]: + try: + normalized = [ + UserTitleItemModel.model_validate(item).model_dump() for item in data_list + ] + return True, normalized, None + except ValidationError as e: + return False, None, str(e) + + +def validate_golden_quote_items( + data_list: list[dict], +) -> tuple[bool, list[dict] | None, str | None]: + try: + normalized = [ + GoldenQuoteItemModel.model_validate(item).model_dump() for item in data_list + ] + return True, normalized, None + except ValidationError as e: + return False, None, str(e) + + +def validate_quality_review_item(data: dict) -> tuple[bool, dict | None, str | None]: + try: + normalized = QualityReviewModel.model_validate(data).model_dump() + return True, normalized, None + except ValidationError as e: + return False, None, str(e) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/structured_output_schema.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/structured_output_schema.py new file mode 100644 index 0000000..2509ac8 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/analysis/utils/structured_output_schema.py @@ -0,0 +1,101 @@ +from __future__ import annotations + +from typing import TypeAlias + +JSONScalar: TypeAlias = str | int | float | bool | None +JSONValue: TypeAlias = JSONScalar | dict[str, "JSONValue"] | list["JSONValue"] +JSONObject: TypeAlias = dict[str, JSONValue] + + +def build_response_format(name: str, schema: JSONObject) -> JSONObject: + return { + "type": "json_schema", + "json_schema": { + "name": name, + "strict": True, + "schema": schema, + }, + } + + +def build_topics_schema(max_items: int) -> JSONObject: + return { + "type": "array", + "maxItems": max(1, int(max_items)), + "items": { + "type": "object", + "properties": { + "topic": {"type": "string"}, + "contributors": { + "type": "array", + "items": {"type": "string"}, + }, + "detail": {"type": "string"}, + }, + "required": ["topic", "contributors", "detail"], + "additionalProperties": False, + }, + } + + +def build_user_titles_schema(max_items: int) -> JSONObject: + return { + "type": "array", + "maxItems": max(1, int(max_items)), + "items": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "user_id": {"type": "string"}, + "title": {"type": "string"}, + "mbti": {"type": "string"}, + "reason": {"type": "string"}, + }, + "required": ["name", "user_id", "title", "mbti", "reason"], + "additionalProperties": False, + }, + } + + +def build_golden_quotes_schema(max_items: int) -> JSONObject: + return { + "type": "array", + "maxItems": max(1, int(max_items)), + "items": { + "type": "object", + "properties": { + "content": {"type": "string"}, + "sender": {"type": "string"}, + "reason": {"type": "string"}, + }, + "required": ["content", "sender", "reason"], + "additionalProperties": False, + }, + } + + +def build_chat_quality_schema(max_dimensions: int) -> JSONObject: + return { + "type": "object", + "properties": { + "title": {"type": "string"}, + "subtitle": {"type": "string"}, + "dimensions": { + "type": "array", + "maxItems": max(1, int(max_dimensions)), + "items": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "percentage": {"type": "number"}, + "comment": {"type": "string"}, + }, + "required": ["name", "percentage", "comment"], + "additionalProperties": False, + }, + }, + "summary": {"type": "string"}, + }, + "required": ["title", "subtitle", "dimensions", "summary"], + "additionalProperties": False, + } diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/config/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/config/__init__.py new file mode 100644 index 0000000..e814246 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/config/__init__.py @@ -0,0 +1,7 @@ +""" +Config Module - Configuration management +""" + +from .config_manager import ConfigManager + +__all__ = ["ConfigManager"] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/config/config_manager.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/config/config_manager.py new file mode 100644 index 0000000..f3607bd --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/config/config_manager.py @@ -0,0 +1,1724 @@ +""" +配置管理模块 - 基础设施层 +负责处理插件配置 +""" + +import hashlib +import json +import os +import random +import re +import shutil +from datetime import datetime +from pathlib import Path +from zoneinfo import ZoneInfo, ZoneInfoNotFoundError + +from ...shared.constants import PLUGIN_NAME +from ...utils.logger import logger +from ...utils.paths import get_data_dir +from ..utils.template_utils import upgrade_str_format_template + + +class ConfigManager: + """配置管理器 + + 配置结构采用分组嵌套方式,顶层分为以下分组: + - basic: 基础设置 + - qq_official: QQ 官方机器人展示设置 + - auto_analysis: 自动分析设置 + - llm: LLM 设置 + - analysis_features: 分析功能开关 + - incremental: 增量分析设置 + - prompts: 提示词模板 + """ + + def __init__(self, config): + self.config = config + self._migrate_daily_comic_characters() + self._migrate_daily_comic_character_prompts() + self._protect_upgrade_data() + + def _protect_upgrade_data(self) -> None: + """在插件升级时备份发生结构变更的旧配置,并保护用户修改的模板。""" + plugin_root = self._get_plugin_root() + current_version = self._get_plugin_version(plugin_root) + current_schema_fingerprint = self._get_schema_fingerprint(plugin_root) + state_path = ( + get_data_dir(PLUGIN_NAME) / "upgrade_protection_state.json" + ) + previous_state = self._read_upgrade_protection_state(state_path) + previous_version = str(previous_state.get("version", "")).strip() + version_changed = bool(previous_version and previous_version != current_version) + + if not previous_state: + logger.debug("升级保护基线已建立,后续配置结构变化时可备份本次快照。") + + if previous_state.get( + "schema_fingerprint" + ) != current_schema_fingerprint and isinstance( + previous_state.get("config"), dict + ): + if not self._write_upgrade_config_backup( + previous_state["config"], previous_version + ): + logger.warning("插件旧配置备份失败,本次不会更新升级保护状态。") + return + + template_hashes = self._protect_custom_t2i_templates( + plugin_root, + previous_state.get("template_hashes", {}), + version_changed, + bool(previous_state), + ) + self._save_upgrade_protection_state( + state_path, + { + "version": current_version, + "schema_fingerprint": current_schema_fingerprint, + "config": dict(self.config), + "template_hashes": template_hashes, + }, + ) + + @staticmethod + def _get_plugin_root() -> Path: + """获取插件根目录。""" + return Path(__file__).resolve().parents[3] + + @staticmethod + def _get_plugin_version(plugin_root: Path) -> str: + """从 metadata.yaml 读取当前插件版本。""" + try: + metadata = (plugin_root / "metadata.yaml").read_text(encoding="utf-8") + match = re.search(r"^version:\s*([^\s#]+)", metadata, re.MULTILINE) + if match: + return match.group(1) + except OSError as exc: + logger.warning(f"读取插件版本失败,将使用未知版本标识: {exc}") + return "unknown" + + @staticmethod + def _get_schema_fingerprint(plugin_root: Path) -> str: + """计算配置结构指纹,忽略描述等纯界面字段。""" + try: + schema = json.loads( + (plugin_root / "_conf_schema.json").read_text(encoding="utf-8-sig") + ) + except (OSError, json.JSONDecodeError) as exc: + logger.warning(f"读取插件配置结构失败: {exc}") + return "" + + def extract_shape(items: dict) -> dict: + shape = {} + for key, item in items.items(): + if not isinstance(item, dict): + continue + entry = {"type": item.get("type")} + for property_name in ("default", "options", "file_types"): + if property_name in item: + entry[property_name] = item[property_name] + if isinstance(item.get("items"), dict): + entry["items"] = extract_shape(item["items"]) + if isinstance(item.get("templates"), dict): + entry["templates"] = { + template_key: extract_shape(template.get("items", {})) + for template_key, template in item["templates"].items() + if isinstance(template, dict) + } + shape[key] = entry + return shape + + serialized_shape = json.dumps( + extract_shape(schema), + ensure_ascii=False, + sort_keys=True, + separators=(",", ":"), + ) + return hashlib.sha256(serialized_shape.encode("utf-8")).hexdigest() + + @staticmethod + def _read_upgrade_protection_state(state_path: Path) -> dict: + """读取上一次正常启动记录的升级保护状态。""" + try: + state = json.loads(state_path.read_text(encoding="utf-8")) + return state if isinstance(state, dict) else {} + except (OSError, json.JSONDecodeError): + return {} + + @staticmethod + def _save_upgrade_protection_state(state_path: Path, state: dict) -> None: + """原子保存升级保护状态。""" + try: + state_path.parent.mkdir(parents=True, exist_ok=True) + temporary_path = state_path.with_suffix(".tmp") + temporary_path.write_text( + json.dumps(state, ensure_ascii=False, indent=2), encoding="utf-8" + ) + temporary_path.replace(state_path) + except OSError as exc: + logger.warning(f"保存插件升级保护状态失败: {exc}") + + def _write_upgrade_config_backup(self, config: dict, version: str) -> bool: + """保存旧版本配置快照,并最多保留二十份。 + + Args: + config: 上一次正常加载时记录的插件配置快照。 + version: 该配置快照对应的旧插件版本。 + + Returns: + 备份写入并完成轮换时返回 True,否则返回 False。 + """ + try: + backup_dir = get_data_dir(PLUGIN_NAME) / "config_backups" + backup_dir.mkdir(parents=True, exist_ok=True) + safe_version = re.sub(r"[^A-Za-z0-9._-]", "_", version) or "unknown" + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f") + backup_path = backup_dir / f"plugin_config_{safe_version}_{timestamp}.json" + backup_path.write_text( + json.dumps( + { + "backed_up_at": datetime.now().isoformat(), + "plugin_version": version, + "config": config, + }, + ensure_ascii=False, + indent=2, + ), + encoding="utf-8", + ) + backups = sorted( + backup_dir.glob("plugin_config_*.json"), + key=lambda path: (path.stat().st_mtime, path.name), + ) + for expired_backup in backups[:-20]: + expired_backup.unlink() + logger.info( + "检测到插件配置结构变化,已备份上一次正常启动保存的配置快照:" + f"旧版本={version},文件={backup_path.name},路径={backup_path.resolve()}," + f"当前保留={min(len(backups), 20)} 份。" + ) + return True + except OSError as exc: + logger.warning(f"备份插件旧配置失败: {exc}") + return False + + def _protect_custom_t2i_templates( + self, + plugin_root: Path, + previous_hashes: object, + version_changed: bool, + has_previous_state: bool, + ) -> dict[str, str]: + """将本版本内用户改动过的 T2I 模板保存到插件数据目录。 + + Args: + plugin_root: 当前插件根目录。 + previous_hashes: 上一次启动记录的官方或用户模板哈希。 + version_changed: 当前版本是否已发生变化。 + has_previous_state: 是否已有上一次启动的完整状态。 + + Returns: + 本次启动读取到的模板哈希。 + """ + known_hashes = previous_hashes if isinstance(previous_hashes, dict) else {} + template_roots = { + "reporting_templates": plugin_root + / "src/infrastructure/reporting/templates", + "standalone_templates": plugin_root / "data/t2i_templates", + } + current_hashes = {} + plugin_data_dir = get_data_dir(PLUGIN_NAME) + for category, template_root in template_roots.items(): + if not template_root.is_dir(): + continue + for template_path in template_root.rglob("*.html"): + relative_path = template_path.relative_to(template_root) + state_key = f"{category}/{relative_path.as_posix()}" + try: + content_hash = hashlib.sha256( + template_path.read_bytes() + ).hexdigest() + except OSError as exc: + logger.warning( + f"读取 T2I 模板失败,跳过保护: {template_path}: {exc}" + ) + continue + is_standalone_template = category == "standalone_templates" + if ( + (not has_previous_state and not is_standalone_template) + or (version_changed and not is_standalone_template) + or known_hashes.get(state_key) == content_hash + ): + current_hashes[state_key] = content_hash + continue + + backup_path = plugin_data_dir / "custom_t2i_templates" / state_key + try: + backup_path.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(template_path, backup_path) + current_hashes[state_key] = content_hash + logger.info(f"已保护用户修改的 T2I 模板: {relative_path}") + except OSError as exc: + if state_key in known_hashes: + current_hashes[state_key] = known_hashes[state_key] + logger.warning(f"保存用户 T2I 模板失败: {template_path}: {exc}") + return current_hashes + + def get_custom_report_template_dir(self, template_name: str) -> Path | None: + """获取指定报告模板的用户覆盖目录。""" + custom_dir = ( + get_data_dir(PLUGIN_NAME) + / "custom_t2i_templates/reporting_templates" + / template_name + ) + return custom_dir if custom_dir.is_dir() else None + + def _migrate_daily_comic_characters(self) -> None: + """迁移旧版漫画参考图配置,并保存迁移前备份。 + + 旧版仅支持一个全局参考图列表;新版将参考图归属到具体角色方案。 + 迁移只在尚未创建角色方案时执行,避免覆盖用户已编辑的新配置。 + """ + daily_comic = self._get_group("daily_comic") + old_references = daily_comic.get("drawing_reference_image", []) + characters = daily_comic.get("comic_characters", []) + if isinstance(characters, list) and characters: + return + + if isinstance(old_references, str): + # 早期版本允许 URL 或任意本地路径,原生文件控件不能安全地继续使用它们。 + backup_data = {"drawing_reference_image": old_references} + if not self._write_comic_config_backup(backup_data): + logger.warning( + "旧版漫画参考图备份失败,将保留原配置并在下次重载时重试。" + ) + return + daily_comic["drawing_reference_image"] = [] + self.config.save_config() + logger.info( + "已备份并清除不受支持的旧版漫画参考图配置,请在 WebUI 重新选择图片。" + ) + return + + references = ( + [ + reference.strip() + for reference in old_references + if isinstance(reference, str) and reference.strip() + ] + if isinstance(old_references, list) + else [] + ) + if not references: + return + + specific_persona_id = "" + if self.get_use_plugin_specific_persona(): + specific_persona_id = self.get_plugin_specific_persona_id().strip() + migrated_references = self._copy_legacy_comic_reference_images(references) + if len(migrated_references) != len(references): + logger.warning( + "旧版漫画参考图尚未完整迁移,将保留原配置并在下次重载时重试。" + ) + return + backup_data = { + "drawing_reference_image": references, + "use_plugin_specific_persona": self.get_use_plugin_specific_persona(), + "plugin_specific_persona_id": specific_persona_id, + } + if not self._write_comic_config_backup(backup_data): + logger.warning("旧版漫画参考图备份失败,将保留原配置并在下次重载时重试。") + return + daily_comic["comic_characters"] = [ + { + "__template_key": "character", + "name": "默认角色方案", + "enable": True, + "persona_id": specific_persona_id, + "reference_images": migrated_references, + "storyboard_prompt": self.get_comic_storyboard_prompt(), + } + ] + # 已迁移的数据不再保留在兼容字段,避免用户主动清空角色方案后被重复迁移。 + daily_comic["drawing_reference_image"] = [] + self.config.save_config() + logger.info( + "已将旧版漫画参考图迁移到“默认角色方案”,原始配置已备份到插件数据目录。" + ) + + def _migrate_daily_comic_character_prompts(self) -> None: + """将旧版全局分镜提示词复制到既有角色方案。""" + state_path = ( + get_data_dir(PLUGIN_NAME) + / "comic_character_prompt_migration.json" + ) + if state_path.exists(): + return + + daily_comic = self._get_group("daily_comic") + characters = daily_comic.get("comic_characters", []) + default_prompt = self.get_comic_storyboard_prompt() + modified = False + if isinstance(characters, list): + for character in characters: + if not isinstance(character, dict): + continue + if not str(character.get("storyboard_prompt", "")).strip(): + character["storyboard_prompt"] = default_prompt + modified = True + + try: + if modified: + self.config.save_config() + logger.info("已将默认漫画场景分析提示词迁移到既有角色方案。") + state_path.parent.mkdir(parents=True, exist_ok=True) + state_path.write_text(json.dumps({"completed": True}), encoding="utf-8") + except OSError as exc: + logger.warning(f"迁移漫画角色场景提示词失败,将在下次重载时重试: {exc}") + + def _write_comic_config_backup(self, data: dict) -> bool: + """写入漫画配置迁移备份。 + + Args: + data: 需要保留的旧版漫画相关配置。 + + Returns: + 备份写入是否成功。 + """ + try: + backup_dir = get_data_dir(PLUGIN_NAME) / "config_backups" + backup_dir.mkdir(parents=True, exist_ok=True) + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + backup_path = backup_dir / f"comic_character_migration_{timestamp}.json" + backup_path.write_text( + json.dumps( + { + "migrated_at": datetime.now().isoformat(), + "config": data, + }, + ensure_ascii=False, + indent=2, + ), + encoding="utf-8", + ) + return True + except OSError as exc: + logger.warning(f"保存漫画配置迁移备份失败: {exc}") + return False + + def _copy_legacy_comic_reference_images(self, references: list[str]) -> list[str]: + """复制旧参考图到角色模板对应的原生上传目录。 + + AstrBot 会校验 file 类型配置的路径前缀。旧字段与模板字段的目录不同, + 因此不能只复用旧路径字符串,否则用户在 WebUI 保存时会校验失败。 + + Args: + references: 旧版全局参考图相对路径列表。 + + Returns: + 可写入新角色方案的参考图相对路径列表。 + """ + plugin_data_dir = get_data_dir(PLUGIN_NAME) + relative_dir = Path( + "files/daily_comic/comic_characters/templates/character/reference_images" + ) + target_dir = plugin_data_dir / relative_dir + migrated_references = [] + for index, reference in enumerate(references, start=1): + try: + source_path = (plugin_data_dir / reference).resolve() + source_path.relative_to(plugin_data_dir.resolve()) + if not source_path.is_file(): + logger.warning(f"旧版漫画参考图不存在,跳过迁移: {reference}") + continue + + target_dir.mkdir(parents=True, exist_ok=True) + target_name = f"migrated_{index}_{source_path.name}" + target_path = target_dir / target_name + shutil.copy2(source_path, target_path) + migrated_references.append((relative_dir / target_name).as_posix()) + except (OSError, ValueError) as exc: + logger.warning(f"迁移旧版漫画参考图失败 {reference}: {exc}") + return migrated_references + + def _get_group(self, group: str) -> dict: + """获取指定分组的配置字典,不存在时返回空字典""" + return self.config.get(group, {}) + + def _ensure_group(self, group: str) -> dict: + """确保指定分组存在并返回其字典引用""" + if group not in self.config: + self.config[group] = {} + return self.config[group] + + def get_group_list_mode(self) -> str: + """获取群组列表模式 (whitelist/blacklist/none)""" + return self._get_group("basic").get("group_list_mode", "none") + + def get_group_list(self) -> list[str]: + """获取群组列表(用于黑白名单)""" + return self._get_group("basic").get("group_list", []) + + def is_group_allowed(self, group_id_or_umo: str) -> bool: + """ + 根据配置的白/黑名单判断是否允许在该群聊中使用 + 支持传入 simple group_id 或 UMO (Unified Message Origin) + """ + mode = self.get_group_list_mode().lower() + if mode not in ("whitelist", "blacklist", "none"): + mode = "none" + + if mode == "none": + return True + + glist = [str(g).strip() for g in self.get_group_list()] + target = str(group_id_or_umo).strip() + + is_in_list = any(self._is_group_match(target, item) for item in glist) + + if mode == "whitelist": + return is_in_list + if mode == "blacklist": + return not is_in_list + + return True + + def _is_group_match(self, target: str, item: str) -> bool: + """ + 核心匹配逻辑:判断名单中的 item 是否匹配目标的 target (Unified Message Origin, UMO 或 纯 ID)。 + 支持处理 Telegram 话题 (#) 和 独立隔离会话 (_) 的双向穿透匹配。 + """ + if item == target: + return True + + # 分解目标 UMO 的前缀和 ID 部分 (如 default:GroupMessage:ID) + if ":" in target: + target_prefix, target_id = target.rsplit(":", 1) + else: + target_prefix, target_id = "", target + + # 生成目标 ID 的所有“穿透”候选 (处理隔离模式和话题) + candidates = {target_id} + if "#" in target_id: + candidates.add(target_id.split("#", 1)[0]) + if "_" in target_id: + for part in target_id.split("_"): + candidates.add(part) + + # 检查名单项 (item) 的格式 + if ":" in item: + i_prefix, i_id = item.rsplit(":", 1) + # 名单项带前缀时,前缀必须匹配 (如果 target 本身没前缀,则允许作为跨平台通用 ID 匹配) + if target_prefix and i_prefix != target_prefix: + return False + else: + i_id = item + + # [修复] 名单项 ID 也可能包含复合形式 (如 UserId_GroupId),需要拆解匹配 + item_variants = {i_id} + if "#" in i_id: + item_variants.add(i_id.split("#", 1)[0]) + if "_" in i_id: + for part in i_id.split("_"): + item_variants.add(part) + + # 只要两边的 ID “核心部分”存在交集,即视为匹配成功 + return not item_variants.isdisjoint(candidates) + + def get_max_messages(self) -> int: + """获取最大消息数量""" + return self._get_group("basic").get("max_messages", 1000) + + def get_analysis_days(self) -> int: + """获取分析天数""" + return self._get_group("basic").get("analysis_days", 1) + + def get_auto_analysis_time(self) -> list[str]: + """获取自动分析时间列表""" + group = self._get_group("auto_analysis") + val = group.get("auto_analysis_time", ["09:00"]) + # 兼容旧版本字符串配置 + if isinstance(val, str): + val_list = [val] + # 自动修复配置格式 + try: + auto_group = self._ensure_group("auto_analysis") + auto_group["auto_analysis_time"] = val_list + self.config.save_config() + logger.info(f"自动修复配置格式 auto_analysis_time: {val} -> {val_list}") + except Exception as e: + logger.warning(f"修复配置格式失败: {e}") + return val_list + return val if isinstance(val, list) else ["09:00"] + + def get_enable_auto_analysis(self) -> bool: + """ + 获取是否启用自动分析(兼容旧接口)。 + + 旧版本使用 auto_analysis.enable_auto_analysis 布尔值; + 新版本改为由 scheduled_group_list_mode + scheduled_group_list 推导。 + """ + return self.is_auto_analysis_enabled() + + def get_output_format(self) -> list[str]: + """获取输出格式""" + val = self._get_group("basic").get("output_format", ["image"]) + return val if isinstance(val, list) else [val] + + def get_qq_official_t2i_summary_dashboard_enabled(self) -> bool: + """是否启用 QQ 官方 T2I 概览图。""" + group = self._get_group("qq_official") + if "enable_t2i_summary_dashboard" in group: + return bool(group["enable_t2i_summary_dashboard"]) + return bool(group.get("enable_t2i_activity_histogram", True)) + + def get_min_messages_threshold(self) -> int: + """获取最小消息阈值""" + return self._get_group("basic").get("min_messages_threshold", 50) + + def get_topic_analysis_enabled(self) -> bool: + """获取是否启用话题分析""" + return self._get_group("analysis_features").get("topic_analysis_enabled", True) + + def get_user_title_analysis_enabled(self) -> bool: + """获取是否启用用户称号分析""" + return self._get_group("analysis_features").get( + "user_title_analysis_enabled", True + ) + + def get_golden_quote_analysis_enabled(self) -> bool: + """获取是否启用金句分析""" + return self._get_group("analysis_features").get( + "golden_quote_analysis_enabled", True + ) + + def get_chat_quality_analysis_enabled(self) -> bool: + """获取是否启用聊天质量分析""" + return self._get_group("analysis_features").get( + "chat_quality_analysis_enabled", False + ) + + def get_max_topics(self) -> int: + """获取最大话题数量""" + return self._get_group("analysis_features").get("max_topics", 5) + + def get_max_user_titles(self) -> int: + """获取最大用户称号数量""" + return self._get_group("analysis_features").get("max_user_titles", 8) + + def get_max_golden_quotes(self) -> int: + """获取最大金句数量""" + return self._get_group("analysis_features").get("max_golden_quotes", 5) + + def get_llm_retries(self) -> int: + """获取LLM请求重试次数""" + return self._get_group("llm").get("llm_retries", 2) + + def get_llm_backoff(self) -> int: + """获取LLM请求重试退避基值(秒),实际退避会乘以尝试次数""" + return self._get_group("llm").get("llm_backoff", 2) + + def get_enable_streaming_llm_call(self) -> bool: + """获取是否启用流式 LLM 调用""" + return self._get_group("llm").get("enable_streaming_llm_call", False) + + def get_debug_mode(self) -> bool: + """获取是否启用调试模式""" + return self._get_group("basic").get("debug_mode", False) + + def get_enable_base64_image(self) -> bool: + """获取是否启用 Base64 图片传输""" + return self._get_group("basic").get("enable_base64_image", False) + + def get_napcat_stream_threshold_mb(self) -> float: + """获取可触发 NapCat 流式上传兜底的本地图片最小大小。""" + value = self._get_group("basic").get("napcat_stream_threshold_mb", 2.0) + try: + return max(0.0, float(value)) + except (TypeError, ValueError): + return 0.0 + + def get_t2i_rendering_strategies(self) -> list[dict]: + """获取用户配置的两轮 T2I 渲染策略""" + group = self._get_group("t2i_rendering") + viewport_width = max(1, int(group.get("t2i_viewport_width", 1440))) + viewport_height = max(1, int(group.get("t2i_viewport_height", 900))) + + return [ + # 第一轮:质量优先 + { + "full_page": True, + "type": group.get("t2i_r1_type", "png"), + "quality": group.get("t2i_r1_quality", 100), + "device_scale_factor_level": group.get("t2i_r1_device_scale", "ultra"), + "timeout": group.get("t2i_r1_timeout", 30000), + "viewport_width": viewport_width, + "viewport_height": viewport_height, + }, + # 第二轮:稳定性/回退优先 + { + "full_page": True, + "type": group.get("t2i_r2_type", "jpeg"), + "quality": group.get("t2i_r2_quality", 80), + "device_scale_factor_level": group.get("t2i_r2_device_scale", "normal"), + "timeout": group.get("t2i_r2_timeout", 60000), + "viewport_width": viewport_width, + "viewport_height": viewport_height, + }, + ] + + def get_t2i_font_source(self) -> str: + """获取 T2I 字体源 (Mainland/Overseas)""" + return self._get_group("t2i_rendering").get("t2i_font_source", "Overseas") + + def get_t2i_google_fonts_mirror(self) -> str: + """根据环境选择获取 Google Fonts 镜像地址""" + source = self.get_t2i_font_source() + group = self._get_group("t2i_rendering") + if source == "Mainland": + return group.get("t2i_mainland_google_fonts", "https://fonts.loli.net") + return group.get("t2i_overseas_google_fonts", "https://fonts.googleapis.com") + + def get_t2i_gstatic_mirror(self) -> str: + """根据环境选择获取 Gstatic 镜像地址""" + source = self.get_t2i_font_source() + group = self._get_group("t2i_rendering") + if source == "Mainland": + return group.get("t2i_mainland_gstatic", "https://gstatic.loli.net") + return group.get("t2i_overseas_gstatic", "https://fonts.gstatic.com") + + def get_t2i_atri_font_mirror(self) -> str: + """获取 ATRI 主题字体镜像地址 (目前保持不变,如有需要可后续添加 Mainland/Overseas 配置)""" + return self._get_group("t2i_rendering").get( + "t2i_atri_font_mirror", "https://tc.ciallo.ccwu.cc" + ) + + def get_llm_provider_id(self) -> str: + """获取主 LLM Provider ID""" + return self._get_group("llm").get("llm_provider_id", "") + + def get_topic_provider_id(self) -> str: + """获取话题分析专用 Provider ID""" + return self._get_group("llm").get("topic_provider_id", "") + + def get_user_title_provider_id(self) -> str: + """获取用户称号分析专用 Provider ID""" + return self._get_group("llm").get("user_title_provider_id", "") + + def get_golden_quote_provider_id(self) -> str: + """获取金句分析专用 Provider ID""" + return self._get_group("llm").get("golden_quote_provider_id", "") + + def get_quality_provider_id(self) -> str: + """获取聊天质量分析专用 Provider ID""" + return self._get_group("llm").get("quality_provider_id", "") + + def get_drawing_prompt_provider_id(self) -> str: + """获取画图提示词专用 Provider ID""" + return self._get_group("llm").get("drawing_prompt_provider_id", "") + + def get_llm_api_base(self) -> str: + """NoneBot 版:OpenAI 兼容 API 基础地址""" + return self._get_group("llm").get("llm_api_base", "") + + def get_llm_api_key(self) -> str: + """NoneBot 版:API Key""" + return self._get_group("llm").get("llm_api_key", "") + + def get_llm_model(self) -> str: + """NoneBot 版:模型名称""" + return self._get_group("llm").get("llm_model", "") + + def get_llm_timeout(self) -> int: + """NoneBot 版:单次请求超时秒数""" + return int(self._get_group("llm").get("llm_timeout", 120)) + + def get_llm_temperature(self) -> float | None: + """NoneBot 版:默认 temperature(None 表示交给请求方)""" + return self._get_group("llm").get("llm_temperature", None) + + def get_keep_original_persona(self) -> bool: + """获取是否继承会话原始人格设定""" + return self._get_group("analysis_features").get("keep_original_persona", False) + + def get_use_plugin_specific_persona(self) -> bool: + """获取是否强制使用插件指定的人格设定""" + return self._get_group("analysis_features").get( + "use_plugin_specific_persona", False + ) + + def get_plugin_specific_persona_id(self) -> str: + """获取插件指定的全局人格 ID (通过 select_persona 接口选择)""" + return self._get_group("analysis_features").get( + "plugin_specific_persona_id", "" + ) + + def get_bot_self_ids(self) -> list: + """获取机器人自身的 ID 列表 (兼容 bot_qq_ids)""" + basic = self._get_group("basic") + ids = basic.get("bot_self_ids", []) + if not ids: + ids = basic.get("bot_qq_ids", []) + return ids + + def get_filter_bot_messages(self) -> bool: + """获取是否过滤机器人自己的消息。""" + return self._get_group("basic").get("filter_bot_messages", True) + + def set_filter_bot_messages(self, enabled: bool): + """设置是否过滤机器人自己的消息。""" + self._ensure_group("basic")["filter_bot_messages"] = enabled + self.config.save_config() + + def get_html_output_dir(self) -> str: + """获取HTML输出目录""" + + default_path = get_data_dir(PLUGIN_NAME) / "self_hosted_html_reports" + val = self._get_group("html").get("html_output_dir") + return val if val else str(default_path) + + def get_html_base_url(self) -> str: + """获取HTML外链Base URL""" + return self._get_group("html").get("html_base_url", "") + + def get_html_only_url(self) -> bool: + """获取是否仅输出外链而不发送文件本体""" + return self._get_group("html").get("html_only_url", False) + + def set_html_only_url(self, enabled: bool): + """设置是否仅输出外链而不发送文件本体""" + self._ensure_group("html")["html_only_url"] = enabled + self.config.save_config() + + def get_html_filename_format(self) -> str: + """获取HTML文件名格式""" + return self._get_group("html").get( + "html_filename_format", "群聊分析报告_${group_id}_${date}_${ulid}.html" + ) + + def get_topic_analysis_prompt(self, style: str = "topic_prompt") -> str: + """获取话题分析提示词模板""" + prompts_config = self._get_group("prompts").get("topic_analysis_prompts", {}) + prompt = prompts_config.get(style, "") + if prompt: + return prompt + return "" + + def get_user_title_analysis_prompt(self, style: str = "user_title_prompt") -> str: + """获取用户称号分析提示词模板""" + prompts_config = self._get_group("prompts").get( + "user_title_analysis_prompts", {} + ) + prompt = prompts_config.get(style, "") + if prompt: + return prompt + return "" + + def get_golden_quote_analysis_prompt( + self, style: str = "golden_quote_v2_prompt" + ) -> str: + """获取金句分析提示词模板""" + prompts_config = self._get_group("prompts").get( + "golden_quote_analysis_prompts", {} + ) + prompt = prompts_config.get(style, "") + if prompt: + return prompt + return "" + + def get_quality_analysis_prompt(self, style: str = "quality_v2_prompt") -> str: + """获取聊天质量分析提示词模板""" + prompts_config = self._get_group("prompts").get("quality_analysis_prompts", {}) + prompt = prompts_config.get(style, "") + if prompt: + return prompt + return "" + + def set_quality_analysis_prompt(self, prompt: str): + """设置聊天质量分析提示词模板""" + prompts = self._ensure_group("prompts") + if "quality_analysis_prompts" not in prompts: + prompts["quality_analysis_prompts"] = {} + prompts["quality_analysis_prompts"]["quality_v2_prompt"] = prompt + self.config.save_config() + + def _upgrade_config_item(self, group: str, key: str, setter_func): + """升级指定配置项的值(从 str.format -> string.Template),并回写。""" + # 如果是 prompts,则先取 prompts 分组,再取子分组 (group) + if group in ( + "quality_analysis_prompts", + "topic_analysis_prompts", + "user_title_analysis_prompts", + "golden_quote_analysis_prompts", + "comic_analysis_prompts", + ): + target_group = self._get_group("prompts").get(group, {}) + else: + target_group = self._get_group(group) + + val = target_group.get(key, "") + if not val or not isinstance(val, str): + return False + + upgraded_val, upgraded = upgrade_str_format_template(val) + if upgraded and upgraded_val != val: + setter_func(upgraded_val) + logger.info( + f"配置项 {group}.{key} 发现旧版语法并已自动升级为 string.Template 格式。" + ) + return True + return False + + def upgrade_prompt_templates(self): + """启动时调用,扫描并升级所有可配置的模板(含 prompt 和文件名)。""" + modified = False + # 1. 提示词模板升级 + modified |= self._upgrade_config_item( + "quality_analysis_prompts", + "quality_v2_prompt", + self.set_quality_analysis_prompt, + ) + modified |= self._upgrade_config_item( + "quality_analysis_prompts", + "quality_summary_prompt", + self.set_quality_summary_prompt, + ) + modified |= self._upgrade_config_item( + "topic_analysis_prompts", + "topic_prompt", + self.set_topic_analysis_prompt, + ) + modified |= self._upgrade_config_item( + "user_title_analysis_prompts", + "user_title_prompt", + self.set_user_title_analysis_prompt, + ) + modified |= self._upgrade_config_item( + "golden_quote_analysis_prompts", + "golden_quote_v2_prompt", + self.set_golden_quote_analysis_prompt, + ) + modified |= self._upgrade_config_item( + "comic_analysis_prompts", + "comic_storyboard_prompt", + self.set_comic_storyboard_prompt, + ) + + # 2. 文件名格式升级 + modified |= self._upgrade_config_item( + "html", + "html_filename_format", + self.set_html_filename_format, + ) + + if modified: + logger.info( + "已完成所有配置模板从 str.format 到 string.Template 的安全迁移。(已自动回写配置)" + ) + return modified + + def migrate_legacy_configs(self): + """升级旧版配置项的类型/结构,确保兼容新 schema""" + modified = False + + val = self._get_group("basic").get("output_format") + if isinstance(val, str): + self._ensure_group("basic")["output_format"] = [val] + logger.info("output_format 已从旧版 string 自动迁移为 list") + modified = True + + if modified: + self.config.save_config() + logger.info("旧版配置迁移完成,已自动回写") + + def get_quality_summary_prompt(self, style: str = "quality_summary_prompt") -> str: + """获取聊天质量汇总分析提示词模板""" + prompts_config = self._get_group("prompts").get("quality_analysis_prompts", {}) + prompt = prompts_config.get(style, "") + if prompt: + return prompt + return "" + + def set_topic_analysis_prompt(self, prompt: str): + """设置话题分析提示词模板""" + prompts = self._ensure_group("prompts") + if "topic_analysis_prompts" not in prompts: + prompts["topic_analysis_prompts"] = {} + prompts["topic_analysis_prompts"]["topic_prompt"] = prompt + self.config.save_config() + + def set_quality_summary_prompt(self, prompt: str): + """设置聊天质量汇总分析提示词模板""" + prompts = self._ensure_group("prompts") + if "quality_analysis_prompts" not in prompts: + prompts["quality_analysis_prompts"] = {} + prompts["quality_analysis_prompts"]["quality_summary_prompt"] = prompt + self.config.save_config() + + def set_user_title_analysis_prompt(self, prompt: str): + """设置用户称号分析提示词模板""" + prompts = self._ensure_group("prompts") + if "user_title_analysis_prompts" not in prompts: + prompts["user_title_analysis_prompts"] = {} + prompts["user_title_analysis_prompts"]["user_title_prompt"] = prompt + self.config.save_config() + + def set_golden_quote_analysis_prompt(self, prompt: str): + """设置金句分析提示词模板""" + prompts = self._ensure_group("prompts") + if "golden_quote_analysis_prompts" not in prompts: + prompts["golden_quote_analysis_prompts"] = {} + prompts["golden_quote_analysis_prompts"]["golden_quote_v2_prompt"] = prompt + self.config.save_config() + + def set_comic_storyboard_prompt(self, prompt: str): + """设置漫画场景分析提示词模板""" + prompts = self._ensure_group("prompts") + if "comic_analysis_prompts" not in prompts: + prompts["comic_analysis_prompts"] = {} + prompts["comic_analysis_prompts"]["comic_storyboard_prompt"] = prompt + self.config.save_config() + + def set_output_format(self, format_types: str | list[str]): + """设置输出格式""" + if isinstance(format_types, str): + format_types = [ + f.strip() for f in format_types.replace(",", ",").split(",") + ] + for f in format_types: + if f not in ("image", "text", "html"): + raise ValueError(f"无效格式: {f}。有效: image, text, html") + + self._ensure_group("basic")["output_format"] = format_types + self.config.save_config() + + def set_group_list_mode(self, mode: str): + """设置群组列表模式""" + self._ensure_group("basic")["group_list_mode"] = mode + self.config.save_config() + + def set_group_list(self, groups: list[str]): + """设置群组列表""" + self._ensure_group("basic")["group_list"] = groups + self.config.save_config() + + def get_max_concurrent_tasks(self) -> int: + """获取自动分析最大并发群数""" + return self._get_group("performance").get("max_concurrent_groups", 3) + + def get_llm_max_concurrent(self) -> int: + """获取全局 LLM 最大并发请求数""" + return self._get_group("performance").get("max_concurrent_llm", 3) + + def get_t2i_max_concurrent(self) -> int: + """获取全局图片渲染(T2I)最大并发数""" + return self._get_group("performance").get("max_concurrent_t2i", 1) + + def get_stagger_seconds(self) -> int: + """获取多群分析任务启动时的交错间隔(秒)""" + return self._get_group("performance").get("stagger_seconds", 2) + + def set_max_concurrent_tasks(self, count: int): + """设置自动分析最大并发数""" + self._ensure_group("performance")["max_concurrent_groups"] = count + self.config.save_config() + + def set_max_messages(self, count: int): + """设置最大消息数量""" + self._ensure_group("basic")["max_messages"] = count + self.config.save_config() + + def set_analysis_days(self, days: int): + """设置分析天数""" + self._ensure_group("basic")["analysis_days"] = days + self.config.save_config() + + def set_auto_analysis_time(self, time_val: str | list[str]): + """设置自动分析时间点""" + self._ensure_group("auto_analysis")["auto_analysis_time"] = time_val + self.config.save_config() + + def is_auto_analysis_enabled(self) -> bool: + """ + 判断自动分析功能是否通过名单“按需开启”。 + inherit 模式会继承基础群权限的开启状态;其他模式沿用自身名单判断。 + """ + mode = self.get_scheduled_group_list_mode() + if mode == "inherit": + basic_mode = self.get_group_list_mode().lower() + if basic_mode == "whitelist": + return bool(self.get_group_list()) + return True + + lst = self.get_scheduled_group_list() + return (mode == "whitelist" and len(lst) > 0) or (mode == "blacklist") + + def get_scheduled_group_list_mode(self) -> str: + """获取定时分析名单模式 (inherit/whitelist/blacklist)。""" + mode = str( + self._get_group("auto_analysis").get( + "scheduled_group_list_mode", "whitelist" + ) + ).lower() + if mode not in ("inherit", "whitelist", "blacklist"): + return "whitelist" + return mode + + def set_scheduled_group_list_mode(self, mode: str): + """设置定时分析名单模式""" + self._ensure_group("auto_analysis")["scheduled_group_list_mode"] = mode + self.config.save_config() + + def get_scheduled_group_list(self) -> list[str]: + """获取定时分析目标群列表""" + return self._get_group("auto_analysis").get("scheduled_group_list", []) + + def set_scheduled_group_list(self, groups: list[str]): + """设置定时分析目标群列表""" + self._ensure_group("auto_analysis")["scheduled_group_list"] = groups + self.config.save_config() + + def is_scheduled_group_allowed(self, group_umo_or_id: str) -> bool: + """判断当前群是否允许参与定时分析。 + + Args: + group_umo_or_id: 要检查的完整 UMO 或纯群号。 + + Returns: + 当前群是否同时通过基础群权限和定时分析名单。 + """ + if not self.is_group_allowed(group_umo_or_id): + return False + + mode = self.get_scheduled_group_list_mode() + if mode == "inherit": + return True + return self.is_group_in_filtered_list( + group_umo_or_id, mode, self.get_scheduled_group_list() + ) + + def is_group_in_filtered_list( + self, group_umo_or_id: str, mode: str, group_list: list + ) -> bool: + """ + 通用的名单判定逻辑。 + + 逻辑如下: + - whitelist 模式: + - 如果列表为空,则视为“此级别未开启”。 + - 如果不为空,仅在列表中的通过。 + - blacklist 模式: + - 在列表中的不通过。 + - 如果列表为空,则全部通过。 + """ + group_list = [str(x).strip() for x in group_list] + target = str(group_umo_or_id).strip() + + if mode == "whitelist": + if not group_list: + # 白名单为空:此级别不开启 (按需开启逻辑) + return False + return any(self._is_group_match(target, item) for item in group_list) + else: # blacklist + if not group_list: + # 黑名单为空:全通过 + return True + return not any(self._is_group_match(target, item) for item in group_list) + + def set_min_messages_threshold(self, threshold: int): + """设置最小消息阈值""" + self._ensure_group("basic")["min_messages_threshold"] = threshold + self.config.save_config() + + def set_topic_analysis_enabled(self, enabled: bool): + """设置是否启用话题分析""" + self._ensure_group("analysis_features")["topic_analysis_enabled"] = enabled + self.config.save_config() + + def set_user_title_analysis_enabled(self, enabled: bool): + """设置是否启用用户称号分析""" + self._ensure_group("analysis_features")["user_title_analysis_enabled"] = enabled + self.config.save_config() + + def set_golden_quote_analysis_enabled(self, enabled: bool): + """设置是否启用金句分析""" + self._ensure_group("analysis_features")["golden_quote_analysis_enabled"] = ( + enabled + ) + self.config.save_config() + + def set_chat_quality_analysis_enabled(self, enabled: bool): + """设置是否启用聊天质量分析""" + self._ensure_group("analysis_features")["chat_quality_analysis_enabled"] = ( + enabled + ) + self.config.save_config() + + def set_max_topics(self, count: int): + """设置最大话题数量""" + self._ensure_group("analysis_features")["max_topics"] = count + self.config.save_config() + + def set_max_user_titles(self, count: int): + """设置最大用户称号数量""" + self._ensure_group("analysis_features")["max_user_titles"] = count + self.config.save_config() + + def set_max_golden_quotes(self, count: int): + """设置最大金句数量""" + self._ensure_group("analysis_features")["max_golden_quotes"] = count + self.config.save_config() + + def set_html_filename_format(self, format_str: str): + """设置HTML文件名格式""" + self._ensure_group("html")["html_filename_format"] = format_str + self.config.save_config() + + def get_report_template(self) -> str: + """获取报告模板名称""" + return self._get_group("basic").get("report_template", "scrapbook") + + def set_report_template(self, template_name: str): + """设置报告模板名称""" + self._ensure_group("basic")["report_template"] = template_name + self.config.save_config() + + def get_enable_user_card(self) -> bool: + """获取是否使用用户群名片""" + return self._get_group("basic").get("enable_user_card", False) + + def get_enable_analysis_reply(self) -> bool: + """获取是否在群分析完成后发送文本回复""" + return self._get_group("basic").get("enable_analysis_reply", False) + + def set_enable_analysis_reply(self, enabled: bool): + """设置是否在群分析完成后发送文本回复""" + self._ensure_group("basic")["enable_analysis_reply"] = enabled + self.config.save_config() + + def get_show_report_caption(self) -> bool: + """获取是否发送 \"📊 每日群聊分析报告已生成\" 前缀文字。""" + return self._get_group("basic").get("show_report_caption", True) + + def set_show_report_caption(self, enabled: bool): + """设置是否发送 \"📊 每日群聊分析报告已生成\" 前缀文字。""" + self._ensure_group("basic")["show_report_caption"] = enabled + self.config.save_config() + + def get_profile_display_mode(self) -> str: + """获取人格标签展示模式。""" + mode = str(self._get_group("basic").get("profile_display_mode", "mbti")).lower() + if mode not in {"mbti", "sbti", "acgti"}: + return "mbti" + return mode + + def get_profile_image_opacity(self) -> float: + """获取人格背景图透明度。""" + value = self._get_group("basic").get("profile_image_opacity", 0.12) + try: + return max(0.0, min(1.0, float(value))) + except (TypeError, ValueError): + return 0.12 + + def get_profile_image_size_mode(self) -> str: + """获取人格背景图尺寸模式。""" + mode = str( + self._get_group("basic").get("profile_image_size_mode", "contain") + ).lower() + if mode not in {"contain", "cover"}: + return "contain" + return mode + + def get_profile_mapping_config(self) -> str: + """获取人格映射配置(JSON 文本)。""" + return str(self._get_group("basic").get("profile_mapping_config", "")).strip() + + # ========== 群文件/群相册上传配置 ========== + + def get_enable_group_file_upload(self) -> bool: + """获取是否启用群文件上传""" + return self._get_group("qq_group_upload").get("enable_group_file_upload", False) + + def get_group_file_folder(self) -> str: + """获取群文件上传目录名,空字符串表示根目录""" + return self._get_group("qq_group_upload").get("group_file_folder", "") + + def get_enable_group_album_upload(self) -> bool: + """获取是否启用群相册上传(仅 NapCat)""" + return self._get_group("qq_group_upload").get( + "enable_group_album_upload", False + ) + + def get_group_album_name(self) -> str: + """获取目标群相册名称,空字符串表示默认相册""" + return self._get_group("qq_group_upload").get("group_album_name", "") + + def get_group_album_strict_mode(self) -> bool: + """获取群相册上传严格模式开关。""" + return bool( + self._get_group("qq_group_upload").get("group_album_strict_mode", True) + ) + + def set_group_album_strict_mode(self, enabled: bool): + """设置群相册上传严格模式""" + self._ensure_group("qq_group_upload")["group_album_strict_mode"] = enabled + self.config.save_config() + + # ========== 增量分析配置 ========== + + def get_incremental_enabled(self) -> bool: + """获取是否开启了增量分析(由名单状态决定)""" + mode = self.get_incremental_group_list_mode() + if mode == "inherit": + return self.is_auto_analysis_enabled() + + lst = self.get_incremental_group_list() + # 如果是白名单且不为空,或者是黑名单模式,则视为功能“开启” + return (mode == "whitelist" and len(lst) > 0) or (mode == "blacklist") + + def get_incremental_group_list_mode(self) -> str: + """获取增量分析名单模式 (inherit/whitelist/blacklist)。""" + mode = str( + self._get_group("incremental").get( + "incremental_group_list_mode", "whitelist" + ) + ).lower() + if mode not in ("inherit", "whitelist", "blacklist"): + return "whitelist" + return mode + + def get_incremental_group_list(self) -> list[str]: + """获取增量分析群列表""" + return self._get_group("incremental").get("incremental_group_list", []) + + def is_incremental_group_allowed(self, group_umo_or_id: str) -> bool: + """判断当前群是否应使用增量分析。 + + Args: + group_umo_or_id: 要检查的完整 UMO 或纯群号。 + + Returns: + 当前群是否通过基础、定时和增量三级名单。 + """ + if not self.is_scheduled_group_allowed(group_umo_or_id): + return False + + mode = self.get_incremental_group_list_mode() + if mode == "inherit": + return True + return self.is_group_in_filtered_list( + group_umo_or_id, mode, self.get_incremental_group_list() + ) + + def get_incremental_fallback_enabled(self) -> bool: + """获取增量分析失败回退到全量分析的开关(默认启用)""" + return self._get_group("incremental").get("incremental_fallback_enabled", True) + + def get_incremental_report_immediately(self) -> bool: + """获取是否启用增量分析立即发送报告(调试用)""" + return self._get_group("incremental").get( + "incremental_report_immediately", False + ) + + def set_incremental_report_immediately(self, enabled: bool): + """设置增量分析是否立即发送报告""" + self._ensure_group("incremental")["incremental_report_immediately"] = enabled + self.config.save_config() + + def get_incremental_min_messages(self) -> int: + """获取触发增量分析的最小消息数阈值""" + value = self._get_group("incremental").get("incremental_min_messages", 300) + return max(1, int(value)) + + def get_incremental_topics_per_batch(self) -> int: + """获取单次增量分析提取的最大话题数""" + return self._get_group("incremental").get("incremental_topics_per_batch", 3) + + def get_incremental_quotes_per_batch(self) -> int: + """获取单次增量分析提取的最大金句数""" + return self._get_group("incremental").get("incremental_quotes_per_batch", 3) + + # ========== 每日群漫画配置 ========== + + def get_enable_daily_comic(self) -> bool: + """获取漫画功能总开关。""" + return self._get_group("daily_comic").get("enable_daily_comic", False) + + def get_enable_auto_daily_comic(self) -> bool: + """获取是否在分析完成后自动生成漫画。""" + return self._get_group("daily_comic").get("enable_auto_daily_comic", True) + + def get_comic_group_list_mode(self) -> str: + """获取漫画生成名单模式。 + + Returns: + 规范化后的漫画名单模式。默认 inherit,表示继承基础群权限, + 避免同一批群需要在多个配置里重复填写。 + """ + mode = str( + self._get_group("daily_comic").get("comic_group_list_mode", "inherit") + ).lower() + if mode not in ("inherit", "whitelist", "blacklist"): + return "inherit" + return mode + + def get_comic_group_list(self) -> list[str]: + """获取漫画生成白/黑名单列表。 + + Returns: + 配置的群 UMO 或纯群号列表。配置格式异常时按空列表处理。 + """ + group_list = self._get_group("daily_comic").get("comic_group_list", []) + if not isinstance(group_list, list): + return [] + return group_list + + def is_comic_group_allowed( + self, group_umo_or_id: str, inherit_allowed: bool | None = None + ) -> bool: + """判断当前群是否允许生成漫画。 + + Args: + group_umo_or_id: 要检查的完整 UMO 或纯群号。 + inherit_allowed: 上游入口已完成权限判断时传入其结果。自动报告 + 漫画会传入 True,避免重复读取基础/定时/增量名单;手动漫画 + 不传入时会按基础群权限实时判断。 + + Returns: + 当前群是否允许生成漫画。 + """ + mode = self.get_comic_group_list_mode() + if mode == "inherit": + if inherit_allowed is not None: + return bool(inherit_allowed) + return self.is_group_allowed(group_umo_or_id) + + return self.is_group_in_filtered_list( + group_umo_or_id, + mode, + self.get_comic_group_list(), + ) + + def get_drawing_backend(self) -> str: + """获取漫画绘图后端 (builtin/general_plugin/big_banana)。""" + group = self._get_group("daily_comic") + return str(group.get("drawing_backend", "builtin")).strip() or "builtin" + + def get_drawing_external_fallback(self) -> bool: + """外部绘图后端失败时是否回退内置后端。""" + return bool( + self._get_group("daily_comic").get("drawing_external_fallback", True) + ) + + def get_drawing_provider_configs(self) -> list[dict]: + """获取按优先级排序的已启用绘图供应商候选。 + + 空条目或格式错误的条目会被忽略。绘图供应商配置表是唯一的连接配置 + 来源;没有有效候选时,调用方会返回明确的未配置错误。 + + Returns: + 已启用供应商的配置字典列表。 + """ + providers = self._get_group("daily_comic").get("drawing_provider_overrides", []) + if not isinstance(providers, list): + return [] + + template_protocols = { + "google": "google", + "openai": "chat", + "zai": "chat", + "grok2api": "grok", + "agnes_ai": "agnes_ai", + "agnes_ai_china": "agnes_ai", + "xai": "xai", + "minimax": "minimax", + "stepfun": "stepfun", + "openai_images": "images", + "doubao": "doubao", + "sensenova": "sensenova", + "dashscope": "dashscope", + } + valid_protocols = {"images", "chat", "grok", "gemini", *template_protocols} + candidates = [] + for index, provider in enumerate(providers): + if not isinstance(provider, dict) or not provider.get("enable", True): + continue + template_key = str(provider.get("__template_key", "")).strip().lower() + name_val = str(provider.get("name", "")).strip().lower() + endpoint_mode = str(provider.get("endpoint_mode", "")).strip().lower() + api_url_val = str(provider.get("api_url", "")).strip().lower() + model_val = str(provider.get("model", "")).strip().lower() + + inferred_key = template_key or name_val or endpoint_mode + if inferred_key not in template_protocols: + if ( + "dashscope" in api_url_val + or "aliyuncs.com" in api_url_val + or "qwen" in model_val + or "wan" in model_val + ): + inferred_key = "dashscope" + elif ( + "generativelanguage.googleapis.com" in api_url_val + or "gemini" in model_val + ): + inferred_key = "google" + elif "sensenova" in api_url_val or "sensechat" in model_val: + inferred_key = "sensenova" + elif "x.ai" in api_url_val or "grok" in model_val: + inferred_key = "xai" + elif "minimax" in api_url_val or "image-01" in model_val: + inferred_key = "minimax" + elif "stepfun" in api_url_val or "step-" in model_val: + inferred_key = "stepfun" + elif "doubao" in api_url_val or "volces.com" in api_url_val: + inferred_key = "doubao" + elif "api_protocol" in provider: + inferred_key = str(provider["api_protocol"]).strip().lower() + + protocol = template_protocols.get( + inferred_key, str(provider.get("api_protocol", "images")).strip() + ) + api_key = str(provider.get("api_key", "")).strip() + if protocol not in valid_protocols or not api_key: + logger.warning("跳过索引 %s 处无效的漫画绘图供应商配置", index) + continue + candidate = provider.copy() + candidate["api_protocol"] = protocol + candidate["__template_key"] = inferred_key or template_key or "images" + candidate["api_key"] = api_key + candidate["_index"] = index + try: + candidate["_priority"] = int(provider.get("priority", 0)) + except (TypeError, ValueError): + candidate["_priority"] = 0 + candidates.append(candidate) + + return sorted( + candidates, + key=lambda item: (-item["_priority"], item["_index"]), + ) + + def get_drawing_output_exception_retries(self) -> int: + group = self._get_group("daily_comic") + return int(group.get("drawing_output_exception_retries", 3)) + + def get_drawing_output_exception_retry_keywords(self) -> list[str]: + group = self._get_group("daily_comic") + keywords = group.get("drawing_output_exception_retry_keywords", []) + if not isinstance(keywords, list): + keywords = [] + return [str(k) for k in keywords if str(k).strip()] + + def get_drawing_retry_delay(self) -> int: + group = self._get_group("daily_comic") + return int(group.get("drawing_retry_delay", 2)) + + def get_drawing_network_retries(self) -> int: + group = self._get_group("daily_comic") + return int(group.get("drawing_network_retries", 2)) + + def get_drawing_download_proxy(self) -> str: + group = self._get_group("daily_comic") + return group.get("drawing_download_proxy", "").strip() + + def get_drawing_proxy(self) -> str: + """获取漫画生图 API 的全局代理地址。""" + return str(self._get_group("daily_comic").get("drawing_proxy", "")).strip() + + def get_enable_comic_album_upload(self) -> bool: + group = self._get_group("qq_group_upload") + return bool(group.get("enable_comic_album_upload", False)) + + def get_comic_album_name(self) -> str: + return str( + self._get_group("qq_group_upload").get("comic_album_name", "daily_analysis") + ).strip() + + def get_drawing_reference_image(self) -> str: + """获取当前选中的漫画参考图相对路径。 + + Returns: + 当前角色方案最后添加的参考图;未配置角色方案时兼容旧版字段。 + """ + character = self.get_selected_comic_character() + reference_images = ( + character.get("reference_images", []) + if character + else self._get_group("daily_comic").get("drawing_reference_image", []) + ) + if isinstance(reference_images, str): + reference_images = [reference_images] + if not isinstance(reference_images, list): + return "" + for reference_image in reversed(reference_images): + if isinstance(reference_image, str) and reference_image.strip(): + return reference_image.strip() + return "" + + def get_drawing_reference_images(self) -> list[str]: + """Get every valid reference image for the selected comic character. + + Returns: + Relative image paths in their configured order. + """ + character = self.get_selected_comic_character() + reference_images = ( + character.get("reference_images", []) + if character + else self._get_group("daily_comic").get("drawing_reference_image", []) + ) + if isinstance(reference_images, str): + reference_images = [reference_images] + if not isinstance(reference_images, list): + return [] + return [ + reference_image.strip() + for reference_image in reference_images + if isinstance(reference_image, str) and reference_image.strip() + ] + + def get_selected_comic_character(self) -> dict | None: + """获取本次漫画应使用的角色方案。 + + 开启随机后,同一运行环境自然日内固定选择同一个已启用方案;关闭时始终使用 + 第一个已启用方案。角色列表为空时返回 None,调用方将回退到既有文生图行为。 + + Returns: + 角色方案配置;没有可用方案时返回 None。 + """ + characters = self._get_group("daily_comic").get("comic_characters", []) + enabled_characters = ( + [ + character + for character in characters + if isinstance(character, dict) and character.get("enable", True) + ] + if isinstance(characters, list) + else [] + ) + if not enabled_characters: + return None + + if not self._get_group("daily_comic").get( + "random_daily_comic_character", False + ): + return enabled_characters[0] + + timezone_name = os.environ.get("TZ", "").strip() + if timezone_name: + try: + current_time = datetime.now(ZoneInfo(timezone_name)) + except ZoneInfoNotFoundError: + logger.warning( + f"环境变量 TZ={timezone_name!r} 不是有效 IANA 时区," + "每日漫画角色将使用系统本地时区。" + ) + current_time = datetime.now().astimezone() + else: + current_time = datetime.now().astimezone() + today = current_time.date().isoformat() + state_path = self._get_comic_character_state_path() + state = self._read_comic_character_state(state_path) + selected_character = state.get("selected_character") + if state.get("date") == today and selected_character in enabled_characters: + return selected_character + + selected_character = random.choice(enabled_characters) + self._save_comic_character_state( + state_path, + {"date": today, "selected_character": selected_character}, + ) + character_name = str(selected_character.get("name", "")).strip() or "未命名方案" + logger.info(f"今日漫画角色已随机选择: {character_name}") + return selected_character + + def get_comic_character_persona_id(self, character: dict | None) -> str: + """获取角色方案绑定的漫画专用人格 ID。 + + Args: + character: 当前选中的角色方案。 + + Returns: + 人格 ID;未配置时为空字符串。 + """ + if not isinstance(character, dict): + return "" + return str(character.get("persona_id", "")).strip() + + def get_comic_character_storyboard_prompt(self, character: dict | None) -> str: + """获取角色专属分镜提示词,未配置时回退全局默认模板。 + + Args: + character: 当前选中的角色方案。 + + Returns: + 本次漫画分镜应使用的提示词模板。 + """ + if isinstance(character, dict): + prompt = str(character.get("storyboard_prompt", "")).strip() + if prompt: + return prompt + return self.get_comic_storyboard_prompt() + + @staticmethod + def _get_comic_character_state_path() -> Path: + """获取每日随机角色状态文件路径。""" + return get_data_dir(PLUGIN_NAME) / "comic_character_daily_state.json" + + @staticmethod + def _read_comic_character_state(state_path: Path) -> dict: + """读取每日随机角色状态。 + + Args: + state_path: 状态文件路径。 + + Returns: + 可用状态字典;文件不存在或无效时返回空字典。 + """ + try: + state = json.loads(state_path.read_text(encoding="utf-8")) + return state if isinstance(state, dict) else {} + except (OSError, json.JSONDecodeError): + return {} + + @staticmethod + def _save_comic_character_state(state_path: Path, state: dict) -> None: + """原子写入每日随机角色状态。 + + Args: + state_path: 状态文件路径。 + state: 待保存状态。 + """ + try: + state_path.parent.mkdir(parents=True, exist_ok=True) + temporary_path = state_path.with_suffix(".tmp") + temporary_path.write_text( + json.dumps(state, ensure_ascii=False), encoding="utf-8" + ) + temporary_path.replace(state_path) + except OSError as exc: + logger.warning(f"保存每日漫画角色选择失败: {exc}") + + def get_comic_storyboard_prompt( + self, style: str = "comic_storyboard_prompt" + ) -> str: + """获取分镜生成提示词模板""" + prompts_config = self._get_group("prompts").get("comic_analysis_prompts", {}) + return prompts_config.get(style, "") + + def save_config(self): + """保存配置到AstrBot配置系统""" + try: + self.config.save_config() + logger.info("配置已保存") + except Exception as e: + logger.error(f"保存配置失败: {e}") + + def reload_config(self): + """重新加载配置""" + try: + logger.info("重新加载配置...") + logger.info("配置重载完成") + except Exception as e: + logger.error(f"重新加载配置失败: {e}") diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/__init__.py new file mode 100644 index 0000000..a129422 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/__init__.py @@ -0,0 +1,3 @@ +from .service import DrawingApiRequestService + +__all__ = ["DrawingApiRequestService"] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/chat.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/chat.py new file mode 100644 index 0000000..9bb0a35 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/chat.py @@ -0,0 +1,89 @@ +import base64 +from math import gcd +from typing import Any + +import httpx + +from ....utils.logger import logger +from .context import DrawingRequestContext + + +async def call_chat_api( + context: DrawingRequestContext, + prompt: str, + images_data: list[tuple[bytes, str]] | None = None, + provider: dict | None = None, +) -> bytes | None: + provider = provider or {} + raw_url = context.get_provider_value("api_url", provider) + target_url = context.build_target_url(raw_url, "chat") + + api_key = context.get_provider_value("api_key", provider) + model = context.get_provider_value("model", provider) + + timeout = context.get_provider_value("timeout", provider) + + headers = { + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + } + + raw_size = context.get_provider_value("image_size", provider) + ar = context.get_provider_value("aspect_ratio", provider) + resolved_size = context.resolve_size(raw_size, ar) + + # 将长宽比与分辨率要求显式追加到 prompt 结尾,防止 Chat 协议模型忽略 + width, height = map(int, resolved_size.split("x", 1)) + divisor = gcd(width, height) + effective_aspect_ratio = f"{width // divisor}:{height // divisor}" + if width > height: + orientation = "Horizontal Landscape Orientation" + elif width < height: + orientation = "Vertical Portrait Orientation" + else: + orientation = "Square Orientation" + full_prompt = f"{prompt}\n\n[Image Layout & Spec Requirements: Aspect Ratio {effective_aspect_ratio}, Resolution {resolved_size}, {orientation}]" + + content = [] + for img_bytes, mime in images_data or []: + b64 = base64.b64encode(img_bytes).decode("utf-8") + content.append( + {"type": "image_url", "image_url": {"url": f"data:{mime};base64,{b64}"}} + ) + + content.append({"type": "text", "text": full_prompt}) + + payload: dict[str, Any] = { + "model": model, + "messages": [{"role": "user", "content": content}], + } + + logger.info( + f"[Comic] 发起 Chat API 请求 -> {context.sanitize_url(target_url)} (model={model}, size={resolved_size}, aspect_ratio={ar})..." + ) + + api_timeout = httpx.Timeout(connect=20.0, read=timeout, write=20.0, pool=20.0) + async with httpx.AsyncClient( + timeout=api_timeout, proxy=context.get_request_proxy(provider) + ) as client: + resp = await client.post(target_url, headers=headers, json=payload) + + if resp.status_code != 200: + snippet = resp.text[:500] if resp.text else "(空响应)" + raise Exception(f"API 请求失败 [HTTP {resp.status_code}]: {snippet}") + + try: + data = resp.json() + except Exception: + snippet = resp.text[:500] if resp.text else "(空正文)" + raise Exception( + f"API 未返回合法的 JSON [HTTP {resp.status_code}]: {snippet}" + ) + + image = await context.extract_image(data, context.get_request_proxy(provider)) + if image: + return image + + raise Exception( + f"无法从 Chat API 的回复中提取到图片: {context.summarize_response(data)}" + ) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/common.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/common.py new file mode 100644 index 0000000..11bd061 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/common.py @@ -0,0 +1,42 @@ +from typing import Any + +import httpx + +from ....utils.logger import logger +from .context import DrawingRequestContext + + +async def post_json_for_image( + context: DrawingRequestContext, + target_url: str, + headers: dict[str, str], + payload: dict[str, Any], + timeout: int | float, + provider_name: str, + provider: dict, +) -> bytes | None: + """发送 JSON 图片生成请求,并从响应中提取图片。""" + headers["Content-Type"] = "application/json" + api_timeout = httpx.Timeout(connect=20.0, read=timeout, write=20.0, pool=20.0) + logger.info( + f"[Comic] 发起 {provider_name} 图片请求 -> {context.sanitize_url(target_url)}" + ) + async with httpx.AsyncClient( + timeout=api_timeout, proxy=context.get_request_proxy(provider) + ) as client: + response = await client.post(target_url, headers=headers, json=payload) + if not 200 <= response.status_code < 300: + message = response.text[:500] if response.text else "(空响应)" + raise Exception( + f"{provider_name} API 请求失败 [HTTP {response.status_code}]: {message}" + ) + try: + data = response.json() + except ValueError as exc: + raise Exception(f"{provider_name} API 未返回合法 JSON") from exc + image = await context.extract_image(data, context.get_request_proxy(provider)) + if image: + return image + raise Exception( + f"{provider_name} API 返回格式异常: {context.summarize_response(data)}" + ) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/context.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/context.py new file mode 100644 index 0000000..5cfa68b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/context.py @@ -0,0 +1,73 @@ +"""绘图请求服务与客户端之间的显式依赖契约。 + +供应商请求模块不直接依赖 ``DrawingClient``,只通过本上下文访问 URL 解析、 +配置回退、代理、尺寸换算和响应解析能力。这样服务商文件保持可独立阅读,且 +不会因继承关系隐式获得不相关的客户端状态。 +""" + +from __future__ import annotations + +from collections.abc import Awaitable, Callable +from dataclasses import dataclass +from typing import Any, Protocol + + +class DrawingRequestHooks(Protocol): + """描述绘图请求服务依赖的宿主能力。""" + + def _build_target_url(self, raw_url: str, protocol: str) -> str: ... + + def _get_provider_value(self, name: str, provider: dict) -> Any: ... + + def _get_request_proxy(self, provider: dict | None = None) -> str | None: ... + + def _resolve_size(self, size_or_ratio: str, aspect_ratio: str) -> str: ... + + def _sanitize_url(self, url: str) -> str: ... + + def _summarize_response(self, data: Any) -> str: ... + + def _decode_base64(self, encoded: str) -> bytes: ... + + +@dataclass(slots=True) +class DrawingRequestContext: + """聚合绘图请求执行所需的显式依赖。 + + 该数据对象是组合关系的边界:请求模块只接收这个最小能力集合,HTTP JSON + 请求和图片提取则以函数形式注入,方便保留原有可替换入口。 + """ + + hooks: DrawingRequestHooks + request_json: Callable[..., Awaitable[bytes | None]] + extract_image: Callable[[Any, str | None], Awaitable[bytes | None]] + + def build_target_url(self, raw_url: str, protocol: str) -> str: + return self.hooks._build_target_url(raw_url, protocol) + + def get_provider_value(self, name: str, provider: dict) -> Any: + return self.hooks._get_provider_value(name, provider) + + def get_request_proxy(self, provider: dict | None = None) -> str | None: + return self.hooks._get_request_proxy(provider) + + def resolve_size(self, size_or_ratio: str, aspect_ratio: str) -> str: + """按当前供应商条目的宽高比解析尺寸别名。 + + Args: + size_or_ratio: 条目中的尺寸别名、分辨率或比例。 + aspect_ratio: 同一条目中的目标宽高比。 + + Returns: + 对应的 ``宽x高`` 尺寸字符串。 + """ + return self.hooks._resolve_size(size_or_ratio, aspect_ratio) + + def sanitize_url(self, url: str) -> str: + return self.hooks._sanitize_url(url) + + def summarize_response(self, data: Any) -> str: + return self.hooks._summarize_response(data) + + def decode_base64(self, encoded: str) -> bytes: + return self.hooks._decode_base64(encoded) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/gemini.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/gemini.py new file mode 100644 index 0000000..fda6bf2 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/gemini.py @@ -0,0 +1,154 @@ +import base64 +import binascii +import re +from typing import Any + +import httpx + +from ....utils.logger import logger +from .context import DrawingRequestContext + + +async def call_gemini_api( + context: DrawingRequestContext, + prompt: str, + images_data: list[tuple[bytes, str]] | None = None, + provider: dict | None = None, +) -> bytes | None: + """调用 Google Gemini Interactions 图片接口。 + + Args: + prompt: 图片生成或编辑提示词。 + images_data: 可选参考图片及其 MIME 类型列表,当前只使用第一张。 + + Returns: + 最后一个模型输出中的图片二进制数据。 + + Raises: + Exception: 请求失败、响应不是 JSON 或响应中没有最终图片。 + """ + provider = provider or {} + raw_url = context.get_provider_value("api_url", provider) + target_url = context.build_target_url(raw_url, "gemini") + api_key = context.get_provider_value("api_key", provider) + model = context.get_provider_value("model", provider) + timeout = context.get_provider_value("timeout", provider) + aspect_ratio = context.get_provider_value("aspect_ratio", provider) + + raw_size = str(context.get_provider_value("image_size", provider)).strip() + if raw_size.upper() in {"1K", "2K", "4K"}: + image_size = raw_size.upper() + elif re.fullmatch(r"\d+x\d+", raw_size.lower()): + width, height = map(int, raw_size.lower().split("x", 1)) + longest_edge = max(width, height) + if longest_edge <= 1024: + image_size = "1K" + elif longest_edge <= 2048: + image_size = "2K" + else: + image_size = "4K" + else: + image_size = "1K" + + output_format = str(context.get_provider_value("output_format", provider)).lower() + output_mime = { + "png": "image/png", + "jpeg": "image/jpeg", + "jpg": "image/jpeg", + }.get(output_format) + + input_content: list[dict[str, str]] = [{"type": "text", "text": prompt}] + reference_bytes = 0 + for image_bytes, mime in images_data or []: + image_mime = mime if mime.startswith("image/") else "image/png" + input_content.append( + { + "type": "image", + "data": base64.b64encode(image_bytes).decode("ascii"), + "mime_type": image_mime, + } + ) + reference_bytes += len(image_bytes) + + response_format: dict[str, str] = { + "type": "image", + "aspect_ratio": aspect_ratio, + "image_size": image_size, + } + if output_mime: + response_format["mime_type"] = output_mime + + payload: dict[str, Any] = { + "model": model, + "input": input_content, + "response_format": response_format, + "store": False, + } + headers = { + "x-goog-api-key": api_key, + "Content-Type": "application/json", + } + + logger.info( + f"[Comic] 发起 Gemini Interactions API 请求 -> {context.sanitize_url(target_url)} " + f"(model={model}, image_size={image_size}, " + f"aspect_ratio={aspect_ratio}, reference_bytes={reference_bytes})..." + ) + api_timeout = httpx.Timeout(connect=20.0, read=timeout, write=20.0, pool=20.0) + async with httpx.AsyncClient( + timeout=api_timeout, proxy=context.get_request_proxy(provider) + ) as client: + resp = await client.post(target_url, headers=headers, json=payload) + + if not 200 <= resp.status_code < 300: + error_summary = resp.text[:500] if resp.text else "(空响应)" + raise Exception( + f"Gemini API 请求失败 [HTTP {resp.status_code}]: {error_summary}" + ) + + try: + data = resp.json() + except Exception: + raise Exception( + f"Gemini API 未返回合法的 JSON [HTTP {resp.status_code}]: " + f"" + ) + + steps = data.get("steps") if isinstance(data, dict) else None + model_outputs = ( + [ + step + for step in steps + if isinstance(step, dict) and step.get("type") == "model_output" + ] + if isinstance(steps, list) + else [] + ) + for step in reversed(model_outputs): + content = step.get("content") + if not isinstance(content, list): + continue + for item in reversed(content): + if not isinstance(item, dict) or item.get("type") != "image": + continue + encoded = item.get("data") + if not isinstance(encoded, str) or not encoded.strip(): + continue + try: + return context.decode_base64(encoded) + except (ValueError, TypeError, binascii.Error) as exc: + logger.debug(f"[Comic] 跳过无效 Gemini 最终图片: {exc}") + + # 当响应包含 steps 时,只在最终模型输出中回退提取图片,避免误取中间推理图。 + fallback_data: Any = model_outputs if isinstance(steps, list) else data + image = await context.extract_image( + fallback_data, context.get_request_proxy(provider) + ) + if image: + return image + + status = data.get("status") if isinstance(data, dict) else None + raise Exception( + f"Gemini API 未返回最终图片 (status={status or 'unknown'}): " + f"{context.summarize_response(data)}" + ) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/google.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/google.py new file mode 100644 index 0000000..f8df24d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/google.py @@ -0,0 +1,53 @@ +import base64 +from typing import Any + +from .context import DrawingRequestContext + + +async def call_google_api( + context: DrawingRequestContext, + prompt: str, + images_data: list[tuple[bytes, str]] | None, + provider: dict, +) -> bytes | None: + """调用 Google Gemini generateContent 官方接口。""" + api_base = str(context.get_provider_value("api_url", provider)).rstrip("/") + model = context.get_provider_value("model", provider) + if ":generateContent" in api_base: + target_url = api_base + else: + if not api_base: + api_base = "https://generativelanguage.googleapis.com/v1beta" + if not api_base.endswith(("/v1", "/v1beta")): + api_base = f"{api_base}/v1beta" + target_url = f"{api_base}/models/{model}:generateContent" + + image_size = str(context.get_provider_value("image_size", provider)).upper() + parts: list[dict[str, Any]] = [{"text": prompt}] + for image_bytes, mime in (images_data or [])[:14]: + parts.append( + { + "inlineData": { + "mimeType": mime if mime.startswith("image/") else "image/png", + "data": base64.b64encode(image_bytes).decode("ascii"), + } + } + ) + payload = { + "contents": [{"role": "user", "parts": parts}], + "generationConfig": { + "responseModalities": ["TEXT", "IMAGE"], + "imageConfig": { + "image_size": image_size if image_size in {"1K", "2K", "4K"} else "2K", + "aspect_ratio": context.get_provider_value("aspect_ratio", provider), + }, + }, + } + return await context.request_json( + target_url, + {"x-goog-api-key": context.get_provider_value("api_key", provider)}, + payload, + context.get_provider_value("timeout", provider), + "Google Gemini", + provider, + ) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/grok.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/grok.py new file mode 100644 index 0000000..7c97930 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/grok.py @@ -0,0 +1,93 @@ +import base64 +from typing import Any + +import httpx + +from ....utils.logger import logger +from .context import DrawingRequestContext + + +async def call_grok_api( + context: DrawingRequestContext, + prompt: str, + images_data: list[tuple[bytes, str]] | None = None, + provider: dict | None = None, +) -> bytes | None: + """调用 xAI Grok Imagine 官方图片接口。 + + Args: + prompt: 图片生成或编辑提示词。 + images_data: 可选参考图片及其 MIME 类型列表,当前只使用第一张。 + + Returns: + API 返回的图片二进制数据。 + + Raises: + Exception: 请求失败、响应不是 JSON 或响应中没有有效图片。 + """ + provider = provider or {} + raw_url = context.get_provider_value("api_url", provider) + target_url = context.build_target_url(raw_url, "grok") + api_key = context.get_provider_value("api_key", provider) + model = context.get_provider_value("model", provider) + timeout = context.get_provider_value("timeout", provider) + aspect_ratio = context.get_provider_value("aspect_ratio", provider) + + headers = { + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + } + response_format = ( + context.get_provider_value("response_format", provider) or "b64_json" + ) + payload: dict[str, Any] = { + "model": model, + "prompt": prompt, + "response_format": response_format, + } + if aspect_ratio: + payload["aspect_ratio"] = aspect_ratio + + reference_bytes = 0 + if images_data: + if target_url.endswith("/generations"): + target_url = target_url.removesuffix("/generations") + "/edits" + image_bytes, mime = images_data[0] + image_mime = mime if mime.startswith("image/") else "image/png" + encoded = base64.b64encode(image_bytes).decode("ascii") + payload["image"] = { + "type": "image_url", + "url": f"data:{image_mime};base64,{encoded}", + } + reference_bytes = len(image_bytes) + elif target_url.endswith("/edits"): + target_url = target_url.removesuffix("/edits") + "/generations" + + logger.info( + f"[Comic] 发起 Grok Images API 请求 -> {context.sanitize_url(target_url)} " + f"(model={model}, aspect_ratio={aspect_ratio}, " + f"reference_bytes={reference_bytes})..." + ) + api_timeout = httpx.Timeout(connect=20.0, read=timeout, write=20.0, pool=20.0) + async with httpx.AsyncClient( + timeout=api_timeout, proxy=context.get_request_proxy(provider) + ) as client: + resp = await client.post(target_url, headers=headers, json=payload) + + if not 200 <= resp.status_code < 300: + error_summary = resp.text[:500] if resp.text else "(空响应)" + raise Exception(f"Grok API 请求失败 [HTTP {resp.status_code}]: {error_summary}") + + try: + data = resp.json() + except Exception: + raise Exception( + f"Grok API 未返回合法的 JSON [HTTP {resp.status_code}]: " + f"" + ) + + image = await context.extract_image(data, context.get_request_proxy(provider)) + if image: + return image + + raise Exception(f"Grok API 返回格式异常: {context.summarize_response(data)}") diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/images.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/images.py new file mode 100644 index 0000000..f388363 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/images.py @@ -0,0 +1,187 @@ +"""OpenAI Images 兼容接口的请求实现。 + +该文件负责在同一套 Images API 中区分文生图和图生图请求:没有参考图时使用 +JSON 的 ``/images/generations``,有参考图时使用 multipart 的 ``/images/edits``。 +它同时将预设中的 GPT Image 专属参数限制在对应模型和输出格式下,避免兼容端点 +因未知字段拒绝请求。 +""" + +from typing import Any + +import httpx + +from ....utils.logger import logger +from .context import DrawingRequestContext + + +async def call_images_api( + context: DrawingRequestContext, + prompt: str, + images_data: list[tuple[bytes, str]] | None = None, + provider: dict | None = None, +) -> bytes | None: + """调用 OpenAI Images 兼容接口。 + + 文生图走 JSON,带参考图时切换为 multipart 的 edits 请求。供应商专属 + 参数仅在显式配置时写入,以免把 GPT Image 的参数错误发送给兼容端点。 + """ + provider = provider or {} + raw_url = context.get_provider_value("api_url", provider) + target_url = context.build_target_url(raw_url, "images") + + api_key = context.get_provider_value("api_key", provider) + model = context.get_provider_value("model", provider) + timeout = context.get_provider_value("timeout", provider) + + headers = { + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + } + + raw_size = context.get_provider_value("image_size", provider) + ar = context.get_provider_value("aspect_ratio", provider) + resolved_size = context.resolve_size(raw_size, ar) + output_format = context.get_provider_value("output_format", provider) + + payload: dict[str, Any] = { + "prompt": prompt, + "model": model, + "n": 1, + "size": resolved_size, + "output_format": output_format, + } + + # 优先使用预设中的 quality,保留 image_quality 以兼容旧版全局配置。 + # ``auto`` 只有用户在预设中显式选择时才会发送,避免改变旧版全局配置 + # 中 ``auto`` 表示“让服务端保持默认”的既有语义。 + configured_quality = str(provider.get("quality") or "").strip().lower() + quality = ( + configured_quality + or str(context.get_provider_value("image_quality", provider) or "") + .strip() + .lower() + ) + should_send_quality = quality in {"low", "medium", "high"} or ( + configured_quality == "auto" + ) + if should_send_quality: + payload["quality"] = quality + + bg = context.get_provider_value("background", provider) + is_gpt_image = str(model).lower().startswith("gpt-image") + # background、压缩率和审核策略都是 GPT Image 专属字段。背景为 auto + # 时不传,交由服务端按其默认策略处理。 + if is_gpt_image and bg and bg != "auto": + payload["background"] = bg + + # 压缩率仅适用于 JPEG/WebP,审核策略留空时不传,确保其他 OpenAI + # 兼容服务不会收到未知字段。 + response_format = str(provider.get("response_format") or "").strip() + if response_format: + payload["response_format"] = response_format + try: + output_compression = int(provider.get("output_compression", 0)) + except (TypeError, ValueError): + output_compression = 0 + if is_gpt_image and output_compression > 0 and output_format in {"jpeg", "webp"}: + payload["output_compression"] = min(output_compression, 100) + moderation = str(provider.get("moderation") or "").strip() + if is_gpt_image and moderation: + payload["moderation"] = moderation + + # 某些中转服务只实现 generations;启用后显式丢弃角色参考图,避免请求 + # 被自动改写到不支持的 edits 端点。 + if provider.get("generations_only", False) and images_data: + logger.info( + "[Comic] OpenAI Images 已启用仅文生图模式,忽略 %d 张参考图。", + len(images_data), + ) + images_data = None + + # 模板的参考图数量是用户侧的主动限制。它在切换为 edits 前执行,因此 + # 设置为 0 会自然退回到文生图;无效输入则使用模板默认值 6。 + if images_data: + try: + max_references = max(0, int(provider.get("max_reference_images", 6))) + except (TypeError, ValueError): + max_references = 6 + if len(images_data) > max_references: + logger.info( + "[Comic] OpenAI Images 参考图数量从 %d 张限制为 %d 张。", + len(images_data), + max_references, + ) + images_data = images_data[:max_references] + + if images_data and len(images_data) > 0: + if target_url.endswith("/generations"): + target_url = target_url.replace("/generations", "/edits") + + headers.pop( + "Content-Type", None + ) # 移除 JSON 的 Content-Type,让 httpx 自动设置为 multipart/form-data + + multipart_data: dict[str, str] = { + "prompt": prompt, + "model": model, + "n": "1", + "size": resolved_size, + "output_format": output_format, + } + if should_send_quality: + multipart_data["quality"] = quality + if is_gpt_image and bg and bg != "auto": + multipart_data["background"] = bg + if response_format: + multipart_data["response_format"] = response_format + if ( + is_gpt_image + and output_compression > 0 + and output_format in {"jpeg", "webp"} + ): + multipart_data["output_compression"] = str(min(output_compression, 100)) + if is_gpt_image and moderation: + multipart_data["moderation"] = moderation + + files = [] + for index, (img_bytes, mime) in enumerate(images_data, start=1): + ext = mime.split("/")[-1] if "/" in mime else "png" + files.append(("image[]", (f"image_{index}.{ext}", img_bytes, mime))) + + logger.info( + f"[Comic] 发起 Images API 请求 (含图) -> {context.sanitize_url(target_url)} " + f"(model={model}, size={resolved_size}, aspect_ratio={ar}, " + f"references={len(images_data)}, reference_bytes={sum(len(image[0]) for image in images_data)})..." + ) + api_timeout = httpx.Timeout(connect=20.0, read=timeout, write=20.0, pool=20.0) + async with httpx.AsyncClient( + timeout=api_timeout, proxy=context.get_request_proxy(provider) + ) as client: + resp = await client.post( + target_url, headers=headers, data=multipart_data, files=files + ) + else: + logger.info( + f"[Comic] 发起 Images API 请求 -> {context.sanitize_url(target_url)} (model={model}, size={resolved_size}, aspect_ratio={ar})..." + ) + api_timeout = httpx.Timeout(connect=20.0, read=timeout, write=20.0, pool=20.0) + async with httpx.AsyncClient( + timeout=api_timeout, proxy=context.get_request_proxy(provider) + ) as client: + resp = await client.post(target_url, headers=headers, json=payload) + + if resp.status_code != 200: + snippet = resp.text[:500] if resp.text else "(空响应)" + raise Exception(f"API 请求失败 [HTTP {resp.status_code}]: {snippet}") + + try: + data = resp.json() + except Exception: + snippet = resp.text[:500] if resp.text else "(空正文)" + raise Exception(f"API 未返回合法的 JSON [HTTP {resp.status_code}]: {snippet}") + + image = await context.extract_image(data, context.get_request_proxy(provider)) + if image: + return image + + raise Exception(f"API 返回格式异常: {context.summarize_response(data)}") diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/presets.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/presets.py new file mode 100644 index 0000000..8834967 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/presets.py @@ -0,0 +1,394 @@ +"""漫画绘图供应商预设的请求体构造。 + +本模块只处理各家官方接口不兼容的字段、端点和能力约束;通用 HTTP +发送、重试以及图片响应提取仍由上层服务统一负责。这样新增预设时只需 +在对应分支描述其请求格式,不会把服务商细节重新堆回 DrawingClient。 +""" + +import base64 +from typing import Any + +import httpx + +from ....utils.logger import logger +from .context import DrawingRequestContext + + +async def call_preset_api( + context: DrawingRequestContext, + prompt: str, + images_data: list[tuple[bytes, str]] | None, + provider: dict, + provider_type: str, +) -> bytes | None: + """调用使用专有请求格式的绘图供应商预设。 + + Args: + context: 由绘图客户端提供的公共配置、代理和响应处理能力。 + prompt: 本次漫画分镜的提示词。 + images_data: 已读取的角色参考图片二进制数据。 + provider: 当前供应商模板保存后的配置。 + provider_type: 预设类型,用于选择官方接口格式。 + + Returns: + 成功时返回图片二进制数据,没有图片时返回 ``None``。 + + Raises: + ValueError: 供应商预设类型不受支持时抛出。 + """ + api_key = context.get_provider_value("api_key", provider) + api_base = str(context.get_provider_value("api_url", provider)).rstrip("/") + model = context.get_provider_value("model", provider) + timeout = context.get_provider_value("timeout", provider) + image_size = str(context.get_provider_value("image_size", provider)) + aspect_ratio = context.get_provider_value("aspect_ratio", provider) + output_format = context.get_provider_value("output_format", provider) + # 各个原生 JSON 接口都可接收 data URI。这里统一转换一次,后续分支只 + # 负责自己的字段语义和参考图数量上限。 + data_uris = [ + f"data:{mime if mime.startswith('image/') else 'image/png'};base64," + f"{base64.b64encode(image_bytes).decode('ascii')}" + for image_bytes, mime in images_data or [] + ] + headers = {"Authorization": f"Bearer {api_key}"} + + if provider_type == "agnes_ai": + base = api_base or "https://apihub.agnes-ai.com" + target_url = ( + f"{base}/images/generations" + if "/v1" in base + else f"{base}/v1/images/generations" + ) + payload: dict[str, Any] = { + "model": model, + "prompt": prompt, + "size": context.resolve_size(image_size, aspect_ratio), + "extra_body": {"response_format": output_format or "url"}, + } + if data_uris: + payload["extra_body"]["image"] = data_uris + provider_name = "Agnes AI" + elif provider_type == "xai": + base = api_base or "https://api.x.ai" + base = base if base.endswith("/v1") else f"{base}/v1" + payload = { + "model": model, + "prompt": prompt, + "n": 1, + "resolution": image_size.lower() + if image_size.upper() in {"1K", "2K"} + else "2k", + "response_format": output_format or "url", + } + target_url = f"{base}/images/generations" + if data_uris: + target_url = f"{base}/images/edits" + image_items = [ + {"type": "image_url", "url": data_uri} for data_uri in data_uris[:5] + ] + payload["image" if len(image_items) == 1 else "images"] = ( + image_items[0] if len(image_items) == 1 else image_items + ) + payload["aspect_ratio"] = aspect_ratio + provider_name = "xAI" + elif provider_type == "minimax": + base = (api_base or "https://api.minimaxi.com").removesuffix("/v1") + target_url = f"{base}/v1/image_generation" + payload = { + "model": model, + "prompt": prompt, + "response_format": "url", + "n": 1, + "aspect_ratio": aspect_ratio, + } + if data_uris: + payload["subject_reference"] = [ + {"type": "character", "image_file": data_uri} + for data_uri in data_uris[:9] + ] + provider_name = "MiniMax" + elif provider_type == "doubao": + base = api_base or "https://ark.cn-beijing.volces.com" + endpoint = ( + "/api/plan/v3/images/generations" + if provider.get("endpoint_mode") == "agent_plan" + else "/api/v3/images/generations" + ) + target_url = f"{base}{endpoint}" + configured_model = str(provider.get("endpoint_id") or model).strip() + model = configured_model or model + size_mode = str(provider.get("size_mode") or "preset").strip().lower() + configured_size = ( + provider.get("custom_size") + if size_mode == "custom" + else provider.get("size") or image_size + ) + resolved_doubao_size = str(configured_size or image_size).strip() + if "x" in resolved_doubao_size.lower() or "×" in resolved_doubao_size: + resolved_doubao_size = resolved_doubao_size.lower().replace("×", "x") + elif resolved_doubao_size.upper() not in {"1K", "2K", "3K", "4K"}: + resolved_doubao_size = context.resolve_size( + resolved_doubao_size, aspect_ratio + ) + is_seedream_5_pro = ( + str(provider.get("model_capability") or "").lower() == "seedream_5_pro" + or "seedream-5.0-pro" in model.lower() + or "seedream-5-0-pro" in model.lower() + ) + payload: dict[str, Any] = { + "model": model, + "prompt": prompt, + "response_format": "url", + "output_format": output_format or "png", + "watermark": bool(provider.get("watermark", False)), + "size": resolved_doubao_size, + } + if data_uris: + max_references = 10 if is_seedream_5_pro else 14 + try: + max_references = min( + max_references, + max(0, int(provider.get("max_reference_images", max_references))), + ) + except (TypeError, ValueError): + pass + selected_images = data_uris[:max_references] + if selected_images: + payload["image"] = ( + selected_images[0] if len(selected_images) == 1 else selected_images + ) + optimize_mode = str(provider.get("optimize_prompt_mode") or "").strip() + if optimize_mode in {"standard", "fast"}: + payload["optimize_prompt_options"] = {"mode": optimize_mode} + sequential_mode = provider.get("sequential_image_generation") + if sequential_mode == "auto" and not is_seedream_5_pro: + payload["sequential_image_generation"] = "auto" + try: + sequential_max_images = int(provider.get("sequential_max_images", 0)) + except (TypeError, ValueError): + sequential_max_images = 0 + if 1 <= sequential_max_images <= 12: + payload["sequential_image_generation_options"] = { + "max_images": sequential_max_images + } + elif sequential_mode == "auto": + logger.info("[Comic] 豆包 Seedream 5.0 Pro 不支持组图生成,已忽略该配置。") + provider_name = "豆包" + elif provider_type == "sensenova": + base = api_base or "https://token.sensenova.cn" + target_url = ( + f"{base}/images/generations" + if base.endswith("/v1") + else f"{base}/v1/images/generations" + ) + if data_uris: + logger.info( + "[Comic] SenseNova U1 Fast 不支持参考图,已忽略 %d 张。", + len(data_uris), + ) + # U1 Fast 仅接受官方枚举尺寸,宽高比不能映射时使用用户配置的默认 + # 尺寸,仍不合法时再回退到官方横版默认值。 + size_map = { + "1:1": "2048x2048", + "2:3": "1664x2496", + "3:2": "2496x1664", + "16:9": "2752x1536", + "9:16": "1536x2752", + "4:3": "2368x1760", + "3:4": "1760x2368", + "4:5": "1824x2272", + "5:4": "2272x1824", + "21:9": "3072x1376", + "9:21": "1344x3136", + } + default_size = str(provider.get("default_size") or "2752x1536").lower() + allowed_sizes = set(size_map.values()) + resolved_sensenova_size = size_map.get(str(aspect_ratio), default_size) + if resolved_sensenova_size not in allowed_sizes: + logger.warning( + "[Comic] SenseNova 默认尺寸 %s 不受支持,回退为 2752x1536。", + resolved_sensenova_size, + ) + resolved_sensenova_size = "2752x1536" + try: + sensenova_n = max(1, min(4, int(provider.get("n", 1)))) + except (TypeError, ValueError): + sensenova_n = 1 + payload = { + "model": model, + "prompt": prompt, + "size": resolved_sensenova_size, + "n": sensenova_n, + } + provider_name = "SenseNova" + elif provider_type == "dashscope": + endpoint_mode = str(provider.get("endpoint_mode", "dashscope")) + base = api_base or ( + "https://token-plan.cn-beijing.maas.aliyuncs.com" + if endpoint_mode == "token_plan" + else "https://dashscope.aliyuncs.com" + ) + clean_base = base.rstrip("/") + if clean_base.endswith("/api/v1"): + clean_base = clean_base[:-7].rstrip("/") + elif clean_base.endswith("/v1"): + clean_base = clean_base[:-3].rstrip("/") + target_url = ( + f"{clean_base}/api/v1/services/aigc/multimodal-generation/generation" + ) + content: list[dict[str, str]] = [{"text": prompt}] + try: + dashscope_max_references = min( + 9, max(0, int(provider.get("max_reference_images", 9))) + ) + except (TypeError, ValueError): + dashscope_max_references = 9 + content.extend( + {"image": data_uri} for data_uri in data_uris[:dashscope_max_references] + ) + size_mode = str(provider.get("size_mode") or "preset").strip().lower() + custom_size = str(provider.get("custom_size") or "").strip() + if size_mode == "custom" and custom_size: + normalized_size = custom_size.upper() + if normalized_size not in {"1K", "2K", "4K"}: + normalized_size = ( + custom_size.lower().replace("×", "*").replace("x", "*") + ) + dashscope_size = normalized_size + else: + dashscope_size = resolve_dashscope_size(image_size, aspect_ratio) + is_wan27 = str(model).startswith("wan2.7") + enable_sequential = is_wan27 and bool(provider.get("enable_sequential", False)) + if enable_sequential: + dashscope_n_limit = 12 + elif is_wan27: + dashscope_n_limit = 4 + elif str(model).startswith("qwen-image-2.0"): + dashscope_n_limit = 6 + else: + dashscope_n_limit = 1 + try: + dashscope_n = max(1, min(dashscope_n_limit, int(provider.get("n", 1)))) + except (TypeError, ValueError): + dashscope_n = 1 + parameters: dict[str, Any] = { + "size": dashscope_size, + "n": dashscope_n, + "watermark": bool(provider.get("watermark", False)), + } + negative_prompt = str(provider.get("negative_prompt") or "").strip() + if negative_prompt and not is_wan27: + parameters["negative_prompt"] = negative_prompt + elif negative_prompt: + logger.info("[Comic] DashScope wan2.7 不支持负面提示词,已忽略该配置。") + if is_wan27: + if enable_sequential: + parameters["enable_sequential"] = True + else: + parameters["thinking_mode"] = bool(provider.get("thinking_mode", True)) + else: + parameters["prompt_extend"] = bool(provider.get("prompt_extend", False)) + payload = { + "model": model, + "input": {"messages": [{"role": "user", "content": content}]}, + "parameters": parameters, + } + provider_name = "DashScope" + elif provider_type == "stepfun": + return await call_stepfun_api( + context, prompt, images_data, provider, api_key, model, timeout + ) + else: + raise ValueError(f"不支持的绘图供应商预设: {provider_type}") + + return await context.request_json( + target_url, headers, payload, timeout, provider_name, provider + ) + + +async def call_stepfun_api( + context: DrawingRequestContext, + prompt: str, + images_data: list[tuple[bytes, str]] | None, + provider: dict, + api_key: str, + model: str, + timeout: int | float, +) -> bytes | None: + """调用阶跃星辰图片接口,图生图使用官方 multipart 字段。""" + target_url = context.build_target_url( + context.get_provider_value("api_url", provider), "images" + ) + headers = {"Authorization": f"Bearer {api_key}"} + api_timeout = httpx.Timeout(connect=20.0, read=timeout, write=20.0, pool=20.0) + + if images_data: + target_url = target_url.replace("/generations", "/edits") + image_bytes, mime = images_data[0] + extension = mime.split("/")[-1] if "/" in mime else "png" + form_data = { + "model": model, + "prompt": prompt, + "response_format": "url", + } + files = { + "image": (f"reference.{extension}", image_bytes, mime), + } + logger.info( + f"[Comic] 发起阶跃星辰图生图请求 -> {context.sanitize_url(target_url)}" + ) + async with httpx.AsyncClient( + timeout=api_timeout, proxy=context.get_request_proxy(provider) + ) as client: + response = await client.post( + target_url, headers=headers, data=form_data, files=files + ) + else: + payload = { + "model": model, + "prompt": prompt, + "size": context.resolve_size( + context.get_provider_value("image_size", provider), + context.get_provider_value("aspect_ratio", provider), + ), + "response_format": "url", + } + logger.info( + f"[Comic] 发起阶跃星辰文生图请求 -> {context.sanitize_url(target_url)}" + ) + async with httpx.AsyncClient( + timeout=api_timeout, proxy=context.get_request_proxy(provider) + ) as client: + response = await client.post(target_url, headers=headers, json=payload) + + if not 200 <= response.status_code < 300: + message = response.text[:500] if response.text else "(空响应)" + raise Exception( + f"阶跃星辰 API 请求失败 [HTTP {response.status_code}]: {message}" + ) + try: + data = response.json() + except ValueError as exc: + raise Exception("阶跃星辰 API 未返回合法 JSON") from exc + image = await context.extract_image(data, context.get_request_proxy(provider)) + if image: + return image + raise Exception(f"阶跃星辰 API 返回格式异常: {context.summarize_response(data)}") + + +def resolve_dashscope_size(image_size: str, aspect_ratio: str) -> str: + """将漫画尺寸和比例换算为 DashScope 的 size 格式。""" + long_edge = {"1K": 1280, "2K": 2048, "4K": 4096}.get(image_size.upper(), 2048) + try: + width_ratio, height_ratio = (int(value) for value in aspect_ratio.split(":", 1)) + if width_ratio <= 0 or height_ratio <= 0: + raise ValueError + except (AttributeError, TypeError, ValueError): + width_ratio, height_ratio = 1, 1 + if width_ratio >= height_ratio: + width = long_edge + height = round(long_edge * height_ratio / width_ratio / 16) * 16 + else: + height = long_edge + width = round(long_edge * width_ratio / height_ratio / 16) * 16 + return f"{max(512, width)}*{max(512, height)}" diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/service.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/service.py new file mode 100644 index 0000000..6f68c6d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/api_requests/service.py @@ -0,0 +1,114 @@ +"""绘图供应商请求服务的统一分发层。 + +每个服务商协议位于独立模块中,本服务仅提供稳定的调用入口并传递共享上下文。 +``DrawingClient`` 因此不需要了解某个服务商的请求体格式,也无需使用 Mixin +将大量实现混入客户端类。 +""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any + +from .chat import call_chat_api +from .common import post_json_for_image +from .context import DrawingRequestContext +from .gemini import call_gemini_api +from .google import call_google_api +from .grok import call_grok_api +from .images import call_images_api +from .presets import call_preset_api, call_stepfun_api + + +@dataclass(slots=True) +class DrawingApiRequestService: + """协调各服务商请求实现并对外暴露统一调用入口。 + + 每个方法保持一层直接转发,目的是固定高层调用契约;服务商特有的参数和 + 能力限制仍留在各自模块,避免该类成为新的请求逻辑聚集点。 + """ + + context: DrawingRequestContext + + async def call_google_api( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None, + provider: dict, + ) -> bytes | None: + return await call_google_api(self.context, prompt, images_data, provider) + + async def call_preset_api( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None, + provider: dict, + provider_type: str, + ) -> bytes | None: + return await call_preset_api( + self.context, prompt, images_data, provider, provider_type + ) + + async def post_json_for_image( + self, + target_url: str, + headers: dict[str, str], + payload: dict[str, Any], + timeout: int | float, + provider_name: str, + provider: dict, + ) -> bytes | None: + return await post_json_for_image( + self.context, + target_url, + headers, + payload, + timeout, + provider_name, + provider, + ) + + async def call_stepfun_api( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None, + provider: dict, + api_key: str, + model: str, + timeout: int | float, + ) -> bytes | None: + return await call_stepfun_api( + self.context, prompt, images_data, provider, api_key, model, timeout + ) + + async def call_images_api( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None = None, + provider: dict | None = None, + ) -> bytes | None: + return await call_images_api(self.context, prompt, images_data, provider) + + async def call_grok_api( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None = None, + provider: dict | None = None, + ) -> bytes | None: + return await call_grok_api(self.context, prompt, images_data, provider) + + async def call_gemini_api( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None = None, + provider: dict | None = None, + ) -> bytes | None: + return await call_gemini_api(self.context, prompt, images_data, provider) + + async def call_chat_api( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None = None, + provider: dict | None = None, + ) -> bytes | None: + return await call_chat_api(self.context, prompt, images_data, provider) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/drawing_client.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/drawing_client.py new file mode 100644 index 0000000..9466eed --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/drawing_client.py @@ -0,0 +1,432 @@ +"""漫画绘图客户端的高层调度入口。 + +``DrawingClient`` 保留插件既有的私有兼容入口,供调用方和扩展继续使用;实际 +供应商请求与图片响应分别委托给两个组合服务。客户端只保留供应商回退、重试和 +全局配置读取,避免 HTTP 协议细节再次集中到一个过大的类中。 +""" + +import asyncio +import re +from typing import Any + +import httpx + +from ...utils.logger import logger +from ..config.config_manager import ConfigManager +from .api_requests import DrawingApiRequestService +from .api_requests.context import DrawingRequestContext +from .api_requests.presets import resolve_dashscope_size +from .drawing_image_response import ( + DrawingImageResponseService, + ImageDownloadFailedError, +) + +__all__ = ["DrawingClient", "ImageDownloadFailedError"] + + +# 供应商条目是唯一的连接配置来源。这里的默认值只用于兼容手工编辑的缺失字段, +# 不再读取配置面板中已移除的外层绘图参数。 +DRAWING_PROVIDER_DEFAULTS: dict[str, Any] = { + "api_url": "", + "api_key": "", + "model": "gpt-image-2", + "api_protocol": "images", + "image_size": "1024x1024", + "aspect_ratio": "16:9", + "image_quality": "high", + "background": "auto", + "output_format": "png", + "timeout": 600, +} + + +class DrawingClient: + """协调绘图供应商选择、重试、请求服务和图片响应处理。 + + 服务对象通过 ``DrawingRequestContext`` 显式获取所需能力,而不是继承 + 客户端内部状态。私有兼容入口仍保留为薄转发层,确保既有扩展和测试替换 + ``_post_json_for_image`` 等方法时能够继续生效。 + """ + + def __init__(self, config_manager: ConfigManager): + self.config_manager = config_manager + self._image_response_service = DrawingImageResponseService( + hooks=self, + # 保持实例替换下载方法时,响应服务也会使用替换后的实现。 + download_image=lambda url, proxy: self.download_public_image(url, proxy), + ) + self._request_service = DrawingApiRequestService( + DrawingRequestContext( + hooks=self, + # 保持既有测试和扩展对兼容入口的动态替换能力。 + request_json=lambda *args: self._post_json_for_image(*args), + extract_image=lambda data, proxy: self._extract_image_from_response( + data, proxy + ), + ) + ) + + def _build_target_url(self, raw_url: str, protocol: str) -> str: + """智能解析补全用户配置的 API URL。""" + url = (raw_url or "").strip().rstrip("/") + if not url: + if protocol == "grok": + url = "https://api.x.ai" + elif protocol == "gemini": + url = "https://generativelanguage.googleapis.com" + else: + url = "https://api.openai.com/v1" + + if protocol == "images": + if url.endswith("/images/generations"): + return url + if url.endswith("/v1"): + return f"{url}/images/generations" + if "/v1/" in url: + return url if "images" in url else f"{url}/images/generations" + return f"{url}/v1/images/generations" + if protocol == "chat": + if url.endswith("/chat/completions"): + return url + if url.endswith("/v1"): + return f"{url}/chat/completions" + if "/v1/" in url: + return url if "chat" in url else f"{url}/chat/completions" + return f"{url}/v1/chat/completions" + if protocol == "grok": + if url.endswith(("/images/generations", "/images/edits")): + return url + if url.endswith("/v1"): + return f"{url}/images/generations" + if "/v1/" in url: + return url if "/images/" in url else f"{url}/images/generations" + return f"{url}/v1/images/generations" + if protocol == "gemini": + if url.endswith("/interactions"): + return url + if url.endswith(("/v1beta", "/v1")): + return f"{url}/interactions" + return f"{url}/v1beta/interactions" + raise ValueError(f"不支持的绘图 API 协议: {protocol}") + + async def generate_image( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None = None, + disable_retry: bool = False, + ) -> tuple[bytes | None, str | None]: + """调用候选供应商生成单张图片。 + + Args: + prompt: 用于生成图片的提示词。 + images_data: 可选参考图片及其 MIME 类型。 + disable_retry: 是否禁用请求失败后的重试。 + + Returns: + 图片二进制数据与最后一次错误信息组成的元组。 + """ + provider_configs = self.config_manager.get_drawing_provider_configs() + if not provider_configs: + message = "未配置有效的漫画绘图供应商,请在绘图供应商配置表中添加条目。" + logger.warning("[Comic] %s", message) + return None, message + + last_error_msg = None + last_download_error: ImageDownloadFailedError | None = None + for provider in provider_configs: + try: + result, last_error_msg = await self._generate_image_with_provider( + prompt, images_data, disable_retry, provider + ) + except ImageDownloadFailedError as exc: + # 图片已经由上游生成,但当前候选返回的 URL 无法下载;继续尝试后备供应商。 + last_download_error = exc + last_error_msg = str(exc) + result = None + if result: + return result, None + provider_name = str(provider.get("name", "unnamed")).strip() + logger.warning( + "[Comic] 绘图供应商 %s 失败,尝试下一个候选。", + provider_name or "unnamed", + ) + if last_download_error: + raise last_download_error + return None, last_error_msg + + async def _generate_image_with_provider( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None, + disable_retry: bool, + provider: dict, + ) -> tuple[bytes | None, str | None]: + """使用一个已配置供应商执行生成并处理重试。""" + api_protocol = self._get_provider_value("api_protocol", provider) + max_retries = self.config_manager.get_drawing_network_retries() + output_exception_retries = ( + 0 + if disable_retry + else self.config_manager.get_drawing_output_exception_retries() + ) + exception_keywords = ( + self.config_manager.get_drawing_output_exception_retry_keywords() + ) + retry_delay = self.config_manager.get_drawing_retry_delay() + exception_retry_count = 0 + network_retry_count = 0 + last_error_msg = None + + while True: + try: + if api_protocol == "images": + result = await self._call_images_api(prompt, images_data, provider) + elif api_protocol == "chat": + result = await self._call_chat_api(prompt, images_data, provider) + elif api_protocol == "google": + result = await self._call_google_api(prompt, images_data, provider) + elif api_protocol == "grok": + result = await self._call_grok_api(prompt, images_data, provider) + elif api_protocol == "gemini": + result = await self._call_gemini_api(prompt, images_data, provider) + elif api_protocol in { + "agnes_ai", + "xai", + "minimax", + "doubao", + "sensenova", + "dashscope", + "stepfun", + }: + result = await self._call_preset_api( + prompt, images_data, provider, api_protocol + ) + else: + raise ValueError(f"不支持的绘图 API 协议: {api_protocol}") + if result: + return result, None + break + except Exception as exc: + if isinstance(exc, ImageDownloadFailedError): + raise + last_error_msg = str(exc) + logger.error( + "[Comic] 画图报错 (%s): %s", type(exc).__name__, last_error_msg + ) + if disable_retry: + break + is_exception = any( + keyword in last_error_msg + for keyword in exception_keywords + if keyword + ) + if is_exception: + if exception_retry_count < output_exception_retries: + exception_retry_count += 1 + logger.info( + "[Comic] 命中异常关键词,开始第 %d 次内容重试...", + exception_retry_count, + ) + await asyncio.sleep(retry_delay) + continue + break + status_match = re.search(r"HTTP (\d{3})", last_error_msg) + status_code = int(status_match.group(1)) if status_match else None + is_retryable_network_error = isinstance(exc, httpx.RequestError) or ( + status_code in {408, 409, 429} + or status_code is not None + and status_code >= 500 + ) + if not is_retryable_network_error or network_retry_count >= max_retries: + break + network_retry_count += 1 + logger.info( + "[Comic] 网络或服务报错,开始第 %d 次网络重试...", + network_retry_count, + ) + await asyncio.sleep(retry_delay) + + logger.debug("[Comic] 画图重试次数耗尽或请求失败,任务终止。") + return None, last_error_msg + + def _get_provider_value(self, name: str, provider: dict) -> Any: + """读取供应商条目字段,并为缺失字段提供安全默认值。 + + 绘图连接参数只允许来自当前条目,避免删除面板外层字段后仍出现不可见的 + 回退来源。模板正常保存时会提供完整字段,默认值仅保护旧数据或手工配置。 + """ + value = provider.get(name) + if value not in (None, ""): + return value + return DRAWING_PROVIDER_DEFAULTS.get(name, "") + + def _get_request_proxy(self, provider: dict | None = None) -> str | None: + """获取当前绘图请求的代理,供应商配置优先于全局配置。""" + provider_proxy = str((provider or {}).get("proxy", "")).strip() + if provider_proxy: + return provider_proxy + getter = getattr(self.config_manager, "get_drawing_proxy", None) + global_proxy = getter() if callable(getter) else "" + return str(global_proxy).strip() or None + + def _resolve_size(self, size_or_ratio: str, aspect_ratio: str) -> str: + """按当前供应商条目的比例解析 API 支持的 WxH 尺寸。""" + size = (size_or_ratio or "").strip().lower() + aspect_ratio = (aspect_ratio or "").strip().lower() + if not aspect_ratio: + aspect_ratio = "16:9" + size_aliases = {"1k": 1024, "2k": 2560, "4k": 3840} + if size in size_aliases: + result = self._build_size_from_ratio(size_aliases[size], aspect_ratio) + elif size in {"auto", ""}: + result = self._build_size_from_ratio(1792, aspect_ratio) + elif ":" in size and re.fullmatch(r"\d+:\d+", size): + result = self._build_size_from_ratio(1792, size) + elif re.fullmatch(r"\d+x\d+", size): + result = size + else: + result = self._build_size_from_ratio(1792, aspect_ratio) + if re.fullmatch(r"\d+x\d+", result): + try: + width, height = map(int, result.split("x")) + result = ( + f"{max(16, ((width + 15) // 16) * 16)}" + f"x{max(16, ((height + 15) // 16) * 16)}" + ) + except ValueError: + pass + return result + + @staticmethod + def _build_size_from_ratio(long_edge: int, aspect_ratio: str) -> str: + """按长边和宽高比构建 16 的倍数尺寸。""" + if not aspect_ratio or ":" not in aspect_ratio: + aspect_ratio = "16:9" + try: + width_ratio, height_ratio = map(int, aspect_ratio.split(":", 1)) + except ValueError: + width_ratio, height_ratio = 16, 9 + if width_ratio >= height_ratio: + width = long_edge + height = max(2, round(long_edge * height_ratio / width_ratio)) + else: + height = long_edge + width = max(2, round(long_edge * width_ratio / height_ratio)) + width = max(16, ((width + 15) // 16) * 16) + height = max(16, ((height + 15) // 16) * 16) + return f"{width}x{height}" + + async def _call_google_api( + self, prompt: str, images_data: list[tuple[bytes, str]] | None, provider: dict + ) -> bytes | None: + return await self._request_service.call_google_api( + prompt, images_data, provider + ) + + async def _call_preset_api( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None, + provider: dict, + provider_type: str, + ) -> bytes | None: + return await self._request_service.call_preset_api( + prompt, images_data, provider, provider_type + ) + + async def _call_stepfun_api( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None, + provider: dict, + api_key: str, + model: str, + timeout: int | float, + ) -> bytes | None: + return await self._request_service.call_stepfun_api( + prompt, images_data, provider, api_key, model, timeout + ) + + async def _post_json_for_image( + self, + target_url: str, + headers: dict[str, str], + payload: dict[str, Any], + timeout: int | float, + provider_name: str, + provider: dict, + ) -> bytes | None: + return await self._request_service.post_json_for_image( + target_url, headers, payload, timeout, provider_name, provider + ) + + def _resolve_dashscope_size(self, image_size: str, aspect_ratio: str) -> str: + return resolve_dashscope_size(image_size, aspect_ratio) + + async def _call_images_api( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None = None, + provider: dict | None = None, + ) -> bytes | None: + return await self._request_service.call_images_api( + prompt, images_data, provider + ) + + async def _call_grok_api( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None = None, + provider: dict | None = None, + ) -> bytes | None: + return await self._request_service.call_grok_api(prompt, images_data, provider) + + async def _call_gemini_api( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None = None, + provider: dict | None = None, + ) -> bytes | None: + return await self._request_service.call_gemini_api( + prompt, images_data, provider + ) + + async def _call_chat_api( + self, + prompt: str, + images_data: list[tuple[bytes, str]] | None = None, + provider: dict | None = None, + ) -> bytes | None: + return await self._request_service.call_chat_api(prompt, images_data, provider) + + async def _extract_image_from_response( + self, data: Any, proxy: str | None = None + ) -> bytes | None: + return await self._image_response_service.extract_image_from_response( + data, proxy + ) + + @staticmethod + def _decode_data_uri(data_uri: str) -> bytes: + return DrawingImageResponseService.decode_data_uri(data_uri) + + @staticmethod + def _decode_base64(encoded: str) -> bytes: + return DrawingImageResponseService.decode_base64(encoded) + + @staticmethod + def _validate_image_bytes(data: bytes) -> None: + DrawingImageResponseService.validate_image_bytes(data) + + async def download_public_image( + self, url: str, proxy: str | None = None + ) -> bytes | None: + return await self._image_response_service.download_public_image(url, proxy) + + @staticmethod + def _sanitize_url(url: str) -> str: + return DrawingImageResponseService.sanitize_url(url) + + @staticmethod + def _summarize_response(data: Any) -> str: + return DrawingImageResponseService.summarize_response(data) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/drawing_image_response.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/drawing_image_response.py new file mode 100644 index 0000000..846f5c2 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/drawing/drawing_image_response.py @@ -0,0 +1,305 @@ +"""绘图接口响应的图片提取、下载与安全校验。 + +不同供应商会把图片放在 Base64、Data URI、Markdown 或 URL 字段中。本服务按 +可靠性由高到低依次处理这些候选内容,并对公网下载地址及图片签名做校验,防止 +将接口错误页、内网地址或超大内容作为漫画图片继续投递。 +""" + +import asyncio +import base64 +import binascii +import re +from collections.abc import Awaitable, Callable +from dataclasses import dataclass +from typing import Any, Protocol +from urllib.parse import urlsplit, urlunsplit + +import httpx + +from ...utils.logger import logger + + +class ImageDownloadFailedError(Exception): + """图片下载失败,但保留了最后一次尝试的原始 URL 供兜底发送。""" + + def __init__(self, message: str, fallback_url: str | None = None): + super().__init__(message) + self.fallback_url = fallback_url + + +class DrawingImageResponseHooks(Protocol): + """描述图片响应服务依赖的宿主能力。""" + + config_manager: Any + + +@dataclass(slots=True) +class DrawingImageResponseService: + """封装绘图响应解析、图片下载和安全校验。 + + ``hooks`` 只保存下载代理所需的配置访问能力,实际下载函数显式注入,使 + 响应处理独立于 ``DrawingClient`` 的具体实现,也允许测试安全地替换下载。 + """ + + hooks: DrawingImageResponseHooks + download_image: Callable[[str, str | None], Awaitable[bytes | None]] + + MAX_IMAGE_BYTES = 100 * 1024 * 1024 + MAX_IMAGE_REDIRECTS = 5 + IMAGE_DOWNLOAD_TOTAL_TIMEOUT = 90 + + async def extract_image_from_response( + self, data: Any, proxy: str | None = None + ) -> bytes | None: + """递归提取绘图响应中的图片数据。""" + encoded: list[tuple[str, str]] = [] + image_fields: list[tuple[str, str]] = [] + content_images: list[tuple[str, str]] = [] + content_urls: list[tuple[str, str]] = [] + fallback_urls: list[tuple[str, str]] = [] + + def collect(value: Any, path: tuple[str, ...] = ()) -> None: + if isinstance(value, dict): + for name, item in value.items(): + collect(item, (*path, name.lower())) + elif isinstance(value, list): + for item in value: + collect(item, path) + elif isinstance(value, str): + text = value.strip() + if not text: + return + key = path[-1] if path else "" + if key in {"b64_json", "base64"}: + encoded.append(("base64", text)) + return + if key in {"image_url", "image"} or ( + key == "url" + and any( + name in {"data", "image", "images", "image_url"} + for name in path[:-1] + ) + ): + image_fields.append(("value", text)) + return + + data_uris = re.findall( + r"data:image/[^\s,;]+(?:;[^\s,;]+)*;base64,[A-Za-z0-9+/=_-]+", + text, + re.IGNORECASE, + ) + content_images.extend(("value", item) for item in data_uris) + + markdown_urls = re.findall( + r"!\[[^\]]*\]\((https?://[^\s<>\"')\]]+)\)", text + ) + content_images.extend( + ("url", item.rstrip(".,;`")) for item in markdown_urls + ) + + urls = re.findall(r"https?://[^\s<>\"')\]]+", text) + markdown_url_set = set(markdown_urls) + target = content_urls if key in {"content", "text"} else fallback_urls + target.extend( + ("url", item.rstrip(".,;`")) + for item in urls + if item not in markdown_url_set + ) + + if not data_uris and not urls and len(text) >= 100: + encoded.append(("base64", text)) + + collect(data) + last_download_error: Exception | None = None + last_download_url: str | None = None + candidates = ( + encoded + image_fields + content_images + content_urls + fallback_urls + ) + for candidate_type, candidate in candidates: + try: + if candidate_type == "url" or candidate.startswith( + ("http://", "https://") + ): + last_download_url = candidate + image = await self.download_image(candidate, proxy) + elif candidate.startswith("data:image/"): + image = self.decode_data_uri(candidate) + elif candidate.startswith("base64://"): + image = self.decode_base64(candidate[len("base64://") :]) + else: + image = self.decode_base64(candidate) + if image: + return image + except (httpx.HTTPError, httpx.TimeoutException) as exc: + logger.warning("[Comic] 图片下载失败 (%s): %s", type(exc).__name__, exc) + last_download_error = exc + except (ValueError, TypeError, binascii.Error) as exc: + logger.warning("[Comic] 跳过无效图片候选内容: %s", exc) + + if last_download_error: + raise ImageDownloadFailedError( + str(last_download_error), fallback_url=last_download_url + ) + return None + + @classmethod + def decode_data_uri(cls, data_uri: str) -> bytes: + """解码 image/* Data URI。""" + header, encoded = data_uri.split(",", 1) + if ";base64" not in header.lower(): + raise ValueError("Data URI 不是 Base64 图片") + return cls.decode_base64(encoded) + + @classmethod + def decode_base64(cls, encoded: str) -> bytes: + """解码标准或 URL-safe Base64,并确认结果是图片。""" + normalized = re.sub(r"\s+", "", encoded).replace("-", "+").replace("_", "/") + try: + normalized.encode("ascii") + except UnicodeEncodeError as exc: + raise ValueError("Base64 候选内容含非 ASCII 字符,跳过") from exc + if len(normalized) > cls.MAX_IMAGE_BYTES * 4 // 3 + 4: + raise ValueError("Base64 图片负载超过 100MB") + normalized += "=" * (-len(normalized) % 4) + decoded = base64.b64decode(normalized, validate=True) + cls.validate_image_bytes(decoded) + return decoded + + @staticmethod + def validate_image_bytes(data: bytes) -> None: + """拒绝 HTML、JSON 等非图片响应。""" + if not data: + raise ValueError("响应内容为空") + probe = data[:32] + is_webp = len(data) >= 12 and data[:4] == b"RIFF" and data[8:12] == b"WEBP" + is_avif = ( + len(data) >= 12 + and data[4:8] == b"ftyp" + and data[8:12] in {b"avif", b"avis"} + ) + is_jp2 = len(data) >= 12 and data[4:8] == b"ftyp" and b"jp2" in data[8:12] + signatures = ( + b"\x89PNG\r\n\x1a\n", + b"\xff\xd8\xff", + b"GIF87a", + b"GIF89a", + b"BM", + b"II*\x00", + b"MM\x00*", + b"\x00\x00\x00\x0cjP ", + ) + starts_with_sig = any(probe.find(sig) < 4 for sig in signatures) + if starts_with_sig or is_webp or is_avif or is_jp2: + return + head = data[:64].decode("ascii", errors="ignore").lower() + if head.startswith((" bytes | None: + """从公网 URL 下载已校验且大小受限的图片。""" + try: + return await asyncio.wait_for( + self._download_image_inner(url, proxy), + timeout=self.IMAGE_DOWNLOAD_TOTAL_TIMEOUT, + ) + except asyncio.TimeoutError as exc: + raise httpx.TimeoutException( + f"图片下载超过 {self.IMAGE_DOWNLOAD_TOTAL_TIMEOUT}s 总超时限制: {self.sanitize_url(url)}" + ) from exc + + async def _download_image_inner( + self, url: str, proxy: str | None = None + ) -> bytes | None: + """实际下载逻辑。""" + current_url = url + download_timeout = httpx.Timeout(connect=20.0, read=60.0, write=20.0, pool=20.0) + request_proxy = ( + proxy or self.hooks.config_manager.get_drawing_download_proxy() or None + ) + if request_proxy: + logger.debug( + "[Comic] 图片下载使用代理: %s", self.sanitize_url(request_proxy) + ) + async with httpx.AsyncClient( + timeout=download_timeout, + follow_redirects=False, + proxy=request_proxy, + ) as client: + for redirect_count in range(self.MAX_IMAGE_REDIRECTS + 1): + await self._validate_public_image_url(current_url) + logger.info( + "[Comic] 正在下载图片 URL: %s", self.sanitize_url(current_url) + ) + resp = await client.get(current_url) + if resp.status_code in {301, 302, 303, 307, 308}: + location = resp.headers.get("Location") + if not location: + raise httpx.HTTPStatusError( + f"图片重定向缺少地址 [HTTP {resp.status_code}]", + request=resp.request, + response=resp, + ) + if redirect_count >= self.MAX_IMAGE_REDIRECTS: + raise ValueError("图片下载重定向次数超过限制") + current_url = str(resp.url.join(location)) + continue + if resp.status_code != 200: + raise httpx.HTTPStatusError( + f"图片下载失败 [HTTP {resp.status_code}]", + request=resp.request, + response=resp, + ) + image_bytes = resp.content + if len(image_bytes) > self.MAX_IMAGE_BYTES: + raise ValueError("图片下载内容超过 100MB") + self.validate_image_bytes(image_bytes) + return image_bytes + raise ValueError("图片下载失败") + + async def _validate_public_image_url(self, url: str) -> None: + """校验图片地址协议与基础合法性,兼容本地与私网自建绘图服务。""" + parsed = urlsplit(url) + if parsed.scheme not in {"http", "https"} or not parsed.hostname: + raise ValueError("图片地址必须是有效的 HTTP/HTTPS URL") + if parsed.username or parsed.password: + raise ValueError("图片地址不允许包含用户凭据") + + @staticmethod + def sanitize_url(url: str) -> str: + """移除日志中的查询参数、片段和用户凭据。""" + parsed = urlsplit(url) + host = parsed.hostname or "" + if parsed.port: + host = f"{host}:{parsed.port}" + return urlunsplit((parsed.scheme, host, parsed.path, "", "")) + + @staticmethod + def summarize_response(data: Any) -> str: + """生成不包含响应正文和 Base64 的结构摘要。""" + + def summarize(value: Any, depth: int = 0) -> str: + if isinstance(value, str): + return f"" + if depth >= 3: + return type(value).__name__ + if isinstance(value, dict): + items = list(value.items())[:10] + body = ", ".join( + f"{str(key)[:64]}: {summarize(item, depth + 1)}" + for key, item in items + ) + suffix = ", ..." if len(value) > len(items) else "" + return f"{{{body}{suffix}}}" + if isinstance(value, list): + items = value[:3] + body = ", ".join(summarize(item, depth + 1) for item in items) + suffix = ", ..." if len(value) > len(items) else "" + return f"[{body}{suffix}] (len={len(value)})" + return f"<{type(value).__name__}>" + + return summarize(data) + + +__all__ = ["DrawingImageResponseService", "ImageDownloadFailedError"] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/logging/plugin_log_buffer.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/logging/plugin_log_buffer.py new file mode 100644 index 0000000..7773c7e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/logging/plugin_log_buffer.py @@ -0,0 +1,266 @@ +""" +群分析插件专用内存日志缓冲与标签提取器 +提供高性能环形队列日志存储、语义化标签提取与多维度筛选能力。 +""" + +from __future__ import annotations + +import logging +import re +import time +from collections import deque +from dataclasses import asdict, dataclass +from typing import Any + + +@dataclass +class PluginLogEntry: + id: str + timestamp: float + time_str: str + level: str + logger_name: str + trace_id: str | None + stage: str | None + tag: str + message: str + raw: str + + def to_dict(self) -> dict[str, Any]: + return asdict(self) + + +class PluginLogBuffer(logging.Handler): + """ + 专用插件日志处理器,挂载到 logging 捕获群分析插件全链路日志 + """ + + TAG_PATTERNS: list[tuple[str, str, re.Pattern[str]]] = [ + ( + "LLM", + "大模型调用", + re.compile( + r"(llm|analyzer|prompt|openai|deepseek|claude|qwen|gpt|token)", re.I + ), + ), + ( + "Album", + "群相册", + re.compile(r"(album|相册|qun_album|group_album)", re.I), + ), + ( + "OneBot", + "OneBot协议", + re.compile(r"(onebot|napcat|llonebot|aiocqhttp|gocq)", re.I), + ), + ( + "QQOfficial", + "QQ官方机器人", + re.compile(r"(qq_official|botpy|c2c|guild)", re.I), + ), + ("Telegram", "Telegram平台", re.compile(r"(telegram|telethon)", re.I)), + ("Discord", "Discord平台", re.compile(r"(discord|discord_bot)", re.I)), + ( + "Scheduler", + "定时与调度", + re.compile(r"(scheduler|cron|job|timer|incremental)", re.I), + ), + ( + "Resilience", + "容错与重试", + re.compile(r"(resilience|retry|limiter|circuit|lock|reaper)", re.I), + ), + ( + "Comic", + "群漫画", + re.compile( + r"(comic|漫画|分镜|drawing|storyboard|grok2api|big_banana)", re.I + ), + ), + ( + "Render", + "报告与长图", + re.compile(r"(render|template|html|image|report|playwright|canvas)", re.I), + ), + ( + "WebUI", + "控制台交互", + re.compile(r"(webui|bridge|api_|dashboard|route)", re.I), + ), + ("Trace", "链路追踪", re.compile(r"(trace|span|context_metric)", re.I)), + ] + + STAGE_NAMES = { + "FETCH_MESSAGES": "拉取聊天记录", + "CLEAN_MESSAGES": "消息清洗过滤", + "STATS_ANALYSIS": "基础统计分析", + "LLM_ANALYSIS": "大模型话题与画像分析", + "SAVE_SUMMARY": "历史记录持久化", + "RENDER_REPORT": "报告图片渲染与发送", + "COMIC_STORYBOARD": "漫画分镜提示词提取", + "COMIC_DRAWING": "漫画长图生成与投递", + "CRASH_RECOVERY": "异常终止恢复", + } + + def __init__(self, max_capacity: int = 2000): + super().__init__() + self.max_capacity = max_capacity + self._buffer: deque[PluginLogEntry] = deque(maxlen=max_capacity) + self._counter = 0 + self._listeners: set[Any] = set() + + def register_listener(self, listener: Any) -> None: + """注册日志实时推送监听器""" + self._listeners.add(listener) + + def unregister_listener(self, listener: Any) -> None: + """注销日志实时推送监听器""" + self._listeners.discard(listener) + + def record_log( + self, + level: str, + msg: str, + trace_id: str | None = None, + logger_name: str = "plugin", + ) -> PluginLogEntry: + """主动记录日志条目并实时推送给前端监听器""" + self._counter += 1 + now = time.time() + time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(now)) + msecs = int((now - int(now)) * 1000) + full_time_str = f"{time_str}.{msecs:03d}" + + # 解析 TraceID:优先从参数取,其次从 TraceContext 上下文取,最后从日志文本中提取 + if not trace_id: + try: + from ...shared.trace_context import TraceContext + + ctx = TraceContext.current() + if ctx and ctx.trace_id: + trace_id = ctx.trace_id + except Exception: + pass + + if not trace_id: + trace_match = re.search( + r"\[(manual|incr|group|web_manual|report|[a-zA-Z0-9_\-]+)_[a-zA-Z0-9_\-]+\]", + msg, + ) + if trace_match: + trace_id = trace_match.group(0).strip("[]") + + # 语义化标签分类 + tag = "General" + for tag_key, _, pattern in self.TAG_PATTERNS: + if pattern.search(msg) or pattern.search(logger_name): + tag = tag_key + break + + # 阶段解析 + stage = None + for stage_code, stage_label in self.STAGE_NAMES.items(): + if stage_code in msg or stage_label in msg: + stage = stage_label + break + + entry = PluginLogEntry( + id=f"log_{self._counter}", + timestamp=now, + time_str=full_time_str, + level=level.upper(), + logger_name=logger_name, + trace_id=trace_id, + stage=stage, + tag=tag, + message=msg, + raw=f"[{full_time_str}] [{level.upper()}] [{logger_name}]: {msg}", + ) + self._buffer.append(entry) + + for listener in list(self._listeners): + try: + listener(entry) + except Exception: + pass + + return entry + + def emit(self, record: logging.LogRecord) -> None: + try: + msg = record.getMessage() + logger_name = record.name + + # 仅捕获群分析插件内部日志或带标识日志 + is_plugin_log = ( + "astrbot_plugin_qq_group_daily_analysis" in logger_name + or "daily_analysis" in logger_name + or "[群分析插件]" in msg + or hasattr(record, "trace_id") + ) + if not is_plugin_log: + return + + trace_id = getattr(record, "trace_id", None) + self.record_log( + level=record.levelname, + msg=msg, + trace_id=trace_id, + logger_name=logger_name.split(".")[-1] + if "." in logger_name + else logger_name, + ) + except Exception: + self.handleError(record) + + def query( + self, + limit: int = 100, + offset: int = 0, + level: str | None = None, + trace_id: str | None = None, + tag: str | None = None, + search: str | None = None, + ) -> tuple[list[dict[str, Any]], int]: + """按条件多维度筛选日志列表(按时间倒序)""" + results: list[PluginLogEntry] = [] + target_level = level.upper().strip() if level else None + target_trace = trace_id.strip() if trace_id else None + target_tag = tag.strip() if tag else None + search_kw = search.strip().lower() if search else None + + for entry in reversed(self._buffer): + if target_level and entry.level != target_level: + continue + if target_trace and entry.trace_id != target_trace: + continue + if target_tag and entry.tag.lower() != target_tag.lower(): + continue + if search_kw: + if ( + search_kw not in entry.message.lower() + and search_kw not in (entry.trace_id or "").lower() + and search_kw not in entry.logger_name.lower() + ): + continue + results.append(entry) + + total = len(results) + paged = results[offset : offset + limit] + return [e.to_dict() for e in paged], total + + def get_trace_logs(self, trace_id: str) -> list[dict[str, Any]]: + """获取特定 TraceID 的全部日志记录""" + return [ + e.to_dict() + for e in self._buffer + if e.trace_id == trace_id or (trace_id and trace_id in e.message) + ] + + def clear(self) -> None: + """清空内存缓冲""" + self._buffer.clear() + + +# 全局单例日志缓冲器 +global_log_buffer = PluginLogBuffer() diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/messaging/message_sender.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/messaging/message_sender.py new file mode 100644 index 0000000..dab4834 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/messaging/message_sender.py @@ -0,0 +1,79 @@ +""" +消息发送器 - 基础设施层 +提供高层消息发送接口,支持跨平台智能路由。 +""" + +from ...utils.logger import logger + + +class MessageSender: + """ + 消息发送器 + 封装了 PlatformAdapter 的底层调用,提供更高层的发送接口 + """ + + def __init__(self, bot_manager, config_manager): + self.bot_manager = bot_manager + self.config_manager = config_manager + + async def send_text( + self, group_id: str, text: str, platform_id: str | None = None + ) -> bool: + """发送文本消息""" + adapter = self.bot_manager.get_adapter(platform_id) + if not adapter: + logger.error(f"[MessageSender] 未找到平台 {platform_id} 的适配器") + return False + return await adapter.send_text(group_id, text) + + async def send_image_smart( + self, + group_id: str, + image_url: str, + caption: str = "", + platform_id: str | None = None, + ) -> bool: + """智能发送图片,支持自动选择适配器""" + adapter = self.bot_manager.get_adapter(platform_id) + if not adapter: + logger.error(f"[MessageSender] 未找到平台 {platform_id} 的适配器") + return False + return await adapter.send_image(group_id, image_url, caption) + + async def send_file( + self, + group_id: str, + file_path: str, + caption: str = "", + platform_id: str | None = None, + ) -> bool: + """发送文件(HTML/PDF/其它文件)。支持可选 caption。""" + adapter = self.bot_manager.get_adapter(platform_id) + if not adapter: + logger.error(f"[MessageSender] 未找到平台 {platform_id} 的适配器") + return False + + # 首先发送文件,本方法的返回值只代表文件是否发送成功。 + file_sent = await adapter.send_file(group_id, file_path) + + if not file_sent: + # 适配器返回 False,表示文件未成功发送 + return False + + # 文件已成功发送,下面的 caption 发送为尽力而为,不影响整体成功与否。 + if caption: + try: + caption_sent = await adapter.send_text(group_id, f"{caption}") + if not caption_sent: + logger.warning( + "[MessageSender] 文件已发送,但 caption 发送失败(适配器返回 False)" + ) + except Exception as e: + logger.warning(f"[MessageSender] 文件已发送,但 caption 发送异常: {e}") + + return True + + def _get_available_platforms(self, group_id: str): + """获取可用的平台列表 (Helper for Dispatcher)""" + # 简单实现:返回所有已加载的平台 + return [(pid, None) for pid in self.bot_manager.get_platform_ids()] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/__init__.py new file mode 100644 index 0000000..d429bd8 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/__init__.py @@ -0,0 +1,10 @@ +""" +持久化模块 - 数据存储实现 + +包含历史记录仓储和增量分析状态仓储。 +""" + +from .history_repository import HistoryRepository +from .incremental_store import IncrementalStore + +__all__ = ["HistoryRepository", "IncrementalStore"] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/checkpoint_store.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/checkpoint_store.py new file mode 100644 index 0000000..46b997b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/checkpoint_store.py @@ -0,0 +1,124 @@ +""" +阶段 Checkpoint 缓存仓储 - 支持分析子阶段产物缓存与局部断点续跑 (Partial Resume) +""" + +from __future__ import annotations + +import json +import sqlite3 +import time +from pathlib import Path +from typing import Any + + +class CheckpointStore: + """阶段 Checkpoint 存储器,用于在子阶段失败时实现秒级局部重试并节省 Token""" + + def __init__(self, db_path: Path): + self.db_path = Path(db_path) + self.db_path.parent.mkdir(parents=True, exist_ok=True) + self._init_db() + + def _get_connection(self) -> sqlite3.Connection: + conn = sqlite3.connect(str(self.db_path), timeout=10.0) + conn.row_factory = sqlite3.Row + conn.execute("PRAGMA journal_mode=WAL;") + return conn + + def _init_db(self) -> None: + with self._get_connection() as conn: + conn.execute( + """ + CREATE TABLE IF NOT EXISTS stage_checkpoints ( + checkpoint_id TEXT PRIMARY KEY, + group_id TEXT NOT NULL, + date_str TEXT NOT NULL, + stage_name TEXT NOT NULL, + data_json TEXT NOT NULL, + created_at REAL NOT NULL, + expire_at REAL NOT NULL + ); + """ + ) + conn.execute( + "CREATE INDEX IF NOT EXISTS idx_chk_group_date ON stage_checkpoints(group_id, date_str);" + ) + + def save_checkpoint( + self, + group_id: str, + date_str: str, + stage_name: str, + data: Any, + ttl_seconds: int = 86400 * 30, + ) -> None: + """保存阶段产物快照(默认与 Trace 保留期对齐,保留 30 天)""" + checkpoint_id = f"{group_id}_{date_str}_{stage_name}" + now = time.time() + expire_at = now + ttl_seconds + + with self._get_connection() as conn: + conn.execute( + """ + INSERT INTO stage_checkpoints ( + checkpoint_id, group_id, date_str, stage_name, data_json, created_at, expire_at + ) VALUES (?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(checkpoint_id) DO UPDATE SET + data_json=excluded.data_json, + created_at=excluded.created_at, + expire_at=excluded.expire_at; + """, + ( + checkpoint_id, + str(group_id), + str(date_str), + stage_name, + json.dumps(data, ensure_ascii=False), + now, + expire_at, + ), + ) + + def get_checkpoint( + self, group_id: str, date_str: str, stage_name: str + ) -> Any | None: + """读取有效的阶段产物快照(若已过期则返回 None 并删除)""" + checkpoint_id = f"{group_id}_{date_str}_{stage_name}" + now = time.time() + + with self._get_connection() as conn: + row = conn.execute( + "SELECT * FROM stage_checkpoints WHERE checkpoint_id = ?", + (checkpoint_id,), + ).fetchone() + if not row: + return None + + if row["expire_at"] < now: + conn.execute( + "DELETE FROM stage_checkpoints WHERE checkpoint_id = ?", + (checkpoint_id,), + ) + return None + + try: + return json.loads(row["data_json"]) + except Exception: + return None + + def clear_checkpoints(self, group_id: str, date_str: str) -> None: + """任务全部成功后清理该群当天的临时 Checkpoint""" + with self._get_connection() as conn: + conn.execute( + "DELETE FROM stage_checkpoints WHERE group_id = ? AND date_str = ?", + (str(group_id), str(date_str)), + ) + + def cleanup_expired(self) -> int: + """清理所有已过期的 Checkpoint""" + now = time.time() + with self._get_connection() as conn: + cursor = conn.execute( + "DELETE FROM stage_checkpoints WHERE expire_at < ?", (now,) + ) + return cursor.rowcount diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/history_manager.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/history_manager.py new file mode 100644 index 0000000..aba14cc --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/history_manager.py @@ -0,0 +1,103 @@ +""" +历史记录管理器模块 - 基础设施持久化层 +负责存储和查询群聊分析报告的摘要信息 +使用 AstrBot 的 put_kv_data/get_kv_data 实现 +""" + +import datetime +from typing import Any + +from ...utils.logger import logger + + +class HistoryManager: + """ + 核心组件:历史分析存档管理器 + + 该类负责将每日生成的群消息分析报告摘要持久化存储,并提供查询接口。 + 底层基于 AstrBot 提供的 KV 存储能力(put_kv_data/get_kv_data), + 确保即使在 Bot 重启后也能回溯历史数据。 + """ + + def __init__(self, star_instance: Any): + """ + 初始化历史记录管理器。 + + Args: + star_instance (Any): Star 插件实例,用于访问底层持久化引擎 + """ + self.plugin = star_instance + + async def save_analysis( + self, + group_id: str, + analysis_result: dict[str, Any], + date_str: str | None = None, + time_str: str | None = None, + ) -> bool: + """ + 序列化并存储一份分析报告摘要。 + + 摘要包含:发言总量、人数、提取的主题摘要及生成时间,不包含完整的原始消息流。 + + Args: + group_id (str): 群组 ID + analysis_result (dict[str, Any]): 包含 statistics, topics, user_titles 的完整分析对象 + date_str (str, optional): 归档日期 (YYYY-MM-DD),缺省为当天 + time_str (str, optional): 归档时间点 (HH-MM),缺省为当前时刻 + + Returns: + bool: 存储是否成功 + """ + try: + now = datetime.datetime.now() + if not date_str: + date_str = now.strftime("%Y-%m-%d") + if not time_str: + time_str = now.strftime("%H-%M") + + # 消解非法字符,确保 Key 兼容性 + time_str = time_str.replace(":", "-") + + # 从分析结果中剥离非持久化字段,提取核心统计元数据 + stats = analysis_result.get("statistics") + topics = analysis_result.get("topics", []) + user_titles = analysis_result.get("user_titles", []) + + summary = { + "message_count": getattr(stats, "message_count", 0) if stats else 0, + "participant_count": getattr(stats, "participant_count", 0) + if stats + else 0, + "topics": [{"topic": t.topic, "detail": t.detail} for t in topics], + "user_titles_count": len(user_titles), + "generated_at": now.strftime("%Y-%m-%d %H:%M:%S"), + } + + key = f"analysis_{group_id}_{date_str}_{time_str}" + await self.plugin.put_kv_data(key, summary) + + logger.info( + f"已保存群 {group_id} 在 {date_str} {time_str} 的分析摘要到历史记录 (Key: {key})" + ) + return True + except Exception as e: + logger.error(f"保存历史分析记录失败: {e}", exc_info=True) + return False + + async def get_history( + self, group_id: str, date_str: str, time_str: str + ) -> dict[str, Any] | None: + """ + 根据群组、日期和时间点检索一份历史摘要。 + """ + time_str = time_str.replace(":", "-") + key = f"analysis_{group_id}_{date_str}_{time_str}" + return await self.plugin.get_kv_data(key, None) + + async def has_history(self, group_id: str, date_str: str, time_str: str) -> bool: + """ + 快速判定是否存在指定时间点的历史分析记录。 + """ + history = await self.get_history(group_id, date_str, time_str) + return history is not None diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/history_repository.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/history_repository.py new file mode 100644 index 0000000..278ff3d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/history_repository.py @@ -0,0 +1,212 @@ +""" +历史仓库 - 存储分析历史的实现 + +该模块提供分析结果和历史记录的持久化存储。 +它封装了现有的 history_manager 功能。 +""" + +import json +from datetime import datetime +from pathlib import Path +from typing import Any + +from ...utils.logger import logger + + +class HistoryRepository: + """ + 基础设施:历史仓库 + + 负责群聊分析历史记录的持久化存储与检索。目前使用本地 JSON 文件实现, + 保持了与旧版 `history_manager` 的数据格式兼容性。 + + Attributes: + data_dir (Path): 插件数据存储的总根目录 + history_dir (Path): 专门存放历史记录的子目录 + """ + + def __init__(self, data_dir: str): + """ + 初始化历史仓库。 + + Args: + data_dir (str): 存储历史数据的基础目录路径 + """ + self.data_dir = Path(data_dir) + self.history_dir = self.data_dir / "history" + self._ensure_directories() + + def _ensure_directories(self) -> None: + """内部方法:确保所需的目录结构已创建。""" + self.history_dir.mkdir(parents=True, exist_ok=True) + + def _get_group_history_path(self, group_id: str) -> Path: + """内部方法:获取特定群组的历史 JSON 文件路径。""" + return self.history_dir / f"group_{group_id}.json" + + def save_analysis_result( + self, + group_id: str, + result: dict[str, Any], + date_str: str | None = None, + ) -> bool: + """ + 将分析结果保存到持久化存储。 + + Args: + group_id (str): 群组标识符 + result (dict[str, Any]): 包含统计、金句等信息的分析结果字典 + date_str (str, optional): 关联日期 (YYYY-MM-DD),默认为执行日 + + Returns: + bool: 保存成功返回 True,发生异常返回 False + """ + try: + date_str = date_str or datetime.now().strftime("%Y-%m-%d") + history = self.load_group_history(group_id) + + # 注入执行时间戳 + if "timestamp" not in result: + result["timestamp"] = datetime.now().isoformat() + + # 结构化存储:二级映射 {date -> result} + if "daily" not in history: + history["daily"] = {} + + history["daily"][date_str] = result + history["last_updated"] = datetime.now().isoformat() + + # 原子写入(覆盖) + history_path = self._get_group_history_path(group_id) + with open(history_path, "w", encoding="utf-8") as f: + json.dump(history, f, ensure_ascii=False, indent=2) + + logger.debug(f"已保存群 {group_id} 在 {date_str} 的历史分析记录") + return True + + except Exception as e: + logger.error(f"保存群 {group_id} 的历史记录失败: {e}") + return False + + def load_group_history(self, group_id: str) -> dict[str, Any]: + """ + 加载特定群组的完整历史记录字典。 + + Args: + group_id (str): 群组标识符 + + Returns: + dict[str, Any]: 历史数据字典,若文件不存在则返回包含空 daily 结构的初始字典 + """ + try: + history_path = self._get_group_history_path(group_id) + if history_path.exists(): + with open(history_path, encoding="utf-8") as f: + return json.load(f) + return {"daily": {}, "group_id": group_id} + except Exception as e: + logger.error(f"加载群 {group_id} 的历史记录失败: {e}") + return {"daily": {}, "group_id": group_id} + + def get_analysis_result( + self, group_id: str, date_str: str + ) -> dict[str, Any] | None: + """ + 获取指定日期已存档的分析结果。 + + Args: + group_id (str): 群组 ID + date_str (str): 目标日期 (YYYY-MM-DD) + + Returns: + Optional[dict[str, Any]]: 分析结果字典,未找到则返回 None + """ + history = self.load_group_history(group_id) + return history.get("daily", {}).get(date_str) + + def get_recent_results(self, group_id: str, limit: int = 7) -> list[dict[str, Any]]: + """ + 获取指定群组最近 N 次的分析结果列表。 + + Args: + group_id (str): 群组 ID + limit (int): 最大返回条数 + + Returns: + list[dict[str, Any]]: 按日期降序排列的结果列表 + """ + history = self.load_group_history(group_id) + daily = history.get("daily", {}) + + # 按日期字符串字典序降序排列(YYYY-MM-DD 天然有序) + sorted_dates = sorted(daily.keys(), reverse=True)[:limit] + return [daily[date] for date in sorted_dates] + + def has_analysis_for_date(self, group_id: str, date_str: str) -> bool: + """ + 检查指定日期是否已经生成过分析。 + + Args: + group_id (str): 群组 ID + date_str (str): 日期字符串 + + Returns: + bool: 存在记录则返回 True + """ + return self.get_analysis_result(group_id, date_str) is not None + + def delete_old_history(self, group_id: str, keep_days: int = 30) -> int: + """ + 自动清理超过天数限制的陈旧历史记录。 + + Args: + group_id (str): 群组 ID + keep_days (int): 保留的天数上限 + + Returns: + int: 实际删除的记录条数 + """ + try: + history = self.load_group_history(group_id) + daily = history.get("daily", {}) + + # 计算截止日期边界 + from datetime import timedelta + + cutoff = (datetime.now() - timedelta(days=keep_days)).strftime("%Y-%m-%d") + + # 筛选已过期的日期 + dates_to_delete = [date for date in daily.keys() if date < cutoff] + + for date in dates_to_delete: + del daily[date] + + if dates_to_delete: + history["daily"] = daily + history_path = self._get_group_history_path(group_id) + with open(history_path, "w", encoding="utf-8") as f: + json.dump(history, f, ensure_ascii=False, indent=2) + + return len(dates_to_delete) + + except Exception as e: + logger.error(f"清理群 {group_id} 的陈旧历史记录失败: {e}") + return 0 + + def list_groups_with_history(self) -> list[str]: + """ + 扫描文件系统,列出当前所有具有存档记录的群组 ID。 + + Returns: + list[str]: 群组 ID 字符串列表 + """ + try: + groups = [] + for file_path in self.history_dir.glob("group_*.json"): + # 从文件名反推群组 ID (group_123.json -> 123) + group_id = file_path.stem.replace("group_", "") + groups.append(group_id) + return groups + except Exception as e: + logger.error(f"列出历史记录群组失败: {e}") + return [] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/incremental_store.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/incremental_store.py new file mode 100644 index 0000000..944d3d6 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/incremental_store.py @@ -0,0 +1,374 @@ +""" +增量分析批次持久化存储 — 滑动窗口架构 + +基于 AstrBot 的 put_kv_data/get_kv_data 实现按批次独立存储, +支持按时间窗口查询批次、批次索引管理和过期批次清理。 + +KV 键设计: +- 批次索引: incr_batch_index_{group_id} + 值: [{"batch_id": "xxx", "timestamp": 1234567890.0}, ...] +- 批次数据: incr_batch_{group_id}_{batch_id} + 值: IncrementalBatch.to_dict() +- 最后分析消息游标: incr_last_ts_{group_id} + 值: {"timestamp": 1234567890, "message_ids": ["..."]} +""" + +from typing import Any + +from ...domain.entities.incremental_state import IncrementalBatch +from ...utils.logger import logger + + +class IncrementalStore: + """ + 增量分析批次持久化仓储 + + 核心职责: + - save_batch: 保存单个批次数据并更新索引 + - query_batches: 按时间窗口查询批次列表 + - get_last_analyzed_cursor / update_last_analyzed_cursor: 跨批次去重 + - cleanup_old_batches: 清理过期批次 + - get_batch_count: 获取当前批次总数(状态查询用) + """ + + # KV 键前缀 + INDEX_PREFIX = "incr_batch_index" + BATCH_PREFIX = "incr_batch" + LAST_TS_PREFIX = "incr_last_ts" + + def __init__(self, star_instance: Any): + """ + 初始化批次持久化仓储。 + + Args: + star_instance: Star 插件实例,用于访问底层 KV 存储引擎 + """ + self.plugin = star_instance + + # ================================================================ + # 键构建 + # ================================================================ + + def _index_key(self, group_id: str) -> str: + """构建批次索引键""" + return f"{self.INDEX_PREFIX}_{group_id}" + + def _batch_key(self, group_id: str, batch_id: str) -> str: + """构建单个批次数据键""" + return f"{self.BATCH_PREFIX}_{group_id}_{batch_id}" + + def _last_ts_key(self, group_id: str) -> str: + """构建最后分析消息时间戳键""" + return f"{self.LAST_TS_PREFIX}_{group_id}" + + # ================================================================ + # 批次索引操作 + # ================================================================ + + async def _get_index(self, group_id: str) -> list[dict]: + """ + 获取指定群的批次索引列表。 + + Args: + group_id: 群组 ID + + Returns: + list[dict]: 索引条目列表,每项包含 batch_id 和 timestamp + """ + key = self._index_key(group_id) + try: + data = await self.plugin.get_kv_data(key, None) + if data is None: + return [] + if isinstance(data, list): + return data + logger.warning(f"批次索引数据格式异常 (Key: {key}): {type(data)}") + return [] + except Exception as e: + logger.error(f"读取批次索引失败 (Key: {key}): {e}", exc_info=True) + return [] + + async def _save_index(self, group_id: str, index: list[dict]) -> None: + """ + 保存批次索引列表。 + + Args: + group_id: 群组 ID + index: 索引条目列表 + """ + key = self._index_key(group_id) + try: + await self.plugin.put_kv_data(key, index) + except Exception as e: + logger.error(f"保存批次索引失败 (Key: {key}): {e}", exc_info=True) + raise + + # ================================================================ + # 批次数据操作 + # ================================================================ + + async def save_batch(self, batch: IncrementalBatch) -> bool: + """ + 保存单个批次数据并更新索引。 + + 流程: + 1. 将批次数据写入独立 KV 键 + 2. 将批次元数据(batch_id + timestamp)追加到索引 + + Args: + batch: 要保存的增量分析批次 + + Returns: + bool: 保存是否成功 + """ + group_id = batch.group_id + batch_key = self._batch_key(group_id, batch.batch_id) + + try: + # 1. 保存批次数据 + await self.plugin.put_kv_data(batch_key, batch.to_dict()) + + # 2. 更新索引 + index = await self._get_index(group_id) + existing_entry = next( + (entry for entry in index if entry.get("batch_id") == batch.batch_id), + None, + ) + if existing_entry is None: + index.append( + { + "batch_id": batch.batch_id, + "timestamp": batch.timestamp, + } + ) + else: + existing_entry["timestamp"] = batch.timestamp + await self._save_index(group_id, index) + + logger.debug( + f"已保存批次 {batch.batch_id[:8]}... " + f"(群 {group_id}, 消息数={batch.messages_count})" + ) + return True + except Exception as e: + logger.error( + f"保存批次失败 (群 {group_id}, 批次 {batch.batch_id[:8]}...): {e}", + exc_info=True, + ) + return False + + async def query_batches( + self, + group_id: str, + window_start: float, + window_end: float, + ) -> list[IncrementalBatch]: + """ + 按时间窗口查询批次列表。 + + 从索引中筛选时间戳落在 [window_start, window_end] 范围内的批次, + 逐个加载完整批次数据。 + + Args: + group_id: 群组 ID + window_start: 窗口起始时间戳(epoch) + window_end: 窗口结束时间戳(epoch) + + Returns: + list[IncrementalBatch]: 符合窗口范围的批次列表,按时间戳升序 + """ + index = await self._get_index(group_id) + + # 筛选在窗口范围内的批次 + matching_entries = [ + entry + for entry in index + if window_start <= entry.get("timestamp", 0) <= window_end + ] + + # 按时间戳升序排列 + matching_entries.sort(key=lambda x: x.get("timestamp", 0)) + + batches: list[IncrementalBatch] = [] + for entry in matching_entries: + batch_id = entry.get("batch_id", "") + if not batch_id: + continue + + batch_key = self._batch_key(group_id, batch_id) + try: + data = await self.plugin.get_kv_data(batch_key, None) + if data is not None: + batch = IncrementalBatch.from_dict(data) + batches.append(batch) + else: + logger.warning( + f"批次数据缺失 (群 {group_id}, 批次 {batch_id[:8]}...)" + ) + except Exception as e: + logger.error( + f"加载批次数据失败 (群 {group_id}, 批次 {batch_id[:8]}...): {e}", + exc_info=True, + ) + + logger.debug( + f"窗口查询完成: 群 {group_id}, " + f"窗口 [{window_start:.0f}, {window_end:.0f}], " + f"匹配 {len(batches)}/{len(index)} 个批次" + ) + + return batches + + # ================================================================ + # 最后分析消息游标(跨批次去重用) + # ================================================================ + + async def get_last_analyzed_cursor(self, group_id: str) -> tuple[int, set[str]]: + """获取指定群的最后分析消息游标。 + + 旧版本仅保存整数时间戳,此处会将其兼容为不含消息 ID 的游标。 + + Args: + group_id: 群组 ID。 + + Returns: + 最后分析时间戳,以及该时间戳下已经处理的消息 ID 集合。 + """ + key = self._last_ts_key(group_id) + try: + data = await self.plugin.get_kv_data(key, 0) + if isinstance(data, dict): + timestamp = max(0, int(data.get("timestamp", 0))) + message_ids = data.get("message_ids", []) + if not isinstance(message_ids, list): + message_ids = [] + return timestamp, {str(item) for item in message_ids if str(item)} + return (int(data) if data else 0), set() + except Exception as e: + logger.error(f"读取最后分析游标失败 (Key: {key}): {e}", exc_info=True) + return 0, set() + + async def update_last_analyzed_cursor( + self, + group_id: str, + timestamp: int, + message_ids: set[str], + ) -> None: + """更新指定群的最后分析消息游标。 + + Args: + group_id: 群组 ID。 + timestamp: 最后分析消息的 epoch 时间戳。 + message_ids: 该时间戳下已经处理的消息 ID。 + """ + key = self._last_ts_key(group_id) + try: + await self.plugin.put_kv_data( + key, + { + "timestamp": max(0, int(timestamp)), + "message_ids": sorted( + str(item) for item in message_ids if str(item) + ), + }, + ) + logger.debug(f"更新最后分析游标: 群 {group_id}, ts={timestamp}") + except Exception as e: + logger.error(f"更新最后分析游标失败 (Key: {key}): {e}", exc_info=True) + raise + + # ================================================================ + # 过期批次清理 + # ================================================================ + + async def cleanup_old_batches(self, group_id: str, before_timestamp: float) -> int: + """ + 清理指定群中早于给定时间戳的所有批次。 + + 流程: + 1. 从索引中分离出过期条目和保留条目 + 2. 逐个删除过期批次的 KV 数据 + 3. 用保留条目覆盖索引 + + Args: + group_id: 群组 ID + before_timestamp: 清理此时间戳之前的所有批次 + + Returns: + int: 已清理的批次数量 + """ + index = await self._get_index(group_id) + if not index: + return 0 + + # 分离过期和保留 + expired = [] + retained = [] + for entry in index: + if entry.get("timestamp", 0) < before_timestamp: + expired.append(entry) + else: + retained.append(entry) + + if not expired: + return 0 + + # 删除过期批次数据 + deleted_count = 0 + for entry in expired: + batch_id = entry.get("batch_id", "") + if not batch_id: + continue + batch_key = self._batch_key(group_id, batch_id) + try: + await self.plugin.put_kv_data(batch_key, None) + deleted_count += 1 + except Exception as e: + logger.error( + f"删除过期批次失败 (群 {group_id}, 批次 {batch_id[:8]}...): {e}", + exc_info=True, + ) + + # 更新索引(仅保留未过期条目) + await self._save_index(group_id, retained) + + logger.debug( + f"清理过期批次: 群 {group_id}, " + f"删除 {deleted_count} 个, 保留 {len(retained)} 个" + ) + + return deleted_count + + # ================================================================ + # 状态查询 + # ================================================================ + + async def get_batch_count(self, group_id: str) -> int: + """ + 获取指定群的当前批次总数。 + + Args: + group_id: 群组 ID + + Returns: + int: 批次总数 + """ + index = await self._get_index(group_id) + return len(index) + + async def get_all_batch_summaries(self, group_id: str) -> list[dict]: + """ + 获取指定群所有批次的摘要信息(不加载完整数据)。 + + 用于状态查询命令展示批次概览。 + + Args: + group_id: 群组 ID + + Returns: + list[dict]: 批次摘要列表,按时间升序 + """ + index = await self._get_index(group_id) + # 按时间戳升序排列 + index.sort(key=lambda x: x.get("timestamp", 0)) + return index diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/platform_group_registry.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/platform_group_registry.py new file mode 100644 index 0000000..4f16428 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/platform_group_registry.py @@ -0,0 +1,110 @@ +"""Persistent registry of groups observed by event-driven platforms.""" + +import asyncio +from datetime import datetime, timezone +from typing import Any + + +class PlatformGroupRegistry: + """Keep a small, platform-scoped list of groups seen in incoming events.""" + + _KV_KEY = "platform_seen_groups_v1" + _LEGACY_TELEGRAM_KEY = "telegram_seen_groups_v1" + + def __init__(self, plugin_instance: Any): + self.plugin = plugin_instance + self._lock = asyncio.Lock() + self._known_groups: set[tuple[str, str]] = set() + + async def upsert( + self, + platform_id: str, + group_id: str, + sender_id: str = "", + sender_name: str = "", + event_message_id: str = "", + ) -> None: + platform_key = str(platform_id or "").strip() + group_key = str(group_id or "").strip() + if not platform_key or not group_key: + return + + async with self._lock: + identity = (platform_key, group_key) + if identity in self._known_groups: + return + + registry = await self.plugin.get_kv_data(self._KV_KEY, {}) + if not isinstance(registry, dict): + registry = {} + platforms = registry.setdefault("platforms", {}) + if not isinstance(platforms, dict): + platforms = {} + registry["platforms"] = platforms + platform_map = platforms.setdefault(platform_key, {}) + if not isinstance(platform_map, dict): + platform_map = {} + platforms[platform_key] = platform_map + + # Existing groups only need to be remembered in memory. The + # registry is used for group discovery, so rewriting last_seen and + # the full KV document for every message creates unnecessary I/O. + if group_key in platform_map: + self._known_groups.add(identity) + return + + now_iso = datetime.now(timezone.utc).isoformat() + platform_map[group_key] = { + "first_seen": now_iso, + "last_seen": now_iso, + "last_sender_id": str(sender_id or ""), + "last_sender_name": str(sender_name or ""), + "last_event_message_id": str(event_message_id or ""), + } + registry["updated_at"] = now_iso + await self.plugin.put_kv_data(self._KV_KEY, registry) + self._known_groups.add(identity) + + async def get_all_group_ids(self, platform_id: str | None = None) -> list[str]: + async with self._lock: + registry = await self.plugin.get_kv_data(self._KV_KEY, {}) + groups = self._extract_groups(registry, platform_id) + platform_key = str(platform_id).strip() if platform_id else None + if platform_id: + self._known_groups.update( + (str(platform_key), group_id) for group_id in groups + ) + + # Preserve groups recorded by older plugin versions. + legacy = await self.plugin.get_kv_data(self._LEGACY_TELEGRAM_KEY, {}) + legacy_groups = self._extract_groups(legacy, platform_id) + groups.update(legacy_groups) + if platform_id: + self._known_groups.update( + (str(platform_key), group_id) for group_id in legacy_groups + ) + return sorted(groups) + + @staticmethod + def _extract_groups(registry: object, platform_id: str | None) -> set[str]: + if not isinstance(registry, dict): + return set() + platforms = registry.get("platforms") + if not isinstance(platforms, dict): + return set() + + maps: list[object] + if platform_id: + maps = [platforms.get(str(platform_id).strip(), {})] + else: + maps = list(platforms.values()) + + groups: set[str] = set() + for platform_map in maps: + if isinstance(platform_map, dict): + groups.update( + str(group_id).strip() + for group_id in platform_map + if str(group_id).strip() + ) + return groups diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/telegram_group_registry.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/telegram_group_registry.py new file mode 100644 index 0000000..c64ba96 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/telegram_group_registry.py @@ -0,0 +1,102 @@ +import asyncio +from datetime import datetime, timezone + +from astrbot.api.star import Star + + +class TelegramGroupRegistry: + """ + Telegram 群组/话题注册表 + + 负责管理 Telegram 的已见群组和话题列表,用于在无法通过 API 获取群列表时提供回退支持。 + 数据存储在 AstrBot 的 KV 存储中。 + """ + + _KV_KEY = "telegram_seen_groups_v1" + + def __init__(self, plugin_instance: Star): + self.plugin = plugin_instance + self._lock = asyncio.Lock() + + async def upsert( + self, + platform_id: str, + group_id: str, + sender_id: str, + sender_name: str, + event_message_id: str, + ) -> None: + """更新 Telegram 已见群/话题注册表(KV)。""" + async with self._lock: + registry = await self.plugin.get_kv_data(self._KV_KEY, {}) + if not isinstance(registry, dict): + registry = {} + + platforms = registry.get("platforms") + if not isinstance(platforms, dict): + platforms = {} + registry["platforms"] = platforms + + platform_key = str(platform_id).strip() + group_key = str(group_id).strip() + + platform_map = platforms.get(platform_key) + if not isinstance(platform_map, dict): + platform_map = {} + platforms[platform_key] = platform_map + + now_iso = datetime.now(timezone.utc).isoformat() + + entry = platform_map.get(group_key) + if not isinstance(entry, dict): + entry = {} + + first_seen = entry.get("first_seen") + if not isinstance(first_seen, str) or not first_seen: + first_seen = now_iso + + entry.update( + { + "first_seen": first_seen, + "last_seen": now_iso, + "last_sender_id": str(sender_id), + "last_sender_name": str(sender_name), + "last_event_message_id": str(event_message_id), + } + ) + platform_map[group_key] = entry + + registry["updated_at"] = now_iso + await self.plugin.put_kv_data(self._KV_KEY, registry) + + async def get_all_group_ids(self, platform_id: str | None = None) -> list[str]: + """读取 Telegram 已见群/话题列表。""" + async with self._lock: + registry = await self.plugin.get_kv_data(self._KV_KEY, {}) + if not isinstance(registry, dict): + return [] + + platforms = registry.get("platforms") + if not isinstance(platforms, dict): + return [] + + groups: set[str] = set() + if platform_id: + platform_map = platforms.get(str(platform_id).strip(), {}) + if isinstance(platform_map, dict): + groups.update( + str(gid).strip() + for gid in platform_map.keys() + if str(gid).strip() + ) + else: + for platform_map in platforms.values(): + if not isinstance(platform_map, dict): + continue + groups.update( + str(gid).strip() + for gid in platform_map.keys() + if str(gid).strip() + ) + + return sorted(groups) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/trace_sqlite_store.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/trace_sqlite_store.py new file mode 100644 index 0000000..8140379 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/persistence/trace_sqlite_store.py @@ -0,0 +1,902 @@ +""" +Trace 持久化仓储 - 基于 SQLite 的轻量级嵌入式存储 +负责存储链路快照、细粒度 Span 耗时、dsh-context 风格的上下文演进指标与 Token 消耗审计。 +""" + +from __future__ import annotations + +import json +import sqlite3 +import time +from pathlib import Path +from typing import Any + + +class TraceSQLiteStore: + """基于 SQLite 的 Trace 链路持久化仓储""" + + def __init__(self, db_path: Path): + self.db_path = Path(db_path) + self.db_path.parent.mkdir(parents=True, exist_ok=True) + self._init_db() + + def _get_connection(self) -> sqlite3.Connection: + """获取启用了 WAL 模式和外键支持的数据库连接""" + conn = sqlite3.connect(str(self.db_path), timeout=10.0) + conn.row_factory = sqlite3.Row + conn.execute("PRAGMA journal_mode=WAL;") + conn.execute("PRAGMA foreign_keys=ON;") + return conn + + def _init_db(self) -> None: + """初始化数据库表结构与索引""" + with self._get_connection() as conn: + conn.executescript( + """ + CREATE TABLE IF NOT EXISTS analysis_traces ( + trace_id TEXT PRIMARY KEY, + group_id TEXT NOT NULL, + group_name TEXT DEFAULT '', + platform TEXT DEFAULT '', + trigger_type TEXT DEFAULT 'manual', + status TEXT NOT NULL, + started_at REAL NOT NULL, + completed_at REAL, + duration_ms REAL, + error_stage TEXT, + error_message TEXT, + stack_trace TEXT, + extra_json TEXT DEFAULT '{}' + ); + + CREATE TABLE IF NOT EXISTS trace_spans ( + span_id TEXT PRIMARY KEY, + trace_id TEXT NOT NULL, + stage_name TEXT NOT NULL, + status TEXT NOT NULL, + started_at REAL NOT NULL, + duration_ms REAL, + stage_payload_json TEXT DEFAULT '{}', + FOREIGN KEY (trace_id) REFERENCES analysis_traces(trace_id) ON DELETE CASCADE + ); + + CREATE TABLE IF NOT EXISTS context_metrics ( + trace_id TEXT PRIMARY KEY, + raw_message_count INTEGER DEFAULT 0, + cleaned_message_count INTEGER DEFAULT 0, + compression_ratio REAL DEFAULT 0.0, + incremental_batches INTEGER DEFAULT 0, + window_size INTEGER DEFAULT 0, + FOREIGN KEY (trace_id) REFERENCES analysis_traces(trace_id) ON DELETE CASCADE + ); + + CREATE TABLE IF NOT EXISTS token_usage ( + trace_id TEXT PRIMARY KEY, + prompt_tokens INTEGER DEFAULT 0, + completion_tokens INTEGER DEFAULT 0, + total_tokens INTEGER DEFAULT 0, + estimated_cost REAL DEFAULT 0.0, + per_analyzer_tokens_json TEXT DEFAULT '{}', + FOREIGN KEY (trace_id) REFERENCES analysis_traces(trace_id) ON DELETE CASCADE + ); + + CREATE INDEX IF NOT EXISTS idx_traces_started_at ON analysis_traces(started_at DESC); + CREATE INDEX IF NOT EXISTS idx_traces_group_id ON analysis_traces(group_id); + CREATE INDEX IF NOT EXISTS idx_traces_status ON analysis_traces(status); + CREATE INDEX IF NOT EXISTS idx_spans_trace_id ON trace_spans(trace_id); + """ + ) + + def save_trace(self, trace_dict: dict[str, Any]) -> None: + """保存或全量更新 Trace 链路及其关联的 Spans、ContextMetrics、TokenUsage""" + trace_id = trace_dict.get("trace_id", "") + if not trace_id: + return + + with self._get_connection() as conn: + # 1. 写入主表前,合并既有的 extra_json(特别是 report_files 产物列表) + extra_payload = dict(trace_dict.get("extra", {})) + meta = trace_dict.get("metadata", {}) + if isinstance(meta, dict): + for k, v in meta.items(): + if k not in extra_payload: + extra_payload[k] = v + elif isinstance(v, dict) and isinstance(extra_payload.get(k), dict): + extra_payload[k].update(v) + elif isinstance(v, list) and isinstance(extra_payload.get(k), list): + extra_payload[k] = v + + existing_row = conn.execute( + "SELECT extra_json FROM analysis_traces WHERE trace_id = ?", (trace_id,) + ).fetchone() + if existing_row and existing_row[0]: + try: + old_extra = json.loads(existing_row[0]) + merged_rfiles = list(old_extra.get("report_files", [])) + seen_filenames = { + rf.get("filename") + for rf in merged_rfiles + if isinstance(rf, dict) and rf.get("filename") + } + for rf in extra_payload.get("report_files", []): + if isinstance(rf, dict): + fn = rf.get("filename") + if fn and fn not in seen_filenames: + seen_filenames.add(fn) + merged_rfiles.append(rf) + extra_payload["report_files"] = merged_rfiles + + # 保留历史已记录的 prompts 与 attempts + if ( + "llm_prompts" not in extra_payload + and "llm_prompts" in old_extra + ): + extra_payload["llm_prompts"] = old_extra["llm_prompts"] + if ( + "llm_attempts" not in extra_payload + and "llm_attempts" in old_extra + ): + extra_payload["llm_attempts"] = old_extra["llm_attempts"] + except Exception: + pass + + conn.execute( + """ + INSERT INTO analysis_traces ( + trace_id, group_id, group_name, platform, trigger_type, + status, started_at, completed_at, duration_ms, + error_stage, error_message, stack_trace, extra_json + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(trace_id) DO UPDATE SET + group_id=CASE WHEN excluded.group_id != '' THEN excluded.group_id ELSE analysis_traces.group_id END, + group_name=CASE WHEN excluded.group_name != '' AND excluded.group_name != '未知群' THEN excluded.group_name ELSE analysis_traces.group_name END, + platform=CASE WHEN excluded.platform != '' AND excluded.platform NOT IN ('auto', 'default', 'all') THEN excluded.platform ELSE analysis_traces.platform END, + status=excluded.status, + completed_at=excluded.completed_at, + duration_ms=excluded.duration_ms, + error_stage=excluded.error_stage, + error_message=excluded.error_message, + stack_trace=excluded.stack_trace, + extra_json=excluded.extra_json; + """, + ( + trace_id, + str(trace_dict.get("group_id", "")), + str(trace_dict.get("group_name", "")), + str(trace_dict.get("platform", "")), + str(trace_dict.get("trigger_type", "manual")), + str(trace_dict.get("status", "running")), + float(trace_dict.get("started_at", time.time())), + trace_dict.get("completed_at"), + trace_dict.get("duration_ms"), + trace_dict.get("error_stage"), + trace_dict.get("error_message"), + trace_dict.get("stack_trace"), + json.dumps(extra_payload, ensure_ascii=False), + ), + ) + + # 2. 写入 Spans (增量覆写) + spans = trace_dict.get("spans", []) + for span in spans: + conn.execute( + """ + INSERT INTO trace_spans ( + span_id, trace_id, stage_name, status, started_at, duration_ms, stage_payload_json + ) VALUES (?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(span_id) DO UPDATE SET + status=excluded.status, + duration_ms=excluded.duration_ms, + stage_payload_json=excluded.stage_payload_json; + """, + ( + span.get("span_id", f"{trace_id}_{span.get('stage_name')}"), + trace_id, + span.get("stage_name", ""), + span.get("status", "success"), + float(span.get("started_at", time.time())), + span.get("duration_ms"), + json.dumps(span.get("payload", {}), ensure_ascii=False), + ), + ) + + # 3. 写入 Context Metrics + context_metrics = trace_dict.get("context_metrics") + if context_metrics: + conn.execute( + """ + INSERT INTO context_metrics ( + trace_id, raw_message_count, cleaned_message_count, + compression_ratio, incremental_batches, window_size + ) VALUES (?, ?, ?, ?, ?, ?) + ON CONFLICT(trace_id) DO UPDATE SET + raw_message_count=excluded.raw_message_count, + cleaned_message_count=excluded.cleaned_message_count, + compression_ratio=excluded.compression_ratio, + incremental_batches=excluded.incremental_batches, + window_size=excluded.window_size; + """, + ( + trace_id, + int(context_metrics.get("raw_message_count", 0)), + int(context_metrics.get("cleaned_message_count", 0)), + float(context_metrics.get("compression_ratio", 0.0)), + int(context_metrics.get("incremental_batches", 0)), + int(context_metrics.get("window_size", 0)), + ), + ) + + # 4. 写入 Token Usage + token_usage = trace_dict.get("token_usage") + if token_usage: + conn.execute( + """ + INSERT INTO token_usage ( + trace_id, prompt_tokens, completion_tokens, total_tokens, + estimated_cost, per_analyzer_tokens_json + ) VALUES (?, ?, ?, ?, ?, ?) + ON CONFLICT(trace_id) DO UPDATE SET + prompt_tokens=excluded.prompt_tokens, + completion_tokens=excluded.completion_tokens, + total_tokens=excluded.total_tokens, + estimated_cost=excluded.estimated_cost, + per_analyzer_tokens_json=excluded.per_analyzer_tokens_json; + """, + ( + trace_id, + int(token_usage.get("prompt_tokens", 0)), + int(token_usage.get("completion_tokens", 0)), + int(token_usage.get("total_tokens", 0)), + float(token_usage.get("estimated_cost", 0.0)), + json.dumps( + token_usage.get("per_analyzer", {}), ensure_ascii=False + ), + ), + ) + + def get_trace(self, trace_id: str) -> dict[str, Any] | None: + """获取单个 Trace 的完整树状结构(包含 Spans、ContextMetrics、TokenUsage)""" + with self._get_connection() as conn: + trace_row = conn.execute( + "SELECT * FROM analysis_traces WHERE trace_id = ?", (trace_id,) + ).fetchone() + if not trace_row: + return None + + trace_data = dict(trace_row) + try: + trace_data["extra"] = json.loads(trace_data.pop("extra_json") or "{}") + except Exception: + trace_data["extra"] = {} + + # 查询 Spans + spans_rows = conn.execute( + "SELECT * FROM trace_spans WHERE trace_id = ? ORDER BY started_at ASC", + (trace_id,), + ).fetchall() + spans = [] + extra_prompts = trace_data.get("extra", {}).get("llm_prompts", {}) + extra_attempts = trace_data.get("extra", {}).get("llm_attempts", []) + for r in spans_rows: + s = dict(r) + try: + s["payload"] = json.loads(s.pop("stage_payload_json") or "{}") + except Exception: + s["payload"] = {} + if s.get("stage_name") == "LLM_ANALYSIS": + if extra_prompts and not s["payload"].get("prompts"): + s["payload"]["prompts"] = extra_prompts + if extra_attempts and not s["payload"].get("llm_attempts"): + s["payload"]["llm_attempts"] = extra_attempts + spans.append(s) + trace_data["spans"] = spans + + # 查询 Context Metrics + cm_row = conn.execute( + "SELECT * FROM context_metrics WHERE trace_id = ?", (trace_id,) + ).fetchone() + trace_data["context_metrics"] = dict(cm_row) if cm_row else None + + # 查询 Token Usage + token_row = conn.execute( + "SELECT * FROM token_usage WHERE trace_id = ?", (trace_id,) + ).fetchone() + if token_row: + t_data = dict(token_row) + try: + t_data["per_analyzer"] = json.loads( + t_data.pop("per_analyzer_tokens_json") or "{}" + ) + except Exception: + t_data["per_analyzer"] = {} + trace_data["token_usage"] = t_data + else: + trace_data["token_usage"] = None + + raw_rfiles = trace_data.get("extra", {}).get("report_files", []) + seen_rfiles = set() + deduped_rfiles = [] + for rf in raw_rfiles: + fn = rf.get("filename") if isinstance(rf, dict) else None + if fn and fn not in seen_rfiles: + seen_rfiles.add(fn) + deduped_rfiles.append(rf) + + # 额外扫描磁盘 reports 目录,聚合文件名中明确带有 trace_id 的产物文件(如换模板重绘/续跑生成的文件) + try: + reports_dir = self.db_path.parent / "reports" + if reports_dir.is_dir(): + for p in reports_dir.iterdir(): + if ( + p.is_file() + and trace_id in p.name + and p.name not in seen_rfiles + ): + seen_rfiles.add(p.name) + is_html = p.suffix.lower() in (".html", ".htm") + is_comic = p.name.lower().startswith( + "comic_" + ) or p.name.startswith("漫画_") + stat = p.stat() + deduped_rfiles.append( + { + "filename": p.name, + "path": str(p.resolve()), + "format": "html" if is_html else "image", + "report_type": "comic" if is_comic else "daily", + "size_bytes": stat.st_size, + "created_at": stat.st_mtime, + } + ) + except Exception: + pass + + # 按生成时间降序排序,最新生成的报告排在前面 + deduped_rfiles.sort( + key=lambda x: x.get("created_at", 0) if isinstance(x, dict) else 0, + reverse=True, + ) + trace_data["report_files"] = deduped_rfiles + return trace_data + + def get_report_trace_map(self) -> dict[str, str]: + """获取已生成的报告文件名与 trace_id 的双向映射""" + mapping: dict[str, str] = {} + with self._get_connection() as conn: + rows = conn.execute( + "SELECT trace_id, extra_json FROM analysis_traces WHERE extra_json LIKE '%report_files%'" + ).fetchall() + for r in rows: + t_id = str(r["trace_id"]) + try: + extra = json.loads(r["extra_json"] or "{}") + for rf in extra.get("report_files", []): + fn = rf.get("filename") + if fn: + mapping[fn] = t_id + except Exception: + pass + return mapping + + def reconcile_crashed_traces_on_startup(self) -> int: + """开机对账扫描:将上次因系统异常终止/重启而未正常收尾的 running 任务标记为 aborted。""" + with self._get_connection() as conn: + cursor = conn.execute( + """ + UPDATE analysis_traces + SET status = 'aborted', + error_stage = 'CRASH_RECOVERY', + error_message = 'AstrBot/容器在任务执行期间异常终止,开机已自动回收', + completed_at = strftime('%s', 'now') + WHERE status = 'running' + """ + ) + reconciled_count = cursor.rowcount + return reconciled_count + + def get_distinct_groups(self) -> list[dict[str, str]]: + """获取所有有历史分析记录的唯一群组列表(按 group_id 分组,取每个群最新一次运行的群名与平台标识)""" + with self._get_connection() as conn: + rows = conn.execute( + """ + WITH ranked_traces AS ( + SELECT group_id, + group_name, + platform, + started_at, + ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY started_at DESC) AS rn + FROM analysis_traces + WHERE group_id != '' + ) + SELECT r.group_id, + COALESCE( + NULLIF(r.group_name, ''), + NULLIF(r.group_name, '未知群'), + (SELECT group_name FROM analysis_traces WHERE group_id = r.group_id AND group_name != '' AND group_name != '未知群' ORDER BY started_at DESC LIMIT 1), + r.group_id + ) AS group_name, + r.platform, + r.started_at AS last_seen + FROM ranked_traces r + WHERE r.rn = 1 + ORDER BY r.started_at DESC; + """ + ).fetchall() + return [ + { + "group_id": str(r["group_id"]), + "group_name": str(r["group_name"]), + "platform": str(r["platform"] or ""), + } + for r in rows + ] + + def list_traces( + self, + limit: int = 20, + offset: int = 0, + group_id: str | None = None, + status: str | None = None, + search: str | None = None, + start_time: float | None = None, + end_time: float | None = None, + sort_by: str = "started_at", + sort_order: str = "desc", + ) -> tuple[list[dict[str, Any]], int]: + """分页筛选查询 Trace 列表(支持按群组、状态、关键词、时间范围筛选与排序)""" + conditions = [] + params: list[Any] = [] + + if group_id: + conditions.append("t.group_id = ?") + params.append(str(group_id)) + if status: + conditions.append("t.status = ?") + params.append(status) + if start_time is not None: + conditions.append("t.started_at >= ?") + params.append(float(start_time)) + if end_time is not None: + conditions.append("t.started_at <= ?") + params.append(float(end_time)) + if search: + conditions.append( + "(t.trace_id LIKE ? OR t.group_id LIKE ? OR t.group_name LIKE ?)" + ) + like_pattern = f"%{search}%" + params.extend([like_pattern, like_pattern, like_pattern]) + + where_clause = f"WHERE {' AND '.join(conditions)}" if conditions else "" + + # 排序字段白名单校验 + allowed_sort_fields = { + "started_at": "t.started_at", + "duration_ms": "t.duration_ms", + "total_tokens": "tu.total_tokens", + "compression_ratio": "cm.compression_ratio", + } + order_field = allowed_sort_fields.get(sort_by, "t.started_at") + order_direction = "ASC" if sort_order.lower() == "asc" else "DESC" + + with self._get_connection() as conn: + # 查询总数 + count_sql = f"SELECT COUNT(*) FROM analysis_traces t {where_clause}" + total_count = conn.execute(count_sql, params).fetchone()[0] + + # 查询列表与关联 Token 汇总 + query_sql = f""" + SELECT + t.*, + tu.total_tokens, + tu.estimated_cost, + cm.raw_message_count, + cm.cleaned_message_count, + cm.compression_ratio + FROM analysis_traces t + LEFT JOIN token_usage tu ON t.trace_id = tu.trace_id + LEFT JOIN context_metrics cm ON t.trace_id = cm.trace_id + {where_clause} + ORDER BY {order_field} {order_direction} + LIMIT ? OFFSET ? + """ + rows = conn.execute(query_sql, params + [limit, offset]).fetchall() + + traces = [] + for r in rows: + item = dict(r) + try: + item["extra"] = json.loads(item.pop("extra_json") or "{}") + except Exception: + item["extra"] = {} + traces.append(item) + + return traces, total_count + + def get_metrics_summary(self) -> dict[str, Any]: + """获取控制台顶部 KPI 指标与聚合数据""" + now = time.time() + local_tm = time.localtime(now) + # 本地时间今日零点时间戳 + start_of_today = time.mktime( + (local_tm.tm_year, local_tm.tm_mon, local_tm.tm_mday, 0, 0, 0, 0, 0, -1) + ) + + with self._get_connection() as conn: + # 1. 总体概况 + overview = conn.execute( + """ + SELECT + COUNT(*) as total_traces, + SUM(CASE WHEN status IN ('succeeded', 'warning') THEN 1 ELSE 0 END) as succeeded_count, + SUM(CASE WHEN status = 'warning' THEN 1 ELSE 0 END) as warning_count, + SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) as failed_count, + AVG(CASE WHEN status IN ('succeeded', 'warning') THEN duration_ms ELSE NULL END) as avg_duration_ms + FROM analysis_traces; + """ + ).fetchone() + + # 2. 今日数据 + today_data = conn.execute( + """ + SELECT + COUNT(*) as today_traces, + COUNT(DISTINCT group_id) as today_active_groups + FROM analysis_traces + WHERE started_at >= ?; + """, + (start_of_today,), + ).fetchone() + + # 3. Token 累计总数与成本 + token_stats = conn.execute( + """ + SELECT + SUM(total_tokens) as total_tokens_spent, + SUM(estimated_cost) as total_cost_spent + FROM token_usage; + """ + ).fetchone() + + # 4. 今日 Token 消耗 + today_tokens = conn.execute( + """ + SELECT + SUM(tu.total_tokens) as today_tokens_spent, + SUM(tu.estimated_cost) as today_cost_spent + FROM token_usage tu + JOIN analysis_traces t ON tu.trace_id = t.trace_id + WHERE t.started_at >= ?; + """, + (start_of_today,), + ).fetchone() + + return { + "total_traces": overview["total_traces"] or 0, + "succeeded_count": overview["succeeded_count"] or 0, + "failed_count": overview["failed_count"] or 0, + "success_rate": ( + round( + (overview["succeeded_count"] or 0) + / max(1, overview["total_traces"] or 1) + * 100, + 1, + ) + ), + "avg_duration_ms": round(overview["avg_duration_ms"] or 0.0, 1), + "today_traces": today_data["today_traces"] or 0, + "today_active_groups": today_data["today_active_groups"] or 0, + "total_tokens_spent": token_stats["total_tokens_spent"] or 0, + "total_cost_spent": round(token_stats["total_cost_spent"] or 0.0, 4), + "today_tokens_spent": today_tokens["today_tokens_spent"] or 0, + "today_cost_spent": round(today_tokens["today_cost_spent"] or 0.0, 4), + "trends": self.get_analytics_trends(granularity="day", range_count=14), + } + + def get_analytics_trends( + self, granularity: str = "day", range_count: int = 14 + ) -> dict[str, Any]: + """获取时序趋势数据(支持小时 / 天维度切换,并提取服务商与模型消耗细粒度拆分)""" + now = time.time() + local_tm = time.localtime(now) + + points: list[dict[str, Any]] = [] + provider_map: dict[str, dict[str, Any]] = {} + model_map: dict[str, dict[str, Any]] = {} + + if granularity == "hour": + # 按小时划分(默认近 48 小时 / 2 天视野) + hours = max(1, min(range_count, 168)) # 上限7天 + # 当前小时的整点时间戳 + cur_hour_start = time.mktime( + ( + local_tm.tm_year, + local_tm.tm_mon, + local_tm.tm_mday, + local_tm.tm_hour, + 0, + 0, + 0, + 0, + -1, + ) + ) + start_timestamp = cur_hour_start - ((hours - 1) * 3600) + + trend_map: dict[str, dict[str, Any]] = {} + for i in range(hours): + h_ts = start_timestamp + (i * 3600) + h_tm = time.localtime(h_ts) + h_key = f"{h_tm.tm_year:04d}-{h_tm.tm_mon:02d}-{h_tm.tm_mday:02d} {h_tm.tm_hour:02d}:00" + display_date = f"{h_tm.tm_mon}/{h_tm.tm_mday} {h_tm.tm_hour:02d}:00" + trend_map[h_key] = { + "date": display_date, + "date_full": h_key, + "timestamp": h_ts, + "request_count": 0, + "succeeded_count": 0, + "failed_count": 0, + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0, + "estimated_cost": 0.0, + } + + with self._get_connection() as conn: + rows = conn.execute( + """ + SELECT + strftime('%Y-%m-%d %H:00', datetime(t.started_at, 'unixepoch', 'localtime')) as hour_str, + COUNT(t.trace_id) as request_count, + SUM(CASE WHEN t.status IN ('succeeded', 'warning') THEN 1 ELSE 0 END) as succeeded_count, + SUM(CASE WHEN t.status = 'failed' THEN 1 ELSE 0 END) as failed_count, + COALESCE(SUM(tu.prompt_tokens), 0) as prompt_tokens, + COALESCE(SUM(tu.completion_tokens), 0) as completion_tokens, + COALESCE(SUM(tu.total_tokens), 0) as total_tokens, + COALESCE(SUM(tu.estimated_cost), 0.0) as estimated_cost + FROM analysis_traces t + LEFT JOIN token_usage tu ON t.trace_id = tu.trace_id + WHERE t.started_at >= ? + GROUP BY hour_str; + """, + (start_timestamp,), + ).fetchall() + + for r in rows: + h_str = r["hour_str"] + if h_str in trend_map: + trend_map[h_str]["request_count"] = r["request_count"] or 0 + trend_map[h_str]["succeeded_count"] = r["succeeded_count"] or 0 + trend_map[h_str]["failed_count"] = r["failed_count"] or 0 + trend_map[h_str]["prompt_tokens"] = r["prompt_tokens"] or 0 + trend_map[h_str]["completion_tokens"] = ( + r["completion_tokens"] or 0 + ) + trend_map[h_str]["total_tokens"] = r["total_tokens"] or 0 + trend_map[h_str]["estimated_cost"] = round( + r["estimated_cost"] or 0.0, 4 + ) + + points = list(trend_map.values()) + else: + # 按天划分(支持 7 天、14 天、30 天等视野) + days = max(1, min(range_count, 90)) + today_start = time.mktime( + ( + local_tm.tm_year, + local_tm.tm_mon, + local_tm.tm_mday, + 0, + 0, + 0, + 0, + 0, + -1, + ) + ) + start_timestamp = today_start - ((days - 1) * 86400) + + trend_map = {} + for i in range(days): + day_ts = start_timestamp + (i * 86400) + d_tm = time.localtime(day_ts) + day_key = f"{d_tm.tm_year:04d}-{d_tm.tm_mon:02d}-{d_tm.tm_mday:02d}" + display_date = f"{d_tm.tm_mon}/{d_tm.tm_mday}" + trend_map[day_key] = { + "date": display_date, + "date_full": day_key, + "timestamp": day_ts, + "request_count": 0, + "succeeded_count": 0, + "failed_count": 0, + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0, + "estimated_cost": 0.0, + } + + with self._get_connection() as conn: + rows = conn.execute( + """ + SELECT + date(t.started_at, 'unixepoch', 'localtime') as day_str, + COUNT(t.trace_id) as request_count, + SUM(CASE WHEN t.status IN ('succeeded', 'warning') THEN 1 ELSE 0 END) as succeeded_count, + SUM(CASE WHEN t.status = 'failed' THEN 1 ELSE 0 END) as failed_count, + COALESCE(SUM(tu.prompt_tokens), 0) as prompt_tokens, + COALESCE(SUM(tu.completion_tokens), 0) as completion_tokens, + COALESCE(SUM(tu.total_tokens), 0) as total_tokens, + COALESCE(SUM(tu.estimated_cost), 0.0) as estimated_cost + FROM analysis_traces t + LEFT JOIN token_usage tu ON t.trace_id = tu.trace_id + WHERE t.started_at >= ? + GROUP BY day_str; + """, + (start_timestamp,), + ).fetchall() + + for r in rows: + day_str = r["day_str"] + if day_str in trend_map: + trend_map[day_str]["request_count"] = r["request_count"] or 0 + trend_map[day_str]["succeeded_count"] = ( + r["succeeded_count"] or 0 + ) + trend_map[day_str]["failed_count"] = r["failed_count"] or 0 + trend_map[day_str]["prompt_tokens"] = r["prompt_tokens"] or 0 + trend_map[day_str]["completion_tokens"] = ( + r["completion_tokens"] or 0 + ) + trend_map[day_str]["total_tokens"] = r["total_tokens"] or 0 + trend_map[day_str]["estimated_cost"] = round( + r["estimated_cost"] or 0.0, 4 + ) + + points = list(trend_map.values()) + + # 提取该时间范围内的服务商 (Provider) 与模型 (Model) 维度消耗分布 + with self._get_connection() as conn: + traces_with_usage = conn.execute( + """ + SELECT + t.extra_json, + COALESCE(tu.total_tokens, 0) as total_tokens, + COALESCE(tu.prompt_tokens, 0) as prompt_tokens, + COALESCE(tu.completion_tokens, 0) as completion_tokens, + COALESCE(tu.per_analyzer_tokens_json, '{}') as per_analyzer + FROM analysis_traces t + LEFT JOIN token_usage tu ON t.trace_id = tu.trace_id + WHERE t.started_at >= ?; + """, + (start_timestamp,), + ).fetchall() + + invalid_provider_names = { + "default", + "default_provider", + "quality_provider_id", + "none", + "", + } + invalid_model_names = {"default", "default_model", "none", ""} + + for tw in traces_with_usage: + try: + extra = json.loads(tw["extra_json"] or "{}") + except Exception: + extra = {} + + llm_prompts = ( + extra.get("llm_prompts", {}) if isinstance(extra, dict) else {} + ) + + # 收集有效 provider_id + providers_in_trace: set[str] = set() + models_in_trace: set[str] = set() + + if isinstance(llm_prompts, dict): + for _, p_info in llm_prompts.items(): + if isinstance(p_info, dict): + p_id = str(p_info.get("provider_id", "")).strip() + if p_id and p_id.lower() not in invalid_provider_names: + providers_in_trace.add(p_id) + m_id = str(p_info.get("model", "")).strip() + if m_id and m_id.lower() not in invalid_model_names: + models_in_trace.add(m_id) + + if not providers_in_trace: + fallback_p = str(extra.get("provider_id", "")).strip() + if fallback_p and fallback_p.lower() not in invalid_provider_names: + providers_in_trace.add(fallback_p) + else: + providers_in_trace.add("默认会话服务商") + + if not models_in_trace: + fallback_m = str( + extra.get("model") or extra.get("model_id") or "" + ).strip() + if fallback_m and fallback_m.lower() not in invalid_model_names: + models_in_trace.add(fallback_m) + else: + models_in_trace.add("默认会话模型") + + tot_tok = int(tw["total_tokens"] or 0) + tokens_per_p = tot_tok // max(1, len(providers_in_trace)) + for pid in providers_in_trace: + if pid not in provider_map: + provider_map[pid] = { + "name": pid, + "total_tokens": 0, + "request_count": 0, + } + provider_map[pid]["total_tokens"] += tokens_per_p + provider_map[pid]["request_count"] += 1 + + tokens_per_m = tot_tok // max(1, len(models_in_trace)) + for mid in models_in_trace: + if mid not in model_map: + model_map[mid] = { + "name": mid, + "total_tokens": 0, + "request_count": 0, + } + model_map[mid]["total_tokens"] += tokens_per_m + model_map[mid]["request_count"] += 1 + + provider_breakdown = [ + p + for p in sorted( + provider_map.values(), + key=lambda x: x["total_tokens"], + reverse=True, + ) + if p["total_tokens"] > 0 or p["request_count"] > 0 + ] + model_breakdown = [ + m + for m in sorted( + model_map.values(), + key=lambda x: x["total_tokens"], + reverse=True, + ) + if m["total_tokens"] > 0 or m["request_count"] > 0 + ] + + return { + "granularity": granularity, + "range_count": range_count, + "points": points, + "provider_breakdown": provider_breakdown, + "model_breakdown": model_breakdown, + } + + def cleanup_old_traces(self, days: int = 30, max_count: int = 20000) -> int: + """根据保留天数(默认30天)或最大条数上限清理旧的 Trace 数据,防止 SQLite 无限增长""" + cutoff_time = time.time() - (days * 86400) + deleted_count = 0 + + with self._get_connection() as conn: + # 1. 按过期时间清理 + cursor = conn.execute( + "DELETE FROM analysis_traces WHERE started_at < ?", (cutoff_time,) + ) + deleted_count += cursor.rowcount + + # 2. 按最大数量上限清理多余数据 + total_count = conn.execute( + "SELECT COUNT(*) FROM analysis_traces" + ).fetchone()[0] + if total_count > max_count: + excess = total_count - max_count + conn.execute( + """ + DELETE FROM analysis_traces + WHERE trace_id IN ( + SELECT trace_id FROM analysis_traces + ORDER BY started_at ASC LIMIT ? + ); + """, + (excess,), + ) + deleted_count += excess + + return deleted_count diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/__init__.py new file mode 100644 index 0000000..b5b2e57 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/__init__.py @@ -0,0 +1,17 @@ +from .adapters.discord_adapter import DiscordAdapter +from .adapters.lark_adapter import LarkAdapter +from .adapters.onebot_adapter import OneBotAdapter +from .adapters.qq_official_adapter import QQOfficialAdapter +from .adapters.telegram_adapter import TelegramAdapter +from .base import PlatformAdapter +from .factory import PlatformAdapterFactory + +__all__ = [ + "PlatformAdapterFactory", + "PlatformAdapter", + "OneBotAdapter", + "LarkAdapter", + "QQOfficialAdapter", + "TelegramAdapter", + "DiscordAdapter", +] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/__init__.py new file mode 100644 index 0000000..ea34643 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/__init__.py @@ -0,0 +1,35 @@ +"""Optional platform adapter exports. + +Each platform is imported independently so an unavailable optional SDK does not +prevent the QQ Official adapter from being registered. +""" + +__all__: list[str] = [] + +try: + from .discord_adapter import DiscordAdapter # noqa: F401 + + __all__.append("DiscordAdapter") +except ImportError: + pass + +try: + from .lark_adapter import LarkAdapter # noqa: F401 + + __all__.append("LarkAdapter") +except ImportError: + pass + +try: + from .onebot_adapter import OneBotAdapter # noqa: F401 + + __all__.append("OneBotAdapter") +except ImportError: + pass + +try: + from .qq_official_adapter import QQOfficialAdapter # noqa: F401 + + __all__.append("QQOfficialAdapter") +except ImportError: + pass diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/discord_adapter.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/discord_adapter.py new file mode 100644 index 0000000..1a43ffd --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/discord_adapter.py @@ -0,0 +1,806 @@ +""" +Discord 平台适配器 + +为 Discord 平台提供消息获取、发送和群组管理功能。 +这是一个骨架实现,展示如何为新平台创建适配器。 + +注意:Discord 的消息获取需要使用 Discord API, +具体实现取决于 AstrBot 的 Discord 集成方式。 +""" + +from datetime import datetime, timedelta +from typing import Any + +from ....utils.logger import logger + +try: + import discord +except ImportError: + discord = None + +from ....domain.value_objects.platform_capabilities import ( + DISCORD_CAPABILITIES, + PlatformCapabilities, +) +from ....domain.value_objects.unified_group import UnifiedGroup, UnifiedMember +from ....domain.value_objects.unified_message import ( + MessageContent, + MessageContentType, + UnifiedMessage, +) +from ..base import PlatformAdapter + + +class DiscordAdapter(PlatformAdapter): + """ + 具体实现:Discord 平台适配器 + + 利用 Discord API 为群组(频道)提供消息获取、发送及基础元数据查询功能。 + 由于 Discord 的高度异步特性和复杂的权限模型,该适配器集成了懒加载客户端和多级频道查询机制。 + + Attributes: + bot_user_id (str): 机器人自身的 Discord 用户 ID + """ + + def __init__(self, bot_instance: Any, config: dict | None = None): + """ + 初始化 Discord 适配器。 + + Args: + bot_instance (Any): 宿主机器人实例 + config (dict, optional): 配置项,用于提取机器人自身的 Discord ID + """ + super().__init__(bot_instance, config) + # 机器人自己的用户 ID,用于消息过滤(避免分析博取回复) + self.bot_user_id = str(config.get("bot_user_id", "")) if config else "" + + # 缓存 Discord 客户端(Lazy Loading) + self._cached_client = None + + @property + def _discord_client(self) -> Any: + """ + 内部属性:获取实际的 Discord 客户端实例。 + + 具备懒加载和自动身份嗅探功能。 + + Returns: + Any: Discord Client 对象 + """ + if self._cached_client: + return self._cached_client + + # 执行路径探测逻辑,兼容不同版本的 AstrBot 宿主结构 + self._cached_client = self._get_discord_client() + + # 兜底:尝试从客户端连接状态中补全机器人 ID + if not self.bot_user_id and self._cached_client: + if hasattr(self._cached_client, "user") and self._cached_client.user: + self.bot_user_id = str(self._cached_client.user.id) + + return self._cached_client + + def _get_discord_client(self) -> Any: + """内部方法:通过多级探测从 bot_instance 中提取 Discord SDK 客户端。""" + # 路径 A:bot 本身就是 Client (如小型集成) + if hasattr(self.bot, "get_channel"): + return self.bot + # 路径 B:bot 是包装器,client 在标准成员变量中 + if hasattr(self.bot, "client"): + return self.bot.client + # 路径 C:其他常见私有属性名 + for attr in ("_client", "discord_client", "_discord_client"): + if hasattr(self.bot, attr): + client = getattr(self.bot, attr) + if hasattr(client, "get_channel"): + return client + logger.warning(f"无法从 {type(self.bot).__name__} 中提取 Discord 客户端实例") + return None + + def _init_capabilities(self) -> PlatformCapabilities: + """返回预定义的 Discord 平台能力集。""" + return DISCORD_CAPABILITIES + + # ==================== IMessageRepository 实现 ==================== + + async def fetch_messages( + self, + group_id: str, + days: int = 1, + max_count: int = 100, + before_id: str | None = None, + since_ts: int | None = None, + ) -> list[UnifiedMessage]: + """ + 从 Discord 频道异步拉取历史消息记录。 + + Args: + group_id (str): Discord 频道 (Channel) ID + days (int): 查询天数范围 + max_count (int): 最大拉取消息数量上限 + before_id (str, optional): 锚点消息 ID,从此之前开始拉取 + + Returns: + list[UnifiedMessage]: 统一格式的消息对象列表 + """ + if not discord: + logger.error("未找到 Discord 模块 (py-cord),无法拉取历史消息。") + return [] + + try: + channel_id = int(group_id) + # 先从缓存尝试获取频道 + channel = self._discord_client.get_channel(channel_id) + if not channel: + # 缓存未命中则通过网络 fetch + try: + channel = await self._discord_client.fetch_channel(channel_id) + except Exception as e: + logger.debug(f"拉取 Discord 频道 {group_id} 失败: {e}") + return [] + + # 验证权限:确保支持历史消息流 + if not hasattr(channel, "history"): + logger.warning(f"频道 {group_id} 不支持历史消息访问。") + return [] + + if since_ts and since_ts > 0: + start_time = datetime.fromtimestamp(since_ts) + else: + end_time = datetime.now() + start_time = end_time - timedelta(days=days) + + logger.debug( + "Discord 消息拉取开始: group=%s, max_count=%s, since_ts=%s, before_id=%s", + group_id, + max_count, + since_ts, + before_id, + ) + messages = [] + + # 构建 Discord SDK 的 history 查询参数 + history_kwargs = {"limit": max_count, "after": start_time} + if before_id: + try: + # 使用 Snowflake ID 指向特定消息 + history_kwargs["before"] = discord.Object(id=int(before_id)) + except (ValueError, TypeError): + pass + + # 消息迭代处理 + async for msg in channel.history(**history_kwargs): + # 排除机器人自身发布的消息 + if self.bot_user_id and str(msg.author.id) == self.bot_user_id: + continue + + unified = self._convert_message(msg, group_id) + if unified: + messages.append(unified) + + # 排序回升序(SDK 通常返回降序) + messages.sort(key=lambda m: m.timestamp) + logger.debug( + "Discord 消息拉取完成: group=%s, messages=%s", + group_id, + len(messages), + ) + return messages + + except Exception as e: + logger.error(f"Discord fetch_messages failed: {e}", exc_info=True) + return [] + + def _convert_message(self, raw_msg: Any, group_id: str) -> UnifiedMessage | None: + """内部方法:将 `discord.Message` 对象转换为统一的 `UnifiedMessage`。""" + try: + contents = [] + + # 1. 基础文本 + if raw_msg.content: + contents.append( + MessageContent(type=MessageContentType.TEXT, text=raw_msg.content) + ) + + # 2. 附件处理 (图片/视频/语音/普通文件) + for attachment in raw_msg.attachments: + content_type = attachment.content_type or "" + if content_type.startswith("image/"): + contents.append( + MessageContent( + type=MessageContentType.IMAGE, url=attachment.url + ) + ) + elif content_type.startswith("video/"): + contents.append( + MessageContent( + type=MessageContentType.VIDEO, url=attachment.url + ) + ) + elif content_type.startswith("audio/"): + contents.append( + MessageContent( + type=MessageContentType.VOICE, url=attachment.url + ) + ) + else: + contents.append( + MessageContent( + type=MessageContentType.FILE, + url=attachment.url, + raw_data={ + "filename": attachment.filename, + "size": attachment.size, + }, + ) + ) + + # 3. 嵌入内容处理 (部分 Embed 可能包含富文本描述) + for embed in raw_msg.embeds: + if embed.image: + contents.append( + MessageContent( + type=MessageContentType.IMAGE, url=embed.image.url + ) + ) + if embed.description: + contents.append( + MessageContent( + type=MessageContentType.TEXT, + text=f"\n[Embed] {embed.description}", + ) + ) + + # 4. 贴纸处理 (Stickers) + if raw_msg.stickers: + for sticker in raw_msg.stickers: + contents.append( + MessageContent( + type=MessageContentType.IMAGE, # 贴纸在逻辑上按图片处理 + url=sticker.url, + raw_data={ + "sticker_id": str(sticker.id), + "sticker_name": sticker.name, + }, + ) + ) + + # 确定发送者的显示名称(服务器昵称 > 全局名称 > 用户名) + sender_card = None + if hasattr(raw_msg.author, "nick") and raw_msg.author.nick: + sender_card = raw_msg.author.nick + elif hasattr(raw_msg.author, "global_name") and raw_msg.author.global_name: + sender_card = raw_msg.author.global_name + + return UnifiedMessage( + message_id=str(raw_msg.id), + sender_id=str(raw_msg.author.id), + sender_name=raw_msg.author.name, + sender_card=sender_card, + group_id=group_id, + text_content=raw_msg.content, + contents=tuple(contents), + timestamp=int(raw_msg.created_at.timestamp()), + platform="discord", + reply_to_id=str(raw_msg.reference.message_id) + if raw_msg.reference + else None, + ) + except Exception as e: + logger.debug(f"Discord 消息转换错误: {e}") + return None + + def convert_to_raw_format(self, messages: list[UnifiedMessage]) -> list[dict]: + """将统一格式降级转换为 OneBot 风格的字典,以适配下游组件。""" + raw_messages = [] + for msg in messages: + raw_msg = { + "message_id": msg.message_id, + "group_id": msg.group_id, + "time": msg.timestamp, + "sender": { + "user_id": msg.sender_id, + "nickname": msg.sender_name, + "card": msg.sender_card, + }, + "message": [], + "user_id": msg.sender_id, # 后向兼容 + } + + for content in msg.contents: + if content.type == MessageContentType.TEXT: + raw_msg["message"].append( + {"type": "text", "data": {"text": content.text or ""}} + ) + elif content.type == MessageContentType.IMAGE: + raw_msg["message"].append( + { + "type": "image", + "data": {"url": content.url, "file": content.url}, + } + ) + elif content.type == MessageContentType.AT: + raw_msg["message"].append( + {"type": "at", "data": {"qq": content.at_user_id}} + ) + elif content.type == MessageContentType.REPLY: + if content.raw_data and "reply_id" in content.raw_data: + raw_msg["message"].append( + { + "type": "reply", + "data": {"id": content.raw_data["reply_id"]}, + } + ) + + raw_messages.append(raw_msg) + return raw_messages + + # ==================== IMessageSender 实现 ==================== + + async def send_text( + self, + group_id: str, + text: str, + reply_to: str | None = None, + ) -> bool: + """ + 向 Discord 频道发送文本消息。 + + Args: + group_id (str): 频道 ID + text (str): 文本内容 + reply_to (str, optional): 引用的消息 ID + + Returns: + bool: 是否发送成功 + """ + if not discord: + return False + + try: + channel_id = int(group_id) + channel = self.bot.get_channel(channel_id) + if not channel: + channel = await self.bot.fetch_channel(channel_id) + + if not hasattr(channel, "send"): + return False + + reference = None + if reply_to: + try: + reference = discord.MessageReference( + message_id=int(reply_to), channel_id=channel_id + ) + except (ValueError, TypeError): + pass + + await channel.send(content=text, reference=reference) + return True + except Exception as e: + logger.error(f"Discord 文本发送失败: {e}") + return False + + async def send_image( + self, + group_id: str, + image_path: str, + caption: str = "", + ) -> bool: + """ + 向 Discord 频道异步发送图片。 + + 对于远程 URL,会先下载到内存再通过 Discord API 发送。 + + Args: + group_id (str): 频道 ID + image_path (str): 本地路径或 http URL + caption (str): 可选说明文字 + + Returns: + bool: 是否发送成功 + """ + if not discord: + return False + + try: + channel_id = int(group_id) + channel = self._discord_client.get_channel(channel_id) + if not channel: + channel = await self._discord_client.fetch_channel(channel_id) + + if not hasattr(channel, "send"): + return False + + file_to_send = None + if image_path.startswith("base64://"): + # Base64 图片:解码 -> 内存 Object -> Discord + import base64 # Fix: Ensure base64 is imported + from io import BytesIO + + try: + base64_data = image_path.split("base64://")[1] + image_bytes = base64.b64decode(base64_data) + file_to_send = discord.File( + BytesIO(image_bytes), filename="daily_report_image.png" + ) + except Exception as e: + logger.error(f"Discord Base64 图片解码失败: {e}") + return False + + elif image_path.startswith(("http://", "https://")): + # 远程图片:下载 -> 内存 Object -> Discord + from io import BytesIO + + import aiohttp + + try: + async with aiohttp.ClientSession() as session: + async with session.get( + image_path, timeout=aiohttp.ClientTimeout(total=30) + ) as resp: + if resp.status == 200: + data = await resp.read() + # 尽量保留原始后缀 + filename = image_path.split("/")[-1].split("?")[0] + if not filename.lower().endswith( + (".png", ".jpg", ".jpeg", ".gif", ".webp") + ): + filename = "daily_report_image.png" + + file_to_send = discord.File( + BytesIO(data), filename=filename + ) + else: + # 兜底:如果下载失败,直接发 URL 给 Discord 尝试自动解析 + content = ( + f"{caption}\n{image_path}" + if caption + else image_path + ) + await channel.send(content=content) + return True + except Exception as de: + logger.warning( + f"Discord 远程图片下载失败: {de},将回退为发送 URL。" + ) + content = f"{caption}\n{image_path}" if caption else image_path + await channel.send(content=content) + return True + else: + # 本地图片 + file_to_send = discord.File(image_path) + + if file_to_send: + await channel.send(content=caption or None, file=file_to_send) + return True + + except Exception as e: + logger.error(f"Discord 图片发送失败: {e}") + return False + + async def send_file( + self, + group_id: str, + file_path: str, + filename: str | None = None, + ) -> bool: + """向 Discord 频道上传任意文件。""" + if not discord: + return False + + try: + channel_id = int(group_id) + channel = self.bot.get_channel(channel_id) + if not channel: + channel = await self.bot.fetch_channel(channel_id) + + if not hasattr(channel, "send"): + return False + + file_to_send = discord.File(file_path, filename=filename) + await channel.send(file=file_to_send) + return True + except Exception as e: + logger.error(f"Discord 文件发送失败: {e}") + return False + + async def send_forward_msg( + self, + group_id: str, + nodes: list[dict], + ) -> bool: + """ + 在 Discord 模拟合并转发。 + + 由于 Discord 没有原生节点转发 API,我们将其转换为一组文本消息发送。 + """ + if not discord: + return False + + try: + channel_id = int(group_id) + channel = self._discord_client.get_channel(channel_id) + if not channel: + channel = await self._discord_client.fetch_channel(channel_id) + + if not hasattr(channel, "send"): + return False + + # 将节点汇总为美化的文本块 + lines = ["📊 **结构化报告摘要 (Structured Report)**\n"] + for node in nodes: + data = node.get("data", node) # 兼容不同格式 + name = data.get("name", "AstrBot") + content = data.get("content", "") + lines.append(f"**[{name}]**:\n{content}\n") + + full_text = "\n".join(lines) + + # 分段处理大消息 + if len(full_text) > 1900: + parts = [ + full_text[i : i + 1900] for i in range(0, len(full_text), 1900) + ] + for part in parts: + await channel.send(content=part) + else: + await channel.send(content=full_text) + + return True + except Exception as e: + logger.error(f"Discord 模拟转发失败: {e}") + return False + + # ==================== IGroupInfoRepository 实现 ==================== + + async def get_group_info(self, group_id: str) -> UnifiedGroup | None: + """解析 Discord 频道及所属服务器的基本信息。""" + if not discord: + return None + + try: + channel_id = int(group_id) + channel = self.bot.get_channel(channel_id) + if not channel: + channel = await self.bot.fetch_channel(channel_id) + + guild = getattr(channel, "guild", None) + group_name = getattr(channel, "name", str(channel.id)) + + if guild: + # 群聊(服务器频道) + member_count = guild.member_count + owner_id = str(guild.owner_id) + else: + # 私人对话(DM) + member_count = len(getattr(channel, "recipients", [])) + 1 + owner_id = str(getattr(channel, "owner_id", "")) + + return UnifiedGroup( + group_id=str(channel.id), + group_name=group_name, + member_count=member_count, + owner_id=owner_id or None, + create_time=int(channel.created_at.timestamp()), + platform="discord", + ) + except Exception as e: + logger.debug(f"Discord 获取群组信息错误: {e}") + return None + + async def get_group_list(self) -> list[str]: + """列出机器人所在服务器中所有可访问的文本频道 ID。""" + if not discord: + return [] + + try: + channel_ids = [] + for guild in self._discord_client.guilds: + for channel in guild.text_channels: + channel_ids.append(str(channel.id)) + return channel_ids + except Exception: + return [] + + async def get_member_list(self, group_id: str) -> list[UnifiedMember]: + """ + 获取频道对应的成员列表。 + + 注意:对于大型服务器,建议启用 GUILD_MEMBERS 意图以保证列表完整性。 + """ + if not discord: + return [] + + try: + channel_id = int(group_id) + channel = self.bot.get_channel(channel_id) + if not channel: + channel = await self.bot.fetch_channel(channel_id) + + guild = getattr(channel, "guild", None) + if not guild: + # 私聊收件人 + return [ + UnifiedMember( + user_id=str(u.id), + nickname=u.name, + card=u.display_name, + role="member", + ) + for u in getattr(channel, "recipients", []) + ] + + members = [] + for member in guild.members: + role = "member" + if member.id == guild.owner_id: + role = "owner" + elif member.guild_permissions.administrator: + role = "admin" + + members.append( + UnifiedMember( + user_id=str(member.id), + nickname=member.name, + card=member.nick or member.global_name, + role=role, + join_time=int(member.joined_at.timestamp()) + if member.joined_at + else None, + ) + ) + return members + except Exception: + return [] + + async def get_member_info( + self, + group_id: str, + user_id: str, + ) -> UnifiedMember | None: + """获取并解析特定 Discord 用户的身份信息。""" + if not discord: + return None + + try: + uid = int(user_id) + channel_id = int(group_id) + channel = self.bot.get_channel(channel_id) + if not channel: + channel = await self.bot.fetch_channel(channel_id) + + guild = getattr(channel, "guild", None) + if not guild: + # 跨频道/私聊探测 + user = await self.bot.fetch_user(uid) + return UnifiedMember( + user_id=str(user.id), nickname=user.name, card=user.display_name + ) + + member = guild.get_member(uid) or await guild.fetch_member(uid) + if not member: + return None + + role = ( + "owner" + if member.id == guild.owner_id + else ("admin" if member.guild_permissions.administrator else "member") + ) + + return UnifiedMember( + user_id=str(member.id), + nickname=member.name, + card=member.nick or member.global_name, + role=role, + join_time=int(member.joined_at.timestamp()) + if member.joined_at + else None, + ) + except Exception: + return None + + # ==================== IAvatarRepository 实现 ==================== + + async def get_user_avatar_url( + self, + user_id: str, + size: int = 100, + ) -> str | None: + """根据 Discord 用户 ID 动态解析其头像 CDN 地址。""" + if not discord or not self._discord_client: + return None + + try: + uid = int(user_id) + user = self._discord_client.get_user( + uid + ) or await self._discord_client.fetch_user(uid) + + if user: + # 自动对齐 Discord 支持的尺寸 (2的幂) + allowed_sizes = (16, 32, 64, 128, 256, 512, 1024, 2048, 4096) + target_size = min(allowed_sizes, key=lambda x: abs(x - size)) + return user.display_avatar.with_size(target_size).url + + return None + except Exception as e: + logger.debug(f"Discord 获取用户头像 URL 错误: {e}") + return None + + async def get_user_avatar_data( + self, + user_id: str, + size: int = 100, + ) -> str | None: + """暂不提供 Base64 转换服务,优先使用 CDN 链接。""" + return None + + async def get_group_avatar_url( + self, + group_id: str, + size: int = 100, + ) -> str | None: + """获取 Discord 服务器(Guild)的图标地址。""" + if not discord: + return None + + try: + channel = self.bot.get_channel( + int(group_id) + ) or await self.bot.fetch_channel(int(group_id)) + guild = getattr(channel, "guild", None) + if guild and guild.icon: + allowed_sizes = (16, 32, 64, 128, 256, 512, 1024, 2048, 4096) + target_size = min(allowed_sizes, key=lambda x: abs(x - size)) + return guild.icon.with_size(target_size).url + return None + except Exception: + return None + + async def batch_get_avatar_urls( + self, + user_ids: list[str], + size: int = 100, + ) -> dict[str, str | None]: + """批量获取头像的最佳实践。""" + return {uid: await self.get_user_avatar_url(uid, size) for uid in user_ids} + + async def set_reaction( + self, group_id: str, message_id: str, emoji: str | int, is_add: bool = True + ) -> bool: + """ + Discord 实现消息回应。 + """ + if not discord: + return False + + try: + reaction_key = str(emoji) + emoji_to_use = { + "analysis_started": "🔍", + "analysis_done": "📊", + "289": "🔍", + "124": "📊", + "424": "📊", + }.get(reaction_key, reaction_key) + + channel_id = int(group_id) + channel = self._discord_client.get_channel(channel_id) + if not channel: + channel = await self._discord_client.fetch_channel(channel_id) + + if not hasattr(channel, "get_partial_message"): + # 如果较低版本的 SDK 没这个方法,则直接 fetch + msg = await channel.fetch_message(int(message_id)) + else: + msg = channel.get_partial_message(int(message_id)) + + if is_add: + await msg.add_reaction(emoji_to_use) + else: + await msg.remove_reaction(emoji_to_use, self._discord_client.user) + return True + except Exception as e: + logger.debug(f"Discord set_reaction 失败: {e}") + return False diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/lark_adapter.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/lark_adapter.py new file mode 100644 index 0000000..092c26f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/lark_adapter.py @@ -0,0 +1,1129 @@ +""" +Feishu/Lark 平台适配器 + +复用 AstrBot 已有 lark_oapi 生态能力,实现飞书群分析消息读取、成员信息与头像获取。 +""" + +from __future__ import annotations + +import asyncio +import base64 +import json +import random +from collections.abc import Generator, Iterator, Mapping +from pathlib import Path +from tempfile import NamedTemporaryFile +from typing import Protocol, TypeAlias, cast + +import aiohttp +from aiohttp import ClientTimeout + +from ....domain.value_objects.platform_capabilities import ( + LARK_CAPABILITIES, + PlatformCapabilities, +) +from ....domain.value_objects.unified_group import UnifiedGroup, UnifiedMember +from ....domain.value_objects.unified_message import ( + MessageContent, + MessageContentType, + UnifiedMessage, +) +from ....utils.logger import logger +from ..base import PlatformAdapter + + +class _SDKNode(Protocol): + def __getattr__(self, name: str) -> _SDKNode: ... + + def __call__(self, *args: object, **kwargs: object) -> _SDKNode: ... + + def __await__(self) -> Generator[object, None, _SDKNode]: ... + + def __iter__(self) -> Iterator[_SDKNode]: ... + + def __bool__(self) -> bool: ... + + def __int__(self) -> int: ... + + +class _BuilderRequest(Protocol): + @classmethod + def builder(cls) -> object: ... + + +CreateFileRequest: type[_BuilderRequest] | None = None +CreateFileRequestBody: type[_BuilderRequest] | None = None +CreateImageRequest: type[_BuilderRequest] | None = None +CreateImageRequestBody: type[_BuilderRequest] | None = None +CreateMessageRequest: type[_BuilderRequest] | None = None +CreateMessageRequestBody: type[_BuilderRequest] | None = None +GetChatMembersRequest: type[_BuilderRequest] | None = None +GetChatRequest: type[_BuilderRequest] | None = None +GetUserRequest: type[_BuilderRequest] | None = None +ListMessageRequest: type[_BuilderRequest] | None = None +ReplyMessageRequest: type[_BuilderRequest] | None = None +ReplyMessageRequestBody: type[_BuilderRequest] | None = None + +JSONPrimitive: TypeAlias = str | int | float | bool | None +JSONValue: TypeAlias = JSONPrimitive | dict[str, "JSONValue"] | list["JSONValue"] + +try: + from lark_oapi.api.contact.v3 import GetUserRequest as _GetUserRequest + from lark_oapi.api.im.v1 import ( + CreateFileRequest as _CreateFileRequest, + ) + from lark_oapi.api.im.v1 import ( + CreateFileRequestBody as _CreateFileRequestBody, + ) + from lark_oapi.api.im.v1 import ( + CreateImageRequest as _CreateImageRequest, + ) + from lark_oapi.api.im.v1 import ( + CreateImageRequestBody as _CreateImageRequestBody, + ) + from lark_oapi.api.im.v1 import ( + CreateMessageRequest as _CreateMessageRequest, + ) + from lark_oapi.api.im.v1 import ( + CreateMessageRequestBody as _CreateMessageRequestBody, + ) + from lark_oapi.api.im.v1 import ( + GetChatMembersRequest as _GetChatMembersRequest, + ) + from lark_oapi.api.im.v1 import ( + GetChatRequest as _GetChatRequest, + ) + from lark_oapi.api.im.v1 import ( + ListMessageRequest as _ListMessageRequest, + ) + from lark_oapi.api.im.v1 import ( + ReplyMessageRequest as _ReplyMessageRequest, + ) + from lark_oapi.api.im.v1 import ( + ReplyMessageRequestBody as _ReplyMessageRequestBody, + ) + + CreateFileRequest = _CreateFileRequest + CreateFileRequestBody = _CreateFileRequestBody + CreateImageRequest = _CreateImageRequest + CreateImageRequestBody = _CreateImageRequestBody + CreateMessageRequest = _CreateMessageRequest + CreateMessageRequestBody = _CreateMessageRequestBody + GetChatMembersRequest = _GetChatMembersRequest + GetChatRequest = _GetChatRequest + GetUserRequest = _GetUserRequest + ListMessageRequest = _ListMessageRequest + ReplyMessageRequest = _ReplyMessageRequest + ReplyMessageRequestBody = _ReplyMessageRequestBody + + LARK_AVAILABLE = True +except Exception: # pragma: no cover - 兼容缺依赖环境 + LARK_AVAILABLE = False + + +class LarkAdapter(PlatformAdapter): + """飞书平台适配器。""" + + platform_name = "lark" + _DEFAULT_SCOPE_HINT = ( + "Please grant these Feishu app scopes once: " + "`im:message:readonly`, `im:chat:readonly`, and user/contact read scopes " + "for profile avatar fields, then reinstall/re-authorize the app." + ) + + def __init__( + self, + bot_instance: object, + config: Mapping[str, object] | None = None, + ): + normalized_config = dict(config) if config is not None else None + super().__init__(bot_instance, normalized_config) + self._lark_client: _SDKNode | None = self._resolve_lark_client(bot_instance) + self._avatar_url_cache: dict[str, str] = {} + self._member_name_cache: dict[tuple[str, str], str] = {} + self._member_avatar_cache: dict[tuple[str, str], str] = {} + self._permission_checked_groups: set[str] = set() + self._permission_error_by_group: dict[str, str | None] = {} + logger.info( + "飞书适配器初始化完成 (SDK可用=%s, 客户端就绪=%s)", + LARK_AVAILABLE, + bool(self._lark_client), + ) + + @staticmethod + def _request_class_or_throw( + request_cls: type[_BuilderRequest] | None, name: str + ) -> type[_BuilderRequest]: + if request_cls is None: + raise RuntimeError(f"{name} unavailable; install lark_oapi") + return request_cls + + @staticmethod + def _builder(request_cls: type[_BuilderRequest]) -> _SDKNode: + return cast(_SDKNode, request_cls.builder()) + + def _init_capabilities(self) -> PlatformCapabilities: + return LARK_CAPABILITIES + + @staticmethod + def _resolve_lark_client(bot_instance: object) -> _SDKNode | None: + if bot_instance is None: + return None + # 直接是 lark.Client + if hasattr(bot_instance, "im") and hasattr(bot_instance, "contact"): + return cast(_SDKNode, bot_instance) + # 平台实例上暴露 lark_api + if hasattr(bot_instance, "lark_api"): + api = getattr(bot_instance, "lark_api") + if hasattr(api, "im"): + return cast(_SDKNode, api) + # 常见包装层 + for attr in ("client", "_client", "bot"): + if hasattr(bot_instance, attr): + client = getattr(bot_instance, attr) + if hasattr(client, "im"): + return cast(_SDKNode, client) + return None + + @staticmethod + def _to_seconds(ts: int | None) -> int: + if not ts: + return 0 + try: + ts_int = int(ts) + except (TypeError, ValueError): + return 0 + return ts_int // 1000 if ts_int > 10**11 else ts_int + + @staticmethod + def _safe_json_loads(raw: str | None) -> dict[str, JSONValue]: + if not raw: + return {} + try: + parsed = json.loads(raw) + return parsed if isinstance(parsed, dict) else {} + except Exception: + return {} + + @staticmethod + def _is_permission_error(code: int, msg: str) -> bool: + msg_l = (msg or "").lower() + return code in {99991663, 99991664, 230001, 20013} or ( + "permission" in msg_l + or "scope" in msg_l + or "forbidden" in msg_l + or "无权限" in msg_l + ) + + @staticmethod + def _pick_avatar_from_user(user_obj: object, size: int) -> str | None: + avatar = getattr(user_obj, "avatar", None) + if avatar is None: + return None + if size <= 72 and getattr(avatar, "avatar_72", None): + return avatar.avatar_72 + if size <= 240 and getattr(avatar, "avatar_240", None): + return avatar.avatar_240 + if size <= 640 and getattr(avatar, "avatar_640", None): + return avatar.avatar_640 + return getattr(avatar, "avatar_origin", None) or getattr( + avatar, "avatar_640", None + ) + + @staticmethod + def _extract_sender_id(item: object) -> str: + sender = getattr(item, "sender", None) + if sender is None: + return "" + sender_id = getattr(sender, "id", None) + if isinstance(sender_id, str): + return sender_id + if sender_id is not None: + for attr in ("open_id", "user_id", "union_id", "id"): + value = getattr(sender_id, attr, None) + if value: + return str(value) + direct_open_id = getattr(sender, "open_id", None) + if direct_open_id: + return str(direct_open_id) + return "" + + @staticmethod + def _extract_sender_display_name(item: object) -> str: + sender = getattr(item, "sender", None) + if sender is None: + return "" + for attr in ("sender_name", "name", "nickname"): + value = getattr(sender, attr, None) + if value: + return str(value) + sender_id = LarkAdapter._extract_sender_id(item) + return sender_id[:8] if sender_id else "Unknown" + + @staticmethod + def _pick_post_locale_content(content: dict[str, JSONValue]) -> list[JSONValue]: + preferred_locales = ("zh_cn", "zh_tw", "en_us", "ja_jp") + for locale in preferred_locales: + locale_data = content.get(locale) + if isinstance(locale_data, dict): + locale_content = locale_data.get("content", []) + if isinstance(locale_content, list): + return locale_content + for value in content.values(): + if isinstance(value, dict): + locale_content = value.get("content", []) + if isinstance(locale_content, list): + return locale_content + return [] + + @staticmethod + def _build_fallback_avatar(user_id: str, nickname: str | None = None) -> str: + label_raw = (nickname or user_id or "U").strip() + label = label_raw[:1].upper() if label_raw else "U" + seed = sum(ord(ch) for ch in user_id) + hue = random.Random(seed).randint(0, 359) + bg = f"hsl({hue}, 70%, 45%)" + svg = ( + '' + f'' + f'' + f"{label}" + ) + encoded = base64.b64encode(svg.encode("utf-8")).decode("utf-8") + return f"data:image/svg+xml;base64,{encoded}" + + @staticmethod + def _short_id(raw: str, keep: int = 6) -> str: + if not raw: + return "" + if len(raw) <= keep * 2: + return raw + return f"{raw[:keep]}...{raw[-keep:]}" + + async def prepare_group_member_cache( + self, group_id: str + ) -> tuple[bool, str | None]: + """ + 预热群成员缓存并完成权限探测。 + 该方法用于在分析前一次性确认“成员信息+头像”权限是否齐备。 + """ + if group_id in self._permission_checked_groups: + err = self._permission_error_by_group.get(group_id) + logger.debug( + "飞书预检查命中缓存: 群=%s, 结果=%s", + group_id, + err is None, + ) + return err is None, err + logger.info("飞书预检查开始: 群=%s", group_id) + if not LARK_AVAILABLE or not self._lark_client or not self._lark_client.im: + self._permission_error_by_group[group_id] = "飞书 SDK 客户端未初始化。" + self._permission_checked_groups.add(group_id) + logger.warning("飞书预检查失败: 群=%s, 原因=SDK或客户端不可用", group_id) + return False, self._permission_error_by_group[group_id] + + try: + members = await self.get_member_list(group_id) + if not members: + self._permission_error_by_group[group_id] = ( + f"Cannot list chat members. {self._DEFAULT_SCOPE_HINT}" + ) + self._permission_checked_groups.add(group_id) + logger.warning("飞书预检查失败: 群=%s, 原因=未获取到成员列表", group_id) + return False, self._permission_error_by_group[group_id] + + # 只预热近期活跃用户常见数量,避免在超大群上引入不必要延迟 + target_ids = [m.user_id for m in members[:100]] + avatar_map = await self.batch_get_avatar_urls(target_ids, size=240) + avatar_ok_count = sum(1 for uid in target_ids if avatar_map.get(uid)) + if target_ids and all(not avatar_map.get(uid) for uid in target_ids): + self._permission_error_by_group[group_id] = ( + "Fetched members but cannot read avatar URLs. " + f"{self._DEFAULT_SCOPE_HINT}" + ) + self._permission_checked_groups.add(group_id) + logger.warning( + "飞书预检查失败: 群=%s, 原因=头像预热结果为空 (用户数=%s)", + group_id, + len(target_ids), + ) + return False, self._permission_error_by_group[group_id] + + self._permission_error_by_group[group_id] = None + self._permission_checked_groups.add(group_id) + logger.info( + "飞书预检查通过: 群=%s (成员=%s, 头像成功=%s/%s)", + group_id, + len(members), + avatar_ok_count, + len(target_ids), + ) + return True, None + except Exception as e: + self._permission_error_by_group[group_id] = ( + f"飞书成员缓存预热失败: {e}. {self._DEFAULT_SCOPE_HINT}" + ) + self._permission_checked_groups.add(group_id) + logger.error( + "飞书预检查异常: 群=%s, 错误=%s", + group_id, + e, + exc_info=True, + ) + return False, self._permission_error_by_group[group_id] + + async def fetch_messages( + self, + group_id: str, + days: int = 1, + max_count: int = 1000, + before_id: str | None = None, + since_ts: int | None = None, + ) -> list[UnifiedMessage]: + if not LARK_AVAILABLE or not self._lark_client or not self._lark_client.im: + logger.warning("飞书消息拉取跳过: 群=%s, 原因=SDK或客户端不可用", group_id) + return [] + now_seconds = int(__import__("time").time()) + start_seconds = ( + int(since_ts) if since_ts and since_ts > 0 else now_seconds - (days * 86400) + ) + + messages: list[UnifiedMessage] = [] + page_token: str | None = None + page_size = min(max(max_count, 1), 200) + seen_ids: set[str] = set() + page_index = 0 + logger.info( + "飞书消息拉取开始: 群=%s (天数=%s, 最大条数=%s, since_ts=%s)", + group_id, + days, + max_count, + since_ts, + ) + + while len(messages) < max_count: + page_index += 1 + ListMessageRequestClass = self._request_class_or_throw( + ListMessageRequest, "ListMessageRequest" + ) + request = ( + self._builder(ListMessageRequestClass) + .container_id_type("chat") + .container_id(group_id) + .start_time(str(start_seconds * 1000)) + .end_time(str(now_seconds * 1000)) + .page_size(min(page_size, max_count - len(messages))) + .build() + ) + if page_token: + request = ( + self._builder(ListMessageRequestClass) + .container_id_type("chat") + .container_id(group_id) + .start_time(str(start_seconds * 1000)) + .end_time(str(now_seconds * 1000)) + .page_size(min(page_size, max_count - len(messages))) + .page_token(page_token) + .build() + ) + + response = await self._lark_client.im.v1.message.alist(request) + if not response.success(): + logger.warning( + "飞书消息拉取失败: 群=%s, code=%s, msg=%s", + group_id, + response.code, + response.msg, + ) + break + + items_raw = (response.data.items if response.data else None) or [] + items: list[object] = items_raw if isinstance(items_raw, list) else [] + logger.debug( + "飞书消息分页: 页=%s, 群=%s, 条数=%s, has_more=%s", + page_index, + group_id, + len(items), + bool(response.data and response.data.has_more), + ) + if not items: + break + + for item in items: + msg = self._convert_message(item, group_id) + if not msg or not msg.message_id or msg.message_id in seen_ids: + continue + if before_id and msg.message_id >= before_id: + continue + seen_ids.add(msg.message_id) + messages.append(msg) + if len(messages) >= max_count: + break + + has_more = bool(response.data and response.data.has_more) + page_token_raw = ( + getattr(response.data, "page_token", None) if response.data else None + ) + page_token = str(page_token_raw) if page_token_raw else None + if not has_more or not page_token: + break + + messages.sort(key=lambda m: m.timestamp) + logger.info( + "飞书消息拉取完成: 群=%s (消息=%s, 页数=%s, 起始=%s, 结束=%s)", + group_id, + len(messages), + page_index, + start_seconds, + now_seconds, + ) + return messages + + def _convert_message(self, item: object, group_id: str) -> UnifiedMessage | None: + try: + message_id = str(getattr(item, "message_id", "") or "") + sender_id = self._extract_sender_id(item) + sender_name = self._member_name_cache.get( + (group_id, sender_id) + ) or self._extract_sender_display_name(item) + body = getattr(item, "body", None) + raw_content = str(getattr(body, "content", "") or "") + msg_type = str(getattr(item, "msg_type", "") or "text") + content = self._safe_json_loads(raw_content) + + contents: list[MessageContent] = [] + text_parts: list[str] = [] + + if msg_type == "text": + text = str(content.get("text", "")).strip() + if text: + text_parts.append(text) + contents.append( + MessageContent(type=MessageContentType.TEXT, text=text) + ) + elif msg_type == "image": + image_key = str(content.get("image_key", "")).strip() + if image_key: + contents.append( + MessageContent( + type=MessageContentType.IMAGE, + raw_data={"image_key": image_key}, + ) + ) + elif msg_type == "post": + post_content = self._pick_post_locale_content(content) + for row in post_content: + if not isinstance(row, list): + continue + for seg in row: + if not isinstance(seg, dict): + continue + tag = str(seg.get("tag", "")).strip() + if tag == "text": + text = str(seg.get("text", "")).strip() + if text: + text_parts.append(text) + contents.append( + MessageContent( + type=MessageContentType.TEXT, text=text + ) + ) + elif tag == "at": + at_uid = str(seg.get("user_id", "")).strip() + if at_uid: + contents.append( + MessageContent( + type=MessageContentType.AT, + at_user_id=at_uid, + ) + ) + elif tag == "img": + image_key = str(seg.get("image_key", "")).strip() + if image_key: + contents.append( + MessageContent( + type=MessageContentType.IMAGE, + raw_data={"image_key": image_key}, + ) + ) + elif tag == "a": + link_text = str(seg.get("text", "")).strip() + if link_text: + text_parts.append(link_text) + contents.append( + MessageContent( + type=MessageContentType.TEXT, + text=link_text, + ) + ) + elif tag == "emoji": + emoji_type = str(seg.get("emoji_type", "")).strip() + if emoji_type: + contents.append( + MessageContent( + type=MessageContentType.EMOJI, + emoji_id=emoji_type, + raw_data=seg, + ) + ) + elif msg_type in {"file", "media", "audio", "sticker"}: + if raw_content: + contents.append( + MessageContent( + type=MessageContentType.UNKNOWN, + raw_data={"msg_type": msg_type, "content": raw_content}, + ) + ) + else: + if raw_content: + contents.append( + MessageContent( + type=MessageContentType.UNKNOWN, + raw_data={"msg_type": msg_type, "content": raw_content}, + ) + ) + + if not contents: + fallback_text = " ".join(text_parts).strip() + if not fallback_text: + fallback_text = f"[{msg_type}]" + contents.append( + MessageContent( + type=MessageContentType.TEXT, + text=fallback_text, + ) + ) + + return UnifiedMessage( + message_id=message_id, + sender_id=sender_id, + sender_name=sender_name, + sender_card=None, + group_id=group_id, + text_content=" ".join(text_parts).strip(), + contents=tuple(contents), + timestamp=self._to_seconds(getattr(item, "create_time", 0)), + platform="lark", + reply_to_id=( + str(parent_id) + if (parent_id := getattr(item, "parent_id", None)) + else None + ), + ) + except Exception as e: + logger.debug(f"飞书消息转换失败: {e}") + return None + + def convert_to_raw_format(self, messages: list[UnifiedMessage]) -> list[dict]: + result: list[dict] = [] + for msg in messages: + chain: list[dict[str, object]] = [] + for content in msg.contents: + if content.type == MessageContentType.TEXT: + chain.append({"type": "text", "data": {"text": content.text}}) + elif content.type == MessageContentType.AT: + chain.append({"type": "at", "data": {"qq": content.at_user_id}}) + elif content.type == MessageContentType.IMAGE: + chain.append( + { + "type": "image", + "data": { + "url": content.url or "", + "image_key": ( + content.raw_data.get("image_key", "") + if isinstance(content.raw_data, dict) + else "" + ), + }, + } + ) + result.append( + { + "message_id": msg.message_id, + "group_id": msg.group_id, + "time": msg.timestamp, + "sender": {"user_id": msg.sender_id, "nickname": msg.sender_name}, + "message": chain, + "user_id": msg.sender_id, + } + ) + return result + + async def send_text( + self, group_id: str, text: str, reply_to: str | None = None + ) -> bool: + if not self._lark_client or not self._lark_client.im: + return False + try: + ReplyMessageRequestClass = self._request_class_or_throw( + ReplyMessageRequest, "ReplyMessageRequest" + ) + ReplyMessageRequestBodyClass = self._request_class_or_throw( + ReplyMessageRequestBody, "ReplyMessageRequestBody" + ) + CreateMessageRequestClass = self._request_class_or_throw( + CreateMessageRequest, "CreateMessageRequest" + ) + CreateMessageRequestBodyClass = self._request_class_or_throw( + CreateMessageRequestBody, "CreateMessageRequestBody" + ) + + if reply_to: + request = ( + self._builder(ReplyMessageRequestClass) + .message_id(reply_to) + .request_body( + self._builder(ReplyMessageRequestBodyClass) + .content(json.dumps({"text": text}, ensure_ascii=False)) + .msg_type("text") + .build() + ) + .build() + ) + response = await self._lark_client.im.v1.message.areply(request) + else: + request = ( + self._builder(CreateMessageRequestClass) + .receive_id_type("chat_id") + .request_body( + self._builder(CreateMessageRequestBodyClass) + .receive_id(group_id) + .msg_type("text") + .content(json.dumps({"text": text}, ensure_ascii=False)) + .build() + ) + .build() + ) + response = await self._lark_client.im.v1.message.acreate(request) + return bool(response.success()) + except Exception as e: + logger.error(f"飞书文本发送失败: {e}") + return False + + async def send_image( + self, group_id: str, image_path: str, caption: str = "" + ) -> bool: + if not self._lark_client or not self._lark_client.im: + return False + temp_path: Path | None = None + try: + local_path: Path | None = None + if image_path.startswith("base64://"): + data = base64.b64decode(image_path.removeprefix("base64://")) + with NamedTemporaryFile(delete=False, suffix=".png") as f: + f.write(data) + temp_path = Path(f.name) + local_path = temp_path + elif image_path.startswith("data:"): + parts = image_path.split(",", 1) + if len(parts) == 2: + data = base64.b64decode(parts[1]) + with NamedTemporaryFile(delete=False, suffix=".png") as f: + f.write(data) + temp_path = Path(f.name) + local_path = temp_path + elif image_path.startswith(("http://", "https://")): + async with aiohttp.ClientSession() as session: + async with session.get( + image_path, timeout=ClientTimeout(total=20) + ) as resp: + if resp.status != 200: + return False + data = await resp.read() + with NamedTemporaryFile(delete=False, suffix=".png") as f: + f.write(data) + temp_path = Path(f.name) + local_path = temp_path + else: + p = Path(image_path) + if p.exists(): + local_path = p + + if not local_path: + return False + + CreateImageRequestClass = self._request_class_or_throw( + CreateImageRequest, "CreateImageRequest" + ) + CreateImageRequestBodyClass = self._request_class_or_throw( + CreateImageRequestBody, "CreateImageRequestBody" + ) + + with local_path.open("rb") as img_file: + image_req = ( + self._builder(CreateImageRequestClass) + .request_body( + self._builder(CreateImageRequestBodyClass) + .image_type("message") + .image(img_file) + .build() + ) + .build() + ) + image_resp = await self._lark_client.im.v1.image.acreate(image_req) + if not image_resp.success() or not image_resp.data: + return False + image_key = image_resp.data.image_key + + CreateMessageRequestClass = self._request_class_or_throw( + CreateMessageRequest, "CreateMessageRequest" + ) + CreateMessageRequestBodyClass = self._request_class_or_throw( + CreateMessageRequestBody, "CreateMessageRequestBody" + ) + + send_req = ( + self._builder(CreateMessageRequestClass) + .receive_id_type("chat_id") + .request_body( + self._builder(CreateMessageRequestBodyClass) + .receive_id(group_id) + .msg_type("image") + .content(json.dumps({"image_key": image_key}, ensure_ascii=False)) + .build() + ) + .build() + ) + send_resp = await self._lark_client.im.v1.message.acreate(send_req) + if caption: + await self.send_text(group_id, caption) + return bool(send_resp.success()) + except Exception as e: + logger.error(f"飞书图片发送失败: {e}") + return False + finally: + if temp_path and temp_path.exists(): + try: + temp_path.unlink() + except OSError: + pass + + async def send_file( + self, group_id: str, file_path: str, filename: str | None = None + ) -> bool: + if not self._lark_client or not self._lark_client.im: + return False + try: + p = Path(file_path) + if not p.exists(): + return False + with p.open("rb") as file_obj: + CreateFileRequestClass = self._request_class_or_throw( + CreateFileRequest, "CreateFileRequest" + ) + CreateFileRequestBodyClass = self._request_class_or_throw( + CreateFileRequestBody, "CreateFileRequestBody" + ) + + file_req = ( + self._builder(CreateFileRequestClass) + .request_body( + self._builder(CreateFileRequestBodyClass) + .file_type("stream") + .file_name(filename or p.name) + .file(file_obj) + .build() + ) + .build() + ) + file_resp = await self._lark_client.im.v1.file.acreate(file_req) + if not file_resp.success() or not file_resp.data: + return False + file_key = file_resp.data.file_key + + CreateMessageRequestClass = self._request_class_or_throw( + CreateMessageRequest, "CreateMessageRequest" + ) + CreateMessageRequestBodyClass = self._request_class_or_throw( + CreateMessageRequestBody, "CreateMessageRequestBody" + ) + + msg_req = ( + self._builder(CreateMessageRequestClass) + .receive_id_type("chat_id") + .request_body( + self._builder(CreateMessageRequestBodyClass) + .receive_id(group_id) + .msg_type("file") + .content(json.dumps({"file_key": file_key}, ensure_ascii=False)) + .build() + ) + .build() + ) + msg_resp = await self._lark_client.im.v1.message.acreate(msg_req) + return bool(msg_resp.success()) + except Exception as e: + logger.error(f"飞书文件发送失败: {e}") + return False + + async def get_group_info(self, group_id: str) -> UnifiedGroup | None: + if not self._lark_client or not self._lark_client.im: + return None + try: + GetChatRequestClass = self._request_class_or_throw( + GetChatRequest, "GetChatRequest" + ) + request = self._builder(GetChatRequestClass).chat_id(group_id).build() + response = await self._lark_client.im.v1.chat.aget(request) + if not response.success() or not response.data: + return None + group_name_raw = getattr(response.data, "name", None) + owner_id_raw = getattr(response.data, "owner_id", None) + description_raw = getattr(response.data, "description", None) + return UnifiedGroup( + group_id=group_id, + group_name=str(group_name_raw) if group_name_raw else group_id, + member_count=int(getattr(response.data, "user_count", 0) or 0), + owner_id=str(owner_id_raw) if owner_id_raw else None, + description=str(description_raw) if description_raw else None, + platform="lark", + ) + except Exception as e: + logger.debug(f"飞书群信息获取失败: {e}") + return None + + async def get_group_list(self) -> list[str]: + # 飞书服务端 API 不提供简单“机器人可见群列表”枚举能力 + return [] + + async def get_member_list(self, group_id: str) -> list[UnifiedMember]: + if not self._lark_client or not self._lark_client.im: + logger.warning( + "飞书成员列表获取跳过: 群=%s, 原因=客户端不可用", + group_id, + ) + return [] + members: list[UnifiedMember] = [] + page_token: str | None = None + page_index = 0 + logger.debug("飞书成员列表获取开始: 群=%s", group_id) + while True: + page_index += 1 + GetChatMembersRequestClass = self._request_class_or_throw( + GetChatMembersRequest, "GetChatMembersRequest" + ) + builder = ( + self._builder(GetChatMembersRequestClass) + .chat_id(group_id) + .member_id_type("open_id") + .page_size(200) + ) + if page_token: + builder = builder.page_token(page_token) + request = builder.build() + response = await self._lark_client.im.v1.chat_members.aget(request) + if not response.success(): + if self._is_permission_error( + int(getattr(response, "code", 0) or 0), + str(getattr(response, "msg", "") or ""), + ): + logger.warning( + "飞书成员列表权限不足: 群=%s, code=%s, msg=%s", + group_id, + response.code, + response.msg, + ) + else: + logger.warning( + "飞书成员列表获取失败: 群=%s, code=%s, msg=%s", + group_id, + getattr(response, "code", "unknown"), + getattr(response, "msg", "unknown"), + ) + break + items_raw = (response.data.items if response.data else None) or [] + items: list[object] = items_raw if isinstance(items_raw, list) else [] + logger.debug( + "飞书成员分页: 页=%s, 群=%s, 条数=%s", + page_index, + group_id, + len(items), + ) + if not items: + break + for item in items: + uid_raw = getattr(item, "member_id", None) + uid = str(uid_raw or "") + name_raw = getattr(item, "name", None) + name = str(name_raw or uid) + self._member_name_cache[(group_id, uid)] = name + members.append( + UnifiedMember( + user_id=uid, + nickname=name, + role="member", + ) + ) + if not ( + response.data and response.data.has_more and response.data.page_token + ): + break + page_token_raw = getattr(response.data, "page_token", None) + page_token = str(page_token_raw) if page_token_raw else None + logger.info( + "飞书成员列表获取完成: 群=%s (成员=%s, 页数=%s)", + group_id, + len(members), + page_index, + ) + return members + + async def _get_user_profile(self, user_id: str) -> _SDKNode | None: + if not self._lark_client or not self._lark_client.contact: + return None + try: + GetUserRequestClass = self._request_class_or_throw( + GetUserRequest, "GetUserRequest" + ) + request = ( + self._builder(GetUserRequestClass) + .user_id_type("open_id") + .user_id(user_id) + .build() + ) + response = await self._lark_client.contact.v3.user.aget(request) + if not response.success(): + if self._is_permission_error( + int(getattr(response, "code", 0) or 0), + str(getattr(response, "msg", "") or ""), + ): + logger.warning( + "飞书用户资料权限不足: 用户=%s, code=%s, msg=%s", + self._short_id(user_id), + response.code, + response.msg, + ) + else: + logger.warning( + "飞书用户资料获取失败: 用户=%s, code=%s, msg=%s", + self._short_id(user_id), + getattr(response, "code", "unknown"), + getattr(response, "msg", "unknown"), + ) + return None + return response.data + except Exception as e: + logger.debug(f"飞书用户资料获取失败: {e}") + return None + + async def get_member_info( + self, group_id: str, user_id: str + ) -> UnifiedMember | None: + profile = await self._get_user_profile(user_id) + if profile and profile.user: + user = profile.user + name = str(user.name or user.nickname or user_id) + avatar = self._pick_avatar_from_user(user, 240) + if avatar: + self._member_avatar_cache[(group_id, user_id)] = avatar + self._avatar_url_cache[user_id] = avatar + self._member_name_cache[(group_id, user_id)] = name + return UnifiedMember( + user_id=str(user.open_id or user_id), + nickname=name, + card=str(user.nickname or "") or None, + role="member", + avatar_url=avatar, + ) + + cached_name = self._member_name_cache.get((group_id, user_id)) or user_id + fallback_avatar = self._member_avatar_cache.get((group_id, user_id)) + if not fallback_avatar: + fallback_avatar = self._build_fallback_avatar(user_id, cached_name) + self._member_avatar_cache[(group_id, user_id)] = fallback_avatar + self._avatar_url_cache[user_id] = fallback_avatar + return UnifiedMember( + user_id=user_id, + nickname=cached_name, + role="member", + avatar_url=fallback_avatar, + ) + + async def get_user_avatar_url(self, user_id: str, size: int = 100) -> str | None: + if user_id in self._avatar_url_cache: + return self._avatar_url_cache[user_id] + profile = await self._get_user_profile(user_id) + if profile and profile.user: + avatar_url = self._pick_avatar_from_user(profile.user, size) + if avatar_url: + self._avatar_url_cache[user_id] = avatar_url + return avatar_url + cached_name = None + for (gid, uid), name in self._member_name_cache.items(): + if uid == user_id and name: + cached_name = name + break + fallback_avatar = self._build_fallback_avatar(user_id, cached_name) + self._avatar_url_cache[user_id] = fallback_avatar + logger.debug( + "飞书头像使用回退图: 用户=%s, 尺寸=%s", + self._short_id(user_id), + size, + ) + return fallback_avatar + + async def get_user_avatar_data(self, user_id: str, size: int = 100) -> str | None: + avatar_url = await self.get_user_avatar_url(user_id, size) + if not avatar_url: + return None + try: + async with aiohttp.ClientSession() as session: + async with session.get( + avatar_url, timeout=ClientTimeout(total=10) + ) as resp: + if resp.status != 200: + return None + body = await resp.read() + mime = resp.headers.get("Content-Type", "image/png") + return ( + f"data:{mime};base64,{base64.b64encode(body).decode('utf-8')}" + ) + except Exception: + return None + + async def get_group_avatar_url(self, group_id: str, size: int = 100) -> str | None: + group = await self.get_group_info(group_id) + if not group or not self._lark_client: + return None + try: + GetChatRequestClass = self._request_class_or_throw( + GetChatRequest, "GetChatRequest" + ) + req = self._builder(GetChatRequestClass).chat_id(group_id).build() + rsp = await self._lark_client.im.v1.chat.aget(req) + if rsp.success() and rsp.data and rsp.data.avatar: + return str(rsp.data.avatar) + except Exception: + pass + return None + + async def batch_get_avatar_urls( + self, user_ids: list[str], size: int = 100 + ) -> dict[str, str | None]: + if not user_ids: + return {} + unique_ids = list(dict.fromkeys(user_ids)) + semaphore = asyncio.Semaphore(8) + logger.debug( + "飞书批量头像获取开始 (请求=%s, 去重后=%s, 尺寸=%s)", + len(user_ids), + len(unique_ids), + size, + ) + + async def _fetch(uid: str) -> tuple[str, str | None]: + async with semaphore: + return uid, await self.get_user_avatar_url(uid, size) + + pairs = await asyncio.gather(*(_fetch(uid) for uid in unique_ids)) + result = dict(pairs) + ok_count = sum(1 for _, url in pairs if url) + logger.debug("飞书批量头像获取完成 (成功=%s/%s)", ok_count, len(unique_ids)) + return result + + async def set_reaction( + self, group_id: str, message_id: str, emoji: str | int, is_add: bool = True + ) -> bool: + # 当前插件分析流程不依赖飞书 reaction,这里返回 False 以保持兼容。 + return False diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/onebot_adapter.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/onebot_adapter.py new file mode 100644 index 0000000..711bb3c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/onebot_adapter.py @@ -0,0 +1,1586 @@ +""" +OneBot v11 平台适配器 + +支持 NapCat、go-cqhttp、Lagrange 及其他 OneBot 实现。 +""" + +import asyncio +import base64 +import os +import time +from datetime import datetime, timedelta +from pathlib import Path +from typing import Any + +import aiohttp + +from ....domain.value_objects.platform_capabilities import ( + ONEBOT_V11_CAPABILITIES, + PlatformCapabilities, +) +from ....domain.value_objects.unified_group import UnifiedGroup, UnifiedMember +from ....domain.value_objects.unified_message import ( + MessageContent, + MessageContentType, + UnifiedMessage, +) +from ....utils.logger import logger +from ..base import PlatformAdapter +from ..napcat_stream import upload_file_stream + + +class OneBotAdapter(PlatformAdapter): + """ + 具体实现:OneBot v11 平台适配器 + + 支持 NapCat, go-cqhttp, Lagrange 等遵循 OneBot v11 协议的 QQ 机器人框架。 + 实现了消息获取、发送、群组管理及头像解析等全套功能。 + + Attributes: + platform_name (str): 平台硬编码标识 'onebot' + bot_self_ids (list[str]): 机器人自身的 QQ 号列表,用于消息过滤 + """ + + platform_name = "onebot" + + # QQ 头像服务 URL 模板 + USER_AVATAR_TEMPLATE = "https://q1.qlogo.cn/g?b=qq&nk={user_id}&s={size}" + USER_AVATAR_HD_TEMPLATE = ( + "https://q.qlogo.cn/headimg_dl?dst_uin={user_id}&spec={size}&img_type=jpg" + ) + GROUP_AVATAR_TEMPLATE = "https://p.qlogo.cn/gh/{group_id}/{group_id}/{size}/" + + # OneBot 服务支持的头像尺寸像素 + AVAILABLE_SIZES = (40, 100, 140, 160, 640) + + def __init__(self, bot_instance: Any, config: dict | None = None): + """ + 初始化 OneBot 适配器。 + """ + super().__init__(bot_instance, config) + # 支持从多个潜在的配置键中提取机器人 ID + self.bot_self_ids = ( + [str(id) for id in config.get("bot_self_ids", [])] if config else [] + ) + if not self.bot_self_ids and config: + self.bot_self_ids = [str(id) for id in config.get("bot_qq_ids", [])] + self.filter_bot_messages = ( + config.get("filter_bot_messages", True) if config else True + ) + + # LLBot 探测标志 + self._is_llbot = False + self._llbot_checked = False + + # SnowLuma 探测标志 + self._is_snowluma = False + self._snowluma_checked = False + + # 禁言状态缓存 (group_id -> timestamp) + self._muted_groups_cache = {} + # 群角色缓存 (group_id -> (role, timestamp)),用于 get_group_member_info 超时降级 + self._group_role_cache: dict[str, tuple[str, float]] = {} + + def _init_capabilities(self) -> PlatformCapabilities: + """返回预定义的 OneBot v11 能力集。""" + return ONEBOT_V11_CAPABILITIES + + async def _detect_llbot(self): + """探测是否为 LLBot""" + if self._llbot_checked: + return + try: + # 避免在一些不支持 get_version_info 的老版本上卡死 + result = await self.bot.call_action("get_version_info") + if isinstance(result, dict): + app_name = result.get("app_name", "") + self._is_llbot = app_name == "LLOneBot" + if self._is_llbot: + logger.info("[OneBot] 探测到当前协议端为 LLBot") + except Exception: + self._is_llbot = False + self._llbot_checked = True + + async def _detect_snowluma(self): + """探测是否为 SnowLuma""" + if self._snowluma_checked: + return + try: + result = await self.bot.call_action("get_version_info") + if isinstance(result, dict): + app_name = result.get("app_name", "") + self._is_snowluma = app_name.lower() == "snowluma" + if self._is_snowluma: + logger.info("[OneBot] 探测到当前协议端为 SnowLuma") + except Exception as exc: + logger.debug( + "[OneBot] 探测 SnowLuma 失败,将按非 SnowLuma 处理: %s", + exc, + exc_info=True, + ) + self._is_snowluma = False + self._snowluma_checked = True + + def _get_nearest_size(self, requested_size: int) -> int: + """从支持的尺寸列表中找到最接近请求尺寸的一个。""" + return min(self.AVAILABLE_SIZES, key=lambda x: abs(x - requested_size)) + + # ==================== IMessageRepository 实现 ==================== + + async def fetch_messages( + self, + group_id: str, + days: int = 1, + max_count: int = 1000, + before_id: str | None = None, + since_ts: int | None = None, + ) -> list[UnifiedMessage]: + """ + 从 OneBot 后端拉取群组历史消息。 + 采用分页拉取策略(参考 portrayal 插件),减少 NapCat/go-cqhttp 单次请求的 CPU 和内存负担。 + + Args: + group_id (str): 群号 + days (int): 拉取过去几天的消息 + max_count (int): 最大拉取条数 + before_id (str, optional): 锚点消息 ID,用于分页回溯 + since_ts (int, optional): 从指定时间戳开始拉取消息(Unix timestamp),优先级高于 days。 + + Returns: + list[UnifiedMessage]: 统一格式的消息列表 + """ + if not hasattr(self.bot, "call_action"): + return [] + + await self._detect_snowluma() + + try: + chunk_size = 100 # 每次拉取 100 条,较为稳健 + all_raw_messages = [] + seen_raw_ids: set[str] = set() + + # 确定回溯的起始时间点 + if since_ts and since_ts > 0: + start_timestamp = since_ts + else: + end_time_dt = datetime.now() + start_time_dt = end_time_dt - timedelta(days=days) + start_timestamp = int(start_time_dt.timestamp()) + + # 使用 message_seq 或 message_id 进行分页回溯拉取 + current_anchor_id = before_id + + logger.info( + f"OneBot 开始分页回溯消息: 群 {group_id}, " + f"起始时间 {datetime.fromtimestamp(start_timestamp).strftime('%Y-%m-%d %H:%M:%S')}, " + f"上限 {max_count} 条" + ) + + while len(all_raw_messages) < max_count: + fetch_count = min(chunk_size, max_count - len(all_raw_messages)) + + params: dict[str, int | str | bool | None] = { + "group_id": int(group_id), + "count": fetch_count, + } + if self._is_snowluma: + if current_anchor_id: + params["message_id"] = current_anchor_id + else: + params["reverseOrder"] = True + if current_anchor_id: + params["message_seq"] = current_anchor_id + + result = None + fetch_error = None + # 单页请求最多尝试三次,避免 NapCat 偶发 WebSocket 超时导致整次分析失败。 + for attempt in range(1, 4): + try: + result = await self.bot.call_action( + "get_group_msg_history", **params + ) + fetch_error = None + break + except asyncio.CancelledError: + raise + except Exception as exc: + fetch_error = exc + if attempt < 3: + logger.warning( + f"OneBot 分页拉取失败,将进行第 {attempt + 1} 次尝试:" + f"群 {group_id},错误:{exc}" + ) + await asyncio.sleep(attempt) + + if fetch_error is not None: + if all_raw_messages: + logger.warning( + f"OneBot 分页拉取重试耗尽,停止继续回溯并处理已获取的 " + f"{len(all_raw_messages)} 条消息:群 {group_id},错误:{fetch_error}" + ) + else: + logger.warning( + f"OneBot 分页拉取重试耗尽,且尚未获取到消息:" + f"群 {group_id},错误:{fetch_error}" + ) + break + + if not result or "messages" not in result: + logger.debug( + f"OneBot 分页拉取:API 调用返回空或无效数据,停止回溯。群: {group_id}" + ) + break + + messages = result.get("messages", []) + if not messages: + logger.debug( + f"OneBot 分页拉取:获取到 0 条消息,停止回溯。群: {group_id}" + ) + break + + # 确定该批次中最旧的消息作为下一次回溯的起点 + # 不同 OneBot 实现对 reverseOrder 的处理可能导致结果顺序不同(反映在消息时间戳上) + # 我们通过比较首尾消息的时间戳,动态识别出本批次中最旧的消息 + first_msg = messages[0] + last_msg = messages[-1] + if first_msg.get("time", 0) <= last_msg.get("time", 0): + # 正序:首条消息最旧 + chunk_earliest_msg = first_msg + else: + # 逆序:末条消息最旧 + chunk_earliest_msg = last_msg + + chunk_earliest_time = chunk_earliest_msg.get("time", 0) + + for raw_msg in messages: + msg_time = raw_msg.get("time", 0) + msg_id = str(raw_msg.get("message_id", "")) + + # 使用集合去重分页重叠消息,避免消息量较大时反复线性扫描。 + if not msg_id or msg_id in seen_raw_ids: + continue + + # 时间范围判定与集合去重 + if start_timestamp <= msg_time <= int(datetime.now().timestamp()): + all_raw_messages.append(raw_msg) + seen_raw_ids.add(msg_id) + + # 提取锚点。 + # SnowLuma 仅支持 message_id 作为分页锚点。 + # 其他 OneBot 实现优先级: message_seq > real_id > seq > message_id + # 注意:为了兼容 NapCat (NTQQ) 这种 Message ID 非连续的情况, + # 以及 LLBot 这种 Sequence 模式,我们统一不进行 -1 偏移。 + # 分页产生的重叠消息将由上方的去重逻辑 (all_raw_messages 循环对比) 自动处理。 + if self._is_snowluma: + new_anchor_id = chunk_earliest_msg.get("message_id") + else: + seq_val = ( + chunk_earliest_msg.get("message_seq") + or chunk_earliest_msg.get("real_id") + or chunk_earliest_msg.get("seq") + ) + mid_val = chunk_earliest_msg.get("message_id") + new_anchor_id = seq_val if seq_val is not None else mid_val + + # 如果消息时间已到达起始点,或者锚点无法继续往前位移,则停止 + if chunk_earliest_time <= start_timestamp: + logger.debug( + f"OneBot 分页拉取:已到达起始时间 ({start_timestamp}),回溯同步完成。" + ) + break + + if current_anchor_id and str(new_anchor_id) == str(current_anchor_id): + logger.debug( + "OneBot 分页拉取:消息锚点未发生有效位移,可能已到达历史尽头。" + ) + break + + current_anchor_id = new_anchor_id + logger.debug( + f"OneBot 分页拉取进度: 已获取 {len(all_raw_messages)} 条基础/有效消息,下一次锚点: {current_anchor_id}" + ) + + # 稍微延迟,减缓服务端压力 + await asyncio.sleep(0.05) + + # 统一转换为 UnifiedMessage 并在返回前去重排序 + unified_messages = [] + seen_ids = set() + for raw_msg in all_raw_messages: + mid = str(raw_msg.get("message_id", "")) + if not mid or mid in seen_ids: + continue + + unified = self._convert_message(raw_msg, group_id) + if unified: + unified_messages.append(unified) + seen_ids.add(mid) + + # 确保最终结果符合时间顺序 + unified_messages.sort(key=lambda m: m.timestamp) + + logger.info( + f"OneBot 分页拉取完成: 共处理 {len(all_raw_messages)} 条原始消息, 最终有效 {len(unified_messages)} 条" + ) + return unified_messages + + except Exception as e: + logger.warning(f"OneBot 分页获取消息失败: {e}") + return [] + + def _convert_message(self, raw_msg: dict, group_id: str) -> UnifiedMessage | None: + """内部方法:将 OneBot 原生原始消息字典转换为 UnifiedMessage 值对象。""" + try: + sender = raw_msg.get("sender", {}) + message_chain = raw_msg.get("message", []) + + # 兼容性处理:如果是字符串格式的 message,转换为列表格式 + if isinstance(message_chain, str): + message_chain = [{"type": "text", "data": {"text": message_chain}}] + + contents = [] + text_parts = [] + + for seg in message_chain: + seg_type = seg.get("type", "") + seg_data = seg.get("data", {}) + + if seg_type == "text": + text = seg_data.get("text", "") + text_parts.append(text) + contents.append( + MessageContent(type=MessageContentType.TEXT, text=text) + ) + + elif seg_type == "image": + # QQ 平台: subType=1 表示表情包,通过 raw_data 传递给下游统计 + sub_type = seg_data.get("subType", seg_data.get("sub_type")) + # 安全地转换为整数,防止非数字值导致异常 + try: + is_sticker = int(sub_type) == 1 + except (TypeError, ValueError): + is_sticker = False + # 只在 sub_type 有效时包含在 raw_data 中 + raw_data: dict[str, Any] = {"summary": seg_data.get("summary", "")} + if sub_type is not None: + raw_data["sub_type"] = int(sub_type) + contents.append( + MessageContent( + type=MessageContentType.EMOJI + if is_sticker + else MessageContentType.IMAGE, + url=seg_data.get("url", seg_data.get("file", "")), + raw_data=raw_data, + ) + ) + + elif seg_type == "at": + contents.append( + MessageContent( + type=MessageContentType.AT, + at_user_id=str(seg_data.get("qq", "")), + ) + ) + + elif seg_type in ("face", "mface", "bface", "sface"): + contents.append( + MessageContent( + type=MessageContentType.EMOJI, + emoji_id=str(seg_data.get("id", "")), + raw_data={"face_type": seg_type}, + ) + ) + + elif seg_type == "reply": + contents.append( + MessageContent( + type=MessageContentType.REPLY, + raw_data={"reply_id": seg_data.get("id", "")}, + ) + ) + + elif seg_type == "forward": + contents.append( + MessageContent( + type=MessageContentType.FORWARD, raw_data=seg_data + ) + ) + + elif seg_type == "record": + contents.append( + MessageContent( + type=MessageContentType.VOICE, + url=seg_data.get("url", seg_data.get("file", "")), + ) + ) + + elif seg_type == "video": + contents.append( + MessageContent( + type=MessageContentType.VIDEO, + url=seg_data.get("url", seg_data.get("file", "")), + ) + ) + + else: + contents.append( + MessageContent(type=MessageContentType.UNKNOWN, raw_data=seg) + ) + + # 提取回复 ID + reply_to = None + for c in contents: + if c.type == MessageContentType.REPLY and c.raw_data: + reply_to = str(c.raw_data.get("reply_id", "")) + break + + return UnifiedMessage( + message_id=str(raw_msg.get("message_id", "")), + sender_id=str(sender.get("user_id", "")), + sender_name=sender.get("nickname", ""), + sender_card=sender.get("card", "") or None, + group_id=group_id, + text_content="".join(text_parts), + contents=tuple(contents), + timestamp=raw_msg.get("time", 0), + platform="onebot", + reply_to_id=reply_to, + ) + + except Exception as e: + logger.debug(f"OneBot _convert_message 错误: {e}") + return None + + def convert_to_raw_format(self, messages: list[UnifiedMessage]) -> list[dict]: + """ + 将统一格式转换回 OneBot v11 原生字典格式。 + + 使现有业务逻辑逻辑无需重构即可使用新流水。 + + Args: + messages (list[UnifiedMessage]): 统一消息列表 + + Returns: + list[dict]: OneBot 格式的消息字典列表 + """ + raw_messages = [] + for msg in messages: + message_chain = [] + for content in msg.contents: + if content.type == MessageContentType.TEXT: + message_chain.append( + {"type": "text", "data": {"text": content.text or ""}} + ) + elif content.type == MessageContentType.IMAGE: + message_chain.append( + {"type": "image", "data": {"url": content.url or ""}} + ) + elif content.type == MessageContentType.AT: + message_chain.append( + {"type": "at", "data": {"qq": content.at_user_id or ""}} + ) + elif content.type == MessageContentType.EMOJI: + face_type = ( + content.raw_data.get("face_type", "face") + if content.raw_data + else "face" + ) + message_chain.append( + {"type": face_type, "data": {"id": content.emoji_id or ""}} + ) + elif content.type == MessageContentType.REPLY: + reply_id = ( + content.raw_data.get("reply_id", "") if content.raw_data else "" + ) + message_chain.append({"type": "reply", "data": {"id": reply_id}}) + elif content.type == MessageContentType.FORWARD: + message_chain.append( + {"type": "forward", "data": content.raw_data or {}} + ) + elif content.type == MessageContentType.VOICE: + message_chain.append( + {"type": "record", "data": {"url": content.url or ""}} + ) + elif content.type == MessageContentType.VIDEO: + message_chain.append( + {"type": "video", "data": {"url": content.url or ""}} + ) + elif content.type == MessageContentType.UNKNOWN and content.raw_data: + message_chain.append(content.raw_data) + + raw_msg = { + "message_id": msg.message_id, + "time": msg.timestamp, + "sender": { + "user_id": msg.sender_id, + "nickname": msg.sender_name, + "card": msg.sender_card or "", + }, + "message": message_chain, + "group_id": msg.group_id, + "raw_message": msg.text_content, + "user_id": msg.sender_id, + } + raw_messages.append(raw_msg) + + return raw_messages + + # ==================== IMessageSender 实现 ==================== + + async def send_text( + self, + group_id: str, + text: str, + reply_to: str | None = None, + ) -> bool: + """ + 向群组发送文本消息。 + + Args: + group_id (str): 目标群号 + text (str): 消息内容 + reply_to (str, optional): 引用回复的消息 ID + + Returns: + bool: 是否发送成功 + """ + try: + message = [{"type": "text", "data": {"text": text}}] + + if reply_to: + message.insert(0, {"type": "reply", "data": {"id": reply_to}}) + + await self.bot.call_action( + "send_group_msg", + group_id=int(group_id), + message=message, + ) + self._record_mute_status(group_id, False) # 成功发送,清除禁言缓存 + return True + except Exception as e: + if self._is_mute_exception(e): + self._record_mute_status(group_id, True) + logger.error(f"OneBot 文本发送失败: {e}") + return False + + def _is_send_timeout(self, e: Exception) -> bool: + """判断是否为 NapCat/NTQQ 客户端发送超时。 + + 当 NapCat 上传大图到 QQ 服务器耗时超过动作等待时间时, + NT 消息服务实际上已经将消息接收并入队发送。此时若盲目重试会直接导致群内重复发送多张。 + """ + if not e: + return False + err_str = str(e).lower() + if "timeout" in err_str or "timed out" in err_str: + return True + if isinstance(e, (asyncio.TimeoutError, TimeoutError)): + return True + for attr in ("message", "wording"): + val = str(getattr(e, attr, "") or "").lower() + if "timeout" in val or "nodeikernelmsgservice/sendmsg" in val: + return True + return False + + async def _execute_transmission_strategy( + self, + path: str, + worker: Any, + label: str, + format_path_as_url: bool = False, + ) -> bool: + """ + 通用传输策略执行器。 + 处理 Base64 优先(开启时)、物理路径尝试、以及 Base64 兜底。 + 严格限制同一模式最多尝试 1 次,并在捕获 NT 发送超时时避免触发重发刷屏。 + + Args: + path: 文件路径或 URL + worker: 执行具体 API 调用的异步函数,接收 (file_val, mode_label) -> Awaitable[None] + label: 业务标签,用于日志 + format_path_as_url: 是否将本地路径格式化为 file:/// 形式 + """ + try: + use_base64 = self._get_use_base64() + abs_path, is_remote, exists = self._prepare_path(path) + + # 1. 优先尝试 Base64 (如果开启) + if use_base64 and not is_remote: + b64 = await self._get_base64_from_file(abs_path) + if b64: + try: + await worker(b64, "Base64 优先") + return True + except Exception as e: + if self._is_send_timeout(e): + logger.warning( + f"[{label}] Base64 优先发送请求超时(NT 消息服务已接收,为避免重复投递不再重发): {e}" + ) + return True + logger.warning( + f"[{label}] Base64 优先发送失败 ({e}),准备尝试路径模式..." + ) + + # 2. 尝试物理路径/远程 URL + if exists: + try: + file_val = abs_path + if not is_remote and format_path_as_url: + file_val = ( + f"file://{abs_path}" + if abs_path.startswith("/") + else f"file:///{abs_path}" + ) + await worker(file_val, "路径模式") + return True + except Exception as e: + if self._is_send_timeout(e): + logger.warning( + f"[{label}] 路径模式发送请求超时(NT 消息服务已接收,为避免重复投递不再重发): {e}" + ) + return True + if not use_base64 and not is_remote: + logger.warning( + f"[{label}] 路径发送失败 ({e}),准备 Base64 补救..." + ) + else: + logger.error(f"[{label}] 发送失败: {e}") + return False + else: + if not use_base64: + logger.error(f"[{label}] 文件不存在且未开启 Base64: {abs_path}") + return False + + # 3. 兜底回退:仅当第一步未尝试过 Base64 时才执行 + if not use_base64 and not is_remote: + b64 = await self._get_base64_from_file(abs_path) + if b64: + try: + await worker(b64, "Base64 补发") + return True + except Exception as e: + if self._is_send_timeout(e): + logger.warning( + f"[{label}] Base64 补发请求超时(NT 消息服务已接收,为避免重复投递不再重发): {e}" + ) + return True + logger.error(f"[{label}] Base64 补发失败: {e}") + return False + + return False + except Exception as e: + logger.error(f"[{label}] 发送异常: {e}") + return False + + async def send_image( + self, + group_id: str, + image_path: str, + caption: str = "", + ) -> bool: + """向群组发送图片消息。""" + + async def do_send(file_val: str, label: str): + msg = [] + if caption: + msg.append({"type": "text", "data": {"text": caption}}) + msg.append({"type": "image", "data": {"file": file_val}}) + try: + await self.bot.call_action( + "send_group_msg", group_id=int(group_id), message=msg + ) + self._record_mute_status(group_id, False) + except Exception as e: + if self._is_mute_exception(e): + self._record_mute_status(group_id, True) + raise + logger.debug(f"[OneBot] 图片发送成功 ({label}): 群 {group_id}") + + sent = await self._execute_transmission_strategy( + image_path, do_send, "OneBot 图片", format_path_as_url=True + ) + if sent: + return True + + stream_threshold = self._get_napcat_stream_threshold_bytes() + path = Path(image_path) + if ( + stream_threshold <= 0 + or not path.is_file() + or path.stat().st_size < stream_threshold + ): + return False + + logger.warning( + "[OneBot] 常规图片发送失败: %s,准备通过 NapCat Stream API 重试", + path.name, + ) + uploaded_path = await upload_file_stream(self.bot, path) + if not uploaded_path: + return False + try: + await do_send(uploaded_path, "NapCat 流式上传重试") + return True + except Exception as exc: + logger.warning(f"[OneBot] NapCat 流式上传图片重试失败: {exc}") + return False + + async def send_file( + self, + group_id: str, + file_path: str, + filename: str | None = None, + ) -> bool: + """通过群文件功能上传并发送文件。""" + + async def do_upload(content: str, label: str): + try: + await self.bot.call_action( + "upload_group_file", + group_id=int(group_id), + file=content, + name=filename or os.path.basename(file_path), + ) + self._record_mute_status(group_id, False) + except Exception as e: + if self._is_mute_exception(e): + self._record_mute_status(group_id, True) + raise + logger.debug(f"[OneBot] 文件发送成功 ({label}): {filename or file_path}") + + return await self._execute_transmission_strategy( + file_path, do_upload, "OneBot 文件" + ) + + async def send_forward_msg( + self, + group_id: str, + nodes: list[dict], + ) -> bool: + """ + 发送群合并转发消息。 + """ + if not hasattr(self.bot, "call_action"): + return False + + try: + # 兼容处理节点中的 uin -> user_id (有些后端偏好 uin) + for node in nodes: + if "data" in node: + if "user_id" in node["data"] and "uin" not in node["data"]: + node["data"]["uin"] = node["data"]["user_id"] + + await self.bot.call_action( + "send_group_forward_msg", + group_id=int(group_id), + messages=nodes, + ) + self._record_mute_status(group_id, False) + return True + except Exception as e: + if self._is_mute_exception(e): + self._record_mute_status(group_id, True) + logger.warning(f"[OneBot] 发送合并转发消息失败: {e}") + return False + + # ==================== IGroupInfoRepository 实现 ==================== + + async def get_group_info(self, group_id: str) -> UnifiedGroup | None: + """获取指定群组的基础元数据。""" + try: + result = await self.bot.call_action( + "get_group_info", + group_id=int(group_id), + ) + + if not result: + return None + + return UnifiedGroup( + group_id=str(result.get("group_id", group_id)), + group_name=result.get("group_name", ""), + member_count=result.get("member_count", 0), + owner_id=str(result.get("owner_id", "")) or None, + create_time=result.get("group_create_time"), + platform="onebot", + ) + except Exception: + return None + + async def get_group_list(self) -> list[str]: + """获取当前机器人已加入的所有群组 ID 列表。""" + try: + result = await self.bot.call_action("get_group_list") + return [str(g.get("group_id", "")) for g in result or []] + except Exception: + return [] + + async def get_member_list(self, group_id: str) -> list[UnifiedMember]: + """拉取整个群组成员列表。""" + try: + result = await self.bot.call_action( + "get_group_member_list", + group_id=int(group_id), + ) + + members = [] + for m in result or []: + members.append( + UnifiedMember( + user_id=str(m.get("user_id", "")), + nickname=m.get("nickname", ""), + card=m.get("card", "") or None, + role=m.get("role", "member"), + join_time=m.get("join_time"), + ) + ) + return members + except Exception: + return [] + + async def get_member_info( + self, + group_id: str, + user_id: str, + ) -> UnifiedMember | None: + """拉取特定群成员的详细名片及角色信息。""" + try: + result = await self.bot.call_action( + "get_group_member_info", + group_id=int(group_id), + user_id=int(user_id), + ) + + if not result: + return None + + return UnifiedMember( + user_id=str(result.get("user_id", user_id)), + nickname=result.get("nickname", ""), + card=result.get("card", "") or None, + role=result.get("role", "member"), + join_time=result.get("join_time"), + ) + except Exception: + return None + + async def _get_base64_from_file(self, file_path: str) -> str | None: + """ + 读取本地文件并返回 Base64 编码字符串。 + + Args: + file_path: 本地文件绝对路径 + + Returns: + str | None: base64://... 格式的字符串,读取失败返回 None + """ + try: + import os + + if not os.path.exists(file_path): + logger.error(f"文件不存在,无法读取 Base64: {file_path}") + return None + + with open(file_path, "rb") as f: + data = f.read() + b64 = base64.b64encode(data).decode("utf-8") + return f"base64://{b64}" + except Exception as e: + logger.error(f"读取文件并转换 Base64 失败: {e}") + return None + + # ==================== IAvatarRepository 实现 ==================== + + async def get_user_avatar_url( + self, + user_id: str, + size: int = 100, + ) -> str | None: + """ + 拼凑 QQ 官方服务地址获取用户头像。 + + Args: + user_id (str): QQ 号 + size (int): 期望像素大小 + + Returns: + str: 格式化后的 URL + """ + actual_size = self._get_nearest_size(size) + # 640 使用 HD 接口更清晰 + if actual_size >= 640: + return self.USER_AVATAR_HD_TEMPLATE.format(user_id=user_id, size=640) + return self.USER_AVATAR_TEMPLATE.format(user_id=user_id, size=actual_size) + + async def get_user_avatar_data( + self, + user_id: str, + size: int = 100, + ) -> str | None: + """ + 通过网络下载头像并转换为 Base64 格式,适用于前端模板直接渲染。 + """ + url = await self.get_user_avatar_url(user_id, size) + if not url: + return None + + try: + async with aiohttp.ClientSession() as session: + async with session.get( + url, timeout=aiohttp.ClientTimeout(total=5) + ) as resp: + if resp.status == 200: + data = await resp.read() + b64 = base64.b64encode(data).decode("utf-8") + content_type = resp.headers.get("Content-Type", "image/png") + return f"data:{content_type};base64,{b64}" + except Exception as e: + logger.debug(f"OneBot 头像下载失败: {e}") + return None + + async def get_group_avatar_url( + self, + group_id: str, + size: int = 100, + ) -> str | None: + """获取 QQ 群头像地址。""" + actual_size = self._get_nearest_size(size) + return self.GROUP_AVATAR_TEMPLATE.format(group_id=group_id, size=actual_size) + + async def batch_get_avatar_urls( + self, + user_ids: list[str], + size: int = 100, + ) -> dict[str, str | None]: + """批量映射 QQ 号到其头像 URL 地址。""" + return { + user_id: await self.get_user_avatar_url(user_id, size) + for user_id in user_ids + } + + async def is_group_muted(self, group_id: str) -> bool: + """ + 检查 OneBot 平台下的群聊是否被禁言(包括全体禁言或对 Bot 自身禁言)。 + """ + group_id_str = str(group_id) + + # 1. 检查最近缓存的禁言状态(5分钟内有效) + last_mute_time = self._muted_groups_cache.get(group_id_str) + if last_mute_time and (time.time() - last_mute_time) < 300: + logger.info( + f"[OneBot] 从缓存中检测到群 {group_id_str} 最近处于禁言状态,跳过分析" + ) + return True + + if not hasattr(self.bot, "call_action"): + return False + + # 2. 获取 Bot 自身的 QQ 号,并过滤掉非法的字符串(如 functools.partial 或含字母/特殊字符的异常值) + bot_user_id = None + if self.bot_self_ids: + valid_ids = [ + str(uid) + for uid in self.bot_self_ids + if uid + and isinstance(uid, (str, int)) + and not callable(uid) + and "partial" not in str(uid) + and str(uid).isdigit() + ] + if valid_ids: + bot_user_id = valid_ids[0] + + if not bot_user_id: + try: + # 设定 5.0 秒超时,防止接口请求无限挂起 + login_info = await asyncio.wait_for( + self.bot.call_action("get_login_info"), timeout=5.0 + ) + if login_info and "user_id" in login_info: + bot_user_id = str(login_info["user_id"]) + self.bot_self_ids = [bot_user_id] + except Exception as e: + if self._is_mute_exception(e): + self._record_mute_status(group_id, True) + logger.info( + f"[OneBot] 从 get_login_info 异常中检测到 Bot 在群 {group_id} 中已被禁言" + ) + return True + logger.warning(f"[OneBot] 获取 Bot 自身登录信息失败: {e}") + + # 3. 检查 Bot 是否被个人禁言,并获取 Bot 在群内的角色 + is_individually_muted = False + role = "member" # 默认为 member 以防万一 + if bot_user_id: + try: + # 设定 5.0 秒超时,且不传递 no_cache=True 以免强制向腾讯服务器同步导致高延时超时 + member_info = await asyncio.wait_for( + self.bot.call_action( + "get_group_member_info", + group_id=int(group_id), + user_id=int(bot_user_id), + ), + timeout=5.0, + ) + if member_info: + role = member_info.get("role", "member") + # 缓存角色信息,用于 get_group_member_info 超时时降级使用 + self._group_role_cache[group_id_str] = (role, time.time()) + shut_up_time = member_info.get("shut_up_time", 0) + if shut_up_time > 0: + # 如果 shut_up_time 是 Unix 时间戳 + if shut_up_time > 1000000000: + if shut_up_time > time.time(): + is_individually_muted = True + else: + # 否则认为是相对禁言剩余时间(秒) + is_individually_muted = True + except asyncio.TimeoutError: + # 超时降级:优先使用缓存的角色(角色几乎不会变) + cached_role = self._group_role_cache.get(group_id_str) + if cached_role: + role = cached_role[0] + logger.warning( + f"[OneBot] 获取群成员信息超时,使用缓存角色: {role} (group_id={group_id}, user_id={bot_user_id})" + ) + else: + logger.warning( + f"[OneBot] 获取群成员信息超时且无角色缓存,将按 member 处理 (group_id={group_id}, user_id={bot_user_id})" + ) + except Exception as e: + if self._is_mute_exception(e): + self._record_mute_status(group_id, True) + logger.info( + f"[OneBot] 从 get_group_member_info 异常中检测到 Bot 在群 {group_id} 中已被禁言" + ) + return True + logger.warning( + f"[OneBot] 获取群成员信息失败 (group_id={group_id}, user_id={bot_user_id}): {e}" + ) + + if is_individually_muted: + self._record_mute_status(group_id, True) + logger.info(f"[OneBot] 检测到 Bot 在群 {group_id} 中已被单独禁言") + return True + + # 4. 如果 Bot 不是管理员或群主,则需要检查群聊是否开启了全群禁言 + # 管理员 (admin) 和群主 (owner) 在全群禁言下依然可以发言 + if role not in ("admin", "owner"): + try: + # 设定 5.0 秒超时,不传 no_cache=True + group_info = await asyncio.wait_for( + self.bot.call_action( + "get_group_info", + group_id=int(group_id), + ), + timeout=5.0, + ) + if group_info: + # 兼容 LLOneBot, Lagrange, NapCat/SnowLuma 以及标准 OneBot 各种全群禁言状态字段 + is_whole_ban = ( + group_info.get("group_all_shut") + or group_info.get("shutup_all") + or group_info.get("is_whole_ban") + or group_info.get("whole_ban") + or group_info.get("shutup") + or group_info.get("shut_up") + ) + if is_whole_ban: + self._record_mute_status(group_id, True) + logger.info( + f"[OneBot] 检测到群 {group_id} 开启了全群禁言,且 Bot 为普通成员" + ) + return True + except asyncio.TimeoutError: + logger.warning(f"[OneBot] 获取群信息超时 (group_id={group_id})") + except Exception as e: + if self._is_mute_exception(e): + self._record_mute_status(group_id, True) + logger.info( + f"[OneBot] 从 get_group_info 异常中检测到 Bot 在群 {group_id} 中已被禁言" + ) + return True + logger.warning(f"[OneBot] 获取群信息失败 (group_id={group_id}): {e}") + + # 如果所有检测均未发现禁言,则暂时视为未禁言 + return False + + def _is_mute_exception(self, e: Exception) -> bool: + if not e: + return False + err_str = str(e) + + mute_keywords = ("禁言", "操作失败", "下游群鉴权") + + # --- 方法一:根据 retcode 检测 --- + # NapCat/LLOneBot 被禁言时返回 retcode=1200(INTERNAL_ERROR) + # SnowLuma/OIDB 操作被拒时返回 retcode=100(ACTION_FAILED)+ wording 含错误描述 + # SnowLuma 发送消息被拒时返回 result=120 + if any(rc in err_str for rc in ("1200", "retcode=100", "result=120")): + if any(kw in err_str for kw in mute_keywords): + return True + + # --- 方法二:检查 exception 的 message/wording 属性 --- + # 适配不同协议端对错误信息的字段命名差异 + for attr in ("message", "wording"): + val = getattr(e, attr, "") or "" + if any(kw in val for kw in mute_keywords): + return True + if "shut up" in val.lower(): + return True + + # --- 方法三:检测 SnowLuma 发消息被拒的特定模式 --- + # SnowLuma 在群内发消息失败时返回: + # retcode=100, wording="send group message rejected: result=120 err=" + err_lower = err_str.lower() + if "rejected" in err_lower and ( + "result=120" in err_lower or "muted" in err_lower + ): + return True + + # --- 方法四:兜底 --- 直接从 err_str 匹配禁言关键词 --- + # 即使 getattr 获取不到 wording 属性,str(e) 本身仍包含关键词文本 + if any(kw in err_str for kw in mute_keywords): + return True + + return False + + def _record_mute_status(self, group_id: Any, is_muted: bool): + group_id_str = str(group_id) + if is_muted: + # Prune expired cache entries if cache size grows too large (threshold of 1000) + if len(self._muted_groups_cache) >= 1000: + now = time.time() + expired_keys = [ + k for k, t in self._muted_groups_cache.items() if now - t >= 300 + ] + for k in expired_keys: + self._muted_groups_cache.pop(k, None) + + # If still over threshold, evict the oldest entry to prevent unbounded growth + if len(self._muted_groups_cache) >= 1000: + oldest_key = min( + self._muted_groups_cache, + key=lambda k: self._muted_groups_cache[k], + ) + self._muted_groups_cache.pop(oldest_key, None) + + self._muted_groups_cache[group_id_str] = time.time() + else: + self._muted_groups_cache.pop(group_id_str, None) + + # ================================================================ + # 群文件 / 群相册上传 + # ================================================================ + + async def upload_group_file_to_folder( + self, + group_id: str, + file_path: str, + filename: str | None = None, + folder_id: str | None = None, + ) -> bool: + """上传文件到群文件目录的指定子文件夹。""" + + async def do_upload(content: str, label: str): + params = { + "group_id": int(group_id), + "file": content, + "name": filename or os.path.basename(file_path), + } + if folder_id: + params["folder"] = folder_id + await self.bot.call_action("upload_group_file", **params) + logger.debug(f"[OneBot] 群文件发送成功 ({label}): {params['name']}") + + return await self._execute_transmission_strategy( + file_path, do_upload, "OneBot 群文件" + ) + + async def create_group_file_folder( + self, + group_id: str, + folder_name: str, + ) -> str | None: + """ + 在群文件根目录下创建子文件夹。 + + Args: + group_id: 目标群号 + folder_name: 文件夹名称 + + Returns: + str | None: 创建成功时返回 folder_id,失败返回 None + """ + try: + result = await self.bot.call_action( + "create_group_file_folder", + group_id=int(group_id), + name=folder_name, + parent_id="/", + ) + # go-cqhttp 等实现可能不返回 folder_id + folder_id = None + if isinstance(result, dict): + folder_id = result.get("folder_id") or result.get("id") + logger.info( + f"OneBot 群文件夹创建成功: {folder_name} (群 {group_id})" + + (f" [ID: {folder_id}]" if folder_id else "") + ) + return folder_id + except Exception as e: + error_msg = str(e).lower() + # 文件夹已存在的情况不视为错误 + if "exist" in error_msg or "已存在" in error_msg: + logger.info(f"OneBot 群文件夹已存在: {folder_name} (群 {group_id})") + return None # 需要通过 get_group_file_root_folders 获取 ID + logger.error(f"OneBot 群文件夹创建失败: {e}") + return None + + async def get_group_file_root_folders( + self, + group_id: str, + ) -> list[dict]: + """ + 获取群文件根目录下的文件夹列表。 + + Args: + group_id: 目标群号 + + Returns: + list[dict]: 文件夹列表,每项包含 folder_id/name 等字段。 + API 不可用时返回空列表。 + """ + try: + result = await self.bot.call_action( + "get_group_root_files", + group_id=int(group_id), + ) + if isinstance(result, dict): + return result.get("folders", []) or [] + return [] + except Exception as e: + logger.debug(f"OneBot 获取群文件夹列表失败: {e}") + return [] + + async def find_or_create_folder( + self, + group_id: str, + folder_name: str, + ) -> str | None: + """ + 查找或创建指定名称的群文件子文件夹,返回 folder_id。 + + 先尝试在现有根目录文件夹中查找匹配名称的文件夹, + 找不到则创建新文件夹。 + + Args: + group_id: 目标群号 + folder_name: 文件夹名称 + + """ + if not folder_name: + return None + + # 1. 先尝试查找已有文件夹 + folders = await self.get_group_file_root_folders(group_id) + for folder in folders: + name = folder.get("folder_name") or folder.get("name", "") + fid = folder.get("folder_id") or folder.get("id", "") + if name == folder_name and fid: + logger.debug(f"找到已有群文件夹: {folder_name} [ID: {fid}]") + return fid + + # 2. 未找到,尝试创建 + created_id = await self.create_group_file_folder(group_id, folder_name) + if created_id: + return created_id + + # 3. 创建后再次查找(某些实现创建时不返回 ID) + folders = await self.get_group_file_root_folders(group_id) + for folder in folders: + name = folder.get("folder_name") or folder.get("name", "") + fid = folder.get("folder_id") or folder.get("id", "") + if name == folder_name and fid: + logger.debug(f"创建后找到群文件夹: {folder_name} [ID: {fid}]") + return fid + + logger.warning( + f"无法获取群文件夹 ID: {folder_name} (群 {group_id}),将上传到根目录" + ) + return None + + async def upload_group_album( + self, + group_id: str, + image_path: str, + album_id: str | None = None, + album_name: str | None = None, + strict_mode: bool = False, + ) -> bool: + """上传图片到群相册(NapCat 扩展 API)。""" + # 严格模式:指定了相册名但未解析到 album_id 时,禁止上传 + if strict_mode and album_name and not album_id: + logger.info( + f"[群分析相册] 严格模式开启:未找到相册 '{album_name}' (群 {group_id}),停止上传。" + ) + return False + + # 兜底查询 + if not album_id: + albums = await self.get_group_album_list(group_id) + album_id = self._find_item_in_list( + albums, album_name, ["album_id"], ["name", "album_name"] + ) + # 如果仍没确定相册: + # - 没有指定相册名(纯兜底)→ 取第一个 + # - 指定了名字但找不到且非严格模式 → 也取第一个(回退到默认相册) + if not album_id and albums and (not album_name or not strict_mode): + album_id = albums[0].get("album_id") or albums[0].get("id") + if album_name: + logger.info( + f"[群分析相册] 未找到相册 '{album_name}',回退到默认相册 (群 {group_id})" + ) + + if not album_id: + logger.info( + f"[群分析相册] 未能确定目标相册 (群 {group_id}),跳过相册上传。" + ) + return False + + async def do_upload(content: str, label: str): + await self._detect_llbot() + + if self._is_llbot: + # LLBot 模式:使用 files 参数 (列表) + # LLBot 的 upload_group_album 接收 files 作为数组 + llbot_params = { + "group_id": int(group_id), + "album_id": str(album_id), + "files": [content], + } + try: + await self.bot.call_action("upload_group_album", **llbot_params) + logger.debug( + f"[群分析相册] 上传成功 (LLBot, {label}): 群 {group_id}" + ) + return + except Exception as e: + logger.warning( + f"[群分析相册] LLBot 上传接口调用失败: {e},尝试 NapCat 模式..." + ) + + params = { + "group_id": int(group_id), + "file": content, + "album_id": str(album_id), + } + if album_name: + params["album_name"] = album_name + + for action in [ + "upload_image_to_qun_album", + "upload_group_album", + "upload_qun_album", + ]: + try: + await self.bot.call_action(action, **params) + logger.debug( + f"[群分析相册] 上传成功 ({label}, {action}): 群 {group_id}" + ) + return + except Exception: + continue + raise RuntimeError("所有相册上传 API 均调用失败") + + return await self._execute_transmission_strategy( + image_path, do_upload, "OneBot 相册" + ) + + async def get_group_album_list( + self, + group_id: str, + ) -> list[dict]: + """ + 获取群分析相册列表(兼容多种 OneBot 扩展实现)。 + """ + + def extract_list(payload: Any) -> list[dict]: + """从不同结构的响应中提取相册列表:直接列表、嵌套在 data 中、或直接在根字段中。""" + if isinstance(payload, list): + return [item for item in payload if isinstance(item, dict)] + if not isinstance(payload, dict): + logger.debug( + f"[群分析相册] 提取相册列表失败: payload 非字典/列表类型 ({type(payload)})" + ) + return [] + + data = payload.get("data") + if isinstance(data, dict): + album_list = data.get("album_list") or data.get("list") + if isinstance(album_list, list): + return [item for item in album_list if isinstance(item, dict)] + else: + logger.debug(f"[群分析相册] 在 data 字段中未找到列表: data={data}") + + album_list = payload.get("album_list") or payload.get("list") + if isinstance(album_list, list): + return [item for item in album_list if isinstance(item, dict)] + + logger.debug(f"[群分析相册] 无法从响应中提取相册列表: payload={payload}") + return [] + + # 候选 API 名称 + actions = [ + "get_qun_album_list", + "get_group_album_list", + "get_group_albums", + "get_group_root_album_list", + ] + + for action in actions: + try: + logger.debug( + f"[群分析相册] 正在通过 {action} 获取列表 (群: {group_id})..." + ) + result = await self.bot.call_action( + action, + group_id=int(group_id), + ) + logger.debug(f"[群分析相册] 接口 {action} 原始响应内容: {result}") + if result: + albums = extract_list(result) + if albums: + logger.debug( + f"[群分析相册] {action} 成功获取并提取到 {len(albums)} 个相册对象" + ) + return albums + except Exception as e: + logger.debug(f"[群分析相册] 接口 {action} 尝试失败: {e}") + + return [] + + async def find_album_id( + self, + group_id: str, + album_name: str, + ) -> str | None: + """ + 根据相册名称查找 album_id。找不到返回 None(将回退到默认相册)。 + + Args: + group_id: 目标群号 + album_name: 目标相册名称 + + Returns: + str | None: 匹配的 album_id,未找到返回 None + """ + if not album_name: + return None + + logger.debug( + f"[群分析相册] 正在群 {group_id} 中查找名为 '{album_name}' 的相册..." + ) + albums = await self.get_group_album_list(group_id) + for album in albums: + name = album.get("name") or album.get("album_name") + logger.debug( + f"[群分析相册] 正在匹配相册: 目标='{album_name}', 当前相册名称='{name}', 原始数据={album}" + ) + if name == album_name: + aid = album.get("album_id") + if aid: + logger.info( + f"[群分析相册] 成功定位相册: '{album_name}' -> ID: {aid}" + ) + return str(aid) + else: + logger.debug( + f"[群分析相册] 相册 '{name}' 名称匹配,但未找到有效的 album_id" + ) + + logger.info(f"[群分析相册] 未能找到名为 '{album_name}' 的相册 (群 {group_id})") + return None + + async def set_reaction( + self, group_id: str, message_id: str, emoji: str | int, is_add: bool = True + ) -> bool: + """ + OneBot 实现消息回应 (set_msg_emoji_like)。 + 支持 Go-CQHTTP, NapCat, Lagrange 等 OneBot 实现。 + """ + try: + reaction_key = str(emoji) + emoji_id = { + "analysis_started": "289", # 🫣 表情 (表示任务已接收) + "analysis_done": "124", # 👌 表情 (表示任务处理完成) + "🔍": "289", + "📊": "124", + }.get(reaction_key, reaction_key) + + await self.bot.call_action( + "set_msg_emoji_like", + message_id=int(message_id), + emoji_id=emoji_id, + emoji_type="1", # 还原为最稳定的系统表情类型 + set=is_add, + ) + self._record_mute_status(group_id, False) + return True + except Exception as e: + if self._is_mute_exception(e): + self._record_mute_status(group_id, True) + logger.debug(f"OneBot set_reaction 失败 (API 可能不支持): {e}") + return False + + def _get_use_base64(self) -> bool: + """从插件配置中获取是否启用 Base64""" + plugin: Any = self.config.get("plugin_instance") if self.config else None + if plugin and hasattr(plugin, "config_manager"): + return plugin.config_manager.get_enable_base64_image() + return False + + def _get_napcat_stream_threshold_bytes(self) -> int: + """获取配置的 NapCat 流式上传兜底阈值(字节)。""" + plugin: Any = self.config.get("plugin_instance") if self.config else None + if not plugin or not hasattr(plugin, "config_manager"): + return 0 + try: + threshold_mb = plugin.config_manager.get_napcat_stream_threshold_mb() + return max(0, int(float(threshold_mb) * 1024 * 1024)) + except (TypeError, ValueError): + return 0 + + def _prepare_path(self, path: str) -> tuple[str, bool, bool]: + """统一路径预处理。返回: (标准化后的绝对路径, 是否为远程/编码路径, 本地文件是否存在)""" + is_remote = path.startswith(("http://", "https://", "base64://")) + if is_remote: + return path, True, True + + abs_path = os.path.abspath(path) + exists = os.path.exists(abs_path) + return abs_path, False, exists + + def _find_item_in_list( + self, + items: list[dict], + target_name: str | None, + id_keys: list[str], + name_keys: list[str], + ) -> str | None: + """从对象列表中根据名称查找 ID (通用辅助函数)""" + if not target_name: + return None + + for item in items: + name = "" + for nk in name_keys: + if item.get(nk): + name = item[nk] + break + + if name == target_name: + for ik in id_keys: + if item.get(ik): + return str(item[ik]) + return None diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/qq_official_adapter.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/qq_official_adapter.py new file mode 100644 index 0000000..7e88ac3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/qq_official_adapter.py @@ -0,0 +1,582 @@ +"""QQ Official Bot adapter backed by AstrBot's local message history.""" + +from __future__ import annotations + +import asyncio +import base64 +import hashlib +import os +import random +import re +from datetime import datetime, timedelta, timezone +from typing import TYPE_CHECKING, Any +from urllib.parse import quote + +import aiohttp + +from ....domain.value_objects.platform_capabilities import ( + QQ_OFFICIAL_CAPABILITIES, + PlatformCapabilities, +) +from ....domain.value_objects.unified_group import UnifiedGroup, UnifiedMember +from ....domain.value_objects.unified_message import ( + MessageContent, + MessageContentType, + UnifiedMessage, +) +from ....utils.logger import logger +from ..base import PlatformAdapter + +if TYPE_CHECKING: + from astrbot.api.star import Context + + +class QQOfficialAdapter(PlatformAdapter): + """Adapter for QQ Official group bots (WebSocket and Webhook variants).""" + + platform_name = "qq_official" + AVATAR_TEMPLATE = "https://thirdqq.qlogo.cn/qqapp/{appid}/{member_openid}/640" + HISTORY_PAGE_SIZE = 500 + MARKDOWN_CHUNK_SIZE = 3900 + + def __init__(self, bot_instance: Any, config: dict | None = None): + super().__init__(bot_instance, config) + self._context: Context | None = None + self._plugin_instance = config.get("plugin_instance") if config else None + self._platform_id = str(config.get("platform_id", "")).strip() if config else "" + ids = config.get("bot_self_ids", []) if config else [] + self.bot_self_ids = [str(item) for item in ids if item] + self.appid = self._resolve_appid(config or {}) + self._markdown_msg_seq = random.randint(1, 10000) + self._member_profiles: dict[str, dict[str, str]] = {} + + @property + def platform_id(self) -> str: + return self._platform_id or "qq_official" + + def _resolve_appid(self, config: dict) -> str: + direct = str(config.get("appid", "") or "").strip() + if direct: + return direct + platform = getattr(self.bot, "platform", None) + platform_config = getattr(platform, "config", None) + if isinstance(platform_config, dict): + return str(platform_config.get("appid", "") or "").strip() + return "" + + @staticmethod + def _is_placeholder_sender_name(name: str | None, sender_id: str) -> bool: + normalized = str(name or "").strip() + if not normalized: + return True + if normalized.lower() in {"unknown", "none", "null", "nil", "undefined"}: + return True + return normalized == str(sender_id).strip() + + @classmethod + def _resolve_history_sender_name( + cls, sender_name: str | None, sender_id: str, group_id: str + ) -> str: + normalized = str(sender_name or "").strip() + if not cls._is_placeholder_sender_name(normalized, sender_id): + return normalized + digest = hashlib.sha256(f"{group_id}\0{sender_id}".encode()).hexdigest()[:8] + return f"群友-{digest.upper()}" + + def set_context(self, context: Context) -> None: + self._context = context + + def remember_user_profile( + self, user_id: str, nickname: str = "", avatar_url: str = "" + ) -> None: + """缓存 QQ 官方消息事件提供的用户资料。 + + Args: + user_id: QQ 成员 OpenID。 + nickname: 事件提供的显示名称。 + avatar_url: 事件提供的头像地址。 + """ + normalized_user_id = str(user_id or "").strip() + if not normalized_user_id: + return + + profile = self._member_profiles.setdefault(normalized_user_id, {}) + normalized_nickname = str(nickname or "").strip() + if not self._is_placeholder_sender_name( + normalized_nickname, normalized_user_id + ): + profile["nickname"] = normalized_nickname + + normalized_avatar_url = str(avatar_url or "").strip() + if normalized_avatar_url.startswith(("https://", "http://")): + profile["avatar_url"] = normalized_avatar_url + + def _init_capabilities(self) -> PlatformCapabilities: + return QQ_OFFICIAL_CAPABILITIES + + async def fetch_messages( + self, + group_id: str, + days: int = 1, + max_count: int = 1000, + before_id: str | None = None, + since_ts: int | None = None, + ) -> list[UnifiedMessage]: + if not self._context: + logger.warning("[QQOfficial] 未设置 context,无法读取本地消息历史") + return [] + + history_mgr = self._context.message_history_manager + target_count = max(1, int(max_count)) + cutoff_ts = ( + int(since_ts) + if since_ts and since_ts > 0 + else int((datetime.now(timezone.utc) - timedelta(days=days)).timestamp()) + ) + before_record_id: int | None = None + if before_id: + try: + before_record_id = int(before_id) + except (TypeError, ValueError): + pass + + messages: list[UnifiedMessage] = [] + seen_message_ids: set[str] = set() + page = 1 + + try: + while len(messages) < target_count: + records = await history_mgr.get( + platform_id=self.platform_id, + user_id=str(group_id), + page=page, + page_size=self.HISTORY_PAGE_SIZE, + ) + if not records: + break + + reached_cutoff = False + for record in records: + record_id = getattr(record, "id", None) + if ( + before_record_id is not None + and record_id is not None + and int(record_id) >= before_record_id + ): + continue + + unified = self._convert_history_record(record, str(group_id)) + if not unified: + continue + if unified.timestamp < cutoff_ts: + reached_cutoff = True + continue + if unified.sender_id in self.bot_self_ids: + continue + if unified.message_id in seen_message_ids: + continue + + seen_message_ids.add(unified.message_id) + messages.append(unified) + + if len(messages) >= target_count: + break + if reached_cutoff or len(records) < self.HISTORY_PAGE_SIZE: + break + page += 1 + + messages.sort(key=lambda item: (item.timestamp, item.message_id)) + if len(messages) > target_count: + messages = messages[-target_count:] + logger.info( + "[QQOfficial] 从本地历史获取群 %s 消息 %s 条", + group_id, + len(messages), + ) + return messages + except Exception as exc: + logger.error("[QQOfficial] 读取本地消息历史失败: %s", exc, exc_info=True) + return [] + + def _convert_history_record( + self, record: Any, group_id: str + ) -> UnifiedMessage | None: + try: + content = getattr(record, "content", None) + if not isinstance(content, dict): + return None + metadata = content.get("_qq_official") + if not isinstance(metadata, dict): + return None + + contents: list[MessageContent] = [] + text_parts: list[str] = [] + for part in content.get("message", []): + if not isinstance(part, dict): + continue + part_type = str(part.get("type", "")).lower() + if part_type in {"plain", "text"}: + text = str(part.get("text", "") or "") + text_parts.append(text) + contents.append( + MessageContent(type=MessageContentType.TEXT, text=text) + ) + elif part_type == "image": + contents.append( + MessageContent( + type=MessageContentType.IMAGE, + url=str(part.get("url", "") or ""), + ) + ) + elif part_type == "at": + contents.append( + MessageContent( + type=MessageContentType.AT, + at_user_id=str(part.get("target_id", "") or ""), + ) + ) + elif part_type == "file": + contents.append( + MessageContent( + type=MessageContentType.FILE, + url=str(part.get("url", "") or ""), + raw_data={"name": part.get("name", "")}, + ) + ) + elif part_type in {"record", "voice"}: + contents.append( + MessageContent( + type=MessageContentType.VOICE, + url=str(part.get("url", "") or ""), + ) + ) + elif part_type == "video": + contents.append( + MessageContent( + type=MessageContentType.VIDEO, + url=str(part.get("url", "") or ""), + ) + ) + + message_id = str(metadata.get("message_id", "") or "") + if not message_id: + message_id = f"local:{getattr(record, 'id', '')}" + timestamp = int(metadata.get("timestamp", 0) or 0) + if timestamp <= 0: + created_at = getattr(record, "created_at", None) + timestamp = int(created_at.timestamp()) if created_at else 0 + sender_id = str(getattr(record, "sender_id", "") or "") + if not sender_id: + return None + sender_name = self._resolve_history_sender_name( + getattr(record, "sender_name", None), sender_id, group_id + ) + + return UnifiedMessage( + message_id=message_id, + sender_id=sender_id, + sender_name=sender_name, + sender_card=None, + group_id=group_id, + text_content="".join(text_parts), + contents=tuple(contents), + timestamp=timestamp, + platform=self.platform_name, + ) + except Exception as exc: + logger.debug("[QQOfficial] 转换本地历史记录失败: %s", exc) + return None + + def convert_to_raw_format(self, messages: list[UnifiedMessage]) -> list[dict]: + result: list[dict] = [] + for message in messages: + chain: list[dict] = [] + for content in message.contents: + if content.type == MessageContentType.TEXT: + chain.append({"type": "text", "data": {"text": content.text}}) + elif content.type == MessageContentType.IMAGE: + chain.append({"type": "image", "data": {"url": content.url}}) + elif content.type == MessageContentType.AT: + chain.append({"type": "at", "data": {"qq": content.at_user_id}}) + result.append( + { + "message_id": message.message_id, + "time": message.timestamp, + "group_id": message.group_id, + "sender": { + "user_id": message.sender_id, + "nickname": message.sender_name or message.sender_id, + "card": "", + }, + "message": chain, + "user_id": message.sender_id, + } + ) + return result + + async def _send_chain(self, group_id: str, chain: Any) -> bool: + if not self._context: + logger.error("[QQOfficial] 未设置 context,无法发送消息") + return False + try: + # AstrBot's QQ Official adapter keeps the group/channel scene only + # in memory. Restore it before proactive sends so scheduled reports + # continue to work after a process restart, before the next event. + platform = getattr(self.bot, "platform", None) + remember_scene = getattr(platform, "remember_session_scene", None) + if callable(remember_scene): + remember_scene(str(group_id), "group") + umo = f"{self.platform_id}:GroupMessage:{group_id}" + return bool(await self._context.send_message(umo, chain)) + except Exception as exc: + logger.error("[QQOfficial] 发送消息失败: %s", exc, exc_info=True) + return False + + async def send_text( + self, group_id: str, text: str, reply_to: str | None = None + ) -> bool: + from astrbot.api.event import MessageChain + + return await self._send_chain(group_id, MessageChain().message(str(text))) + + async def send_text_report( + self, + group_id: str, + content: str, + fallback_content: str | None = None, + ) -> bool: + """Send long reports as QQ custom Markdown with plain-text fallback.""" + chunks = self._split_markdown_report(str(content)) + if not chunks: + return True + + markdown_enabled = True + sent_markdown_chunks = 0 + for chunk in chunks: + if markdown_enabled: + try: + if await self._send_markdown_chunk(group_id, chunk): + sent_markdown_chunks += 1 + continue + logger.warning( + "[QQOfficial] Markdown 接口未返回成功结果,后续改用普通文本" + ) + except Exception as exc: + logger.warning( + "[QQOfficial] Markdown 报告发送失败,后续改用普通文本: %s", + exc, + ) + markdown_enabled = False + + if fallback_content and sent_markdown_chunks == 0: + for fallback_chunk in self._split_markdown_report( + str(fallback_content) + ): + if not await self.send_text(group_id, fallback_chunk): + return False + return True + + if not await self.send_text(group_id, chunk): + return False + return True + + async def _send_markdown_chunk(self, group_id: str, content: str) -> bool: + api = getattr(self.bot, "api", None) + post_group_message = getattr(api, "post_group_message", None) + if not callable(post_group_message): + return False + + platform = getattr(self.bot, "platform", None) + remember_scene = getattr(platform, "remember_session_scene", None) + if callable(remember_scene): + remember_scene(str(group_id), "group") + + try: + from botpy.types.message import MarkdownPayload + + markdown: Any = MarkdownPayload(content=content) + except ImportError: + # Allows lightweight test environments while botpy is provided by + # AstrBot in production. + markdown = {"content": content} + + result = await post_group_message( # type: ignore[arg-type] + group_openid=str(group_id), + msg_type=2, + markdown=markdown, + msg_seq=self._next_markdown_msg_seq(), + ) + return result is not None + + def _next_markdown_msg_seq(self) -> int: + self._markdown_msg_seq = (self._markdown_msg_seq % 10000) + 1 + return self._markdown_msg_seq + + def _split_markdown_report(self, content: str) -> list[str]: + """Split Markdown on block boundaries without breaking mention tokens.""" + normalized = str(content or "").strip() + if not normalized: + return [] + + blocks = re.split(r"\n{2,}", normalized) + chunks: list[str] = [] + current = "" + + def append_piece(piece: str) -> None: + nonlocal current + candidate = f"{current}\n\n{piece}" if current else piece + if len(candidate) <= self.MARKDOWN_CHUNK_SIZE: + current = candidate + return + if current: + chunks.append(current) + current = piece + + for block in blocks: + block = block.strip() + if not block: + continue + if len(block) <= self.MARKDOWN_CHUNK_SIZE: + append_piece(block) + continue + + lines = block.splitlines() or [block] + piece = "" + for line in lines: + candidate = f"{piece}\n{line}" if piece else line + if len(candidate) <= self.MARKDOWN_CHUNK_SIZE: + piece = candidate + continue + if piece: + append_piece(piece) + while len(line) > self.MARKDOWN_CHUNK_SIZE: + split_at = self.MARKDOWN_CHUNK_SIZE + mention_start = line.rfind("<@", 0, split_at) + mention_end = ( + line.find(">", mention_start) if mention_start >= 0 else -1 + ) + if mention_start >= 0 and mention_end >= split_at: + split_at = mention_start or self.MARKDOWN_CHUNK_SIZE + append_piece(line[:split_at]) + line = line[split_at:] + piece = line + if piece: + append_piece(piece) + + if current: + chunks.append(current) + return chunks + + async def send_image( + self, group_id: str, image_path: str, caption: str = "" + ) -> bool: + from astrbot.api.event import MessageChain + + chain = MessageChain() + if caption: + chain.message(caption) + if image_path.startswith("base64://"): + chain.base64_image(image_path[len("base64://") :]) + elif image_path.startswith("data:") and "," in image_path: + chain.base64_image(image_path.split(",", 1)[1]) + elif image_path.startswith(("http://", "https://")): + chain.url_image(image_path) + else: + chain.file_image(os.path.abspath(image_path)) + return await self._send_chain(group_id, chain) + + async def send_file( + self, group_id: str, file_path: str, filename: str | None = None + ) -> bool: + # Prefer the public API; fall back to internal for backward compat. + # astrbot.core is not part of the stable contract and may change. + from astrbot.api.event import MessageChain + from astrbot.core.message.components import File + + name = filename or os.path.basename(file_path) or "report" + if file_path.startswith(("http://", "https://")): + component = File(name=name, url=file_path) + else: + component = File(name=name, file=os.path.abspath(file_path)) + return await self._send_chain(group_id, MessageChain([component])) + + async def get_group_info(self, group_id: str) -> UnifiedGroup | None: + return UnifiedGroup( + group_id=str(group_id), + group_name=str(group_id), + platform=self.platform_name, + ) + + async def get_group_list(self) -> list[str]: + if self._plugin_instance and hasattr( + self._plugin_instance, "get_seen_group_ids" + ): + try: + return await self._plugin_instance.get_seen_group_ids(self.platform_id) + except Exception as exc: + logger.warning("[QQOfficial] 获取已见群列表失败: %s", exc) + return [] + + async def get_member_list(self, group_id: str) -> list[UnifiedMember]: + return [] + + async def get_member_info( + self, group_id: str, user_id: str + ) -> UnifiedMember | None: + profile = self._member_profiles.get(str(user_id), {}) + return UnifiedMember( + user_id=str(user_id), + nickname=profile.get("nickname", ""), + avatar_url=await self.get_user_avatar_url(str(user_id)), + ) + + async def get_user_avatar_url(self, user_id: str, size: int = 100) -> str | None: + normalized_user_id = str(user_id or "").strip() + if not normalized_user_id: + return None + profile = self._member_profiles.get(normalized_user_id, {}) + remembered_avatar_url = profile.get("avatar_url", "") + if remembered_avatar_url: + return remembered_avatar_url + if not self.appid: + return None + return self.AVATAR_TEMPLATE.format( + appid=quote(self.appid, safe=""), + member_openid=quote(normalized_user_id, safe=""), + ) + + async def get_user_avatar_data(self, user_id: str, size: int = 100) -> str | None: + avatar_url = await self.get_user_avatar_url(user_id, size) + if not avatar_url: + return None + try: + timeout = aiohttp.ClientTimeout(total=15) + async with aiohttp.ClientSession( + timeout=timeout, trust_env=True + ) as session: + async with session.get(avatar_url) as response: + if response.status != 200: + return None + payload = await response.read() + if not payload: + return None + mime = "image/png" if payload.startswith(b"\x89PNG") else "image/jpeg" + return f"data:{mime};base64,{base64.b64encode(payload).decode('utf-8')}" + except Exception as exc: + logger.debug("[QQOfficial] 下载头像失败: %s", exc) + return None + + async def get_group_avatar_url(self, group_id: str, size: int = 100) -> str | None: + return None + + async def batch_get_avatar_urls( + self, user_ids: list[str], size: int = 100 + ) -> dict[str, str | None]: + unique_ids = list( + dict.fromkeys(str(user_id) for user_id in user_ids if user_id) + ) + + async def get_one(user_id: str) -> tuple[str, str | None]: + return user_id, await self.get_user_avatar_url(user_id, size) + + return dict(await asyncio.gather(*(get_one(user_id) for user_id in unique_ids))) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/telegram_adapter.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/telegram_adapter.py new file mode 100644 index 0000000..59f58b3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/adapters/telegram_adapter.py @@ -0,0 +1,1107 @@ +""" +Telegram 平台适配器 + +支持 Telegram Bot API 的消息发送功能。 +通过 AstrBot 的 message_history_manager 存储和读取消息历史。 +""" + +import asyncio +import base64 +import os +import time +from dataclasses import replace +from datetime import datetime, timedelta, timezone +from io import BytesIO +from typing import TYPE_CHECKING, Any + +from ....domain.value_objects.platform_capabilities import ( + TELEGRAM_CAPABILITIES, + PlatformCapabilities, +) +from ....domain.value_objects.unified_group import UnifiedGroup, UnifiedMember +from ....domain.value_objects.unified_message import ( + MessageContent, + MessageContentType, + UnifiedMessage, +) +from ....utils.logger import logger +from ..base import PlatformAdapter + +if TYPE_CHECKING: + from astrbot.api.star import Context + +# Telegram 依赖 +try: + from telegram.ext import ExtBot + + TELEGRAM_AVAILABLE = True +except ImportError: + ExtBot = None + TELEGRAM_AVAILABLE = False + + +TELEGRAM_AVATAR_NEGATIVE_CACHE_TTL = 600 +TELEGRAM_AVATAR_NEGATIVE_CACHE_MAX_SIZE = 1024 + + +class TelegramAdapter(PlatformAdapter): + """ + Telegram Bot API 适配器 + + 实现 PlatformAdapter 接口,支持: + - 消息发送(文本、图片、文件) + - 头像获取 + - 群组信息获取 + - 消息历史(通过 AstrBot 的 message_history_manager) + + 消息历史机制: + - 消息通过拦截器存储到 AstrBot 数据库 + - fetch_messages 从数据库读取历史消息 + """ + + def __init__(self, bot_instance: Any, config: dict | None = None): + super().__init__(bot_instance, config) + self._cached_client: Any = None + self._context: Context | None = None + + # 机器人自身 ID(用于消息过滤) + self.bot_user_id = str(config.get("bot_user_id", "")) if config else "" + + # 尝试从配置获取 bot self ids 列表 + self.bot_self_ids: list[str] = [] + if config: + ids = config.get("bot_self_ids", []) + self.bot_self_ids = [str(i) for i in ids] if ids else [] + self._plugin_instance = config.get("plugin_instance") + else: + self._plugin_instance = None + self._platform_id = str(config.get("platform_id", "")).strip() if config else "" + # user_id -> (expires_at, reason) + self._avatar_negative_cache: dict[str, tuple[float, str]] = {} + + def set_context(self, context: "Context") -> None: + """ + 设置 AstrBot 上下文 + + 用于访问 message_history_manager 等核心服务。 + """ + self._context = context + + def _init_capabilities(self) -> PlatformCapabilities: + """返回 Telegram 平台能力声明""" + return TELEGRAM_CAPABILITIES + + async def get_group_list(self) -> list[str]: + """ + 获取群组列表 + + Telegram Bot API 不支持直接获取群列表。 + 因此这里尝试结合多种策略: + 1. 尝试调用 API (如果未来支持) + 2. 回退:从插件的 KV 存储中获取已知群组 (需注入插件实例) + """ + groups = [] + + # 1. 尝试 API (目前 python-telegram-bot 不支持直接列出所有 chat) + # 如果 client 有扩展方法或未来支持,可在此实现 + + # 2. 回退:使用 KV 注册表 + if not groups and self._plugin_instance: + try: + # 检查插件实例是否有 get_telegram_seen_group_ids 方法 + if hasattr(self._plugin_instance, "get_telegram_seen_group_ids"): + kv_groups = await self._plugin_instance.get_telegram_seen_group_ids( + self._platform_id + ) + if kv_groups: + groups.extend(kv_groups) + logger.debug( + f"[Telegram] 通过 KV 回退获取到 {len(kv_groups)} 个群组" + ) + except Exception as e: + logger.warning(f"[Telegram] KV 回退获取群列表失败: {e}") + + if not groups: + logger.debug("[Telegram] 无法获取群列表 (API不支持且无KV记录)") + + return list(set(groups)) + + @property + def _telegram_client(self) -> Any: + """ + 懒加载获取 Telegram 客户端 + + 支持多种获取路径,适应 AstrBot 不同版本。 + """ + if self._cached_client is not None: + return self._cached_client + + if not TELEGRAM_AVAILABLE: + logger.warning("python-telegram-bot 库未安装,Telegram 适配器不可用") + return None + + # 路径 A: bot 本身就是 ExtBot + if ExtBot is not None and isinstance(self.bot, ExtBot): + self._cached_client = self.bot + return self._cached_client + + # 路径 B: bot.client + if hasattr(self.bot, "client"): + client = self.bot.client + if ExtBot is not None and isinstance(client, ExtBot): + self._cached_client = client + return self._cached_client + + # 路径 C: bot 有 send_message 方法(ExtBot 的特征) + if hasattr(self.bot, "send_message") and hasattr(self.bot, "send_photo"): + self._cached_client = self.bot + return self._cached_client + + # 尝试从 bot 的其他属性获取 + for attr in ("_client", "telegram_client", "_telegram_client", "bot"): + if hasattr(self.bot, attr): + client = getattr(self.bot, attr) + if hasattr(client, "send_message"): + self._cached_client = client + return self._cached_client + + logger.warning("无法从 bot_instance 获取 Telegram 客户端") + return None + + # ==================== IMessageRepository ==================== + + async def fetch_messages( + self, + group_id: str, + days: int = 1, + max_count: int = 100, + before_id: str | None = None, + since_ts: int | None = None, + ) -> list[UnifiedMessage]: + """ + 获取历史消息。 + + 从 AstrBot 的 message_history_manager 读取存储的消息。 + """ + if not self._context: + logger.warning("[Telegram] 未设置 context,无法获取消息历史") + return [] + + try: + history_mgr = self._context.message_history_manager + + platform_id = self._get_platform_id() + logger.info( + f"[Telegram] 正在获取群 {group_id} 的历史消息,使用 platform_id: {platform_id}" + ) + before_id_int: int | None = None + if before_id: + try: + before_id_int = int(before_id) + except (TypeError, ValueError): + logger.warning(f"[Telegram] before_id invalid: {before_id}") + + if since_ts and since_ts > 0: + # 统一使用 UTC 以兼容数据库记录的时间存储 + cutoff_time = datetime.fromtimestamp(since_ts, timezone.utc) + else: + cutoff_time = datetime.now(timezone.utc) - timedelta(days=days) + target_count = max(1, int(max_count)) + page_size = target_count + current_page = 1 + + messages: list[UnifiedMessage] = [] + seen_message_ids: set[str] = set() + sender_name_cache: dict[str, str] = {} + total_records_loaded = 0 + + while len(messages) < target_count: + history_records = await history_mgr.get( + platform_id=platform_id, + user_id=group_id, + page=current_page, + page_size=page_size, + ) + if not history_records: + if current_page == 1: + logger.info( + f"[Telegram] 群 {group_id} 没有存储的消息。" + f"提示:消息需要通过拦截器实时存储。" + ) + break + + total_records_loaded += len(history_records) + + # 先用当前页已有的有效昵称预热缓存,减少额外 API 请求 + for record in history_records: + sender_id = str(getattr(record, "sender_id", "") or "").strip() + sender_name = str(getattr(record, "sender_name", "") or "").strip() + if sender_id and not self._is_placeholder_sender_name( + sender_name, sender_id + ): + sender_name_cache[sender_id] = sender_name + + oldest_record_time: datetime | None = None + for record in history_records: + if before_id_int is not None: + try: + rec_id = getattr(record, "id", None) + if rec_id is not None and int(rec_id) >= before_id_int: + continue + except (TypeError, ValueError): + pass + + record_time = getattr(record, "created_at", None) + if not record_time: + continue + if record_time.tzinfo is None: + record_time = record_time.replace(tzinfo=timezone.utc) + if oldest_record_time is None or record_time < oldest_record_time: + oldest_record_time = record_time + if record_time < cutoff_time: + continue + + msg = self._convert_history_record(record, group_id) + if not msg: + continue + + # 过滤机器人自己的消息 + if self.bot_user_id and msg.sender_id == self.bot_user_id: + continue + if msg.sender_id in self.bot_self_ids: + continue + + msg = await self._fix_sender_name_if_needed( + group_id, msg, sender_name_cache + ) + if msg.message_id in seen_message_ids: + continue + seen_message_ids.add(msg.message_id) + messages.append(msg) + + # 当前页完整处理后已足够,停止继续翻更旧页面。 + if len(messages) >= target_count: + break + + # 下一页一定更旧,若当前页最旧记录已越过时间窗口则可提前停止 + if oldest_record_time and oldest_record_time < cutoff_time: + break + if len(history_records) < page_size: + break + current_page += 1 + + messages.sort(key=lambda m: m.timestamp) + if len(messages) > target_count: + messages = messages[-target_count:] + + logger.info( + f"[Telegram] 从数据库获取群 {group_id} 的消息: " + f"{len(messages)}/{total_records_loaded} 条" + ) + return messages + + except Exception as e: + logger.error(f"[Telegram] 获取消息历史失败: {e}") + return [] + + def _get_platform_id(self) -> str: + """获取平台 ID""" + if self._platform_id: + return self._platform_id + + if isinstance(self.config, dict): + config_platform_id = str(self.config.get("platform_id", "")).strip() + if config_platform_id: + return config_platform_id + + # 尝试从 bot 实例获取 + if hasattr(self.bot, "meta") and callable(self.bot.meta): + try: + meta = self.bot.meta() # type: ignore + if hasattr(meta, "id"): + return str(getattr(meta, "id", "telegram")) + except Exception: + pass + return "telegram" + + @staticmethod + def _is_placeholder_sender_name(name: str | None, sender_id: str | None) -> bool: + """判断 sender_name 是否属于占位值。""" + if not name: + return True + normalized = str(name).strip() + if not normalized: + return True + if normalized.lower() in {"unknown", "none", "null", "nil", "undefined"}: + return True + if sender_id and normalized == str(sender_id).strip(): + return True + return False + + async def _fix_sender_name_if_needed( + self, + group_id: str, + msg: UnifiedMessage, + sender_name_cache: dict[str, str], + ) -> UnifiedMessage: + """ + 如果 sender_name 是占位值,尝试通过 get_member_info 修复。 + + 说明: + - 兼容历史脏数据(sender_name 写成 user_id / Unknown) + - 使用 sender_id 级缓存,避免重复请求 Telegram API + """ + if not self._is_placeholder_sender_name(msg.sender_name, msg.sender_id): + return msg + + sender_id = str(msg.sender_id) + if sender_id in sender_name_cache: + cached_name = sender_name_cache[sender_id] + if cached_name == msg.sender_name: + return msg + return replace(msg, sender_name=cached_name) + + resolved_name = msg.sender_name + try: + member = await self.get_member_info(group_id, sender_id) + if member: + candidate = str(member.nickname or "").strip() + if self._is_placeholder_sender_name(candidate, sender_id): + candidate = str(member.card or "").strip() + if not self._is_placeholder_sender_name(candidate, sender_id): + resolved_name = candidate + except Exception as e: + logger.debug(f"[Telegram] 修复 sender_name 失败 (uid={sender_id}): {e}") + + sender_name_cache[sender_id] = resolved_name + if resolved_name == msg.sender_name: + return msg + return replace(msg, sender_name=resolved_name) + + def _convert_history_record( + self, record: Any, group_id: str + ) -> UnifiedMessage | None: + """ + 将数据库记录转换为 UnifiedMessage + """ + try: + content = record.content + if not content: + return None + + # 提取消息内容 + message_parts = content.get("message", []) + text_content = "" + contents = [] + + for part in message_parts: + if isinstance(part, dict): + part_type = part.get("type", "") + if part_type == "plain" or part_type == "text": + text = part.get("text", "") + text_content += text + contents.append( + MessageContent( + type=MessageContentType.TEXT, + text=text, + ) + ) + elif part_type == "image": + contents.append( + MessageContent( + type=MessageContentType.IMAGE, + url=part.get("url", "") + or part.get("attachment_id", ""), + ) + ) + elif part_type == "at": + target_id = ( + part.get("target_id", "") + or part.get("qq", "") + or part.get("at_user_id", "") + ) + contents.append( + MessageContent( + type=MessageContentType.AT, + at_user_id=str(target_id), + ) + ) + + if not contents: + contents.append( + MessageContent( + type=MessageContentType.TEXT, + text=text_content, + ) + ) + + sender_id = str(record.sender_id or "") + sender_name = str(record.sender_name or "").strip() or "Unknown" + + return UnifiedMessage( + message_id=str(record.id), + sender_id=sender_id, + sender_name=sender_name, + sender_card=None, + group_id=group_id, + text_content=text_content, + contents=tuple(contents), + timestamp=int(record.created_at.timestamp()), + platform="telegram", + reply_to_id=None, + ) + + except Exception as e: + logger.debug(f"[Telegram] 转换历史记录失败: {e}") + return None + + def convert_to_raw_format(self, messages: list[UnifiedMessage]) -> list[dict]: + """ + 将统一消息格式转换为 OneBot 兼容格式 + + 用于向后兼容现有分析逻辑。 + """ + result = [] + for msg in messages: + raw = { + "message_id": msg.message_id, + "group_id": msg.group_id, + "time": msg.timestamp, + "sender": { + "user_id": msg.sender_id, + "nickname": msg.sender_name, + "card": msg.sender_card or "", + }, + "message": [], + "user_id": msg.sender_id, + } + + # 转换消息内容 + for content in msg.contents: + if content.type == MessageContentType.TEXT: + raw["message"].append( + {"type": "text", "data": {"text": content.text or ""}} + ) + elif content.type == MessageContentType.IMAGE: + raw["message"].append( + {"type": "image", "data": {"url": content.url or ""}} + ) + elif content.type == MessageContentType.AT: + raw["message"].append( + {"type": "at", "data": {"qq": content.at_user_id or ""}} + ) + + result.append(raw) + + return result + + # ==================== IMessageSender ==================== + + async def send_text( + self, + group_id: str, + text: str, + reply_to: str | None = None, + ) -> bool: + """发送文本消息""" + client = self._telegram_client + if not client: + logger.error("[Telegram] 客户端未初始化,无法发送文本") + return False + + try: + # 处理群组话题 ID + chat_id, message_thread_id = self._parse_group_id(group_id) + + kwargs: dict[str, Any] = {"chat_id": chat_id, "text": text} + if message_thread_id: + kwargs["message_thread_id"] = int(message_thread_id) + if reply_to: + kwargs["reply_to_message_id"] = int(reply_to) + + await client.send_message(**kwargs) + return True + except Exception as e: + logger.error(f"[Telegram] 发送文本失败: {e}") + return False + + async def send_image( + self, + group_id: str, + image_path: str, + caption: str = "", + ) -> bool: + """发送图片消息""" + client = self._telegram_client + if not client: + logger.error("[Telegram] 客户端未初始化,无法发送图片") + return False + + try: + chat_id, message_thread_id = self._parse_group_id(group_id) + file_obj: Any = None + is_temp_obj = False + + kwargs: dict[str, Any] = {"chat_id": chat_id} + if message_thread_id: + kwargs["message_thread_id"] = int(message_thread_id) + if caption: + kwargs["caption"] = caption + + # 1. 统一处理输入源 (Base64 / URL / Local File) + if image_path.startswith("base64://"): + data = base64.b64decode(image_path[len("base64://") :]) + file_obj = BytesIO(data) + is_temp_obj = True + elif image_path.startswith("data:"): + parts = image_path.split(",", 1) + if len(parts) == 2: + data = base64.b64decode(parts[1]) + file_obj = BytesIO(data) + is_temp_obj = True + elif image_path.startswith(("http://", "https://")): + try: + import aiohttp + + async with aiohttp.ClientSession() as session: + async with session.get( + image_path, timeout=aiohttp.ClientTimeout(total=30) + ) as resp: + if resp.status == 200: + data = await resp.read() + file_obj = BytesIO(data) + is_temp_obj = True + else: + file_obj = image_path # 尝试直接发 URL + except Exception as e: + logger.warning(f"[Telegram] 下载图片失败,尝试直接发送: {e}") + file_obj = image_path + else: + # 本地文件 + if os.path.exists(image_path): + file_obj = open(image_path, "rb") + is_temp_obj = True + else: + file_obj = image_path + + # 2. 发送图片 + kwargs["photo"] = file_obj + try: + await client.send_photo(**kwargs) + finally: + if is_temp_obj and hasattr(file_obj, "close"): + file_obj.close() + + return True + + except Exception as e: + err_msg = str(e) + # Photo_invalid_dimensions: Telegram 报错提示图片长宽比例或总尺寸不合规 + if ( + "Photo_invalid_dimensions" in err_msg + or "Photo invalid dimensions" in err_msg + ): + logger.warning("[Telegram] 图片尺寸超限,正在尝试以文件形式发送...") + # 构造一个更有意义的文件名 + ts = datetime.now().strftime("%Y%m%d_%H%M%S") + fn = f"analysis_report_{group_id}_{ts}.png" + return await self.send_file(group_id, image_path, filename=fn) + + logger.error(f"[Telegram] 发送图片失败: {e}") + return False + + async def send_file( + self, + group_id: str, + file_path: str, + filename: str | None = None, + ) -> bool: + """发送文件消息""" + client = self._telegram_client + if not client: + logger.error("[Telegram] 客户端未初始化,无法发送文件") + return False + + try: + chat_id, message_thread_id = self._parse_group_id(group_id) + file_obj: Any = None + is_temp_obj = False + + kwargs: dict[str, Any] = {"chat_id": chat_id} + if message_thread_id: + kwargs["message_thread_id"] = int(message_thread_id) + + # 1. 统一处理输入源 (Base64 / Local File) + if file_path.startswith("base64://"): + data = base64.b64decode(file_path[len("base64://") :]) + file_obj = BytesIO(data) + is_temp_obj = True + if not filename: + filename = "file.png" + elif file_path.startswith("data:"): + parts = file_path.split(",", 1) + if len(parts) == 2: + data = base64.b64decode(parts[1]) + file_obj = BytesIO(data) + is_temp_obj = True + if not filename: + filename = "file.png" + elif os.path.isfile(file_path): + file_obj = open(file_path, "rb") + is_temp_obj = True + if not filename: + filename = os.path.basename(file_path) + else: + # 可能是 URL 或缓存 ID + file_obj = file_path + if not filename: + filename = "file" + + kwargs["document"] = file_obj + kwargs["filename"] = filename + + try: + await client.send_document(**kwargs) + finally: + if is_temp_obj and hasattr(file_obj, "close"): + file_obj.close() + + return True + except Exception as e: + logger.error(f"[Telegram] 发送文件失败: {e}") + return False + + async def send_forward_msg(self, group_id: str, nodes: list[dict]) -> bool: + """ + 发送合并转发消息 + + Telegram 不支持原生转发消息链,转换为格式化文本发送。 + """ + if not nodes: + return True + + lines = ["📊 **分析报告**\n"] + for node in nodes: + data = node.get("data", node) + name = data.get("name", "AstrBot") + content = data.get("content", "") + if isinstance(content, list): + # 消息链 + text_parts = [] + for seg in content: + if isinstance(seg, dict) and seg.get("type") == "text": + text_parts.append(seg.get("data", {}).get("text", "")) + content = "".join(text_parts) + lines.append(f"**[{name}]**\n{content}\n") + + full_text = "\n".join(lines) + + # 分段发送(Telegram 限制 4096 字符) + max_len = 4000 + if len(full_text) > max_len: + parts = [ + full_text[i : i + max_len] for i in range(0, len(full_text), max_len) + ] + for part in parts: + if not await self.send_text(group_id, part): + return False + return True + else: + return await self.send_text(group_id, full_text) + + # ==================== IGroupInfoRepository ==================== + + async def get_group_info(self, group_id: str) -> UnifiedGroup | None: + """获取群组信息""" + client = self._telegram_client + if not client: + return None + + try: + chat_id, _ = self._parse_group_id(group_id) + chat = await client.get_chat(chat_id=chat_id) + + return UnifiedGroup( + group_id=str(chat.id), + group_name=chat.title or "Unknown", + member_count=await client.get_chat_member_count(chat_id) or 0, + description=chat.description, + platform="telegram", + ) + except Exception as e: + logger.debug(f"[Telegram] 获取群信息失败: {e}") + return None + + async def get_member_list(self, group_id: str) -> list[UnifiedMember]: + """ + 获取成员列表 + + Telegram Bot API 对成员列表获取有限制。 + """ + client = self._telegram_client + if not client: + return [] + + try: + chat_id, _ = self._parse_group_id(group_id) + # Telegram Bot API 需要使用 getChatAdministrators + # 只能获取管理员列表,无法获取全部成员 + admins = await client.get_chat_administrators(chat_id=chat_id) + + members = [] + for admin in admins: + user = admin.user + members.append( + UnifiedMember( + user_id=str(user.id), + nickname=user.full_name + or user.first_name + or user.username + or "Unknown", + card=user.username, + role="admin" if admin.status == "administrator" else "owner", + ) + ) + return members + except Exception as e: + logger.debug(f"[Telegram] 获取成员列表失败: {e}") + return [] + + async def get_member_info( + self, + group_id: str, + user_id: str, + ) -> UnifiedMember | None: + """获取成员信息""" + client = self._telegram_client + if not client: + return None + + try: + chat_id, _ = self._parse_group_id(group_id) + member = await client.get_chat_member(chat_id=chat_id, user_id=int(user_id)) + user = member.user + + role = "member" + if member.status in ("creator", "owner"): + role = "owner" + elif member.status == "administrator": + role = "admin" + + return UnifiedMember( + user_id=str(user.id), + nickname=user.full_name + or user.first_name + or user.username + or "Unknown", + card=user.username, + role=role, + ) + except Exception as e: + logger.debug(f"[Telegram] 获取成员信息失败: {e}") + return None + + # ==================== IAvatarRepository ==================== + + async def get_user_avatar_url( + self, + user_id: str, + size: int = 100, + ) -> str | None: + """ + 获取用户头像 URL + + Telegram 需要调用 API 获取头像文件。 + """ + client = self._telegram_client + if not client: + logger.warning( + f"[Telegram] 获取用户头像失败 uid={user_id}: Telegram 客户端未初始化" + ) + return None + + user_id_str = str(user_id).strip() + cached_reason = self._get_avatar_negative_cache_reason(user_id_str) + if cached_reason: + logger.debug( + f"[Telegram] 跳过用户头像获取 uid={user_id_str}: negative cache 命中," + f"上次失败原因: {cached_reason}" + ) + return None + + try: + tg_user_id = int(user_id_str) + except (TypeError, ValueError): + reason = f"用户 ID 不是有效整数: {user_id!r}" + self._remember_avatar_negative(user_id_str, reason) + logger.warning(f"[Telegram] 获取用户头像失败 uid={user_id}: {reason}") + return None + + try: + photos = await client.get_user_profile_photos(user_id=tg_user_id, limit=1) + if photos.photos: + # 获取最大尺寸的头像 + photo_sizes = photos.photos[0] + if photo_sizes: + # 选择最接近请求尺寸的 + best = photo_sizes[-1] # 通常最后一个是最大的 + file = await client.get_file(best.file_id) + if file.file_path: + # 构建完整 URL + # 格式: https://api.telegram.org/file/bot/ + # python-telegram-bot 的 File.file_path 属性通常只返回路径部分 + # 需要手动拼接或使用 instance.file.file_path (取决于版本) + + file_path = file.file_path + if file_path.startswith("http"): + return file_path + + # 尝试构建完整 URL + if hasattr(client, "token"): + return f"https://api.telegram.org/file/bot{client.token}/{file_path}" + + # 如果无法获取 token,返回 None + reason = "get_file 返回相对 file_path,但 client 没有 token,无法拼接下载 URL" + self._remember_avatar_negative(user_id_str, reason) + logger.warning( + f"[Telegram] 获取用户头像失败 uid={user_id_str}: {reason}" + ) + return None + reason = "get_file 未返回 file_path" + self._remember_avatar_negative(user_id_str, reason) + logger.warning( + f"[Telegram] 获取用户头像失败 uid={user_id_str}: {reason}" + ) + return None + reason = "get_user_profile_photos 返回的首张头像没有可用尺寸" + self._remember_avatar_negative(user_id_str, reason) + logger.info(f"[Telegram] 获取用户头像失败 uid={user_id_str}: {reason}") + return None + reason = "get_user_profile_photos 返回空列表,用户可能没有公开头像或隐私设置不可见" + self._remember_avatar_negative(user_id_str, reason) + logger.info(f"[Telegram] 获取用户头像失败 uid={user_id_str}: {reason}") + return None + except Exception as e: + reason = f"{type(e).__name__}: {e}" + self._remember_avatar_negative(user_id_str, reason) + logger.warning(f"[Telegram] 获取用户头像失败 uid={user_id_str}: {reason}") + return None + + async def get_user_avatar_data( + self, + user_id: str, + size: int = 100, + ) -> str | None: + """获取头像的 Base64 数据""" + # 暂不实现,返回 None + logger.debug( + f"[Telegram] 获取用户头像数据失败 uid={user_id}: get_user_avatar_data 暂未实现" + ) + return None + + async def get_group_avatar_url( + self, + group_id: str, + size: int = 100, + ) -> str | None: + """获取群组头像 URL""" + client = self._telegram_client + if not client: + logger.warning( + f"[Telegram] 获取群头像失败 group_id={group_id}: Telegram 客户端未初始化" + ) + return None + + try: + chat_id, _ = self._parse_group_id(group_id) + chat = await client.get_chat(chat_id=chat_id) + + if chat.photo: + file = await client.get_file(chat.photo.big_file_id) + if file.file_path: + file_path = file.file_path + if file_path.startswith("http"): + return file_path + + if hasattr(client, "token"): + return f"https://api.telegram.org/file/bot{client.token}/{file_path}" + + logger.warning( + f"[Telegram] 获取群头像失败 group_id={group_id}: " + "get_file 返回相对 file_path,但 client 没有 token,无法拼接下载 URL" + ) + return None + logger.warning( + f"[Telegram] 获取群头像失败 group_id={group_id}: get_file 未返回 file_path" + ) + return None + logger.info( + f"[Telegram] 获取群头像失败 group_id={group_id}: 群组未设置头像或 bot 不可见" + ) + return None + except Exception as e: + logger.warning( + f"[Telegram] 获取群头像失败 group_id={group_id}: {type(e).__name__}: {e}" + ) + return None + + def _prune_avatar_negative_cache(self) -> None: + """清理过期项并限制 negative cache 大小,避免长期运行时无界增长。""" + cache = self._avatar_negative_cache + if not cache: + return + + now = time.monotonic() + expired_keys = [ + user_id + for user_id, (expires_at, _reason) in cache.items() + if expires_at <= now + ] + for user_id in expired_keys: + cache.pop(user_id, None) + + overflow = len(cache) - TELEGRAM_AVATAR_NEGATIVE_CACHE_MAX_SIZE + if overflow <= 0: + return + + for user_id, _ in sorted(cache.items(), key=lambda item: item[1][0])[:overflow]: + cache.pop(user_id, None) + + def _get_avatar_negative_cache_reason(self, user_id: str) -> str | None: + self._prune_avatar_negative_cache() + cached = self._avatar_negative_cache.get(user_id) + if not cached: + return None + + expires_at, reason = cached + if time.monotonic() >= expires_at: + self._avatar_negative_cache.pop(user_id, None) + return None + return reason + + def _remember_avatar_negative(self, user_id: str, reason: str) -> None: + self._prune_avatar_negative_cache() + self._avatar_negative_cache[user_id] = ( + time.monotonic() + TELEGRAM_AVATAR_NEGATIVE_CACHE_TTL, + reason, + ) + self._prune_avatar_negative_cache() + + async def batch_get_avatar_urls( + self, + user_ids: list[str], + size: int = 100, + ) -> dict[str, str | None]: + """批量获取头像 URL""" + if not user_ids: + return {} + + # 适度并发,避免串行等待过久,也避免瞬时过载 Telegram API + semaphore = asyncio.Semaphore(8) + + async def _fetch_avatar(uid: str) -> tuple[str, str | None]: + async with semaphore: + try: + return uid, await self.get_user_avatar_url(uid, size) + except Exception as e: + logger.debug(f"[Telegram] 批量获取头像失败 uid={uid}: {e}") + return uid, None + + pairs = await asyncio.gather(*(_fetch_avatar(uid) for uid in user_ids)) + return dict(pairs) + + async def set_reaction( + self, group_id: str, message_id: str, emoji: str | int, is_add: bool = True + ) -> bool: + """ + Telegram 实现消息回应。 + """ + client = self._telegram_client + if not client: + return False + + try: + chat_id, _ = self._parse_group_id(group_id) + + # 只有开启了库支持且版本符合时才尝试。set_message_reaction 是 Bot API 7.0 (PTB 20.8+) 特性。 + if not hasattr(client, "set_message_reaction"): + return False + + if not is_add: + try: + from telegram import ReactionTypeEmoji + + await client.set_message_reaction( + chat_id=chat_id, + message_id=int(message_id), + reaction=[], + ) + return True + except ImportError: + await client.set_message_reaction( + chat_id=chat_id, + message_id=int(message_id), + reaction=None, + ) + return True + + reaction_key = str(emoji) + candidates = { + "analysis_started": ("👀", "🤔", "👍"), + "analysis_done": ("👌", "👍", "🎉"), + "🔍": ("👀", "🤔", "👍"), + "📊": ("👌", "👍", "🎉"), + "289": ("👀", "🤔", "👍"), + "124": ("👌", "👍", "🎉"), + "424": ("👌", "👍", "🎉"), + "✅": ("👌", "👍", "🎉"), + }.get(reaction_key, (reaction_key,)) + + try: + from telegram import ReactionTypeEmoji + + for candidate in candidates: + try: + await client.set_message_reaction( + chat_id=chat_id, + message_id=int(message_id), + reaction=[ReactionTypeEmoji(emoji=candidate)], + ) + return True + except Exception: + continue + except ImportError: + for candidate in candidates: + try: + await client.set_message_reaction( + chat_id=chat_id, + message_id=int(message_id), + reaction=candidate, + ) + return True + except Exception: + continue + + logger.debug( + f"[Telegram] set_reaction 未匹配到可用表情: emoji={emoji}, candidates={candidates}" + ) + return False + except Exception as e: + logger.debug(f"[Telegram] set_reaction 失败: {e}") + return False + + # ==================== 辅助方法 ==================== + + def _parse_group_id(self, group_id: str) -> tuple[str, str | None]: + """ + 解析群组 ID + + Telegram 话题群的 ID 格式为: "chat_id#thread_id" + + Returns: + tuple[str, str | None]: (chat_id, message_thread_id) + """ + if "#" in group_id: + parts = group_id.split("#", 1) + return parts[0], parts[1] + return group_id, None diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/base.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/base.py new file mode 100644 index 0000000..7c92eea --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/base.py @@ -0,0 +1,224 @@ +""" +平台适配器基类 +""" + +from abc import ABC, abstractmethod +from collections.abc import Mapping +from typing import Any + +from ...domain.repositories.avatar_repository import IAvatarRepository +from ...domain.repositories.message_repository import ( + IGroupInfoRepository, + IMessageRepository, + IMessageSender, +) +from ...domain.value_objects.platform_capabilities import PlatformCapabilities +from ...domain.value_objects.unified_message import UnifiedMessage + + +class PlatformAdapter( + IMessageRepository, IMessageSender, IGroupInfoRepository, IAvatarRepository, ABC +): + """ + 基础设施:平台适配器基类 + + 继承自多个领域接口(仓储、发送器、群组信息、头像), + 充当领域层与具体聊天平台(如 OneBot, Discord)之间的中转站。 + + Attributes: + bot (Any): 平台对应的机器人 SDK 实例,显式标注为 Any 以支持动态属性调用 + config (dict): 针对该平台的特定配置 + """ + + bot: Any + + def __init__( + self, + bot_instance: Any, + config: Mapping[str, Any] | None = None, + ): + """ + 初始化平台适配器。 + + Args: + bot_instance (Any): 后端机器人实例 + config (dict, optional): 平台特定配置项 + """ + self.bot = bot_instance + self.config: dict[str, object] = dict(config) if config is not None else {} + self._platform_id: str = str(self.config.get("platform_id", "")).strip() + self.bot_self_ids: list[str] = [] + self._capabilities: PlatformCapabilities | None = None + + @property + def platform_id(self) -> str: + """获取当前适配器的平台实例 ID(如 nuits)""" + return self._platform_id + + def set_context(self, context: Any): + """ + 设置上下文对象(用于部分需要 ctx 的平台如 Telegram)。 + + Args: + context (Any): 上下文对象 + """ + pass + + @property + def capabilities(self) -> PlatformCapabilities: + """ + 获取当前平台的能力描述对象。 + + 采用延迟加载机制,在首次访问时调用 `_init_capabilities`。 + + Returns: + PlatformCapabilities: 平台能力对象 + """ + if self._capabilities is None: + self._capabilities = self._init_capabilities() + return self._capabilities + + @abstractmethod + def _init_capabilities(self) -> PlatformCapabilities: + """ + 初始化并返回当前平台的能力定义。 + + 子类必须实现此方法以声明其对历史记录、图片发送等功能的支持情况。 + + Returns: + PlatformCapabilities: 初始化后的能力对象 + """ + raise NotImplementedError + + def get_capabilities(self) -> PlatformCapabilities: + """获取平台能力的便捷入口。""" + return self.capabilities + + def get_platform_name(self) -> str: + """获取当前适配器的平台标识名称。""" + return self.capabilities.platform_name + + @abstractmethod + def convert_to_raw_format(self, messages: list[UnifiedMessage]) -> list[dict]: + """ + 将平台无关的统一消息列表转换回当前平台的原生字典格式。 + + 此方法主要用于向后兼容,使新的统一接口能与依赖原生数据结构的旧版分析逻辑协同工作。 + + Args: + messages (list[UnifiedMessage]): 待转换的统一消息列表 + + Returns: + list[dict]: 转换后的平台原生消息字典列表 + """ + raise NotImplementedError + + async def send_forward_msg( + self, + group_id: str, + nodes: list[dict], + ) -> bool: + """ + 发送合并转发消息(基类默认实现:转换为格式化文本分段发送)。 + 各适配器可覆盖此方法实现原生合并转发。 + """ + if not nodes: + return True + + # 万能回退:将节点重新组合成易读的长文本 + lines = [] + for node in nodes: + data = node.get("data", node) + name = data.get("name", "Daily Analysis") + content = data.get("content", "") + if content: + lines.append(f"【{name}】\n{content}") + + full_text = "\n\n".join(lines) + + # 处理超长文本分段(取大部分平台的安全阈值 1800 字符) + max_chunk_size = 1800 + if len(full_text) > max_chunk_size: + # 尝试在换行处拆分 + chunks = [] + curr = full_text + while len(curr) > max_chunk_size: + # 寻找最近的换行符 + split_idx = curr.rfind("\n", 0, max_chunk_size) + if split_idx == -1: + split_idx = max_chunk_size + chunks.append(curr[:split_idx].strip()) + curr = curr[split_idx:].strip() + if curr: + chunks.append(curr) + + for chunk in chunks: + if not await self.send_text(group_id, chunk): + return False + return True + else: + return await self.send_text(group_id, full_text) + + async def set_reaction( + self, group_id: str, message_id: str, emoji: str | int, is_add: bool = True + ) -> bool: + """ + 对消息添加/移除表情回应。 + + Args: + group_id (str): 群组/频道 ID + message_id (str): 消息 ID + emoji (str | int): 表情代码或字符 + is_add (bool): True 为添加,False 为移除 + + Returns: + bool: 平台是否支持并成功执行 + """ + return False + + async def send_text_report(self, group_id: str, content: str) -> bool: + """ + 以最适合当前平台的方式发送长文本报告。 + 默认逻辑:将长文本切分为多个节点,然后调用 send_forward_msg。 + 各平台适配器通过实现 send_forward_msg 来决定最终呈现形式(合并转发、分段发送等)。 + """ + import re + + try: + # 1. 准备节点基础信息 + self_id = self.bot_self_ids[0] if self.bot_self_ids else "bot" + self_name = "分析报告" + # 2. 切分文本为逻辑段落(按标题、空行切分) + raw_content = str(content) + sections = re.split(r"\n+(?=[🎯📊💬🏆])|\n{2,}", raw_content.strip()) + nodes = [] + + for sec in sections: + if not sec.strip(): + continue + nodes.append( + { + "type": "node", + "data": { + "name": self_name, + "uin": self_id, + "content": sec.strip(), + }, + } + ) + + if not nodes: + return await self.send_text(group_id, raw_content) + + # 3. 尝试发送转发消息/长消息链 + return await self.send_forward_msg(group_id, nodes) + except Exception: + # 兜底:直接发送 + return await self.send_text(group_id, str(content)) + + async def is_group_muted(self, group_id: str) -> bool: + """ + 检查群聊是否被禁言(包括全体禁言或对 Bot 自身禁言)。 + 默认返回 False。各平台适配器可以根据需要重写此方法。 + """ + return False diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/bot_manager.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/bot_manager.py new file mode 100644 index 0000000..ca951db --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/bot_manager.py @@ -0,0 +1,637 @@ +""" +Bot实例管理模块 - 基础设施层 +统一管理bot实例的获取、设置和使用 +""" + +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any + +from ...utils.logger import logger +from . import PlatformAdapter, PlatformAdapterFactory + + +class BotManager: + """ + Bot实例管理器 - 统一管理所有bot相关操作 + + 与 DDD 架构集成,为每个 bot 实例创建对应的 PlatformAdapter, + 实现跨平台支持。 + """ + + def __init__(self, config_manager): + self.config_manager = config_manager + self._bot_instances: dict[str, object] = {} # {platform_id: bot_instance} + self._adapters: dict[ + str, PlatformAdapter + ] = {} # {platform_id: PlatformAdapter} - DDD 集成 + self._platforms: dict[str, object] = {} # 存储平台对象以访问配置 + self._bot_self_ids: list[str] = [] # 支持多个机器人账号 ID (原 _bot_qq_ids) + self._context: object | None = None + self._is_initialized = False + self._default_platform = "default" # 默认平台 + self._plugin_instance: object | None = None # 插件实例引用,用于适配器回调 + + def set_context(self, context): + """设置AstrBot上下文,并传递给所有支持的适配器""" + self._context = context + + # 将 context 传递给所有支持 set_context 的适配器 + for adapter in self._adapters.values(): + if hasattr(adapter, "set_context"): + adapter.set_context(context) + + def set_plugin_instance(self, plugin_instance: object): + """设置插件实例引用""" + self._plugin_instance = plugin_instance + + def set_bot_instance(self, bot_instance, platform_id=None, platform_name=None): + """ + 设置bot实例,支持指定平台ID + + 同时会创建对应的 PlatformAdapter(如果平台被支持)。 + """ + if not platform_id: + platform_id = self._get_platform_id_from_instance(bot_instance) + + if bot_instance and platform_id: + # 如果 bot_instance 没变,且已经有适配器,跳过重新创建,防止丢失内部状态(如缓存等) + old_instance = self._bot_instances.get(platform_id) + if bot_instance is old_instance and platform_id in self._adapters: + bot_self_id = self._extract_bot_self_id(bot_instance) + if bot_self_id and bot_self_id not in self._bot_self_ids: + self._bot_self_ids.append(str(bot_self_id)) + return + + self._bot_instances[platform_id] = bot_instance + + # 为 DDD 集成创建 PlatformAdapter + if platform_name is None: + platform_name = self._detect_platform_name(bot_instance) + + if platform_name and PlatformAdapterFactory.is_supported(platform_name): + adapter_config = { + "bot_self_ids": self._bot_self_ids.copy(), + "platform_id": str(platform_id), + "filter_bot_messages": self.config_manager.get_filter_bot_messages(), + "plugin_instance": self._plugin_instance, + } + platform_instance = self._platforms.get(str(platform_id)) + platform_config = getattr(platform_instance, "config", None) + if isinstance(platform_config, Mapping): + adapter_config["appid"] = platform_config.get("appid", "") + adapter = PlatformAdapterFactory.create( + platform_name, bot_instance, adapter_config + ) + if adapter: + # 如果有 context,传递给适配器 + if self._context is not None: + adapter.set_context(self._context) + self._adapters[platform_id] = adapter + logger.debug( + f"已为 {platform_id} ({platform_name}) 创建 PlatformAdapter" + ) + + # 自动提取机器人 ID + bot_self_id = self._extract_bot_self_id(bot_instance) + if bot_self_id and bot_self_id not in self._bot_self_ids: + self._bot_self_ids.append(str(bot_self_id)) + + def set_bot_self_ids(self, bot_self_ids): + """设置机器人 ID 列表(支持单个 ID 或 ID 列表)""" + if isinstance(bot_self_ids, list): + self._bot_self_ids = [str(uid) for uid in bot_self_ids if uid] + elif bot_self_ids: + self._bot_self_ids = [str(bot_self_ids)] + + # 同步更新所有现有适配器的 ID 列表 + for adapter in self._adapters.values(): + if hasattr(adapter, "bot_self_ids"): + adapter.bot_self_ids = self._bot_self_ids.copy() + + def get_bot_instance(self, platform_id=None): + """获取指定平台的bot实例,如果不指定则返回第一个可用的实例""" + if platform_id: + # 如果指定了平台ID,尝试获取 + instance = self._bot_instances.get(platform_id) + if not instance and platform_id in self._platforms: + self._refresh_from_stored_platforms() + instance = self._bot_instances.get(platform_id) + return instance + + # 没有指定平台ID + if not self._bot_instances and self._platforms: + self._refresh_from_stored_platforms() + + if self._bot_instances: + # 如果只有一个实例,直接返回 + if len(self._bot_instances) == 1: + return list(self._bot_instances.values())[0] + + # 如果有多个实例,必须指定 platform_id + logger.error( + f"存在多个Bot实例 {list(self._bot_instances.keys())} 但未指定 platform_id," + "无法确定使用哪个实例。请明确指定 platform_id。" + ) + return None + + # 没有任何平台可用 + logger.error("没有任何可用的bot实例") + return None + + def _refresh_from_stored_platforms(self): + """尝试从已存储的平台对象中刷新 bot 实例 (Lazy Load)""" + for platform_id, platform in self._platforms.items(): + bot_client = None + # Lark 平台优先使用 API client,避免拿到仅支持长连接的 ws client + bot_client = getattr(platform, "lark_api", None) + # 优先尝试 get_client() + get_client = getattr(platform, "get_client", None) + if not bot_client and callable(get_client): + bot_client = get_client() + + # 如果 get_client() 返回 None,尝试直接访问属性 + if not bot_client: + bot_client = getattr(platform, "bot", None) + if not bot_client: + # AstrBot v4.14.4 DiscordPlatformAdapter 使用 'client' 属性 + bot_client = getattr(platform, "client", None) + + if bot_client: + # 检查是否已存在且是否发生变化(防止重复创建适配器) + old_client = self._bot_instances.get(platform_id) + + # 如果 client 对象没变且已经有适配器,跳过 + if bot_client is old_client and platform_id in self._adapters: + continue + + platform_name = None + metadata_obj = getattr(platform, "metadata", None) + if metadata_obj is not None: + # 优先使用 type + type_val = getattr(metadata_obj, "type", None) + if isinstance(type_val, str): + platform_name = type_val + else: + name_val = getattr(metadata_obj, "name", None) + if isinstance(name_val, str): + platform_name = name_val + + # 兼容不同版本的元数据获取 + if not platform_name: + meta = getattr(platform, "meta", None) + if callable(meta): + try: + metadata = meta() + platform_name = getattr(metadata, "name", None) + except Exception: + pass + + # 后备检测:如果不支持名称 + if not platform_name or not PlatformAdapterFactory.is_supported( + str(platform_name) + ): + detected = self._detect_platform_name(bot_client) + if detected: + platform_name = detected + + self.set_bot_instance(bot_client, platform_id, platform_name) + logger.info(f"已刷新/发现平台 {platform_id} 的 bot 实例 (变动或懒加载)") + + def get_all_bot_instances(self) -> dict: + """获取所有已加载的bot实例 {platform_id: bot_instance}""" + return self._bot_instances.copy() + + def get_platform_count(self) -> int: + """获取当前已加载的平台数量""" + return len(self._bot_instances) + + def get_platform_ids(self) -> list[str]: + """获取所有已加载的平台 ID 列表""" + return list(self._bot_instances.keys()) + + def has_bot_instance(self) -> bool: + """检查是否有可用的bot实例""" + return bool(self._bot_instances) + + def has_bot_self_id(self) -> bool: + """检查是否有配置的机器人 ID""" + return bool(self._bot_self_ids) + + def is_ready_for_auto_analysis(self) -> bool: + """检查是否准备好进行了自动分析""" + if not self.has_bot_instance(): + logger.debug("[BotManager] 自动分析就绪检查失败:没有可用的 bot 实例。") + return False + + if not self.has_bot_self_id(): + # 允许在没有配置/自动提取到 ID 的情况下尝试,但记录调试信息 + # 这有助于诊断某些平台(如 Telegram)自动获取 ID 失败的情况 + logger.debug( + "[BotManager] 自动分析就绪检查警告:bot_self_ids 列表为空。可能会影响消息过滤能力。" + ) + # 为了解决 #128 及其后续反馈,我们将此检查放宽 + # 只要有 bot 实例就可以尝试运行 + return True + + return True + + def _get_platform_id_from_instance(self, bot_instance): + """从bot实例获取平台ID""" + if hasattr(bot_instance, "platform") and isinstance(bot_instance.platform, str): + return bot_instance.platform + return self._default_platform + + def _detect_platform_name(self, bot_instance) -> str | None: + """ + 从 bot 实例检测平台名称,用于创建适配器。 + + 返回平台名称如 'aiocqhttp', 'discord' 等。 + """ + # 优先使用 platform 属性 + if hasattr(bot_instance, "platform"): + platform = bot_instance.platform + if isinstance(platform, str): + return platform + + # 检查已知的 API 特征(平台无关的方式) + # OneBot/aiocqhttp 特征: 有 call_action 方法 + if hasattr(bot_instance, "call_action"): + return "aiocqhttp" + + # 使用工厂的已注册平台列表进行类名匹配 + class_name = type(bot_instance).__name__.lower() + for platform_name in PlatformAdapterFactory.get_supported_platforms(): + if platform_name in class_name: + return platform_name + + # 通用类名模式匹配(用于尚未注册的平台) + known_patterns = { + "cqhttp": "aiocqhttp", + "onebot": "aiocqhttp", + } + for pattern, platform in known_patterns.items(): + if pattern in class_name: + return platform + + return None + + # ==================== DDD 集成方法 ==================== + + def get_adapter(self, platform_id: str | None = None) -> PlatformAdapter | None: + """ + 获取指定平台的 PlatformAdapter。 + + 支持平台实例 ID 精确匹配、大小写不敏感匹配、协议别名匹配 (如 qq -> aiocqhttp) 与单实例兜底。 + """ + # 如果没有任何适配器,尝试全局刷新一次 + if not self._adapters: + self._refresh_from_stored_platforms() + + if not platform_id or str(platform_id).lower().strip() in ( + "auto", + "default", + "all", + "none", + "", + ): + if self._adapters: + if len(self._adapters) == 1: + return list(self._adapters.values())[0] + # 多个适配器且未指定,优先返回第一个就绪的适配器 + for adp in self._adapters.values(): + if adp: + return adp + return None + + # 检查存储的平台实例是否有最新变动 + if platform_id in self._platforms: + self._refresh_from_stored_platforms() + + # 1. 精确匹配平台 ID + if platform_id in self._adapters: + return self._adapters[platform_id] + + # 2. 大小写不敏感匹配 + p_id_lower = str(platform_id).lower().strip() + for k, adp in self._adapters.items(): + if k.lower().strip() == p_id_lower: + return adp + + # 3. 通过 PlatformAdapterFactory 注册类型匹配 + if PlatformAdapterFactory.is_supported(p_id_lower): + expected_adapter_cls = PlatformAdapterFactory._adapters.get(p_id_lower) + if expected_adapter_cls: + for k, adp in self._adapters.items(): + if isinstance(adp, expected_adapter_cls): + logger.info( + f"[BotManager] 平台类型 '{platform_id}' 匹配到已注册适配器 '{k}'" + ) + return adp + + # 4. 单实例容错兜底:若系统仅有 1 个活跃适配器,自动作为兜底并记录日志 + if len(self._adapters) == 1: + fallback_k, fallback_adp = list(self._adapters.items())[0] + logger.info( + f"[BotManager] 未找到指定平台 '{platform_id}',系统当前仅有 1 个活跃适配器 '{fallback_k}',已自动作为容错兜底使用" + ) + return fallback_adp + + logger.warning( + f"[BotManager] 未找到匹配平台 '{platform_id}' 的适配器。当前已有适配器列表: {list(self._adapters.keys())}" + ) + return None + + def get_adapter_platform_id(self, adapter: Any) -> str: + """获取适配器对应的真实平台实例 ID(如 'nuits')""" + if not adapter: + return "" + # 1. 优先从 _adapters 映射表反查实例 ID + for p_id, adp in self._adapters.items(): + if adp is adapter: + return str(p_id) + # 2. 从 adapter 属性读取 + p_id = getattr(adapter, "platform_id", None) + if callable(p_id): + p_id = p_id() + if p_id: + return str(p_id) + # 3. 兜底读取 platform_name + return str(getattr(adapter, "platform_name", "") or "") + + def get_all_adapters(self) -> dict: + """获取所有 PlatformAdapter 实例 {platform_id: adapter}""" + return self._adapters.copy() + + def has_adapter(self, platform_id: str | None = None) -> bool: + """检查指定平台是否有适配器""" + if platform_id: + return self.get_adapter(platform_id) is not None + return bool(self._adapters) + + def can_analyze(self, platform_id: str | None = None) -> bool: + """使用 DDD 能力检查平台是否支持分析""" + adapter = self.get_adapter(platform_id) + if adapter: + return adapter.get_capabilities().can_analyze() + return False + + async def auto_discover_bot_instances(self): + """ + 自动发现所有可用的bot实例 + + 同时为每个发现的 bot 创建对应的 PlatformAdapter。 + """ + platform_manager = getattr(self._context, "platform_manager", None) + get_insts = getattr(platform_manager, "get_insts", None) + if self._context is None or not callable(get_insts): + return {} + + # 使用新版 API 获取所有平台实例 + raw_platforms = get_insts() + if isinstance(raw_platforms, list): + platforms: list[object] = raw_platforms + elif isinstance(raw_platforms, tuple): + platforms = list(raw_platforms) + else: + logger.warning( + "auto_discover_bot_instances: get_insts() returned non-iterable value." + ) + return {} + discovered = {} + + logger.info( + f"auto_discover_bot_instances: 在管理器中发现 {len(platforms)} 个平台。" + ) + + for platform in platforms: + # 获取bot实例 + bot_client = None + bot_client = getattr(platform, "lark_api", None) + platform_get_client = getattr(platform, "get_client", None) + if not bot_client and callable(platform_get_client): + bot_client = platform_get_client() + + if not bot_client: + bot_client = getattr(platform, "bot", None) + if not bot_client: + bot_client = getattr(platform, "client", None) + + # 健壮地获取元数据 + metadata = getattr(platform, "metadata", None) + platform_meta_method = getattr(platform, "meta", None) + if not metadata and callable(platform_meta_method): + try: + metadata = platform_meta_method() + except Exception: + pass + + # 检查是否有有效的元数据和ID + platform_id = None + if metadata: + metadata_id = getattr(metadata, "id", None) + if metadata_id is not None: + platform_id = metadata_id + elif isinstance(metadata, Mapping): + platform_id = metadata.get("id") + + if platform_id: + # 确保平台 ID 是 str + platform_id = str(platform_id) + + # 知识点发现: 记录元数据以调试自定义 ID + logger.info( + f"[群分析插件 BotManager]: Log metadata for debugging custom IDs ,Platform: {platform_id}, Metadata Type: {getattr(metadata, 'type', 'N/A') if not isinstance(metadata, Mapping) else metadata.get('type', 'N/A')}, Metadata Name: {getattr(metadata, 'name', 'N/A') if not isinstance(metadata, Mapping) else metadata.get('name', 'N/A')}" + ) + + # 从元数据检测平台名称 + platform_name = None + # 优先使用 type + type_val = getattr(metadata, "type", None) + if isinstance(type_val, str): + platform_name = type_val + elif isinstance(metadata, Mapping): + dict_type = metadata.get("type") + if isinstance(dict_type, str): + platform_name = dict_type + if not platform_name: + name_val = getattr(metadata, "name", None) + if isinstance(name_val, str): + platform_name = name_val + elif isinstance(metadata, Mapping): + dict_name = metadata.get("name") + if isinstance(dict_name, str): + platform_name = dict_name + + # 验证此平台名称是否受支持,如果不支持,尝试从bot实例检测(如果可用) + if ( + not platform_name + or not PlatformAdapterFactory.is_supported(str(platform_name)) + ) and bot_client: + detected = self._detect_platform_name(bot_client) + if detected: + platform_name = detected + + logger.debug( + f"发现平台: {platform_id} ({platform_name}), 客户端就绪: {bool(bot_client)}" + ) + + # 无论bot客户端状态如何,都存储平台实例 + self._platforms[platform_id] = platform + + if bot_client: + logger.info( + f"[BotManager] 为平台 {platform_id} ({platform_name}) 注册 bot 实例" + ) + self.set_bot_instance(bot_client, platform_id, platform_name) + discovered[platform_id] = bot_client + else: + logger.info( + f"发现平台 {platform_id} 但客户端未就绪。将进行懒加载。" + ) + discovered[platform_id] = platform + + if self._adapters: + logger.info( + f"已创建 {len(self._adapters)} 个 PlatformAdapter: " + f"{list(self._adapters.keys())}" + ) + + return discovered + + async def initialize_from_config(self): + """从配置初始化bot管理器""" + # 设置配置的bot ID 列表 + bot_self_ids = self.config_manager.get_bot_self_ids() + if bot_self_ids: + self.set_bot_self_ids(bot_self_ids) + + # 自动发现所有bot实例 + discovered = await self.auto_discover_bot_instances() + self._is_initialized = True + + return discovered + + def get_status_info(self) -> dict[str, object]: + """获取bot管理器状态信息""" + adapter_info = {} + for pid, adapter in self._adapters.items(): + caps = adapter.get_capabilities() + adapter_info[pid] = { + "platform_name": caps.platform_name, + "can_analyze": caps.can_analyze(), + "supports_image": caps.supports_image_message, + } + + return { + "has_bot_instance": self.has_bot_instance(), + "bot_self_ids": self._bot_self_ids, + "platform_count": len(self._bot_instances), + "platforms": list(self._bot_instances.keys()), + "adapters": adapter_info, # DDD 集成信息 + "ready_for_auto_analysis": self.is_ready_for_auto_analysis(), + } + + def update_from_event(self, event): + """从事件更新bot实例(用于手动命令)""" + # 兼容不同平台的 bot 实例属性名 (OneBot 使用 bot, Discord 使用 client) + bot_instance = getattr(event, "bot", None) or getattr(event, "client", None) + + if bot_instance: + # 从事件中获取平台ID + platform_id = None + if hasattr(event, "get_platform_id"): + platform_id = event.get_platform_id() + elif hasattr(event, "platform_meta") and hasattr(event.platform_meta, "id"): + platform_id = event.platform_meta.id + elif hasattr(event, "platform") and isinstance(event.platform, str): + platform_id = event.platform + + self.set_bot_instance(bot_instance, platform_id) + + # 优先从事件中提取机器人自身 ID,避免获取到 functools.partial 等异常对象 + bot_self_id = None + if hasattr(event, "get_self_id"): + val = event.get_self_id() + if ( + val + and isinstance(val, (str, int)) + and not callable(val) + and "partial" not in str(val) + ): + bot_self_id = str(val) + + if not bot_self_id: + bot_self_id = self._extract_bot_self_id(bot_instance) + + if bot_self_id: + # 将单个ID转换为列表,保持统一处理 + self.set_bot_self_ids([bot_self_id]) + else: + # 如果bot实例没有ID,尝试使用配置的ID列表 + config_self_ids = self.config_manager.get_bot_self_ids() + if config_self_ids: + self.set_bot_self_ids(config_self_ids) + return True + return False + + def _extract_bot_self_id(self, bot_instance): + """从bot实例中提取自身ID(单个)""" + return self._extract_bot_self_id_impl(bot_instance) + + def _extract_bot_self_id_impl(self, bot_instance): + """从bot实例中提取ID(通用实现)""" + # 尝试多种方式获取bot ID,并严格限制类型为 str/int 且不可调用,防止 OneBot (aiocqhttp) 动态代理返回 functools.partial + if hasattr(bot_instance, "self_id") and bot_instance.self_id: + val = bot_instance.self_id + if isinstance(val, (str, int)) and not callable(val): + return str(val) + if hasattr(bot_instance, "user_id") and bot_instance.user_id: + val = bot_instance.user_id + if isinstance(val, (str, int)) and not callable(val): + return str(val) + # Discord.py style: client.user.id + if hasattr(bot_instance, "user") and hasattr(bot_instance.user, "id"): + val = bot_instance.user.id + if isinstance(val, (str, int)) and not callable(val): + return str(val) + # python-telegram-bot style: bot.id + if hasattr(bot_instance, "id") and bot_instance.id: + val = bot_instance.id + if isinstance(val, (str, int)) and not callable(val): + return str(val) + return None + + def validate_for_message_fetching(self, group_id: str) -> bool: + """验证是否可以进行消息获取""" + return self.has_bot_instance() and bool(group_id) + + def should_filter_bot_message(self, sender_id: str) -> bool: + """判断是否应该过滤bot自己的消息(支持多个ID)""" + if not self._bot_self_ids: + return False + + sender_id_str = str(sender_id) + # 检查是否在ID列表中 + return sender_id_str in self._bot_self_ids + + def is_plugin_enabled(self, platform_id: str, plugin_name: str) -> bool: + """检查指定平台是否启用了该插件""" + if platform_id not in self._platforms: + return True + + platform = self._platforms[platform_id] + platform_config = getattr(platform, "config", None) + if not isinstance(platform_config, dict): + return True + + plugin_set = platform_config.get("plugin_set", ["*"]) + + if plugin_set is None: + return False + + if "*" in plugin_set: + return True + + return plugin_name in plugin_set diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/factory.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/factory.py new file mode 100644 index 0000000..973dccb --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/factory.py @@ -0,0 +1,111 @@ +""" +平台适配器工厂 +""" + +from __future__ import annotations + +from collections.abc import Mapping + +from ...utils.logger import logger +from .base import PlatformAdapter + + +class PlatformAdapterFactory: + """ + 平台适配器工厂 + + 根据平台名称创建适配器实例。 + 使用注册表模式便于扩展。 + """ + + _adapters: dict[str, type[PlatformAdapter]] = {} + + @classmethod + def register(cls, platform_name: str, adapter_class: type[PlatformAdapter]): + """注册新适配器""" + cls._adapters[platform_name.lower()] = adapter_class + + @classmethod + def create( + cls, + platform_name: str, + bot_instance: object, + config: Mapping[str, object] | None = None, + ) -> PlatformAdapter | None: + """ + 创建平台适配器 + + 参数: + platform_name: 平台名称(如 "aiocqhttp"、"telegram") + bot_instance: AstrBot 机器人实例 + config: 配置字典 + + 返回: + 平台适配器实例,如果不支持则返回 None + """ + adapter_class = cls._adapters.get(platform_name.lower()) + + if adapter_class is None: + return None + + try: + return adapter_class(bot_instance, config) + except Exception: + # 记录异常,但不崩溃 + logger.error(f"为 {platform_name} 创建适配器时出错", exc_info=True) + return None + + @classmethod + def get_supported_platforms(cls) -> list[str]: + """获取所有支持的平台名称""" + return list(cls._adapters.keys()) + + @classmethod + def is_supported(cls, platform_name: str) -> bool: + """检查平台是否被支持""" + return platform_name.lower() in cls._adapters + + +# 导入适配器以注册它们 +def _register_adapters(): + try: + from .adapters.onebot_adapter import OneBotAdapter + + PlatformAdapterFactory.register("aiocqhttp", OneBotAdapter) + PlatformAdapterFactory.register("onebot", OneBotAdapter) + except ImportError: + pass + + try: + from .adapters.discord_adapter import DiscordAdapter + + PlatformAdapterFactory.register("discord", DiscordAdapter) + PlatformAdapterFactory.register("discord_bot", DiscordAdapter) # 添加别名 + except ImportError: + pass + + try: + from .adapters.telegram_adapter import TelegramAdapter + + PlatformAdapterFactory.register("telegram", TelegramAdapter) + except ImportError: + pass + + try: + from .adapters.lark_adapter import LarkAdapter + + PlatformAdapterFactory.register("lark", LarkAdapter) + PlatformAdapterFactory.register("feishu", LarkAdapter) + except ImportError: + pass + + try: + from .adapters.qq_official_adapter import QQOfficialAdapter + + PlatformAdapterFactory.register("qq_official", QQOfficialAdapter) + PlatformAdapterFactory.register("qq_official_webhook", QQOfficialAdapter) + except ImportError: + pass + + +_register_adapters() diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/napcat_stream.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/napcat_stream.py new file mode 100644 index 0000000..bf9071b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/napcat_stream.py @@ -0,0 +1,89 @@ +"""通过 NapCat Stream API 上传大文件。""" + +from __future__ import annotations + +import asyncio +import base64 +import hashlib +import math +import uuid +from pathlib import Path +from typing import Any + +from ...utils.logger import logger + + +def _calculate_sha256(file_path: Path) -> str: + """计算文件校验和,避免将完整文件保留在内存中。""" + hasher = hashlib.sha256() + with file_path.open("rb") as file: + while chunk := file.read(64 * 1024): + hasher.update(chunk) + return hasher.hexdigest() + + +async def upload_file_stream(bot: Any, file_path: str | Path) -> str | None: + """通过当前 OneBot 连接上传本地文件。 + + Args: + bot: 提供 ``call_action`` 的 OneBot 客户端。 + file_path: 待上传且已存在的本地文件。 + + Returns: + NapCat 返回的临时文件路径;Stream API 不可用或上传失败时返回 ``None``。 + """ + if not hasattr(bot, "call_action"): + return None + + path = Path(file_path) + if not path.is_file() or path.stat().st_size <= 0: + return None + + chunk_size = 64 * 1024 + file_size = path.stat().st_size + total_chunks = math.ceil(file_size / chunk_size) + stream_id = str(uuid.uuid4()) + + try: + expected_sha256 = await asyncio.to_thread(_calculate_sha256, path) + if path.stat().st_size != file_size: + raise RuntimeError("上传前文件大小发生变化") + + with path.open("rb") as file: + for chunk_index in range(total_chunks): + chunk = file.read(chunk_size) + if not chunk: + raise RuntimeError("文件在所有分块上传完成前提前结束") + response = await bot.call_action( + "upload_file_stream", + stream_id=stream_id, + chunk_data=base64.b64encode(chunk).decode("ascii"), + chunk_index=chunk_index, + total_chunks=total_chunks, + file_size=file_size, + expected_sha256=expected_sha256, + filename=path.name, + file_retention=30_000, + ) + if isinstance(response, dict) and ( + response.get("status") == "failed" + or response.get("retcode") not in (None, 0) + ): + raise RuntimeError(f"NapCat 拒绝接收分块: {response}") + + response = await bot.call_action( + "upload_file_stream", stream_id=stream_id, is_complete=True + ) + if not isinstance(response, dict): + return None + data = response.get("data") + payload = data if isinstance(data, dict) else response + for key in ("file_path", "file", "path"): + uploaded_path = payload.get(key) + if isinstance(uploaded_path, str) and uploaded_path.strip(): + return uploaded_path.strip() + except asyncio.CancelledError: + raise + except Exception as exc: + logger.warning(f"[NapCat 流式上传] {path.name} 上传失败: {exc}") + return None diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/template_preview/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/template_preview/__init__.py new file mode 100644 index 0000000..e8175ea --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/template_preview/__init__.py @@ -0,0 +1,6 @@ +"""平台模板预览交互能力。""" + +from .router import TemplatePreviewRouter +from .telegram_preview_handler import TelegramTemplatePreviewHandler + +__all__ = ["TelegramTemplatePreviewHandler", "TemplatePreviewRouter"] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/template_preview/router.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/template_preview/router.py new file mode 100644 index 0000000..fc4ca5b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/template_preview/router.py @@ -0,0 +1,63 @@ +"""模板预览平台路由。""" + +from __future__ import annotations + +from typing import Any + + +class TemplatePreviewRouter: + """统一分发不同平台的模板预览处理器。""" + + def __init__(self, handlers: list[Any] | None = None): + self._handlers: list[Any] = handlers or [] + + def add_handler(self, handler: Any) -> None: + """注册一个平台处理器。""" + self._handlers.append(handler) + + async def ensure_handlers_registered(self, context: Any) -> None: + """让处理器完成初始化(如注册回调)。""" + for handler in self._handlers: + register_func = getattr( + handler, "ensure_callback_handlers_registered", None + ) + if callable(register_func): + await register_func(context) + + async def unregister_handlers(self) -> None: + """统一注销处理器资源。""" + for handler in self._handlers: + unregister_func = getattr(handler, "unregister_callback_handlers", None) + if callable(unregister_func): + await unregister_func() + + async def handle_view_templates( + self, + event: Any, + platform_id: str, + available_templates: list[str], + ) -> tuple[bool, list[Any]]: + """ + 处理 /查看模板 交互。 + + 返回: + - handled: 是否已由某个平台处理器接管 + - results: 需要回传给框架的消息结果列表 + """ + for handler in self._handlers: + supports_func = getattr(handler, "supports", None) + if not callable(supports_func) or not supports_func(event): + continue + + handle_func = getattr(handler, "handle_view_templates", None) + if not callable(handle_func): + continue + + handled, results = await handle_func( + event=event, + platform_id=platform_id, + available_templates=available_templates, + ) + return handled, results + + return False, [] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/template_preview/telegram_preview_handler.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/template_preview/telegram_preview_handler.py new file mode 100644 index 0000000..bbb8895 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/platform/template_preview/telegram_preview_handler.py @@ -0,0 +1,676 @@ +"""Telegram 模板预览交互处理。""" + +from __future__ import annotations + +import re +import time +import uuid +from dataclasses import dataclass +from typing import TYPE_CHECKING, Any + +from ....utils.logger import logger + +if TYPE_CHECKING: + from astrbot.api.event import AstrMessageEvent + + from ....application.commands.template_command_service import TemplateCommandService + from ...config.config_manager import ConfigManager + +try: + from telegram import ( + InlineKeyboardButton, + InlineKeyboardMarkup, + InputMediaDocument, + InputMediaPhoto, + Update, + ) + from telegram.error import BadRequest + from telegram.ext import CallbackQueryHandler, ContextTypes + + TELEGRAM_RUNTIME_AVAILABLE = True +except Exception: + TELEGRAM_RUNTIME_AVAILABLE = False + InlineKeyboardButton = None + InlineKeyboardMarkup = None + InputMediaPhoto = None + InputMediaDocument = None + Update = None + BadRequest = Exception + CallbackQueryHandler = None + ContextTypes = None + + +@dataclass +class _PreviewSession: + token: str + platform_id: str + chat_id: int | str + message_thread_id: int | None + message_id: int + requester_id: int + templates: list[str] + index: int + created_at: float + + @property + def current_template(self) -> str: + return self.templates[self.index] + + +class TelegramTemplatePreviewHandler: + """Telegram 按钮预览处理器(←/确定/→)。""" + + _SESSION_TTL_SECONDS = 2 * 60 * 60 + _MAX_SESSIONS = 200 + _CONNECT_TIMEOUT = 20 + _READ_TIMEOUT = 120 + _WRITE_TIMEOUT = 120 + _POOL_TIMEOUT = 20 + + def __init__( + self, + config_manager: ConfigManager, + template_service: TemplateCommandService, + ): + self.config_manager = config_manager + self.template_service = template_service + self._sessions: dict[str, _PreviewSession] = {} + self._registered_platform_ids: set[str] = set() + self._handlers: dict[str, tuple[Any, Any]] = {} + self._platform_clients: dict[str, Any] = {} + self._callback_prefix = f"qda_tpl_{uuid.uuid4().hex[:8]}" + + @staticmethod + def supports(event: AstrMessageEvent) -> bool: + """判断是否 Telegram 事件。""" + try: + return (event.get_platform_name() or "").lower() == "telegram" + except Exception: + return False + + # 向后兼容旧调用名 + is_telegram_event = supports + + async def ensure_callback_handlers_registered(self, context: Any) -> None: + """为所有 Telegram 平台注册按钮回调处理器。""" + if not TELEGRAM_RUNTIME_AVAILABLE: + return + if not context or not hasattr(context, "platform_manager"): + return + + platforms = context.platform_manager.get_insts() + seen_platform_ids: set[str] = set() + for platform in platforms: + platform_id, platform_name = self._extract_platform_meta(platform) + if platform_name != "telegram": + continue + if not platform_id: + continue + + seen_platform_ids.add(platform_id) + client = self._extract_platform_client(platform) + if client is not None: + self._platform_clients[platform_id] = client + + application = getattr(platform, "application", None) + if not application: + continue + + existing = self._handlers.get(platform_id) + if existing: + old_application, old_handler = existing + if old_application is application: + self._registered_platform_ids.add(platform_id) + continue + + # 平台对象热替换:解绑旧 application 上的 handler 后重绑 + try: + old_application.remove_handler(old_handler) + logger.info( + f"[TemplatePreview][Telegram] 检测到 application 变更,已解绑旧回调: platform_id={platform_id}" + ) + except Exception as e: + logger.debug( + f"[TemplatePreview][Telegram] 解绑旧回调失败: platform_id={platform_id}, err={e}" + ) + self._handlers.pop(platform_id, None) + self._registered_platform_ids.discard(platform_id) + + try: + handler = CallbackQueryHandler( + self._on_callback_query, + pattern=rf"^{re.escape(self._callback_prefix)}:", + ) + application.add_handler(handler) + self._registered_platform_ids.add(platform_id) + self._handlers[platform_id] = (application, handler) + logger.info( + f"[TemplatePreview][Telegram] 已注册回调处理器: platform_id={platform_id}" + ) + except Exception as e: + logger.warning( + f"[TemplatePreview][Telegram] 注册回调处理器失败: platform_id={platform_id}, err={e}" + ) + + # 兜底清理:平台下线后移除残留 handler,避免资源泄漏 + stale_ids = [ + platform_id + for platform_id in list(self._handlers.keys()) + if platform_id not in seen_platform_ids + ] + for stale_platform_id in stale_ids: + old_application, old_handler = self._handlers.pop(stale_platform_id) + try: + old_application.remove_handler(old_handler) + logger.info( + f"[TemplatePreview][Telegram] 已清理离线平台回调: platform_id={stale_platform_id}" + ) + except Exception as e: + logger.debug( + f"[TemplatePreview][Telegram] 清理离线平台回调失败: platform_id={stale_platform_id}, err={e}" + ) + self._registered_platform_ids.discard(stale_platform_id) + self._platform_clients.pop(stale_platform_id, None) + + async def unregister_callback_handlers(self) -> None: + """卸载已注册的回调处理器(插件终止时调用)。""" + if not TELEGRAM_RUNTIME_AVAILABLE: + return + + for platform_id, (application, handler) in list(self._handlers.items()): + try: + application.remove_handler(handler) + logger.info( + f"[TemplatePreview][Telegram] 已移除回调处理器: platform_id={platform_id}" + ) + except Exception as e: + logger.debug( + f"[TemplatePreview][Telegram] 移除回调处理器失败: platform_id={platform_id}, err={e}" + ) + self._handlers.clear() + self._registered_platform_ids.clear() + self._platform_clients.clear() + + async def send_preview_message( + self, + event: AstrMessageEvent, + platform_id: str, + available_templates: list[str], + ) -> bool: + """ + 在 Telegram 中发送可交互模板预览消息。 + + 返回: + - True: 已由本处理器发送消息(调用方不应再走默认回复) + - False: 无法处理,调用方应走原有降级路径 + """ + if not TELEGRAM_RUNTIME_AVAILABLE: + return False + if not available_templates: + return False + + client = self._get_event_client(event, platform_id) + if client is None: + logger.warning("[TemplatePreview][Telegram] 无法获取 Telegram client") + return False + + target = self._resolve_chat_target(event) + if target is None: + return False + chat_id, message_thread_id = target + + try: + requester_id = int(str(event.get_sender_id())) + except Exception: + logger.warning( + "[TemplatePreview][Telegram] sender_id 非法,无法创建交互会话" + ) + return False + + current_template = self.config_manager.get_report_template() + if current_template in available_templates: + index = available_templates.index(current_template) + else: + index = 0 + + token = uuid.uuid4().hex[:8] + keyboard = self._build_keyboard(token) + caption = self._build_caption( + template_name=available_templates[index], + index=index, + total=len(available_templates), + ) + + image_path = self.template_service.resolve_template_preview_path( + available_templates[index] + ) + if not image_path: + return False + + payload: dict[str, Any] = {"chat_id": chat_id, "reply_markup": keyboard} + if message_thread_id is not None: + payload["message_thread_id"] = message_thread_id + + try: + with open(image_path, "rb") as image_file: + sent_msg = await client.send_photo( + photo=image_file, + caption=caption, + connect_timeout=self._CONNECT_TIMEOUT, + read_timeout=self._READ_TIMEOUT, + write_timeout=self._WRITE_TIMEOUT, + pool_timeout=self._POOL_TIMEOUT, + **payload, + ) + except BadRequest as e: + if not self._is_photo_dimension_error(e): + raise + with open(image_path, "rb") as image_file: + sent_msg = await client.send_document( + document=image_file, + caption=caption, + connect_timeout=self._CONNECT_TIMEOUT, + read_timeout=self._READ_TIMEOUT, + write_timeout=self._WRITE_TIMEOUT, + pool_timeout=self._POOL_TIMEOUT, + **payload, + ) + + self._sessions[token] = _PreviewSession( + token=token, + platform_id=platform_id, + chat_id=chat_id, + message_thread_id=message_thread_id, + message_id=sent_msg.message_id, + requester_id=requester_id, + templates=available_templates.copy(), + index=index, + created_at=time.time(), + ) + self._cleanup_expired_sessions() + logger.info( + "[TemplatePreview][Telegram] 已发送交互预览: " + f"platform_id={platform_id} chat_id={chat_id} token={token} templates={len(available_templates)}" + ) + return True + + async def send_preview_image_fallback( + self, + event: AstrMessageEvent, + platform_id: str, + template_name: str, + ) -> bool: + """TG 回退路径:直接发送单张预览图(不经过 event.image_result)。""" + if not TELEGRAM_RUNTIME_AVAILABLE: + return False + + image_path = self.template_service.resolve_template_preview_path(template_name) + if not image_path: + return False + + client = self._get_event_client(event, platform_id) + if client is None: + logger.warning("[TemplatePreview][Telegram] 回退发图失败:无法获取 client") + return False + + target = self._resolve_chat_target(event) + if target is None: + return False + chat_id, message_thread_id = target + + payload: dict[str, Any] = { + "chat_id": chat_id, + "caption": f"🖼 当前模板预览: {template_name}", + "connect_timeout": self._CONNECT_TIMEOUT, + "read_timeout": self._READ_TIMEOUT, + "write_timeout": self._WRITE_TIMEOUT, + "pool_timeout": self._POOL_TIMEOUT, + } + if message_thread_id is not None: + payload["message_thread_id"] = message_thread_id + + try: + with open(image_path, "rb") as image_file: + await client.send_photo(photo=image_file, **payload) + except BadRequest as e: + if not self._is_photo_dimension_error(e): + raise + with open(image_path, "rb") as image_file: + await client.send_document(document=image_file, **payload) + return True + + async def handle_view_templates( + self, + event: AstrMessageEvent, + platform_id: str, + available_templates: list[str], + ) -> tuple[bool, list[Any]]: + """统一处理 Telegram 的 /查看模板 流程。""" + if not self.supports(event): + return False, [] + + results: list[Any] = [] + + async def _append_fallback_results() -> None: + current_template = self.config_manager.get_report_template() + template_list_str = "\n".join( + [f"【{i}】{t}" for i, t in enumerate(available_templates, start=1)] + ) + results.append( + event.plain_result( + f"""🎨 可用报告模板列表 +📌 当前使用: {current_template} + +{template_list_str} + +💡 使用 /设置模板 [序号] 切换""" + ) + ) + + try: + sent_preview = await self.send_preview_image_fallback( + event=event, + platform_id=platform_id, + template_name=current_template, + ) + if not sent_preview: + results.append(event.plain_result("⚠️ 当前模板预览图发送失败")) + except Exception as image_err: + logger.warning(f"[TemplatePreview][Telegram] 回退发图失败: {image_err}") + results.append(event.plain_result("⚠️ 当前模板预览图发送失败")) + + try: + sent = await self.send_preview_message( + event=event, + platform_id=platform_id, + available_templates=available_templates, + ) + if sent: + return True, results + await _append_fallback_results() + return True, results + except Exception as e: + logger.warning( + f"[TemplatePreview][Telegram] 交互预览发送失败,回退普通模式: {e}" + ) + await _append_fallback_results() + return True, results + + async def _on_callback_query( + self, update: Update, context: ContextTypes.DEFAULT_TYPE + ) -> None: + if not TELEGRAM_RUNTIME_AVAILABLE: + return + if not update.callback_query or not update.callback_query.data: + return + + self._cleanup_expired_sessions() + + query = update.callback_query + data = query.data + parts = data.split(":") + if len(parts) != 3: + await query.answer("无效操作", show_alert=False) + return + + _, token, action = parts + session = self._sessions.get(token) + if not session: + await query.answer("预览会话已过期,请重新发送 /查看模板", show_alert=True) + return + if time.time() - session.created_at > self._SESSION_TTL_SECONDS: + self._sessions.pop(token, None) + await query.answer("预览会话已过期,请重新发送 /查看模板", show_alert=True) + return + + if not query.from_user: + await query.answer("无法识别操作者", show_alert=False) + return + if int(query.from_user.id) != session.requester_id: + await query.answer("仅命令发起人可操作该预览", show_alert=True) + return + + if not query.message: + await query.answer("消息已失效", show_alert=False) + return + + if query.message.message_id != session.message_id or str( + query.message.chat_id + ) != str(session.chat_id): + await query.answer("预览状态不一致,请重新发送 /查看模板", show_alert=True) + return + + if action == "prev": + session.index = (session.index - 1) % len(session.templates) + await self._edit_preview_message(query, session) + await query.answer() + return + + if action == "next": + session.index = (session.index + 1) % len(session.templates) + await self._edit_preview_message(query, session) + await query.answer() + return + + if action == "apply": + template_name = session.current_template + self.config_manager.set_report_template(template_name) + await self._edit_preview_message(query, session, applied=True) + await query.answer(f"已设置模板: {template_name}", show_alert=False) + logger.info( + "[TemplatePreview][Telegram] 已应用模板: " + f"platform_id={session.platform_id} template={template_name} requester={session.requester_id}" + ) + return + + await query.answer("未知操作", show_alert=False) + + async def _edit_preview_message( + self, query: Any, session: _PreviewSession, applied: bool = False + ) -> None: + template_name = session.current_template + caption = self._build_caption( + template_name=template_name, + index=session.index, + total=len(session.templates), + applied=applied, + ) + keyboard = self._build_keyboard(session.token) + image_path = self.template_service.resolve_template_preview_path(template_name) + if not image_path: + await query.edit_message_caption( + caption=caption, + reply_markup=keyboard, + ) + return + + try: + with open(image_path, "rb") as image_file: + media = InputMediaPhoto(media=image_file, caption=caption) + await query.edit_message_media( + media=media, + reply_markup=keyboard, + connect_timeout=self._CONNECT_TIMEOUT, + read_timeout=self._READ_TIMEOUT, + write_timeout=self._WRITE_TIMEOUT, + pool_timeout=self._POOL_TIMEOUT, + ) + except BadRequest as e: + if "message is not modified" in str(e).lower(): + return + if self._is_photo_dimension_error(e): + try: + with open(image_path, "rb") as image_file: + media = InputMediaDocument(media=image_file, caption=caption) + await query.edit_message_media( + media=media, + reply_markup=keyboard, + connect_timeout=self._CONNECT_TIMEOUT, + read_timeout=self._READ_TIMEOUT, + write_timeout=self._WRITE_TIMEOUT, + pool_timeout=self._POOL_TIMEOUT, + ) + except BadRequest as document_error: + if "message is not modified" in str(document_error).lower(): + return + raise + return + raise + + def _build_keyboard(self, token: str) -> Any: + return InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text="←", + callback_data=f"{self._callback_prefix}:{token}:prev", + ), + InlineKeyboardButton( + text="确定", + callback_data=f"{self._callback_prefix}:{token}:apply", + ), + InlineKeyboardButton( + text="→", + callback_data=f"{self._callback_prefix}:{token}:next", + ), + ] + ] + ) + + def _build_caption( + self, + template_name: str, + index: int, + total: int, + applied: bool = False, + ) -> str: + current_active = self.config_manager.get_report_template() + active_mark = "✅ 当前生效" if template_name == current_active else "未生效" + apply_mark = "\n\n✅ 已应用该模板" if applied else "" + return ( + f"🎨 模板预览 ({index + 1}/{total})\n" + f"当前项: {template_name}\n" + f"状态: {active_mark}\n\n" + "操作: ← 上一个 / 确定应用 / → 下一个" + f"{apply_mark}" + ) + + @staticmethod + def _extract_platform_meta(platform: Any) -> tuple[str | None, str | None]: + metadata = getattr(platform, "metadata", None) + if not metadata and hasattr(platform, "meta"): + try: + metadata = platform.meta() + except Exception: + metadata = None + + platform_id = None + platform_name = None + if metadata: + if isinstance(metadata, dict): + platform_id = metadata.get("id") + platform_name = metadata.get("type") or metadata.get("name") + else: + platform_id = getattr(metadata, "id", None) + platform_name = getattr(metadata, "type", None) or getattr( + metadata, "name", None + ) + if platform_name: + platform_name = str(platform_name).lower() + if platform_id: + platform_id = str(platform_id) + return platform_id, platform_name + + @staticmethod + def _extract_platform_client(platform: Any) -> Any | None: + client = None + if hasattr(platform, "get_client"): + try: + client = platform.get_client() + except Exception: + client = None + if client is None: + client = getattr(platform, "client", None) + if client is None: + application = getattr(platform, "application", None) + if application is not None: + client = getattr(application, "bot", None) + if client is None: + return None + if not hasattr(client, "send_photo"): + return None + return client + + @staticmethod + def _get_raw_event_client(event: AstrMessageEvent) -> Any | None: + client = getattr(event, "client", None) + if client: + return client + return getattr(event, "bot", None) + + def _get_event_client( + self, event: AstrMessageEvent, platform_id: str | None = None + ) -> Any | None: + client = self._get_raw_event_client(event) + if client is not None and hasattr(client, "send_photo"): + return client + if platform_id: + cached = self._platform_clients.get(platform_id) + if cached is not None: + return cached + return None + + @staticmethod + def _resolve_chat_target( + event: AstrMessageEvent, + ) -> tuple[int | str, int | None] | None: + try: + group_id = event.get_group_id() + except Exception: + group_id = "" + + if group_id: + raw_target = str(group_id) + else: + try: + raw_target = str(event.get_sender_id()) + except Exception: + return None + + chat_part = raw_target + thread_id: int | None = None + if "#" in raw_target: + chat_part, thread_part = raw_target.split("#", 1) + try: + thread_id = int(thread_part) + except (TypeError, ValueError): + thread_id = None + + try: + chat_id: int | str = int(chat_part) + except (TypeError, ValueError): + chat_id = chat_part + return chat_id, thread_id + + def _cleanup_expired_sessions(self) -> None: + now = time.time() + expired_tokens = [ + token + for token, session in self._sessions.items() + if now - session.created_at > self._SESSION_TTL_SECONDS + ] + for token in expired_tokens: + self._sessions.pop(token, None) + + if len(self._sessions) <= self._MAX_SESSIONS: + return + + ordered = sorted(self._sessions.items(), key=lambda item: item[1].created_at) + overflow_count = len(self._sessions) - self._MAX_SESSIONS + for token, _ in ordered[:overflow_count]: + self._sessions.pop(token, None) + + @staticmethod + def _is_photo_dimension_error(err: Exception) -> bool: + message = str(err).lower() + return "photo_invalid_dimensions" in message or "invalid dimensions" in message diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/__init__.py new file mode 100644 index 0000000..52a016a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/__init__.py @@ -0,0 +1,9 @@ +""" +报告生成模块 +包含HTML、图片、文本报告生成功能 +""" + +from .generators import ReportGenerator +from .templates import HTMLTemplates + +__all__ = ["ReportGenerator", "HTMLTemplates"] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/dispatcher.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/dispatcher.py new file mode 100644 index 0000000..8c74677 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/dispatcher.py @@ -0,0 +1,643 @@ +import base64 +import os +import tempfile +import time +from collections.abc import Callable +from contextlib import nullcontext +from datetime import datetime +from pathlib import Path +from typing import Any +from urllib.parse import quote + +from ...shared.trace_context import TraceContext +from ...utils.logger import logger + + +class ReportDispatcher: + """ + 报告分发器 + 负责协调报告生成、格式选择、消息发送和失败重试 + """ + + def __init__( + self, + config_manager, + report_generator, + message_sender, + ): + self.config_manager = config_manager + self.report_generator = report_generator + self.message_sender = message_sender + self._html_render_func: Callable | None = None + + def set_html_render(self, render_func: Callable): + """设置 HTML 渲染函数 (运行时注入)""" + self._html_render_func = render_func + + def _is_qq_official(self, platform_id: str | None) -> bool: + adapter = self.message_sender.bot_manager.get_adapter(platform_id) + return bool(adapter and adapter.get_platform_name() == "qq_official") + + async def dispatch( + self, + group_id: str, + analysis_result: dict[str, Any], + platform_id: str | None = None, + ) -> bool: + """分发分析报告,并返回至少一种格式是否实际发送成功。""" + trace_id = TraceContext.get() + output_formats = self.config_manager.get_output_format() + if isinstance(output_formats, str): + output_formats = [output_formats] + + logger.info( + f"[{trace_id}] 正在分发群 {group_id} 的报告 (格式: {', '.join(output_formats)})" + ) + + dispatch_map = { + "image": self._dispatch_image, + "html": self._dispatch_html, + "text": self._dispatch_text, + } + sent_any = False + format_results: dict[str, bool] = {} + + for fmt in output_formats: + handler = dispatch_map.get(fmt) + if not handler: + logger.warning(f"[{trace_id}] 不支持的报告格式: {fmt}") + continue + try: + ok = bool(await handler(group_id, analysis_result, platform_id)) + format_results[fmt] = ok + sent_any = ok or sent_any + except Exception as e: + logger.error( + f"[{trace_id}] 群 {group_id} 的 {fmt} 报告发送异常: {e}", + exc_info=True, + ) + format_results[fmt] = False + + if sent_any: + logger.info( + f"[{trace_id}] 群 {group_id} 的报告分发完成,至少一种格式发送成功" + ) + else: + logger.error(f"[{trace_id}] 群 {group_id} 的报告分发失败,未发送任何报告") + return sent_any + + async def _dispatch_image( + self, group_id: str, analysis_result: dict[str, Any], platform_id: str | None + ) -> bool: + trace_id = TraceContext.get() + trace_ctx = TraceContext.current() + # 1. 检查渲染函数 + if not self._html_render_func: + logger.warning(f"[{trace_id}] 未设置 HTML 渲染函数,回退到文本模式。") + return await self._dispatch_text(group_id, analysis_result, platform_id) + + # 2. 生成图片 + image_url = None + html_content = None + try: + # 定义头像获取回调,请求小尺寸头像以优化性能 + async def avatar_url_getter(user_id: str): + if not platform_id: + return None + adapter = self.message_sender.bot_manager.get_adapter(platform_id) + if adapter and hasattr(adapter, "get_user_avatar_url"): + return await adapter.get_user_avatar_url(user_id, size=40) + return None + + trace = TraceContext.current() + override_theme = ( + trace.metadata.get("override_template_name") if trace else None + ) + template_theme = ( + override_theme + or getattr( + self.config_manager, "get_report_template", lambda: "scrapbook" + )() + ) + + if trace: + with trace.span( + "RENDER_REPORT", + {"format": "image", "template": template_theme}, + ): + ( + image_url, + html_content, + ) = await self.report_generator.generate_image_report( + analysis_result, + group_id, + self._html_render_func, + avatar_url_getter=avatar_url_getter, + avatar_cache_namespace=platform_id, + allow_alphanumeric_user_ids=self._is_qq_official(platform_id), + template_theme=template_theme, + ) + else: + ( + image_url, + html_content, + ) = await self.report_generator.generate_image_report( + analysis_result, + group_id, + self._html_render_func, + avatar_url_getter=avatar_url_getter, + avatar_cache_namespace=platform_id, + allow_alphanumeric_user_ids=self._is_qq_official(platform_id), + template_theme=template_theme, + ) + except Exception as e: + logger.error(f"[{trace_id}] Failed to generate image report: {e}") + # image_url and html_content remain None + + # 4. 发送图片 + sent = False + dest_filename: str | None = None + if image_url: + with ( + trace_ctx.span( + "DISPATCH_REPORT", + { + "platform": platform_id or "auto", + "group_id": group_id, + "formats": ["image"], + "format": "image", + }, + ) + if trace_ctx + else nullcontext() + ) as dispatch_span: + try: + reports_dir = self.report_generator.data_dir / "reports" + reports_dir.mkdir(parents=True, exist_ok=True) + ts_str = datetime.now().strftime("%Y%m%d_%H%M%S") + filename = ( + f"report_{group_id}_{ts_str}_{trace_id}.jpg" + if trace_id + else f"report_{group_id}_{ts_str}.jpg" + ) + dest = reports_dir / filename + dest_filename = dest.name + if os.path.exists(image_url): + import shutil + + shutil.copy2(image_url, dest) + elif image_url.startswith("base64://"): + data = base64.b64decode(image_url[9:]) + dest.write_bytes(data) + + # 关联到 TraceContext 并在数据库中更新元数据 + if trace_ctx: + rfiles = trace_ctx.metadata.setdefault("report_files", []) + if not any(rf.get("filename") == dest.name for rf in rfiles): + rfiles.append( + { + "filename": dest.name, + "path": str(dest.resolve()), + "format": "image", + "size_bytes": dest.stat().st_size + if dest.exists() + else 0, + "created_at": time.time(), + } + ) + from ...shared.trace_context import _global_trace_store + + if _global_trace_store is not None: + try: + _global_trace_store.save_trace(trace_ctx.to_dict()) + except Exception: + pass + except Exception as e: + logger.warning(f"[{trace_id}] 保存历史报告副本失败: {e}") + + caption = ( + TraceContext.make_report_caption() + if self.config_manager.get_show_report_caption() + else "" + ) + try: + sent = await self.message_sender.send_image_smart( + group_id, image_url, caption, platform_id + ) + except Exception as e: + logger.error(f"[{trace_id}] 图片报告发送异常: {e}", exc_info=True) + + # 5. 尝试上传到群文件/群相册(静默处理) + try: + await self._try_upload_image(group_id, image_url, platform_id) + except Exception as e: + logger.warning( + f"[{trace_id}] 图片报告备份失败,不影响发送状态: {e}" + ) + + if dispatch_span and isinstance(dispatch_span, dict): + dispatch_span.setdefault("payload", {}).update( + { + "platform": platform_id or "auto", + "formats": ["image"], + "format": "image", + "success": bool(sent), + "image_sent": bool(sent), + "report_file": dest_filename, + } + ) + if not sent: + dispatch_span["status"] = "warning" + dispatch_span["payload"]["warning"] = ( + "图片报告发送失败,已自动降级回退至文本报告" + ) + if trace_ctx: + trace_ctx.metadata["has_warnings"] = True + + if sent: + return True + + # 6. 最终回退:如果图片发送失败(包括生成失败或发送接口报错),直接尝试发送文本报告 + logger.warning( + f"[{trace_id}] Image dispatch failed, falling back to text report." + ) + return await self._dispatch_text(group_id, analysis_result, platform_id) + + async def _dispatch_html( + self, group_id: str, analysis_result: dict[str, Any], platform_id: str | None + ) -> bool: + trace_id = TraceContext.get() + trace_ctx = TraceContext.current() + + html_path = None + try: + + async def avatar_url_getter(user_id: str): + if not platform_id: + return None + adapter = self.message_sender.bot_manager.get_adapter(platform_id) + if adapter and hasattr(adapter, "get_user_avatar_url"): + return await adapter.get_user_avatar_url(user_id, size=40) + return None + + trace = TraceContext.current() + override_theme = ( + trace.metadata.get("override_template_name") if trace else None + ) + template_theme = ( + override_theme + or getattr( + self.config_manager, "get_report_template", lambda: "scrapbook" + )() + ) + + if trace: + with trace.span( + "RENDER_REPORT", + {"format": "html", "template": template_theme}, + ): + ( + html_path, + json_path, + ) = await self.report_generator.generate_html_report( + analysis_result, + group_id, + avatar_url_getter=avatar_url_getter, + avatar_cache_namespace=platform_id, + allow_alphanumeric_user_ids=self._is_qq_official(platform_id), + template_theme=template_theme, + trace_id=trace_id, + ) + else: + html_path, json_path = await self.report_generator.generate_html_report( + analysis_result, + group_id, + avatar_url_getter=avatar_url_getter, + avatar_cache_namespace=platform_id, + allow_alphanumeric_user_ids=self._is_qq_official(platform_id), + template_theme=template_theme, + trace_id=trace_id, + ) + except Exception as e: + logger.error(f"[{trace_id}] Failed to generate HTML report: {e}") + + html_filename: str | None = None + sent = False + if html_path: + with ( + trace_ctx.span( + "DISPATCH_REPORT", + { + "platform": platform_id or "auto", + "group_id": group_id, + "formats": ["html"], + "format": "html", + }, + ) + if trace_ctx + else nullcontext() + ) as dispatch_span: + try: + html_file = Path(html_path) + html_filename = html_file.name + if trace_ctx: + rfiles = trace_ctx.metadata.setdefault("report_files", []) + if not any( + rf.get("filename") == html_file.name for rf in rfiles + ): + rfiles.append( + { + "filename": html_file.name, + "path": str(html_file.resolve()), + "format": "html", + "size_bytes": html_file.stat().st_size + if html_file.exists() + else 0, + "created_at": time.time(), + } + ) + from ...shared.trace_context import _global_trace_store + + if _global_trace_store is not None: + try: + _global_trace_store.save_trace(trace_ctx.to_dict()) + except Exception: + pass + except Exception as e: + logger.warning(f"[{trace_id}] 关联 HTML 报告元数据失败: {e}") + + is_only_url = self.config_manager.get_html_only_url() + base_url = self.config_manager.get_html_base_url() + + if is_only_url: + if base_url and base_url.strip(): + # 获取配置的目录 + html_output_dir = self.config_manager.get_html_output_dir() + + # 若用户配置为空,使用默认目录 + if not html_output_dir: + html_output_dir = str( + self.report_generator.data_dir + / "self_hosted_html_reports" + ) + + # 计算相对路径并转换为URL + rel_path = os.path.relpath(html_path, html_output_dir) + url_path = rel_path.replace(os.sep, "/") + encoded_url_path = quote(url_path.lstrip("/"), safe="/") + report_url = f"{base_url.rstrip('/')}/{encoded_url_path}" + + sent = await self.message_sender.send_text( + group_id, + f"📊 今日群聊分析报告已生成:\n{report_url}", + platform_id, + ) + else: + logger.warning( + f"[{trace_id}] 群 {group_id} 开启了仅发送外链,但未配置 html_base_url,已进行降级,回退至发送 HTML 文件。" + ) + + if not sent: + caption = ( + self.report_generator.build_html_caption(html_path) + if self.config_manager.get_show_report_caption() + else "" + ) + sent = await self.message_sender.send_file( + group_id, + html_path, + caption=caption, + platform_id=platform_id, + ) + + if dispatch_span and isinstance(dispatch_span, dict): + dispatch_span.setdefault("payload", {}).update( + { + "platform": platform_id or "auto", + "formats": ["html"], + "format": "html", + "success": bool(sent), + "html_sent": bool(sent), + "html_file": html_filename, + } + ) + if not sent: + dispatch_span["status"] = "warning" + dispatch_span["payload"]["warning"] = ( + "HTML 报告发送失败,已自动降级回退至文本报告" + ) + if trace_ctx: + trace_ctx.metadata["has_warnings"] = True + + if sent: + return True + + logger.warning( + f"[{trace_id}] HTML dispatch failed, falling back to text report." + ) + return await self._dispatch_text(group_id, analysis_result, platform_id) + + async def _dispatch_text( + self, group_id: str, analysis_result: dict[str, Any], platform_id: str | None + ) -> bool: + """分发文本报告""" + logger.info(f"[分发器] 正在向群组 {group_id} 分发文本报告") + trace_ctx = TraceContext.current() + is_qq_official = self._is_qq_official(platform_id) + fallback_report = None + if is_qq_official: + ( + text_report, + fallback_report, + ) = await self.report_generator.generate_qq_official_markdown_report( + analysis_result, self._html_render_func + ) + else: + text_report = self.report_generator.generate_text_report(analysis_result) + adapter = self.message_sender.bot_manager.get_adapter(platform_id) + # 尝试通过适配器发送文本报告 + logger.info(f"[分发器] 正在尝试通过适配器发送文本报告。群: {group_id}") + + with ( + trace_ctx.span( + "DISPATCH_REPORT", + { + "platform": platform_id or "auto", + "group_id": group_id, + "formats": ["text"], + "format": "text", + }, + ) + if trace_ctx + else nullcontext() + ) as dispatch_span: + sent = False + try: + if adapter: + if is_qq_official: + sent = bool( + await adapter.send_text_report( + group_id, + text_report, + fallback_content=fallback_report, + ) + ) + else: + sent = bool( + await adapter.send_text_report(group_id, text_report) + ) + if not sent: + sent = bool( + await self.message_sender.send_text( + group_id, + f"📊 每日群聊分析报告:\n\n{text_report}", + platform_id, + ) + ) + except Exception as e: + logger.error( + f"[分发器] 发送文本报告最终失败。群: {group_id}, 错误: {e}" + ) + sent = False + + if dispatch_span and isinstance(dispatch_span, dict): + dispatch_span.setdefault("payload", {}).update( + { + "platform": platform_id or "auto", + "formats": ["text"], + "format": "text", + "success": bool(sent), + "text_sent": bool(sent), + } + ) + return sent + + # ================================================================ + # 图片报告上传到群文件 / 群相册(仅 QQ 平台 image 格式) + # ================================================================ + + async def _try_upload_image( + self, + group_id: str, + image_url: str, + platform_id: str | None, + ): + """ + 尝试将图片报告上传到群文件和/或群相册。 + + 仅在配置启用且平台为 OneBot 时执行,失败静默处理。 + """ + enable_file = self.config_manager.get_enable_group_file_upload() + enable_album = self.config_manager.get_enable_group_album_upload() + if not enable_file and not enable_album: + return + + # 仅 OneBot 平台支持 + adapter = self._get_onebot_adapter(platform_id) + if not adapter: + return + + # 将图片保存为临时文件 + image_file = self._save_image_to_temp(image_url, group_id) + if not image_file: + return + + try: + # 上传到群文件 + if enable_file: + await self._do_upload_group_file(adapter, group_id, image_file) + + # 上传到群相册 + if enable_album: + await self._do_upload_group_album(adapter, group_id, image_file) + finally: + try: + os.remove(image_file) + except OSError: + pass + + async def _do_upload_group_file(self, adapter, group_id: str, file_path: str): + """上传文件到群文件目录,失败静默""" + try: + folder_name = self.config_manager.get_group_file_folder() + folder_id = None + if folder_name: + folder_id = await adapter.find_or_create_folder(group_id, folder_name) + await adapter.upload_group_file_to_folder( + group_id=group_id, + file_path=file_path, + folder_id=folder_id, + ) + except Exception as e: + logger.warning(f"群文件上传失败 (群 {group_id}): {e}") + + async def _do_upload_group_album(self, adapter, group_id: str, file_path: str): + """上传图片到群相册,失败静默""" + try: + album_name = self.config_manager.get_group_album_name() + strict_mode = self.config_manager.get_group_album_strict_mode() + album_id = None + + if hasattr(adapter, "find_album_id"): + if album_name: + album_id = await adapter.find_album_id(group_id, album_name) + if not album_id and strict_mode: + logger.info( + f"群相册严格模式开启:在群 {group_id} 中未找到名为 '{album_name}' 的相册,停止上传。" + ) + return + elif strict_mode: + logger.info( + f"群相册严格模式开启:未设置目标相册名称,停止上传以防止操作群 {group_id} 的默认相册。" + ) + return + + await adapter.upload_group_album( + group_id, + file_path, + album_id=album_id, + album_name=album_name, + strict_mode=strict_mode, + ) + except Exception as e: + logger.warning(f"群相册上传失败 (群 {group_id}): {e}") + + def _save_image_to_temp(self, image_url: str, group_id: str) -> str | None: + """将 base64 图片保存为临时 PNG 文件,返回路径。失败返回 None。""" + try: + image_data = None + if image_url.startswith("base64://"): + image_data = base64.b64decode(image_url[len("base64://") :]) + elif image_url.startswith("data:"): + parts = image_url.split(",", 1) + if len(parts) == 2: + image_data = base64.b64decode(parts[1]) + elif os.path.isfile(image_url): + return os.path.abspath(image_url) + elif image_url.startswith("file:///"): + p = image_url[len("file:///") :] + if os.path.isfile(p): + return os.path.abspath(p) + + if not image_data: + return None + + date_str = datetime.now().strftime("%Y%m%d_%H%M%S") + path = os.path.join( + tempfile.gettempdir(), f"report_{group_id}_{date_str}.png" + ) + with open(path, "wb") as f: + f.write(image_data) + return path + except Exception as e: + logger.debug(f"保存图片到临时文件失败: {e}") + return None + + def _get_onebot_adapter(self, platform_id: str | None): + """获取 OneBot 适配器,非 OneBot 平台返回 None。""" + if not platform_id: + return None + adapter = self.message_sender.bot_manager.get_adapter(platform_id) + if adapter and hasattr(adapter, "upload_group_file_to_folder"): + return adapter + return None diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/generators.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/generators.py new file mode 100644 index 0000000..94e303a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/generators.py @@ -0,0 +1,1959 @@ +""" +报告生成器模块 +负责生成各种格式的分析报告 +""" + +import asyncio +import base64 +import copy +import hashlib +import html +import json +import os +import re +import time +from dataclasses import asdict, is_dataclass +from datetime import date, datetime +from enum import Enum +from io import BytesIO +from pathlib import Path +from typing import Any +from urllib.parse import quote + +import aiohttp +import ulid +from diskcache import Cache +from markupsafe import Markup +from PIL import Image, UnidentifiedImageError + +from ...domain.repositories.report_repository import IReportGenerator +from ...shared.trace_context import TraceContext +from ...utils.logger import logger +from ..utils.template_utils import render_template +from ..visualization.activity_charts import ActivityVisualizer +from .qq_official_markdown import QQOfficialMarkdownReportGenerator +from .templates import HTMLTemplates + +# qlogo 在短时间内承受大量并发请求时可能主动断开连接,保留并发预取但限制并发度。 +MAX_CONCURRENT_DOWNLOADS = 4 +AVATAR_DOWNLOAD_RETRY_TIMES = 3 +AVATAR_CACHE_EXPIRE_TIME = 259200 +AVATAR_FAILURE_CACHE_EXPIRE_TIME = 60 +AVATAR_MAX_EDGE_LENGTH = 96 +TRANSPARENT_IMAGE_DATA_URI = ( + "data:image/svg+xml;base64," + "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxIiBoZWlnaHQ9IjEiPjwvc3ZnPg==" +) + +DEFAULT_PROFILE_MAPPING = { + "mbti": { + "INTJ": {"code": "INTJ", "name_zh": "建筑师"}, + "INTP": {"code": "INTP", "name_zh": "逻辑学家"}, + "ENTJ": {"code": "ENTJ", "name_zh": "指挥官"}, + "ENTP": {"code": "ENTP", "name_zh": "辩论家"}, + "INFJ": {"code": "INFJ", "name_zh": "提倡者"}, + "INFP": {"code": "INFP", "name_zh": "调停者"}, + "ENFJ": {"code": "ENFJ", "name_zh": "主人公"}, + "ENFP": {"code": "ENFP", "name_zh": "竞选者"}, + "ISTJ": {"code": "ISTJ", "name_zh": "物流师"}, + "ISFJ": {"code": "ISFJ", "name_zh": "守卫者"}, + "ESTJ": {"code": "ESTJ", "name_zh": "总经理"}, + "ESTP": {"code": "ESTP", "name_zh": "企业家"}, + "ISTP": {"code": "ISTP", "name_zh": "鉴赏家"}, + "ISFP": {"code": "ISFP", "name_zh": "探险家"}, + "ESFJ": {"code": "ESFJ", "name_zh": "执政官"}, + "ESFP": {"code": "ESFP", "name_zh": "表演者"}, + }, + "sbti": { + "INTJ": {"code": "CTRL", "name_zh": "拿捏者", "asset_code": "CTRL"}, + "INTP": {"code": "THIN-K", "name_zh": "思考者", "asset_code": "THIN-K"}, + "ENTJ": {"code": "BOSS", "name_zh": "领导者", "asset_code": "BOSS"}, + "ENTP": {"code": "JOKE-R", "name_zh": "小丑", "asset_code": "JOKE-R"}, + "INFJ": {"code": "LOVE-R", "name_zh": "多情者", "asset_code": "LOVE-R"}, + "INFP": {"code": "SOLO", "name_zh": "孤儿", "asset_code": "SOLO"}, + "ENFJ": {"code": "THAN-K", "name_zh": "感恩者", "asset_code": "THAN-K"}, + "ENFP": {"code": "GOGO", "name_zh": "行者", "asset_code": "GOGO"}, + "ISTJ": {"code": "OH-NO", "name_zh": "哦不人", "asset_code": "OH-NO"}, + "ISTP": {"code": "POOR", "name_zh": "贫困者", "asset_code": "POOR"}, + "ESTJ": {"code": "SHIT", "name_zh": "愤世者", "asset_code": "SHIT"}, + "ESTP": {"code": "WOC!", "name_zh": "握草人", "asset_code": "WOC"}, + "ISFJ": {"code": "MUM", "name_zh": "妈妈", "asset_code": "MUM"}, + "ISFP": {"code": "MALO", "name_zh": "吗喽", "asset_code": "MALO"}, + "ESFJ": {"code": "ATM-er", "name_zh": "送钱者", "asset_code": "ATM-er"}, + "ESFP": {"code": "SEXY", "name_zh": "尤物", "asset_code": "SEXY"}, + }, + "acgti": { + "INTJ": {"code": "MRTS-X", "name_zh": "Mortis"}, + "INTP": {"code": "KNAN", "name_zh": "江户川柯南"}, + "ENTJ": {"code": "SAKI", "name_zh": "丰川祥子"}, + "ENTP": {"code": "CHKA", "name_zh": "藤原千花"}, + "INFJ": {"code": "DLRS", "name_zh": "三角初华"}, + "INFP": {"code": "BCHI", "name_zh": "后藤一里"}, + "ENFJ": {"code": "YCYO", "name_zh": "月见八千代"}, + "ENFP": {"code": "HTMK", "name_zh": "初音未来"}, + "ISTJ": {"code": "MRTS", "name_zh": "若叶睦"}, + "ISTP": {"code": "AYRE", "name_zh": "绫波丽"}, + "ESTJ": {"code": "MIKT", "name_zh": "御坂美琴"}, + "ESTP": {"code": "ASKA", "name_zh": "明日香"}, + "ISFJ": {"code": "SOYO", "name_zh": "长崎爽世"}, + "ISFP": {"code": "LTYI", "name_zh": "洛天依"}, + "ESFJ": {"code": "ANON", "name_zh": "千早爱音"}, + "ESFP": {"code": "FRNA", "name_zh": "芙宁娜"}, + }, +} + + +class ReportGenerator(IReportGenerator): + """报告生成器""" + + def __init__(self, config_manager, data_dir): + self._avatar_session = None + self.config_manager = config_manager + self.data_dir = data_dir + self.activity_visualizer = ActivityVisualizer() + self.html_templates = HTMLTemplates(config_manager) # 实例化HTML模板管理器 + # 全局 T2I 渲染信号量,保护本地资源 + # 使用专用的 T2I 并发配置项 + max_concurrent = self.config_manager.get_t2i_max_concurrent() + self._render_semaphore = asyncio.Semaphore(max_concurrent) + self._qq_official_markdown_generator = QQOfficialMarkdownReportGenerator( + config_manager, + self.html_templates, + self._render_semaphore, + ) + + # 运行时缓存,用于在一次分析任务中避免重复下载同一个头像 + self._avatar_cache = Cache( + str(self.data_dir / "avatar") + ) # user_id -> base64_uri + self._avatar_session_concurrent_semaphore = asyncio.Semaphore( + MAX_CONCURRENT_DOWNLOADS + ) + self._avatar_session = None + self._avatar_session_lock = asyncio.Lock() + self._avatar_failure_cache: dict[str, float] = {} + self._profile_asset_manifest = self._load_profile_asset_manifest() + + def _load_profile_asset_manifest(self) -> dict[str, dict]: + """加载人格资源清单。""" + manifest_path = ( + Path(__file__).resolve().parents[3] + / "assets" + / "profile_assets" + / "manifest.json" + ) + if not manifest_path.exists(): + logger.warning(f"人格资源清单不存在: {manifest_path}") + return {"sbti": {}, "acgti": {}} + + try: + raw = json.loads(manifest_path.read_text(encoding="utf-8-sig")) + except Exception as e: + logger.warning(f"加载人格资源清单失败: {e}") + return {"sbti": {}, "acgti": {}} + + manifest: dict[str, dict] = {"sbti": {}, "acgti": {}} + for item in raw.get("sbti", []): + code = str(item.get("code", "")).strip() + if code: + manifest["sbti"][code] = item + for item in raw.get("acgti", []): + code = str(item.get("code", "")).strip() + if code: + manifest["acgti"][code] = item + return manifest + + def _get_profile_mapping_overrides(self) -> dict[str, dict]: + """解析用户配置的人格映射覆盖项。""" + raw = self.config_manager.get_profile_mapping_config() + if not raw: + return {} + + try: + data = json.loads(raw) + if isinstance(data, dict): + return data + except Exception as e: + logger.warning(f"人格映射配置 JSON 解析失败,已回退到默认映射: {e}") + return {} + + def _build_profile_image_from_manifest_pattern( + self, profile_mode: str, asset_code: str + ) -> str: + """当 manifest 缺少具体 code 时,根据已有资源路径模式推导图片地址。""" + system_manifest = self._profile_asset_manifest.get(profile_mode, {}) + for item in system_manifest.values(): + if not isinstance(item, dict): + continue + sample_code = str(item.get("code", "")).strip() + sample_file = str(item.get("file", "")).strip() + if not sample_code or not sample_file: + continue + code_token = f"/{sample_code}." + if code_token not in sample_file: + continue + return sample_file.replace(code_token, f"/{asset_code}.", 1) + return "" + + def _get_manifest_profile_item_by_mbti( + self, profile_mode: str, mbti: str + ) -> dict | None: + """按 MBTI 从 manifest 中寻找可用资源。""" + normalized_mbti = str(mbti or "").strip().upper() + system_manifest = self._profile_asset_manifest.get(profile_mode, {}) + for item in system_manifest.values(): + if not isinstance(item, dict): + continue + item_mbti = str(item.get("mbti", "")).strip().upper() + if item_mbti == normalized_mbti: + return item + return None + + def _resolve_profile_info( + self, + mbti: str, + profile_mode: str, + overrides: dict[str, dict], + ) -> dict[str, str | float]: + """根据当前展示模式解析人格标签展示信息。""" + normalized_mbti = str(mbti or "").strip().upper() + + # 1. 基础信息获取:从默认映射或用户覆盖中获取核心属性 + profile_defaults = DEFAULT_PROFILE_MAPPING.get(profile_mode, {}) + base_info = dict(profile_defaults.get(normalized_mbti, {})) + + # 用户覆盖优先级最高 + user_override = overrides.get(profile_mode, {}).get(normalized_mbti, {}) + if isinstance(user_override, dict): + base_info.update(user_override) + + code = str(base_info.get("code", normalized_mbti)).strip() or normalized_mbti + name_zh = str(base_info.get("name_zh", "")).strip() + asset_code = str(base_info.get("asset_code", code)).strip() or code + image = str(base_info.get("image", "")).strip() + + # 2. 图片与属性补全 (基于 manifest.json 可信源) + if not image: + system_manifest = self._profile_asset_manifest.get(profile_mode, {}) + # A. 优先按 asset_code 索引 + asset_item = system_manifest.get(asset_code) + if isinstance(asset_item, dict): + image = str(asset_item.get("file", "")).strip() + if not name_zh: + name_zh = str(asset_item.get("name", "")).strip() + + # B. 按照 asset_code 的资源规律推导图片地址 (尝试根据同目录下其他资源的规律猜测当前角色的 CDN 地址) + if not image: + image = self._build_profile_image_from_manifest_pattern( + profile_mode, asset_code + ) + + # C. 对于 acgti 模式,如果没找到明确映射也没能推导出图片,尝试通过 MBTI 反查该类型下的第一个可用资源作为兜底 + if not image and profile_mode == "acgti": + fallback_item = self._get_manifest_profile_item_by_mbti( + profile_mode, normalized_mbti + ) + if isinstance(fallback_item, dict): + image = str(fallback_item.get("file", "")).strip() + if not name_zh: + name_zh = str(fallback_item.get("name", "")).strip() + if not code or code == normalized_mbti: + code = str(fallback_item.get("code", code)).strip() + + # 3. 构造显示文本 (Code + 中文名) + display = str(base_info.get("display", "")).strip() + if not display: + display = f"{code}({name_zh})" if name_zh else code + + return { + "profile_mode": profile_mode, + "profile_code": code, + "profile_name_zh": name_zh, + "profile_display": display, + "profile_image": image, + "profile_image_opacity": self.config_manager.get_profile_image_opacity(), + "profile_image_size_mode": self.config_manager.get_profile_image_size_mode(), + } + + @staticmethod + def _sanitize_path_component(name: str) -> str: + """消毒单个路径/文件名片段,禁止路径穿越和非法字符。""" + # 禁止空组件、相对路径控制符:"."、".." + if not name or name in {".", ".."}: + raise ValueError(f"无效的路径片段: {name!r}") + + # 不允许包含路径分隔符 + name = name.replace("/", "_") + name = name.replace("\\", "_") + + # 去除非打印字符和非法文件名字符 + name = re.sub(r'[\x00-\x1f<>:"|?*]', "_", name) + + # 保留中文、字母、数字、下划线、横线和点 + name = name.strip() + if not name: + raise ValueError("路径片段经过消毒后为空") + + return name + + def _build_safe_report_path( + self, + output_dir: Path, + filename_format: str, + group_id: str, + date: str, + ) -> Path: + """根据格式构建安全输出路径,支持子目录和 {ulid}。""" + generated_ulid = str(ulid.new()) + safe_context = { + "group_id": group_id, + "date": date, + "ulid": generated_ulid, + "trace_id": str(TraceContext.get() or ""), + } + + try: + formatted = render_template(filename_format, strict=True, **safe_context) + except Exception as e: + raise ValueError(f"文件名模板渲染失败: {e}") from e + + if os.path.isabs(formatted): + raise ValueError("文件名格式不得为绝对路径") + + relative_path = Path(formatted) + sanitized_parts = [] + for part in relative_path.parts: + if part in {".", ".."}: + raise ValueError("路径中不得包含 '.' 或 '..'。") + sanitized_parts.append(self._sanitize_path_component(part)) + + safe_relative = Path(*sanitized_parts) + + output_dir_resolved = output_dir.resolve(strict=False) + target_path = (output_dir_resolved / safe_relative).resolve(strict=False) + + # 防止回退到上级目录(使用 Path.relative_to 进行目录包含校验) + try: + target_path.relative_to(output_dir_resolved) + except ValueError: + raise ValueError("文件路径不在输出目录之内,可能包含路径穿越") + + # 防止与已有文件覆盖(如果用户格式没有唯一标记),追加 ULID 后缀 + if target_path.exists(): + suffix = target_path.suffix + stem = target_path.stem + target_path = target_path.with_name(f"{stem}_{generated_ulid}{suffix}") + + target_path.parent.mkdir(parents=True, exist_ok=True) + return target_path + + async def generate_image_report( + self, + analysis_result: dict, + group_id: str, + html_render_func, + avatar_url_getter=None, + nickname_getter=None, + avatar_cache_namespace: str | None = None, + hide_user_names: bool = False, + # Also controls ID normalization and fallback display name ("群友"). + allow_alphanumeric_user_ids: bool = False, + template_theme: str | None = None, + ) -> tuple[str | None, str | None]: + """ + 生成图片格式的分析报告 + + Args: + analysis_result: 分析结果字典 + group_id: 群组ID + html_render_func: HTML渲染函数 + avatar_url_getter: 异步回调函数,接收 user_id 返回 avatar_url/data + nickname_getter: 昵称获取函数 + template_theme: 指定的主题模板名称 (如 scrapbook, ATRI 等) + + Returns: + tuple[str | None, str | None]: (image_url, html_content) + """ + html_content = None + try: + # 准备渲染数据 + render_payload = await self._prepare_render_data( + analysis_result, + chart_template="activity_chart.html", + avatar_url_getter=avatar_url_getter, + nickname_getter=nickname_getter, + avatar_cache_namespace=avatar_cache_namespace, + hide_user_names=hide_user_names, + allow_alphanumeric_user_ids=allow_alphanumeric_user_ids, + ) + + # 先渲染HTML模板(使用 Jinja2 渲染器以支持逻辑标签) + html_content = self.html_templates.render_template( + "image_template.html", template_theme=template_theme, **render_payload + ) + html_content = self._reuse_avatars_in_final_html( + html_content, + render_payload.get("avatar_reuse_registry", {}), + render_payload.get("avatar_reuse_aliases", {}), + ) + + # 检查HTML内容是否有效 + if not html_content: + logger.error("图片报告HTML渲染失败:返回空内容") + return None, None + + logger.debug(f"图片报告HTML渲染完成,长度: {len(html_content)} 字符") + + # 从配置中获取两轮渲染策略 + render_strategies = self.config_manager.get_t2i_rendering_strategies() + + # 使用信号量控制并发进入渲染引擎 + async with self._render_semaphore: + logger.debug(f"[T2I] 已进入渲染队列 (群: {group_id})") + + last_exception = None + + for attempt, image_options in enumerate(render_strategies, 1): + try: + image_options, viewport_description = ( + self._resolve_t2i_viewport_options( + html_content, image_options + ) + ) + + # Cleanse options + if image_options.get("type") == "png": + image_options.pop("quality", None) + + logger.debug( + "正在尝试第 " + f"{attempt} 轮渲染策略: type={image_options['type']}, " + f"full_page={image_options['full_page']}, " + f"viewport={viewport_description}, " + f"scale={image_options.get('device_scale_factor_level')}, " + f"timeout={image_options.get('timeout')}" + ) + + # 改为获取 bytes 数据,避免 OneBot 无法访问内部 URL + image_data = await html_render_func( + html_content, # 渲染后的HTML内容 + {}, # 空数据字典,因为数据已包含在HTML中 + False, # return_url=False,直接获取图片数据 + image_options, + ) + + if image_data: + # 校验是否为合法图片(防止 T2I 返回 500 错误 HTML 字符流) + is_valid = False + actual_data_head = None + + if isinstance(image_data, bytes): + actual_data_head = image_data[:10] + elif isinstance(image_data, str) and os.path.exists( + image_data + ): + try: + with open(image_data, "rb") as f: + actual_data_head = f.read(10) + except Exception as e: + logger.warning(f"读取图片临时文件失败: {e}") + + if actual_data_head: + # 检查 magic numbers (JPEG: FF D8, PNG: 89 50 4E 47) + if actual_data_head.startswith( + b"\xff\xd8" + ) or actual_data_head.startswith(b"\x89PNG"): + is_valid = True + else: + # 尝试解析 HTML 错误(如 502 Bad Gateway) + html_error = None + if isinstance(image_data, bytes): + html_error = self._extract_html_error_summary( + image_data + ) + elif isinstance(image_data, str) and os.path.exists( + image_data + ): + try: + with open(image_data, "rb") as f: + # 读取前 4KB 即可识别 HTML 错误 + html_error = ( + self._extract_html_error_summary( + f.read(4096) + ) + ) + except Exception: + pass + + if html_error: + logger.warning( + f"[T2I] 渲染引擎返回了错误页面而非图片: {html_error}" + ) + else: + logger.warning( + f"渲染结果似乎不是有效的图片数据 (头部: {actual_data_head.hex()})" + ) + + if is_valid: + image_size = ( + len(image_data) + if isinstance(image_data, bytes) + else ( + os.path.getsize(image_data) + if ( + isinstance(image_data, str) + and os.path.exists(image_data) + ) + else 0 + ) + ) + + # 上报渲染全量参数与产物指标至当前 Span + trace_ctx = TraceContext.current() + if trace_ctx: + for s in reversed(trace_ctx._spans): + if s.get("stage_name") == "RENDER_REPORT": + payload = s.setdefault("payload", {}) + payload.update( + { + "format": "image", + "template": template_theme + or "scrapbook (默认)", + "viewport": viewport_description, + "render_attempt": attempt, + "image_format": str( + image_options.get( + "type", "jpeg" + ) + ), + "image_bytes": image_size, + "topics_rendered": len( + analysis_result.get( + "topics", [] + ) + ), + "titles_rendered": len( + analysis_result.get( + "user_titles", [] + ) + ), + "quotes_rendered": len( + getattr( + analysis_result.get( + "statistics" + ), + "golden_quotes", + [], + ) + or [] + ), + "avatars_processed": len( + render_payload.get( + "avatar_reuse_registry", {} + ) + ), + "html_chars": len(html_content) + if html_content + else 0, + "hide_user_names": bool( + hide_user_names + ), + } + ) + payload.setdefault( + "render_attempts", [] + ).append( + { + "attempt": attempt, + "type": str( + image_options.get( + "type", "jpeg" + ) + ), + "viewport": viewport_description, + "status": "success", + } + ) + break + + if isinstance(image_data, bytes): + b64 = base64.b64encode(image_data).decode("utf-8") + image_url = f"base64://{b64}" + logger.info( + "图片生成成功 " + f"(轮次 {attempt}, 视口 {viewport_description}): " + f"[Base64 数据 {len(image_data)} 字节]" + ) + return image_url, html_content + elif isinstance(image_data, str): + logger.info( + "图片生成成功 " + f"(轮次 {attempt}, 视口 {viewport_description}): " + f"{image_data}" + ) + return image_data, html_content + + logger.warning( + f"渲染轮次 {attempt} ({image_options['type']}) 返回了无效或空数据" + ) + trace_ctx = TraceContext.current() + if trace_ctx: + for s in reversed(trace_ctx._spans): + if s.get("stage_name") == "RENDER_REPORT": + s.setdefault("payload", {}).setdefault( + "render_attempts", [] + ).append( + { + "attempt": attempt, + "type": str( + image_options.get("type", "jpeg") + ), + "viewport": viewport_description, + "status": "failed", + "error": html_error + or "返回数据非合法图片头", + } + ) + break + + except Exception as e: + logger.warning(f"渲染轮次 {attempt} 失败: {e}") + last_exception = e + trace_ctx = TraceContext.current() + if trace_ctx: + for s in reversed(trace_ctx._spans): + if s.get("stage_name") == "RENDER_REPORT": + s.setdefault("payload", {}).setdefault( + "render_attempts", [] + ).append( + { + "attempt": attempt, + "type": str( + image_options.get("type", "jpeg") + ), + "viewport": viewport_description, + "status": "failed", + "error": str(e), + } + ) + break + if attempt < len(render_strategies): + logger.debug("准备尝试下一轮回退策略") + continue + + # 如果所有策略都失败 + logger.error(f"所有渲染尝试都失败。最后一个错误: {last_exception}") + return None, html_content + + except Exception as e: + logger.error(f"生成图片报告过程发生严重错误: {e}", exc_info=True) + return None, html_content + + @staticmethod + def _resolve_t2i_viewport_options( + html_content: str, image_options: dict + ) -> tuple[dict, str]: + """优先使用 T2I 可识别的模板视口,缺失维度使用插件兜底值。 + + Args: + html_content: 已渲染完成的报告 HTML。 + image_options: 当前轮次的 T2I 渲染参数,包含兜底视口。 + + Returns: + 实际传给 T2I 的参数,以及用于日志的视口来源说明。 + """ + resolved_options = image_options.copy() + head_snippet = html_content[:4096] + descriptions = [] + for dimension, option_key in ( + ("width", "viewport_width"), + ("height", "viewport_height"), + ): + # 与新版 T2I 的 meta 解析规则保持一致,避免误删兜底参数。 + pattern = ( + r']*name=["\']viewport["\'][^>]*' + rf'content=["\'][^"\']*{dimension}\s*=\s*(\d+)[^"\']*["\'][^>]*>' + ) + match = re.search(pattern, head_snippet, re.IGNORECASE) + if match: + resolved_options.pop(option_key, None) + descriptions.append(f"模板{dimension}={match.group(1)}") + else: + descriptions.append( + f"兜底{dimension}={resolved_options.get(option_key)}" + ) + return resolved_options, ",".join(descriptions) + + async def generate_html_report( + self, + analysis_result: dict, + group_id: str, + avatar_url_getter=None, + nickname_getter=None, + avatar_cache_namespace: str | None = None, + hide_user_names: bool = False, + allow_alphanumeric_user_ids: bool = False, + template_theme: str | None = None, + custom_filename: str | None = None, + trace_id: str | None = None, + ) -> tuple[str | None, str | None]: + """ + 生成HTML格式的分析报告,保存到指定目录 + + Args: + analysis_result: 分析结果字典 + group_id: 群组ID + avatar_url_getter: 异步回调函数,接收 user_id 返回 avatar_url/data + nickname_getter: 昵称获取函数 + template_theme: 指定的主题模板名称 (如 scrapbook, ATRI 等) + custom_filename: 自定义输出文件名 + trace_id: 关联的 Trace ID + + Returns: + tuple[str | None, str | None]: (html_path, json_path) - HTML文件路径和JSON文件路径 + """ + try: + import json + + # 确保输出目录存在(使用 asyncio.to_thread 避免阻塞) + output_dir = Path(self.config_manager.get_html_output_dir()) + await asyncio.to_thread(output_dir.mkdir, parents=True, exist_ok=True) + + # 生成文件路径 + if custom_filename: + html_path = output_dir / custom_filename + if not html_path.suffix: + html_path = html_path.with_suffix(".html") + elif trace_id: + ts_str = datetime.now().strftime("%Y%m%d_%H%M%S") + theme_suffix = f"_{template_theme}" if template_theme else "" + html_path = ( + output_dir + / f"report_{group_id}_{ts_str}_{trace_id}{theme_suffix}.html" + ) + else: + current_date = datetime.now().strftime("%Y%m%d") + base_html_path = self._build_safe_report_path( + output_dir, + self.config_manager.get_html_filename_format(), + group_id=group_id, + date=current_date, + ) + html_path = base_html_path + if not html_path.suffix: + html_path = html_path.with_suffix(".html") + + json_path = html_path.with_suffix(".json") + + html_path.parent.mkdir(parents=True, exist_ok=True) + + # 准备渲染数据 + render_data = await self._prepare_render_data( + analysis_result, + chart_template="activity_chart.html", + avatar_url_getter=avatar_url_getter, + nickname_getter=nickname_getter, + avatar_cache_namespace=avatar_cache_namespace, + hide_user_names=hide_user_names, + allow_alphanumeric_user_ids=allow_alphanumeric_user_ids, + ) + logger.debug(f"HTML 渲染数据准备完成,包含 {len(render_data)} 个字段") + + # 生成 HTML 内容(使用 Jinja2 渲染器,尝试 html_template.html,失败则回退到 image_template.html) + html_content = None + try: + html_content = self.html_templates.render_template( + "html_template.html", template_theme=template_theme, **render_data + ) + html_content = self._reuse_avatars_in_final_html( + html_content, + render_data.get("avatar_reuse_registry", {}), + render_data.get("avatar_reuse_aliases", {}), + ) + logger.debug("使用 html_template.html 渲染成功") + except Exception as e: + logger.warning( + f"html_template.html 不存在或渲染失败,回退到 image_template.html: {e}" + ) + html_content = self.html_templates.render_template( + "image_template.html", template_theme=template_theme, **render_data + ) + html_content = self._reuse_avatars_in_final_html( + html_content, + render_data.get("avatar_reuse_registry", {}), + render_data.get("avatar_reuse_aliases", {}), + ) + logger.debug("使用 image_template.html 渲染成功") + + # 检查HTML内容是否有效 + if not html_content: + logger.error("HTML报告渲染失败:返回空内容") + return None, None + + logger.debug(f"HTML 内容生成完成,长度: {len(html_content)} 字符") + + # 保存 HTML 文件 + await asyncio.to_thread( + html_path.write_text, html_content, encoding="utf-8" + ) + logger.info(f"HTML 报告已保存: {html_path}") + + def json_default_encoder(obj): + if hasattr(obj, "to_dict") and callable(obj.to_dict): + return obj.to_dict() + if is_dataclass(obj) and not isinstance(obj, type): + return asdict(obj) + if isinstance(obj, (datetime, date)): + return obj.isoformat() + if isinstance(obj, Enum): + return obj.value + if isinstance(obj, (set, tuple)): + return list(obj) + raise TypeError( + f"Object of type {type(obj).__name__} is not JSON serializable" + ) + + # 保存原始 JSON 数据 + json_data = { + "analysis_result": ( + self._sanitize_analysis_result_for_export(analysis_result) + if hide_user_names or allow_alphanumeric_user_ids + else analysis_result + ), + "group_id": group_id, + "generated_at": datetime.now().isoformat(), + } + await asyncio.to_thread( + json_path.write_text, + json.dumps( + json_data, + ensure_ascii=False, + indent=2, + default=json_default_encoder, + ), + encoding="utf-8", + ) + logger.info(f"JSON 数据已保存: {json_path}") + + # 实时记录产物报告到当前 TraceContext 与数据库 + trace_ctx = TraceContext.current() + if trace_ctx: + for s in reversed(trace_ctx._spans): + if s.get("stage_name") == "RENDER_REPORT": + s.setdefault("payload", {}).update( + { + "format": "html", + "template": template_theme or "default", + "html_chars": len(html_content) if html_content else 0, + "html_file": html_path.name, + "topics_rendered": len( + analysis_result.get("topics", []) + ), + "titles_rendered": len( + analysis_result.get("user_titles", []) + ), + "quotes_rendered": len( + getattr( + analysis_result.get("statistics"), + "golden_quotes", + [], + ) + or [] + ), + "avatars_processed": len( + render_data.get("avatar_reuse_registry", {}) + ), + "hide_user_names": bool(hide_user_names), + } + ) + break + + rfiles = trace_ctx.metadata.setdefault("report_files", []) + if not any(rf.get("filename") == html_path.name for rf in rfiles): + rfiles.append( + { + "filename": html_path.name, + "path": str(html_path.resolve()), + "format": "html", + "size_bytes": html_path.stat().st_size + if html_path.exists() + else 0, + "created_at": time.time(), + } + ) + from ...shared.trace_context import _global_trace_store + + if _global_trace_store is not None: + try: + _global_trace_store.save_trace(trace_ctx.to_dict()) + except Exception: + pass + + return str(html_path.absolute()), str(json_path.absolute()) + + except Exception as e: + logger.error(f"生成 HTML 报告失败: {e}", exc_info=True) + return None, None + + def build_html_caption(self, html_path: str) -> str: + """根据 html_base_url 生成 HTML 报告链接 caption。由调用方决定是否发送。""" + + caption = "📊 每日群聊分析报告已生成" + base_url = self.config_manager.get_html_base_url() + if not base_url or not html_path: + return caption + + # 支持 html_filename_format 中的子目录,保持相对路径 + output_dir = Path(self.config_manager.get_html_output_dir()).resolve( + strict=False + ) + try: + relative_path = ( + Path(html_path).resolve(strict=False).relative_to(output_dir) + ) + relative_url = str(relative_path).replace(os.sep, "/") + except Exception: + relative_url = Path(html_path).name + + encoded_relative_url = quote(relative_url, safe="/") + return caption + f"\n{base_url.rstrip('/')}/{encoded_relative_url}" + + def generate_text_report(self, analysis_result: dict) -> str: + """生成文本格式的分析报告""" + stats = analysis_result["statistics"] + topics = analysis_result["topics"] + user_titles = analysis_result["user_titles"] + + report = f""" +🎯 群聊日常分析报告 +📅 {datetime.now().strftime("%Y年%m月%d日")} + +📊 基础统计 +• 消息总数: {stats.message_count} +• 参与人数: {stats.participant_count} +• 总字符数: {stats.total_characters} +• 表情数量: {stats.emoji_count} +• 最活跃时段: {stats.most_active_period} + +💬 热门话题 +""" + + max_topics = self.config_manager.get_max_topics() + for i, topic in enumerate(topics[:max_topics], 1): + contributors_str = "、".join(topic.contributors) + report += f"{i}. {topic.topic}\n" + report += f" 参与者: {contributors_str}\n" + report += f" {topic.detail}\n\n" + + report += "🏆 群友称号\n" + max_user_titles = self.config_manager.get_max_user_titles() + for title in user_titles[:max_user_titles]: + report += f"• {title.name} - {title.title} ({title.mbti})\n" + report += f" {title.reason}\n\n" + + report += "💬 群圣经\n" + max_golden_quotes = self.config_manager.get_max_golden_quotes() + for i, golden_quote in enumerate(stats.golden_quotes[:max_golden_quotes], 1): + report += f'{i}. "{golden_quote.content}" —— {golden_quote.sender}\n' + report += f" {golden_quote.reason}\n\n" + + return report + + async def generate_qq_official_markdown_report( + self, analysis_result: dict, html_render_func=None + ) -> tuple[str, str]: + """Delegate QQ-only text generation to the platform-specific module.""" + generator = getattr(self, "_qq_official_markdown_generator", None) + if generator is None: + generator = QQOfficialMarkdownReportGenerator( + self.config_manager, + getattr(self, "html_templates", None), + getattr(self, "_render_semaphore", None), + ) + self._qq_official_markdown_generator = generator + return await generator.generate( + analysis_result, + html_render_func, + ) + + def _sanitize_analysis_result_for_export( + self, analysis_result: dict + ) -> dict[str, Any]: + """Remove platform identities from the HTML sidecar JSON export.""" + sanitized = self._to_plain_export_data(copy.deepcopy(analysis_result)) + sanitized["user_analysis"] = {} + for topic in sanitized.get("topics", []): + if not isinstance(topic, dict): + continue + topic["contributors"] = [] + topic["contributor_ids"] = [] + for title in sanitized.get("user_titles", []): + if not isinstance(title, dict): + continue + title["name"] = "" + title["user_id"] = "" + stats = sanitized.get("statistics") + if isinstance(stats, dict): + for golden_quote in stats.get("golden_quotes", []) or []: + if not isinstance(golden_quote, dict): + continue + golden_quote["sender"] = "" + golden_quote["user_id"] = "" + + activity_visualization = stats.get("activity_visualization") + if isinstance(activity_visualization, dict): + activity_visualization["user_activity_ranking"] = [] + + for golden_quote in sanitized.get("golden_quotes", []) or []: + if not isinstance(golden_quote, dict): + continue + golden_quote["sender"] = "" + golden_quote["user_id"] = "" + + return self._sanitize_export_identity_text(sanitized, analysis_result) # type: ignore[return-type] + + @classmethod + def _to_plain_export_data(cls, value): + """Convert report models into plain containers before privacy filtering.""" + if hasattr(value, "to_dict") and callable(value.to_dict): + return cls._to_plain_export_data(value.to_dict()) + if is_dataclass(value) and not isinstance(value, type): + return cls._to_plain_export_data(asdict(value)) + if isinstance(value, dict): + return {key: cls._to_plain_export_data(item) for key, item in value.items()} + if isinstance(value, (list, tuple, set)): + return [cls._to_plain_export_data(item) for item in value] + return value + + def _sanitize_export_identity_text(self, value, analysis_result: dict): + """Remove known IDs and display names from every exported text field.""" + if isinstance(value, str): + return self._sanitize_identity_text(value, analysis_result, True) + if isinstance(value, dict): + return { + key: self._sanitize_export_identity_text(item, analysis_result) + for key, item in value.items() + } + if isinstance(value, list): + return [ + self._sanitize_export_identity_text(item, analysis_result) + for item in value + ] + return value + + async def _prepare_render_data( + self, + analysis_result: dict, + chart_template: str = "activity_chart.html", + avatar_url_getter=None, + nickname_getter=None, + avatar_cache_namespace: str | None = None, + hide_user_names: bool = False, + allow_alphanumeric_user_ids: bool = False, + ) -> dict: + """准备渲染数据""" + stats = analysis_result["statistics"] + topics = analysis_result["topics"] + user_titles = analysis_result["user_titles"] + activity_viz = stats.activity_visualization + + # 使用Jinja2模板构建话题HTML(批量渲染) + max_topics = self.config_manager.get_max_topics() + topics_list = [] + user_analysis = analysis_result.get("user_analysis") + avatar_reuse_registry: dict[str, str] = {} + avatar_reuse_aliases: dict[str, str] = {} + + # 仅预取本次报告可见区域实际引用的头像。 + avatar_user_ids: set[str] = set() + known_user_ids = { + str(user_id).strip() + for user_id in (user_analysis or {}) + if str(user_id).strip() + } + max_user_titles = self.config_manager.get_max_user_titles() + max_golden_quotes = self.config_manager.get_max_golden_quotes() + for title in user_titles[:max_user_titles]: + user_id = str(getattr(title, "user_id", "") or "").strip() + if user_id: + avatar_user_ids.add(user_id) + for golden_quote in stats.golden_quotes[:max_golden_quotes]: + user_id = str(getattr(golden_quote, "user_id", "") or "").strip() + if user_id: + avatar_user_ids.add(user_id) + mention_sources = [] + for topic in topics[:max_topics]: + if hide_user_names: + avatar_user_ids.update( + str(user_id).strip() + for user_id in (getattr(topic, "contributor_ids", []) or []) + if str(user_id).strip() + ) + mention_sources.append(str(getattr(topic, "detail", "") or "")) + mention_sources.extend( + str(getattr(golden_quote, "reason", "") or "") + for golden_quote in stats.golden_quotes[:max_golden_quotes] + ) + if hide_user_names: + mention_sources.extend( + str(getattr(title, "reason", "") or "") + for title in user_titles[:max_user_titles] + ) + for source in mention_sources: + avatar_user_ids.update( + matched_user_id + for matched_user_id in re.findall(r"\[([A-Za-z0-9_-]{1,128})\]", source) + if matched_user_id in known_user_ids + ) + if avatar_user_ids: + await asyncio.gather( + *( + self._get_user_avatar( + user_id, avatar_url_getter, avatar_cache_namespace + ) + for user_id in avatar_user_ids + ) + ) + + for i, topic in enumerate(topics[:max_topics], 1): + # 处理话题详情中的用户引用头像 + processed_detail = await self._render_mentions( + topic.detail, + avatar_url_getter, + nickname_getter, + user_analysis, + avatar_cache_namespace, + avatar_reuse_registry, + avatar_reuse_aliases, + hide_user_names=hide_user_names, + allow_alphanumeric_user_ids=allow_alphanumeric_user_ids, + ) + if hide_user_names: + contributors = await self._render_avatar_only_ids( + getattr(topic, "contributor_ids", []) or [], + avatar_url_getter, + avatar_cache_namespace, + avatar_reuse_registry, + avatar_reuse_aliases, + ) + else: + contributors = "、".join(topic.contributors) + topics_list.append( + { + "index": i, + "topic": { + "topic": self._sanitize_identity_text( + topic.topic, analysis_result, hide_user_names + ) + }, + "contributors": contributors, + "detail": processed_detail, + } + ) + + # 通用模板上下文,包含可能被子模板引用的全局配置 + common_context = { + "hide_user_names": hide_user_names, + "t2i_font_source": self.config_manager.get_t2i_font_source(), + "t2i_google_fonts_mirror": self.config_manager.get_t2i_google_fonts_mirror(), + "t2i_gstatic_mirror": self.config_manager.get_t2i_gstatic_mirror(), + "t2i_atri_font_mirror": self.config_manager.get_t2i_atri_font_mirror(), + } + + topics_html = self.html_templates.render_template( + "topic_item.html", topics=topics_list, **common_context + ) + logger.debug(f"话题HTML生成完成,长度: {len(topics_html)}") + + # 使用Jinja2模板构建用户称号HTML(批量渲染,包含头像) + titles_list = [] + profile_mode = self.config_manager.get_profile_display_mode() + profile_mapping_overrides = self._get_profile_mapping_overrides() + for title in user_titles[:max_user_titles]: + user_id = str(title.user_id) + # 获取用户头像 + avatar_data = await self._get_user_avatar( + user_id, avatar_url_getter, avatar_cache_namespace + ) + self._register_reusable_avatar( + avatar_data, + avatar_reuse_registry, + avatar_reuse_aliases, + avatar_key=self._get_avatar_cache_key(user_id, avatar_cache_namespace), + ) + profile_info = self._resolve_profile_info( + title.mbti, profile_mode, profile_mapping_overrides + ) + title_reason = title.reason + if hide_user_names: + title_reason = await self._render_mentions( + title.reason, + avatar_url_getter, + nickname_getter, + user_analysis, + avatar_cache_namespace, + avatar_reuse_registry, + avatar_reuse_aliases, + hide_user_names=True, + allow_alphanumeric_user_ids=allow_alphanumeric_user_ids, + ) + title_data = { + "name": "" if hide_user_names else title.name, + "title": title.title, + "mbti": title.mbti, + "reason": title_reason, + "avatar_data": avatar_data, + } + title_data.update(profile_info) + titles_list.append(title_data) + + titles_html = self.html_templates.render_template( + "user_title_item.html", titles=titles_list, **common_context + ) + logger.debug(f"用户称号HTML生成完成,长度: {len(titles_html)}") + + # 使用Jinja2模板构建金句HTML(批量渲染) + quotes_list = [] + for golden_quote in stats.golden_quotes[:max_golden_quotes]: + quote_user_id = str(golden_quote.user_id) if golden_quote.user_id else None + avatar_url = ( + await self._get_user_avatar( + quote_user_id, + avatar_url_getter, + avatar_cache_namespace, + ) + if quote_user_id + else None + ) + if quote_user_id: + self._register_reusable_avatar( + avatar_url, + avatar_reuse_registry, + avatar_reuse_aliases, + avatar_key=self._get_avatar_cache_key( + quote_user_id, avatar_cache_namespace + ), + ) + # 处理解析锐评中的用户引用头像 + processed_reason = await self._render_mentions( + golden_quote.reason, + avatar_url_getter, + nickname_getter, + user_analysis, + avatar_cache_namespace, + avatar_reuse_registry, + avatar_reuse_aliases, + hide_user_names=hide_user_names, + allow_alphanumeric_user_ids=allow_alphanumeric_user_ids, + ) + quotes_list.append( + { + "content": self._sanitize_identity_text( + golden_quote.content, analysis_result, hide_user_names + ), + "sender": "" if hide_user_names else golden_quote.sender, + "reason": processed_reason, + "avatar_url": avatar_url, + } + ) + + quotes_html = self.html_templates.render_template( + "quote_item.html", quotes=quotes_list, **common_context + ) + logger.debug(f"金句HTML生成完成,长度: {len(quotes_html)}") + + # 生成活跃度可视化HTML + chart_data = self.activity_visualizer.get_hourly_chart_data( + activity_viz.hourly_activity + ) + hourly_chart_html = self.html_templates.render_template( + chart_template, chart_data=chart_data, **common_context + ) + logger.debug(f"活跃度图表HTML生成完成,长度: {len(hourly_chart_html)}") + + # 生成聊天质量锐评HTML + chat_quality_html = "" + chat_quality_review = analysis_result.get("chat_quality_review") + if not chat_quality_review and hasattr(stats, "chat_quality_review"): + chat_quality_review = stats.chat_quality_review + + if chat_quality_review: + # 如果是对象,转为字典(为了统一渲染) + if hasattr(chat_quality_review, "dimensions"): + review_data = { + "title": chat_quality_review.title, + "subtitle": chat_quality_review.subtitle, + "dimensions": [ + { + "name": d.name, + "percentage": d.percentage, + "comment": d.comment, + "color": d.color, + } + for d in chat_quality_review.dimensions + ], + "summary": chat_quality_review.summary, + } + else: + review_data = chat_quality_review + + if hide_user_names and isinstance(review_data, dict): + review_data = { + **review_data, + "title": self._sanitize_identity_text( + review_data.get("title", ""), analysis_result, True + ), + "subtitle": self._sanitize_identity_text( + review_data.get("subtitle", ""), analysis_result, True + ), + "summary": self._sanitize_identity_text( + review_data.get("summary", ""), analysis_result, True + ), + "dimensions": [ + { + **dimension, + "name": self._sanitize_identity_text( + dimension.get("name", ""), analysis_result, True + ), + "comment": self._sanitize_identity_text( + dimension.get("comment", ""), analysis_result, True + ), + } + for dimension in review_data.get("dimensions", []) + if isinstance(dimension, dict) + ], + } + + chat_quality_html = self.html_templates.render_template( + "chat_quality_item.html", **review_data, **common_context + ) + logger.debug(f"聊天质量锐评HTML生成完成,长度: {len(chat_quality_html)}") + + # 准备最终渲染数据 + render_data = { + "t2i_font_source": self.config_manager.get_t2i_font_source(), + "t2i_google_fonts_mirror": self.config_manager.get_t2i_google_fonts_mirror(), + "t2i_gstatic_mirror": self.config_manager.get_t2i_gstatic_mirror(), + "t2i_atri_font_mirror": self.config_manager.get_t2i_atri_font_mirror(), + "current_date": datetime.now().strftime("%Y年%m月%d日"), + "current_datetime": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + "message_count": stats.message_count, + "participant_count": stats.participant_count, + "total_characters": stats.total_characters, + "emoji_count": stats.emoji_count, + "most_active_period": stats.most_active_period, + "topics_html": topics_html, + "titles_html": titles_html, + "quotes_html": quotes_html, + "hourly_chart_html": hourly_chart_html, + "chat_quality_html": chat_quality_html, + "total_tokens": stats.token_usage.total_tokens + if stats.token_usage.total_tokens + else 0, + "prompt_tokens": stats.token_usage.prompt_tokens + if stats.token_usage.prompt_tokens + else 0, + "completion_tokens": stats.token_usage.completion_tokens + if stats.token_usage.completion_tokens + else 0, + "avatar_reuse_registry": avatar_reuse_registry, + "avatar_reuse_aliases": avatar_reuse_aliases, + } + + logger.debug(f"渲染数据准备完成,包含 {len(render_data)} 个字段") + return render_data + + async def _render_avatar_only_ids( + self, + user_ids: list[str], + avatar_url_getter, + avatar_cache_namespace: str | None, + avatar_reuse_registry: dict[str, str] | None, + avatar_reuse_aliases: dict[str, str] | None, + ) -> Markup: + avatars: list[Markup] = [] + for raw_user_id in user_ids: + user_id = str(raw_user_id or "").strip() + if not user_id: + continue + avatar_url = await self._get_user_avatar( + user_id, avatar_url_getter, avatar_cache_namespace + ) + avatar_ref = self._register_reusable_avatar( + avatar_url, + avatar_reuse_registry, + avatar_reuse_aliases, + avatar_key=self._get_avatar_cache_key(user_id, avatar_cache_namespace), + ) + style = ( + "width:24px;height:24px;border-radius:50%;display:inline-block;" + "vertical-align:middle;margin:0 2px;background-size:cover;" + "background-position:center;background-repeat:no-repeat;" + ) + if avatar_ref: + avatars.append( + Markup( + f'' + ) + ) + else: + avatars.append( + Markup( + f'' + ) + ) + return Markup("").join(avatars) + + async def _render_mentions( + self, + text: str, + avatar_url_getter, + nickname_getter=None, + user_analysis: dict | None = None, + avatar_cache_namespace: str | None = None, + avatar_reuse_registry: dict[str, str] | None = None, + avatar_reuse_aliases: dict[str, str] | None = None, + hide_user_names: bool = False, + allow_alphanumeric_user_ids: bool = False, + ) -> Markup: + """ + 处理文本,将 [用户ID] 格式的引用替换为头像胶囊。 + """ + if not text: + return Markup("") + + known_ids = { + str(user_id).strip() + for user_id in (user_analysis or {}) + if str(user_id).strip() + } + source_text = str(text) + supports_extended_ids = hide_user_names or allow_alphanumeric_user_ids + if supports_extended_ids: + # LLM 偶尔会直接输出 ID;先标准化为引用,避免 OpenID 以明文形式显示。 + for user_id in sorted(known_ids, key=len, reverse=True): + source_text = re.sub( + rf"(? Markup: + uid = match.group(1) + if supports_extended_ids and uid not in known_ids: + return Markup(html.escape(f"[{uid}]", quote=True)) + url = await self._get_user_avatar( + uid, avatar_url_getter, avatar_cache_namespace + ) # 内部已有缓存,无需顶层并发获取 + + name = None + # 1. 尝试从 LLM 分析结果获取 + if user_analysis and uid in user_analysis: + stats = user_analysis[uid] + name = stats.get("nickname") or stats.get("name") + if self._is_placeholder_display_name(name, uid): + name = None + + # 2. 尝试通过回调获取实时昵称 + if not name and nickname_getter: + try: + name = await nickname_getter(uid) + if self._is_placeholder_display_name(name, uid): + name = None + except Exception as e: + logger.warning(f"获取昵称失败 {uid}: {e}") + + # 胶囊样式 (Capsule Style) - 统一使用 + capsule_style = ( + "display:inline-flex;align-items:center;background:rgba(0,0,0,0.05);" + "padding:2px 6px 2px 2px;border-radius:12px;margin:0 2px;" + "vertical-align:middle;border:1px solid rgba(0,0,0,0.1);text-decoration:none;" + ) + img_style = ( + "width:18px;height:18px;border-radius:50%;" + f"margin-right:{'0' if hide_user_names else '4px'};display:block;" + ) + name_style = "font-size:0.85em;color:inherit;font-weight:500;line-height:1;" + + # 3. 最终后备: 确保有头像和名称 + final_url = url if url else self._get_default_avatar_base64() + final_name = ( + name + if (name and not self._is_placeholder_display_name(name, uid)) + else ("群友" if allow_alphanumeric_user_ids else str(uid)) + ) + + avatar_ref = self._register_reusable_avatar( + final_url, + avatar_reuse_registry, + avatar_reuse_aliases, + avatar_key=self._get_avatar_cache_key(uid, avatar_cache_namespace), + ) + if avatar_ref: + avatar_html = ( + f'' + ) + else: + avatar_html = ( + f'' + ) + + name_html = ( + "" + if hide_user_names + else f'{html.escape(final_name)}' + ) + return Markup( + f'' + f"{avatar_html}{name_html}" + ) + + result: list[Markup | str] = [] + last_end = 0 + for match in matches: + result.append( + self._escape_text_segment(source_text[last_end : match.start()]) + ) + result.append(await render_capsule(match)) + last_end = match.end() + + result.append(self._escape_text_segment(source_text[last_end:])) + return Markup("").join(result) + + @staticmethod + def _sanitize_identity_text( + text: str, analysis_result: dict, hide_user_names: bool + ) -> str: + if not hide_user_names: + return str(text) + sanitized = str(text) + user_analysis = analysis_result.get("user_analysis") or {} + known_ids = { + str(user_id).strip() for user_id in user_analysis if str(user_id).strip() + } + known_names = set() + for stats in user_analysis.values(): + if not isinstance(stats, dict): + continue + for key in ("nickname", "name"): + value = str(stats.get(key, "") or "").strip() + if value: + known_names.add(value) + for identity in sorted(known_ids | known_names, key=len, reverse=True): + sanitized = sanitized.replace(identity, "") + return re.sub(r"\[\s*\]", "", sanitized) + + @staticmethod + def _escape_text_segment(text: str) -> Markup: + return Markup(html.escape(text, quote=False).replace("\n", "
")) + + @staticmethod + def _is_placeholder_display_name(name: str | None, user_id: str) -> bool: + """判断展示名称是否为占位值。""" + if not name: + return True + normalized = str(name).strip() + if not normalized: + return True + if normalized.lower() in {"unknown", "none", "null", "nil", "undefined"}: + return True + return normalized == str(user_id).strip() + + @staticmethod + def _safe_url_for_log(url: str | None) -> str: + """对日志中的 URL 进行脱敏,避免泄露 token。""" + if not url: + return "" + # Telegram file URL: .../file/bot/ + return re.sub(r"/bot[^/]+/", "/bot/", url) + + @staticmethod + def _build_avatar_ref(avatar_key: str | None, avatar_url: str) -> str: + """根据稳定输入生成不暴露平台或用户 ID 的头像引用。""" + if avatar_key: + digest = hashlib.sha256(avatar_key.encode("utf-8")).hexdigest()[:24] + return f"avatar-{digest}" + + digest = hashlib.sha256(avatar_url.encode("utf-8")).hexdigest()[:24] + return f"avatar-{digest}" + + @staticmethod + def _register_reusable_avatar( + avatar_url: str | None, + avatar_reuse_registry: dict[str, str] | None, + avatar_reuse_aliases: dict[str, str] | None = None, + avatar_key: str | None = None, + ) -> str | None: + """将 Data URI 头像登记为可复用资源,并返回短引用 ID。""" + if not avatar_url or avatar_reuse_registry is None: + return None + if not avatar_url.startswith("data:image/"): + return None + + if avatar_reuse_aliases and avatar_url in avatar_reuse_aliases: + return avatar_reuse_aliases[avatar_url] + + ref = ReportGenerator._build_avatar_ref(avatar_key, avatar_url) + avatar_reuse_registry.setdefault(ref, avatar_url) + if avatar_reuse_aliases is not None: + avatar_reuse_aliases[avatar_url] = ref + return ref + + @staticmethod + def _build_avatar_reuse_styles(avatar_reuse_registry: dict[str, str]) -> str: + """为头像生成一次性复用样式。""" + if not avatar_reuse_registry: + return "" + + rules = [ + '") + return "\n".join(rules) + + @staticmethod + def _reuse_inline_avatar_img_sources( + html_content: str, + avatar_reuse_registry: dict[str, str], + avatar_reuse_aliases: dict[str, str] | None = None, + ) -> str: + """将最终 HTML 中的内联 Data URI 头像 img 改为短引用。""" + if not html_content: + return html_content + + img_src_pattern = re.compile( + r'(]*?\bsrc\s*=\s*)(["\'])(data:image/[^"\']+)(\2)([^>]*>)', + re.IGNORECASE | re.DOTALL, + ) + + def replace(match: re.Match[str]) -> str: + prefix, quote_char, data_uri, _, suffix = match.groups() + if data_uri == TRANSPARENT_IMAGE_DATA_URI: + return match.group(0) + + avatar_ref = ( + avatar_reuse_aliases.get(data_uri) if avatar_reuse_aliases else None + ) + if not avatar_ref: + return match.group(0) + + escaped_ref = html.escape(avatar_ref, quote=True) + return ( + f"{prefix}{quote_char}{TRANSPARENT_IMAGE_DATA_URI}{quote_char}" + f' data-avatar-ref="{escaped_ref}"{suffix}' + ) + + return img_src_pattern.sub(replace, html_content) + + @staticmethod + def _reuse_avatars_in_final_html( + html_content: str, + avatar_reuse_registry: dict[str, str] | None, + avatar_reuse_aliases: dict[str, str] | None = None, + ) -> str: + """复用最终 HTML 中所有内联头像资源,并注入复用样式。""" + if not html_content: + return html_content + + registry = avatar_reuse_registry if avatar_reuse_registry is not None else {} + aliases = avatar_reuse_aliases if avatar_reuse_aliases is not None else {} + html_content = ReportGenerator._reuse_inline_avatar_img_sources( + html_content, registry, aliases + ) + return ReportGenerator._inject_avatar_reuse_styles( + html_content, ReportGenerator._build_avatar_reuse_styles(registry) + ) + + @staticmethod + def _inject_avatar_reuse_styles(html_content: str, avatar_reuse_styles: str) -> str: + """将头像复用样式注入最终 HTML。""" + if not html_content or not avatar_reuse_styles: + return html_content + + head_close = re.search(r"", html_content, re.IGNORECASE) + if head_close: + return ( + html_content[: head_close.start()] + + avatar_reuse_styles + + "\n" + + html_content[head_close.start() :] + ) + return avatar_reuse_styles + "\n" + html_content + + def _get_avatar_cache_key( + self, avatar_id: str, avatar_cache_namespace: str | None = None + ) -> str: + """生成头像缓存键,避免不同平台的同一数字 ID 互相污染。""" + namespace = str(avatar_cache_namespace or "legacy").strip() or "legacy" + return f"{namespace}:{avatar_id}" + + async def _get_user_avatar( + self, + avatar_id: str, + avatar_url_getter=None, + avatar_cache_namespace: str | None = None, + ) -> str: + """ + 获取用户头像的 Base64 Data URI。 + 使用磁盘缓存,支持跨任务复用。失败结果短时缓存,避免同一报告重复请求。 + """ + cache_key = self._get_avatar_cache_key(avatar_id, avatar_cache_namespace) + # 1. 检查缓存 (仅包含成功的头像数据) + if cache_key in self._avatar_cache: + data = self._avatar_cache[cache_key] + if isinstance(data, str): + return data + return str(data) + + failure_cache = getattr(self, "_avatar_failure_cache", {}) + failed_until = failure_cache.get(cache_key, 0) + if failed_until > time.monotonic(): + return self._get_default_avatar_base64() + failure_cache.pop(cache_key, None) + + # 2. 尝试获取头像字节流 + avatar_bytes = await self._get_user_avatar_bytes(avatar_id, avatar_url_getter) + + if not avatar_bytes: + failure_cache[cache_key] = ( + time.monotonic() + AVATAR_FAILURE_CACHE_EXPIRE_TIME + ) + self._avatar_failure_cache = failure_cache + logger.debug(f"获取用户头像失败 {avatar_id},本次将使用回退头像") + return self._get_default_avatar_base64() + + # 3. 获取成功:转换并缓存 + avatar = self._b64_with_mime(self._resize_avatar_bytes(avatar_bytes)) + if avatar: + self._avatar_cache.set(cache_key, avatar, expire=AVATAR_CACHE_EXPIRE_TIME) + failure_cache.pop(cache_key, None) + return avatar + + failure_cache[cache_key] = time.monotonic() + AVATAR_FAILURE_CACHE_EXPIRE_TIME + self._avatar_failure_cache = failure_cache + return self._get_default_avatar_base64() + + @staticmethod + def _resize_avatar_bytes(payload: bytes) -> bytes: + """缩放头像后再嵌入 HTML,降低渲染请求体积。 + + Args: + payload: 下载得到的头像二进制数据。 + + Returns: + 压缩后的头像;解码失败时返回原始数据。 + """ + try: + with Image.open(BytesIO(payload)) as image: + image.load() + image.thumbnail( + (AVATAR_MAX_EDGE_LENGTH, AVATAR_MAX_EDGE_LENGTH), + Image.Resampling.LANCZOS, + ) + output = BytesIO() + if image.mode in {"RGBA", "LA"} or "transparency" in image.info: + image.convert("RGBA").save(output, format="PNG", optimize=True) + else: + image.convert("RGB").save( + output, + format="JPEG", + quality=85, + optimize=True, + ) + return output.getvalue() + except (OSError, UnidentifiedImageError): + return payload + + def _b64_with_mime(self, _bytes: bytes) -> str | None: + """将字节数据转换为 Base64 Data URI,并自动识别 MIME 类型。""" + try: + b64 = base64.b64encode(_bytes).decode("utf-8") + # 简单判断 mime type + mime = "image/jpeg" + if _bytes.startswith(b"\x89PNG"): + mime = "image/png" + elif _bytes.startswith(b"GIF8"): + mime = "image/gif" + elif _bytes.startswith(b"RIFF") and b"WEBP" in _bytes[8:16]: + mime = "image/webp" + elif _bytes.startswith(b"\xff\xd8"): + mime = "image/jpeg" + + return f"data:{mime};base64,{b64}" + except Exception as e: + logger.error(f"base64 转换失败: {e}", exc_info=True) + return None + + async def _get_user_avatar_bytes( + self, user_id: str, avatar_url_getter=None + ) -> bytes | None: + """核心头像获取逻辑""" + avatar_session_lock = getattr(self, "_avatar_session_lock", None) + if avatar_session_lock is None: + avatar_session_lock = asyncio.Lock() + self._avatar_session_lock = avatar_session_lock + async with avatar_session_lock: + if not self._avatar_session or self._avatar_session.closed: + self._avatar_session = aiohttp.ClientSession( + trust_env=True, timeout=aiohttp.ClientTimeout(total=15) + ) + async with self._avatar_session_concurrent_semaphore: + avatar_url = None + if avatar_url_getter: + try: + # avatar_url_getter 应该返回 URL + result = await avatar_url_getter(user_id) + if result: + if result.startswith("http"): + avatar_url = result + elif result.startswith("base64://"): + return base64.b64decode(result[len("base64://") :]) + elif result.startswith("data:"): + parts = result.split(",", 1) + if len(parts) == 2: + return base64.b64decode(parts[1]) + else: + logger.warning( + "自定义头像地址获取器返回了非 HTTP 地址: " + f"{result[:50]}..." + ) + except Exception as e: + logger.warning(f"使用自定义头像地址获取器失败: {e}") + + if not avatar_url: + if ( + avatar_url_getter is None + and user_id.isdigit() + and 5 <= len(user_id) <= 12 + ): + # 强制使用 spec=40 + avatar_url = ( + f"https://q4.qlogo.cn/headimg_dl?dst_uin={user_id}&spec=40" + ) + else: + # 其他平台若无 URL,无法获取头像 + return None + + # 5. 下载并保存 + safe_avatar_url = self._safe_url_for_log(avatar_url) + failure_reason = "" + for attempt in range(1, AVATAR_DOWNLOAD_RETRY_TIMES + 1): + try: + async with self._avatar_session.get(avatar_url) as response: + if response.status == 200: + content = await response.read() + if not content: + failure_reason = "响应内容为空" + elif content.startswith( + (b"\xff\xd8", b"\x89PNG\r\n\x1a\n", b"GIF8") + ) or ( + content.startswith(b"RIFF") and b"WEBP" in content[:16] + ): + return content + else: + logger.warning( + f"下载的头像数据格式无效 ({safe_avatar_url})" + ) + return None + else: + failure_reason = f"HTTP {response.status}" + if ( + response.status not in {408, 429} + and response.status < 500 + ): + logger.warning( + f"下载头像失败 {safe_avatar_url}: {failure_reason}" + ) + return None + except (aiohttp.ClientError, asyncio.TimeoutError) as e: + # 部分 aiohttp 断连异常的字符串为空,保留异常类型便于定位。 + failure_reason = f"{type(e).__name__}: {e!r}" + except Exception as e: + logger.warning( + f"下载头像发生未知错误 {safe_avatar_url}: " + f"{type(e).__name__}: {e!r}" + ) + return None + + if attempt < AVATAR_DOWNLOAD_RETRY_TIMES: + logger.debug( + f"下载头像失败,将在短暂等待后重试 " + f"({attempt}/{AVATAR_DOWNLOAD_RETRY_TIMES}): " + f"{safe_avatar_url},原因: {failure_reason}" + ) + await asyncio.sleep(0.5 * attempt) + + logger.warning( + f"下载头像网络错误,已重试 {AVATAR_DOWNLOAD_RETRY_TIMES} 次 " + f"{safe_avatar_url}: {failure_reason}" + ) + return None + + def _get_default_avatar_base64(self) -> str: + """返回默认头像 (灰色圆形占位符)""" + # 一个简单的灰色圆圈 SVG 转 Base64 + svg = '' + b64 = base64.b64encode(svg.encode("utf-8")).decode("utf-8") + return f"data:image/svg+xml;base64,{b64}" + + async def close(self): + """释放资源,关闭缓存和 session""" + if self._avatar_session: + await self._avatar_session.close() + self._avatar_session = None + + try: + if self._avatar_cache: + self._avatar_cache.close() + logger.debug("头像缓存已关闭") + except Exception as e: + logger.warning(f"关闭头像缓存失败: {e}") + + def _extract_html_error_summary(self, data: bytes) -> str | None: + """从返回的字节流中尝试提取 HTML 错误信息(如 )""" + try: + content = data.decode("utf-8", errors="ignore") + content_lower = content.lower() + if "<html" in content_lower or "<!doctype html" in content_lower: + # 尝试提取标题 + title_match = re.search( + r"<title>(.*?)", content, re.IGNORECASE | re.DOTALL + ) + if title_match: + return f"HTML 错误页: {title_match.group(1).strip()}" + + # 尝试提取 h1 + h1_match = re.search( + r"

(.*?)

", content, re.IGNORECASE | re.DOTALL + ) + if h1_match: + return f"HTML 错误页: {h1_match.group(1).strip()}" + + return f"HTML 响应 (前100字): {content[:100].strip()}..." + except Exception: + pass + return None diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/platform_templates/qq_official/summary_dashboard.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/platform_templates/qq_official/summary_dashboard.html new file mode 100644 index 0000000..d0eb4ed --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/platform_templates/qq_official/summary_dashboard.html @@ -0,0 +1,173 @@ + + + + + + + + +
+
+
{{ report_title }}
+
{{ report_date }}
+
+ +
+ {% for metric in metrics %} +
+
{{ metric.value }}
+
{{ metric.label }}
+
+ {% endfor %} +
+ +
+ {% for item in chart_data %} +
+
+
+
+
{{ item.hour }}
+
+ {% endfor %} +
+
+ + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/qq_official_markdown.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/qq_official_markdown.py new file mode 100644 index 0000000..28ba4c2 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/qq_official_markdown.py @@ -0,0 +1,336 @@ +"""QQ Official Bot-specific Markdown report generation.""" + +from __future__ import annotations + +import re +from datetime import datetime +from typing import Any + +from ...utils.logger import logger + + +class QQOfficialMarkdownReportGenerator: + """Generate QQ Official Markdown without changing other platform reports.""" + + def __init__( + self, + config_manager: Any, + html_templates: Any = None, + render_semaphore: Any = None, + ) -> None: + self.config_manager = config_manager + self.html_templates = html_templates + self.render_semaphore = render_semaphore + + async def generate( + self, analysis_result: dict, html_render_func=None + ) -> tuple[str, str]: + """Generate QQ Markdown and a URL-free Markdown fallback report.""" + fallback_report = self._generate_markdown_report(analysis_result) + enabled = self.config_manager.get_qq_official_t2i_summary_dashboard_enabled() + if not enabled or not callable(html_render_func) or self.html_templates is None: + return fallback_report, fallback_report + + dashboard_url = await self._generate_summary_dashboard_url( + analysis_result, html_render_func + ) + if not dashboard_url: + return fallback_report, fallback_report + return ( + self._generate_markdown_report( + analysis_result, summary_dashboard_url=dashboard_url + ), + fallback_report, + ) + + async def _generate_summary_dashboard_url( + self, analysis_result: dict, html_render_func + ) -> str | None: + stats = analysis_result["statistics"] + hourly_counts = self.get_hourly_counts(stats) + max_count = max(hourly_counts, default=0) + chart_data = [ + { + "hour": f"{hour:02d}", + "count": count, + "height": ( + max(2, round(count / max_count * 100)) + if count > 0 and max_count > 0 + else 0 + ), + } + for hour, count in enumerate(hourly_counts) + ] + metrics = [ + {"value": self.format_metric(stats.message_count), "label": "消息"}, + {"value": self.format_metric(stats.participant_count), "label": "参与"}, + {"value": self.format_metric(stats.total_characters), "label": "字符"}, + {"value": self.format_metric(stats.emoji_count), "label": "表情"}, + { + "value": self.format_peak_period(stats.most_active_period), + "label": "高峰", + }, + ] + html_content = self.html_templates.render_platform_template( + "qq_official", + "summary_dashboard.html", + report_title="群聊日常分析", + report_date=datetime.now().strftime("%Y.%m.%d"), + metrics=metrics, + chart_data=chart_data, + ) + if not html_content: + return None + + options = { + "type": "png", + "omit_background": True, + "full_page": False, + "clip": {"x": 0, "y": 0, "width": 800, "height": 360}, + "animations": "disabled", + "caret": "hide", + "scale": "device", + "device_scale_factor_level": "high", + "timeout": 30000, + } + + async def render() -> str | None: + result = await html_render_func(html_content, {}, True, options) + url = str(result or "").strip() + if url.startswith(("http://", "https://")): + return url + logger.warning("[QQOfficial] T2I 概览图未返回可公开访问的 URL") + return None + + try: + if self.render_semaphore is None: + return await render() + async with self.render_semaphore: + return await render() + except Exception as exc: + logger.warning("[QQOfficial] T2I 群聊概览图生成失败: %s", exc) + return None + + def _generate_markdown_report( + self, analysis_result: dict, summary_dashboard_url: str | None = None + ) -> str: + stats = analysis_result["statistics"] + topics = analysis_result["topics"] + user_titles = analysis_result["user_titles"] + + if summary_dashboard_url: + lines = [ + f"![群聊分析概览 #800px #360px]({summary_dashboard_url})", + "", + ] + else: + lines = [ + "# 🎯 群聊日常分析报告", + f"📅 {datetime.now().strftime('%Y年%m月%d日')}", + "", + "## 📊 基础统计", + f"- **消息总数**:{stats.message_count}", + f"- **参与人数**:{stats.participant_count}", + f"- **总字符数**:{stats.total_characters}", + f"- **表情数量**:{stats.emoji_count}", + f"- **最活跃时段**:{stats.most_active_period}", + "", + ] + activity_chart = self.build_activity_chart(stats) + if activity_chart: + lines.extend(activity_chart) + lines.append("") + + lines.append("## 💬 热门话题") + max_topics = self.config_manager.get_max_topics() + for index, topic in enumerate(topics[:max_topics], 1): + topic_name = self.render_identity_text(topic.topic, analysis_result) + lines.append(f"### {index}. {topic_name}") + contributor_ids = list(getattr(topic, "contributor_ids", []) or []) + mentions = self.mentions(contributor_ids) + if mentions: + lines.append(f"**参与者**:{mentions}") + detail = self.render_identity_text(topic.detail, analysis_result) + if detail: + lines.append(detail) + lines.append("") + + lines.append("## 🏆 群友称号") + max_user_titles = self.config_manager.get_max_user_titles() + for title in user_titles[:max_user_titles]: + mention = self.mention(getattr(title, "user_id", "")) + title_text = self.render_identity_text(title.title, analysis_result) + mbti = f" · {title.mbti}" if getattr(title, "mbti", "") else "" + prefix = f"{mention} — " if mention else "" + lines.append(f"- {prefix}**{title_text}**{mbti}") + reason = self.render_identity_text(title.reason, analysis_result) + if reason: + lines.append(f" > {reason}") + lines.append("") + + lines.append("## 💬 群圣经") + max_golden_quotes = self.config_manager.get_max_golden_quotes() + for index, golden_quote in enumerate( + stats.golden_quotes[:max_golden_quotes], 1 + ): + quote_content = self.render_identity_text( + golden_quote.content, analysis_result + ) + mention = self.mention(getattr(golden_quote, "user_id", "")) + attribution = f" — {mention}" if mention else "" + lines.append(f"- **{index}. {quote_content}**{attribution}") + reason = self.render_identity_text(golden_quote.reason, analysis_result) + if reason: + lines.append(f" > {reason}") + lines.append("") + + return "\n".join(lines).strip() + + @staticmethod + def format_metric(value: object) -> str: + try: + number = max(0, int(value) if value is not None else 0) # type: ignore[arg-type] + except (TypeError, ValueError): + return "0" + if number >= 1_000_000: + formatted = f"{number / 1_000_000:.1f}".rstrip("0").rstrip(".") + return f"{formatted}M" + if number >= 10_000: + formatted = f"{number / 1_000:.1f}".rstrip("0").rstrip(".") + return f"{formatted}K" + return f"{number:,}" + + @staticmethod + def format_peak_period(value: object) -> str: + text = str(value or "").strip() + match = re.search(r"(\d{1,2}):\d{2}\s*[-~—至]\s*(\d{1,2}):\d{2}", text) + if match: + return f"{int(match.group(1)):02d}–{int(match.group(2)):02d}" + return text or "—" + + @classmethod + def build_activity_chart(cls, stats: object, bar_width: int = 12) -> list[str]: + hourly_counts = cls.get_hourly_counts(stats) + max_count = max(hourly_counts, default=0) + if max_count <= 0: + return [] + + effective_width = max(1, int(bar_width)) + lines = ["## ⏰ 活跃时间分布"] + for hour, count in enumerate(hourly_counts): + if count > 0: + blocks = max( + 1, + (count * effective_width + max_count - 1) // max_count, + ) + bar = "█" * blocks + else: + bar = "—" + lines.append(f"- {hour:02d}:00 {bar} {count}") + return lines + + @staticmethod + def get_hourly_counts(stats: object) -> list[int]: + activity_viz = getattr(stats, "activity_visualization", None) + raw_activity = getattr(activity_viz, "hourly_activity", None) or {} + if not isinstance(raw_activity, dict): + return [0] * 24 + + hourly_counts: list[int] = [] + for hour in range(24): + raw_count = raw_activity.get(hour, raw_activity.get(str(hour), 0)) + try: + count = max(0, int(raw_count or 0)) + except (TypeError, ValueError): + count = 0 + hourly_counts.append(count) + return hourly_counts + + @staticmethod + def mention(user_id: object) -> str: + normalized = str(user_id or "").strip().strip("[]") + return f"<@{normalized}>" if normalized else "" + + @classmethod + def mentions(cls, user_ids: list[object]) -> str: + unique_ids = list( + dict.fromkeys( + str(user_id or "").strip().strip("[]") + for user_id in user_ids + if str(user_id or "").strip().strip("[]") + ) + ) + return " ".join(cls.mention(user_id) for user_id in unique_ids) + + @classmethod + def render_identity_text(cls, text: object, analysis_result: dict) -> str: + """Replace known IDs and display names with QQ mention syntax.""" + source = str(text or "") + user_analysis = analysis_result.get("user_analysis") or {} + id_to_names: dict[str, set[str]] = {} + + for user_id, user_data in user_analysis.items(): + normalized_id = str(user_id or "").strip() + if not normalized_id: + continue + names: set[str] = set() + if isinstance(user_data, dict): + for key in ("nickname", "name", "card"): + name = str(user_data.get(key, "") or "").strip() + if name and name != normalized_id: + names.add(name) + id_to_names[normalized_id] = names + + for title in analysis_result.get("user_titles", []) or []: + user_id = str(getattr(title, "user_id", "") or "").strip() + name = str(getattr(title, "name", "") or "").strip() + if user_id: + id_to_names.setdefault(user_id, set()) + if name and name != user_id: + id_to_names[user_id].add(name) + + stats = analysis_result.get("statistics") + for golden_quote in getattr(stats, "golden_quotes", []) or []: + user_id = str(getattr(golden_quote, "user_id", "") or "").strip() + name = str(getattr(golden_quote, "sender", "") or "").strip() + if user_id: + id_to_names.setdefault(user_id, set()) + if name and name != user_id: + id_to_names[user_id].add(name) + + placeholders: dict[str, str] = {} + + def protect_mention(match: re.Match[str]) -> str: + key = f"\x00QQMENTION{len(placeholders)}\x00" + placeholders[key] = match.group(0) + return key + + source = re.sub(r"<@[A-Za-z0-9_-]+>", protect_mention, source) + for user_id in sorted(id_to_names, key=len, reverse=True): + mention = cls.mention(user_id) + source = re.sub(rf"\[{re.escape(user_id)}\]", mention, source) + source = re.sub(r"<@[A-Za-z0-9_-]+>", protect_mention, source) + source = re.sub( + rf"(?", protect_mention, source) + + source = re.sub(r"<@[A-Za-z0-9_-]+>", protect_mention, source) + name_to_ids: dict[str, set[str]] = {} + for user_id, names in id_to_names.items(): + for name in names: + if name: + name_to_ids.setdefault(name, set()).add(user_id) + for name in sorted(name_to_ids, key=len, reverse=True): + matched_ids = name_to_ids[name] + replacement = ( + cls.mention(next(iter(matched_ids))) if len(matched_ids) == 1 else "" + ) + source = source.replace(name, replacement) + source = re.sub(r"<@[A-Za-z0-9_-]+>", protect_mention, source) + + for placeholder, mention in placeholders.items(): + source = source.replace(placeholder, mention) + return source.strip() diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates.py new file mode 100644 index 0000000..0542118 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates.py @@ -0,0 +1,275 @@ +""" +HTML模板模块 +使用Jinja2加载外部HTML模板文件 +""" + +from __future__ import annotations + +import asyncio +import hashlib +import os +import threading +from pathlib import Path +from typing import Any + +from jinja2 import ChoiceLoader, Environment, FileSystemLoader, select_autoescape + +from ...utils.logger import logger + + +class HTMLTemplates: + """HTML模板管理类""" + + def __init__(self, config_manager): + """初始化Jinja2环境""" + self.config_manager = config_manager + # 设置模板根目录 + self.base_dir = os.path.join(os.path.dirname(__file__), "templates") + self.platform_base_dir = os.path.join( + os.path.dirname(__file__), "platform_templates" + ) + # 缓存不同模板的Jinja2环境(多线程安全) + self._envs = {} + self._env_lock = threading.Lock() + + KNOWN_TEMPLATE_NAMES: dict[str, str] = { + "scrapbook": "手账风格 (Scrapbook / 默认)", + "ATRI": "亚托莉 (ATRI)", + "HatsuneMiku": "初音未来 (HatsuneMiku)", + "spring_festival": "新春佳节 (Spring Festival)", + "retro_futurism": "复古未来 (Retro Futurism)", + "hack": "黑客赛博 (Hack)", + "BlueArchive": "蔚蓝档案 (BlueArchive)", + "simple": "极简黑白 (Simple)", + } + + def _get_env_sync(self, template_theme: str | None = None) -> Environment: + """获取当前配置或指定主题的模板环境(同步版本,供 asyncio.to_thread 调用)""" + template_name = template_theme or self.config_manager.get_report_template() + + # 如果环境已缓存且配置未变(使用锁保证多线程安全) + with self._env_lock: + env = self._envs.get(template_name) + if env is not None: + return env + + template_dir = os.path.join(self.base_dir, template_name) + get_custom_template_dir = getattr( + self.config_manager, "get_custom_report_template_dir", None + ) + custom_template_res = ( + get_custom_template_dir(template_name) + if callable(get_custom_template_dir) + else None + ) + custom_template_dir = ( + Path(str(custom_template_res)) if custom_template_res else None + ) + + loaders = [] + if custom_template_dir and custom_template_dir.exists(): + loaders.append(FileSystemLoader(str(custom_template_dir))) + if os.path.exists(template_dir): + loaders.append(FileSystemLoader(template_dir)) + + # 若目标模板既不在自定义目录也不在内置目录,回退到默认的 scrapbook + if not loaders: + logger.warning(f"模板目录不存在: {template_dir},回退到 scrapbook") + template_name = "scrapbook" + template_dir = os.path.join(self.base_dir, template_name) + loaders.append(FileSystemLoader(template_dir)) + else: + # 无论何种情况,将默认的 scrapbook 目录追加为最底层 Fallback,避免自定义模板缺少局部组件时渲染失败 + default_dir = os.path.join(self.base_dir, "scrapbook") + if default_dir != template_dir and not any( + isinstance(ld, FileSystemLoader) and ld.searchpath == [default_dir] + for ld in loaders + ): + loaders.append(FileSystemLoader(default_dir)) + + env = Environment( + loader=ChoiceLoader(loaders), + autoescape=select_autoescape(["html", "xml"]), + trim_blocks=True, + lstrip_blocks=True, + ) + + # 使用双重检查锁定,避免在高并发下重复创建相同 template_name 的 env + with self._env_lock: + existing = self._envs.get(template_name) + if existing is not None: + return existing + self._envs[template_name] = env + + return env + + def get_available_templates(self) -> list[dict[str, Any]]: + """动态扫描内置与自定义数据目录,返回所有可用的视觉主题模板列表""" + found_themes: dict[str, dict[str, Any]] = {} + + # 1. 扫描内置模板目录 + if os.path.isdir(self.base_dir): + for entry in sorted(os.listdir(self.base_dir)): + if entry.startswith(".") or entry == "format": + continue + p = os.path.join(self.base_dir, entry) + if os.path.isdir(p): + has_image = os.path.exists(os.path.join(p, "image_template.html")) + has_html = os.path.exists(os.path.join(p, "html_template.html")) + if has_image or has_html: + label = self.KNOWN_TEMPLATE_NAMES.get( + entry, f"{entry} (内置模板)" + ) + found_themes[entry] = { + "id": entry, + "label": label, + "is_custom": False, + "has_image": has_image, + "has_html": has_html, + } + + # 2. 扫描用户自定义模板目录 + get_custom_dir = getattr( + self.config_manager, "get_custom_report_template_dir", None + ) + custom_base: Path | None = None + if callable(get_custom_dir): + sample_res = get_custom_dir("") + if sample_res: + p_sample = Path(str(sample_res)) + custom_base = p_sample if p_sample.is_dir() else p_sample.parent + + if custom_base and custom_base.is_dir(): + for p in sorted(custom_base.iterdir()): + if p.is_dir() and not p.name.startswith("."): + entry = p.name + has_image = (p / "image_template.html").exists() + has_html = (p / "html_template.html").exists() + if has_image or has_html: + builtin_label = self.KNOWN_TEMPLATE_NAMES.get(entry) + builtin_dir = os.path.join(self.base_dir, entry) + + is_custom = True + if builtin_label and os.path.isdir(builtin_dir): + # 对比自定义目录与内置目录中的所有 HTML 文件哈希,避免未修改时误判 + is_truly_modified = False + for ch_file in p.glob("*.html"): + bh_file = Path(builtin_dir) / ch_file.name + if not bh_file.exists(): + is_truly_modified = True + break + try: + if ( + hashlib.sha256(ch_file.read_bytes()).digest() + != hashlib.sha256(bh_file.read_bytes()).digest() + ): + is_truly_modified = True + break + except Exception: + is_truly_modified = True + break + + if not is_truly_modified: + is_custom = False + custom_label = builtin_label + else: + custom_label = f"{builtin_label} (自定义修改版)" + else: + custom_label = f"{entry} (自定义本地模板)" + + found_themes[entry] = { + "id": entry, + "label": custom_label, + "is_custom": is_custom, + "has_image": has_image, + "has_html": has_html, + } + + # 确保默认的 scrapbook 始终位于第一个 + result = [] + if "scrapbook" in found_themes: + result.append(found_themes.pop("scrapbook")) + result.extend(found_themes.values()) + return result + + async def _get_env_async(self, template_theme: str | None = None) -> Environment: + """获取当前配置或指定主题的模板环境(异步版本)""" + return await asyncio.to_thread(self._get_env_sync, template_theme) + + def _get_env(self, template_theme: str | None = None) -> Environment: + """获取当前配置或指定主题的模板环境(同步版本,向后兼容)""" + return self._get_env_sync(template_theme=template_theme) + + def _read_template_file_sync(self, filename: str) -> str: + """同步读取模板文件内容""" + with open(filename, encoding="utf-8") as f: + return f.read() + + async def get_image_template_async(self) -> str: + """获取图片报告的HTML模板(异步版本,返回原始模板字符串)""" + try: + env = await self._get_env_async() + template = env.get_template("image_template.html") + if template.filename is None: + logger.error("图片模板路径为空") + return "" + return await asyncio.to_thread( + self._read_template_file_sync, template.filename + ) + except Exception as e: + logger.error(f"加载图片模板失败: {e}") + return "" + + def get_image_template(self) -> str: + """获取图片报告的HTML模板(同步版本,向后兼容)""" + try: + env = self._get_env() + template = env.get_template("image_template.html") + if template.filename is None: + logger.error("图片模板路径为空") + return "" + with open(template.filename, encoding="utf-8") as f: + return f.read() + except Exception as e: + logger.error(f"加载图片模板失败: {e}") + return "" + + def render_template( + self, template_name: str, template_theme: str | None = None, **kwargs + ) -> str: + """渲染指定的模板文件 + + Args: + template_name: 模板文件名 + template_theme: 可选指定的主题模板名称 + **kwargs: 传递给模板的变量 + + Returns: + 渲染后的HTML字符串 + """ + try: + env = self._get_env(template_theme=template_theme) + template = env.get_template(template_name) + return template.render(**kwargs) + except Exception as e: + logger.error( + f"渲染模板 {template_name} (theme: {template_theme}) 失败: {e}" + ) + return "" + + def render_platform_template( + self, platform_name: str, template_name: str, **kwargs + ) -> str: + """渲染与报告主题解耦的平台专用模板。""" + try: + template_dir = os.path.join(self.platform_base_dir, platform_name) + env = Environment( + loader=FileSystemLoader(template_dir), + autoescape=select_autoescape(["html", "xml"]), + trim_blocks=True, + lstrip_blocks=True, + ) + return env.get_template(template_name).render(**kwargs) + except Exception as e: + logger.error(f"渲染平台模板 {platform_name}/{template_name} 失败: {e}") + return "" diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/activity_chart.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/activity_chart.html new file mode 100644 index 0000000..bb2dd7a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/activity_chart.html @@ -0,0 +1,53 @@ +
+
+ {% for hour_data in chart_data %} + {% set ratio = loop.index0 / ((chart_data|length - 1) if (chart_data|length - 1) > 0 else 1) %} + {% if ratio < 0.3333 %} + {% set local_ratio = ratio / 0.3333 %} + {% set top_red = (210 + local_ratio * 45)|round|int %} + {% set top_green = (225 + local_ratio * 15)|round|int %} + {% set top_blue = (255 - local_ratio * 25)|round|int %} + {% set bottom_red = (170 + local_ratio * 85)|round|int %} + {% set bottom_green = (190 - local_ratio * 5)|round|int %} + {% set bottom_blue = (255 - local_ratio * 55)|round|int %} + {% elif ratio < 0.6666 %} + {% set local_ratio = (ratio - 0.3333) / 0.3333 %} + {% set top_red = (255 - local_ratio * 20)|round|int %} + {% set top_green = (240 + local_ratio * 15)|round|int %} + {% set top_blue = (230 + local_ratio * 10)|round|int %} + {% set bottom_red = (255 - local_ratio * 105)|round|int %} + {% set bottom_green = (185 + local_ratio * 45)|round|int %} + {% set bottom_blue = 200 %} + {% else %} + {% set local_ratio = (ratio - 0.6666) / 0.3334 %} + {% set top_red = (235 - local_ratio * 25)|round|int %} + {% set top_green = (255 - local_ratio * 30)|round|int %} + {% set top_blue = (240 + local_ratio * 15)|round|int %} + {% set bottom_red = (150 + local_ratio * 20)|round|int %} + {% set bottom_green = (230 - local_ratio * 40)|round|int %} + {% set bottom_blue = (200 + local_ratio * 55)|round|int %} + {% endif %} + {% set count_red = (bottom_red * 0.7)|round|int %} + {% set count_green = (bottom_green * 0.7)|round|int %} + {% set count_blue = (bottom_blue * 0.7)|round|int %}
+
+ {{hour_data.count}} +
+
+ {{hour_data.hour}} +
+ {% endfor %} +
+
diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/chat_quality_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/chat_quality_item.html new file mode 100644 index 0000000..b0d3a5e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/chat_quality_item.html @@ -0,0 +1,155 @@ + + +
+
+
+
{{ title }}
+
{{ subtitle }}
+
+
+ +
+ {% for dim in dimensions %} +
+
{{ dim.name }}
+
+
+
+
{{ dim.percentage }}%
+
+ {% endfor %} +
+ +
+ {% for dim in dimensions %} +
+ {{ dim.name }} +
{{ dim.comment }}
+
+ {% endfor %} +
+ +
{{ summary }}
+
diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/html_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/html_template.html new file mode 100644 index 0000000..c85afca --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/html_template.html @@ -0,0 +1,3101 @@ + + + + + + + ATRI 群聊日报 · {{ current_date }} + + + + + +
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ ATRI decor + +
+
+
+ +
+
+
A.T.R.I · Daily Communication Report
+

亚托莉的群聊观测日志

+
+ 主人,今天群里的大家也超级精神呢!身为高性能的亚托莉,已经把所有闪闪发光的聊天记忆,像打捞海底宝藏一样全都收集好啦! +
+
+
+
REPORT GENERATED
+
✦
+
{{ current_date }}
{{ current_datetime }}
+
+
+ +
+
+
+
+ + + +
+ Overview + cute icon +
+

来看看今天都发生了什么吧!

+
+ 报告主人!今天一共捕获了 {{ message_count }} 条消息,有 {{ participant_count }} + 位群友浮出水面参与了互动哦!我都仔细做好了备忘录哦,哼哼! +
+ ATRI main +
+ +
+
+
+
MOST ACTIVE PERIOD
+
{{ current_datetime }}
+
{{ most_active_period }}
+
+ 这段时间的心跳值达到最高峰!大家的讨论就像退缩时沙滩上的贝壳一样密集,是今天最棒的高光时刻! +
+
+
+ ATRI peak +
+
+ +
+
+
+ +
+
+
{{ message_count }}
+
消息总数
+
+
+
+
+ +
+
+
{{ participant_count }}
+
参与人数
+
+
+
+
+ +
+
+
{{ total_characters }}
+
总字符数
+
+
+
+
+ +
+
+
{{ emoji_count }}
+
表情数量
+
+
+
+ +
+
+
+
+ +
+
+

心跳潮汐kawaii icon

+
一整天的心跳节拍,由亚托莉为您完美记录
+
+
+
TIDE CHART badge icon +
+
+
{{ hourly_chart_html | safe }}
+
+ +
+
+
+
+ +
+
+

高亮记忆碎片kawaii icon

+
亚托莉捕获的最亮眼的记忆碎片!
+
+
+
TOPIC BOARD badge icon +
+
+
{{ topics_html | safe }}
+
+ +
+
+
+
+ +
+
+

神人名片颁发kawaii icon

+
颁发给各位的高性能称号!
+
+
+
SPOTLIGHT badge icon +
+
+
{{ titles_html | safe }}
+
+ +
+
+
+
+ +
+
+

亚托莉的宝藏瓶kawaii icon

+
亚托莉偷偷记在小本子上的宝藏名言!
+
+
+
PRECIOUS WORDS badge icon +
+
+
{{ quotes_html | safe }}
+
+ + {% if chat_quality_html %} +
+
+
+
+ +
+
+

亚托莉观测报告kawaii icon

+
来自高性能亚托莉的每日特别观测报告!
+
+
+
GROUP VIBE badge icon +
+
+
{{ chat_quality_html | safe }}
+
+ {% endif %} + +
+
+
+
+ +
+
+

能量解析雷达kawaii icon

+
维持亚托莉运行与心跳的能量消耗~
+
+
+
ENERGY COST badge icon +
+
+
+
+
总消耗
+
{{ total_tokens }}
+
+
+
提示词 Token
+
{{ prompt_tokens }}
+
+
+
生成内容 Token
+
{{ completion_tokens }}
+
+
+
+ + +
+
+ + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/image_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/image_template.html new file mode 100644 index 0000000..2fc3505 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/image_template.html @@ -0,0 +1,1928 @@ + + + + + + + ATRI 群聊日报 · {{ current_date }} + + + + + +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ ATRI decor + +
+
+
+
A.T.R.I · Daily Communication Report
+

亚托莉的群聊观测日志

+
+ 主人,今天群里的大家也超级精神呢!身为高性能的亚托莉,已经把所有闪闪发光的聊天记忆,像打捞海底宝藏一样全都收集好啦! +
+
+
+
REPORT GENERATED
+
✦
+
{{ current_date }}
{{ current_datetime }}
+
+
+ +
+
+
+
+ + + +
+ Overview + cute icon +
+

来看看今天
都发生了什
么吧!

+
+ 报告主人!今天一共捕获了 {{ message_count }} 条消息,有 {{ participant_count }} + 位群友浮出水面参与了互动哦!我都仔细做好了备忘录哦,哼哼! +
+ ATRI main +
+ +
+
+
+
MOST ACTIVE PERIOD
+
{{ current_datetime }}
+
{{ most_active_period }}
+
+ 这段时间的心跳值达到最高峰!大家的讨论就像退缩时沙滩上的贝壳一样密集,是今天最棒的高光时刻! +
+
+
+ ATRI peak +
+
+ +
+
+
+ +
+
+
{{ message_count }}
+
消息总数
+
+
+
+
+ +
+
+
{{ participant_count }}
+
参与人数
+
+
+
+
+ +
+
+
{{ total_characters }}
+
总字符数
+
+
+
+
+ +
+
+
{{ emoji_count }}
+
表情数量
+
+
+
+ +
+
+
+
+ +
+
+

心跳潮汐kawaii icon

+
一整天的心跳节拍,由亚托莉为您完美记录
+
+
+
TIDE CHART badge icon
+
+
{{ hourly_chart_html | safe }}
+
+ +
+
+
+
+ +
+
+

高亮记忆碎片kawaii icon

+
亚托莉捕获的最亮眼的记忆碎片!
+
+
+
TOPIC BOARD badge icon
+
+
{{ topics_html | safe }}
+
+ +
+
+
+
+ +
+
+

神人名片颁发kawaii icon

+
颁发给各位的高性能称号!
+
+
+
SPOTLIGHT badge icon
+
+
{{ titles_html | safe }}
+
+ +
+
+
+
+ +
+
+

亚托莉的宝藏瓶kawaii icon

+
亚托莉偷偷记在小本子上的宝藏名言!
+
+
+
PRECIOUS WORDS badge icon
+
+
{{ quotes_html | safe }}
+
+ + {% if chat_quality_html %} +
+
+
+
+ +
+
+

亚托莉观测报告kawaii icon

+
来自高性能亚托莉的每日特别观测报告!
+
+
+
GROUP VIBE badge icon
+
+
{{ chat_quality_html | safe }}
+
+ {% endif %} + +
+
+
+
+ +
+
+

能量解析雷达kawaii icon

+
维持亚托莉运行与心跳的能量消耗~
+
+
+
ENERGY COST badge icon
+
+
+
+
总消耗
+
{{ total_tokens }}
+
+
+
提示词 Token
+
{{ prompt_tokens }}
+
+
+
生成内容 Token
+
{{ completion_tokens }}
+
+
+
+ + +
+
+ + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/quote_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/quote_item.html new file mode 100644 index 0000000..711f7f3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/quote_item.html @@ -0,0 +1,33 @@ +{% set quote_emojis = [ + t2i_atri_font_mirror ~ '/file/1775132814629_1774881270686_爱心.gif', + t2i_atri_font_mirror ~ '/file/1775132815504_1774881268554_可爱.gif', + t2i_atri_font_mirror ~ '/file/1775132809943_1774881264350_睡觉.gif', + t2i_atri_font_mirror ~ '/file/1775175892953_1774881267664_舔屏幕.gif' +] %} +{% for quote in quotes %} +
+
+
+ {% if quote.avatar_url %} +
+ +
+ {% endif %} +
+ +
+
{{ quote.sender }}
+
+
+
{{ quote.content }}
+
+ 金句表情 +
+
+ 📝 亚托莉的高性能分析: + {{ quote.reason | safe }} +
+
+
+
+{% endfor %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/topic_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/topic_item.html new file mode 100644 index 0000000..cd3d279 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/topic_item.html @@ -0,0 +1,44 @@ +{% set topic_emojis = [ + t2i_atri_font_mirror ~ '/file/1775132804506_1774881263342_观察.gif', + t2i_atri_font_mirror ~ '/file/1775132805081_1774881262835_疑惑.gif', + t2i_atri_font_mirror ~ '/file/1775132815504_1774881268554_可爱.gif', + t2i_atri_font_mirror ~ '/file/1775132817115_1774881269400_可爱-1.gif', + t2i_atri_font_mirror ~ '/file/1775132805485_1774881263748_可爱-3.gif' +] %} +{% set topic_rank_colors = [ +{'bg': 'linear-gradient(135deg, #a9d8ff 0%, #8fc5ff 48%, #8aaeff 100%)', 'text': '#ffffff', 'shadow': 'rgba(126, 177, +255, 0.34)', 'border': 'rgba(255, 255, 255, 0.82)'}, +{'bg': 'linear-gradient(135deg, #ffc8d8 0%, #ffb7cd 50%, #ffb2b2 100%)', 'text': '#ffffff', 'shadow': 'rgba(255, 176, +204, 0.32)', 'border': 'rgba(255, 255, 255, 0.8)'}, +{'bg': 'linear-gradient(135deg, #ffe0ad 0%, #ffd29f 46%, #ffc3b8 100%)', 'text': '#ffffff', 'shadow': 'rgba(255, 199, +142, 0.3)', 'border': 'rgba(255, 255, 255, 0.8)'}, +{'bg': 'linear-gradient(135deg, #c7efe7 0%, #bfe7ff 52%, #c8d8ff 100%)', 'text': '#ffffff', 'shadow': 'rgba(163, 221, +230, 0.28)', 'border': 'rgba(255, 255, 255, 0.8)'} +] %} +{% for topic in topics %} +{% set rank = topic_rank_colors[loop.index0 % (topic_rank_colors|length)] %} +
  • +
    +
    + + #{{ topic.index }} + + {{ topic.topic.topic }} +
    +
    + {% if topic.topic.count is defined %} +

    讨论热度: {{ topic.topic.count }} 次提及

    + {% endif %} +

    参与的群友: {{ topic.contributors }}

    + {% if topic.detail %} +
    + {{ topic.detail | safe }} +
    + {% endif %} +
    +
    + 话题表情 +
  • +{% endfor %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/user_title_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/user_title_item.html new file mode 100644 index 0000000..2ce9010 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/ATRI/user_title_item.html @@ -0,0 +1,43 @@ +{% set title_emojis = [ + t2i_atri_font_mirror ~ '/file/1775132813334_1774881267181_得意.gif', + t2i_atri_font_mirror ~ '/file/1775132808652_1774881267385_得意-1.gif', + t2i_atri_font_mirror ~ '/file/1775132804506_1774881263342_观察.gif', + t2i_atri_font_mirror ~ '/file/1775132811492_1774881264336_不要.gif' +] %} +{% set title_badge_colors = [ + {'bg': 'linear-gradient(135deg, #ffcadf 0%, #ffc1cc 45%, #ffd9b8 100%)', 'text': '#b85c7b', 'shadow': 'rgba(255, 177, 203, 0.28)', 'border': 'rgba(255, 184, 210, 0.72)'}, + {'bg': 'linear-gradient(135deg, #bfe7ff 0%, #c8dbff 48%, #d8ccff 100%)', 'text': '#5d71b8', 'shadow': 'rgba(168, 198, 255, 0.26)', 'border': 'rgba(173, 204, 255, 0.74)'}, + {'bg': 'linear-gradient(135deg, #c7f3df 0%, #d3f1ff 50%, #e1ddff 100%)', 'text': '#4e8e88', 'shadow': 'rgba(161, 232, 205, 0.24)', 'border': 'rgba(178, 230, 214, 0.72)'}, + {'bg': 'linear-gradient(135deg, #ffe5b7 0%, #ffd6c7 48%, #ffd7ef 100%)', 'text': '#b57752', 'shadow': 'rgba(255, 210, 163, 0.28)', 'border': 'rgba(255, 214, 178, 0.76)'} +] %} +{% for title in titles %} +{% set badge = title_badge_colors[loop.index0 % (title_badge_colors|length)] %} +
  • +
    +
    + {% if title.avatar_data %} + 头像 + {% endif %} +
    +
    + {{ title.name }} + + {{ title.title }} + +
    +
    +

    人格标签: {{ title.profile_display or title.mbti }}

    +

    称号理由: {{ title.reason }}

    +
    +
    +
    +
    + {% if title.profile_image %} + + {% endif %} + 称号表情 +
  • +{% endfor %} + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/activity_chart.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/activity_chart.html new file mode 100644 index 0000000..180a55e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/activity_chart.html @@ -0,0 +1,40 @@ +
    + {% for item in chart_data %} + {% set bar_percentage = item.percentage | float %} + {% if bar_percentage < 0 %} + {% set bar_percentage = 0 %} + {% elif bar_percentage > 100 %} + {% set bar_percentage = 100 %} + {% endif %} + + {% set bar_bg = 'var(--ba-blue)' %} + {% set bar_height = '4px' %} + {% set bar_opacity = '1' %} + + {% if item.count == 0 %} + {% set bar_bg = 'var(--ba-text-muted)' %} + {% set bar_height = '4px' %} + {% set bar_opacity = '0.15' %} + {% elif bar_percentage >= 70 %} + {% set bar_bg = 'var(--ba-accent-orange)' %} + {% set bar_height = bar_percentage ~ '%' %} + {% elif bar_percentage >= 30 %} + {% set bar_bg = 'var(--ba-accent-green)' %} + {% set bar_height = bar_percentage ~ '%' %} + {% else %} + {% set bar_bg = 'var(--ba-blue)' %} + {% set bar_height = bar_percentage ~ '%' %} + {% endif %} + +
    + {% if item.count > 0 %} +
    {{ item.count }}
    + {% endif %} + + {% set style_str = 'height: ' ~ bar_height ~ '; background: ' ~ bar_bg ~ '; opacity: ' ~ bar_opacity ~ ';' %} +
    + +
    {{ "%02d" | format(item.hour) }}
    +
    + {% endfor %} +
    diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/chat_quality_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/chat_quality_item.html new file mode 100644 index 0000000..24340fc --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/chat_quality_item.html @@ -0,0 +1,62 @@ +
    +
    +
    {{ title }}
    +
    {{ subtitle }}
    +
    + +
    +
    + {% set colors = ['#3593f3', '#58c3e5', '#7c6ff7', '#f06292', '#ff9800', '#66bb6a', '#ffc107', '#26c6da'] %} + {% for dim in dimensions %} + {% set safe_percentage = dim.percentage|float %} + {% if safe_percentage < 0 %} + {% set safe_percentage = 0 %} + {% elif safe_percentage > 100 %} + {% set safe_percentage = 100 %} + {% endif %} + {% if safe_percentage > 0 %} +
    + + {{ dim.name }} + +
    + {% endif %} + {% endfor %} +
    +
    + +
    + {% set colors = ['#3593f3', '#58c3e5', '#7c6ff7', '#f06292', '#ff9800', '#66bb6a', '#ffc107', '#26c6da'] %} + {% for dim in dimensions %} + {% set safe_percentage = dim.percentage|float %} + {% if safe_percentage < 0 %} + {% set safe_percentage = 0 %} + {% elif safe_percentage > 100 %} + {% set safe_percentage = 100 %} + {% endif %} + {% if safe_percentage > 0 %} +
    +
    + {{ dim.name }} + {{ '%.1f'|format(safe_percentage) }}% +
    + {{ dim.comment }} +
    + {% endif %} + {% endfor %} +
    + +
    +
    + Assistant +
    +
    +
    {{ summary }}
    +
    +
    +
    diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/html_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/html_template.html new file mode 100644 index 0000000..8fc433f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/html_template.html @@ -0,0 +1,1279 @@ + + + + + + + 阿洛娜的今日群聊速报! · {{current_datetime}} + + + + + + + + + + + +
    + +
    +
    + 阿洛娜 +
    +

    老师,这是今天的作战报告!

    +
    +
    +
    +
    +

    阿洛娜的今日群聊速报!

    + {{current_date}} +
    +
    + +
    +
    +
    +
    + +
    +
    {{message_count}}
    +
    消息总数
    +
    +
    +
    + +
    +
    {{participant_count}}
    +
    参与人数
    +
    +
    +
    + +
    +
    {{emoji_count}}
    +
    表情统计
    +
    +
    +
    + +
    +
    {{total_characters}}
    +
    总字符数
    +
    +
    + +
    +
    ⚡ Highlight Time
    +
    {{most_active_period}}
    +
    最活跃的时刻
    +
    +
    + +
    + +
    +
    +
    + +
    + 24H 活跃轨迹 +
    +
    + {{hourly_chart_html | safe}} +
    +
    + + {{topics_html | safe}} + {{titles_html | safe}} + {{quotes_html | safe}} + + {% if chat_quality_html %} +
    +
    +
    + +
    + 群聊质量锐评 +
    + {{ chat_quality_html | safe }} +
    + {% endif %} + +
    + + + +
    + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/image_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/image_template.html new file mode 100644 index 0000000..8fc433f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/image_template.html @@ -0,0 +1,1279 @@ + + + + + + + 阿洛娜的今日群聊速报! · {{current_datetime}} + + + + + + + + + + + +
    + +
    +
    + 阿洛娜 +
    +

    老师,这是今天的作战报告!

    +
    +
    +
    +
    +

    阿洛娜的今日群聊速报!

    + {{current_date}} +
    +
    + +
    +
    +
    +
    + +
    +
    {{message_count}}
    +
    消息总数
    +
    +
    +
    + +
    +
    {{participant_count}}
    +
    参与人数
    +
    +
    +
    + +
    +
    {{emoji_count}}
    +
    表情统计
    +
    +
    +
    + +
    +
    {{total_characters}}
    +
    总字符数
    +
    +
    + +
    +
    ⚡ Highlight Time
    +
    {{most_active_period}}
    +
    最活跃的时刻
    +
    +
    + +
    + +
    +
    +
    + +
    + 24H 活跃轨迹 +
    +
    + {{hourly_chart_html | safe}} +
    +
    + + {{topics_html | safe}} + {{titles_html | safe}} + {{quotes_html | safe}} + + {% if chat_quality_html %} +
    +
    +
    + +
    + 群聊质量锐评 +
    + {{ chat_quality_html | safe }} +
    + {% endif %} + +
    + + + +
    + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/quote_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/quote_item.html new file mode 100644 index 0000000..4e504bf --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/quote_item.html @@ -0,0 +1,34 @@ +{% if quotes %} +
    +
    +
    + +
    + 群贤毕至 Bible Quotes +
    + {% for quote in quotes %} +
    +
    +
    + {% if quote.avatar_url %} +
    + +
    + {% endif %} +
    + +
    +
    {{ quote.sender }}
    +
    +
    {{ quote.content }}
    +
    +
    + 🤣👉 AI 锐评: + {{ quote.reason | safe }} +
    +
    +
    +
    + {% endfor %} +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/topic_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/topic_item.html new file mode 100644 index 0000000..59405f6 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/topic_item.html @@ -0,0 +1,20 @@ +{% if topics %} +
    +
    +
    + +
    + 今日话题 Topics +
    + {% for topic in topics %} +
    +
    {{ "%02d" | format(topic.index) }}
    +
    +
    {{ topic.topic.topic }}
    +
    🙋‍♀️ 参与者: {{ topic.contributors }}
    +
    {{ topic.detail | safe }}
    +
    +
    + {% endfor %} +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/user_title_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/user_title_item.html new file mode 100644 index 0000000..ce7794f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/BlueArchive/user_title_item.html @@ -0,0 +1,40 @@ +{% if titles %} +
    +
    +
    + +
    + 群友画像 Portraits +
    +
    + {% for title in titles %} +
    +
    +
    + {% if title.avatar_data %} + 头像 + {% else %} + + + + {% endif %} +
    +
    +
    {{ title.name }}
    +
    + {{ title.title }} + {{ title.profile_display or title.mbti }} +
    +
    +
    +
    + {{ title.reason }} +
    + {% if title.profile_image %} + + {% endif %} +
    + {% endfor %} +
    +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/activity_chart.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/activity_chart.html new file mode 100644 index 0000000..128d01f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/activity_chart.html @@ -0,0 +1,46 @@ +
    + {# 柱状图主体层:确保底部对齐 #} +
    + {% set chart_colors = [ + '#66D1C7', '#6FD3C6', '#79D5C4', '#85D8C3', '#93DAC1', '#A3DDBF', + '#B4E0BD', '#C7E2BA', '#DBE5B8', '#EFE8B5', '#FFEAB3', '#FFDF9E', + '#FFD38B', '#FFC67A', '#FFB96D', '#FFAC62', '#FFA059', '#FF9552', + '#FF8B4D', '#FF834B', '#FF7D4D', '#FF7752', '#FF745A', '#FF7365' + ] %} + + {% for item in chart_data %} + {% set h = item.percentage | float %} + {% set bar_color = chart_colors[loop.index0 % 24] %} + {% set bar_opacity = '1' %} + {% if item.count == 0 %} + {% set h = '4' %} + {% set bar_opacity = '0.3' %} + {% set bar_color = 'var(--miku-blue)' %} + {% endif %} + +
    + {% if item.count > 0 %} + {{ item.count }} + {% endif %} + +
    +
    + {% endfor %} +
    + + {# X轴标签层:独立容器确保水平对齐且不换行 #} +
    + {% for item in chart_data %} +
    + + {{ "%02d"|format(item.hour) }}{% if loop.index0 % 4 == 0 or loop.last %}时{% endif %} + +
    + {% endfor %} +
    +
    + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/chat_quality_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/chat_quality_item.html new file mode 100644 index 0000000..1b5d28c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/chat_quality_item.html @@ -0,0 +1,43 @@ +
    +
    +
    {{ title }}
    +
    {{ subtitle }}
    +
    + +
    + {% set colors = ['var(--miku-base)', 'var(--miku-pink-light)', 'var(--miku-light)', 'var(--miku-yellow)', '#80CBC4'] %} + {% for dim in dimensions %} +
    + {% endfor %} +
    + +
    + {% for dim in dimensions %} +
    +
    +
    +
    {{ dim.name }} ({{ '%.1f'|format(dim.percentage|float) }}%)
    +
    {{ dim.comment }}
    +
    +
    + {% endfor %} +
    + +
    +
    +
    + + + + + Miku 综合点评 +
    +
    {{ summary }}
    +
    +
    + + Quality Deco +
    +
    +
    + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/html_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/html_template.html new file mode 100644 index 0000000..2376670 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/html_template.html @@ -0,0 +1,1811 @@ +{% import "inline_assets.html" as inline_assets %} + + + + + + + 群聊日常分析看板 · {{current_date}} + + + + + + +{{ inline_assets.peak_activity_image_css() | safe }} + + + +
    +
    01
    +
    39
    +
    [ SYSTEM_VOCALOID_INITIALIZED ]
    HATSUNE MIKU v4X
    +
    + +
    +

    群聊日常分析看板

    + +
    + +
    +
    +
    + +
    今日消息数
    +
    +
    {{message_count}}
    +
    +
    +
    + +
    活跃成员数
    +
    +
    {{participant_count}}
    +
    +
    +
    + +
    表情互动
    +
    +
    {{emoji_count}}
    +
    +
    +
    + +
    今日字数累计
    +
    +
    {{total_characters}}
    +
    +
    + +
    +
    +
    + + 峰值活跃时间段 +
    +
    {{most_active_period}}
    +
    + +
    + +
    +
    + + + {% if hourly_chart_html %} +
    +
    +
    +
    + + 24小时活动 +
    +
    +
    + {{hourly_chart_html | safe}} +
    +
    + {% endif %} + + + {% if topics_html %} +
    +
    +
    +
    + + 话题总结 +
    +
    + {{topics_html | safe}} +
    + {% endif %} + + + {% if titles_html %} +
    +
    +
    +
    + + 群友画像 +
    +
    + {{titles_html | safe}} +
    + {% endif %} + + + {% if quotes_html %} +
    +
    +
    +
    + + 今日圣经 +
    +
    + {{quotes_html | safe}} +
    + {% endif %} + + + {% if chat_quality_html %} +
    +
    +
    +
    + + 群聊锐评 +
    +
    + {{chat_quality_html | safe}} +
    + {% endif %} + + +
    + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/image_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/image_template.html new file mode 100644 index 0000000..7c601cd --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/image_template.html @@ -0,0 +1,1629 @@ +{% import "inline_assets.html" as inline_assets %} + + + + + + + 群聊日常分析看板 · {{current_date}} + + + + + + +{{ inline_assets.peak_activity_image_css() | safe }} + + + +
    +
    01
    +
    39
    +
    [ SYSTEM_VOCALOID_INITIALIZED ]
    HATSUNE MIKU v4X
    +
    + +
    +

    群聊日常分析看板

    + +
    + +
    +
    +
    + +
    今日消息数
    +
    +
    {{message_count}}
    +
    +
    +
    + +
    活跃成员数
    +
    +
    {{participant_count}}
    +
    +
    +
    + +
    表情互动
    +
    +
    {{emoji_count}}
    +
    +
    +
    + +
    今日字数累计
    +
    +
    {{total_characters}}
    +
    +
    + +
    +
    +
    + + 峰值活跃时间段 +
    +
    {{most_active_period}}
    +
    + +
    + +
    +
    + + + {% if hourly_chart_html %} +
    +
    +
    +
    + + 24小时活动 +
    +
    +
    + {{hourly_chart_html | safe}} +
    +
    + {% endif %} + + + {% if topics_html %} +
    +
    +
    +
    + + 话题总结 +
    +
    + {{topics_html | safe}} +
    + {% endif %} + + + {% if titles_html %} +
    +
    +
    +
    + + 群友画像 +
    +
    + {{titles_html | safe}} +
    + {% endif %} + + + {% if quotes_html %} +
    +
    +
    +
    + + 今日圣经 +
    +
    + {{quotes_html | safe}} +
    + {% endif %} + + + {% if chat_quality_html %} +
    +
    +
    +
    + + 群聊锐评 +
    +
    + {{chat_quality_html | safe}} +
    + {% endif %} + + +
    + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/inline_assets.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/inline_assets.html new file mode 100644 index 0000000..2f08d59 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/inline_assets.html @@ -0,0 +1,7 @@ +{% macro peak_activity_image_css() -%} + +{%- endmacro %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/quote_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/quote_item.html new file mode 100644 index 0000000..4b8687b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/quote_item.html @@ -0,0 +1,30 @@ +{% if quotes %} + {% for quote in quotes %} +
    +
    +
    + {% if quote.avatar_url %}{% endif %} +
    +
    +
    {{ quote.sender }}
    + +
    +
    {{ quote.content }}
    +
    + +
    +
    + + + + + Miku 锐评 +
    +
    {{ quote.reason | safe }}
    +
    +
    +
    +
    + {% endfor %} +{% endif %} + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/topic_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/topic_item.html new file mode 100644 index 0000000..939d9ee --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/topic_item.html @@ -0,0 +1,37 @@ +{% set miku_topic_images = [ + "https://fastly.jsdelivr.net/gh/SXP-Simon/astrbot_plugin_qq_group_daily_analysis@main/assets/HatsuneMiku/retouch_2026032810150449.png", + "https://fastly.jsdelivr.net/gh/SXP-Simon/astrbot_plugin_qq_group_daily_analysis@main/assets/HatsuneMiku/retouch_2026032810143720.png", + "https://fastly.jsdelivr.net/gh/SXP-Simon/astrbot_plugin_qq_group_daily_analysis@main/assets/HatsuneMiku/retouch_2026032810151717.png", + "https://fastly.jsdelivr.net/gh/SXP-Simon/astrbot_plugin_qq_group_daily_analysis@main/assets/HatsuneMiku/retouch_2026032810153327.png", + "https://fastly.jsdelivr.net/gh/SXP-Simon/astrbot_plugin_qq_group_daily_analysis@main/assets/HatsuneMiku/retouch_2026032810145078.png" +] %} +{% for topic in topics %} +
    +
    + #{{ "%02d" | format(topic.index) }} +
    +
    +
    + {{ topic.topic.topic }} +
    +
    + {{ topic.detail | safe }} +
    + +
    +
    + + + + 参与成员: + {{ topic.contributors }} +
    + +
    + 装饰图 +
    +
    +
    +
    +{% endfor %} + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/user_title_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/user_title_item.html new file mode 100644 index 0000000..16b2184 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/HatsuneMiku/user_title_item.html @@ -0,0 +1,38 @@ +{% if titles %} +
    + {% for title in titles %} +
    +
    +
    + {% if title.avatar_data %} + + {% else %} +
    + {{ title.name[0] if title.name else '?' }} +
    + {% endif %} +
    +
    +
    {{ title.name }}
    +
    + {{ title.title }} + {% if title.profile_display or title.mbti %} + {{ title.profile_display or title.mbti }} + {% endif %} +
    +
    +
    +
    + {{ title.reason }} + + + +
    + {% if title.profile_image %} + + {% endif %} +
    + {% endfor %} +
    +{% endif %} + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/activity_chart.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/activity_chart.html new file mode 100644 index 0000000..0eda4dd --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/activity_chart.html @@ -0,0 +1,14 @@ +{% for item in chart_data %} +
    +
    {{ "%02d" | format(item.hour) }}:00
    +
    +
    + {% if item.percentage > 15 %} + {{ item.count }} + {% endif %} +
    + {% if item.percentage <= 15 %} {{ item.count }} + {% endif %} +
    +
    +{% endfor %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/chat_quality_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/chat_quality_item.html new file mode 100644 index 0000000..7cfa946 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/chat_quality_item.html @@ -0,0 +1,131 @@ + + +
    +
    +
    {{ title }}
    + {% if subtitle %}
    {{ subtitle }}
    {% endif %} +
    + +
    + {% set colors = ['#007bff', '#6610f2', '#6f42c1', '#e83e8c', '#fd7e14', '#28a745', '#20c997', '#17a2b8'] %} + + {% for dim in dimensions %} + {% if dim.percentage > 0 %} +
    +
    + {% endif %} + {% endfor %} +
    + +
    + {% for dim in dimensions %} + {% if dim.percentage > 0 %} +
    + {{ dim.name }} + {{ dim.percentage }}% +
    {{ dim.comment }}
    +
    + {% endif %} + {% endfor %} +
    + +
    + EXECUTIVE SUMMARY + {{ summary }} +
    +
    + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/html_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/html_template.html new file mode 100644 index 0000000..6311404 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/html_template.html @@ -0,0 +1,546 @@ + + + + + + + 群聊日常分析报告 + + + + + + + +
    +
    +

    群聊日常分析报告

    +
    {{current_date}}
    +
    +
    +
    +

    基础统计

    +
    +
    +
    {{message_count}}
    +
    消息总数
    +
    +
    +
    {{participant_count}}
    +
    参与人数
    +
    +
    +
    {{total_characters}}
    +
    总字符数
    +
    +
    +
    {{emoji_count}}
    +
    表情数量
    +
    +
    +
    +
    {{most_active_period}}
    +
    最活跃时段
    +
    +
    + +
    +
    +
    24小时活跃度分布
    +
    + {{hourly_chart_html | safe}} +
    + + {% if chat_quality_html %} +
    +

    群聊质量分析

    + {{ chat_quality_html | safe }} +
    + {% endif %} + + {{topics_html | safe}} + {{titles_html | safe}} + {{quotes_html | safe}} +
    + +
    + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/image_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/image_template.html new file mode 100644 index 0000000..6311404 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/image_template.html @@ -0,0 +1,546 @@ + + + + + + + 群聊日常分析报告 + + + + + + + +
    +
    +

    群聊日常分析报告

    +
    {{current_date}}
    +
    +
    +
    +

    基础统计

    +
    +
    +
    {{message_count}}
    +
    消息总数
    +
    +
    +
    {{participant_count}}
    +
    参与人数
    +
    +
    +
    {{total_characters}}
    +
    总字符数
    +
    +
    +
    {{emoji_count}}
    +
    表情数量
    +
    +
    +
    +
    {{most_active_period}}
    +
    最活跃时段
    +
    +
    + +
    +
    +
    24小时活跃度分布
    +
    + {{hourly_chart_html | safe}} +
    + + {% if chat_quality_html %} +
    +

    群聊质量分析

    + {{ chat_quality_html | safe }} +
    + {% endif %} + + {{topics_html | safe}} + {{titles_html | safe}} + {{quotes_html | safe}} +
    + +
    + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/quote_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/quote_item.html new file mode 100644 index 0000000..9414d35 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/quote_item.html @@ -0,0 +1,12 @@ +{% if quotes %} +
    +

    群圣经

    + {% for quote in quotes %} +
    +
    "{{ quote.content }}"
    +
    —— {{ quote.sender }}
    +
    {{ quote.reason }}
    +
    + {% endfor %} +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/topic_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/topic_item.html new file mode 100644 index 0000000..8159744 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/topic_item.html @@ -0,0 +1,17 @@ +{% if topics %} +
    +

    热门话题

    +
    + {% for topic in topics %} +
    +
    + {{ topic.index }} + {{ topic.topic.topic }} +
    +
    参与者: {{ topic.contributors }}
    +
    {{ topic.detail | safe }}
    +
    + {% endfor %} +
    +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/user_title_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/user_title_item.html new file mode 100644 index 0000000..7f80e53 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/format/user_title_item.html @@ -0,0 +1,30 @@ +{% if titles %} +
    +

    群友称号

    +
    + {% for title in titles %} +
    + +
    {{ title.reason }}
    + {% if title.profile_image %} + + {% endif %} +
    + {% endfor %} +
    +
    +{% endif %} + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/activity_chart.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/activity_chart.html new file mode 100644 index 0000000..f84d1ee --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/activity_chart.html @@ -0,0 +1,13 @@ +{% if chart_data %} +{% for item in chart_data %} +
    + {{ item.count }} +
    + {{ "%02d"|format(item.hour) }}:00 +
    +{% endfor %} +{% else %} +
    +
    // NO_DATA_STREAM
    +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/chat_quality_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/chat_quality_item.html new file mode 100644 index 0000000..96749ec --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/chat_quality_item.html @@ -0,0 +1,188 @@ + + +
    +
    +
    > {{ title }}
    + {% if subtitle %}
    # {{ subtitle }}
    {% endif %} +
    + +
    + {% set bg_colors = ['#ff9900', '#e68a00', '#cc7a00', '#b36b00', '#995c00', '#804d00'] %} + {% set txt_colors = ['#000', '#000', '#fff', '#fff', '#fff', '#fff'] %} + + {% for dim in dimensions %} + {% if dim.percentage > 0 %} +
    + {{ dim.name }} +
    + {% endif %} + {% endfor %} +
    + +
    + {% for dim in dimensions %} + {% if dim.percentage > 0 %} +
    + :: {{ dim.name }} + >> {{ dim.percentage }}% +
    {{ dim.comment }}
    +
    + {% endif %} + {% endfor %} +
    + +
    + [SYSTEM_SUMMARY] + {{ summary }} +
    +
    + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/html_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/html_template.html new file mode 100644 index 0000000..b7b6b0b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/html_template.html @@ -0,0 +1,129 @@ + + + + + + + Night Mode Analysis Portal + + + + {% include 'shared_styles.html' %} + + + +
    + +
    + + +
    + + + + +
    +
    + +
    + +
    +
    +
    // main.ts
    +

    > Group Activity
    Insights

    +
    // Report for {{current_date}}
    + +
    + const stats = {
    +   messages: {{message_count}},
    +   active_users: {{participant_count}},
    +   peak_time: '{{most_active_period}}'
    + };
    + // Total characters: {{total_characters}} +
    +
    + + {% if chat_quality_html %} +
    +
    + $ analyze --quality +
    + {{ chat_quality_html | safe }} +
    + {% endif %} + + + {% if topics_html %} +
    +
    + $ ls ./topics +
    +
    + {{topics_html | safe}} +
    +
    + {% endif %} +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +
    trend-analytics.tsx
    +
    +
    + {{hourly_chart_html | safe}} +
    +
    + + + {% if titles_html %} +
    +
    + $ cat ./user_titles +
    +
    + {{titles_html | safe}} +
    +
    + {% endif %} + + + {% if quotes_html %} +
    +
    + $ grep -r "golden_quotes" +
    +
    + {{quotes_html | safe}} +
    +
    + {% endif %} +
    +
    + +
    +
    SYSTEM_REPORT // {{current_datetime}}
    +
    + TOKENS: {{total_tokens}} + [P: {{prompt_tokens}} | C: {{completion_tokens}}] +
    +
    SXP-Simon/astrbot_plugin_qq_group_daily_analysis 群分析
    +
    +
    + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/image_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/image_template.html new file mode 100644 index 0000000..b7b6b0b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/image_template.html @@ -0,0 +1,129 @@ + + + + + + + Night Mode Analysis Portal + + + + {% include 'shared_styles.html' %} + + + +
    + +
    + + +
    + + + + +
    +
    + +
    + +
    +
    +
    // main.ts
    +

    > Group Activity
    Insights

    +
    // Report for {{current_date}}
    + +
    + const stats = {
    +   messages: {{message_count}},
    +   active_users: {{participant_count}},
    +   peak_time: '{{most_active_period}}'
    + };
    + // Total characters: {{total_characters}} +
    +
    + + {% if chat_quality_html %} +
    +
    + $ analyze --quality +
    + {{ chat_quality_html | safe }} +
    + {% endif %} + + + {% if topics_html %} +
    +
    + $ ls ./topics +
    +
    + {{topics_html | safe}} +
    +
    + {% endif %} +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +
    trend-analytics.tsx
    +
    +
    + {{hourly_chart_html | safe}} +
    +
    + + + {% if titles_html %} +
    +
    + $ cat ./user_titles +
    +
    + {{titles_html | safe}} +
    +
    + {% endif %} + + + {% if quotes_html %} +
    +
    + $ grep -r "golden_quotes" +
    +
    + {{quotes_html | safe}} +
    +
    + {% endif %} +
    +
    + +
    +
    SYSTEM_REPORT // {{current_datetime}}
    +
    + TOKENS: {{total_tokens}} + [P: {{prompt_tokens}} | C: {{completion_tokens}}] +
    +
    SXP-Simon/astrbot_plugin_qq_group_daily_analysis 群分析
    +
    +
    + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/quote_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/quote_item.html new file mode 100644 index 0000000..98c24c3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/quote_item.html @@ -0,0 +1,24 @@ +{% if quotes %} +
    + {% for quote in quotes %} +
    +
    + {% if quote.avatar_url %} + {{ quote.sender }} + {% elif quote.avatar_data %} + {{ quote.sender }} + {% else %} +
    + ID
    + {% endif %} +
    +
    +
    "{{ quote.content }}"
    +
    -- {{ quote.sender }}
    +
    // Reason: {{ quote.reason }}
    +
    +
    + {% endfor %} +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/shared_styles.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/shared_styles.html new file mode 100644 index 0000000..db4ad57 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/shared_styles.html @@ -0,0 +1,782 @@ + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/topic_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/topic_item.html new file mode 100644 index 0000000..ee4cc0d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/topic_item.html @@ -0,0 +1,11 @@ +{% if topics %} +
    + {% for topic in topics %} +
    +
    {{ topic.topic.topic }}
    +
    /* Participants: {{ topic.contributors }} */
    +
    {{ topic.detail | safe }}
    +
    + {% endfor %} +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/user_title_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/user_title_item.html new file mode 100644 index 0000000..e372f5e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/hack/user_title_item.html @@ -0,0 +1,30 @@ +{% if titles %} +
    + {% for title in titles %} +
    +
    + {% if title.avatar_data %} + {{ title.name }} + {% else %} +
    + ID_REF
    + {% endif %} +
    + + {% if title.profile_image %} + + {% endif %} +
    + {% endfor %} +
    +{% endif %} + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/activity_chart.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/activity_chart.html new file mode 100644 index 0000000..410c600 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/activity_chart.html @@ -0,0 +1,15 @@ +{% if chart_data %} +
    + {% for item in chart_data %} +
    + {{ item.count }} +
    + {{ "%02d"|format(item.hour) }}:00 +
    + {% endfor %} +
    +{% else %} +
    +
    NO_DATA_AVAILABLE_FOR_ACTIVITY_SPECTRUM
    +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/chat_quality_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/chat_quality_item.html new file mode 100644 index 0000000..86fd0f0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/chat_quality_item.html @@ -0,0 +1,177 @@ + + +
    +
    +
    {{ title }}
    + {% if subtitle %}
    {{ subtitle }}
    {% endif %} +
    + + +
    + {% set bg_colors = ['var(--c-accent)', 'var(--c-dec-1)', 'var(--c-dec-3)', 'var(--c-dec-2)', '#FFBA08', '#273C75', '#E07A5F', '#8D99AE'] %} + {% set txt_colors = ['#ffffff', '#ffffff', '#000000', '#ffffff', '#000000', '#ffffff', '#000000', '#ffffff'] %} + + {% for dim in dimensions %} + {% if dim.percentage > 0 %} +
    + + {{ dim.name }} + +
    + {% endif %} + {% endfor %} +
    + + +
    + {% for dim in dimensions %} + {% if dim.percentage > 0 %} +
    +
    {{ dim.name }}
    +
    PROPORTION: {{ dim.percentage }}%
    +
    {{ dim.comment }}
    +
    + {% endif %} + {% endfor %} +
    + + +
    + OVERVIEW + {{ summary }} +
    +
    + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/html_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/html_template.html new file mode 100644 index 0000000..e26372f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/html_template.html @@ -0,0 +1,846 @@ + + + + + + Retro Futurism Daily Export + + + + + + + +
    + +
    +
    +
    +
    +
    +
    +
    +
    System Report // {{current_date}}
    +

    Daily
    Analysis
    Export

    +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    +

    + Daily activity analysis report, generated based on message statistics and AI analysis +

    +
    +
    +
    Generated At
    + {{current_datetime}} +
    +
    +
    Peak Window
    + {{most_active_period}} +
    +
    +
    + + +
    +
    + Messages +
    {{message_count}}
    +
    累计消息数量
    +
    + +
    + Participants +
    {{participant_count}}
    +
    参与者计数
    +
    + +
    + Characters +
    {{total_characters}}
    +
    文本总字数
    +
    + +
    + Emoji +
    {{emoji_count}}
    +
    表情符号统计
    +
    +
    + + +
    +
    +
    + + + +
    +
    Peak Activity Window
    +
    {{most_active_period}}
    +
    活跃序列 SCAN // 消息流强度 {{message_count}}
    +
    +
    + + + +
    +
    +
    + {{hourly_chart_html|safe}} +
    +
    +
    + + + {% if chat_quality_html %} + +
    +
    + {{ chat_quality_html|safe }} +
    +
    + {% endif %} + + + {% if topics_html %} + +
    + {{topics_html|safe}} +
    + {% endif %} + + + {% if titles_html %} + +
    +
    +
    + {{titles_html|safe}} +
    +
    +
    + {% endif %} + + + {% if quotes_html %} + +
    + {{quotes_html|safe}} +
    + {% endif %} + +
    + + +
    {{current_datetime}} // END_OF_LINE_
    +
    +
    + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/image_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/image_template.html new file mode 100644 index 0000000..e26372f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/image_template.html @@ -0,0 +1,846 @@ + + + + + + Retro Futurism Daily Export + + + + + + + +
    + +
    +
    +
    +
    +
    +
    +
    +
    System Report // {{current_date}}
    +

    Daily
    Analysis
    Export

    +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    +

    + Daily activity analysis report, generated based on message statistics and AI analysis +

    +
    +
    +
    Generated At
    + {{current_datetime}} +
    +
    +
    Peak Window
    + {{most_active_period}} +
    +
    +
    + + +
    +
    + Messages +
    {{message_count}}
    +
    累计消息数量
    +
    + +
    + Participants +
    {{participant_count}}
    +
    参与者计数
    +
    + +
    + Characters +
    {{total_characters}}
    +
    文本总字数
    +
    + +
    + Emoji +
    {{emoji_count}}
    +
    表情符号统计
    +
    +
    + + +
    +
    +
    + + + +
    +
    Peak Activity Window
    +
    {{most_active_period}}
    +
    活跃序列 SCAN // 消息流强度 {{message_count}}
    +
    +
    + + + +
    +
    +
    + {{hourly_chart_html|safe}} +
    +
    +
    + + + {% if chat_quality_html %} + +
    +
    + {{ chat_quality_html|safe }} +
    +
    + {% endif %} + + + {% if topics_html %} + +
    + {{topics_html|safe}} +
    + {% endif %} + + + {% if titles_html %} + +
    +
    +
    + {{titles_html|safe}} +
    +
    +
    + {% endif %} + + + {% if quotes_html %} + +
    + {{quotes_html|safe}} +
    + {% endif %} + +
    + + +
    {{current_datetime}} // END_OF_LINE_
    +
    +
    + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/quote_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/quote_item.html new file mode 100644 index 0000000..ea987f2 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/quote_item.html @@ -0,0 +1,20 @@ +{% if quotes %} +{% for quote in quotes %} +
    + {% if quote.avatar_url %} +
    + {{ quote.sender }} +
    + {% elif quote.avatar_data %} +
    + {{ quote.sender }} +
    + {% endif %} +
    +
    {{ quote.content }}
    +
    ORIGIN: {{ quote.sender }}
    +
    ANALYSIS // {{ quote.reason }}
    +
    +
    +{% endfor %} +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/topic_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/topic_item.html new file mode 100644 index 0000000..4942d3e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/topic_item.html @@ -0,0 +1,12 @@ +{% if topics %} +{% for topic in topics %} +
    +
    +

    {{ topic.topic.topic }}

    +
    SUBJECT ID: #{{ "%02d"|format(loop.index) }} // PARTICIPANTS: {{ topic.contributors }} +
    +
    {{ topic.detail | safe }}
    +
    +
    +{% endfor %} +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/user_title_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/user_title_item.html new file mode 100644 index 0000000..b0e2b1e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/retro_futurism/user_title_item.html @@ -0,0 +1,28 @@ +{% if titles %} +{% for title in titles %} +
    +
    + {% if title.avatar_data %} + {{ title.name }} + {% else %} +
    + DATA_ERR
    + {% endif %} +
    +
    +

    {{ title.name }}

    +
    + {{ title.profile_display or title.mbti }} + // + {{ title.title }} +
    +
    {{ title.reason }}
    +
    + {% if title.profile_image %} + + {% endif %} +
    +{% endfor %} +{% endif %} + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/activity_chart.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/activity_chart.html new file mode 100644 index 0000000..bf3f8f9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/activity_chart.html @@ -0,0 +1,41 @@ +
    + {% for item in chart_data %} + {% set bar_percentage = item.percentage | float %} + {% if bar_percentage < 0 %} + {% set bar_percentage = 0 %} + {% elif bar_percentage > 100 %} + {% set bar_percentage = 100 %} + {% endif %} + + {% set bar_bg = 'var(--color-purple)' %} + {% set bar_height = '4px' %} + {% set bar_opacity = '1' %} + + {% if item.count == 0 %} + {% set bar_bg = 'var(--ink-secondary)' %} + {% set bar_height = '4px' %} + {% set bar_opacity = '0.2' %} + {% elif bar_percentage >= 70 %} + {% set bar_bg = 'var(--accent-orange)' %} + {% set bar_height = bar_percentage ~ '%' %} + {% elif bar_percentage >= 30 %} + {% set bar_bg = 'var(--color-green)' %} + {% set bar_height = bar_percentage ~ '%' %} + {% else %} + {% set bar_bg = 'var(--color-blue)' %} + {% set bar_height = bar_percentage ~ '%' %} + {% endif %} + +
    + {% if item.count > 0 %} +
    {{ item.count }}
    + {% endif %} + + {% set style_str = 'height: ' ~ bar_height ~ '; background: ' ~ bar_bg ~ '; opacity: ' ~ bar_opacity ~ '; border-bottom: none;' %} +
    + +
    {{ "%02d" | format(item.hour) }}
    +
    + {% endfor %} +
    + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/chat_quality_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/chat_quality_item.html new file mode 100644 index 0000000..46a1469 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/chat_quality_item.html @@ -0,0 +1,296 @@ + + +
    +
    +
    +
    {{ title }}
    +
    {{ subtitle }}
    +
    + + +
    +
    + {% set ns = namespace(total=0) %} + {% set colors = ['#ffb74d', '#ff8a65', '#ba68c8', '#4db6ac', '#4dd0e1', '#64b5f6', '#81c784', '#e57373'] %} + {% for dim in dimensions %} + {% set safe_percentage = dim.percentage|float %} + {% if safe_percentage < 0 %} + {% set safe_percentage = 0 %} + {% elif safe_percentage > 100 %} + {% set safe_percentage = 100 %} + {% endif %} + {% if safe_percentage > 0 %} +
    + + {{ dim.name }} + +
    + {% endif %} + {% endfor %} +
    +
    + + +
    + {% set colors = ['#ffb74d', '#ff8a65', '#ba68c8', '#4db6ac', '#4dd0e1', '#64b5f6', '#81c784', '#e57373'] %} + {% for dim in dimensions %} + {% set safe_percentage = dim.percentage|float %} + {% if safe_percentage < 0 %} + {% set safe_percentage = 0 %} + {% elif safe_percentage > 100 %} + {% set safe_percentage = 100 %} + {% endif %} + {% if safe_percentage > 0 %} + {% set rot = loop.cycle('-1deg', '1.5deg', '-0.5deg', '1deg', '-1.5deg', '0.5deg') %} + {% set tape_rot = loop.cycle('2deg', '-1deg', '3deg', '-2deg', '1deg', '-3deg') %} +
    +
    +
    + {{ dim.name }} + {{ '%.1f'|format(safe_percentage) }}% +
    + {{ dim.comment }} +
    + {% endif %} + {% endfor %} +
    + + +
    +
    + + Assistant +
    +
    +
    {{ summary }}
    +
    +
    +
    + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/html_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/html_template.html new file mode 100644 index 0000000..1df9ddb --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/html_template.html @@ -0,0 +1,1198 @@ + + + + + + + 五彩斑斓的一天,来看看群里发生了什么吧! · {{current_date}} + + + + + + + + + +
    + + +
    +
    +
    +

    五彩斑斓的一天,来看看群里发生了什么吧!

    +
    {{current_date}}
    +
    +
    + + +
    + +
    + +
    +
    + + + +
    {{message_count}}
    +
    消息总数
    +
    +
    + +
    +
    + + + +
    {{participant_count}}
    +
    参与人数
    +
    +
    + +
    +
    + + + +
    {{emoji_count}}
    +
    表情统计
    +
    +
    + +
    +
    + + + +
    {{total_characters}}
    +
    总字符数
    +
    +
    +
    + + +
    +
    +
    + ✨ Highlight Time +
    +
    {{most_active_period}}
    +
    (此刻,世界色彩斑斓)
    +
    +
    + +
    + + +
    +
    +
    + + + + 24H 活跃轨迹 +
    +
    + {{hourly_chart_html | safe}} +
    +
    + + {{topics_html | safe}} + {{titles_html | safe}} + {{quotes_html | safe}} + + + {% if chat_quality_html %} +
    +
    +
    +
    + + + + 群聊质量锐评 +
    + {{ chat_quality_html | safe }} +
    + {% endif %} + +
    + + + + +
    + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/image_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/image_template.html new file mode 100644 index 0000000..1df9ddb --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/image_template.html @@ -0,0 +1,1198 @@ + + + + + + + 五彩斑斓的一天,来看看群里发生了什么吧! · {{current_date}} + + + + + + + + + +
    + + +
    +
    +
    +

    五彩斑斓的一天,来看看群里发生了什么吧!

    +
    {{current_date}}
    +
    +
    + + +
    + +
    + +
    +
    + + + +
    {{message_count}}
    +
    消息总数
    +
    +
    + +
    +
    + + + +
    {{participant_count}}
    +
    参与人数
    +
    +
    + +
    +
    + + + +
    {{emoji_count}}
    +
    表情统计
    +
    +
    + +
    +
    + + + +
    {{total_characters}}
    +
    总字符数
    +
    +
    +
    + + +
    +
    +
    + ✨ Highlight Time +
    +
    {{most_active_period}}
    +
    (此刻,世界色彩斑斓)
    +
    +
    + +
    + + +
    +
    +
    + + + + 24H 活跃轨迹 +
    +
    + {{hourly_chart_html | safe}} +
    +
    + + {{topics_html | safe}} + {{titles_html | safe}} + {{quotes_html | safe}} + + + {% if chat_quality_html %} +
    +
    +
    +
    + + + + 群聊质量锐评 +
    + {{ chat_quality_html | safe }} +
    + {% endif %} + +
    + + + + +
    + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/quote_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/quote_item.html new file mode 100644 index 0000000..8d54fc3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/quote_item.html @@ -0,0 +1,35 @@ +{% if quotes %} +
    +
    + + + + 群贤毕至 Bible Quotes +
    + {% for quote in quotes %} +
    +
    +
    + {% if quote.avatar_url %} +
    + +
    + {% endif %} +
    + +
    +
    {{ quote.sender }}
    +
    +
    "
    +
    {{ quote.content }}
    +
    +
    + 🤣👉 AI 锐评: + {{ quote.reason | safe }} +
    +
    +
    +
    + {% endfor %} +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/topic_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/topic_item.html new file mode 100644 index 0000000..4e44e06 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/topic_item.html @@ -0,0 +1,34 @@ +{% if topics %} +
    +
    +
    +
    +
    +
    +
    + + + + 今日话题 Topics +
    + {% for topic in topics %} +
    +
    +
    +
    +
    +
    + {{ topic.topic.topic }} + #{{ + "%02d"|format(topic.index) }} +
    +
    + 🙋‍♀️ 参与者: {{ topic.contributors }} +
    +
    {{ topic.detail | safe }}
    +
    +
    + {% endfor %} +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/user_title_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/user_title_item.html new file mode 100644 index 0000000..20d8711 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/scrapbook/user_title_item.html @@ -0,0 +1,44 @@ +{% if titles %} +
    +
    + + + + 群友画像 Portraits +
    +
    + {% for title in titles %} +
    +
    +
    +
    + {% if title.avatar_data %} + 头像 + {% else %} + + + + {% endif %} +
    +
    +
    {{ title.name }}
    +
    + {{ title.title }} + {{ title.profile_display or title.mbti }} +
    +
    +
    +
    + {{ title.reason }} +
    + {% if title.profile_image %} + + {% endif %} +
    + {% endfor %} +
    +
    +{% endif %} + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/activity_chart.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/activity_chart.html new file mode 100644 index 0000000..cd38a0c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/activity_chart.html @@ -0,0 +1,11 @@ +
    + {% for item in chart_data %} +
    + {{ "%02d" | format(item.hour) }}:00 +
    +
    +
    + {{ item.count }} +
    + {% endfor %} +
    diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/chat_quality_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/chat_quality_item.html new file mode 100644 index 0000000..0fffa9c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/chat_quality_item.html @@ -0,0 +1,121 @@ + + +
    +
    +
    {{ title }}
    + {% if subtitle %}
    {{ subtitle }}
    {% endif %} +
    + +
    + {% set colors = ['#4dabf7', '#ff922b', '#51cf66', '#f06595', '#845ef7', '#339af0'] %} + + {% for dim in dimensions %} + {% if dim.percentage > 0 %} +
    +
    + {% endif %} + {% endfor %} +
    + +
    + {% for dim in dimensions %} + {% if dim.percentage > 0 %} +
    + {{ dim.name }} + {{ dim.percentage }}% +
    {{ dim.comment }}
    +
    + {% endif %} + {% endfor %} +
    + +
    + Summary + {{ summary }} +
    +
    + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/html_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/html_template.html new file mode 100644 index 0000000..0894e0b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/html_template.html @@ -0,0 +1,69 @@ + + + + + + Simple Report + + + + + + + +

    群聊日报 - {{current_date}}

    + +
    +

    基础统计

    +

    消息数: {{message_count}}

    +

    参与人数: {{participant_count}}

    +

    总字符数: {{total_characters}}

    +

    表情数: {{emoji_count}}

    +

    最活跃时段: {{most_active_period}}

    +
    + +
    +

    活跃度图表

    + {{hourly_chart_html | safe}} +
    + + {% if chat_quality_html %} +
    +

    群聊质量分析

    + {{ chat_quality_html | safe }} +
    + {% endif %} + + {{topics_html | safe}} + + {{titles_html | safe}} + + {{quotes_html | safe}} + + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/image_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/image_template.html new file mode 100644 index 0000000..0894e0b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/image_template.html @@ -0,0 +1,69 @@ + + + + + + Simple Report + + + + + + + +

    群聊日报 - {{current_date}}

    + +
    +

    基础统计

    +

    消息数: {{message_count}}

    +

    参与人数: {{participant_count}}

    +

    总字符数: {{total_characters}}

    +

    表情数: {{emoji_count}}

    +

    最活跃时段: {{most_active_period}}

    +
    + +
    +

    活跃度图表

    + {{hourly_chart_html | safe}} +
    + + {% if chat_quality_html %} +
    +

    群聊质量分析

    + {{ chat_quality_html | safe }} +
    + {% endif %} + + {{topics_html | safe}} + + {{titles_html | safe}} + + {{quotes_html | safe}} + + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/quote_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/quote_item.html new file mode 100644 index 0000000..5d6cf7f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/quote_item.html @@ -0,0 +1,16 @@ +{% if quotes %} +
    +

    群圣经

    + {% for quote in quotes %} +
    +

    "{{ quote.content }}"

    +
    + — {{ quote.sender }} +
    +
    + 入选理由: {{ quote.reason }} +
    +
    + {% endfor %} +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/topic_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/topic_item.html new file mode 100644 index 0000000..7be8c6f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/topic_item.html @@ -0,0 +1,12 @@ +{% if topics %} +
    +

    热门话题

    + {% for item in topics %} +
    + #{{ item.index }} {{ item.topic.topic }} + (参与者: {{ item.contributors }}) +

    {{ item.detail | safe }}

    +
    + {% endfor %} +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/user_title_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/user_title_item.html new file mode 100644 index 0000000..b5daec2 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/simple/user_title_item.html @@ -0,0 +1,16 @@ +{% if titles %} +
    +

    群友称号

    + {% for item in titles %} +
    +
    {{ item.name }} - {{ item.title }}
    +
    {{ item.profile_display or item.mbti }}
    +
    {{ item.reason }}
    + {% if item.profile_image %} + + {% endif %} +
    + {% endfor %} +
    +{% endif %} + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/activity_chart.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/activity_chart.html new file mode 100644 index 0000000..b6e7ed3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/activity_chart.html @@ -0,0 +1,44 @@ +{% if chart_data %} +
    + {% for item in chart_data %} +
    + +
    + {{ item.count if item.count > 0 else '' }} +
    + + +
    + + +
    + {{ "%02d"|format(item.hour) }}:00 +
    +
    + {% endfor %} +
    +{% else %} +
    + 🏮 尚无活跃记录 🏮 +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/chat_quality_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/chat_quality_item.html new file mode 100644 index 0000000..f6f2b2a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/chat_quality_item.html @@ -0,0 +1,153 @@ + + +
    +
    +
    🧧 {{ title }} 🧧
    + {% if subtitle %}
    {{ subtitle }}
    {% endif %} +
    + +
    + {% set bg_colors = ['#f5222d', '#fa541c', '#fa8c16', '#faad14', '#d46b08', '#ad2102'] %} + + {% for dim in dimensions %} + {% if dim.percentage > 0 %} +
    + {{ dim.name }} +
    + {% endif %} + {% endfor %} +
    + +
    + {% for dim in dimensions %} + {% if dim.percentage > 0 %} +
    + ✨ {{ dim.name }} + 占比: {{ dim.percentage }}% +
    {{ dim.comment }}
    +
    + {% endif %} + {% endfor %} +
    + +
    + 📜 分析总结 + {{ summary }} +
    +
    + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/html_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/html_template.html new file mode 100644 index 0000000..6258942 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/html_template.html @@ -0,0 +1,693 @@ + + + + + + 春节特供 · 群聊日报 + + + + + + + + +
    +
    +
    +
    +
    + +
    +
    +

    🧧 春节特供日报 🧧

    +
    +
    —— {{current_date}} · 岁在丙午 ——
    +
    + +
    +
    +
    +
    消息总数
    +
    {{message_count}}
    +
    +
    +
    参与群友
    +
    {{participant_count}}
    +
    +
    +
    表情统计
    +
    {{emoji_count}}
    +
    +
    +
    总字符数
    +
    {{total_characters}}
    +
    +
    + +
    +
    + 巅峰时刻 +
    +
    + {{most_active_period}} +
    +
    🏮 鸿运齐天 + · 众友云集 🏮
    +
    +
    + +
    + + {% if chat_quality_html %} +
    +
    🏺 聊天质量锐评
    + {{ chat_quality_html | safe }} +
    + {% endif %} + + + {% if topics_html %} +
    +
    🏮 核心话题回顾
    +
    + {{topics_html | safe}} +
    +
    + {% endif %} + + +
    +
    📈 活跃时序图
    +
    +
    ACTIVITY CHRONICLE
    + {{hourly_chart_html | safe}} +
    +
    + + + {% if titles_html %} +
    +
    🎖️ 群友风云榜
    + {{titles_html | safe}} +
    + {% endif %} + + + {% if quotes_html %} +
    +
    ✨ 每日金句回响
    +
    + {{quotes_html | safe}} +
    +
    + {% endif %} +
    + +
    +
    宜 · 总结分析 // {{current_datetime}}
    +
    Token 消耗:{{total_tokens}} (Prompt: {{prompt_tokens}}, Completion: {{completion_tokens}})
    + +
    +
    + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/image_template.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/image_template.html new file mode 100644 index 0000000..6571399 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/image_template.html @@ -0,0 +1,692 @@ + + + + + + 春节特供 · 群聊日报 + + + + + + + +
    +
    +
    +
    +
    + +
    +
    +

    🧧 春节特供日报 🧧

    +
    +
    —— {{current_date}} · 岁在丙午 ——
    +
    + +
    +
    +
    +
    消息总数
    +
    {{message_count}}
    +
    +
    +
    参与群友
    +
    {{participant_count}}
    +
    +
    +
    表情统计
    +
    {{emoji_count}}
    +
    +
    +
    总字符数
    +
    {{total_characters}}
    +
    +
    + +
    +
    + 巅峰时刻 +
    +
    + {{most_active_period}} +
    +
    🏮 鸿运齐天 + · 众友云集 🏮
    +
    +
    + +
    + + {% if chat_quality_html %} +
    +
    🏺 聊天质量锐评
    + {{ chat_quality_html | safe }} +
    + {% endif %} + + + {% if topics_html %} +
    +
    🏮 核心话题回顾
    +
    + {{topics_html | safe}} +
    +
    + {% endif %} + + +
    +
    📈 活跃时序图
    +
    +
    ACTIVITY CHRONICLE
    + {{hourly_chart_html | safe}} +
    +
    + + + {% if titles_html %} +
    +
    🎖️ 群友风云榜
    + {{titles_html | safe}} +
    + {% endif %} + + + {% if quotes_html %} +
    +
    ✨ 每日金句回响
    +
    + {{quotes_html | safe}} +
    +
    + {% endif %} +
    + +
    +
    宜 · 总结分析 // {{current_datetime}}
    +
    Token 消耗:{{total_tokens}} (Prompt: {{prompt_tokens}}, Completion: {{completion_tokens}})
    + +
    +
    + + + + + + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/quote_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/quote_item.html new file mode 100644 index 0000000..8b59d57 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/quote_item.html @@ -0,0 +1,24 @@ +{% if quotes %} +
    + {% for quote in quotes %} +
    +
    + {% if quote.avatar_url %} + {{ quote.sender }} + {% elif quote.avatar_data %} + {{ quote.sender }} + {% else %} +
    福
    + {% endif %} +
    +
    +
    “{{ quote.content }}”
    +
    —— {{ quote.sender }}
    +
    【评语】{{ quote.reason }}
    +
    +
    + {% endfor %} +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/topic_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/topic_item.html new file mode 100644 index 0000000..9b43266 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/topic_item.html @@ -0,0 +1,14 @@ +{% if topics %} +
    + {% for topic in topics %} +
    +
    + 🏮 + {{ topic.topic.topic }} +
    +
    参与者: {{ topic.contributors }}
    +
    {{ topic.detail | safe }}
    +
    + {% endfor %} +
    +{% endif %} diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/user_title_item.html b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/user_title_item.html new file mode 100644 index 0000000..fd99173 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/reporting/templates/spring_festival/user_title_item.html @@ -0,0 +1,30 @@ +{% if titles %} +
    + {% for title in titles %} +
    +
    +
    + {% if title.avatar_data %} + {{ title.name }} + {% else %} +
    福
    + {% endif %} +
    + +
    +
    {{ title.reason }}
    + {% if title.profile_image %} + + {% endif %} +
    + {% endfor %} +
    +{% endif %} + diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/scheduler/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/scheduler/__init__.py new file mode 100644 index 0000000..790b53f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/scheduler/__init__.py @@ -0,0 +1,8 @@ +""" +调度和自动化模块 +包含定时任务和自动分析功能 +""" + +from .auto_scheduler import AutoScheduler + +__all__ = ["AutoScheduler"] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/scheduler/auto_scheduler.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/scheduler/auto_scheduler.py new file mode 100644 index 0000000..01d8210 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/scheduler/auto_scheduler.py @@ -0,0 +1,1239 @@ +""" +自动调度器模块 +负责定时任务和自动分析功能,支持传统单次分析与增量多次分析两种调度模式。 +""" + +import asyncio +import time as time_mod +from typing import Any + +from apscheduler.triggers.cron import CronTrigger + +from ...application.services.analysis_application_service import DuplicateGroupTaskError +from ...shared.trace_context import TraceContext +from ...utils.logger import logger +from ..messaging.message_sender import MessageSender +from ..platform.factory import PlatformAdapterFactory +from ..reporting.dispatcher import ReportDispatcher +from .incremental_trigger import IncrementalTriggerCoordinator + +_SCHEDULED_DISPATCH_INFO_SECONDS = 1.0 +_SCHEDULED_DISPATCH_WARN_SECONDS = 15.0 + + +class AutoScheduler: + """自动调度器,支持传统模式和增量模式""" + + def __init__( + self, + config_manager, + analysis_service, + bot_manager, + report_generator=None, + html_render_func=None, + plugin_instance: Any | None = None, + ): + self.config_manager = config_manager + self.analysis_service = analysis_service + self.bot_manager = bot_manager + self.report_generator = report_generator + self.html_render_func = html_render_func + self.plugin_instance = plugin_instance + + # 初始化核心组件 + self.message_sender = MessageSender(bot_manager, config_manager) + self.report_dispatcher = ReportDispatcher( + config_manager, report_generator, self.message_sender + ) + if html_render_func: + self.report_dispatcher.set_html_render(html_render_func) + + self.scheduler_job_ids = [] # 存储已注册的定时任务 ID + self.last_executed_target = None # 记录上次执行的具体时间点,防止重复执行 + + # Cache: group_id -> group_name (populated lazily) + self._group_name_cache: dict[str, str] = {} + self._terminating = False # 终止标志位 + self._immediate_report_tasks: dict[str, asyncio.Task] = {} + self._immediate_report_versions: dict[str, int] = {} + self.incremental_trigger = ( + IncrementalTriggerCoordinator( + config_manager, + plugin_instance, + self._trigger_incremental_analysis, + self._request_immediate_incremental_report, + ) + if plugin_instance is not None + else None + ) + + def set_bot_instance(self, bot_instance): + """设置bot实例(保持向后兼容)""" + self.bot_manager.set_bot_instance(bot_instance) + + def set_bot_self_ids(self, bot_self_ids): + """设置bot ID(支持单个ID或ID列表)""" + # 确保传入的是列表,保持统一处理 + if isinstance(bot_self_ids, list): + self.bot_manager.set_bot_self_ids(bot_self_ids) + elif bot_self_ids: + self.bot_manager.set_bot_self_ids([bot_self_ids]) + + def set_bot_qq_ids(self, bot_qq_ids): + """设置bot QQ号(已弃用,使用 set_bot_self_ids)""" + self.set_bot_self_ids(bot_qq_ids) + + async def get_platform_id_for_group(self, group_id): + """根据群ID获取对应的平台ID""" + try: + # 首先检查已注册的bot实例 + if ( + hasattr(self.bot_manager, "_bot_instances") + and self.bot_manager._bot_instances + ): + # 如果只有一个实例,直接返回 + if self.bot_manager.get_platform_count() == 1: + platform_id = self.bot_manager.get_platform_ids()[0] + logger.debug(f"只有一个适配器,使用平台: {platform_id}") + return platform_id + + # 如果有多个实例,尝试通过适配器检查群属于哪个平台 + logger.info(f"检测到多个适配器,正在验证群 {group_id} 属于哪个平台...") + for platform_id in self.bot_manager.get_platform_ids(): + try: + adapter = self.bot_manager.get_adapter(platform_id) + if adapter: + # 通过统一接口尝试获取群信息,如果能获取到则说明属于该平台 + info = await adapter.get_group_info(str(group_id)) + if info: + logger.info(f"✅ 群 {group_id} 属于平台 {platform_id}") + return platform_id + else: + logger.debug( + f"平台 {platform_id} 无法获取群 {group_id} 信息" + ) + except Exception as e: + logger.debug(f"平台 {platform_id} 验证群 {group_id} 失败: {e}") + continue + + # 如果所有适配器都尝试失败,记录错误并返回 None + logger.error( + f"❌ 无法确定群 {group_id} 属于哪个平台 (已尝试: {list(self.bot_manager._bot_instances.keys())})" + ) + return None + + # 没有任何bot实例,返回None + logger.error("❌ 没有注册的bot实例") + return None + except Exception as e: + logger.error(f"❌ 获取平台ID失败: {e}") + return None + + async def _get_group_name_safe( + self, group_id: str, platform_id: str | None = None + ) -> str: + """ + 为 TraceID 生成解析可读的群名。 + 使用内存缓存以避免重复的 API 调用。 + 若名称不可用,则回退到 group_id。 + """ + if group_id in self._group_name_cache: + return self._group_name_cache[group_id] + + try: + pid = platform_id or await self.get_platform_id_for_group(group_id) + if pid: + adapter = self.bot_manager.get_adapter(pid) + if adapter: + info = await adapter.get_group_info(group_id) + if info and info.group_name: + self._group_name_cache[group_id] = info.group_name + return info.group_name + except Exception: + pass + + return group_id + + # ================================================================ + # 任务注册与取消 + # ================================================================ + + def schedule_jobs(self, context): + """根据分层名单配置注册定时任务。""" + # 首先清理之前的任务 + self.unschedule_jobs(context) + + # unschedule_jobs 会将 _terminating 设为 True (用于关闭场景), + # 但 schedule_jobs 意味着插件仍在运行;因此需要重置此标志位 + self._terminating = False + + if not self.config_manager.is_auto_analysis_enabled(): + logger.info("定时分析名单为空且为白名单模式,不注册定时任务。") + return + + scheduler = context.cron_manager.scheduler + + # 1. 注册核心报告生成任务(涵盖全量分析与增量总结报告) + # 每个配置的时间点都会触发一次解析 + logger.info("注册定时分析报告任务...") + self._schedule_report_time_jobs(scheduler) + + # 2. 增量提取由群消息事件计数触发,此处不注册提取定时任务。 + if self.config_manager.get_incremental_enabled(): + logger.info("增量分析功能已开启,将按目标群新增消息数量触发。") + else: + logger.info("增量分析总开关未启用,仅执行传统定时全量分析。") + + def _schedule_report_time_jobs(self, scheduler): + """在配置的时间点注册报告生成任务。 + + 这些任务根据运行时解析出的生效模式,决定执行传统的全量分析还是增量汇报。 + """ + time_config = self.config_manager.get_auto_analysis_time() + if isinstance(time_config, str): + time_config = [time_config] + + for i, t_str in enumerate(time_config): + try: + t_str = str(t_str).replace(":", ":").strip() + hour, minute = t_str.split(":") + + trigger = CronTrigger(hour=int(hour), minute=int(minute)) + job_id = f"astrbot_plugin_qq_group_daily_analysis_trigger_{i}" + + scheduler.add_job( + self._run_scheduled_report, + trigger=trigger, + id=job_id, + replace_existing=True, + misfire_grace_time=60, + ) + self.scheduler_job_ids.append(job_id) + logger.info(f"已注册定时报告任务: {t_str} (Job ID: {job_id})") + + except Exception as e: + logger.error(f"注册定时任务失败 ({t_str}): {e}") + + def unschedule_jobs(self, context): + """取消定时任务""" + self._terminating = True + if ( + not context + or not hasattr(context, "cron_manager") + or not context.cron_manager + ): + return + + scheduler = context.cron_manager.scheduler + if not scheduler: + return + + for job_id in self.scheduler_job_ids: + try: + if scheduler.get_job(job_id): + scheduler.remove_job(job_id) + logger.debug(f"已移除定时任务: {job_id}") + except Exception as e: + logger.warning(f"移除定时任务失败 ({job_id}): {e}") + self.scheduler_job_ids.clear() + + async def shutdown(self, context) -> None: + """停止调度器并持久化增量消息计数。 + + Args: + context: AstrBot 插件上下文。 + """ + self._terminating = True + immediate_report_tasks = list(self._immediate_report_tasks.values()) + for task in immediate_report_tasks: + task.cancel() + if immediate_report_tasks: + await asyncio.gather(*immediate_report_tasks, return_exceptions=True) + self._immediate_report_tasks.clear() + self._immediate_report_versions.clear() + + if self.incremental_trigger: + await self.incremental_trigger.close() + self.unschedule_jobs(context) + + async def start_incremental_trigger(self) -> None: + """恢复达到消息阈值但尚未完成的增量任务。""" + if self.incremental_trigger and self.config_manager.get_incremental_enabled(): + recovered = await self.incremental_trigger.start() + if recovered: + logger.info(f"已恢复 {recovered} 个达到消息阈值的增量分析任务") + + # ================================================================ + # 共享辅助方法:解析定时分析目标 + # ================================================================ + + async def _get_scheduled_targets( + self, mode_filter: str | None = None + ) -> list[tuple[str, str, str]]: + """ + 根据分层过滤逻辑判定所有应参与计划分析的目标群组及其分析策略。 + + 判定过程: + 1. 准入层:群组必须在基础设置的允许名单内。 + 2. 定时层:群组需通过定时分析名单的过滤。 + 3. 模式层:如果群组在增量名单内,则使用增量模式,否则使用默认策略。 + + 参数: + mode_filter: 如果提供,则只返回匹配指定模式的目标 (traditional 或 incremental)。 + """ + # 获取基础信息 + all_groups = await self._get_all_groups() + + result = [] + + # 遍历所有平台上的群组 + for platform_id, group_id_orig in all_groups: + group_id = str(group_id_orig) + umo = f"{platform_id}:GroupMessage:{group_id}" + + # 配置管理器统一处理基础名单与定时 inherit/白黑名单。 + if not self.config_manager.is_scheduled_group_allowed(umo): + continue + + # 配置管理器统一处理增量 inherit/白黑名单。 + if self.config_manager.is_incremental_group_allowed(umo): + # 如果在增量名单内,则执行增量模式 + effective_mode = "incremental" + else: + # 不在增量名单内,则执行普通模式 + effective_mode = "traditional" + + # 4. 模式过滤 (如果函数调用者要求过滤) + if mode_filter and effective_mode != mode_filter: + continue + + result.append((group_id, platform_id, effective_mode)) + + logger.info( + f"分层调度解析完成:符合条件的群组共 {len(result)} 个" + + (f" (模式过滤: {mode_filter})" if mode_filter else "") + ) + return result + + # ================================================================ + # 统一报告调度入口 + # ================================================================ + + async def _run_scheduled_report(self): + """统一的定时分析入口。 + + 在配置的时间点触发,解析所有目标群并根据其分析模式分发任务: + - traditional: 执行全量拉取分析并发送报告 + - incremental: 执行增量最终报告阶段(合并并汇报) + """ + if self._terminating: + return + try: + logger.info("定时报告触发 — 开始解析调度目标") + + if self.incremental_trigger: + await self.incremental_trigger.refresh_target_states() + + all_targets = await self._get_scheduled_targets() + + if not all_targets: + logger.info("没有配置的群聊需要定时分析") + return + + max_concurrent = self.config_manager.get_max_concurrent_tasks() + sem = asyncio.Semaphore(max_concurrent) + logger.info( + f"定时报告: {len(all_targets)} 个目标 (并发限制: {max_concurrent})" + ) + + async def dispatch_group(gid, pid, mode): + wait_started_at = time_mod.monotonic() + logger.debug( + "定时报告等待调度槽位: platform=%s, group=%s, mode=%s, available=%s/%s", + pid or "default", + gid, + mode, + getattr(sem, "_value", None), + max_concurrent, + ) + while True: + try: + await asyncio.wait_for( + sem.acquire(), timeout=_SCHEDULED_DISPATCH_WARN_SECONDS + ) + break + except asyncio.TimeoutError: + logger.warning( + "定时报告等待调度槽位超过 %.0fs: platform=%s, group=%s, " + "mode=%s, available=%s/%s", + time_mod.monotonic() - wait_started_at, + pid or "default", + gid, + mode, + getattr(sem, "_value", None), + max_concurrent, + ) + + waited_seconds = time_mod.monotonic() - wait_started_at + log_method = ( + logger.info + if waited_seconds >= _SCHEDULED_DISPATCH_INFO_SECONDS + else logger.debug + ) + log_method( + "定时报告已取得调度槽位: platform=%s, group=%s, mode=%s, " + "wait=%.2fs, available=%s/%s", + pid or "default", + gid, + mode, + waited_seconds, + getattr(sem, "_value", None), + max_concurrent, + ) + run_started_at = time_mod.monotonic() + try: + if mode == "incremental": + return await self._perform_incremental_final_report_for_group_with_timeout( + gid, pid + ) + else: + return await self._perform_auto_analysis_for_group_with_timeout( + gid, pid + ) + finally: + sem.release() + logger.debug( + "定时报告已释放调度槽位: platform=%s, group=%s, mode=%s, " + "duration=%.2fs, available=%s/%s", + pid or "default", + gid, + mode, + time_mod.monotonic() - run_started_at, + getattr(sem, "_value", None), + max_concurrent, + ) + + tasks = [] + stagger = self.config_manager.get_stagger_seconds() or 2 + # 针对定时大任务加入交错等待,减少瞬间峰值延迟 + for idx, (gid, pid, mode) in enumerate(all_targets): + if self._terminating: + logger.info("检测到插件正在停止,取消后续任务创建") + break + + # 为前几个任务添加微小的启动间隔,均匀分散 API 压力 + if idx > 0 and stagger > 0: + await asyncio.sleep(stagger) + + task = asyncio.create_task( + dispatch_group(gid, pid, mode), + name=f"report_{mode}_{gid}", + ) + tasks.append(task) + + results = await asyncio.gather(*tasks, return_exceptions=True) + + # 统计结果 + success_count = 0 + skip_count = 0 + error_count = 0 + + for i, result in enumerate(results): + gid, _, _ = all_targets[i] + if isinstance(result, DuplicateGroupTaskError): + skip_count += 1 + elif isinstance(result, Exception): + logger.error(f"群 {gid} 定时报告任务异常: {result}") + error_count += 1 + elif isinstance(result, dict) and result.get("success"): + success_count += 1 + elif isinstance(result, dict): + reason = result.get("reason", "unknown") + if reason in { + "below_threshold", + "no_incremental_data", + "already_running", + "muted", + "bot_not_ready", + "target_removed", + }: + skip_count += 1 + else: + logger.error(f"群 {gid} 定时报告失败: {reason}") + error_count += 1 + else: + logger.error(f"群 {gid} 定时报告返回了无效状态: {result!r}") + error_count += 1 + + logger.info( + f"定时报告完成 — 成功: {success_count}, 跳过: {skip_count}, " + f"失败: {error_count}, 总计: {len(all_targets)}" + ) + + except Exception as e: + logger.error(f"定时报告执行失败: {e}", exc_info=True) + + async def _perform_auto_analysis_for_group_with_timeout( + self, group_id: str, target_platform_id: str | None = None + ): + """为指定群执行自动分析并返回真实的分析与发送状态。""" + try: + result = await asyncio.wait_for( + self._perform_auto_analysis_for_group(group_id, target_platform_id), + timeout=1800, + ) + if not isinstance(result, dict): + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": "invalid_result", + } + return result + except asyncio.TimeoutError: + logger.error(f"群 {group_id} 分析超时(30分钟),跳过该群分析") + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": "timeout", + } + except Exception as e: + logger.error(f"群 {group_id} 分析任务执行失败: {e}") + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": str(e), + } + + async def _perform_auto_analysis_for_group( + self, group_id: str, target_platform_id: str | None = None + ): + """为指定群执行自动分析(业务逻辑委派给 AnalysisApplicationService)""" + trace = None + try: + # 解析可读群名以生成语义化的 TraceID + group_name = await self._get_group_name_safe(group_id, target_platform_id) + trace_id = TraceContext.generate(prefix="group", group_name=group_name) + trace = TraceContext.set( + trace_id=trace_id, + group_id=group_id, + group_name=group_name, + platform=target_platform_id or "", + trigger_type="auto", + ) + + if self._terminating: + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": "terminating", + } + + logger.info( + f"开始为群 {group_id} 执行自动分析 (Platform: {target_platform_id or 'Auto'})" + ) + + # 检查平台状态 (BotManager 为基础设施层,用于获取平台就绪状态) + if not self.bot_manager.is_ready_for_auto_analysis(): + logger.warning(f"群 {group_id} 自动分析跳过:bot管理器未就绪") + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": "bot_not_ready", + } + + # 委派给应用层服务执行核心用例 + # AnalysisApplicationService 内部已处理群锁 (group_lock) + result = await self.analysis_service.execute_daily_analysis( + group_id=group_id, platform_id=target_platform_id, manual=False + ) + + if not result.get("success"): + reason = result.get("reason") + if trace and trace.status == "running": + trace.finish( + status="failed", + error_message=result.get("error") + or f"Auto analysis skipped: {reason}", + ) + logger.info( + f"群 {group_id} 自动分析未完成: {reason} - {result.get('error', '')}" + ) + result["analysis_success"] = False + result["report_sent"] = False + return result + + # 获取分析结果及适配器 + analysis_result = result["analysis_result"] + adapter = result["adapter"] + dispatch_platform_id = ( + adapter.platform_id + if hasattr(adapter, "platform_id") + else target_platform_id + ) + + # 调度导出并发送报告 + comic_trigger = getattr( + getattr(self, "plugin_instance", None), + "_try_trigger_comic_generation", + None, + ) + if callable(comic_trigger): + try: + comic_trigger(group_id, dispatch_platform_id, analysis_result) + except Exception as exc: + logger.error( + f"群 {group_id} 触发定时报告漫画失败: {exc}", exc_info=True + ) + + report_sent = await self.report_dispatcher.dispatch( + group_id, + analysis_result, + dispatch_platform_id, + ) + + result["analysis_success"] = True + result["report_sent"] = bool(report_sent) + if not report_sent: + if trace and trace.status == "running": + trace.finish( + status="failed", error_message="Report delivery failed" + ) + result["success"] = False + result["reason"] = "report_delivery_failed" + logger.error(f"群 {group_id} 自动分析完成,但报告发送失败") + return result + + if trace and trace.status == "running": + trace.finish(status="succeeded") + logger.info(f"群 {group_id} 自动分析及报告发送成功") + return result + + except DuplicateGroupTaskError: + if trace and trace.status == "running": + trace.finish( + status="aborted", error_message="Task already running in group" + ) + logger.debug(f"群 {group_id} 任务因并发锁冲突而跳过(已在运行)") + raise + except Exception as e: + if trace and trace.status == "running": + trace.finish(status="failed", error_message=str(e)) + logger.error(f"群 {group_id} 自动分析执行失败: {e}", exc_info=True) + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": str(e), + } + finally: + logger.debug(f"群 {group_id} 自动分析流程结束") + + # ================================================================ + # 增量模式:增量分析 + # ================================================================ + + async def record_incremental_message(self, event) -> bool: + """记录一条群消息,用于按消息量触发增量分析。 + + Args: + event: AstrBot 群消息事件。 + + Returns: + 消息是否属于启用增量分析的目标群。 + """ + if self._terminating or not self.incremental_trigger: + return False + if str(event.get_sender_id()) == str(event.get_self_id()): + return False + message_obj = getattr(event, "message_obj", None) + return await self.incremental_trigger.record_message( + platform_id=event.get_platform_id(), + group_id=event.get_group_id(), + unified_msg_origin=event.unified_msg_origin, + message_id=str(getattr(message_obj, "message_id", "") or ""), + ) + + async def _trigger_incremental_analysis( + self, group_id: str, platform_id: str + ) -> dict | None: + """执行消息量触发的单群增量分析。 + + Args: + group_id: 群组 ID。 + platform_id: 平台实例 ID。 + + Returns: + 增量分析结果。 + """ + result = await self._perform_incremental_analysis_for_group_with_timeout( + group_id, platform_id + ) + return result + + def _request_immediate_incremental_report( + self, group_id: str, platform_id: str + ) -> None: + """合并同群即时报告请求,并在后台发送报告。""" + if ( + self._terminating + or not self.config_manager.get_incremental_report_immediately() + ): + return + + state_key = f"{platform_id}:GroupMessage:{group_id}" + version = self._immediate_report_versions.get(state_key, 0) + 1 + self._immediate_report_versions[state_key] = version + task = self._immediate_report_tasks.get(state_key) + if task and not task.done(): + logger.debug( + "即时增量报告已合并到运行中任务:platform=%s,group=%s,版本=%s", + platform_id, + group_id, + version, + ) + return + + task = asyncio.create_task( + self._run_immediate_incremental_report(state_key, group_id, platform_id), + name=f"incremental_immediate_report_{state_key}", + ) + self._immediate_report_tasks[state_key] = task + logger.debug( + "即时增量报告已安排:platform=%s,group=%s,版本=%s,当前即时报告任务=%s", + platform_id, + group_id, + version, + len(self._immediate_report_tasks), + ) + + async def _run_immediate_incremental_report( + self, state_key: str, group_id: str, platform_id: str + ) -> None: + """串行发送同群即时报告,并合并执行期间新增的批次。""" + current_task = asyncio.current_task() + try: + while not self._terminating: + requested_version = self._immediate_report_versions.get(state_key, 0) + logger.debug( + "即时增量报告开始:platform=%s,group=%s,版本=%s", + platform_id, + group_id, + requested_version, + ) + result = ( + await self._perform_incremental_final_report_for_group_with_timeout( + group_id, platform_id + ) + ) + result = result if isinstance(result, dict) else {} + has_new_batch = ( + self._immediate_report_versions.get(state_key, 0) + != requested_version + ) + logger.debug( + "即时增量报告结束:platform=%s,group=%s,版本=%s,success=%s," + "reason=%s,执行期间有新批次=%s", + platform_id, + group_id, + requested_version, + bool(result.get("success")), + result.get("reason", "none"), + has_new_batch, + ) + if not has_new_batch: + break + logger.debug( + "即时增量报告检测到新批次,合并后继续发送:platform=%s,group=%s", + platform_id, + group_id, + ) + except asyncio.CancelledError: + raise + except Exception as exc: + logger.error( + f"即时增量报告后台任务异常:群 {group_id},平台 {platform_id},错误:{exc}", + exc_info=True, + ) + finally: + if self._immediate_report_tasks.get(state_key) is current_task: + self._immediate_report_tasks.pop(state_key, None) + self._immediate_report_versions.pop(state_key, None) + logger.debug( + "即时增量报告任务已结束:platform=%s,group=%s,当前即时报告任务=%s", + platform_id, + group_id, + len(self._immediate_report_tasks), + ) + + async def _perform_incremental_analysis_for_group_with_timeout( + self, + group_id: str, + target_platform_id: str | None = None, + ): + """为指定群执行增量分析(带超时控制,10分钟)。""" + try: + result = await asyncio.wait_for( + self._perform_incremental_analysis_for_group( + group_id, target_platform_id + ), + timeout=600, + ) + return result + except asyncio.TimeoutError: + logger.error(f"群 {group_id} 增量分析超时(10分钟),跳过") + return {"success": False, "reason": "timeout"} + except Exception as e: + logger.error(f"群 {group_id} 增量分析任务执行失败: {e}") + return {"success": False, "reason": str(e)} + + async def _perform_incremental_analysis_for_group( + self, + group_id: str, + target_platform_id: str | None = None, + ): + """为指定群执行增量分析(业务逻辑委派给 AnalysisApplicationService)""" + trace = None + try: + # 解析可读群名以生成语义化的 TraceID + group_name = await self._get_group_name_safe(group_id, target_platform_id) + trace_id = TraceContext.generate(prefix="incr", group_name=group_name) + trace = TraceContext.set( + trace_id=trace_id, + group_id=group_id, + group_name=group_name, + platform=target_platform_id or "", + trigger_type="incremental", + ) + + if self._terminating: + return + + logger.debug( + f"开始为群 {group_id} 执行增量分析 " + f"(Platform: {target_platform_id or 'Auto'})" + ) + + # 检查平台状态 + if not self.bot_manager.is_ready_for_auto_analysis(): + logger.warning(f"群 {group_id} 增量分析跳过:bot管理器未就绪") + return {"success": False, "reason": "bot_not_ready"} + + # 委派给应用层服务执行增量分析用例 + # AnalysisApplicationService 内部已处理群锁 (group_lock) + result = await self.analysis_service.execute_incremental_analysis( + group_id=group_id, + platform_id=target_platform_id, + ) + + if not result.get("success"): + reason = result.get("reason", "unknown") + if trace and trace.status == "running": + trace.finish( + status="failed", error_message=f"Incremental skipped: {reason}" + ) + logger.debug(f"群 {group_id} 增量分析未完成: reason={reason}") + return result + + # 增量分析只累积数据,不发送报告 + batch_summary = result.get("batch_summary", {}) + logger.debug( + f"群 {group_id} 增量分析调度回调完成: " + f"消息数={result.get('messages_count', 0)}, " + f"话题={batch_summary.get('topics_count', 0)}, " + f"金句={batch_summary.get('quotes_count', 0)}" + ) + if trace and trace.status == "running": + trace.finish(status="succeeded") + return result + + except DuplicateGroupTaskError: + if trace and trace.status == "running": + trace.finish( + status="aborted", error_message="Task already running in group" + ) + logger.debug(f"群 {group_id} 增量分析因并发锁冲突而跳过(已在运行)") + return {"success": False, "reason": "already_running"} + except Exception as e: + if trace and trace.status == "running": + trace.finish(status="failed", error_message=str(e)) + logger.error(f"群 {group_id} 增量分析执行失败: {e}", exc_info=True) + return {"success": False, "reason": str(e)} + finally: + logger.debug(f"群 {group_id} 增量分析流程结束") + + # ================================================================ + # 增量最终报告(单群)与回退逻辑 + # ================================================================ + + async def _perform_incremental_final_report_for_group_with_timeout( + self, group_id: str, target_platform_id: str | None = None + ): + """带超时及回退机制的增量最终报告生成。 + + 若增量汇报失败(非 '消息不足' 或 '正在运行' 导致的), + 且启用了自动回退,则将该群转由传统模式执行全量分析。 + """ + try: + result = await asyncio.wait_for( + self._perform_incremental_final_report_for_group( + group_id, target_platform_id + ), + timeout=1800, + ) + + if not isinstance(result, dict): + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": "invalid_result", + } + + # 判定是否需要触发回退 (例如:无增量数据等) + if not result.get("success"): + reason = result.get("reason", "") + if reason in ("below_threshold", "already_running", "target_removed"): + return result # 正常跳过,无需回退 + if self.config_manager.get_incremental_fallback_enabled(): + logger.warning( + f"群 {group_id} 增量最终报告失败 (reason={reason})," + f"正在回退到传统全量分析..." + ) + return await self._fallback_to_traditional( + group_id, target_platform_id + ) + + return result + + except asyncio.TimeoutError: + logger.error(f"群 {group_id} 最终报告超时(30分钟)") + if self.config_manager.get_incremental_fallback_enabled(): + logger.warning(f"群 {group_id} 增量报告超时,正在回退到传统全量分析...") + return await self._fallback_to_traditional(group_id, target_platform_id) + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": "timeout", + } + + except Exception as e: + logger.error(f"群 {group_id} 最终报告任务执行失败: {e}") + if self.config_manager.get_incremental_fallback_enabled(): + logger.warning(f"群 {group_id} 增量报告异常,正在回退到传统全量分析...") + return await self._fallback_to_traditional(group_id, target_platform_id) + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": str(e), + } + + async def _fallback_to_traditional( + self, group_id: str, target_platform_id: str | None = None + ): + """回退操作:在增量报告失败时,执行传统的全量拉取分析。""" + try: + logger.info( + f"⬆️ 群 {group_id} 回退到传统全量分析 " + f"(Platform: {target_platform_id or 'Auto'})" + ) + result = await self._perform_auto_analysis_for_group_with_timeout( + group_id, target_platform_id + ) + if not isinstance(result, dict): + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "fallback": True, + "reason": "fallback_invalid_result", + } + result["fallback"] = True + return result + except Exception as fallback_err: + logger.error( + f"群 {group_id} 回退传统分析也失败: {fallback_err}", + exc_info=True, + ) + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "fallback": True, + "reason": f"fallback_failed: {fallback_err}", + } + + async def _perform_incremental_final_report_for_group( + self, group_id: str, target_platform_id: str | None = None + ): + """为指定群生成增量最终报告(业务逻辑委派给 AnalysisApplicationService)""" + trace = None + try: + # 解析可读群名以生成语义化的 TraceID + group_name = await self._get_group_name_safe(group_id, target_platform_id) + trace_id = TraceContext.generate(prefix="report", group_name=group_name) + trace = TraceContext.set( + trace_id=trace_id, + group_id=group_id, + group_name=group_name, + platform=target_platform_id or "", + trigger_type="incremental_report", + ) + + if self._terminating: + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": "terminating", + } + + incremental_trigger = getattr(self, "incremental_trigger", None) + if ( + incremental_trigger + and target_platform_id + and not incremental_trigger.is_target_group( + f"{target_platform_id}:GroupMessage:{group_id}" + ) + ): + logger.info(f"群 {group_id} 已移出增量名单,跳过最终报告") + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": "target_removed", + } + + logger.info( + f"开始为群 {group_id} 生成增量最终报告 " + f"(Platform: {target_platform_id or 'Auto'})" + ) + + # 检查平台状态 + if not self.bot_manager.is_ready_for_auto_analysis(): + logger.warning(f"群 {group_id} 最终报告跳过:bot管理器未就绪") + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": "bot_not_ready", + } + + # 委派给应用层服务执行最终报告用例 + # AnalysisApplicationService 内部已处理群锁 (group_lock) + result = await self.analysis_service.execute_incremental_final_report( + group_id=group_id, platform_id=target_platform_id + ) + + if not result.get("success"): + reason = result.get("reason", "unknown") + if trace and trace.status == "running": + trace.finish( + status="failed", error_message=f"Final report skipped: {reason}" + ) + logger.info(f"群 {group_id} 最终报告跳过: {reason}") + result["analysis_success"] = False + result["report_sent"] = False + return result + + # 获取分析结果及适配器,分发报告 + analysis_result = result["analysis_result"] + adapter = result["adapter"] + dispatch_platform_id = ( + adapter.platform_id + if hasattr(adapter, "platform_id") + else target_platform_id + ) + + if ( + incremental_trigger + and dispatch_platform_id + and not incremental_trigger.is_target_group( + f"{dispatch_platform_id}:GroupMessage:{group_id}" + ) + ): + result["success"] = False + result["analysis_success"] = True + result["report_sent"] = False + result["reason"] = "target_removed" + logger.info(f"群 {group_id} 已移出增量名单,取消发送最终报告") + return result + + comic_trigger = getattr( + getattr(self, "plugin_instance", None), + "_try_trigger_comic_generation", + None, + ) + if callable(comic_trigger): + try: + comic_trigger(group_id, dispatch_platform_id, analysis_result) + except Exception as exc: + logger.error( + f"群 {group_id} 触发增量报告漫画失败: {exc}", exc_info=True + ) + + report_sent = await self.report_dispatcher.dispatch( + group_id, + analysis_result, + dispatch_platform_id, + ) + + result["analysis_success"] = True + result["report_sent"] = bool(report_sent) + if not report_sent: + if trace and trace.status == "running": + trace.finish( + status="failed", error_message="Report delivery failed" + ) + result["success"] = False + result["reason"] = "report_delivery_failed" + logger.error(f"群 {group_id} 最终报告生成完成,但报告发送失败") + return result + + # 清理过期批次(保留 2 倍窗口范围的数据作为缓冲) + try: + analysis_days = self.config_manager.get_analysis_days() + before_ts = time_mod.time() - (analysis_days * 2 * 24 * 3600) + incremental_store = self.analysis_service.incremental_store + if incremental_store: + cleaned = await incremental_store.cleanup_old_batches( + group_id, before_ts + ) + if cleaned > 0: + logger.debug( + f"群 {group_id} 报告发送后清理了 {cleaned} 个过期批次" + ) + except Exception as cleanup_err: + logger.warning( + f"群 {group_id} 过期批次清理失败(不影响报告): {cleanup_err}" + ) + + if trace and trace.status == "running": + trace.finish(status="succeeded") + logger.info(f"群 {group_id} 增量最终报告发送成功") + return result + + except DuplicateGroupTaskError: + if trace and trace.status == "running": + trace.finish( + status="aborted", error_message="Task already running in group" + ) + logger.debug(f"群 {group_id} 最终报告因并发锁冲突而跳过(已在运行)") + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": "already_running", + } + except Exception as e: + if trace and trace.status == "running": + trace.finish(status="failed", error_message=str(e)) + logger.error(f"群 {group_id} 最终报告执行失败: {e}", exc_info=True) + return { + "success": False, + "analysis_success": False, + "report_sent": False, + "reason": str(e), + } + finally: + logger.debug(f"群 {group_id} 最终报告流程结束") + + # ================================================================ + # 群列表获取(基础设施层) + # ================================================================ + + async def _get_all_groups(self) -> list[tuple[str, str]]: + """ + 获取所有bot实例所在的群列表(使用 PlatformAdapter) + + Returns: + list[tuple[str, str]]: [(platform_id, group_id), ...] + """ + all_groups = set() + + # 1. [韧性增强] 进入扫描前,尝试最后一次实时发现机器人 + # 这确保了即使冷启动初始化失败,定时任务触发时仍能刷新状态 + if hasattr(self.bot_manager, "auto_discover_bot_instances"): + try: + await self.bot_manager.auto_discover_bot_instances() + except Exception as e: + logger.warning(f"[AutoScheduler] 周期性扫描中的平台发现失败: {e}") + + bot_ids = list(self.bot_manager._bot_instances.keys()) + + if not bot_ids: + logger.warning( + "[AutoScheduler] 分析周期开启,但全局未发现任何在线 Bot。任务将跳过。" + ) + return [] + + logger.info(f"[AutoScheduler] 正在扫描 {len(bot_ids)} 个平台的群聊资源...") + + for platform_id, bot_instance in self.bot_manager._bot_instances.items(): + # 检查该平台是否启用了此插件 + if not self.bot_manager.is_plugin_enabled( + platform_id, "astrbot_plugin_qq_group_daily_analysis" + ): + logger.debug(f"平台 {platform_id} 未启用此插件,跳过获取群列表") + continue + + try: + # 1. 优先从 BotManager 获取已创建的适配器 + adapter = self.bot_manager.get_adapter(platform_id) + + # 2. 如果没有,尝试临时创建(降级方案) + platform_name = None + if not adapter: + platform_name = self.bot_manager._detect_platform_name(bot_instance) + if platform_name: + adapter = PlatformAdapterFactory.create( + platform_name, + bot_instance, + config={ + "bot_self_ids": self.config_manager.get_bot_self_ids(), + "platform_id": str(platform_id), + }, + ) + + # 3. 使用适配器获取群列表 + if adapter: + try: + groups = await adapter.get_group_list() + groups = [ + str(group_id).strip() + for group_id in groups + if str(group_id).strip() + ] + + # 获取平台名称(仅用于日志) + p_name = None + if hasattr(adapter, "get_platform_name"): + try: + p_name = adapter.get_platform_name() + except Exception: + p_name = None + + for group_id in groups: + all_groups.add((platform_id, str(group_id))) + + logger.info( + f"平台 {platform_id} ({p_name or 'unknown'}) 成功获取 {len(groups)} 个群组" + ) + continue + + except Exception as e: + logger.warning(f"适配器 {platform_id} 获取群列表失败: {e}") + + # 4. 降级:无法通过适配器获取 + logger.debug(f"平台 {platform_id} 无法通过适配器获取群列表") + + except Exception as e: + logger.error(f"平台 {platform_id} 获取群列表异常: {e}") + + return list(all_groups) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/scheduler/incremental_trigger.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/scheduler/incremental_trigger.py new file mode 100644 index 0000000..adee392 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/scheduler/incremental_trigger.py @@ -0,0 +1,535 @@ +"""基于群消息量的增量分析触发协调器。""" + +import asyncio +import time +from collections import OrderedDict +from collections.abc import Awaitable, Callable +from typing import Any + +from ...utils.logger import logger + + +class IncrementalTriggerCoordinator: + """维护每个群的待处理消息计数并触发增量分析。""" + + _KV_KEY = "incremental_trigger_states_v1" + _SEEN_EVENT_LIMIT = 8192 + _FLUSH_DELAY_SECONDS = 5 + _SEMAPHORE_WARN_SECONDS = 15.0 + + def __init__( + self, + config_manager: Any, + plugin_instance: Any, + analyze_callback: Callable[[str, str], Awaitable[dict | None]], + on_analysis_succeeded: Callable[[str, str], None] | None = None, + ) -> None: + """初始化触发协调器。 + + Args: + config_manager: 插件配置管理器。 + plugin_instance: 提供 KV 存储接口的插件实例。 + analyze_callback: 执行单群增量分析的异步回调。 + on_analysis_succeeded: 批次成功结算后执行的同步通知回调。 + """ + self.config_manager = config_manager + self.plugin = plugin_instance + self.analyze_callback = analyze_callback + self.on_analysis_succeeded = on_analysis_succeeded + self._states: dict[str, dict[str, Any]] = {} + self._loaded = False + self._load_lock = asyncio.Lock() + self._state_lock = asyncio.Lock() + self._seen_event_ids: OrderedDict[str, None] = OrderedDict() + self._analysis_tasks: dict[str, asyncio.Task] = {} + self._running_state_keys: set[str] = set() + self._state_versions: dict[str, int] = {} + self._target_config_signature: tuple[Any, ...] | None = None + self._flush_task: asyncio.Task | None = None + self._closed = False + self._semaphore: asyncio.Semaphore | None = None + + def is_target_group(self, unified_msg_origin: str) -> bool: + """判断消息所属群是否启用了增量分析。""" + if not self.config_manager.get_incremental_enabled(): + return False + return self.config_manager.is_incremental_group_allowed(unified_msg_origin) + + def _get_target_config_signature(self) -> tuple[Any, ...]: + """生成影响增量目标群判定的配置快照。""" + + def get_group_list(getter_name: str) -> tuple[str, ...]: + getter = getattr(self.config_manager, getter_name, None) + values = getter() if callable(getter) else [] + if not isinstance(values, (list, tuple, set)): + values = [values] + return tuple(sorted({str(value).strip() for value in values})) + + def get_group_mode(getter_name: str, default: str) -> str: + getter = getattr(self.config_manager, getter_name, None) + value = getter() if callable(getter) else default + return str(value).strip().lower() + + return ( + bool(self.config_manager.get_incremental_enabled()), + get_group_mode("get_group_list_mode", "none"), + get_group_list("get_group_list"), + get_group_mode("get_scheduled_group_list_mode", "whitelist"), + get_group_list("get_scheduled_group_list"), + get_group_mode("get_incremental_group_list_mode", "whitelist"), + get_group_list("get_incremental_group_list"), + ) + + async def refresh_target_states(self) -> None: + """在名单配置变化后清理不再允许的待处理状态。""" + await self._ensure_loaded() + config_signature = self._get_target_config_signature() + if config_signature == self._target_config_signature: + return + + tasks_to_cancel: list[asyncio.Task] = [] + removed_state_keys: list[str] = [] + cancelled_state_keys: list[str] = [] + removed_count = 0 + is_initial_snapshot = self._target_config_signature is None + async with self._state_lock: + for state_key in list(self._states): + if self.is_target_group(state_key): + continue + self._states.pop(state_key, None) + self._state_versions[state_key] = ( + self._state_versions.get(state_key, 0) + 1 + ) + removed_count += 1 + removed_state_keys.append(state_key) + task = self._analysis_tasks.get(state_key) + if task and state_key not in self._running_state_keys: + # 尚未进入分析服务的任务可以安全取消。先移出任务表,避免 + # 任务在首次执行前被取消而没有机会运行 finally,留下幽灵任务。 + self._analysis_tasks.pop(state_key, None) + tasks_to_cancel.append(task) + cancelled_state_keys.append(state_key) + self._target_config_signature = config_signature + active_task_count = len(self._analysis_tasks) + + for task in tasks_to_cancel: + task.cancel() + if removed_count: + self._schedule_flush() + if is_initial_snapshot: + logger.debug( + "增量名单初始快照已建立:清理待处理群=%s,当前活跃群任务=%s", + removed_count, + active_task_count, + ) + else: + logger.info( + "增量名单配置已更新:清理待处理群=%s,取消未开始任务=%s,当前活跃群任务=%s", + removed_count, + len(tasks_to_cancel), + active_task_count, + ) + if removed_state_keys: + logger.debug( + "增量名单变更明细:移出群=%s,取消未开始任务=%s", + ", ".join(sorted(removed_state_keys)), + ", ".join(sorted(cancelled_state_keys)) or "无", + ) + + async def _ensure_loaded(self) -> None: + """首次使用时从 KV 恢复尚未消费的群消息计数。""" + if self._loaded: + return + async with self._load_lock: + if self._loaded: + return + data = await self.plugin.get_kv_data(self._KV_KEY, {}) + if isinstance(data, dict) and isinstance(data.get("states"), dict): + for key, state in data["states"].items(): + if not isinstance(state, dict): + continue + platform_id = str(state.get("platform_id", "")).strip() + group_id = str(state.get("group_id", "")).strip() + if not platform_id or not group_id: + continue + try: + count = max(0, int(state.get("count", 0))) + except (TypeError, ValueError): + continue + self._states[str(key)] = { + "platform_id": platform_id, + "group_id": group_id, + "count": count, + "version": 1, + } + self._state_versions[str(key)] = 1 + self._loaded = True + state_details = ", ".join( + f"{state_key}={int(state['count'])}" + for state_key, state in sorted(self._states.items()) + ) + logger.debug( + "增量计数状态恢复完成: 群数=%s, 待处理消息=%s, 群计数=[%s]", + len(self._states), + sum(int(state.get("count", 0)) for state in self._states.values()), + state_details or "无", + ) + + def _schedule_flush(self) -> None: + """合并短时间内的计数更新,避免每条消息都写 KV。""" + if self._closed or (self._flush_task and not self._flush_task.done()): + return + self._flush_task = asyncio.create_task( + self._delayed_flush(), name="incremental_counter_flush" + ) + + async def _delayed_flush(self) -> None: + """短暂合并连续计数写入后持久化状态。""" + try: + await asyncio.sleep(self._FLUSH_DELAY_SECONDS) + await self.flush() + except asyncio.CancelledError: + raise + except Exception as exc: + logger.warning(f"持久化增量消息计数失败:{exc}") + + async def flush(self) -> None: + """立即持久化当前计数状态。""" + await self._ensure_loaded() + async with self._state_lock: + states = { + key: { + "platform_id": state["platform_id"], + "group_id": state["group_id"], + "count": int(state["count"]), + } + for key, state in self._states.items() + if int(state.get("count", 0)) > 0 + } + await self.plugin.put_kv_data( + self._KV_KEY, + {"version": 1, "updated_at": time.time(), "states": states}, + ) + logger.debug( + "增量计数状态已持久化: 群数=%s, 待处理消息=%s", + len(states), + sum(int(state.get("count", 0)) for state in states.values()), + ) + + async def record_message( + self, + platform_id: str, + group_id: str, + unified_msg_origin: str, + message_id: str = "", + ) -> bool: + """记录一条群消息,并在达到阈值时安排分析。 + + Args: + platform_id: AstrBot 平台实例 ID。 + group_id: 平台群组 ID。 + unified_msg_origin: AstrBot 统一消息来源。 + message_id: 平台消息 ID,用于抑制重复事件。 + + Returns: + 消息是否属于启用增量分析的目标群。 + """ + if self._closed: + return False + + await self.refresh_target_states() + if not self.is_target_group(unified_msg_origin): + return False + + platform_id = str(platform_id or "").strip() + group_id = str(group_id or "").strip() + if not platform_id or not group_id: + return False + + event_key = f"{platform_id}:{group_id}:{message_id}" if message_id else "" + if event_key: + if event_key in self._seen_event_ids: + self._seen_event_ids.move_to_end(event_key) + logger.debug( + "忽略重复增量消息事件: platform=%s, group=%s, message_id=%s", + platform_id, + group_id, + message_id, + ) + return True + self._seen_event_ids[event_key] = None + if len(self._seen_event_ids) > self._SEEN_EVENT_LIMIT: + self._seen_event_ids.popitem(last=False) + + await self._ensure_loaded() + state_key = f"{platform_id}:GroupMessage:{group_id}" + async with self._state_lock: + state = self._states.get(state_key) + if state is None: + version = self._state_versions.get(state_key, 0) + 1 + self._state_versions[state_key] = version + state = { + "platform_id": platform_id, + "group_id": group_id, + "count": 0, + "version": version, + } + self._states[state_key] = state + state["count"] = int(state["count"]) + 1 + pending_count = int(state["count"]) + threshold = self.config_manager.get_incremental_min_messages() + should_trigger = pending_count >= threshold + + self._schedule_flush() + if should_trigger: + self._schedule_analysis(state_key) + logger.debug( + "增量消息 Hook 已记录: platform=%s, group=%s, pending=%s, " + "threshold=%s, 已安排任务=%s, 当前活跃群任务=%s", + platform_id, + group_id, + pending_count, + threshold, + state_key in self._analysis_tasks, + len(self._analysis_tasks), + ) + return True + + def _schedule_analysis(self, state_key: str) -> None: + """确保同一个群同一时间只有一个消息量触发任务。""" + if ( + self._closed + or state_key in self._analysis_tasks + or not self.is_target_group(state_key) + ): + return + state = self._states.get(state_key, {}) + task = asyncio.create_task( + self._run_analysis(state_key), + name=f"incremental_volume_{state_key}", + ) + self._analysis_tasks[state_key] = task + logger.debug( + "增量消息计数达到阈值,安排分析任务: platform=%s, group=%s, pending=%s, " + "threshold=%s, 当前活跃群任务=%s", + state.get("platform_id", ""), + state.get("group_id", ""), + int(state.get("count", 0)), + self.config_manager.get_incremental_min_messages(), + len(self._analysis_tasks), + ) + + async def _run_analysis(self, state_key: str) -> None: + """执行分析并根据实际消费数量修正估算计数。""" + allow_continuation = False + discarded = False + task_version = -1 + current_task = asyncio.current_task() + try: + await self.refresh_target_states() + async with self._state_lock: + state = self._states.get(state_key) + if not state: + return + count_at_start = int(state.get("count", 0)) + platform_id = str(state["platform_id"]) + group_id = str(state["group_id"]) + task_version = int(state.get("version", 0)) + + logger.debug( + "增量分析任务开始: platform=%s, group=%s, pending_at_start=%s", + platform_id, + group_id, + count_at_start, + ) + started_at = time.monotonic() + + if self._semaphore is None: + self._semaphore = asyncio.Semaphore( + max(1, self.config_manager.get_max_concurrent_tasks()) + ) + wait_started_at = time.monotonic() + logger.debug( + "增量分析等待调度槽位: platform=%s, group=%s, available=%s, active_tasks=%s", + platform_id, + group_id, + getattr(self._semaphore, "_value", None), + len(self._analysis_tasks), + ) + while True: + try: + await asyncio.wait_for( + self._semaphore.acquire(), timeout=self._SEMAPHORE_WARN_SECONDS + ) + break + except TimeoutError: + logger.warning( + "增量分析等待调度槽位超过 %.0fs: platform=%s, group=%s, " + "available=%s, active_tasks=%s", + time.monotonic() - wait_started_at, + platform_id, + group_id, + getattr(self._semaphore, "_value", None), + len(self._analysis_tasks), + ) + logger.debug( + "增量分析已取得调度槽位: platform=%s, group=%s, wait=%.2fs, available=%s", + platform_id, + group_id, + time.monotonic() - wait_started_at, + getattr(self._semaphore, "_value", None), + ) + try: + async with self._state_lock: + state = self._states.get(state_key) + if ( + not state + or int(state.get("version", -1)) != task_version + or not self.is_target_group(state_key) + ): + return + self._running_state_keys.add(state_key) + try: + result = await self.analyze_callback(group_id, platform_id) + finally: + self._running_state_keys.discard(state_key) + finally: + self._semaphore.release() + logger.debug( + "增量分析已释放调度槽位: platform=%s, group=%s, available=%s", + platform_id, + group_id, + getattr(self._semaphore, "_value", None), + ) + + result = result if isinstance(result, dict) else {} + consumed = max(0, int(result.get("messages_count", 0))) + reason = str(result.get("reason", "")) + await self.refresh_target_states() + async with self._state_lock: + state = self._states.get(state_key) + if ( + not state + or int(state.get("version", -1)) != task_version + or not self.is_target_group(state_key) + ): + discarded = True + remaining_count = 0 + new_arrivals = 0 + else: + current_count = int(state.get("count", 0)) + new_arrivals = max(0, current_count - count_at_start) + if result.get("success"): + state["count"] = max(0, current_count - consumed) + elif reason == "below_threshold": + state["count"] = consumed + new_arrivals + elif reason == "no_messages": + state["count"] = new_arrivals + # 成功消费后可连续排空积压;失败必须等待任务结束后的新消息。 + allow_continuation = bool(result.get("success") and consumed > 0) + remaining_count = int(state.get("count", 0)) + + logger.debug( + "增量分析计数结算: platform=%s, group=%s, success=%s, reason=%s, " + "pending_at_start=%s, new_arrivals=%s, consumed=%s, remaining=%s, " + "allow_continuation=%s, discarded=%s, 当前活跃群任务=%s, duration=%.2fs", + platform_id, + group_id, + bool(result.get("success")), + reason or "none", + count_at_start, + new_arrivals, + consumed, + remaining_count, + allow_continuation, + discarded, + len(self._analysis_tasks), + time.monotonic() - started_at, + ) + + self._schedule_flush() + if ( + result.get("success") + and consumed > 0 + and not discarded + and self.on_analysis_succeeded + ): + try: + self.on_analysis_succeeded(group_id, platform_id) + except Exception as exc: + logger.error(f"通知增量批次成功事件失败:{exc}", exc_info=True) + except asyncio.CancelledError: + raise + except Exception as exc: + logger.error(f"消息量触发增量分析失败:{exc}", exc_info=True) + finally: + if self._analysis_tasks.get(state_key) is current_task: + self._analysis_tasks.pop(state_key, None) + logger.debug( + "增量分析任务已结束:state=%s,当前活跃群任务=%s", + state_key, + len(self._analysis_tasks), + ) + + if self._closed: + return + async with self._state_lock: + state = self._states.get(state_key) + current_count = int(state.get("count", 0)) if state else 0 + should_continue = bool( + state + and self.is_target_group(state_key) + and current_count >= self.config_manager.get_incremental_min_messages() + and ( + allow_continuation + or (discarded and int(state.get("version", -1)) != task_version) + ) + ) + if should_continue: + logger.debug( + "增量分析继续处理待办批次: state=%s, pending=%s, threshold=%s", + state_key, + current_count, + self.config_manager.get_incremental_min_messages(), + ) + self._schedule_analysis(state_key) + + async def start(self) -> int: + """恢复持久化计数,并继续执行已经达到阈值的群。 + + Returns: + 启动时恢复的分析任务数量。 + """ + await self.refresh_target_states() + async with self._state_lock: + ready_keys = [ + state_key + for state_key, state in self._states.items() + if self.is_target_group(state_key) + and int(state.get("count", 0)) + >= self.config_manager.get_incremental_min_messages() + ] + for state_key in ready_keys: + self._schedule_analysis(state_key) + logger.info( + "增量状态恢复完成:恢复任务=%s,当前活跃群任务=%s", + len(ready_keys), + len(self._analysis_tasks), + ) + if ready_keys: + logger.debug("增量状态恢复任务明细:群=%s", ", ".join(sorted(ready_keys))) + return len(ready_keys) + + async def close(self) -> None: + """停止后台任务并持久化尚未消费的计数。""" + self._closed = True + if self._flush_task and not self._flush_task.done(): + self._flush_task.cancel() + await asyncio.gather(self._flush_task, return_exceptions=True) + tasks = list(self._analysis_tasks.values()) + for task in tasks: + task.cancel() + if tasks: + await asyncio.gather(*tasks, return_exceptions=True) + self._analysis_tasks.clear() + await self.flush() diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/utils/template_utils.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/utils/template_utils.py new file mode 100644 index 0000000..6147e57 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/utils/template_utils.py @@ -0,0 +1,106 @@ +"""安全模板渲染工具(String Template 兼容)""" + +import re +from string import Template + +from ...utils.logger import logger + +# 统一默认 placeholder +PLACEHOLDERS = { + # 分析类核心变量 + "messages_text": "${messages_text}", + "reviews_text": "${reviews_text}", + "max_topics": "${max_topics}", + "users_text": "${users_text}", + "max_golden_quotes": "${max_golden_quotes}", + # 文件名渲染类变量 + "group_id": "${group_id}", + "date": "${date}", + "ulid": "${ulid}", +} + + +def is_str_format_template(template: str) -> bool: + """判断模板是否为 str.format 风格。 + + 只认为满足: + 1) 不包含 String Template `${var}` 或 `$var` + 2) 包含 str.format `{var}`(非 `{{...}}`) + """ + if not template: + return False + + # 1. 預先建立排除模式 (匹配 ${var} 或 $var) + # 使用 set 去重並組合 + dollar_patterns = [re.escape(v) for v in PLACEHOLDERS.values()] + [ + rf"\${re.escape(k)}" for k in PLACEHOLDERS.keys() + ] + exclude_regex = "|".join(dollar_patterns) + + # 如果包含任何 $ 相關的佔位符,則不視為 str.format 模板 + if re.search(exclude_regex, template): + return False + + # 2. 檢查是否包含標準的 {key},確保匹配單個花括號包裹的 Key + for key in PLACEHOLDERS.keys(): + # (? tuple[str, bool]: + """如果模板是 str.format 风格,则自动升级为 string.Template。 + + 返回 (升级后的模板, 是否升级) + """ + if template is None: + return "", False + + if not is_str_format_template(template): + return template, False + + # 先转义原文中的 $,避免被 Template 误解释为占位符 + safe_template = template.replace("$", "$$") + + # 将 {var} 转为 ${var} + safe_template = re.sub( + r"(? str: + """渲染模板(String Template)。 + + Args: + template: 模板字符串 + strict: 是否使用严格模式(变量缺失则抛出异常) + **kwargs: 渲染变量 + + 由于插件启动时已完成 str.format 兼容升级,运行时直接按 string.Template 渲染。 + """ + if template is None: + return "" + + try: + t = Template(template) + return t.substitute(**kwargs) if strict else t.safe_substitute(**kwargs) + except Exception as e: + if strict: + raise + logger.warning( + f"[template_utils] 模板渲染失败,返回原始文本,错误: {e}", + exc_info=True, + ) + return template diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/visualization/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/visualization/__init__.py new file mode 100644 index 0000000..b980bb0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/visualization/__init__.py @@ -0,0 +1,7 @@ +""" +可视化模块 +""" + +from .activity_charts import ActivityVisualizer + +__all__ = ["ActivityVisualizer"] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/visualization/activity_charts.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/visualization/activity_charts.py new file mode 100644 index 0000000..60a73ad --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/visualization/activity_charts.py @@ -0,0 +1,157 @@ +""" +群聊活跃度可视化模块 +参考 astrbot_plugin_github_analyzer 的实现方式 +""" + +from collections import defaultdict +from datetime import datetime + +from ...domain.models.data_models import ActivityVisualization +from ...domain.repositories.visualization_repository import IActivityVisualizer + + +class ActivityVisualizer(IActivityVisualizer): + """活跃度可视化器""" + + def __init__(self): + pass + + def generate_activity_visualization( + self, messages: list[dict] + ) -> ActivityVisualization: + """生成活跃度可视化数据 - 专注于小时级别分析""" + hourly_activity = defaultdict(int) + user_activity = defaultdict(int) + emoji_activity = defaultdict(int) # 每小时表情统计 + + # 分析消息数据 + for msg in messages: + # 时间分析 - 只关注小时 + msg_time = datetime.fromtimestamp(msg.get("time", 0)) + hour = msg_time.hour + + # # 用户分析 + # sender = msg.get("sender", {}) + # user_id = str(sender.get("user_id", "")) + # nickname = InfoUtils.get_user_nickname(self.config_manager, sender) + + # 统计每小时消息数 + hourly_activity[hour] += 1 + + # # 统计用户活跃度 + # user_activity[user_id] = { + # "nickname": nickname, + # "count": user_activity.get(user_id, {}).get("count", 0) + 1 + # } + + # 统计每小时表情数 + for content in msg.get("message", []): + if content.get("type") in ["face", "mface", "bface", "sface"]: + emoji_activity[hour] += 1 + elif content.get("type") == "image": + data = content.get("data", {}) + summary = data.get("summary", "") + if "动画表情" in summary or "表情" in summary: + emoji_activity[hour] += 1 + + # 生成用户活跃度排行 + user_ranking = [] + for user_id, data in user_activity.items(): + user_ranking.append( + { + "user_id": user_id, + "nickname": data["nickname"], + "message_count": data["count"], + } + ) + user_ranking.sort(key=lambda x: x["message_count"], reverse=True) + + # 找出高峰时段(活跃度最高的3个小时) + peak_hours = sorted(hourly_activity.items(), key=lambda x: x[1], reverse=True)[ + :3 + ] + peak_hours = [{"hour": hour, "count": count} for hour, count in peak_hours] + + return ActivityVisualization( + hourly_activity=dict(hourly_activity), + daily_activity={}, # 不使用日期分析 + user_activity_ranking=user_ranking[:10], # 前10名 + peak_hours=peak_hours, + activity_heatmap_data=self._generate_hourly_heatmap_data( + hourly_activity, emoji_activity + ), + ) + + def _generate_hourly_heatmap_data( + self, hourly_activity: dict, emoji_activity: dict + ) -> dict: + """生成小时级热力图数据""" + # 计算活跃度等级 + norm_hourly = { + int(k) if str(k).isdigit() else k: v + for k, v in (hourly_activity or {}).items() + } + norm_emoji = { + int(k) if str(k).isdigit() else k: v + for k, v in (emoji_activity or {}).items() + } + max_hourly = max(norm_hourly.values()) if norm_hourly else 1 + max_emoji = max(norm_emoji.values()) if norm_emoji else 1 + + return { + "hourly_max": max_hourly, + "emoji_max": max_emoji, + "hourly_normalized": { + hour: (norm_hourly.get(hour, 0) / max_hourly) * 100 + for hour in range(24) + }, + "emoji_normalized": { + hour: (norm_emoji.get(hour, 0) / max_emoji) * 100 for hour in range(24) + }, + "activity_levels": self._calculate_activity_levels(norm_hourly), + } + + def _calculate_activity_levels(self, hourly_activity: dict) -> dict: + """计算活跃度等级""" + if not hourly_activity: + return {} + + norm_hourly = { + int(k) if str(k).isdigit() else k: v + for k, v in (hourly_activity or {}).items() + } + max_count = max(norm_hourly.values()) if norm_hourly else 0 + levels = {} + + for hour in range(24): + count = norm_hourly.get(hour, 0) + if count == 0: + level = "inactive" + elif max_count > 0 and count <= max_count * 0.3: + level = "low" + elif max_count > 0 and count <= max_count * 0.7: + level = "medium" + else: + level = "high" + levels[hour] = level + + return levels + + def get_hourly_chart_data(self, hourly_activity: dict) -> list[dict]: + """生成每小时活动分布的数据""" + chart_data = [] + norm_hourly = { + int(k) if str(k).isdigit() else k: v + for k, v in (hourly_activity or {}).items() + } + max_activity = max(norm_hourly.values()) if norm_hourly else 1 + + for hour in range(24): + count = norm_hourly.get(hour, 0) + percentage = (count / max_activity) * 100 if max_activity > 0 else 0 + + chart_data.append( + {"hour": hour, "count": count, "percentage": round(percentage, 1)} + ) + + return chart_data diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/webui/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/webui/__init__.py new file mode 100644 index 0000000..a6f9749 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/webui/__init__.py @@ -0,0 +1,8 @@ +""" +WebUI 基础设施层 - 任务管理器与 Web API 桥接 +""" + +from .active_task_manager import ActiveTaskManager +from .plugin_page_bridge import PluginPageWebUIBridge + +__all__ = ["ActiveTaskManager", "PluginPageWebUIBridge"] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/webui/active_task_manager.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/webui/active_task_manager.py new file mode 100644 index 0000000..5be6465 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/webui/active_task_manager.py @@ -0,0 +1,248 @@ +""" +活跃任务管理器与 Task Reaper 孤儿回收守护器 +负责内存活跃任务追踪、主动中止 (Cancellation) 以及超时任务的自动回收清理。 +""" + +from __future__ import annotations + +import asyncio +import time +from dataclasses import dataclass, field +from typing import Any + +from ...utils.logger import logger + + +@dataclass +class ActiveTaskInfo: + task_id: str + group_id: str + group_name: str + platform: str + trigger_type: str + current_stage: str + started_at: float = field(default_factory=time.time) + last_heartbeat: float = field(default_factory=time.time) + asyncio_task: asyncio.Task[Any] | None = None + + def to_dict(self) -> dict[str, Any]: + return { + "task_id": self.task_id, + "group_id": self.group_id, + "group_name": self.group_name, + "platform": self.platform, + "trigger_type": self.trigger_type, + "current_stage": self.current_stage, + "started_at": self.started_at, + "duration_s": round(time.time() - self.started_at, 1), + "last_heartbeat": self.last_heartbeat, + } + + +class ActiveTaskManager: + """活跃任务管理器与孤儿回收器""" + + def __init__(self, trace_store: Any | None = None): + self.trace_store = trace_store + self._tasks: dict[str, ActiveTaskInfo] = {} + self._lock = asyncio.Lock() + self._reaper_task: asyncio.Task[None] | None = None + self._subscribers: set[asyncio.Queue[str]] = set() + + async def register_task( + self, + task_id: str, + group_id: str, + group_name: str = "", + platform: str = "", + trigger_type: str = "manual", + current_stage: str = "FETCH_MESSAGES", + asyncio_task: asyncio.Task[Any] | None = None, + ) -> None: + """注册新运行中的任务""" + async with self._lock: + info = ActiveTaskInfo( + task_id=task_id, + group_id=str(group_id), + group_name=group_name, + platform=platform, + trigger_type=trigger_type, + current_stage=current_stage, + asyncio_task=asyncio_task, + ) + self._tasks[task_id] = info + await self._broadcast_event({"event": "task_started", "data": info.to_dict()}) + + async def update_stage(self, task_id: str, stage_name: str) -> None: + """更新当前活跃任务的阶段名称并更新心跳""" + async with self._lock: + if task_id in self._tasks: + self._tasks[task_id].current_stage = stage_name + self._tasks[task_id].last_heartbeat = time.time() + info = self._tasks[task_id] + else: + info = None + + if info: + await self._broadcast_event( + {"event": "task_progress", "data": info.to_dict()} + ) + + update_task_stage = update_stage + + def update_stage_sync(self, task_id: str, stage_name: str) -> None: + """同步更新活跃任务阶段(供 Span 上下文即时调用)""" + if task_id in self._tasks: + self._tasks[task_id].current_stage = stage_name + self._tasks[task_id].last_heartbeat = time.time() + info = self._tasks[task_id] + try: + loop = asyncio.get_running_loop() + loop.create_task( + self._broadcast_event( + {"event": "task_progress", "data": info.to_dict()} + ) + ) + except RuntimeError: + pass + + async def finish_task(self, task_id: str) -> None: + """标记任务结束并移出活跃列表""" + async with self._lock: + removed = self._tasks.pop(task_id, None) + + if removed: + await self._broadcast_event( + { + "event": "task_finished", + "data": {"task_id": task_id, "group_id": removed.group_id}, + } + ) + + async def cancel_task(self, task_id: str) -> bool: + """主动取消任务""" + async with self._lock: + task_info = self._tasks.get(task_id) + if not task_info: + return False + + if task_info.asyncio_task and not task_info.asyncio_task.done(): + task_info.asyncio_task.cancel() + + self._tasks.pop(task_id, None) + + if self.trace_store: + try: + self.trace_store.save_trace( + { + "trace_id": task_id, + "status": "aborted", + "error_message": "Task canceled manually via WebUI", + } + ) + except Exception as e: + logger.warning(f"更新取消任务状态失败: {e}") + + await self._broadcast_event( + {"event": "task_canceled", "data": {"task_id": task_id}} + ) + return True + + def get_active_tasks(self) -> list[dict[str, Any]]: + """获取所有当前正在运行的任务快照""" + return [t.to_dict() for t in self._tasks.values()] + + # ── SSE 实时广播支持 ── + + def subscribe(self) -> asyncio.Queue[str]: + """订阅实时事件队列""" + q: asyncio.Queue[str] = asyncio.Queue() + self._subscribers.add(q) + return q + + def unsubscribe(self, q: asyncio.Queue[str]) -> None: + """取消订阅""" + self._subscribers.discard(q) + + async def _broadcast_event(self, event_data: dict[str, Any]) -> None: + """向所有连接的 WebUI 客户端广播事件""" + import json + + raw = json.dumps(event_data, ensure_ascii=False) + for q in list(self._subscribers): + try: + q.put_nowait(raw) + except Exception: + self._subscribers.discard(q) + + # ── Task Reaper 守护线程 ── + + def start_reaper( + self, interval_seconds: int = 30, timeout_seconds: int = 600 + ) -> None: + """启动孤儿任务超时扫描守护协程,并在开机时自动对账清理历史遗留 running 记录""" + if self.trace_store and hasattr( + self.trace_store, "reconcile_crashed_traces_on_startup" + ): + try: + reconciled = self.trace_store.reconcile_crashed_traces_on_startup() + if reconciled > 0: + logger.info( + f"[TaskReaper] 开机自愈对账:已回收 {reconciled} 条异常中断的幽灵任务" + ) + except Exception as e: + logger.error(f"[TaskReaper] 开机自愈对账异常: {e}") + + if self._reaper_task is None or self._reaper_task.done(): + self._reaper_task = asyncio.create_task( + self._reaper_loop(interval_seconds, timeout_seconds) + ) + + def stop_reaper(self) -> None: + """停止守护协程""" + if self._reaper_task and not self._reaper_task.done(): + self._reaper_task.cancel() + + async def _reaper_loop(self, interval_seconds: int, timeout_seconds: int) -> None: + while True: + try: + await asyncio.sleep(interval_seconds) + now = time.time() + timed_out_tasks: list[ActiveTaskInfo] = [] + + async with self._lock: + for task_id, info in list(self._tasks.items()): + if now - info.last_heartbeat > timeout_seconds: + timed_out_tasks.append(info) + self._tasks.pop(task_id, None) + + for info in timed_out_tasks: + logger.warning( + f"[TaskReaper] 任务 {info.task_id} (群 {info.group_id}) 超过 {timeout_seconds}s 未更新心跳,强制回收清理" + ) + if info.asyncio_task and not info.asyncio_task.done(): + info.asyncio_task.cancel() + + if self.trace_store: + try: + self.trace_store.save_trace( + { + "trace_id": info.task_id, + "status": "failed", + "error_stage": info.current_stage, + "error_message": f"Task timed out after {timeout_seconds}s (Reaped)", + } + ) + except Exception as e: + logger.error(f"Reaper 更新持久化状态失败: {e}") + + await self._broadcast_event( + { + "event": "task_timed_out", + "data": {"task_id": info.task_id}, + } + ) + except asyncio.CancelledError: + break + except Exception as e: + logger.error(f"[TaskReaper] 巡检异常: {e}", exc_info=True) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/webui/plugin_page_bridge.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/webui/plugin_page_bridge.py new file mode 100644 index 0000000..d2f9dd4 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/infrastructure/webui/plugin_page_bridge.py @@ -0,0 +1,1695 @@ +""" +AstrBot 插件 Pages 后端 Web API 桥接服务 +为 React + Ant Design 5 控制台提供 REST 与 SSE 接口。 +""" + +from __future__ import annotations + +import asyncio +import base64 +import json +import re +import time +from collections.abc import Iterable +from pathlib import Path +from typing import Any + +try: + from astrbot.api.star import Context + from astrbot.api.web import ( + error_response, + json_response, + request, + stream_response, + ) +except (ImportError, AttributeError): + + class Context: # type: ignore + pass + + def json_response(data: Any, status_code: int = 200) -> Any: # type: ignore + return {"status_code": status_code, "data": data} + + def error_response(msg: str, status_code: int = 400) -> Any: # type: ignore + return {"status_code": status_code, "message": msg} + + request: Any = None # type: ignore + + def stream_response(gen: Any) -> Any: # type: ignore + return gen + + +from ...shared.constants import PLUGIN_NAME +from ...shared.trace_context import TraceContext +from ...utils.logger import logger +from ..persistence.trace_sqlite_store import TraceSQLiteStore +from ..platform.factory import PlatformAdapterFactory +from .active_task_manager import ActiveTaskManager + + +def _sanitize_path_segment(segment: str) -> str: + cleaned = [] + for ch in segment: + if ("a" <= ch <= "z") or ("A" <= ch <= "Z") or ch.isdigit() or ch in {"-", "_"}: + cleaned.append(ch) + else: + cleaned.append("_") + result = "".join(cleaned).strip("_") + return result or "_" + + +def _config_key_to_folder(key_path: str) -> str: + """与 AstrBot 官方核心完全一致的 config_key 到存储目录转换规则(以 / 分隔)""" + parts = [_sanitize_path_segment(part) for part in key_path.split(".") if part] + return "/".join(parts) if parts else "_" + + +class PluginPageWebUIBridge: + """WebUI 面板 API 桥接适配器""" + + def __init__( + self, + context: Context, + trace_store: TraceSQLiteStore, + active_task_manager: ActiveTaskManager, + analysis_service: Any, + report_dispatcher: Any = None, + report_output_dir: Path | None = None, + ): + self.context = context + self.trace_store = trace_store + self.active_task_manager = active_task_manager + self.analysis_service = analysis_service + self.report_dispatcher = report_dispatcher + self.report_output_dir = report_output_dir + TraceContext.set_active_task_manager(self.active_task_manager) + + def register_routes(self) -> None: + """向 AstrBot 注册所有 Web API 端点""" + routes = [ + # 1. 活跃任务与控制 + ( + f"/{PLUGIN_NAME}/tasks/active", + self.api_get_active_tasks, + ["GET"], + "Get active running analysis tasks", + ), + ( + f"/{PLUGIN_NAME}/tasks/cancel", + self.api_cancel_task, + ["POST"], + "Cancel an active analysis task", + ), + ( + f"/{PLUGIN_NAME}/tasks/trigger", + self.api_trigger_task, + ["POST"], + "Trigger an analysis task manually", + ), + ( + f"/{PLUGIN_NAME}/tasks//resume", + self.api_resume_task, + ["POST"], + "Resume an analysis task from checkpoint", + ), + # 2. 链路追溯与详情 + ( + f"/{PLUGIN_NAME}/traces", + self.api_list_traces, + ["GET"], + "List execution traces with filters", + ), + ( + f"/{PLUGIN_NAME}/traces/", + self.api_get_trace_detail, + ["GET"], + "Get full trace details with spans and metrics", + ), + ( + f"/{PLUGIN_NAME}/metrics/summary", + self.api_get_metrics_summary, + ["GET"], + "Get KPI and token metrics summary", + ), + ( + f"/{PLUGIN_NAME}/metrics/trends", + self.api_get_analytics_trends, + ["GET"], + "Get time-series trends with hour/day granularity and provider breakdowns", + ), + ( + f"/{PLUGIN_NAME}/groups", + self.api_get_distinct_groups, + ["GET"], + "Get distinct groups list for filtering", + ), + ( + f"/{PLUGIN_NAME}/platforms", + self.api_get_platforms, + ["GET"], + "Get active connected bot platforms list", + ), + ( + f"/{PLUGIN_NAME}/providers", + self.api_get_providers, + ["GET"], + "Get available LLM providers list", + ), + ( + f"/{PLUGIN_NAME}/personas", + self.api_get_personas, + ["GET"], + "Get available AstrBot personas list", + ), + # 4. 历史产物 + ( + f"/{PLUGIN_NAME}/reports/history", + self.api_get_report_history, + ["GET"], + "Get generated report image list", + ), + ( + f"/{PLUGIN_NAME}/reports/content", + self.api_get_report_content, + ["GET"], + "Get generated report image base64 content", + ), + ( + f"/{PLUGIN_NAME}/reports/rerender", + self.api_rerender_report, + ["POST"], + "Re-render report with a new theme template using cached checkpoint without LLM tokens", + ), + ( + f"/{PLUGIN_NAME}/reports/templates", + self.api_get_report_templates, + ["GET"], + "Get available built-in and custom report visual templates", + ), + # 5. SSE 实时事件流 + ( + f"/{PLUGIN_NAME}/events/stream", + self.api_stream_events, + ["GET"], + "SSE stream for real-time task progress events", + ), + # 6. 插件专属日志 + ( + f"/{PLUGIN_NAME}/logs", + self.api_get_plugin_logs, + ["GET"], + "Get plugin live logs with filters", + ), + ( + f"/{PLUGIN_NAME}/traces//logs", + self.api_get_trace_logs, + ["GET"], + "Get execution logs for a specific trace", + ), + ( + f"/{PLUGIN_NAME}/logs/clear", + self.api_clear_plugin_logs, + ["POST"], + "Clear in-memory plugin log buffer", + ), + # 7. 插件配置中心 + ( + f"/{PLUGIN_NAME}/config", + self.api_get_config, + ["GET"], + "Get current plugin configuration and schema definition", + ), + ( + f"/{PLUGIN_NAME}/config", + self.api_save_config, + ["POST"], + "Save and persist updated plugin configuration", + ), + ( + f"/{PLUGIN_NAME}/config/upload_file", + self.api_upload_config_file, + ["POST"], + "Upload a config reference image/file and store to files/ folder", + ), + ( + f"/{PLUGIN_NAME}/config/file/content", + self.api_get_config_file_content, + ["GET"], + "Get thumbnail or content of a config file path", + ), + ] + + for path, handler, methods, desc in routes: + try: + self.context.register_web_api(path, handler, methods, desc) # type: ignore + except Exception as e: + logger.error(f"注册 Web API 路由 {path} 失败: {e}") + + # 挂载日志流至 SSE 广播通道,实现毫秒级实时日志推送 + try: + from ..logging.plugin_log_buffer import global_log_buffer + + def _forward_log_to_sse(entry: Any) -> None: + try: + loop = asyncio.get_running_loop() + loop.create_task( + self.active_task_manager._broadcast_event( + {"event": "log_entry", "data": entry.to_dict()} + ) + ) + except RuntimeError: + pass + + global_log_buffer.register_listener(_forward_log_to_sse) + except Exception as e: + logger.warning(f"挂载日志 SSE 监听器失败: {e}") + + async def api_get_active_tasks(self) -> Any: + """获取当前正在执行的任务列表""" + tasks = self.active_task_manager.get_active_tasks() + return json_response({"status": "ok", "data": tasks}) + + async def api_cancel_task(self) -> Any: + """手动取消正在执行的任务""" + try: + payload = await request.json(default={}) + task_id = payload.get("task_id", "").strip() + if not task_id: + return error_response("Missing task_id in request", status_code=400) + + success = await self.active_task_manager.cancel_task(task_id) + if success: + return json_response( + {"status": "ok", "message": f"Task {task_id} canceled successfully"} + ) + return error_response( + f"Task {task_id} not found or already finished", status_code=404 + ) + except Exception as e: + logger.error(f"取消任务异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_trigger_task(self) -> Any: + """从 Web 界面手动触发群分析任务""" + try: + payload = await request.json(default={}) + group_id = str(payload.get("group_id", "")).strip() + if not group_id: + return error_response("group_id is required", status_code=400) + + group_name = str(payload.get("group_name", f"群 {group_id}")) + platform = str(payload.get("platform", "qq")) + + # 生成语义化 TraceID + trace_id = TraceContext.generate("web_manual", group_name) + + provider_id = ( + payload.get("provider_id") if isinstance(payload, dict) else None + ) + if not provider_id and hasattr(request, "query"): + provider_id = request.query.get("provider_id") + + # 启动后台异步任务 + asyncio_task = asyncio.create_task( + self._run_triggered_task( + trace_id=trace_id, + group_id=group_id, + group_name=group_name, + platform=platform, + provider_id=provider_id, + ) + ) + + # 注册到活跃任务管理器 + await self.active_task_manager.register_task( + task_id=trace_id, + group_id=group_id, + group_name=group_name, + platform=platform, + trigger_type="web_ui", + current_stage="FETCH_MESSAGES", + asyncio_task=asyncio_task, + ) + + return json_response( + { + "status": "ok", + "data": { + "trace_id": trace_id, + "group_id": group_id, + "message": "Analysis task queued successfully", + }, + } + ) + except Exception as e: + logger.error(f"触发分析任务异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def _run_triggered_task( + self, + trace_id: str, + group_id: str, + group_name: str, + platform: str, + provider_id: str | None = None, + ) -> None: + """后台异步执行触发任务""" + trace_ctx = TraceContext.set( + trace_id=trace_id, + group_id=group_id, + group_name=group_name, + platform=platform, + trigger_type="web_ui", + ) + if provider_id: + trace_ctx.metadata["override_provider_id"] = str(provider_id) + try: + if hasattr(self.analysis_service, "execute_daily_analysis"): + result = await self.analysis_service.execute_daily_analysis( + group_id=group_id, + platform_id=platform + if platform and platform not in ("all", "auto", "default") + else None, + manual=True, + ) + if result and result.get("success"): + analysis_result = result.get("analysis_result") + adapter = result.get("adapter") + bot_mgr = getattr(self.analysis_service, "bot_manager", None) + dispatch_platform_id = ( + ( + bot_mgr.get_adapter_platform_id(adapter) + if bot_mgr and adapter + else "" + ) + or getattr(adapter, "platform_id", "") + or ( + platform + if platform and platform not in ("all", "auto", "default") + else "" + ) + ) + trace_ctx.platform = str(dispatch_platform_id) + # 调度生成报告长图并推送到目标群聊 + if self.report_dispatcher and analysis_result: + try: + await self.report_dispatcher.dispatch( + group_id, + analysis_result, + dispatch_platform_id, + ) + except Exception as dispatch_err: + logger.error( + f"WebUI 触发报告发送异常 (群 {group_id}): {dispatch_err}", + exc_info=True, + ) + + if trace_ctx.status == "running": + trace_ctx.finish(status="succeeded") + else: + if trace_ctx.status == "running": + trace_ctx.finish( + status="failed", + error_message=str(result.get("reason", "unknown")), + ) + elif hasattr(self.analysis_service, "analyze_group_daily"): + await self.analysis_service.analyze_group_daily( + group_id=group_id, + platform_name=platform, + is_manual=True, + trace_ctx=trace_ctx, + ) + if trace_ctx.status == "running": + trace_ctx.finish(status="succeeded") + else: + with trace_ctx.span("FETCH_MESSAGES"): + await asyncio.sleep(0.5) + with trace_ctx.span("LLM_ANALYSIS"): + await asyncio.sleep(1.0) + trace_ctx.set_context_metrics(1200, 800) + trace_ctx.add_token_usage(1500, 300, "topics") + if trace_ctx.status == "running": + trace_ctx.finish(status="succeeded") + except Exception as e: + if trace_ctx.status == "running": + trace_ctx.finish(status="failed", error_message=str(e)) + logger.error(f"任务 {trace_id} 执行出错: {e}", exc_info=True) + finally: + await self.active_task_manager.finish_task(trace_id) + + async def api_resume_task(self, trace_id: str) -> Any: + """从 Checkpoint 幂等恢复并重试任务""" + try: + trace_record = self.trace_store.get_trace(trace_id) + if not trace_record: + return error_response(f"Trace {trace_id} not found", status_code=404) + + group_id = str(trace_record.get("group_id", "")) + group_name = str(trace_record.get("group_name", "")) + platform = str(trace_record.get("platform", "")) + + payload = {} + if hasattr(request, "json"): + try: + payload = await request.json() + except Exception: + payload = {} + provider_id = ( + payload.get("provider_id") if isinstance(payload, dict) else None + ) + template_name = ( + payload.get("template_name") if isinstance(payload, dict) else None + ) + if not provider_id and hasattr(request, "query"): + provider_id = request.query.get("provider_id") + if not template_name and hasattr(request, "query"): + template_name = request.query.get("template_name") + + # 启动后台异步任务 + asyncio_task = asyncio.create_task( + self._run_resumed_task( + trace_id=trace_id, + group_id=group_id, + group_name=group_name, + platform=platform, + provider_id=provider_id, + template_name=template_name, + ) + ) + + await self.active_task_manager.register_task( + task_id=trace_id, + group_id=group_id, + group_name=group_name, + platform=platform, + trigger_type="resume", + current_stage="LLM_ANALYSIS", + asyncio_task=asyncio_task, + ) + + return json_response( + { + "status": "ok", + "data": { + "trace_id": trace_id, + "group_id": group_id, + "provider_id": provider_id, + "template_name": template_name, + "message": "Task resume queued successfully", + }, + } + ) + except Exception as e: + logger.error(f"恢复任务异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def _run_resumed_task( + self, + trace_id: str, + group_id: str, + group_name: str, + platform: str, + provider_id: str | None = None, + template_name: str | None = None, + ) -> None: + """后台异步执行断点续跑""" + trace_ctx = TraceContext.set( + trace_id=trace_id, + group_id=group_id, + group_name=group_name, + platform=platform, + trigger_type="resume", + ) + if provider_id: + trace_ctx.metadata["override_provider_id"] = str(provider_id) + if template_name and template_name != "auto": + trace_ctx.metadata["override_template_name"] = str(template_name) + try: + if hasattr(self.analysis_service, "resume_analysis"): + result = await self.analysis_service.resume_analysis( + trace_id=trace_id, + group_id=group_id, + platform_id=platform + if platform and platform not in ("all", "auto", "default") + else None, + template_name=template_name, + ) + if result and result.get("success"): + analysis_result = result.get("analysis_result") + adapter = result.get("adapter") + bot_mgr = getattr(self.analysis_service, "bot_manager", None) + dispatch_platform_id = ( + ( + bot_mgr.get_adapter_platform_id(adapter) + if bot_mgr and adapter + else "" + ) + or getattr(adapter, "platform_id", "") + or ( + platform + if platform and platform not in ("all", "auto", "default") + else "" + ) + ) + trace_ctx.platform = str(dispatch_platform_id) + if self.report_dispatcher and analysis_result: + try: + with trace_ctx.span( + "DISPATCH_REPORT", + { + "platform": dispatch_platform_id or "auto", + "group_id": group_id, + }, + ): + await self.report_dispatcher.dispatch( + group_id, + analysis_result, + dispatch_platform_id, + ) + except Exception as dispatch_err: + logger.error( + f"WebUI 续跑报告发送异常 (群 {group_id}): {dispatch_err}", + exc_info=True, + ) + + if trace_ctx.status == "running": + trace_ctx.finish(status="succeeded") + else: + if trace_ctx.status == "running": + trace_ctx.finish( + status="failed", + error_message=str(result.get("reason", "unknown")), + ) + else: + await self._run_triggered_task(trace_id, group_id, group_name, platform) + except Exception as e: + if trace_ctx.status == "running": + trace_ctx.finish(status="failed", error_message=str(e)) + logger.error(f"续跑任务 {trace_id} 执行出错: {e}", exc_info=True) + finally: + await self.active_task_manager.finish_task(trace_id) + + async def api_list_traces(self) -> Any: + """分页与条件筛选 Trace 列表""" + try: + limit = int(request.query.get("limit", 20)) + offset = int(request.query.get("offset", 0)) + group_id = request.query.get("group_id") + status = request.query.get("status") + search = request.query.get("search") + start_time_raw = request.query.get("start_time") + end_time_raw = request.query.get("end_time") + sort_by = request.query.get("sort_by", "started_at") + sort_order = request.query.get("sort_order", "desc") + + start_time = float(start_time_raw) if start_time_raw else None + end_time = float(end_time_raw) if end_time_raw else None + + items, total = self.trace_store.list_traces( + limit=limit, + offset=offset, + group_id=group_id, + status=status, + search=search, + start_time=start_time, + end_time=end_time, + sort_by=sort_by, + sort_order=sort_order, + ) + return json_response( + {"status": "ok", "data": {"items": items, "total": total}} + ) + except Exception as e: + logger.error(f"查询 Trace 列表异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_get_distinct_groups(self) -> Any: + """获取所有有历史分析记录的群组列表(用于下拉快速筛选)""" + try: + groups = self.trace_store.get_distinct_groups() + return json_response({"status": "ok", "data": groups}) + except Exception as e: + logger.error(f"查询群组列表异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_get_platforms(self) -> Any: + """获取当前 AstrBot 中已注册并就绪的所有聊天平台列表(基于 AstrBot 原生 PlatformMetadata)""" + try: + platforms: list[dict[str, Any]] = [] + seen_ids = set() + type_display_map = { + "aiocqhttp": "OneBot v11", + "qq_official": "QQ 官方机器人", + "qq_official_webhook": "QQ 官方 Webhook", + "telegram": "Telegram", + "discord": "Discord", + } + + # 1. 优先从 AstrBot 原生 platform_manager 获取标准元数据 + platform_manager = getattr(self.context, "platform_manager", None) + if platform_manager and hasattr(platform_manager, "get_insts"): + insts = platform_manager.get_insts() or [] + for inst in insts: + try: + meta = ( + inst.meta() + if callable(getattr(inst, "meta", None)) + else None + ) + p_id = ( + getattr(meta, "id", None) + or ( + getattr(inst, "config", {}).get("id") + if isinstance(getattr(inst, "config", None), dict) + else None + ) + or "" + ) + p_type = ( + getattr(meta, "name", "") + or ( + getattr(inst, "config", {}).get("type", "") + if isinstance(getattr(inst, "config", None), dict) + else "" + ) + or "" + ) + # 仅保留插件适配器工厂支持的聊天平台 + if ( + not p_id + or p_id in seen_ids + or not PlatformAdapterFactory.is_supported(p_type) + ): + continue + + meta_display = getattr(meta, "adapter_display_name", "") + display_name = ( + meta_display + if (meta_display and meta_display != p_type) + else type_display_map.get(p_type, p_type) + ) + label = ( + display_name + if (p_id == p_type or p_id == display_name) + else f"{display_name} ({p_id})" + ) + + seen_ids.add(p_id) + platforms.append( + { + "id": str(p_id), + "type": str(p_type), + "display_name": str(display_name), + "label": str(label), + } + ) + except Exception: + pass + + # 2. 兜底补全已在 bot_manager 注册的适配器 + bot_manager = getattr(self.analysis_service, "bot_manager", None) + if bot_manager: + for p_id, adp in bot_manager.get_all_adapters().items(): + if p_id in seen_ids: + continue + p_name = getattr(adp, "platform_name", "unknown") + display_name = type_display_map.get( + p_name, type(adp).__name__.replace("Adapter", "") + ) + label = ( + display_name if p_id == p_name else f"{display_name} ({p_id})" + ) + seen_ids.add(p_id) + platforms.append( + { + "id": str(p_id), + "type": str(p_name), + "display_name": str(display_name), + "label": str(label), + } + ) + + return json_response({"status": "ok", "data": platforms}) + except Exception as e: + logger.error(f"获取平台列表异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_get_providers(self) -> Any: + """获取当前 AstrBot 中已就绪的所有 LLM Provider 列表""" + try: + providers: list[dict[str, Any]] = [] + seen_ids = set() + provider_getter = getattr(self.context, "get_all_providers", None) + if not callable(provider_getter): + provider_mgr = getattr(self.context, "provider_manager", None) + provider_getter = getattr(provider_mgr, "get_all_providers", None) + + if callable(provider_getter): + raw_list = provider_getter() + provider_list: list[Any] = ( + list(raw_list) if isinstance(raw_list, Iterable) else [] + ) + for p in provider_list: + try: + meta = p.meta() if callable(getattr(p, "meta", None)) else None + p_id = ( + getattr(meta, "id", None) + or ( + getattr(p, "config", {}).get("id") + if isinstance(getattr(p, "config", None), dict) + else None + ) + or getattr(p, "id", None) + or str(p) + ) + if not p_id or p_id in seen_ids: + continue + p_name = ( + getattr(meta, "name", None) + or getattr(meta, "model", None) + or p_id + ) + p_type = getattr(meta, "provider_type", "") + seen_ids.add(p_id) + providers.append( + { + "id": str(p_id), + "name": str(p_name), + "type": str(p_type), + "label": f"{p_name} ({p_id})" + if p_name != p_id + else str(p_name), + } + ) + except Exception: + pass + return json_response({"status": "ok", "data": providers}) + except Exception as e: + logger.error(f"获取 Provider 列表异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_get_personas(self) -> Any: + """获取当前 AstrBot 中配置的所有人格 (Persona) 列表""" + try: + personas: list[dict[str, Any]] = [] + seen_ids = set() + pm = getattr(self.context, "persona_manager", None) + if pm: + # 1. 优先读取 v3 personas + for p in getattr(pm, "personas_v3", []) or []: + p_name = ( + p.get("name") + if isinstance(p, dict) + else getattr(p, "name", None) + ) + if p_name and p_name not in seen_ids: + seen_ids.add(p_name) + personas.append( + { + "id": str(p_name), + "name": str(p_name), + "label": str(p_name), + } + ) + # 2. 读取持久化 DB personas + for p in getattr(pm, "personas", []) or []: + p_id = getattr(p, "persona_id", None) or getattr(p, "name", None) + p_name = getattr(p, "name", None) or p_id + if p_id and p_id not in seen_ids: + seen_ids.add(p_id) + personas.append( + { + "id": str(p_id), + "name": str(p_name), + "label": f"{p_name} ({p_id})" + if p_name != p_id + else str(p_name), + } + ) + return json_response({"status": "ok", "data": personas}) + except Exception as e: + logger.error(f"获取 Persona 列表异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_get_trace_detail(self, trace_id: str) -> Any: + """获取单个 Trace 的完整 Span 树与上下文指标 + + 优先查 SQLite 持久化记录;若未入库(任务尚在运行中),则回退到 + TraceContext 内存活跃实例与 ActiveTaskManager 快照,实时展示运行中的 Spans 状态。 + """ + try: + trace = self.trace_store.get_trace(trace_id) + if trace: + return json_response({"status": "ok", "data": trace}) + + # 回退:从活跃 TraceContext 实例获取实时未完成的 Spans 和当前阶段 + active_trace = TraceContext.get_active_trace(trace_id) + task_info = None + for t in self.active_task_manager.get_active_tasks(): + if t.get("task_id") == trace_id: + task_info = t + break + + if active_trace or task_info: + started_at = ( + active_trace.started_at + if active_trace + else ( + task_info.get("started_at", time.time()) + if task_info + else time.time() + ) + ) + current_stage = ( + active_trace.current_stage + if (active_trace and active_trace.current_stage) + else ( + task_info.get("current_stage", "") + if task_info + else "FETCH_MESSAGES" + ) + ) + spans = list(active_trace._spans) if active_trace else [] + context_metrics = ( + active_trace._context_metrics if active_trace else None + ) + token_usage = active_trace._token_usage if active_trace else None + + group_id_val = (active_trace.group_id if active_trace else "") or ( + task_info.get("group_id", "") if task_info else "" + ) + group_name_val = (active_trace.group_name if active_trace else "") or ( + task_info.get("group_name", "") if task_info else "" + ) + platform_val = (active_trace.platform if active_trace else "") or ( + task_info.get("platform", "") if task_info else "" + ) + trigger_type_val = ( + active_trace.trigger_type if active_trace else "" + ) or ( + task_info.get("trigger_type", "manual") if task_info else "manual" + ) + + return json_response( + { + "status": "ok", + "data": { + "trace_id": trace_id, + "group_id": group_id_val, + "group_name": group_name_val, + "platform": platform_val, + "trigger_type": trigger_type_val, + "status": "running", + "started_at": started_at, + "completed_at": None, + "duration_ms": round((time.time() - started_at) * 1000), + "error_stage": None, + "error_message": None, + "stack_trace": None, + "extra": dict(active_trace.metadata) + if active_trace + else {}, + "spans": spans, + "context_metrics": context_metrics, + "token_usage": token_usage, + "current_stage": current_stage, + }, + } + ) + + return error_response(f"Trace {trace_id} not found", status_code=404) + except Exception as e: + logger.error(f"查询 Trace 详情异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_get_metrics_summary(self) -> Any: + """获取顶部 KPI 与 Token 统计概览""" + try: + summary = self.trace_store.get_metrics_summary() + return json_response({"status": "ok", "data": summary}) + except Exception as e: + logger.error(f"获取指标概览异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_get_analytics_trends(self) -> Any: + """获取时序趋势统计(支持按小时或按天细粒度切换,并包含服务商与模型统计)""" + try: + granularity = ( + request.query.get("granularity", "day") + if request and hasattr(request, "query") + else "day" + ) + range_count = ( + int( + request.query.get( + "range_count", 48 if granularity == "hour" else 14 + ) + ) + if request and hasattr(request, "query") + else (48 if granularity == "hour" else 14) + ) + + trends_data = self.trace_store.get_analytics_trends( + granularity=granularity, range_count=range_count + ) + return json_response({"status": "ok", "data": trends_data}) + except Exception as e: + logger.error(f"获取趋势图表数据异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_get_report_history(self) -> Any: + """获取历史生成的报告文件列表(支持图片与 HTML 报告,包含群号、群名与平台归属精准解析)""" + try: + reports: list[dict[str, Any]] = [] + group_info_map = { + str(g["group_id"]): { + "group_name": str(g.get("group_name", "")), + "platform": str(g.get("platform", "")), + } + for g in self.trace_store.get_distinct_groups() + } + candidate_dirs: list[Path] = [] + if self.report_output_dir and self.report_output_dir.exists(): + candidate_dirs.append(self.report_output_dir) + + # 兼容自托管 HTML 输出目录 + cfg_mgr = getattr(self.analysis_service, "config_manager", None) or getattr( + self.report_dispatcher, "config_manager", None + ) + if cfg_mgr: + custom_html_dir = getattr(cfg_mgr, "get_html_output_dir", lambda: "")() + if custom_html_dir: + p = Path(custom_html_dir) + if p.exists() and p not in candidate_dirs: + candidate_dirs.append(p) + + seen_paths = set() + all_files: list[Path] = [] + for d in candidate_dirs: + for p in d.iterdir(): + if ( + p.is_file() + and p.suffix.lower() + in {".jpg", ".jpeg", ".png", ".webp", ".html", ".htm"} + and p.resolve() not in seen_paths + ): + seen_paths.add(p.resolve()) + all_files.append(p) + + report_trace_map: dict[str, str] = {} + if hasattr(self.trace_store, "get_report_trace_map"): + try: + report_trace_map = self.trace_store.get_report_trace_map() + except Exception: + pass + + for file_path in sorted( + all_files, + key=lambda p: p.stat().st_mtime, + reverse=True, + )[:150]: + try: + stat = file_path.stat() + stem = file_path.stem + is_html = file_path.suffix.lower() in {".html", ".htm"} + is_comic = stem.lower().startswith("comic_") or stem.startswith( + "漫画_" + ) + trace_id = report_trace_map.get(file_path.name, "") + group_id = "" + + # 1. 优先通过数据库已登记群号精确匹配(最长匹配优先,避免前缀歧义) + for known_gid in sorted( + group_info_map.keys(), key=len, reverse=True + ): + if not known_gid: + continue + if re.search(rf"(?:^|_){re.escape(known_gid)}(?:_|$)", stem): + group_id = known_gid + break + + # 2. 若未匹配到已知群,按结构化模式解析群号 + if not group_id: + m = re.match( + r"^(?:report|群聊分析报告|comic|漫画)_(.+?)_(?:\d{4}-?\d{2}-?\d{2}|\d{8})(?:_\d{6})?(?:_([a-zA-Z0-9_\-]+))?$", + stem, + re.IGNORECASE, + ) + if m: + group_id = m.group(1) + if m.group(2) and not trace_id: + cand = m.group(2) + if "_" in cand or len(cand) < 26: + trace_id = cand + else: + m = re.match( + r"^(?:report|群聊分析报告|comic|漫画)_(.+?)_\d+$", + stem, + re.IGNORECASE, + ) + if m: + group_id = m.group(1) + else: + m = re.match( + r"^(?:report|群聊分析报告|comic|漫画)_(.+?)$", + stem, + re.IGNORECASE, + ) + group_id = m.group(1) if m else stem + + # 3. 兜底获取 trace_id + if not trace_id: + trace_id = report_trace_map.get(file_path.name, "") + if not trace_id: + # 检查文件名中是否直接包含了已知 trace_id + for tid in set(report_trace_map.values()): + if tid and tid in stem: + trace_id = tid + break + if not trace_id and group_id: + # 检查同群同精确时间戳(年月日_时分秒)前缀的文件映射,避免同天不同任务误匹配 + stem_parts = stem.split("_") + if len(stem_parts) >= 4 and re.match(r"^\d{6}$", stem_parts[3]): + stem_prefix = "_".join(stem_parts[:4]) + for fn, tid in report_trace_map.items(): + if tid and fn.startswith(stem_prefix): + trace_id = tid + break + + g_info = group_info_map.get(group_id, {}) + group_name = g_info.get("group_name", "") + platform = g_info.get("platform", "") + + reports.append( + { + "filename": file_path.name, + "size_bytes": stat.st_size, + "modified_at": stat.st_mtime, + "absolute_path": str(file_path.resolve()), + "is_html": is_html, + "is_comic": is_comic, + "report_type": "comic" + if is_comic + else ("html" if is_html else "image"), + "group_id": group_id, + "group_name": group_name, + "platform": platform, + "trace_id": trace_id, + } + ) + except Exception: + pass + return json_response({"status": "ok", "data": reports}) + except Exception as e: + logger.error(f"查询历史报告异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_get_report_content(self) -> Any: + """获取单个历史报告文件(图片或 HTML)的内容用于在线预览与下载""" + try: + filename = ( + request.query.get("filename", "").strip() + if request and hasattr(request, "query") + else "" + ) + if not filename: + return error_response("Missing filename parameter", status_code=400) + + safe_filename = Path(filename).name + target_file: Path | None = None + + # 搜索输出目录与自托管 HTML 目录 + search_dirs = [] + if self.report_output_dir and self.report_output_dir.exists(): + search_dirs.append(self.report_output_dir) + cfg_mgr = getattr(self.analysis_service, "config_manager", None) or getattr( + self.report_dispatcher, "config_manager", None + ) + if cfg_mgr: + custom_html_dir = getattr(cfg_mgr, "get_html_output_dir", lambda: "")() + if custom_html_dir: + p = Path(custom_html_dir) + if p.exists() and p not in search_dirs: + search_dirs.append(p) + + for d in search_dirs: + cand = d / safe_filename + if cand.is_file() and cand.exists(): + target_file = cand + break + + if not target_file: + return error_response( + f"Report file {safe_filename} not found", status_code=404 + ) + + ext = target_file.suffix.lower().lstrip(".") + is_html = ext in ("html", "htm") + stat = target_file.stat() + + if is_html: + raw_text = target_file.read_text(encoding="utf-8", errors="replace") + b64_content = base64.b64encode(raw_text.encode("utf-8")).decode("utf-8") + data_url = f"data:text/html;charset=utf-8;base64,{b64_content}" + return json_response( + { + "status": "ok", + "data": { + "filename": safe_filename, + "size_bytes": stat.st_size, + "modified_at": stat.st_mtime, + "absolute_path": str(target_file.resolve()), + "is_html": True, + "html_content": raw_text, + "data_url": data_url, + }, + } + ) + else: + mime_type = f"image/{'jpeg' if ext in ('jpg', 'jpeg') else ext}" + with open(target_file, "rb") as f: + b64_content = base64.b64encode(f.read()).decode("utf-8") + return json_response( + { + "status": "ok", + "data": { + "filename": safe_filename, + "size_bytes": stat.st_size, + "modified_at": stat.st_mtime, + "absolute_path": str(target_file.resolve()), + "is_html": False, + "data_url": f"data:{mime_type};base64,{b64_content}", + }, + } + ) + except Exception as e: + logger.error(f"读取历史报告内容异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_rerender_report(self) -> Any: + """免 Token 切换模板重新渲染历史分析报告""" + try: + body = await request.json() if hasattr(request, "json") else {} + except Exception: + body = {} + + group_id = str(body.get("group_id", "")).strip() + date_str = str(body.get("date_str", "")).strip() + template_name = str(body.get("template_name", "default")).strip() + render_format = str(body.get("render_format", "image")).strip() + platform_id = body.get("platform_id") + trace_id = str(body.get("trace_id", "")).strip() + + if not group_id: + return error_response("缺少群号参数 group_id", status_code=400) + if not date_str: + import datetime as _dt + + date_str = _dt.datetime.now().strftime("%Y-%m-%d") + + if not trace_id and hasattr(self, "trace_store"): + try: + recent_res = self.trace_store.list_traces(group_id=group_id, limit=5) + items = recent_res.get("items") if isinstance(recent_res, dict) else [] + if items: + trace_id = str(items[0].get("trace_id", "")) + except Exception: + pass + + try: + result = await self.analysis_service.rerender_report( + group_id=group_id, + date_str=date_str, + template_name=template_name, + platform_id=platform_id, + render_format=render_format, + trace_id=trace_id if trace_id else None, + ) + if not result.get("success"): + return error_response( + result.get("reason", "重新渲染失败"), status_code=400 + ) + return json_response({"status": "ok", "data": result}) + except Exception as e: + logger.error(f"重新渲染报告异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_get_report_templates(self) -> Any: + """获取系统内置及用户自定义的所有可用报告视觉模板""" + try: + generator = getattr( + self.analysis_service, "report_generator", None + ) or getattr(self.report_dispatcher, "report_generator", None) + html_tpls = getattr(generator, "html_templates", None) + if html_tpls and hasattr(html_tpls, "get_available_templates"): + templates = html_tpls.get_available_templates() + else: + from ..reporting.templates import HTMLTemplates + + cfg_mgr = getattr( + self.analysis_service, "config_manager", None + ) or getattr(self.report_dispatcher, "config_manager", None) + tpl_mgr = HTMLTemplates(cfg_mgr) + templates = tpl_mgr.get_available_templates() + return json_response({"status": "ok", "data": templates}) + except Exception as e: + logger.error(f"获取模板列表异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_stream_events(self) -> Any: + """SSE 实时推送任务生命周期事件""" + q = self.active_task_manager.subscribe() + + async def sse_generator(): + try: + # 首次连接发送当前活跃任务快照 + active = self.active_task_manager.get_active_tasks() + initial_event = json.dumps( + {"event": "initial_state", "data": active}, ensure_ascii=False + ) + yield f"data: {initial_event}\n\n" + + while True: + event_str = await q.get() + yield f"data: {event_str}\n\n" + except asyncio.CancelledError: + pass + finally: + self.active_task_manager.unsubscribe(q) + + return stream_response(sse_generator()) + + async def api_get_plugin_logs(self) -> Any: + """获取群分析专属日志列表""" + try: + limit = ( + int(request.query.get("limit", 100)) + if request and hasattr(request, "query") + else 100 + ) + offset = ( + int(request.query.get("offset", 0)) + if request and hasattr(request, "query") + else 0 + ) + level = ( + request.query.get("level") + if request and hasattr(request, "query") + else None + ) + trace_id = ( + request.query.get("trace_id") + if request and hasattr(request, "query") + else None + ) + tag = ( + request.query.get("tag") + if request and hasattr(request, "query") + else None + ) + search = ( + request.query.get("search") + if request and hasattr(request, "query") + else None + ) + + from ..logging.plugin_log_buffer import global_log_buffer + + items, total = global_log_buffer.query( + limit=limit, + offset=offset, + level=level, + trace_id=trace_id, + tag=tag, + search=search, + ) + tags = [ + {"key": t[0], "label": t[1]} for t in global_log_buffer.TAG_PATTERNS + ] + return json_response( + { + "status": "ok", + "data": { + "items": items, + "total": total, + "available_tags": tags, + }, + } + ) + except Exception as e: + logger.error(f"查询插件日志异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_get_trace_logs(self, trace_id: str) -> Any: + """获取指定 TraceID 的专属执行日志""" + try: + from ..logging.plugin_log_buffer import global_log_buffer + + logs = global_log_buffer.get_trace_logs(trace_id) + return json_response({"status": "ok", "data": logs}) + except Exception as e: + logger.error(f"查询 Trace 日志异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_clear_plugin_logs(self) -> Any: + """清空内存中的插件日志""" + try: + from ..logging.plugin_log_buffer import global_log_buffer + + global_log_buffer.clear() + return json_response({"status": "ok", "message": "Logs cleared"}) + except Exception as e: + logger.error(f"清空插件日志异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_get_config(self) -> Any: + """获取插件当前配置数据与完整 Schema 结构定义""" + try: + cfg_mgr = getattr(self.analysis_service, "config_manager", None) or getattr( + self.report_dispatcher, "config_manager", None + ) + config_dict = {} + if cfg_mgr and hasattr(cfg_mgr, "config"): + raw_cfg = cfg_mgr.config + if hasattr(raw_cfg, "items"): + config_dict = {str(k): v for k, v in raw_cfg.items()} + elif isinstance(raw_cfg, dict): + config_dict = dict(raw_cfg) + + # 读取插件根目录下的 _conf_schema.json + plugin_root = Path(__file__).resolve().parents[3] + schema_file = plugin_root / "_conf_schema.json" + if not schema_file.exists(): + for candidate in [ + Path.cwd() / "_conf_schema.json", + Path(__file__).resolve().parents[2] / "_conf_schema.json", + Path(__file__).resolve().parents[1] / "_conf_schema.json", + ]: + if candidate.exists(): + schema_file = candidate + break + + schema_dict = {} + if schema_file.exists(): + try: + schema_dict = json.loads(schema_file.read_text(encoding="utf-8")) + except Exception as e: + logger.warning(f"读取 _conf_schema.json 失败: {e}") + + return json_response( + { + "status": "ok", + "data": { + "config": config_dict, + "schema": schema_dict, + }, + } + ) + except Exception as e: + logger.error(f"获取配置信息异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_save_config(self) -> Any: + """保存并更新插件配置""" + try: + body = await request.json() if hasattr(request, "json") else {} + new_config = body.get("config") if isinstance(body, dict) else None + if not isinstance(new_config, dict): + return error_response("缺少有效的 config 配置数据", status_code=400) + + cfg_mgr = getattr(self.analysis_service, "config_manager", None) or getattr( + self.report_dispatcher, "config_manager", None + ) + config_obj = getattr(cfg_mgr, "config", None) if cfg_mgr else None + if config_obj is None: + return error_response("配置管理器未初始化", status_code=500) + + plugin_root = Path(__file__).resolve().parents[3] + + # 自动清洗并迁移历史中残存的 Base64 图片或不合规路径为合规的 files/... 物理文件 + def _cleanse_reference_images(val: Any) -> Any: + if isinstance(val, list): + cleaned = [] + for item in val: + if isinstance(item, dict): + cleaned_item = _cleanse_reference_images(item) + if isinstance(cleaned_item, dict): + if ( + "__template_key" not in cleaned_item + or not cleaned_item["__template_key"] + ): + cleaned_item["__template_key"] = "character" + cleaned.append(cleaned_item) + elif isinstance(item, str): + folder = _config_key_to_folder( + "daily_comic.comic_characters.templates.character.reference_images" + ) + if item.startswith("data:image/"): + try: + _, b64 = item.split(",", 1) + file_bytes = base64.b64decode(b64) + ts = int(time.time() * 1000) + filename = f"{ts}_migrated_image.png" + for d in [ + Path.cwd() + / "data" + / "plugin_data" + / PLUGIN_NAME + / "files" + / Path(folder), + plugin_root / "files" / Path(folder), + ]: + d.mkdir(parents=True, exist_ok=True) + (d / filename).write_bytes(file_bytes) + cleaned.append(f"files/{folder}/{filename}") + except Exception: + pass + elif item.startswith("files/"): + expected_prefix = f"files/{folder}/" + if item.startswith(expected_prefix): + cleaned.append(item.strip()) + else: + clean_name = Path(item).name + cleaned.append(f"files/{folder}/{clean_name}") + elif item.strip(): + cleaned.append(item.strip()) + else: + cleaned.append(item) + return cleaned + elif isinstance(val, dict): + return {k: _cleanse_reference_images(v) for k, v in val.items()} + return val + + new_config = _cleanse_reference_images(new_config) + + # 更新 AstrBotConfig 字典 + for k, v in new_config.items(): + config_obj[k] = v + + # 持久化保存 + if hasattr(config_obj, "save_config"): + try: + config_obj.save_config() + except TypeError: + config_obj.save_config() + + logger.info("WebUI 配置中心已更新并保存插件配置。") + return json_response( + { + "status": "ok", + "message": "配置已成功保存并持久化生效", + "data": dict(config_obj), + } + ) + except Exception as e: + logger.error(f"保存配置异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_upload_config_file(self) -> Any: + """上传插件配置所需的文件/参考图,并存入合规的 files/{folder}/ 物理路径""" + try: + body: dict[str, Any] = {} + if hasattr(request, "json"): + try: + parsed_body = await request.json(default={}) + if isinstance(parsed_body, dict): + body = parsed_body + except Exception: + body = {} + + config_key = "" + if ( + hasattr(request, "query") + and request.query + and request.query.get("config_key") + ): + config_key = request.query.get("config_key") + elif body.get("config_key"): + config_key = str(body.get("config_key")) + + if not config_key or config_key == "reference_images": + config_key = ( + "daily_comic.comic_characters.templates.character.reference_images" + ) + + folder = _config_key_to_folder(config_key) + + # 优先使用 AstrBot 官方的标准 plugin_data 目录,与 AstrBot 原生保持 100% 一致 + target_dirs: list[Path] = [] + try: + from astrbot.api.star import StarTools + + data_dir = StarTools.get_data_dir(PLUGIN_NAME) + if data_dir: + target_dirs.append(data_dir / "files" / Path(folder)) + except Exception: + pass + + target_dirs.append( + Path.cwd() + / "data" + / "plugin_data" + / PLUGIN_NAME + / "files" + / Path(folder) + ) + plugin_root = Path(__file__).resolve().parents[3] + target_dirs.append(plugin_root / "files" / Path(folder)) + + for d in target_dirs: + d.mkdir(parents=True, exist_ok=True) + + saved_paths: list[str] = [] + + # 1. 尝试从 multipart 上传中读取 + if hasattr(request, "files"): + try: + uploaded_files = await request.files() + for key in uploaded_files.keys(): + for f in uploaded_files.getlist(key): + orig_name = ( + getattr(f, "filename", "") or "uploaded_image.png" + ) + clean_name = re.sub(r"[^\w\.\-]", "_", orig_name) + ts = int(time.time() * 1000) + final_name = f"{ts}_{clean_name}" + file_bytes = await f.read() + if file_bytes: + for d in target_dirs: + (d / final_name).write_bytes(file_bytes) + saved_paths.append(f"files/{folder}/{final_name}") + except Exception: + pass + + # 2. 尝试从 JSON (包含 Base64 或 Data URL) 中解析 + if not saved_paths and body: + raw_data = ( + body.get("file_data") or body.get("data") or body.get("base64") + ) + file_name = body.get("filename") or "upload.png" + clean_name = re.sub(r"[^\w\.\-]", "_", file_name) + if raw_data and isinstance(raw_data, str): + if raw_data.startswith("data:"): + _, b64 = raw_data.split(",", 1) + else: + b64 = raw_data + file_bytes = base64.b64decode(b64) + ts = int(time.time() * 1000) + final_name = f"{ts}_{clean_name}" + for d in target_dirs: + (d / final_name).write_bytes(file_bytes) + saved_paths.append(f"files/{folder}/{final_name}") + + if not saved_paths: + return error_response("未检测到有效的文件数据", status_code=400) + + return json_response( + { + "status": "ok", + "data": { + "path": saved_paths[0], + "paths": saved_paths, + "folder": folder, + }, + } + ) + except Exception as e: + logger.error(f"上传配置文件异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) + + async def api_get_config_file_content(self) -> Any: + """获取配置中的文件(如角色参考图)内容用于 WebUI 在线缩略图展示""" + try: + rel_path = "" + if hasattr(request, "query") and request.query: + rel_path = request.query.get("path", "").strip() + + if not rel_path and hasattr(request, "json"): + try: + body = await request.json(default={}) + if isinstance(body, dict): + rel_path = str(body.get("path") or "").strip() + except Exception: + pass + + if not rel_path: + return error_response("Missing path parameter", status_code=400) + + # 搜索候选目录 + search_roots: list[Path] = [] + try: + from astrbot.api.star import StarTools + + data_dir = StarTools.get_data_dir(PLUGIN_NAME) + if data_dir: + search_roots.append(data_dir) + except Exception: + pass + + search_roots.append(Path.cwd() / "data" / "plugin_data" / PLUGIN_NAME) + plugin_root = Path(__file__).resolve().parents[3] + search_roots.append(plugin_root) + search_roots.append(Path.cwd() / "data" / "plugins" / PLUGIN_NAME) + + target_file: Path | None = None + clean_rel = rel_path.lstrip("/\\") + for root in search_roots: + cand = (root / clean_rel).resolve() + if cand.is_file() and cand.exists(): + target_file = cand + break + + if not target_file: + # 尝试纯文件名在 files/ 下模糊搜索 + filename = Path(clean_rel).name + for root in search_roots: + files_dir = root / "files" + if files_dir.exists(): + for match in files_dir.rglob(filename): + if match.is_file(): + target_file = match + break + if target_file: + break + + if not target_file or not target_file.is_file(): + return error_response(f"File {rel_path} not found", status_code=404) + + ext = target_file.suffix.lower().lstrip(".") + mime_type = f"image/{'jpeg' if ext in ('jpg', 'jpeg') else ext}" + with open(target_file, "rb") as f: + b64_content = base64.b64encode(f.read()).decode("utf-8") + + return json_response( + { + "status": "ok", + "data": { + "path": rel_path, + "filename": target_file.name, + "data_url": f"data:{mime_type};base64,{b64_content}", + }, + } + ) + except Exception as e: + logger.error(f"获取配置文件内容异常: {e}", exc_info=True) + return error_response(str(e), status_code=500) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/shared/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/shared/__init__.py new file mode 100644 index 0000000..763c6ef --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/shared/__init__.py @@ -0,0 +1,14 @@ +""" +共享模块 - 通用工具和常量 +""" + +from .constants import ContentType, Platform, ReportFormat, TaskStatus +from .trace_context import TraceContext + +__all__ = [ + "TraceContext", + "Platform", + "TaskStatus", + "ContentType", + "ReportFormat", +] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/shared/constants.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/shared/constants.py new file mode 100644 index 0000000..4b7249e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/shared/constants.py @@ -0,0 +1,121 @@ +""" +常量 - 插件中使用的共享常量 +""" + +from enum import Enum + + +class Platform(str, Enum): + """ + 支持的聊天平台枚举 + + 定义了插件适配的所有基础通讯平台标识。 + """ + + ONEBOT = "onebot" + AIOCQHTTP = "aiocqhttp" + TELEGRAM = "telegram" + DISCORD = "discord" + SLACK = "slack" + LARK = "lark" + + +class TaskStatus(str, Enum): + """ + 分析任务执行状态枚举 + + 用于在异步处理流水线中标记分析任务的生命阶段。 + """ + + PENDING = "pending" + RUNNING = "running" + COMPLETED = "completed" + FAILED = "failed" + CANCELLED = "cancelled" + + +class ContentType(str, Enum): + """ + 统一消息内容类型枚举 + + 将不同平台(OneBot, Discord 等)的消息片段抽象为统一的类型体系。 + """ + + TEXT = "text" + IMAGE = "image" + EMOJI = "emoji" + STICKER = "sticker" + FILE = "file" + AUDIO = "audio" + VIDEO = "video" + REPLY = "reply" + AT = "at" + UNKNOWN = "unknown" + + +class ReportFormat(str, Enum): + """ + 分析报告导出格式枚举 + + 控制最终呈现给用户的报告呈现形式。 + """ + + TEXT = "text" + MARKDOWN = "markdown" + IMAGE = "image" + HTML = "html" + + +# 插件元数据 +PLUGIN_NAME = "astrbot_plugin_qq_group_daily_analysis" +PLUGIN_VERSION = "2.0.0" + +# 平台标识符 +SUPPORTED_PLATFORMS = [ + Platform.ONEBOT.value, + Platform.TELEGRAM.value, + Platform.DISCORD.value, +] + +# 分析默认值 +DEFAULT_MAX_TOPICS = 5 +DEFAULT_MAX_USER_TITLES = 10 +DEFAULT_MAX_GOLDEN_QUOTES = 5 +DEFAULT_MIN_MESSAGES = 50 +DEFAULT_MAX_TOKENS = 2000 + +# 时间段 +HOUR_RANGES = { + "morning": (6, 12), + "afternoon": (12, 18), + "evening": (18, 24), + "night": (0, 6), +} + +# 错误代码 +ERROR_INSUFFICIENT_DATA = "INSUFFICIENT_DATA" +ERROR_LLM_FAILED = "LLM_FAILED" +ERROR_PLATFORM_ERROR = "PLATFORM_ERROR" +ERROR_CONFIG_ERROR = "CONFIG_ERROR" +ERROR_TIMEOUT = "TIMEOUT" + +# 缓存 TTL(秒) +CACHE_TTL_SHORT = 60 # 1 分钟 +CACHE_TTL_MEDIUM = 300 # 5 分钟 +CACHE_TTL_LONG = 3600 # 1 小时 +CACHE_TTL_DAY = 86400 # 24 小时 + +# 速率限制默认值 +RATE_LIMIT_LLM_CALLS = 10 # 每分钟调用次数 +RATE_LIMIT_API_CALLS = 60 # 每分钟调用次数 +RATE_LIMIT_BURST = 5 # 突发大小 + +# 重试默认值 +RETRY_MAX_ATTEMPTS = 3 +RETRY_BASE_DELAY = 1.0 +RETRY_MAX_DELAY = 30.0 + +# 文件路径 +HISTORY_DIR = "history" +CACHE_DIR = "cache" +TEMP_DIR = "temp" diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/shared/trace_context.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/shared/trace_context.py new file mode 100644 index 0000000..07915e4 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/shared/trace_context.py @@ -0,0 +1,439 @@ +""" +追踪上下文 - 全链路请求追踪、Span 耗时打点与 dsh-context 风格指标审计 +""" + +from __future__ import annotations + +import functools +import logging +import re +import time +import uuid +from collections.abc import Generator +from contextlib import contextmanager +from contextvars import ContextVar, Token +from dataclasses import dataclass, field +from datetime import datetime +from typing import Any + +# Trace ID 中群名的最大长度(平衡可读性和日志宽度) +_MAX_GROUP_NAME_LEN = 10 + +# 用于匹配报告 Caption 中去重 Token 的正则模式 +REPORT_CAPTION_PATTERN = re.compile(r"\| (\d{2}-\d{2} \d{2}:\d{2}:\d{2})") + +# 当前追踪的上下文变量 +_current_trace: ContextVar[TraceContext | None] = ContextVar( + "current_trace", default=None +) + +# 全局持有的 Trace 仓储引用(用于链路自动持久化) +_global_trace_store: Any | None = None +_global_active_task_manager: Any | None = None +_active_traces: dict[str, Any] = {} + + +@dataclass +class TraceContext: + """ + 核心组件:全链路追踪上下文 (Tracing Context) + + 集成 TraceId 传递、Span 级细粒度耗时打点、dsh-context 风格的上下文演进与 Token 审计。 + """ + + trace_id: str = field(default_factory=lambda: str(uuid.uuid4())[:8]) + group_id: str = "" + group_name: str = "" + platform: str = "" + operation: str = "" + trigger_type: str = "manual" + status: str = "running" + current_stage: str = "" + started_at: float = field(default_factory=time.time) + completed_at: float | None = None + duration_ms: float | None = None + + # 错误归因 + error_stage: str | None = None + error_message: str | None = None + stack_trace: str | None = None + + # 扩展元数据 + metadata: dict[str, Any] = field(default_factory=dict) + + # 细粒度 Span 列表 + _spans: list[dict[str, Any]] = field(default_factory=list, init=False) + + # dsh-context 上下文演进指标 + _context_metrics: dict[str, Any] | None = field(default=None, init=False) + + # Token 消耗与成本审计 + _token_usage: dict[str, Any] = field( + default_factory=lambda: { + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0, + "estimated_cost": 0.0, + "per_analyzer": {}, + }, + init=False, + ) + + # 传统锚点兼容 + _checkpoints: dict[str, datetime] = field(default_factory=dict, init=False) + _token: Token | None = field(default=None, init=False, repr=False) + + @classmethod + def set_global_store(cls, store: Any) -> None: + """设置全局持久化仓储实例""" + global _global_trace_store + _global_trace_store = store + + @classmethod + def set_active_task_manager(cls, manager: Any) -> None: + """设置全局活跃任务管理器引用""" + global _global_active_task_manager + _global_active_task_manager = manager + + @classmethod + def get_active_trace(cls, trace_id: str) -> Any | None: + """根据 trace_id 获取内存中活跃运行的 TraceContext 实例""" + return _active_traces.get(trace_id) + + @property + def start_time(self) -> datetime: + """兼容旧版 start_time 属性""" + return datetime.fromtimestamp(self.started_at) + + def checkpoint(self, name: str) -> None: + """在当前时间轴上设置命名锚点(兼容旧接口)""" + self._checkpoints[name] = datetime.now() + + def elapsed_ms(self, from_checkpoint: str | None = None) -> float: + """计算从开始或指定锚点到当前时刻经过的毫秒数""" + if from_checkpoint and from_checkpoint in self._checkpoints: + delta = datetime.now() - self._checkpoints[from_checkpoint] + return delta.total_seconds() * 1000 + return (time.time() - self.started_at) * 1000 + + @contextmanager + def span( + self, stage_name: str, payload: dict[str, Any] | None = None + ) -> Generator[dict[str, Any]]: + """ + 创建一个细粒度 Span 上下文,自动记录该步骤耗时与执行状态。 + + Args: + stage_name: 阶段名称,如 'FETCH_MESSAGES', 'LLM_TOPICS', 'RENDER_REPORT' + payload: 随 Span 记录的参数或快照字典 + """ + self.current_stage = stage_name + _active_traces[self.trace_id] = self + if _global_active_task_manager is not None: + try: + _global_active_task_manager.update_stage_sync(self.trace_id, stage_name) + except Exception: + pass + + start_ts = time.time() + span_id = f"{self.trace_id}_{stage_name}_{len(self._spans) + 1}" + span_record: dict[str, Any] = { + "span_id": span_id, + "trace_id": self.trace_id, + "stage_name": stage_name, + "status": "running", + "started_at": start_ts, + "duration_ms": None, + "payload": payload or {}, + } + self._spans.append(span_record) + + try: + yield span_record + if span_record.get("status") in ("running", None): + span_record["status"] = "success" + except Exception as exc: + span_record["status"] = "failed" + span_record.setdefault("payload", {})["error"] = str(exc) + raise + finally: + span_record["duration_ms"] = round((time.time() - start_ts) * 1000, 2) + if self.status != "running" and _global_trace_store is not None: + try: + _global_trace_store.save_trace(self.to_dict()) + except Exception: + pass + + def set_context_metrics( + self, + raw_message_count: int, + cleaned_message_count: int, + incremental_batches: int = 0, + window_size: int = 0, + ) -> None: + """ + 记录上下文演进与清洗漏斗指标(dsh-context 核心)。 + + Args: + raw_message_count: 原始拉取消息数 + cleaned_message_count: 规则清洗后保留的消息数 + incremental_batches: 增量处理分批数 + window_size: 采样窗口大小 + """ + compression_ratio = ( + round(cleaned_message_count / max(1, raw_message_count), 4) + if raw_message_count > 0 + else 1.0 + ) + self._context_metrics = { + "raw_message_count": raw_message_count, + "cleaned_message_count": cleaned_message_count, + "compression_ratio": compression_ratio, + "incremental_batches": incremental_batches, + "window_size": window_size, + } + + def add_token_usage( + self, + prompt_tokens: int, + completion_tokens: int, + analyzer_name: str = "", + cost_est: float = 0.0, + ) -> None: + """ + 累加 Token 消耗与成本。 + + Args: + prompt_tokens: 输入 Token + completion_tokens: 输出 Token + analyzer_name: 具体的 Analyzer 名称 (如 'topics', 'user_titles', 'comics') + cost_est: 估算费用 + """ + total = prompt_tokens + completion_tokens + self._token_usage["prompt_tokens"] += prompt_tokens + self._token_usage["completion_tokens"] += completion_tokens + self._token_usage["total_tokens"] += total + self._token_usage["estimated_cost"] += cost_est + + if analyzer_name: + cur = self._token_usage["per_analyzer"].get( + analyzer_name, + { + "prompt_tokens": 0, + "completion_tokens": 0, + "total_tokens": 0, + }, + ) + cur["prompt_tokens"] += prompt_tokens + cur["completion_tokens"] += completion_tokens + cur["total_tokens"] += total + self._token_usage["per_analyzer"][analyzer_name] = cur + + def finish( + self, + status: str = "succeeded", + error_stage: str | None = None, + error_message: str | None = None, + stack_trace: str | None = None, + ) -> None: + """ + 标记任务完成,计算总耗时并自动持久化到 SQLite + """ + if status == "succeeded": + if any(s.get("status") == "failed" for s in self._spans): + status = "failed" + elif any( + s.get("status") == "warning" + or s.get("payload", {}).get("success") is False + or bool(s.get("payload", {}).get("warning")) + or bool(s.get("payload", {}).get("subtask_errors")) + for s in self._spans + ) or self.metadata.get("has_warnings"): + status = "warning" + + self.status = status + self.completed_at = time.time() + self.duration_ms = round((self.completed_at - self.started_at) * 1000, 2) + if error_stage: + self.error_stage = error_stage + if error_message: + self.error_message = error_message + if stack_trace: + self.stack_trace = stack_trace + + # 确保所有未完成的 Span 在 Trace 结束时被正确收尾,避免前端面板出现永久运行状态 + for s in self._spans: + if s.get("status") == "running": + s["status"] = "success" + if s.get("started_at") and s.get("duration_ms") is None: + s["duration_ms"] = round( + (self.completed_at - s["started_at"]) * 1000, 2 + ) + + _active_traces.pop(self.trace_id, None) + + # 自动落盘 + if _global_trace_store is not None: + try: + _global_trace_store.save_trace(self.to_dict()) + except Exception as e: + from ..utils.logger import logger + + logger.warning(f"Trace 持久化保存失败: {e}") + + def to_dict(self) -> dict[str, Any]: + """将完整链路快照序列化为字典""" + return { + "trace_id": self.trace_id, + "group_id": self.group_id, + "group_name": self.group_name, + "platform": self.platform, + "operation": self.operation, + "trigger_type": self.trigger_type, + "status": self.status, + "started_at": self.started_at, + "completed_at": self.completed_at, + "duration_ms": ( + self.duration_ms + if self.duration_ms is not None + else (time.time() - self.started_at) * 1000 + ), + "error_stage": self.error_stage, + "error_message": self.error_message, + "stack_trace": self.stack_trace, + "extra": self.metadata, + "spans": list(self._spans), + "context_metrics": self._context_metrics, + "token_usage": self._token_usage, + "checkpoints": {k: v.isoformat() for k, v in self._checkpoints.items()}, + } + + def __enter__(self) -> TraceContext: + self._token = _current_trace.set(self) + _active_traces[self.trace_id] = self + return self + + def __exit__(self, exc_type, exc_val, exc_tb) -> None: + if exc_type is not None and self.status == "running": + self.finish( + status="failed", + error_stage=self._spans[-1]["stage_name"] + if self._spans + else "PIPELINE", + error_message=str(exc_val), + ) + elif self.status == "running": + self.finish(status="succeeded") + + if self._token: + _current_trace.reset(self._token) + self._token = None + + @classmethod + def current(cls) -> TraceContext | None: + return _current_trace.get() + + @classmethod + def get_or_create( + cls, + trace_id: str = "", + group_id: str = "", + group_name: str = "", + platform: str = "", + operation: str = "", + trigger_type: str = "manual", + auto_bind: bool = False, + ) -> TraceContext: + current = cls.current() + if current: + return current + + new_ctx = cls( + trace_id=trace_id or str(uuid.uuid4())[:8], + group_id=group_id, + group_name=group_name, + platform=platform, + operation=operation, + trigger_type=trigger_type, + ) + if auto_bind: + new_ctx._token = _current_trace.set(new_ctx) + _active_traces[new_ctx.trace_id] = new_ctx + return new_ctx + + @staticmethod + def generate(prefix: str = "", group_name: str = "") -> str: + timestamp = datetime.now().strftime("%H%M") + parts: list[str] = [] + if prefix: + parts.append(prefix) + if group_name: + safe_name = re.sub(r'[\s\n\r\t/\\:*?"<>|\[\]{}]', "", group_name) + safe_name = safe_name[:_MAX_GROUP_NAME_LEN] + if safe_name: + parts.append(safe_name) + parts.append(timestamp) + return "_".join(parts) + + @staticmethod + def make_report_caption() -> str: + ts = datetime.now().strftime("%m-%d %H:%M:%S") + return f"📊 每日群聊分析报告已生成 | {ts}" + + @classmethod + def set( + cls, + trace_id: str, + group_id: str = "", + group_name: str = "", + platform: str = "", + trigger_type: str = "manual", + ) -> TraceContext: + ctx = cls( + trace_id=trace_id, + group_id=str(group_id), + group_name=group_name, + platform=platform, + trigger_type=trigger_type, + ) + ctx._token = _current_trace.set(ctx) + _active_traces[ctx.trace_id] = ctx + return ctx + + @classmethod + def get(cls) -> str: + return get_trace_id() + + +class TraceLogFilter(logging.Filter): + def filter(self, record: logging.LogRecord) -> bool: + record.trace_id = get_trace_id() + return True + + +def get_trace_id() -> str: + trace = TraceContext.current() + if trace: + return trace.trace_id + return str(uuid.uuid4())[:8] + + +def with_trace( + group_id: str = "", + platform: str = "", + operation: str = "", +): + def decorator(func): + @functools.wraps(func) + async def wrapper(*args, **kwargs): + op_name = operation or func.__name__ + with TraceContext( + group_id=group_id, + platform=platform, + operation=op_name, + ): + return await func(*args, **kwargs) + + return wrapper + + return decorator diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/utils/__init__.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/utils/__init__.py new file mode 100644 index 0000000..4e06a57 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/utils/__init__.py @@ -0,0 +1,6 @@ +""" +工具函数模块 +包含通用工具函数 +""" + +__all__ = [] diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/utils/logger.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/utils/logger.py new file mode 100644 index 0000000..086c049 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/utils/logger.py @@ -0,0 +1,77 @@ +from nonebot.log import logger as astrbot_logger + +from ..infrastructure.logging.plugin_log_buffer import global_log_buffer +from ..shared.trace_context import TraceContext + + +class PluginLogger: + """ + 日志代理类:插件级统一日志装饰器与记录器 + + 自动向所有通过该实例输出的日志信息前缀添加 `[群分析插件]` 标签, + 同时将日志实时推入插件内存队列,支持 WebUI 专属日志观测与 SSE 实时推流。 + """ + + def __init__(self, prefix: str = "[群分析插件]"): + self.prefix = prefix + + def _format_msg(self, msg: str) -> tuple[str, str | None]: + trace_id = TraceContext.get() + if trace_id: + return f"[{trace_id}] {self.prefix} {msg}", trace_id + return f"{self.prefix} {msg}", None + + def _record( + self, + level: str, + formatted_msg: str, + trace_id: str | None, + args: tuple = (), + ) -> None: + try: + rendered = (formatted_msg % args) if args else formatted_msg + except Exception: + rendered = formatted_msg + try: + global_log_buffer.record_log(level=level, msg=rendered, trace_id=trace_id) + except Exception: + pass + + @staticmethod + def _render(formatted_msg: str, args: tuple) -> str: + if args: + try: + return formatted_msg % args + except Exception: + pass + return formatted_msg + + def _log(self, level: str, msg: str, args: tuple, kwargs: dict, method) -> None: + formatted_msg, trace_id = self._format_msg(msg) + self._record(level, formatted_msg, trace_id, args) + rendered = self._render(formatted_msg, args) + kwargs["stacklevel"] = kwargs.get("stacklevel", 1) + 1 + # 用参数化模板,避免消息里的 {} 被 loguru 误当作 format 占位符 + method("{}", rendered, **kwargs) + + def info(self, msg: str, *args, **kwargs): + self._log("INFO", msg, args, kwargs, astrbot_logger.info) + + def error(self, msg: str, *args, **kwargs): + self._log("ERROR", msg, args, kwargs, astrbot_logger.error) + + def warning(self, msg: str, *args, **kwargs): + self._log("WARNING", msg, args, kwargs, astrbot_logger.warning) + + def debug(self, msg: str, *args, **kwargs): + self._log("DEBUG", msg, args, kwargs, astrbot_logger.debug) + + def critical(self, msg: str, *args, **kwargs): + self._log("CRITICAL", msg, args, kwargs, astrbot_logger.critical) + + def exception(self, msg: str, *args, **kwargs): + self._log("ERROR", msg, args, kwargs, astrbot_logger.exception) + + +# 导出带前缀与缓冲支持的插件统一 logger +logger = PluginLogger() diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/utils/paths.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/utils/paths.py new file mode 100644 index 0000000..a7f8a8d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/utils/paths.py @@ -0,0 +1,28 @@ +"""AstrBot 无关的数据目录解析封装。 + +NoneBot 版插件用自身在项目中的位置推导数据目录, +默认放在 hexi/data/group_daily_analysis 下,可用环境变量 +HEXI_GROUP_DAILY_DATA_DIR 覆盖。 +""" +from __future__ import annotations + +import os +from pathlib import Path + +_PLUGIN_NAME = "group_daily_analysis" + + +def get_plugin_root() -> Path: + return Path(__file__).resolve().parents[2] + + +def get_data_dir(plugin_name: str | None = None) -> Path: + override = os.environ.get("HEXI_GROUP_DAILY_DATA_DIR") + if override: + root = Path(override) + else: + # hexi/plugins//core/utils/paths.py -> hexi/ + hexi_root = Path(__file__).resolve().parents[4] + root = hexi_root / "data" / "group_daily_analysis" + root.mkdir(parents=True, exist_ok=True) + return root diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/core/utils/resilience.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/utils/resilience.py new file mode 100644 index 0000000..e417e1b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/core/utils/resilience.py @@ -0,0 +1,179 @@ +import asyncio +import time + +from .logger import logger + + +class CircuitBreaker: + """ + 韧性设计:熔断器 (Circuit Breaker) + + 用于监控外部服务(如 LLM API)的调用状态。当错误率达到阈值时,自动开启熔断, + 拦截对故障服务的进一步请求,保护系统不被连锁故障拖累,直到服务窗口恢复。 + + States: + CLOSED: 正常工作状态,允许请求 + OPEN: 熔断状态,拒绝请求 + HALF_OPEN: 尝试恢复状态,允许少量测试请求 + """ + + STATE_CLOSED = "CLOSED" + STATE_OPEN = "OPEN" + STATE_HALF_OPEN = "HALF_OPEN" + + def __init__( + self, + failure_threshold: int = 5, + recovery_timeout: int = 60, + name: str = "default", + ): + """ + 初始化熔断器。 + + Args: + failure_threshold (int): 连续失败触发熔断的次数上限 + recovery_timeout (int): 熔断开启后尝试恢复之前的冷却时间(秒) + name (str): 熔断器标识符(用于日志区分) + """ + self.name = name + self.failure_threshold = failure_threshold + self.recovery_timeout = recovery_timeout + + self.failure_count = 0 + self.state = self.STATE_CLOSED + self.last_failure_time = 0.0 + + def record_failure(self) -> None: + """记录一次调用失败,并根据阈值决定是否切换到 OPEN 状态。""" + self.failure_count += 1 + if ( + self.state == self.STATE_CLOSED + and self.failure_count >= self.failure_threshold + ): + self._open_circuit() + elif self.state == self.STATE_HALF_OPEN: + # 半开状态下任何一次失败都将立即导致熔断重开 + self._open_circuit() + + def record_success(self) -> None: + """记录一次调用成功,并尝试重置或关闭熔断器。""" + if self.state == self.STATE_HALF_OPEN: + self._close_circuit() + elif self.state == self.STATE_CLOSED: + # 正常状态下的成功重置累积计数值 + self.failure_count = 0 + + def allow_request(self) -> bool: + """ + 判断是否允许本次服务请求。 + + Returns: + bool: True 为允许,False 为拦截 + """ + if self.state == self.STATE_OPEN: + # 检查冷却时间是否已过,过则进入试探性的半开状态 + if time.monotonic() - self.last_failure_time > self.recovery_timeout: + self._half_open_circuit() + return True + return False + return True + + def _open_circuit(self) -> None: + """动作:开启熔断""" + self.state = self.STATE_OPEN + self.last_failure_time = time.monotonic() + logger.warning( + f"熔断器 CircuitBreaker[{self.name}] 已激活!将拦截请求 {self.recovery_timeout} 秒。" + ) + + def _close_circuit(self) -> None: + """动作:关闭熔断,恢复常态""" + self.state = self.STATE_CLOSED + self.failure_count = 0 + logger.info(f"熔断器 CircuitBreaker[{self.name}] 已恢复至关闭 (CLOSED) 状态。") + + def _half_open_circuit(self) -> None: + """动作:进入半开状态""" + self.state = self.STATE_HALF_OPEN + logger.info( + f"熔断器 CircuitBreaker[{self.name}] 进入半开 (HALF_OPEN) 测试模式。" + ) + + +class GlobalRateLimiter: + """ + 韧性设计:全局并发动态限流器 + + 基于单例模式管理 asyncio.Semaphore,确保在插件内的异步任务 + 不会超过设定的最大并发限制(如保护 LLM 账单或避免 API 拥塞)。 + """ + + _instance: "GlobalRateLimiter | None" = None + _semaphore: asyncio.Semaphore | None = None + _max_concurrency: int | None = None + + def __new__(cls): + if cls._instance is None: + cls._instance = super().__new__(cls) + return cls._instance + + @classmethod + def get_instance(cls, max_concurrency: int | None = None) -> "GlobalRateLimiter": + """ + 获取或创建限流器单例。 + + Args: + max_concurrency (int, optional): 允许的最大并发数。如果提供且与当前不同,则重置信号量。 + + Returns: + GlobalRateLimiter: 唯一实例 + """ + instance = cls() + if max_concurrency is not None: + instance.reconfigure(max_concurrency) + elif cls._semaphore is None: + # 默认兜底 + cls._semaphore = asyncio.Semaphore(4) + cls._max_concurrency = 4 + return instance + + def reconfigure(self, max_concurrency: int): + """重新配置并发上限。注意:这会替换信号量对象。 + + Args: + max_concurrency: 新的全局 LLM 并发上限。 + """ + max_concurrency = max(1, int(max_concurrency)) + if self.__class__._semaphore is None or ( + self.__class__._max_concurrency != max_concurrency + ): + old_val = self.__class__._max_concurrency or "None" + logger.info( + f"GlobalRateLimiter 重新配置并发上限:{old_val} -> {max_concurrency}" + ) + self.__class__._semaphore = asyncio.Semaphore(max_concurrency) + self.__class__._max_concurrency = max_concurrency + + @property + def semaphore(self) -> asyncio.Semaphore: + """返回核心的异步信号量对象。""" + if self._semaphore is None: + self.__class__._semaphore = asyncio.Semaphore(4) + self.__class__._max_concurrency = 4 + assert self._semaphore is not None + return self._semaphore + + @property + def max_concurrency(self) -> int: + """返回当前配置的全局并发上限。""" + if self.__class__._max_concurrency is None: + return 4 + return self.__class__._max_concurrency + + @property + def available_slots(self) -> int | None: + """返回当前可用槽位数量,仅用于诊断日志。""" + semaphore = self.__class__._semaphore + if semaphore is None: + return None + return getattr(semaphore, "_value", None) diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/kv_store.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/kv_store.py new file mode 100644 index 0000000..d189872 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/kv_store.py @@ -0,0 +1,59 @@ +"""NoneBot 版本地 KV 存储,用于替代 AstrBot 的 put_kv_data / get_kv_data。 + +持久化到一个 JSON 文件,提供 async get/put/delete 语义。 +""" + +from __future__ import annotations + +import asyncio +import json +from pathlib import Path +from typing import Any + + +class AsyncKVStore: + """一个最小可用的异步 KV 存储(JSON 文件)。""" + + def __init__(self, path: Path): + self.path = Path(path) + self.path.parent.mkdir(parents=True, exist_ok=True) + self._lock = asyncio.Lock() + self._data: dict[str, Any] = {} + self._loaded = False + + async def _ensure_loaded(self): + if self._loaded: + return + try: + self._data = json.loads(self.path.read_text(encoding="utf-8")) + except (OSError, json.JSONDecodeError): + self._data = {} + self._loaded = True + + async def _persist(self): + await self._ensure_loaded() + self.path.write_text( + json.dumps(self._data, ensure_ascii=False, indent=2, default=str), + encoding="utf-8", + ) + + async def put_kv_data(self, key: str, value: Any) -> None: + """写入键值。value 为 None 时表示删除。""" + async with self._lock: + await self._ensure_loaded() + if value is None: + self._data.pop(key, None) + else: + self._data[key] = value + await self._persist() + + async def get_kv_data(self, key: str, default: Any = None) -> Any: + """读取键值。""" + async with self._lock: + await self._ensure_loaded() + return self._data.get(key, default) + + async def clear(self) -> None: + async with self._lock: + self._data = {} + await self._persist() diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/metadata.yaml b/hexi/plugins/nonebot_plugin_group_daily_analysis/metadata.yaml new file mode 100644 index 0000000..66a5dd4 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/metadata.yaml @@ -0,0 +1,13 @@ +name: astrbot_plugin_qq_group_daily_analysis # 这是你的插件的唯一识别名。 +display_name: 群分析总结插件 # 插件的显示名称 +desc: "群日常分析总结插件 - 支持 OneBot (NapCat, LLOneBot, Snowluma)、QQ 官方机器人、Telegram、Discord;生成精美的群聊分析报告,支持话题分析、用户形象、群聊圣经等功能" # 插件简短描述 +version: v5.0.14 # 插件版本号。格式:v1.1.1 或者 v1.1 +author: SXP-Simon # 作者 +astrbot_version: ">=4.24.1" # 插件 WebUI 自定义页面 (Plugin Pages) 能力在 AstrBot v4.24.1 首次正式引入 +support_platforms: + - aiocqhttp + - discord + - telegram + - qq_official + - qq_official_webhook +repo: https://github.com/SXP-Simon/astrbot_plugin_qq_group_daily_analysis # 插件的仓库地址 diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/renderer.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/renderer.py new file mode 100644 index 0000000..85a1246 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/renderer.py @@ -0,0 +1,62 @@ +"""Playwright 渲染器:将报告 HTML 渲染为图片字节。 + +签名对应原插件 html_render(html, data, return_url, options)。 +""" + +from __future__ import annotations + +from typing import Any + +from .core.utils.logger import logger + +_SCALE_MAP = { + "ultra": 3, + "high": 2, + "normal": 1, + "low": 0.5, +} + + +async def html_render( + html_content: str, + data: dict | None = None, + return_url: bool = False, + options: dict | None = None, +) -> bytes | str: + """渲染 HTML 为图片。返回 bytes(PNG/JPEG)。""" + options = options or {} + viewport_width = int(options.get("viewport_width", 1440)) + viewport_height = int(options.get("viewport_height", 900)) + full_page = bool(options.get("full_page", True)) + img_type = str(options.get("type", "png")).lower() + if img_type in ("jpg", "jpeg"): + img_type = "jpeg" + quality = int(options.get("quality", 90)) + timeout = int(options.get("timeout", 30000)) + scale_level = str(options.get("device_scale_factor_level", "normal")).lower() + scale = _SCALE_MAP.get(scale_level, 1) + + try: + from playwright.async_api import async_playwright + except Exception as e: + logger.error(f"[T2I] 无法导入 playwright: {e}") + return "" + + try: + async with async_playwright() as p: + browser = await p.chromium.launch() + page = await browser.new_page( + viewport={"width": viewport_width, "height": viewport_height}, + device_scale_factor=scale, + ) + await page.set_content(html_content, wait_until="networkidle", timeout=timeout) + shot = await page.screenshot( + type=img_type, + quality=quality if img_type == "jpeg" else None, + full_page=full_page, + ) + await browser.close() + return shot + except Exception as e: + logger.error(f"[T2I] Playwright 渲染失败: {e}", exc_info=True) + return "" diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/service.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/service.py new file mode 100644 index 0000000..2bf59e5 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/service.py @@ -0,0 +1,125 @@ +"""NoneBot 版服务装配与执行入口。""" + +from __future__ import annotations + +from typing import Any + +from .adapter import OneBotAdapter +from .bot_manager import BotManager +from .config import ConfigDict, load_config +from .core.application.services.analysis_application_service import ( + AnalysisApplicationService, +) +from .core.domain.services.analysis_domain_service import AnalysisDomainService +from .core.domain.services.incremental_merge_service import IncrementalMergeService +from .core.domain.services.statistics_service import StatisticsService +from .core.infrastructure.analysis.llm_analyzer import LLMAnalyzer +from .core.infrastructure.config.config_manager import ConfigManager +from .core.infrastructure.persistence.checkpoint_store import CheckpointStore +from .core.infrastructure.persistence.history_manager import HistoryManager +from .core.infrastructure.persistence.incremental_store import IncrementalStore +from .core.infrastructure.reporting.generators import ReportGenerator +from .core.infrastructure.visualization.activity_charts import ActivityVisualizer +from .core.shared.constants import PLUGIN_NAME +from .core.shared.trace_context import TraceContext +from .core.utils.logger import logger +from .core.utils.paths import get_data_dir +from .kv_store import AsyncKVStore +from .renderer import html_render + +_services: dict[str, Any] | None = None + + +class _DummyContext: + """替代 AstrBot Context;本插件的 LLM 层不再使用它。""" + + def get_provider_by_id(self, **kwargs): + return None + + def get_all_providers(self): + return [] + + async def get_current_chat_provider_id(self, **kwargs): + return None + + async def llm_generate(self, **kwargs): + raise NotImplementedError + + +def _build_services() -> dict[str, Any]: + global _services + if _services is not None: + return _services + + cfg = load_config() + config_manager = ConfigManager(cfg) + data_dir = get_data_dir(PLUGIN_NAME) + data_dir.mkdir(parents=True, exist_ok=True) + + kv_store = AsyncKVStore(data_dir / "kv_store.json") + + activity_visualizer = ActivityVisualizer() + statistics_service = StatisticsService(activity_visualizer) + analysis_domain_service = AnalysisDomainService() + incremental_merge_service = IncrementalMergeService() + + report_generator = ReportGenerator(config_manager, data_dir) + llm_analyzer = LLMAnalyzer(_DummyContext(), config_manager) + + history_manager = HistoryManager(kv_store) + incremental_store = IncrementalStore(kv_store) + checkpoint_store = CheckpointStore(data_dir / "traces.db") + + # 登记 TraceContext 持久化(可选,不影响分析主链路) + try: + from .core.infrastructure.persistence.trace_sqlite_store import TraceSQLiteStore + TraceContext.set_global_store(TraceSQLiteStore(data_dir / "traces.db")) + except Exception as e: + logger.debug(f"TraceStore 初始化失败(忽略): {e}") + + bot_manager = BotManager() + + analysis_service = AnalysisApplicationService( + config_manager=config_manager, + bot_manager=bot_manager, + history_manager=history_manager, + report_generator=report_generator, + llm_analyzer=llm_analyzer, + statistics_service=statistics_service, + analysis_domain_service=analysis_domain_service, + incremental_store=incremental_store, + incremental_merge_service=incremental_merge_service, + checkpoint_store=checkpoint_store, + html_render=html_render, + ) + + _services = { + "config_manager": config_manager, + "report_generator": report_generator, + "analysis_service": analysis_service, + "bot_manager": bot_manager, + "data_dir": data_dir, + } + return _services + + +def get_services() -> dict[str, Any]: + return _build_services() + + +def register_bot_adapter(bot: Any, platform_id: str | None = None) -> OneBotAdapter: + """为当前 Bot 注册/更新 OneBot 适配器。""" + svc = _build_services() + bot_manager = svc["bot_manager"] + config_manager = svc["config_manager"] + bot_self_ids = list(config_manager.get_bot_self_ids() or []) + adapter = OneBotAdapter( + bot, + { + "platform_id": platform_id or "onebot", + "bot_self_ids": bot_self_ids, + "filter_bot_messages": config_manager.get_filter_bot_messages(), + }, + ) + bot_manager.register_adapter(adapter, platform_id or "onebot") + return adapter diff --git a/hexi/plugins/nonebot_plugin_group_daily_analysis/templates.py b/hexi/plugins/nonebot_plugin_group_daily_analysis/templates.py new file mode 100644 index 0000000..0e450db --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_daily_analysis/templates.py @@ -0,0 +1,34 @@ +"""模板目录的本地访问(NoneBot 版,避免引入 AstrBot 消息组件)。""" + +from __future__ import annotations + +from pathlib import Path + +_TEMPLATES_DIR = ( + Path(__file__).resolve().parent + / "core" + / "infrastructure" + / "reporting" + / "templates" +) +_ASSETS_DIR = Path(__file__).resolve().parent / "assets" + + +def list_templates() -> list[str]: + """按字典序返回可用模板名,与设置模板的 1..N 编号一致。""" + if not _TEMPLATES_DIR.exists(): + return [] + return sorted( + d.name + for d in _TEMPLATES_DIR.iterdir() + if d.is_dir() and not d.name.startswith("__") + ) + + +def template_exists(template: str) -> bool: + return (_TEMPLATES_DIR / template).is_dir() + + +def preview_image(template: str) -> Path | None: + p = _ASSETS_DIR / f"{template}-demo.jpg" + return p if p.exists() else None diff --git a/hexi/plugins/nonebot_plugin_group_tools/__init__.py b/hexi/plugins/nonebot_plugin_group_tools/__init__.py new file mode 100644 index 0000000..1f84281 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/__init__.py @@ -0,0 +1,33 @@ +from nonebot import require +from nonebot.plugin import PluginMetadata + +require("nonebot_plugin_alconna") + +__plugin_meta__ = PluginMetadata( + name="群管理工具", + description=( + "群管理指令与群管小功能合集:龙王查询、禁言、头衔、名片、群名管理、" + "违禁词语音、聊天互动、退群通知、随机复读、禁言套餐" + ), + usage=( + "注意本页指令可能由于风控在您的群不可用\n" + "[谁是龙王] 查看本群龙王\n" + "[龙王榜] 查看本群B话最多的人\n" + "以下指令需要机器人是管理员, 且被执行人是普通群员\n" + "[修改群名XXX] 群名修改为XXX\n" + "[修改名片XXX@某人] 修改某人的群名片为XXX\n" + "[来发口球360@某人] 禁言某人360秒, 可以修改为自己需要的时间\n" + "[解除口球@某人] 取消某人的禁言\n" + "[全员口球] 开启全员禁言\n" + "[取消全员禁言] 关闭全员禁言\n" + "[极限一换一60@某人]神秘功能, 60可以修改为30以下的秒数\n" + "[申请头衔XXX] 申请/删除专属头衔(bot需为群主)\n" + "[违禁词] 触发黑手语音\n" + "[沙雕机器人/老婆/老公/mua/何意味/确实/内鬼...] 聊天互动\n" + "[睡眠套餐/精致睡眠] 8小时禁言(bot需具有群管理权限)\n" + "[来一份精致昏睡下午茶套餐] 随机时长禁言(bot需具有群管理权限)" + ), + type="application", +) + +from .handlers import chat, management, notices, repeater # noqa: E402,F401 diff --git a/hexi/plugins/nonebot_plugin_group_tools/constants.py b/hexi/plugins/nonebot_plugin_group_tools/constants.py new file mode 100644 index 0000000..c754ee4 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/constants.py @@ -0,0 +1,16 @@ +from pathlib import Path + +# 插件根目录(放 dk_is_me.jpg 等根级资源) +PLUGIN_ROOT = Path(__file__).resolve().parent +IMG_DIR = PLUGIN_ROOT +# 资源目录:res/ 下的 record/ 与 img/ +RES_DIR = PLUGIN_ROOT / "res" +# 视频临时目录(项目数据目录下) +TEMP_DIR = PLUGIN_ROOT.parents[1] / "data" / "temp" + +# 违禁词(触发黑手语音) +BANNED_WORDS = ( + "rbq", "RBQ", "憨批", "废物", "死妈", "崽种", "傻逼", "傻逼玩意", + "没用东西", "傻B", "傻b", "SB", "sb", "煞笔", "cnm", "爬", "kkp", + "nmsl", "D区", "口区", "我是你爹", "nmbiss", "弱智", "给爷爬", "杂种爬", "爪巴", +) diff --git a/hexi/plugins/nonebot_plugin_group_tools/dk_is_me.jpg b/hexi/plugins/nonebot_plugin_group_tools/dk_is_me.jpg new file mode 100644 index 0000000..11bb0b8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/dk_is_me.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/handlers/__init__.py b/hexi/plugins/nonebot_plugin_group_tools/handlers/__init__.py new file mode 100644 index 0000000..e367117 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/handlers/__init__.py @@ -0,0 +1 @@ +"""群管理工具插件的消息/事件处理器子包。""" diff --git a/hexi/plugins/nonebot_plugin_group_tools/handlers/chat.py b/hexi/plugins/nonebot_plugin_group_tools/handlers/chat.py new file mode 100644 index 0000000..3814055 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/handlers/chat.py @@ -0,0 +1,164 @@ +import random + +from nonebot import get_driver, on_command, on_fullmatch, on_keyword, require +from nonebot.adapters.onebot.v11 import Bot, MessageEvent +from nonebot.rule import to_me + +require("nonebot_plugin_alconna") +from nonebot_plugin_alconna import UniMessage + +from ..constants import BANNED_WORDS, RES_DIR +from ..services.moderation import silence +from ..utils.media import image_to_base64, random_audio + +SUPERUSERS = get_driver().config.superusers + + +# ---------- 基础打招呼 ---------- + +say_hello = on_command( + "zai?", + aliases={"在?", "在?", "在吗", "在么?", "在嘛", "在嘛?"}, + rule=to_me(), + block=True, +) + + +@say_hello.handle() +async def say_hello_handle(ev: MessageEvent): + await UniMessage.text("はい!私はいつも貴方の側にいますよ!").send() + + +# ---------- 关键词/整句互动 ---------- + +say_sorry = on_fullmatch("沙雕机器人") + + +@say_sorry.handle() +async def say_sorry_handle(ev: MessageEvent): + await UniMessage.text("ごめんなさい!嘤嘤嘤(〒︿〒)").send() + + +say_heweidao = on_keyword({"何意味"}) + + +@say_heweidao.handle() +async def say_heweidao_handle(ev: MessageEvent): + await UniMessage.text("何意味是什么意思喵~").send() + + +chat_waifu = on_fullmatch(("老婆", "waifu", "laopo"), rule=to_me()) + + +@chat_waifu.handle() +async def chat_waifu_handle(ev: MessageEvent): + is_superuser = str(ev.user_id) in SUPERUSERS + img_name = "love.jpg" if is_superuser else "laopo.jpg" + base64_str = image_to_base64(RES_DIR / "img" / img_name) + if not base64_str: + return + if is_superuser: + msg = UniMessage.text("mua~") + UniMessage.image(url=base64_str) + else: + msg = UniMessage.image(url=base64_str) + await msg.send() + + +chat_laogong = on_fullmatch("老公", rule=to_me()) + + +@chat_laogong.handle() +async def chat_laogong_handle(ev: MessageEvent): + await UniMessage.text("你给我滚!").send(at_sender=True) + + +chat_mua = on_fullmatch("mua", rule=to_me()) + + +@chat_mua.handle() +async def chat_mua_handle(ev: MessageEvent): + await UniMessage.text("笨蛋~").send(at_sender=True) + + +ddhaole = on_fullmatch(("我有个朋友说他好了", "我朋友说他好了")) + + +@ddhaole.handle() +async def ddhaole_handle(bot: Bot, ev: MessageEvent): + await UniMessage.text("那个朋友是不是你弟弟?").send() + await silence(bot, ev, 30) + + +nihaole = on_fullmatch("我好了") + + +@nihaole.handle() +async def nihaole_handle(bot: Bot, ev: MessageEvent): + await UniMessage.text("不许好,憋回去!").send() + # await silence(bot, ev, 30) + + +play_zhanshi = on_keyword({"优质的战士"}) + + +@play_zhanshi.handle() +async def play_zhanshi_handle(ev: MessageEvent): + base64_str = random_audio(RES_DIR / "record" / "voice" / "youzhizhanshi") + if base64_str: + await UniMessage.voice(url=base64_str).send() + + +play_ice = on_fullmatch("溜冰") + + +@play_ice.handle() +async def play_ice_handle(ev: MessageEvent): + base64_str = random_audio(RES_DIR / "record" / "voice" / "ice") + if base64_str: + await UniMessage.voice(url=base64_str).send() + + +play_dxl = on_fullmatch("罕见") + + +@play_dxl.handle() +async def play_dxl_handle(ev: MessageEvent): + base64_str = random_audio(RES_DIR / "record" / "voice" / "dxl") + if base64_str: + await UniMessage.voice(url=base64_str).send() + + +chat_queshi = on_keyword({"确实", "有一说一", "u1s1", "yysy"}) + + +@chat_queshi.handle() +async def chat_queshi_handle(ev: MessageEvent): + if random.random() < 0.05: + base64_str = image_to_base64(RES_DIR / "img" / "确实.jpg") + if base64_str: + await UniMessage.image(url=base64_str).send() + + +chat_neigui = on_keyword({"内鬼"}) + + +@chat_neigui.handle() +async def chat_neigui_handle(ev: MessageEvent): + if random.random() < 0.10: + base64_str = image_to_base64(RES_DIR / "img" / "内鬼.png") + if base64_str: + await UniMessage.image(url=base64_str).send() + + +# ---------- 违禁词黑手语音 ---------- + +banned_word_voice = on_command( + "ban_word", aliases=set(BANNED_WORDS), rule=to_me(), block=True +) + + +@banned_word_voice.handle() +async def banned_word_voice_handle(ev: MessageEvent): + base64_str = random_audio(RES_DIR / "record" / "voice" / "heishou") + if base64_str: + await UniMessage.voice(url=base64_str).send() diff --git a/hexi/plugins/nonebot_plugin_group_tools/handlers/management.py b/hexi/plugins/nonebot_plugin_group_tools/handlers/management.py new file mode 100644 index 0000000..7617ec1 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/handlers/management.py @@ -0,0 +1,399 @@ +import asyncio +import math +import random +import re +import time + +from nonebot import logger, on_fullmatch, on_message, on_regex, on_startswith, require +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent +from nonebot.rule import Rule, is_type + +require("nonebot_plugin_alconna") +from nonebot_plugin_alconna import UniMessage + +from hexi.plugins.nonebot_plugin_hexi_core.custom_utils import check_manage + +from ..constants import IMG_DIR, TEMP_DIR +from ..services.moderation import group_silence, member_silence, silence +from ..services.profile import card_edit, group_name, title_get +from ..services.video import download_video, get_video_info, local_video +from ..utils.media import image_to_base64 +from ..utils.message import get_at_id, has_at_all +from ..utils.permissions import check_perm, honor_info, self_member_info +from ..utils.text import is_number, parse_seconds, strip_prefix + + +# ============ 管理员与公告 ============ + +set_admin = on_startswith("设置管理员") +unset_admin = on_startswith("取消管理员") +set_group_notice = on_startswith("设置群公告") + + +@set_admin.handle() +async def set_admin_handle(bot: Bot, ev: GroupMessageEvent): + if not await check_perm(bot, ev): + return + for seg in ev.message: + if seg.type == "at" and seg.data.get("qq") != "all": + await bot.set_group_admin( + group_id=ev.group_id, user_id=int(seg.data["qq"]), enable=True + ) + await UniMessage.text("我好了").send() + + +@unset_admin.handle() +async def unset_admin_handle(bot: Bot, ev: GroupMessageEvent): + if not await check_perm(bot, ev): + return + for seg in ev.message: + if seg.type == "at" and seg.data.get("qq") != "all": + await bot.set_group_admin( + group_id=ev.group_id, user_id=int(seg.data["qq"]), enable=False + ) + await UniMessage.text("我好了").send() + + +@set_group_notice.handle() +async def set_group_notice_handle(bot: Bot, ev: GroupMessageEvent): + content = ev.message.extract_plain_text().removeprefix("设置群公告").strip() + if not content: + return + if not await check_perm(bot, ev): + return + await bot.call_api("_send_group_notice", group_id=ev.group_id, content=content) + await UniMessage.text("我好了").send() + + +# ============ 禁言相关 ============ + + +def _is_ban_cmd(event: GroupMessageEvent) -> bool: + """分钟制禁言命令:"禁言@xxx 5" 表示禁言 5 分钟;排除秒制的 "禁言一下" """ + text = event.message.extract_plain_text() + return text.startswith("禁言") and not text.startswith("禁言一下") + + +ban_user = on_message(rule=Rule(_is_ban_cmd) & is_type(GroupMessageEvent), block=True) +ban_member = on_startswith(("来发口球", "塞口球", "禁言一下")) +one_for_one = on_startswith("极限一换一") +cancel_ban = on_startswith(("解除口球", "取消口球", "摘口球", "脱口球", "取消禁言", "解除禁言", "解禁")) +ban_all = on_fullmatch(("全员口球", "全员禁言")) +cancel_ban_all = on_fullmatch(("取消全员口球", "取消全员禁言", "解除全员口球", "解除全员禁言")) + +sleep_8h = on_fullmatch(("睡眠套餐", "休眠套餐", "精致睡眠", "来一份精致睡眠套餐")) +tea = on_regex(r"(来|來)(.*(份|个)(.*)(睡|茶)(.*))套餐") + + +@ban_user.handle() +async def ban_user_handle(bot: Bot, ev: GroupMessageEvent): + if not await check_perm(bot, ev, silent=True): + return + msg = ev.message.extract_plain_text().removeprefix("禁言").strip() + at_seg = next( + (seg for seg in ev.message if seg.type == "at" and seg.data.get("qq") != "all"), + None, + ) + if not at_seg: + return + try: + uid = int(at_seg.data["qq"]) + minutes = 1 if not msg else int(msg) + await bot.set_group_ban( + group_id=ev.group_id, user_id=uid, duration=minutes * 60 + ) + await UniMessage.text("我好了").send() + except Exception as ex: + logger.error(ex) + + +@ban_member.handle() +async def ban_member_handle(bot: Bot, ev: GroupMessageEvent): + uid = ev.user_id + gid = ev.group_id + duration_text = strip_prefix( + ev.message.extract_plain_text(), ("来发口球", "塞口球", "禁言一下") + ) + if not duration_text: + duration_text = "30" + if has_at_all(ev): + await group_silence(bot, ev, gid, True) + return + sid = get_at_id(ev) or uid + await member_silence(bot, ev, uid, sid, gid, duration_text, silent=False) + + +@one_for_one.handle() +async def one_for_one_handle(bot: Bot, ev: GroupMessageEvent): + uid = ev.user_id + gid = ev.group_id + duration_text = strip_prefix(ev.message.extract_plain_text(), ("极限一换一",)) + if has_at_all(ev): + await UniMessage.text("人干事?").send(at_sender=True) + await member_silence(bot, ev, uid, uid, gid, "180", silent=False) + return + seconds = parse_seconds(duration_text) + if seconds is None: + await UniMessage.text("请输入正确时长~").send(at_sender=True) + return + if seconds > 30: + await UniMessage.text("时长不可大于30秒哟~").send(at_sender=True) + return + sid = get_at_id(ev) or uid + await member_silence(bot, ev, uid, sid, gid, str(seconds), silent=True) + await member_silence(bot, ev, uid, uid, gid, str(seconds), silent=True) + await ( + UniMessage.at(user_id=str(uid)) + .text("成功一换一") + .at(user_id=str(sid)) + .text(f"{seconds}秒~") + .send() + ) + + +@cancel_ban.handle() +async def cancel_ban_handle(bot: Bot, ev: GroupMessageEvent): + if not await check_manage(bot, ev): + await UniMessage.text("权限不足").send() + return + uid = ev.user_id + gid = ev.group_id + if has_at_all(ev): + await group_silence(bot, ev, gid, False) + return + sid = get_at_id(ev) + if sid is None: + await UniMessage.text("请@需要摘口球的群员哦w").send() + return + await member_silence(bot, ev, uid, sid, gid, "0", silent=False) + + +@ban_all.handle() +async def ban_all_handle(bot: Bot, ev: GroupMessageEvent): + if not await check_manage(bot, ev): + await UniMessage.text("权限不足").send() + return + await group_silence(bot, ev, ev.group_id, True) + + +@cancel_ban_all.handle() +async def cancel_ban_all_handle(bot: Bot, ev: GroupMessageEvent): + if not await check_manage(bot, ev): + await UniMessage.text("权限不足").send() + return + await group_silence(bot, ev, ev.group_id, False) + + +@sleep_8h.handle() +async def sleep_8h_handle(bot: Bot, ev: MessageEvent): + await silence(bot, ev, 8 * 60 * 60) + + +@tea.handle() +async def tea_handle(bot: Bot, ev: MessageEvent): + base = 0 if "午" in ev.plain_text else 5 * 60 * 60 + length = len(ev.plain_text) + sleep_time = base + round( + math.sqrt(length) * 60 * 30 + 60 * random.randint(-15, 15) + ) + await silence(bot, ev, sleep_time) + + +# ============ 头衔 / 名片 / 群名 ============ + +special_title = on_startswith("申请头衔") +del_special_title = on_fullmatch(("删除头衔", "清除头衔", "收回头衔", "回收头衔")) +card_set = on_startswith(("修改名片", "修改群名片", "设置名片", "设置群名片")) +set_group_name = on_startswith(("修改群名", "设置群名")) + + +@special_title.handle() +async def special_title_handle(bot: Bot, ev: GroupMessageEvent): + uid = ev.user_id + gid = ev.group_id + title = strip_prefix(ev.message.extract_plain_text(), ("申请头衔",)) + sid = get_at_id(ev) or uid + await title_get(bot, ev, uid, sid, gid, title) + + +# go-cqhttp似乎暂时不支持收回专属头衔... +@del_special_title.handle() +async def del_special_title_handle(bot: Bot, ev: GroupMessageEvent): + uid = ev.user_id + gid = ev.group_id + sid = get_at_id(ev) or uid + await title_get(bot, ev, uid, sid, gid, None) + + +@card_set.handle() +async def card_set_handle(bot: Bot, ev: GroupMessageEvent): + uid = ev.user_id + gid = ev.group_id + card_text = strip_prefix( + ev.message.extract_plain_text(), ("修改名片", "修改群名片", "设置名片", "设置群名片") + ) + sid = get_at_id(ev) or uid + await card_edit(bot, ev, uid, sid, gid, card_text) + + +@set_group_name.handle() +async def set_group_name_handle(bot: Bot, ev: GroupMessageEvent): + if not await check_manage(bot, ev): + await UniMessage.text("权限不足").send() + return + gid = ev.group_id + name_text = strip_prefix(ev.message.extract_plain_text(), ("修改群名", "设置群名")) + await group_name(bot, ev, gid, name_text) + + +# ============ 龙王 ============ + +whois_dragon = on_fullmatch(("谁是龙王", "迫害龙王", "龙王是谁")) +dragon_list = on_fullmatch(("龙王榜", "龙王排行", "龙王排行榜", "龙王榜单")) + + +@whois_dragon.handle() +async def whois_dragon_handle(bot: Bot, ev: GroupMessageEvent): + gid = ev.group_id + self_info = await self_member_info(bot, gid) + sid = self_info["user_id"] + ta_info = await honor_info(bot, gid, "talkative") + if not ta_info or not ta_info.get("current_talkative"): + await UniMessage.text("本群没有开启龙王标志哦~").send() + return + dk = ta_info["current_talkative"]["user_id"] + if sid == dk: + pic = image_to_base64(IMG_DIR / "dk_is_me.jpg") + await ( + UniMessage.text("你们这群丢人玩意,龙王怎么又是我\n") + .image(url=pic) + .send() + ) + else: + action = random.choice(["龙王出来挨透", "龙王出来喷水"]) + dk_avatar = ta_info["current_talkative"]["avatar"] + "640" + f"&t={dk}" + await ( + UniMessage.at(user_id=str(dk)) + .text(f"\n{action}\n") + .image(url=dk_avatar) + .send() + ) + + +@dragon_list.handle() +async def dragon_list_handle(bot: Bot, ev: GroupMessageEvent): + gid = ev.group_id + ta_info = await honor_info(bot, gid, "talkative") + if not ta_info or not ta_info.get("talkative_list"): + await UniMessage.text("本群暂时没有龙王数据哦~").send() + return + dragon_king_list_info = ta_info["talkative_list"] + + # 处理description和nickname关系 + dkdir = {} + for item in dragon_king_list_info: + user_id = item["user_id"] + nickname = item["nickname"] + description = item["description"] + temp = re.findall(r"\d+", description) + + # 累计获得龙王的次数 + dragon_king_days = int(temp[0]) + # 连续获得龙王 + dragon_king_days_continuous = int(temp[1]) + dkdir[nickname] = { + "user_id": user_id, + "days_max": dragon_king_days, + "days_contin": dragon_king_days_continuous, + } + # 瞎写的排序 + dkdir_sorted = sorted(dkdir.items(), key=lambda d: d[1]["days_max"], reverse=True) + dkk = dkdir_sorted[0][1]["user_id"] + msg = UniMessage.text(f"本群获得龙王次数最多的是:\n{dkdir_sorted[0][0]}\n") + dk_avatar = f"http://q1.qlogo.cn/g?b=qq&nk={dkk}&s=5" + msg += UniMessage.image(url=dk_avatar) + msg += UniMessage.text("\n本群龙王榜\n") + for i, it in enumerate(dkdir_sorted[:5]): + _nickname = it[0] + _days_max = it[1]["days_max"] + _days_contin = it[1]["days_contin"] + msg += UniMessage.text( + f"第{i + 1}名:{_nickname},共{_days_max}次,最长连续{_days_contin}天获得龙王\n" + ) + await msg.send() + + +# ============ 视频下载 ============ + +down_video = on_startswith("/video") + + +@down_video.handle() +async def down_video_handle(bot: Bot, ev: GroupMessageEvent): + url = ev.message.extract_plain_text().removeprefix("/video").strip() + if not url: + return + match = re.match(r"https?:/{2}\w.+$", url) + if not match: + await UniMessage.text("参数不合法").send() + return + + timespan = int(time.time()) + filename = f"{timespan}" + file = TEMP_DIR / f"{filename}.mp4" + fileabs = str(file) + cover = TEMP_DIR / f"{filename}.mp4.jpg" + + TEMP_DIR.mkdir(parents=True, exist_ok=True) + try: + info = await asyncio.to_thread(get_video_info, url) + match = re.search(r"MPEG-4 video(.*)\s*Size:(.*)MiB", info) + if not match: + await UniMessage.text("参数不正确").send() + return + info_type = match.group(1).strip() + if info_type != "(video/mp4)": + await UniMessage.text("未找到视频信息").send() + return + info_size = match.group(2).strip() + if not is_number(info_size): + await UniMessage.text("无法获取视频大小").send() + return + size = float(info_size) + if size >= 6.0: + await UniMessage.text("视频体积过大").send() + return + + await UniMessage.text("正在发送...").send() + await asyncio.to_thread(download_video, url, TEMP_DIR, filename) + except Exception as e: + logger.error(e) + await UniMessage.text("获取视频失败了").send() + file.unlink(missing_ok=True) + cover.unlink(missing_ok=True) + return + + try: + await local_video(f"file:///{fileabs}").send() + except Exception: + await UniMessage.text("发送失败了").send() + file.unlink(missing_ok=True) + cover.unlink(missing_ok=True) + + +# ============ 病毒消息拦截 ============ + +fuck_xxs = on_message(rule=is_type(GroupMessageEvent), block=False) + + +@fuck_xxs.handle() +async def fuck_xxs_handle(bot: Bot, ev: GroupMessageEvent): + for m in ev.message: + if m.type == "json" and '"app":"com.tencent.autoreply"' in m.data.get( + "data", "" + ): + await bot.delete_msg(message_id=ev.message_id) + await UniMessage.text( + "这是onse病毒码,会获取到你手机的xxs,然后发起攻击...以下省略6行需要全文背诵的金句" + ).send() + return diff --git a/hexi/plugins/nonebot_plugin_group_tools/handlers/notices.py b/hexi/plugins/nonebot_plugin_group_tools/handlers/notices.py new file mode 100644 index 0000000..de7cb53 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/handlers/notices.py @@ -0,0 +1,37 @@ +from nonebot import on_notice, require +from nonebot.adapters.onebot.v11 import ( + Bot, + GroupDecreaseNoticeEvent, + GroupIncreaseNoticeEvent, +) +from nonebot.rule import is_type + +require("nonebot_plugin_alconna") +from nonebot_plugin_alconna import UniMessage + +group_decrease_notice = on_notice(rule=is_type(GroupDecreaseNoticeEvent)) + + +@group_decrease_notice.handle() +async def group_decrease_handle(bot: Bot, ev: GroupDecreaseNoticeEvent): + sub_type = ev.sub_type + uid = ev.user_id + operator_id = ev.operator_id + data = await bot.get_stranger_info(user_id=uid) + name = data["nickname"] + if sub_type == "kick": + await UniMessage.at(user_id=operator_id).text( + f"认为{name}({uid})不适合本群" + ).send() + elif sub_type == "leave": + await UniMessage.text(f"{name}({uid})离开了我们,相信会有再见的一天!").send() + + +group_increase_notice = on_notice(rule=is_type(GroupIncreaseNoticeEvent)) + + +@group_increase_notice.handle() +async def group_increase_handle(bot: Bot, ev: GroupIncreaseNoticeEvent): + if ev.user_id == ev.self_id: + return # 忽略自己 + await UniMessage.text("欢迎入群~,请认真阅读群规").send(at_sender=True) diff --git a/hexi/plugins/nonebot_plugin_group_tools/handlers/repeater.py b/hexi/plugins/nonebot_plugin_group_tools/handlers/repeater.py new file mode 100644 index 0000000..d71fb78 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/handlers/repeater.py @@ -0,0 +1,49 @@ +import random + +from nonebot import on_message, require +from nonebot.adapters.onebot.v11 import GroupMessageEvent +from nonebot.log import logger + +require("nonebot_plugin_alconna") +from nonebot_plugin_alconna import UniMessage + +PROB_A = 1.4 +# group_id: (last_msg, is_repeated, p) +group_stat: dict[int, tuple[str, bool, float]] = {} + +""" +不复读率 随 复读次数 指数级衰减 +从第2条复读,即第3条重复消息开始有几率触发复读 + +a 设为一个略大于1的小数,最好不要超过2,建议1.6 +复读概率计算式:p_n = 1 - 1/a^n +递推式:p_n+1 = 1 - (1 - p_n) / a +""" + +repeater = on_message(block=False) + + +@repeater.handle() +async def repeater_handle(ev: GroupMessageEvent): + group_id = ev.group_id + msg = str(ev.message) + + if group_id not in group_stat: + group_stat[group_id] = (msg, False, 0.0) + return + + last_msg, is_repeated, p = group_stat[group_id] + if last_msg == msg: # 群友正在复读 + if not is_repeated: # 机器人尚未复读过,开始测试复读 + if random.random() < p: # 概率测试通过,复读并设 flag + try: + group_stat[group_id] = (msg, True, 0.0) + await UniMessage.text(ev.message.extract_plain_text()).send() + except Exception as e: + logger.error(f"复读失败: {type(e)}") + logger.exception(e) + else: # 概率测试失败,蓄力 + p = 1 - (1 - p) / PROB_A + group_stat[group_id] = (msg, False, p) + else: # 不是复读,重置 + group_stat[group_id] = (msg, False, 0.0) diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/H~@%PMGOFZNLLE@3I~%@4N9.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/H~@%PMGOFZNLLE@3I~%@4N9.png new file mode 100644 index 0000000..85a2e04 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/H~@%PMGOFZNLLE@3I~%@4N9.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/anti.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/anti.jpg new file mode 100644 index 0000000..2afb52b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/anti.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/antiqks.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/antiqks.jpg new file mode 100644 index 0000000..2afb52b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/antiqks.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/gadget/star-1.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/gadget/star-1.png new file mode 100644 index 0000000..3b7e03f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/gadget/star-1.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/gadget/star.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/gadget/star.png new file mode 100644 index 0000000..cafac30 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/gadget/star.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/gadget/star_disabled.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/gadget/star_disabled.png new file mode 100644 index 0000000..4914bd0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/gadget/star_disabled.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_1000.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_1000.png new file mode 100644 index 0000000..954d274 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_1000.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10000.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10000.png new file mode 100644 index 0000000..39ac0f3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10000.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10001.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10001.png new file mode 100644 index 0000000..b34e7b3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10001.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10002.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10002.png new file mode 100644 index 0000000..9051f94 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10002.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10003.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10003.png new file mode 100644 index 0000000..f221945 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10003.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10004.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10004.png new file mode 100644 index 0000000..9ac9d56 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10004.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10005.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10005.png new file mode 100644 index 0000000..90a4fb2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10005.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10006.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10006.png new file mode 100644 index 0000000..75d9e8d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10006.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10007.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10007.png new file mode 100644 index 0000000..b4596d3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10007.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10008.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10008.png new file mode 100644 index 0000000..4195dde Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10008.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10009.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10009.png new file mode 100644 index 0000000..b2eab49 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10009.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10010.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10010.png new file mode 100644 index 0000000..01554be Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10010.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10011.png new file mode 100644 index 0000000..bcf2831 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10012.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10012.png new file mode 100644 index 0000000..6e0b97c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10012.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10013.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10013.png new file mode 100644 index 0000000..bb7d2ca Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10013.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10014.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10014.png new file mode 100644 index 0000000..bb8c0a3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10014.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10015.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10015.png new file mode 100644 index 0000000..a2f1ab1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10015.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10016.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10016.png new file mode 100644 index 0000000..26f6a15 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10016.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10017.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10017.png new file mode 100644 index 0000000..0aa9ad2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10017.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10018.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10018.png new file mode 100644 index 0000000..afc3986 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10018.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10019.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10019.png new file mode 100644 index 0000000..a7ac351 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10019.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10020.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10020.png new file mode 100644 index 0000000..3665bc8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10020.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10021.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10021.png new file mode 100644 index 0000000..77d7598 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10021.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10022.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10022.png new file mode 100644 index 0000000..284a0e4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10022.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10023.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10023.png new file mode 100644 index 0000000..75b0480 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10023.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10024.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10024.png new file mode 100644 index 0000000..bfedcc0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10024.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10025.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10025.png new file mode 100644 index 0000000..130ad0a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10025.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10026.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10026.png new file mode 100644 index 0000000..376ce0e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10026.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10027.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10027.png new file mode 100644 index 0000000..c57f12e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10027.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10028.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10028.png new file mode 100644 index 0000000..7b600a0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10028.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10029.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10029.png new file mode 100644 index 0000000..abfe26d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10029.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10030.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10030.png new file mode 100644 index 0000000..39ced8b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10030.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10031.png new file mode 100644 index 0000000..10bd293 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10032.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10032.png new file mode 100644 index 0000000..3d687c6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10032.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10033.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10033.png new file mode 100644 index 0000000..938ceff Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10033.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10034.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10034.png new file mode 100644 index 0000000..2e6dda1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10034.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10035.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10035.png new file mode 100644 index 0000000..eaa329b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10035.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10036.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10036.png new file mode 100644 index 0000000..65750eb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10036.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10037.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10037.png new file mode 100644 index 0000000..cc4640d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10037.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10038.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10038.png new file mode 100644 index 0000000..d8d00c5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10038.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10039.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10039.png new file mode 100644 index 0000000..b637e41 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10039.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10040.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10040.png new file mode 100644 index 0000000..ea1322e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10040.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10041.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10041.png new file mode 100644 index 0000000..f780cd0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10041.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10042.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10042.png new file mode 100644 index 0000000..865c1f2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10042.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10043.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10043.png new file mode 100644 index 0000000..e83ba1c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10043.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10044.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10044.png new file mode 100644 index 0000000..f824ce4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10044.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10045.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10045.png new file mode 100644 index 0000000..355d7a0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10045.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10046.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10046.png new file mode 100644 index 0000000..3e414d6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10046.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10047.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10047.png new file mode 100644 index 0000000..d3baef4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10047.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10048.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10048.png new file mode 100644 index 0000000..0132639 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10048.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10049.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10049.png new file mode 100644 index 0000000..9077919 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10049.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10050.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10050.png new file mode 100644 index 0000000..b0259df Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10050.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10051.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10051.png new file mode 100644 index 0000000..13098ca Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10051.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10052.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10052.png new file mode 100644 index 0000000..6004173 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10052.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10053.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10053.png new file mode 100644 index 0000000..313b4e8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10053.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10054.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10054.png new file mode 100644 index 0000000..4f2e40b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10054.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10055.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10055.png new file mode 100644 index 0000000..890a44a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10055.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10056.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10056.png new file mode 100644 index 0000000..e36a372 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10056.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10057.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10057.png new file mode 100644 index 0000000..d17c785 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10057.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10058.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10058.png new file mode 100644 index 0000000..47ef99c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10058.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10059.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10059.png new file mode 100644 index 0000000..84a954f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10059.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10060.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10060.png new file mode 100644 index 0000000..6022634 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10060.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10061.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10061.png new file mode 100644 index 0000000..25859e2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10061.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10062.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10062.png new file mode 100644 index 0000000..c08c411 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10062.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10063.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10063.png new file mode 100644 index 0000000..18fbb15 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10063.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10064.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10064.png new file mode 100644 index 0000000..ba0acfb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10064.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10065.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10065.png new file mode 100644 index 0000000..5ad2762 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10065.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10066.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10066.png new file mode 100644 index 0000000..7ec1fd1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10066.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10067.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10067.png new file mode 100644 index 0000000..4bc9aad Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10067.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10068.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10068.png new file mode 100644 index 0000000..060fd42 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10068.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10069.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10069.png new file mode 100644 index 0000000..7fa67a1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10069.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10070.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10070.png new file mode 100644 index 0000000..3ac5e00 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10070.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10071.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10071.png new file mode 100644 index 0000000..892b76e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10071.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10072.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10072.png new file mode 100644 index 0000000..abdf260 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10072.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10073.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10073.png new file mode 100644 index 0000000..b295d09 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10073.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10074.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10074.png new file mode 100644 index 0000000..68d408e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10074.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10075.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10075.png new file mode 100644 index 0000000..6a70ae8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10075.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10076.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10076.png new file mode 100644 index 0000000..4dde0f0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10076.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10077.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10077.png new file mode 100644 index 0000000..90bad57 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10077.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10078.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10078.png new file mode 100644 index 0000000..adb726d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10078.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10079.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10079.png new file mode 100644 index 0000000..9ab6ec6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10079.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10080.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10080.png new file mode 100644 index 0000000..e6b672b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10080.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10081.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10081.png new file mode 100644 index 0000000..32fc74e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10081.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10082.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10082.png new file mode 100644 index 0000000..aacd9e3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10082.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10083.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10083.png new file mode 100644 index 0000000..97497c8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10083.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10084.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10084.png new file mode 100644 index 0000000..0460535 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10084.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10085.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10085.png new file mode 100644 index 0000000..71e3588 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10085.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10086.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10086.png new file mode 100644 index 0000000..56e4cc8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10086.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10087.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10087.png new file mode 100644 index 0000000..205488e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_10087.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13000.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13000.png new file mode 100644 index 0000000..0b8bf27 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13000.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13001.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13001.png new file mode 100644 index 0000000..9dc40af Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13001.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13002.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13002.png new file mode 100644 index 0000000..74aad46 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13002.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13003.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13003.png new file mode 100644 index 0000000..b8aa4fb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13003.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13004.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13004.png new file mode 100644 index 0000000..07e1317 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13004.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13005.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13005.png new file mode 100644 index 0000000..598af22 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13005.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13006.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13006.png new file mode 100644 index 0000000..69de6c6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13006.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13007.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13007.png new file mode 100644 index 0000000..829f8fc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13007.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13008.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13008.png new file mode 100644 index 0000000..66e240b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13008.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13009.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13009.png new file mode 100644 index 0000000..2b0f3c7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13009.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13010.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13010.png new file mode 100644 index 0000000..82cfb50 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13010.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13011.png new file mode 100644 index 0000000..6bdefc9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13012.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13012.png new file mode 100644 index 0000000..857ede3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13012.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13013.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13013.png new file mode 100644 index 0000000..f0426e0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_13013.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16000.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16000.png new file mode 100644 index 0000000..29d10a5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16000.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16001.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16001.png new file mode 100644 index 0000000..bfc9ac0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16001.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16002.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16002.png new file mode 100644 index 0000000..7b24491 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16002.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16003.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16003.png new file mode 100644 index 0000000..f273a41 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16003.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16004.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16004.png new file mode 100644 index 0000000..a531601 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16004.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16005.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16005.png new file mode 100644 index 0000000..8f8eb14 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16005.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16006.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16006.png new file mode 100644 index 0000000..27aa2ee Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16006.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16007.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16007.png new file mode 100644 index 0000000..3b71411 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16007.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16008.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16008.png new file mode 100644 index 0000000..a1f8070 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16008.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16009.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16009.png new file mode 100644 index 0000000..a82c2df Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16009.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16010.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16010.png new file mode 100644 index 0000000..c7a0605 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16010.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16011.png new file mode 100644 index 0000000..12aeb65 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16012.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16012.png new file mode 100644 index 0000000..033b148 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16012.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16013.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16013.png new file mode 100644 index 0000000..6b56966 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16013.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16014.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16014.png new file mode 100644 index 0000000..9a19ac0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_16014.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20000.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20000.png new file mode 100644 index 0000000..3004de3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20000.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20001.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20001.png new file mode 100644 index 0000000..9da4b2a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20001.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20002.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20002.png new file mode 100644 index 0000000..6ed71bb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20002.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20003.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20003.png new file mode 100644 index 0000000..947faca Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20003.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20004.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20004.png new file mode 100644 index 0000000..5af8bf0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20004.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20005.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20005.png new file mode 100644 index 0000000..aa2057d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20005.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20006.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20006.png new file mode 100644 index 0000000..7c7987b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20006.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20007.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20007.png new file mode 100644 index 0000000..02f7e82 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20007.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20008.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20008.png new file mode 100644 index 0000000..76b1b24 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20008.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20009.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20009.png new file mode 100644 index 0000000..1a06849 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20009.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20010.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20010.png new file mode 100644 index 0000000..d8ac4cc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20010.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20011.png new file mode 100644 index 0000000..7703785 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20012.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20012.png new file mode 100644 index 0000000..309ba62 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20012.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20013.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20013.png new file mode 100644 index 0000000..78d7542 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20013.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20014.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20014.png new file mode 100644 index 0000000..3cfd7a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20014.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20015.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20015.png new file mode 100644 index 0000000..5e1c812 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20015.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20016.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20016.png new file mode 100644 index 0000000..45583cf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20016.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20017.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20017.png new file mode 100644 index 0000000..756c659 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20017.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20018.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20018.png new file mode 100644 index 0000000..5b56bff Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20018.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20019.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20019.png new file mode 100644 index 0000000..d4f26da Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20019.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20020.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20020.png new file mode 100644 index 0000000..4679311 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20020.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20021.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20021.png new file mode 100644 index 0000000..d8de3ea Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20021.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20022.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20022.png new file mode 100644 index 0000000..1596138 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20022.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20023.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20023.png new file mode 100644 index 0000000..13ea4e7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20023.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20024.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20024.png new file mode 100644 index 0000000..5b0ff2e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20024.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20025.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20025.png new file mode 100644 index 0000000..8003976 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20025.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20026.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20026.png new file mode 100644 index 0000000..4b80b18 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20026.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20027.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20027.png new file mode 100644 index 0000000..13f69cb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20027.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20028.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20028.png new file mode 100644 index 0000000..0b8a195 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20028.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20029.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20029.png new file mode 100644 index 0000000..fadb115 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20029.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20030.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20030.png new file mode 100644 index 0000000..0045232 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20030.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20031.png new file mode 100644 index 0000000..f67ba57 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20032.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20032.png new file mode 100644 index 0000000..742f6c3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20032.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20033.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20033.png new file mode 100644 index 0000000..46582e3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_20033.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23000.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23000.png new file mode 100644 index 0000000..4a4c04f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23000.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23001.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23001.png new file mode 100644 index 0000000..834acc4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23001.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23002.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23002.png new file mode 100644 index 0000000..ca466bf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23002.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23003.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23003.png new file mode 100644 index 0000000..803c1b4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23003.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23004.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23004.png new file mode 100644 index 0000000..13253be Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23004.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23005.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23005.png new file mode 100644 index 0000000..dc40fcf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23005.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23006.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23006.png new file mode 100644 index 0000000..3f0d4c7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23006.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23007.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23007.png new file mode 100644 index 0000000..e44db57 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23007.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23008.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23008.png new file mode 100644 index 0000000..1c9196f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_23008.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26000.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26000.png new file mode 100644 index 0000000..99f1121 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26000.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26001.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26001.png new file mode 100644 index 0000000..fceca09 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26001.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26002.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26002.png new file mode 100644 index 0000000..c83dcad Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26002.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26003.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26003.png new file mode 100644 index 0000000..f563d9e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26003.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26004.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26004.png new file mode 100644 index 0000000..d9ecea4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26004.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26005.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26005.png new file mode 100644 index 0000000..9c62fcb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26005.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26006.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26006.png new file mode 100644 index 0000000..0428535 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26006.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26007.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26007.png new file mode 100644 index 0000000..a4cae07 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26007.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26008.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26008.png new file mode 100644 index 0000000..e767c73 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26008.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26009.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26009.png new file mode 100644 index 0000000..f3b3f7b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26009.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26010.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26010.png new file mode 100644 index 0000000..b275a4a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26010.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26011.png new file mode 100644 index 0000000..4629355 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/unit/icon_unit_26011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/wiki/student_rank/泳装花子.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/wiki/student_rank/泳装花子.png new file mode 100644 index 0000000..269aabf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/bluearchive/wiki/student_rank/泳装花子.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/chieri1.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/chieri1.jpg new file mode 100644 index 0000000..57abcfa Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/chieri1.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/chieri2.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/chieri2.jpg new file mode 100644 index 0000000..6f626c4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/chieri2.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/chieri3.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/chieri3.jpg new file mode 100644 index 0000000..88ae875 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/chieri3.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/chieri4.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/chieri4.jpg new file mode 100644 index 0000000..74dded0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/chieri4.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/icon_unit_112931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/icon_unit_112931.png new file mode 100644 index 0000000..5e66537 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/icon_unit_112931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/icon_unit_113731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/icon_unit_113731.png new file mode 100644 index 0000000..cda94e3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/icon_unit_113731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1004511835.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1004511835.jpg new file mode 100644 index 0000000..bac89bd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1004511835.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1005092621.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1005092621.jpg new file mode 100644 index 0000000..af7f850 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1005092621.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1014885965.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1014885965.jpg new file mode 100644 index 0000000..df344c8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1014885965.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1015189293.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1015189293.jpg new file mode 100644 index 0000000..44c2e03 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1015189293.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1023226162.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1023226162.jpg new file mode 100644 index 0000000..fa92ba8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1023226162.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1024947457.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1024947457.jpg new file mode 100644 index 0000000..5d5fcec Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1024947457.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1030081969.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1030081969.jpg new file mode 100644 index 0000000..cfc89d6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1030081969.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1031653806.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1031653806.jpg new file mode 100644 index 0000000..edeeb8c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1031653806.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1042413351.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1042413351.jpg new file mode 100644 index 0000000..e6899ae Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1042413351.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1043468471.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1043468471.jpg new file mode 100644 index 0000000..ef19a59 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1043468471.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1044482651.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1044482651.jpg new file mode 100644 index 0000000..e991afc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1044482651.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1044576134.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1044576134.jpg new file mode 100644 index 0000000..c2b3a23 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1044576134.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1047555675.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1047555675.jpg new file mode 100644 index 0000000..c845f47 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1047555675.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1049232495.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1049232495.jpg new file mode 100644 index 0000000..569452e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1049232495.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1057069677.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1057069677.jpg new file mode 100644 index 0000000..1aedbce Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1057069677.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1060389942.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1060389942.jpg new file mode 100644 index 0000000..7b62f73 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1060389942.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1069719537.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1069719537.jpg new file mode 100644 index 0000000..d283859 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1069719537.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1072324725.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1072324725.jpg new file mode 100644 index 0000000..6da8aa9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1072324725.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1072872877.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1072872877.jpg new file mode 100644 index 0000000..81c8d62 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1072872877.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1085683272.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1085683272.jpg new file mode 100644 index 0000000..f2c2dd4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1085683272.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1097887063.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1097887063.jpg new file mode 100644 index 0000000..4501e7b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1097887063.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1115375166.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1115375166.jpg new file mode 100644 index 0000000..1d7fa6e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1115375166.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1124369490.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1124369490.jpg new file mode 100644 index 0000000..1272fc7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1124369490.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1124868809.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1124868809.jpg new file mode 100644 index 0000000..ea629f4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1124868809.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1136694448.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1136694448.jpg new file mode 100644 index 0000000..5a3d917 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1136694448.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1141903494.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1141903494.jpg new file mode 100644 index 0000000..fc28728 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1141903494.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1144746331.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1144746331.jpg new file mode 100644 index 0000000..0e56705 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1144746331.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1150068242.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1150068242.jpg new file mode 100644 index 0000000..235e82d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1150068242.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1174701649.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1174701649.jpg new file mode 100644 index 0000000..4f3f6a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1174701649.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1191670942.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1191670942.jpg new file mode 100644 index 0000000..5b1f5da Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1191670942.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1191717937.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1191717937.jpg new file mode 100644 index 0000000..df511f5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1191717937.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1193866709.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1193866709.jpg new file mode 100644 index 0000000..1c8de9e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1193866709.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1204707481.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1204707481.jpg new file mode 100644 index 0000000..954ee3e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1204707481.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1209581401.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1209581401.jpg new file mode 100644 index 0000000..010ecc5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1209581401.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1210807886.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1210807886.jpg new file mode 100644 index 0000000..e677408 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1210807886.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1215988576.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1215988576.jpg new file mode 100644 index 0000000..c26b01f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1215988576.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1224737973.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1224737973.jpg new file mode 100644 index 0000000..e91578b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1224737973.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1241261026.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1241261026.jpg new file mode 100644 index 0000000..2bae6bc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1241261026.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1242525639.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1242525639.jpg new file mode 100644 index 0000000..996bc51 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1242525639.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1247698498.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1247698498.jpg new file mode 100644 index 0000000..8926523 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1247698498.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1254535464.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1254535464.jpg new file mode 100644 index 0000000..c7c7c17 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1254535464.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1256390702.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1256390702.jpg new file mode 100644 index 0000000..bb941b7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1256390702.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1257297430.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1257297430.jpg new file mode 100644 index 0000000..a895d2c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1257297430.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1259843337.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1259843337.jpg new file mode 100644 index 0000000..0b99055 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1259843337.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1269978948.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1269978948.jpg new file mode 100644 index 0000000..a6b7362 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1269978948.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1273632724.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1273632724.jpg new file mode 100644 index 0000000..9b5007b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1273632724.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1294917696.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1294917696.jpg new file mode 100644 index 0000000..a08e1d6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1294917696.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1321725916.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1321725916.jpg new file mode 100644 index 0000000..713daed Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1321725916.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1334130524.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1334130524.jpg new file mode 100644 index 0000000..bc28f71 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1334130524.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1339128595.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1339128595.jpg new file mode 100644 index 0000000..24edcf8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1339128595.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1345589532.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1345589532.jpg new file mode 100644 index 0000000..a23d945 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1345589532.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1356445571.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1356445571.jpg new file mode 100644 index 0000000..fcabb96 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1356445571.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1359883227.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1359883227.jpg new file mode 100644 index 0000000..33d0c50 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1359883227.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1394333608.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1394333608.jpg new file mode 100644 index 0000000..1f5793e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1394333608.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1415363827.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1415363827.jpg new file mode 100644 index 0000000..db1a4de Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1415363827.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1418953320.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1418953320.jpg new file mode 100644 index 0000000..f2c2e4d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1418953320.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1422189943.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1422189943.jpg new file mode 100644 index 0000000..01d6e83 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1422189943.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1425862560.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1425862560.jpg new file mode 100644 index 0000000..39d84a1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1425862560.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1454814118.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1454814118.jpg new file mode 100644 index 0000000..daee1f9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1454814118.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1462006618.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1462006618.jpg new file mode 100644 index 0000000..7f29fdd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1462006618.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1478779903.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1478779903.jpg new file mode 100644 index 0000000..4281dce Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1478779903.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1521584288.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1521584288.jpg new file mode 100644 index 0000000..92fa20a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1521584288.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1548245927.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1548245927.jpg new file mode 100644 index 0000000..be81c74 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1548245927.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1584311796.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1584311796.jpg new file mode 100644 index 0000000..7257751 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1584311796.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/160406838.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/160406838.jpg new file mode 100644 index 0000000..9b40ae8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/160406838.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1647124293.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1647124293.jpg new file mode 100644 index 0000000..ad4132a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1647124293.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/171469095.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/171469095.jpg new file mode 100644 index 0000000..713daed Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/171469095.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1719155080.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1719155080.jpg new file mode 100644 index 0000000..852c3de Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1719155080.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1728046590.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1728046590.jpg new file mode 100644 index 0000000..a4f0f1a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1728046590.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1738148743.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1738148743.jpg new file mode 100644 index 0000000..75e2104 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1738148743.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1763346489.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1763346489.jpg new file mode 100644 index 0000000..b67fc19 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1763346489.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1796718174.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1796718174.jpg new file mode 100644 index 0000000..1e5b741 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1796718174.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1816930071.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1816930071.jpg new file mode 100644 index 0000000..a895d2c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1816930071.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1823991302.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1823991302.jpg new file mode 100644 index 0000000..4103b17 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1823991302.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1825834668.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1825834668.jpg new file mode 100644 index 0000000..8216e78 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1825834668.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1832472182.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1832472182.jpg new file mode 100644 index 0000000..7a4ccdf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1832472182.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1832596584.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1832596584.jpg new file mode 100644 index 0000000..32d7b81 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1832596584.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1846058388.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1846058388.jpg new file mode 100644 index 0000000..12b1fc7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1846058388.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/185997462.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/185997462.jpg new file mode 100644 index 0000000..e3698bb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/185997462.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1874073604.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1874073604.jpg new file mode 100644 index 0000000..843ea01 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1874073604.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1901510232.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1901510232.jpg new file mode 100644 index 0000000..b024def Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1901510232.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/191072540.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/191072540.jpg new file mode 100644 index 0000000..07bb5b2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/191072540.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1935350790.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1935350790.jpg new file mode 100644 index 0000000..482fdc9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1935350790.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1983347559.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1983347559.jpg new file mode 100644 index 0000000..0a05e81 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1983347559.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1987262935.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1987262935.jpg new file mode 100644 index 0000000..b48b658 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/1987262935.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2051218754.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2051218754.jpg new file mode 100644 index 0000000..b67fdf4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2051218754.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2061892856.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2061892856.jpg new file mode 100644 index 0000000..d984c14 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2061892856.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2084848914.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2084848914.jpg new file mode 100644 index 0000000..869f36d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2084848914.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2090832627.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2090832627.jpg new file mode 100644 index 0000000..8a3c788 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2090832627.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2169380262.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2169380262.jpg new file mode 100644 index 0000000..815bb65 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2169380262.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2169571429.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2169571429.jpg new file mode 100644 index 0000000..480764a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2169571429.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2185247294.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2185247294.jpg new file mode 100644 index 0000000..6c19f15 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2185247294.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2192326388.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2192326388.jpg new file mode 100644 index 0000000..b04a0cd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2192326388.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2239627890.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2239627890.jpg new file mode 100644 index 0000000..695494c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2239627890.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2248745386.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2248745386.jpg new file mode 100644 index 0000000..b44ad07 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2248745386.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2248863880.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2248863880.jpg new file mode 100644 index 0000000..382993b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2248863880.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2369669861.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2369669861.jpg new file mode 100644 index 0000000..1bdbf46 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2369669861.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2406318045.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2406318045.jpg new file mode 100644 index 0000000..5fbb560 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2406318045.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2414601352.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2414601352.jpg new file mode 100644 index 0000000..7c1b437 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2414601352.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2417224603.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2417224603.jpg new file mode 100644 index 0000000..fa5456e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2417224603.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2426120505.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2426120505.jpg new file mode 100644 index 0000000..94c871e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2426120505.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2428121151.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2428121151.jpg new file mode 100644 index 0000000..e6b5d40 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2428121151.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/243118462.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/243118462.jpg new file mode 100644 index 0000000..07d22ef Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/243118462.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2433640468.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2433640468.jpg new file mode 100644 index 0000000..9282571 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2433640468.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2445055638.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2445055638.jpg new file mode 100644 index 0000000..8342a1d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2445055638.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/247248275.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/247248275.jpg new file mode 100644 index 0000000..9473e5c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/247248275.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2475650896.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2475650896.jpg new file mode 100644 index 0000000..a9659a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2475650896.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/252923735.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/252923735.jpg new file mode 100644 index 0000000..33046b9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/252923735.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/25538927.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/25538927.jpg new file mode 100644 index 0000000..e765fb1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/25538927.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2567322625.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2567322625.jpg new file mode 100644 index 0000000..e1b0313 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2567322625.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2607804644.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2607804644.jpg new file mode 100644 index 0000000..cdf3f14 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2607804644.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/261696203.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/261696203.jpg new file mode 100644 index 0000000..962be3b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/261696203.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2628667008.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2628667008.jpg new file mode 100644 index 0000000..6e6388f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2628667008.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2630608319.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2630608319.jpg new file mode 100644 index 0000000..0610f64 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2630608319.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/263103573.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/263103573.jpg new file mode 100644 index 0000000..5f8b3b8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/263103573.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2634347200.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2634347200.jpg new file mode 100644 index 0000000..bca50cf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2634347200.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2646565979.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2646565979.jpg new file mode 100644 index 0000000..9d49191 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2646565979.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2657313686.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2657313686.jpg new file mode 100644 index 0000000..e2ec477 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2657313686.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2665514251.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2665514251.jpg new file mode 100644 index 0000000..62d73c4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2665514251.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2665573801.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2665573801.jpg new file mode 100644 index 0000000..e09823e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2665573801.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2711287814.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2711287814.jpg new file mode 100644 index 0000000..feba907 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/2711287814.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/274107639.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/274107639.jpg new file mode 100644 index 0000000..b951479 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/274107639.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/276538827.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/276538827.jpg new file mode 100644 index 0000000..c6a381b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/276538827.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/284402839.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/284402839.jpg new file mode 100644 index 0000000..8b53e43 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/284402839.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/291170713.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/291170713.jpg new file mode 100644 index 0000000..5dff16c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/291170713.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/29600931.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/29600931.jpg new file mode 100644 index 0000000..f952bf7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/29600931.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/296728593.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/296728593.jpg new file mode 100644 index 0000000..2e00d51 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/296728593.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/305718025.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/305718025.jpg new file mode 100644 index 0000000..62cc090 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/305718025.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3065113788.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3065113788.jpg new file mode 100644 index 0000000..61fa8d7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3065113788.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3087230059.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3087230059.jpg new file mode 100644 index 0000000..5e4d142 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3087230059.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3096023144.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3096023144.jpg new file mode 100644 index 0000000..64da492 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3096023144.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3199802469.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3199802469.jpg new file mode 100644 index 0000000..bcd005e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3199802469.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3208615251.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3208615251.jpg new file mode 100644 index 0000000..285fa05 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3208615251.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3213712336.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3213712336.jpg new file mode 100644 index 0000000..e17ef20 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3213712336.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/328592742.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/328592742.jpg new file mode 100644 index 0000000..a9366ca Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/328592742.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3286054438.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3286054438.jpg new file mode 100644 index 0000000..8e88d1f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3286054438.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3289692539.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3289692539.jpg new file mode 100644 index 0000000..7817383 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3289692539.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3297371681.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3297371681.jpg new file mode 100644 index 0000000..4414bfa Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3297371681.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3306807790.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3306807790.jpg new file mode 100644 index 0000000..69bc43e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/3306807790.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/331856031.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/331856031.jpg new file mode 100644 index 0000000..5eae35e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/331856031.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/350012950.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/350012950.jpg new file mode 100644 index 0000000..ed6c3e5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/350012950.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/361341005.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/361341005.jpg new file mode 100644 index 0000000..3eea27e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/361341005.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/372302129.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/372302129.jpg new file mode 100644 index 0000000..3b203c7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/372302129.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/381670311.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/381670311.jpg new file mode 100644 index 0000000..4fa6a69 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/381670311.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/382896007.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/382896007.jpg new file mode 100644 index 0000000..957ccb7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/382896007.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/384468552.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/384468552.jpg new file mode 100644 index 0000000..7dcc0c4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/384468552.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/389138125.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/389138125.jpg new file mode 100644 index 0000000..38188d2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/389138125.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/394500669.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/394500669.jpg new file mode 100644 index 0000000..3bb2862 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/394500669.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/396348696.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/396348696.jpg new file mode 100644 index 0000000..d583e1a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/396348696.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/396903228.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/396903228.jpg new file mode 100644 index 0000000..7e338ef Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/396903228.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/399516587.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/399516587.jpg new file mode 100644 index 0000000..5a3d917 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/399516587.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/404961008.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/404961008.jpg new file mode 100644 index 0000000..710de10 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/404961008.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/407942945.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/407942945.jpg new file mode 100644 index 0000000..3a084e2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/407942945.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/417704967.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/417704967.jpg new file mode 100644 index 0000000..fec9f0d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/417704967.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/424409712.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/424409712.jpg new file mode 100644 index 0000000..e797105 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/424409712.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/437628393.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/437628393.jpg new file mode 100644 index 0000000..dbede6f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/437628393.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/441534737.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/441534737.jpg new file mode 100644 index 0000000..0ee4088 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/441534737.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/449175426.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/449175426.jpg new file mode 100644 index 0000000..0af846c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/449175426.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/455153183.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/455153183.jpg new file mode 100644 index 0000000..81b0ba6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/455153183.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/462239613.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/462239613.jpg new file mode 100644 index 0000000..1cdd435 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/462239613.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/474216826.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/474216826.jpg new file mode 100644 index 0000000..d203d17 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/474216826.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/477807875.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/477807875.jpg new file mode 100644 index 0000000..0074b39 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/477807875.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/477973848.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/477973848.jpg new file mode 100644 index 0000000..c80a947 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/477973848.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/491520296.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/491520296.jpg new file mode 100644 index 0000000..2550fee Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/491520296.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/497178033.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/497178033.jpg new file mode 100644 index 0000000..cb0f3a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/497178033.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/499468502.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/499468502.jpg new file mode 100644 index 0000000..0173d0c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/499468502.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/504153435.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/504153435.jpg new file mode 100644 index 0000000..42dcc20 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/504153435.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/514993413.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/514993413.jpg new file mode 100644 index 0000000..465983e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/514993413.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/51601559.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/51601559.jpg new file mode 100644 index 0000000..bb941b7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/51601559.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/524186683.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/524186683.jpg new file mode 100644 index 0000000..fc6e47a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/524186683.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/531420711.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/531420711.jpg new file mode 100644 index 0000000..7ea53ae Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/531420711.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/543313585.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/543313585.jpg new file mode 100644 index 0000000..99065eb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/543313585.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/544594054.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/544594054.jpg new file mode 100644 index 0000000..a119bb6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/544594054.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/545184877.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/545184877.jpg new file mode 100644 index 0000000..c3fb589 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/545184877.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/546054758.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/546054758.jpg new file mode 100644 index 0000000..5a1b5d1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/546054758.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/549357392.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/549357392.jpg new file mode 100644 index 0000000..50e203e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/549357392.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/550435285.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/550435285.jpg new file mode 100644 index 0000000..d53548e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/550435285.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/550551182.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/550551182.jpg new file mode 100644 index 0000000..2fb0059 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/550551182.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/55106879.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/55106879.jpg new file mode 100644 index 0000000..6aa2a1c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/55106879.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/553924454.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/553924454.jpg new file mode 100644 index 0000000..b044ee0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/553924454.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/570663326.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/570663326.jpg new file mode 100644 index 0000000..d623986 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/570663326.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/575908312.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/575908312.jpg new file mode 100644 index 0000000..807af68 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/575908312.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/598105607.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/598105607.jpg new file mode 100644 index 0000000..93984aa Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/598105607.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/601668065.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/601668065.jpg new file mode 100644 index 0000000..ac42ae7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/601668065.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/604419992.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/604419992.jpg new file mode 100644 index 0000000..f7e3f76 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/604419992.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/610632170.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/610632170.jpg new file mode 100644 index 0000000..28ce33c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/610632170.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/623959830.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/623959830.jpg new file mode 100644 index 0000000..2454cb6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/623959830.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/630335515.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/630335515.jpg new file mode 100644 index 0000000..5eec02f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/630335515.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/644201934.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/644201934.jpg new file mode 100644 index 0000000..a8ba734 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/644201934.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/645680902.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/645680902.jpg new file mode 100644 index 0000000..4e8568b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/645680902.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/648401136.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/648401136.jpg new file mode 100644 index 0000000..a674b13 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/648401136.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/673276676.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/673276676.jpg new file mode 100644 index 0000000..241329f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/673276676.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/690025634.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/690025634.jpg new file mode 100644 index 0000000..ff72dec Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/690025634.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/704664751.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/704664751.jpg new file mode 100644 index 0000000..1818ac7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/704664751.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/704709014.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/704709014.jpg new file mode 100644 index 0000000..71c654b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/704709014.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/706967911.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/706967911.jpg new file mode 100644 index 0000000..2130c35 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/706967911.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/719870850.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/719870850.jpg new file mode 100644 index 0000000..3eeb861 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/719870850.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/724453866.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/724453866.jpg new file mode 100644 index 0000000..df511f5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/724453866.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/727445654.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/727445654.jpg new file mode 100644 index 0000000..4e241ae Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/727445654.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/729241368.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/729241368.jpg new file mode 100644 index 0000000..4b8a63f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/729241368.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/739771180.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/739771180.jpg new file mode 100644 index 0000000..5bb25cc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/739771180.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/752579115.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/752579115.jpg new file mode 100644 index 0000000..aee425d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/752579115.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/761231651.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/761231651.jpg new file mode 100644 index 0000000..6e6f72e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/761231651.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/764209949.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/764209949.jpg new file mode 100644 index 0000000..2c0f71c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/764209949.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/771704158.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/771704158.jpg new file mode 100644 index 0000000..0ebb713 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/771704158.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/785724717.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/785724717.jpg new file mode 100644 index 0000000..ef30701 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/785724717.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/804104317.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/804104317.jpg new file mode 100644 index 0000000..e4c5494 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/804104317.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/804466834.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/804466834.jpg new file mode 100644 index 0000000..29a24ff Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/804466834.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/807648230.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/807648230.jpg new file mode 100644 index 0000000..ba31f60 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/807648230.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/815243941.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/815243941.jpg new file mode 100644 index 0000000..eb236f6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/815243941.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/815979951.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/815979951.jpg new file mode 100644 index 0000000..b1adb41 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/815979951.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/820489487.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/820489487.jpg new file mode 100644 index 0000000..6df1cc0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/820489487.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/836197203.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/836197203.jpg new file mode 100644 index 0000000..9711d67 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/836197203.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/836973794.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/836973794.jpg new file mode 100644 index 0000000..ba31f60 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/836973794.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/837316140.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/837316140.jpg new file mode 100644 index 0000000..98dc92d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/837316140.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/838432469.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/838432469.jpg new file mode 100644 index 0000000..02838ca Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/838432469.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/838952446.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/838952446.jpg new file mode 100644 index 0000000..eef8034 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/838952446.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/839362009.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/839362009.jpg new file mode 100644 index 0000000..f8b23b6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/839362009.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/840788452.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/840788452.jpg new file mode 100644 index 0000000..976bdaf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/840788452.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/843366923.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/843366923.jpg new file mode 100644 index 0000000..e696a59 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/843366923.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/845667840.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/845667840.jpg new file mode 100644 index 0000000..21002f4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/845667840.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/859311284.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/859311284.jpg new file mode 100644 index 0000000..3f458fc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/859311284.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/861137091.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/861137091.jpg new file mode 100644 index 0000000..fa39d47 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/861137091.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/865026025.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/865026025.jpg new file mode 100644 index 0000000..7817383 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/865026025.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/874390484.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/874390484.jpg new file mode 100644 index 0000000..0f5d64e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/874390484.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/876502611.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/876502611.jpg new file mode 100644 index 0000000..0c7fb93 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/876502611.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/879028931.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/879028931.jpg new file mode 100644 index 0000000..1264364 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/879028931.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/894517787.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/894517787.jpg new file mode 100644 index 0000000..d75b4d4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/894517787.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/916277662.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/916277662.jpg new file mode 100644 index 0000000..62781b8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/916277662.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/916597274.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/916597274.jpg new file mode 100644 index 0000000..786a11d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/916597274.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/925488243.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/925488243.jpg new file mode 100644 index 0000000..e84d591 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/925488243.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/932788548.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/932788548.jpg new file mode 100644 index 0000000..83abdd7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/932788548.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/937751466.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/937751466.jpg new file mode 100644 index 0000000..eb28017 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/937751466.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/939839415.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/939839415.jpg new file mode 100644 index 0000000..1cc49c6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/939839415.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/940370567.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/940370567.jpg new file mode 100644 index 0000000..df85328 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/940370567.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/940724946.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/940724946.jpg new file mode 100644 index 0000000..4b34e3e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/940724946.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/944092892.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/944092892.jpg new file mode 100644 index 0000000..b9bbb5b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/944092892.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/944437590.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/944437590.jpg new file mode 100644 index 0000000..0f8afa1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/944437590.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/949711310.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/949711310.jpg new file mode 100644 index 0000000..9536a67 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/949711310.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/951159498.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/951159498.jpg new file mode 100644 index 0000000..ffc5bf0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/951159498.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/961368854.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/961368854.jpg new file mode 100644 index 0000000..db36c29 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/961368854.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/962019527.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/962019527.jpg new file mode 100644 index 0000000..940f643 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/962019527.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/969904947.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/969904947.jpg new file mode 100644 index 0000000..db94314 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/969904947.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/971189701.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/971189701.jpg new file mode 100644 index 0000000..494ef8e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/971189701.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/972474813.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/972474813.jpg new file mode 100644 index 0000000..07bb5b2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/972474813.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/987144184.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/987144184.jpg new file mode 100644 index 0000000..5366c14 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/987144184.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/992034472.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/992034472.jpg new file mode 100644 index 0000000..e566e87 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/992034472.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/setu.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/setu.png new file mode 100644 index 0000000..078bcee Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image/setu.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/akai/akai.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/akai/akai.jpg new file mode 100644 index 0000000..67afa87 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/akai/akai.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/akai/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/akai/config.ini new file mode 100644 index 0000000..b7e6029 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/akai/config.ini @@ -0,0 +1,9 @@ +{ + "name":"akai", + "font_max":220, + "font_size":40, + "font_center_x":125, + "font_center_y":220, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/alice/alice.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/alice/alice.jpg new file mode 100644 index 0000000..05fed34 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/alice/alice.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/alice/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/alice/config.ini new file mode 100644 index 0000000..766d2bd --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/alice/config.ini @@ -0,0 +1,9 @@ +{ + "name":"alice", + "font_max":380, + "font_size":65, + "font_center_x":200, + "font_center_y":488, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/aqua/aqua.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/aqua/aqua.jpg new file mode 100644 index 0000000..ab7ee55 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/aqua/aqua.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/aqua/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/aqua/config.ini new file mode 100644 index 0000000..f95edc0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/aqua/config.ini @@ -0,0 +1,9 @@ +{ + "name":"aqua", + "font_max":220, + "font_size":25, + "font_center_x":120, + "font_center_y":263, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/bieming/name.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/bieming/name.ini new file mode 100644 index 0000000..a2cdc4e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/bieming/name.ini @@ -0,0 +1,35 @@ +心心 akai +阿夸 aqua +臭鼬 chouyou +好学 haoxue +黑手 heishou +逗乐了 heishou_four +熊猫1 initial +奥利给 jumozhanjiang +狗妈1 kaguranana +狗妈2 kaguranana_1 +狗妈3 kaguranana_2 +马自立1 matsuri +马自立2 matsuri_1 +kora katsuna +珂学家 keduoli +财布 mea +熊猫2 panda_shuai +熊猫3 panda_tutou +守夜冠军 qichuang +恶臭 xianbei +我爱你 jupai +吹雪1 fbk1 +吹雪2 fbk2 +peko peko +星姐 xingjie +粽子1 lxy1 +粽子2 lxy2 +爱丽丝 alice +猫猫 serena +猪 kasumi +猫猫猫 mengheqianli +gvc gbf +猫 mao +ksm ksm +栞栞 kan \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/chouyou/chouyou.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/chouyou/chouyou.jpg new file mode 100644 index 0000000..01bf4f0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/chouyou/chouyou.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/chouyou/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/chouyou/config.ini new file mode 100644 index 0000000..30cc73a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/chouyou/config.ini @@ -0,0 +1,9 @@ +{ + "name":"chouyou", + "font_max":180, + "font_size":30, + "font_center_x":100, + "font_center_y":180, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/fbk1/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/fbk1/config.ini new file mode 100644 index 0000000..e2bca37 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/fbk1/config.ini @@ -0,0 +1,9 @@ +{ + "name":"fbk1", + "font_max":280, + "font_size":40, + "font_center_x":151, + "font_center_y":290, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/fbk1/fbk1.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/fbk1/fbk1.jpg new file mode 100644 index 0000000..d629a10 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/fbk1/fbk1.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/fbk2/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/fbk2/config.ini new file mode 100644 index 0000000..b938dd6 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/fbk2/config.ini @@ -0,0 +1,9 @@ +{ + "name":"fbk2", + "font_max":346, + "font_size":50, + "font_center_x":193, + "font_center_y":385, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/fbk2/fbk2.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/fbk2/fbk2.jpg new file mode 100644 index 0000000..dadc268 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/fbk2/fbk2.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/gbf/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/gbf/config.ini new file mode 100644 index 0000000..9cb589f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/gbf/config.ini @@ -0,0 +1,9 @@ +{ + "name":"gbf", + "font_max":251, + "font_size":40, + "font_center_x":135, + "font_center_y":290, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/gbf/gbf.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/gbf/gbf.jpg new file mode 100644 index 0000000..98bfa1b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/gbf/gbf.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/haoxue/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/haoxue/config.ini new file mode 100644 index 0000000..6c5898a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/haoxue/config.ini @@ -0,0 +1,9 @@ +{ + "name":"haoxue", + "font_max":460, + "font_size":40, + "font_center_x":250, + "font_center_y":433, + "color":"blue", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/haoxue/haoxue.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/haoxue/haoxue.jpg new file mode 100644 index 0000000..9fddde5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/haoxue/haoxue.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/heishou/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/heishou/config.ini new file mode 100644 index 0000000..230cce8 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/heishou/config.ini @@ -0,0 +1,9 @@ +{ + "name":"heishou", + "font_max":240, + "font_size":40, + "font_center_x":150, + "font_center_y":262, + "color":"white", + "font_sub":10 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/heishou/heishou.JPG b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/heishou/heishou.JPG new file mode 100644 index 0000000..240b31f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/heishou/heishou.JPG differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/heishou_four/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/heishou_four/config.ini new file mode 100644 index 0000000..c0a7ac3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/heishou_four/config.ini @@ -0,0 +1,9 @@ +{ + "name":"heishou_four", + "font_max":380, + "font_size":50, + "font_center_x":250, + "font_center_y":250, + "color":"white", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/heishou_four/heishou_four.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/heishou_four/heishou_four.jpg new file mode 100644 index 0000000..db65c32 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/heishou_four/heishou_four.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/image/.gitkeep b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/image/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/initial/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/initial/config.ini new file mode 100644 index 0000000..424b5c0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/initial/config.ini @@ -0,0 +1,9 @@ +{ + "name":"initial", + "font_max":310, + "font_size":55, + "font_center_x":175, + "font_center_y":313, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/initial/initial.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/initial/initial.jpg new file mode 100644 index 0000000..9d8ae08 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/initial/initial.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/initial/panda_normal.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/initial/panda_normal.jpg new file mode 100644 index 0000000..9d8ae08 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/initial/panda_normal.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/initial/xiongmao.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/initial/xiongmao.jpg new file mode 100644 index 0000000..d1e1e6d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/initial/xiongmao.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jinghua/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jinghua/config.ini new file mode 100644 index 0000000..f0f2307 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jinghua/config.ini @@ -0,0 +1,9 @@ +{ + "name":"jinghua", + "font_max":150, + "font_size":20, + "font_center_x":80, + "font_center_y":150, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jinghua/jinghua.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jinghua/jinghua.jpg new file mode 100644 index 0000000..f5c0555 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jinghua/jinghua.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jumozhanjiang/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jumozhanjiang/config.ini new file mode 100644 index 0000000..128e846 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jumozhanjiang/config.ini @@ -0,0 +1,9 @@ +{ + "name":"jumozhanjiang", + "font_max":340, + "font_size":60, + "font_center_x":200, + "font_center_y":465, + "color":"white", + "font_sub":10 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jumozhanjiang/jumozhanjiang.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jumozhanjiang/jumozhanjiang.jpg new file mode 100644 index 0000000..f503454 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jumozhanjiang/jumozhanjiang.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jupai/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jupai/config.ini new file mode 100644 index 0000000..3b6721c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jupai/config.ini @@ -0,0 +1,9 @@ +{ + "name":"jupai", + "font_max":380, + "font_size":80, + "font_center_x":400, + "font_center_y":650, + "color":"black", + "font_sub":10 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jupai/jupai.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jupai/jupai.jpg new file mode 100644 index 0000000..9f6380c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/jupai/jupai.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana/config.ini new file mode 100644 index 0000000..5eac9ce --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana/config.ini @@ -0,0 +1,9 @@ +{ + "name":"kaguranana", + "font_max":340, + "font_size":40, + "font_center_x":200, + "font_center_y":405, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana/kaguranana.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana/kaguranana.jpg new file mode 100644 index 0000000..d50a2b2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana/kaguranana.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana_1/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana_1/config.ini new file mode 100644 index 0000000..a1e7a1f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana_1/config.ini @@ -0,0 +1,9 @@ +{ + "name":"kaguranana_1", + "font_max":360, + "font_size":40, + "font_center_x":200, + "font_center_y":275, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana_1/kaguranana_1.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana_1/kaguranana_1.jpg new file mode 100644 index 0000000..067c6d1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana_1/kaguranana_1.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana_2/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana_2/config.ini new file mode 100644 index 0000000..10599db --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana_2/config.ini @@ -0,0 +1,9 @@ +{ + "name":"kaguranana_2", + "font_max":615, + "font_size":70, + "font_center_x":327, + "font_center_y":645, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana_2/kaguranana_2.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana_2/kaguranana_2.jpg new file mode 100644 index 0000000..bab9ce7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kaguranana_2/kaguranana_2.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kan/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kan/config.ini new file mode 100644 index 0000000..193d8c7 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kan/config.ini @@ -0,0 +1,9 @@ +{ + "name":"kan", + "font_max":170, + "font_size":20, + "font_center_x":90, + "font_center_y":171, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kan/kan.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kan/kan.jpg new file mode 100644 index 0000000..f3e2015 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kan/kan.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kasumi/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kasumi/config.ini new file mode 100644 index 0000000..88303fb --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kasumi/config.ini @@ -0,0 +1,9 @@ +{ + "name":"kasumi", + "font_max":323, + "font_size":60, + "font_center_x":186, + "font_center_y":345, + "color":"white", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kasumi/kasumi.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kasumi/kasumi.jpg new file mode 100644 index 0000000..9694b95 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/kasumi/kasumi.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/katsuna/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/katsuna/config.ini new file mode 100644 index 0000000..efe5803 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/katsuna/config.ini @@ -0,0 +1,9 @@ +{ + "name":"katsuna", + "font_max":230, + "font_size":35, + "font_center_x":125, + "font_center_y":278, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/katsuna/katsuna.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/katsuna/katsuna.jpg new file mode 100644 index 0000000..8151ece Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/katsuna/katsuna.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/keduoli/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/keduoli/config.ini new file mode 100644 index 0000000..04ffe84 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/keduoli/config.ini @@ -0,0 +1,9 @@ +{ + "name":"keduoli", + "font_max":180, + "font_size":25, + "font_center_x":100, + "font_center_y":223, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/keduoli/keduoli.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/keduoli/keduoli.jpg new file mode 100644 index 0000000..c8561a0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/keduoli/keduoli.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/ksm/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/ksm/config.ini new file mode 100644 index 0000000..98218f4 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/ksm/config.ini @@ -0,0 +1,9 @@ +{ + "name":"ksm", + "font_max":469, + "font_size":50, + "font_center_x":254, + "font_center_y":320, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/ksm/ksm.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/ksm/ksm.jpg new file mode 100644 index 0000000..36af46e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/ksm/ksm.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/lxy1/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/lxy1/config.ini new file mode 100644 index 0000000..d4b5708 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/lxy1/config.ini @@ -0,0 +1,9 @@ +{ + "name":"lxy1", + "font_max":460, + "font_size":70, + "font_center_x":250, + "font_center_y":535, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/lxy1/lxy1.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/lxy1/lxy1.jpg new file mode 100644 index 0000000..3013941 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/lxy1/lxy1.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/lxy2/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/lxy2/config.ini new file mode 100644 index 0000000..452bd68 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/lxy2/config.ini @@ -0,0 +1,9 @@ +{ + "name":"lxy2", + "font_max":460, + "font_size":65, + "font_center_x":250, + "font_center_y":458, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/lxy2/lxy2.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/lxy2/lxy2.jpg new file mode 100644 index 0000000..94f75bf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/lxy2/lxy2.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mao/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mao/config.ini new file mode 100644 index 0000000..e39e1a5 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mao/config.ini @@ -0,0 +1,9 @@ +{ + "name":"mao", + "font_max":464, + "font_size":80, + "font_center_x":252, + "font_center_y":550, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mao/mao.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mao/mao.jpg new file mode 100644 index 0000000..145b927 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mao/mao.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/matsuri/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/matsuri/config.ini new file mode 100644 index 0000000..9b2783c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/matsuri/config.ini @@ -0,0 +1,9 @@ +{ + "name":"matsuri", + "font_max":180, + "font_size":35, + "font_center_x":100, + "font_center_y":195, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/matsuri/matsuri.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/matsuri/matsuri.jpg new file mode 100644 index 0000000..28ace9a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/matsuri/matsuri.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/matsuri_1/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/matsuri_1/config.ini new file mode 100644 index 0000000..404cc3a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/matsuri_1/config.ini @@ -0,0 +1,9 @@ +{ + "name":"matsuri_1", + "font_max":230, + "font_size":25, + "font_center_x":125, + "font_center_y":233, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/matsuri_1/matsuri_1.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/matsuri_1/matsuri_1.jpg new file mode 100644 index 0000000..c955784 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/matsuri_1/matsuri_1.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mea/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mea/config.ini new file mode 100644 index 0000000..a8ad1d3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mea/config.ini @@ -0,0 +1,9 @@ +{ + "name":"mea", + "font_max":380, + "font_size":40, + "font_center_x":200, + "font_center_y":280, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mea/mea.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mea/mea.jpg new file mode 100644 index 0000000..2acfd8e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mea/mea.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mengheqianli/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mengheqianli/config.ini new file mode 100644 index 0000000..60aa3ff --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mengheqianli/config.ini @@ -0,0 +1,9 @@ +{ + "name":"mengheqianli", + "font_max":250, + "font_size":30, + "font_center_x":135, + "font_center_y":190, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mengheqianli/mengheqianli.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mengheqianli/mengheqianli.jpg new file mode 100644 index 0000000..f0581ae Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/mengheqianli/mengheqianli.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/panda_shuai/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/panda_shuai/config.ini new file mode 100644 index 0000000..9c1cd0a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/panda_shuai/config.ini @@ -0,0 +1,9 @@ +{ + "name":"panda_shuai", + "font_max":170, + "font_size":35, + "font_center_x":100, + "font_center_y":173, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/panda_shuai/panda_shuai.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/panda_shuai/panda_shuai.jpg new file mode 100644 index 0000000..ec759c6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/panda_shuai/panda_shuai.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/panda_tutou/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/panda_tutou/config.ini new file mode 100644 index 0000000..3e934ad --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/panda_tutou/config.ini @@ -0,0 +1,9 @@ +{ + "name":"panda_tutou", + "font_max":160, + "font_size":40, + "font_center_x":100, + "font_center_y":170, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/panda_tutou/panda_tutou.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/panda_tutou/panda_tutou.jpg new file mode 100644 index 0000000..1d2aba7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/panda_tutou/panda_tutou.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/peko/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/peko/config.ini new file mode 100644 index 0000000..0455fff --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/peko/config.ini @@ -0,0 +1,9 @@ +{ + "name":"peko", + "font_max":460, + "font_size":90, + "font_center_x":250, + "font_center_y":485, + "color":"black", + "font_sub":10 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/peko/peko.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/peko/peko.jpg new file mode 100644 index 0000000..f59f9b6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/peko/peko.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/qichuang/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/qichuang/config.ini new file mode 100644 index 0000000..01ad03b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/qichuang/config.ini @@ -0,0 +1,9 @@ +{ + "name":"qichuang", + "font_max":440, + "font_size":70, + "font_center_x":250, + "font_center_y":80, + "color":"black", + "font_sub":10 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/qichuang/qichuang.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/qichuang/qichuang.jpg new file mode 100644 index 0000000..429971a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/qichuang/qichuang.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/qqdata/.gitignore b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/qqdata/.gitignore new file mode 100644 index 0000000..86d0cb2 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/qqdata/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/serena/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/serena/config.ini new file mode 100644 index 0000000..6ab3341 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/serena/config.ini @@ -0,0 +1,9 @@ +{ + "name":"serena", + "font_max":470, + "font_size":90, + "font_center_x":250, + "font_center_y":370, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/serena/serena.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/serena/serena.jpg new file mode 100644 index 0000000..a9f6582 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/serena/serena.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/test/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/test/config.ini new file mode 100644 index 0000000..6f56662 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/test/config.ini @@ -0,0 +1,9 @@ +{ + "name":"xiongmao", + "font_max":320, + "font_size":40, + "font_center_x":200, + "font_center_y":350, + "color":"black", + "font_sub":10 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/test/xiongmao.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/test/xiongmao.jpg new file mode 100644 index 0000000..d1e1e6d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/test/xiongmao.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/xianbei/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/xianbei/config.ini new file mode 100644 index 0000000..e58e6ed --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/xianbei/config.ini @@ -0,0 +1,9 @@ +{ + "name":"xianbei", + "font_max":280, + "font_size":40, + "font_center_x":150, + "font_center_y":290, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/xianbei/xianbei.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/xianbei/xianbei.jpg new file mode 100644 index 0000000..c3e7e6a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/xianbei/xianbei.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/xingjie/config.ini b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/xingjie/config.ini new file mode 100644 index 0000000..4ff54ee --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/xingjie/config.ini @@ -0,0 +1,9 @@ +{ + "name":"xingjie", + "font_max":180, + "font_size":25, + "font_center_x":100, + "font_center_y":253, + "color":"black", + "font_sub":5 +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/xingjie/xingjie.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/xingjie/xingjie.jpg new file mode 100644 index 0000000..90379a9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/image-generate/image_data/xingjie/xingjie.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/kancolle/quick/kokkoro_stamp.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/kancolle/quick/kokkoro_stamp.png new file mode 100644 index 0000000..7e63710 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/kancolle/quick/kokkoro_stamp.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/kancolle/quick/菱饼2020.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/kancolle/quick/菱饼2020.jpg new file mode 100644 index 0000000..a9a93f0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/kancolle/quick/菱饼2020.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/kancolle/quick/驱逐改二特殊装备早见表.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/kancolle/quick/驱逐改二特殊装备早见表.jpg new file mode 100644 index 0000000..6315beb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/kancolle/quick/驱逐改二特殊装备早见表.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/kokkoro_stamp.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/kokkoro_stamp.png new file mode 100644 index 0000000..7e63710 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/kokkoro_stamp.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/laopo.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/laopo.jpg new file mode 100644 index 0000000..6dff106 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/laopo.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/longwang/dk_is_me.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/longwang/dk_is_me.jpg new file mode 100644 index 0000000..11bb0b8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/longwang/dk_is_me.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/love.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/love.jpg new file mode 100644 index 0000000..5fe53e3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/love.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/newyearburst.gif b/hexi/plugins/nonebot_plugin_group_tools/res/img/newyearburst.gif new file mode 100644 index 0000000..659cb59 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/newyearburst.gif differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/newyearburst.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/newyearburst.jpg new file mode 100644 index 0000000..9146be9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/newyearburst.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/nmsl.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/nmsl.jpg new file mode 100644 index 0000000..0290118 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/nmsl.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/font/Mamelon.otf b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/font/Mamelon.otf new file mode 100644 index 0000000..fcaabb8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/font/Mamelon.otf differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/font/sakura.ttf b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/font/sakura.ttf new file mode 100644 index 0000000..f0bd372 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/font/sakura.ttf differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/fortune/copywriting.json b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/fortune/copywriting.json new file mode 100644 index 0000000..ff4e723 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/fortune/copywriting.json @@ -0,0 +1,662 @@ +{ + "copywriting": [ + { + "charaid": ["1", "2"], + "_name": "凯露", + "type": [ + { + "good-luck": 10, + "content": "仅限今天而已!别想多了!!" + }, + { + "good-luck": 8, + "content": "宜抽卡﹁十连五彩不是梦﹂" + }, + { + "good-luck": 7, + "content": "宜刷本﹁碎片装备一大堆!你是托吧﹂" + }, + { + "good-luck": 6, + "content": "还不学习吗,殺すわよっ!" + }, + { + "good-luck": -6, + "content": "忌抽卡﹁这个池子不行的,没有3x啊﹂" + }, + { + "good-luck": -9, + "content": "ヤバイわよ!钱包又没了" + }, + { + "good-luck": 5, + "content": "双场排名飞升" + }, + { + "good-luck": -7, + "content": "伊莉亚又暴击了︵对自己" + }, + { + "good-luck": -8, + "content": "害学习呢,你被梯了" + }, + { + "good-luck": -10, + "content": "遇到困难,睡大觉" + }, + { + "good-luck": 24, + "content": "金运不错,所以你能借钱给我吗?" + } + ] + }, + { + "charaid": ["3", "4"], + "_name": "初音", + "type": [ + { + "good-luck": 10, + "content": "Kira☆今天运气绝佳♫" + }, + { + "good-luck": 9, + "content": "睡个午觉可以变清爽一点☆" + }, + { + "good-luck": 4, + "content": "醒醒你体力满了!" + }, + { + "good-luck": -6, + "content": "梦到熬夜赶ddl" + }, + { + "good-luck": -9, + "content": "用超能力的话,运气会不会好一点呢" + }, + { + "good-luck": 20, + "content": "ハツネちゃんの应援だよ!一切都会好起来的" + }, + { + "good-luck": 25, + "content": "叫上栞栞一起学习吧" + } + ] + }, + { + "charaid": ["5", "6"], + "_name": "杏奈", + "type": [ + { + "good-luck": 8, + "content": "氷狂凍獄絶零破!︵宜JJC" + }, + { + "good-luck": 7, + "content": "我ら煉獄に舞いし一陣の疾風︵宜现充" + }, + { + "good-luck": 4, + "content": "就到此为止了吗…︵宜摸鱼" + }, + { + "good-luck": -6, + "content": "冥 空 天 升︵会被演" + }, + { + "good-luck": -8, + "content": "会被提起黑历史" + }, + { + "good-luck": 21, + "content": "邪王真眼、我会追上你的︵宜表白" + } + ] + }, + { + "charaid": ["7", "8"], + "_name": "优妮", + "type": [ + { + "good-luck": 7, + "content": "宜学习﹁今天去图书馆自习吗﹂" + }, + { + "good-luck": 5, + "content": "宜击剑﹁讨论人性与哲学光辉﹂" + }, + { + "good-luck": 4, + "content": "论文的事,需要帮忙吗" + }, + { + "good-luck": -6, + "content": "会思考怎么拆对手到超时" + }, + { + "good-luck": -7, + "content": "会忘记每日十连" + }, + { + "good-luck": -9, + "content": "忌表白﹁啊啊,浓咖啡真好喝﹂" + }, + { + "good-luck": 26, + "content": "見たまえ同志!これこそわ﹁ユニちゃんズ﹂!" + } + ] + }, + { + "charaid": ["9", "10"], + "_name": "琪爱儿", + "type": [ + { + "good-luck": 9, + "content": "切噜☆♪" + }, + { + "good-luck": 6, + "content": "宜水群﹁你就是龙王切噜♪﹂" + }, + { + "good-luck": 4, + "content": "末小吉就是说你今天也没什么运气切噜噜" + }, + { + "good-luck": -6, + "content": "忌装弱﹁因为先辈你本来就很弱切噜♪﹂" + }, + { + "good-luck": -9, + "content": "切噜噜噜噜♪困难本0碎切噜!" + }, + { + "good-luck": 27, + "content": "总是萌混过关是交不到朋友的切噜☆" + } + ] + }, + { + "charaid": ["11", "12"], + "_name": "克萝依", + "type": [ + { + "good-luck": 10, + "content": "哦|偶尔也会有这样的日子呢,偶尔就是了" + }, + { + "good-luck": 6, + "content": "JJC啊,没几个人打你的" + }, + { + "good-luck": 5, + "content": "小心拖延症" + }, + { + "good-luck": -7, + "content": "会跨服聊天" + }, + { + "good-luck": -8, + "content": "水群会冷场" + }, + { + "good-luck": 23, + "content": "工作总是遇到奇怪的人" + } + ] + }, + { + "charaid": ["13", "14"], + "_name": "静流", + "type": [ + { + "good-luck": 9, + "content": "会十连出碎片" + }, + { + "good-luck": 8, + "content": "宜熬夜爆肝" + }, + { + "good-luck": 5, + "content": "宜出刀﹁希望弟弟暴击﹂" + }, + { + "good-luck": -6, + "content": "抽卡会+19" + }, + { + "good-luck": -8, + "content": "没什么精神,要姐姐的头槌清醒下吗♡" + }, + { + "good-luck": 21, + "content": "偷跑才是王道!︵冬马&静流" + } + ] + }, + { + "charaid": ["15", "16"], + "_name": "惠理子", + "type": [ + { + "good-luck": 10, + "content": "诸事皆宜" + }, + { + "good-luck": 7, + "content": "宜现充﹁会遇到命 运 之 人﹂" + }, + { + "good-luck": -7, + "content": "你就是记仇碎钻回刺人" + }, + { + "good-luck": -8, + "content": "忌dd﹁别的女人就这么吸引你吗﹂" + }, + { + "good-luck": -10, + "content": "今天……一直会在你身后的" + }, + { + "good-luck": 22, + "content": "爱情也需要调味料︵电脑配件" + } + ] + }, + { + "charaid": ["17", "18"], + "_name": "优花梨", + "type": [ + { + "good-luck": 8, + "content": "宜社畜﹁你就是戒酒后的优花梨﹂" + }, + { + "good-luck": 7, + "content": "宜摸鱼﹁我就再喝亿杯﹂" + }, + { + "good-luck": 4, + "content": "宜追番﹁守护最好的二刺螈﹂" + }, + { + "good-luck": -7, + "content": "忌现充﹁现充爆炸吧﹂" + }, + { + "good-luck": -8, + "content": "優花梨,为什么不喝呢~♫" + }, + { + "good-luck": 20, + "content": "运气用在了没用的地方" + } + ] + }, + { + "charaid": ["19", "20"], + "_name": "空花", + "type": [ + { + "good-luck": 9, + "content": "宜摸鱼﹁空花的妄想停不下来﹂" + }, + { + "good-luck": 7, + "content": "宜瑟图﹁群涩批时不时来暴露xp﹂" + }, + { + "good-luck": -6, + "content": "忌社畜﹁会被当成抖M﹂" + }, + { + "good-luck": -7, + "content": "忌水群﹁会被放置PLAY﹂" + }, + { + "good-luck": -8, + "content": "忌瑟图﹁哦淦老兄你xp好怪啊﹂" + }, + { + "good-luck": 26, + "content": "摩多摩多摩多~" + } + ] + }, + { + "charaid": ["21", "22"], + "_name": "忍", + "type": [ + { + "good-luck": 8, + "content": "父亲说这个占卜一点都不准。。。" + }, + { + "good-luck": 6, + "content": "宜DD﹁骷髅老爹也想栞栞!﹂" + }, + { + "good-luck": 4, + "content": "宜对线﹁你就是送爸人﹂" + }, + { + "good-luck": -7, + "content": "忌抽卡﹁父亲的占卜罢了,你身后是有挺多怨灵的﹂" + }, + { + "good-luck": -9, + "content": "忌表白﹁会得骷髅老爹真传﹂" + }, + { + "good-luck": 20, + "content": "今天你身边也是有各种各样的幽灵在呢" + } + ] + }, + { + "charaid": ["23", "24"], + "_name": "真步", + "type": [ + { + "good-luck": 10, + "content": "みらくるもほりん、くるりんぱ" + }, + { + "good-luck": 7, + "content": "宜刷本﹁这个是真步真步N3魔法!﹂" + }, + { + "good-luck": 5, + "content": "宜膜佬﹁?这真步河里﹂" + }, + { + "good-luck": -6, + "content": "宜复读﹁真步真步教○脑开始﹂" + }, + { + "good-luck": -7, + "content": "忌竞技场﹁那么,答案就只有一个了!﹂" + }, + { + "good-luck": 20, + "content": "咕噜灵波~" + } + ] + }, + { + "charaid": ["25", "26"], + "_name": "茜里", + "type": [ + { + "good-luck": 6, + "content": "宜出游﹁诶诶要在外面吗﹂" + }, + { + "good-luck": 5, + "content": "宜运动﹁这样的、太激烈了嗯﹂" + }, + { + "good-luck": 4, + "content": "那里,已经满满的了︵指体力" + }, + { + "good-luck": -7, + "content": "明明还是早上就要从后面。。。︵打回前排" + }, + { + "good-luck": -9, + "content": "忌瑟图﹁是谁害想着开车呢爪巴﹂" + }, + { + "good-luck": 21, + "content": "这种事,就是两个人一起会变舒服︵心情上︶的对吧?" + } + ] + }, + { + "charaid": ["27", "28"], + "_name": "镜华", + "type": [ + { + "good-luck": 7, + "content": "宜水群﹁今天你就是喷水龙王﹂" + }, + { + "good-luck": 5, + "content": "宜社畜﹁就算很讨厌,今天我也努力吃了一片胡萝卜﹂" + }, + { + "good-luck": 6, + "content": "宜出刀﹁虽然希望可以暴击変態桑而不是王﹂" + }, + { + "good-luck": -6, + "content": "忌装弱﹁优妮就算了,你也想叫妈妈?﹂" + }, + { + "good-luck": 26, + "content": "全体运会不会是能吃到纸杯蛋糕呢" + }, + { + "good-luck": 27, + "content": "変態変態変態変態!" + } + ] + }, + { + "charaid": ["29", "30"], + "_name": "美美", + "type": [ + { + "good-luck": 8, + "content": "天兔霸断剑,要试试吗" + }, + { + "good-luck": 7, + "content": "宜出游﹁会遇到小萝莉﹂" + }, + { + "good-luck": 4, + "content": "宜刷本﹁お兄ちゃん見ていて、いっぱい箱!﹂" + }, + { + "good-luck": -7, + "content": "忌出刀﹁美美的狮鹫长大了也会伤害它吗﹂" + }, + { + "good-luck": -8, + "content": "这个月会战摸了" + }, + { + "good-luck": 27, + "content": "镜华和未奏希也会吵架,但最后还是会和好的" + } + ] + }, + { + "charaid": ["31", "32"], + "_name": "未奏希", + "type": [ + { + "good-luck": 8, + "content": "宜刷本﹁成功避开攻略烟雾弹﹂" + }, + { + "good-luck": 5, + "content": "宜摸鱼﹁每天三刀甜心刀,大家一起睡饱饱﹂" + }, + { + "good-luck": 5, + "content": "小 心 熊 孩 子" + }, + { + "good-luck": -6, + "content": "忌出刀﹁刚跟镜华吵完架,现在是0暴镜华﹂" + }, + { + "good-luck": -8, + "content": "忌作死﹁自己挖的陷阱,自己踩下去﹂" + }, + { + "good-luck": 25, + "content": "哎呀,学不会啊!" + } + ] + }, + { + "charaid": ["33", "34"], + "_name": "怜", + "type": [ + { + "good-luck": 7, + "content": "宜钓鱼﹁剑圣之意不在鱼,在乎::﹂" + }, + { + "good-luck": 5, + "content": "宜击剑﹁要刺得快!刺得狠!﹂" + }, + { + "good-luck": 4, + "content": "宜现充﹁一起特训到晚上吧﹂" + }, + { + "good-luck": -8, + "content": "今天你就是老醋坛︵士条怜︶了" + }, + { + "good-luck": -10, + "content": "忌摸鱼﹁当你偷偷快乐的时候,优衣正在凝视着你﹂" + }, + { + "good-luck": 23, + "content": "遇到困难的时候,男?朋友总会帮你︵雪乃&怜" + } + ] + }, + { + "charaid": ["35", "36"], + "_name": "优衣", + "type": [ + { + "good-luck": 10, + "content": "诸事皆宜!今、今后也请::︵宕机" + }, + { + "good-luck": 6, + "content": "宜现充﹁朋?友都会顾及关心你﹂" + }, + { + "good-luck": -6, + "content": "说着对不起实际却偷吃的屑都不配被我奶" + }, + { + "good-luck": -7, + "content": "忌表白﹁诶诶诶我怎么又被对不起了﹂" + }, + { + "good-luck": -10, + "content": "忌抽卡﹁又井了呢,骑士君﹂" + }, + { + "good-luck": 21, + "content": "不许说对不起!" + } + ] + }, + { + "charaid": ["37", "38"], + "_name": "日和莉", + "type": [ + { + "good-luck": 9, + "content": "宜竞技场﹁欧拉欧拉欧拉欧拉欧拉!﹂" + }, + { + "good-luck": 8, + "content": "日行一善会有好事发生" + }, + { + "good-luck": 6, + "content": "宜对线﹁那就对他使用炎拳吧﹂" + }, + { + "good-luck": -7, + "content": "忌偏见﹁你以为我是猫,其实我是老虎哒﹂" + }, + { + "good-luck": -8, + "content": "忌表白﹁游戏也好,相遇也好,明明是我先来的﹂" + }, + { + "good-luck": 27, + "content": "开朗活泼想要保持他人关系,到底哪里出错了︵团子&日和莉" + } + ] + }, + { + "charaid": ["39", "40"], + "_name": "贪吃佩可", + "type": [ + { + "good-luck": 10, + "content": "んま~い!ごはんは命のエネルギー☆" + }, + { + "good-luck": 7, + "content": "宜现充﹁おいっす~☆﹂" + }, + { + "good-luck": 5, + "content": "宜二刺猿﹁真男人就该?高达﹂" + }, + { + "good-luck": -7, + "content": "今日性能降低﹁因为好吃就是高兴嘛﹂" + }, + { + "good-luck": -10, + "content": "忌水群﹁群霸瞳篡改群员记忆导致冷场﹂" + }, + { + "good-luck": 20, + "content": "ヤバイですね‼" + } + ] + }, + { + "charaid": ["41", "42"], + "_name": "可可萝", + "type": [ + { + "good-luck": 10, + "content": "今天也做得很好、主さま" + }, + { + "good-luck": 9, + "content": "宜抽卡﹁爱梅斯大人说今天又会遇到新的女生﹂" + }, + { + "good-luck": 8, + "content": "宜刷本﹁已经让密涅瓦偷偷改过数据了﹂" + }, + { + "good-luck": -8, + "content": "果然又是主人认识的女生,以后叫わんわんの主さま好了" + }, + { + "good-luck": -9, + "content": "忌半途而废﹁第几次转生了,DD﹂" + }, + { + "good-luck": 26, + "content": "诸事皆宜" + } + ] + } + ] +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/fortune/goodLuck.json b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/fortune/goodLuck.json new file mode 100644 index 0000000..c3368b1 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/fortune/goodLuck.json @@ -0,0 +1,84 @@ +{ + "types_of": [ + { + "good-luck": 10, + "name": "大吉" + }, + { + "good-luck": 9, + "name": "中吉" + }, + { + "good-luck": 8, + "name": "小吉" + }, + { + "good-luck": 7, + "name": "吉" + }, + { + "good-luck": 6, + "name": "半吉" + }, + { + "good-luck": 5, + "name": "末吉" + }, + { + "good-luck": 4, + "name": "末小吉" + }, + { + "good-luck": -6, + "name": "凶" + }, + { + "good-luck": -7, + "name": "小凶" + }, + { + "good-luck": -8, + "name": "半凶" + }, + { + "good-luck": -9, + "name": "末凶" + }, + { + "good-luck": -10, + "name": "大凶" + }, + { + "good-luck": 20, + "name": "総合運" + }, + { + "good-luck": 21, + "name": "恋愛運" + }, + { + "good-luck": 22, + "name": "結婚運" + }, + { + "good-luck": 23, + "name": "仕事運" + }, + { + "good-luck": 24, + "name": "金運" + }, + { + "good-luck": 25, + "name": "勉強運" + }, + { + "good-luck": 26, + "name": "全体運" + }, + { + "good-luck": 27, + "name": "関係運" + } + ] +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_1.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_1.jpg new file mode 100644 index 0000000..b9feb5d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_1.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_10.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_10.jpg new file mode 100644 index 0000000..c93faef Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_10.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_11.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_11.jpg new file mode 100644 index 0000000..9a74039 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_11.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_12.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_12.jpg new file mode 100644 index 0000000..0dff1ec Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_12.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_13.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_13.jpg new file mode 100644 index 0000000..b7e2619 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_13.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_14.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_14.jpg new file mode 100644 index 0000000..adb9369 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_14.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_15.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_15.jpg new file mode 100644 index 0000000..c86c42c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_15.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_16.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_16.jpg new file mode 100644 index 0000000..3f8127e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_16.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_17.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_17.jpg new file mode 100644 index 0000000..644d1d6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_17.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_18.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_18.jpg new file mode 100644 index 0000000..9bf472d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_18.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_19.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_19.jpg new file mode 100644 index 0000000..8c20a85 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_19.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_2.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_2.jpg new file mode 100644 index 0000000..1054e9e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_2.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_20.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_20.jpg new file mode 100644 index 0000000..6f3aa3e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_20.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_21.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_21.jpg new file mode 100644 index 0000000..99c5591 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_21.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_22.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_22.jpg new file mode 100644 index 0000000..34cd620 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_22.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_23.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_23.jpg new file mode 100644 index 0000000..8506394 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_23.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_24.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_24.jpg new file mode 100644 index 0000000..099ab4c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_24.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_25.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_25.jpg new file mode 100644 index 0000000..3ee8952 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_25.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_26.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_26.jpg new file mode 100644 index 0000000..41821e4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_26.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_27.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_27.jpg new file mode 100644 index 0000000..655b0bc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_27.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_28.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_28.jpg new file mode 100644 index 0000000..40c8723 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_28.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_29.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_29.jpg new file mode 100644 index 0000000..072d1b2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_29.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_3.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_3.jpg new file mode 100644 index 0000000..c583e04 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_3.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_30.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_30.jpg new file mode 100644 index 0000000..7819769 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_30.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_31.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_31.jpg new file mode 100644 index 0000000..e45c905 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_31.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_32.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_32.jpg new file mode 100644 index 0000000..186157d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_32.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_33.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_33.jpg new file mode 100644 index 0000000..4ad4803 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_33.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_34.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_34.jpg new file mode 100644 index 0000000..0b5bd15 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_34.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_35.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_35.jpg new file mode 100644 index 0000000..c9e085f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_35.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_36.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_36.jpg new file mode 100644 index 0000000..c898569 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_36.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_37.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_37.jpg new file mode 100644 index 0000000..f784645 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_37.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_38.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_38.jpg new file mode 100644 index 0000000..9d4f205 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_38.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_39.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_39.jpg new file mode 100644 index 0000000..796d479 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_39.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_4.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_4.jpg new file mode 100644 index 0000000..b9ee189 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_4.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_40.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_40.jpg new file mode 100644 index 0000000..ab8b3fc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_40.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_41.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_41.jpg new file mode 100644 index 0000000..b29e890 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_41.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_42.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_42.jpg new file mode 100644 index 0000000..a0d4411 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_42.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_5.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_5.jpg new file mode 100644 index 0000000..0c57554 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_5.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_6.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_6.jpg new file mode 100644 index 0000000..20891e4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_6.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_7.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_7.jpg new file mode 100644 index 0000000..f087283 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_7.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_8.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_8.jpg new file mode 100644 index 0000000..5777ff5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_8.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_9.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_9.jpg new file mode 100644 index 0000000..583051e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/imgbase/frame_9.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/out/frame_11.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/out/frame_11.jpg new file mode 100644 index 0000000..4aa235e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/out/frame_11.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/out/frame_27.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/out/frame_27.jpg new file mode 100644 index 0000000..85eb5fc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/out/frame_27.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/out/frame_28.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/out/frame_28.jpg new file mode 100644 index 0000000..7fab895 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/out/frame_28.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/out/frame_34.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/out/frame_34.jpg new file mode 100644 index 0000000..7cf35ac Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/portunedata/out/frame_34.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/H~@%PMGOFZNLLE@3I~%@4N9.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/H~@%PMGOFZNLLE@3I~%@4N9.png new file mode 100644 index 0000000..85a2e04 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/H~@%PMGOFZNLLE@3I~%@4N9.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/KyaruMiniGame/kokkoro_stamp.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/KyaruMiniGame/kokkoro_stamp.png new file mode 100644 index 0000000..7e63710 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/KyaruMiniGame/kokkoro_stamp.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/KyaruMiniGame/接龙.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/KyaruMiniGame/接龙.jpg new file mode 100644 index 0000000..c41201e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/KyaruMiniGame/接龙.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/KyaruMiniGame/注音文字.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/KyaruMiniGame/注音文字.jpg new file mode 100644 index 0000000..6924a00 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/KyaruMiniGame/注音文字.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/antiqks.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/antiqks.jpg new file mode 100644 index 0000000..2afb52b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/antiqks.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_1.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_1.png new file mode 100644 index 0000000..015538d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_1.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_10.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_10.png new file mode 100644 index 0000000..cb87da7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_10.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_100.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_100.png new file mode 100644 index 0000000..79764c0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_100.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_101.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_101.png new file mode 100644 index 0000000..51438f3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_101.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_102.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_102.png new file mode 100644 index 0000000..a0c2d9e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_102.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_103.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_103.png new file mode 100644 index 0000000..df93fd4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_103.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_104.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_104.png new file mode 100644 index 0000000..423821c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_104.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_105.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_105.png new file mode 100644 index 0000000..a8e1d65 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_105.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_106.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_106.png new file mode 100644 index 0000000..d68debd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_106.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_107.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_107.png new file mode 100644 index 0000000..b843a2a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_107.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_108.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_108.png new file mode 100644 index 0000000..e666aa0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_108.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_109.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_109.png new file mode 100644 index 0000000..d32d896 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_109.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_11.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_11.png new file mode 100644 index 0000000..285caff Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_11.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_110.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_110.png new file mode 100644 index 0000000..7c9fed8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_110.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_111.png new file mode 100644 index 0000000..1b624ab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_112.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_112.png new file mode 100644 index 0000000..2171163 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_112.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_113.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_113.png new file mode 100644 index 0000000..2ae354c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_113.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_114.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_114.png new file mode 100644 index 0000000..498f6ee Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_114.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_115.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_115.png new file mode 100644 index 0000000..bab5752 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_115.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_116.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_116.png new file mode 100644 index 0000000..4a41877 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_116.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_117.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_117.png new file mode 100644 index 0000000..c132064 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_117.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_118.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_118.png new file mode 100644 index 0000000..a4543d6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_118.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_119.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_119.png new file mode 100644 index 0000000..00b3418 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_119.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_12.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_12.png new file mode 100644 index 0000000..d9f44a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_12.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_120.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_120.png new file mode 100644 index 0000000..4166cd4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_120.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_121.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_121.png new file mode 100644 index 0000000..87b9d76 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_121.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_122.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_122.png new file mode 100644 index 0000000..10b8c7b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_122.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_123.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_123.png new file mode 100644 index 0000000..0a1a98c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_123.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_124.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_124.png new file mode 100644 index 0000000..6ddd625 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_124.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_125.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_125.png new file mode 100644 index 0000000..f804601 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_125.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_126.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_126.png new file mode 100644 index 0000000..6be59a0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_126.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_127.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_127.png new file mode 100644 index 0000000..136a7bf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_127.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_128.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_128.png new file mode 100644 index 0000000..2f6fefc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_128.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_129.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_129.png new file mode 100644 index 0000000..a7595b1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_129.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_13.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_13.png new file mode 100644 index 0000000..5939943 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_13.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_130.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_130.png new file mode 100644 index 0000000..894dbab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_130.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_131.png new file mode 100644 index 0000000..2a1ee80 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_132.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_132.png new file mode 100644 index 0000000..c21cee1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_132.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_133.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_133.png new file mode 100644 index 0000000..33c6e4a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_133.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_134.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_134.png new file mode 100644 index 0000000..7152117 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_134.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_135.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_135.png new file mode 100644 index 0000000..1c91820 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_135.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_136.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_136.png new file mode 100644 index 0000000..504a6fd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_136.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_137.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_137.png new file mode 100644 index 0000000..376a7d4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_137.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_138.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_138.png new file mode 100644 index 0000000..6f8fcab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_138.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_139.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_139.png new file mode 100644 index 0000000..8aba6fc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_139.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_14.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_14.png new file mode 100644 index 0000000..0fdcfed Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_14.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_140.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_140.png new file mode 100644 index 0000000..93524fd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_140.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_141.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_141.png new file mode 100644 index 0000000..f5e3871 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_141.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_142.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_142.png new file mode 100644 index 0000000..58d1ceb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_142.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_143.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_143.png new file mode 100644 index 0000000..2e4eb7f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_143.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_144.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_144.png new file mode 100644 index 0000000..cf5ee4a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_144.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_145.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_145.png new file mode 100644 index 0000000..f98c5f2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_145.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_146.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_146.png new file mode 100644 index 0000000..5d8300c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_146.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_147.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_147.png new file mode 100644 index 0000000..3d2b705 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_147.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_148.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_148.png new file mode 100644 index 0000000..2a5e6e7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_148.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_149.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_149.png new file mode 100644 index 0000000..6d9dc00 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_149.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_15.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_15.png new file mode 100644 index 0000000..e60144f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_15.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_150.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_150.png new file mode 100644 index 0000000..24c6013 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_150.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_151.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_151.png new file mode 100644 index 0000000..16ce6ab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_151.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_152.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_152.png new file mode 100644 index 0000000..df30c0e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_152.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_153.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_153.png new file mode 100644 index 0000000..d814120 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_153.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_154.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_154.png new file mode 100644 index 0000000..a3ac33f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_154.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_155.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_155.png new file mode 100644 index 0000000..9477bdd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_155.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_156.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_156.png new file mode 100644 index 0000000..0b4924e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_156.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_157.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_157.png new file mode 100644 index 0000000..60ca5da Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_157.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_158.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_158.png new file mode 100644 index 0000000..f62d2dd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_158.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_159.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_159.png new file mode 100644 index 0000000..72d762e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_159.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_16.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_16.png new file mode 100644 index 0000000..8e47158 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_16.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_160.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_160.png new file mode 100644 index 0000000..d4fcf5c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_160.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_161.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_161.png new file mode 100644 index 0000000..cffce4b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_161.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_162.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_162.png new file mode 100644 index 0000000..c00c437 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_162.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_163.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_163.png new file mode 100644 index 0000000..bfe21d1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_163.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_164.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_164.png new file mode 100644 index 0000000..a8faf55 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_164.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_165.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_165.png new file mode 100644 index 0000000..5c2680d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_165.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_166.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_166.png new file mode 100644 index 0000000..200383d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_166.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_167.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_167.png new file mode 100644 index 0000000..11476ce Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_167.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_168.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_168.png new file mode 100644 index 0000000..b23cedd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_168.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_169.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_169.png new file mode 100644 index 0000000..c13a2ea Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_169.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_17.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_17.png new file mode 100644 index 0000000..579eb92 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_17.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_170.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_170.png new file mode 100644 index 0000000..c85fb69 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_170.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_171.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_171.png new file mode 100644 index 0000000..f58a01f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_171.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_172.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_172.png new file mode 100644 index 0000000..940ef05 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_172.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_173.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_173.png new file mode 100644 index 0000000..7ece500 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_173.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_174.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_174.png new file mode 100644 index 0000000..df803b1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_174.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_175.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_175.png new file mode 100644 index 0000000..c4e26cd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_175.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_176.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_176.png new file mode 100644 index 0000000..18398aa Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_176.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_177.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_177.png new file mode 100644 index 0000000..3336868 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_177.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_178.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_178.png new file mode 100644 index 0000000..25ebbbc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_178.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_179.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_179.png new file mode 100644 index 0000000..5e15e3b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_179.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_18.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_18.png new file mode 100644 index 0000000..ede37d0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_18.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_180.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_180.png new file mode 100644 index 0000000..3a54ef8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_180.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_181.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_181.png new file mode 100644 index 0000000..4fc550a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_181.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_182.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_182.png new file mode 100644 index 0000000..75e2e98 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_182.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_183.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_183.png new file mode 100644 index 0000000..9631b9b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_183.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_184.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_184.png new file mode 100644 index 0000000..8bcae10 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_184.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_185.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_185.png new file mode 100644 index 0000000..63e609a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_185.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_186.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_186.png new file mode 100644 index 0000000..018bc26 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_186.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_187.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_187.png new file mode 100644 index 0000000..3956df1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_187.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_188.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_188.png new file mode 100644 index 0000000..4a23448 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_188.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_189.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_189.png new file mode 100644 index 0000000..84e3d23 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_189.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_19.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_19.png new file mode 100644 index 0000000..161de2d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_19.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_190.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_190.png new file mode 100644 index 0000000..c81e1ac Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_190.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_191.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_191.png new file mode 100644 index 0000000..e58da31 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_191.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_192.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_192.png new file mode 100644 index 0000000..46cf581 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_192.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_193.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_193.png new file mode 100644 index 0000000..d1b372b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_193.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_194.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_194.png new file mode 100644 index 0000000..c937d5c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_194.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_195.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_195.png new file mode 100644 index 0000000..a90f9b3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_195.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_196.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_196.png new file mode 100644 index 0000000..215f943 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_196.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_197.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_197.png new file mode 100644 index 0000000..f947727 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_197.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_198.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_198.png new file mode 100644 index 0000000..ff7ed65 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_198.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_199.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_199.png new file mode 100644 index 0000000..5fd7812 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_199.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_2.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_2.png new file mode 100644 index 0000000..05af9f4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_2.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_20.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_20.png new file mode 100644 index 0000000..7041f4d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_20.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_200.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_200.png new file mode 100644 index 0000000..6518130 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_200.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_201.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_201.png new file mode 100644 index 0000000..8d5ceab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_201.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_209.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_209.png new file mode 100644 index 0000000..984b8fd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_209.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_21.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_21.png new file mode 100644 index 0000000..949cc2a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_21.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_210.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_210.png new file mode 100644 index 0000000..748d4e8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_210.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_211.png new file mode 100644 index 0000000..3e0afee Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_212.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_212.png new file mode 100644 index 0000000..6df851a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_212.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_213.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_213.png new file mode 100644 index 0000000..c130172 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_213.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_214.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_214.png new file mode 100644 index 0000000..d358525 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_214.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_215.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_215.png new file mode 100644 index 0000000..4a4e4d5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_215.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_216.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_216.png new file mode 100644 index 0000000..dc90a46 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_216.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_217.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_217.png new file mode 100644 index 0000000..f681443 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_217.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_218.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_218.png new file mode 100644 index 0000000..b4fd0c9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_218.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_219.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_219.png new file mode 100644 index 0000000..bcd4c1b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_219.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_22.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_22.png new file mode 100644 index 0000000..4536e5b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_22.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_220.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_220.png new file mode 100644 index 0000000..8ecc369 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_220.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_221.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_221.png new file mode 100644 index 0000000..330a4f0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_221.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_222.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_222.png new file mode 100644 index 0000000..bc0584b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_222.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_223.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_223.png new file mode 100644 index 0000000..ebc520e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_223.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_23.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_23.png new file mode 100644 index 0000000..a1fca7e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_23.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_24.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_24.png new file mode 100644 index 0000000..b6e4f34 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_24.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_25.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_25.png new file mode 100644 index 0000000..05a831d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_25.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_26.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_26.png new file mode 100644 index 0000000..1a9079d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_26.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_27.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_27.png new file mode 100644 index 0000000..b398159 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_27.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_28.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_28.png new file mode 100644 index 0000000..ee2f310 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_28.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_29.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_29.png new file mode 100644 index 0000000..c8f1f63 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_29.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_3.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_3.png new file mode 100644 index 0000000..f814613 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_3.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_30.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_30.png new file mode 100644 index 0000000..30e8392 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_30.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_31.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_31.png new file mode 100644 index 0000000..44fdecb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_31.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_32.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_32.png new file mode 100644 index 0000000..9614908 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_32.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_33.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_33.png new file mode 100644 index 0000000..2bcc069 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_33.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_337.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_337.png new file mode 100644 index 0000000..b86f002 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_337.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_338.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_338.png new file mode 100644 index 0000000..b76d6d0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_338.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_339.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_339.png new file mode 100644 index 0000000..f3fcfc7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_339.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_34.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_34.png new file mode 100644 index 0000000..0b4ad95 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_34.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_340.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_340.png new file mode 100644 index 0000000..8822112 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_340.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_341.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_341.png new file mode 100644 index 0000000..7d42b55 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_341.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_342.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_342.png new file mode 100644 index 0000000..882e370 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_342.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_343.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_343.png new file mode 100644 index 0000000..adfaac3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_343.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_344.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_344.png new file mode 100644 index 0000000..fc238c8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_344.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_345.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_345.png new file mode 100644 index 0000000..5bbf7fd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_345.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_346.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_346.png new file mode 100644 index 0000000..dc37d6e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_346.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_347.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_347.png new file mode 100644 index 0000000..d9771f2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_347.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_348.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_348.png new file mode 100644 index 0000000..6e0854a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_348.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_349.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_349.png new file mode 100644 index 0000000..abaab42 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_349.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_35.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_35.png new file mode 100644 index 0000000..201a419 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_35.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_350.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_350.png new file mode 100644 index 0000000..547235b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_350.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_351.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_351.png new file mode 100644 index 0000000..f199872 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_351.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_352.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_352.png new file mode 100644 index 0000000..f654494 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_352.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_353.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_353.png new file mode 100644 index 0000000..c9b4ddb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_353.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_36.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_36.png new file mode 100644 index 0000000..c1a376b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_36.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_37.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_37.png new file mode 100644 index 0000000..bbedc49 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_37.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_38.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_38.png new file mode 100644 index 0000000..2fe006a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_38.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_39.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_39.png new file mode 100644 index 0000000..19145c8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_39.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_4.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_4.png new file mode 100644 index 0000000..22aed3a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_4.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_40.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_40.png new file mode 100644 index 0000000..506e6a2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_40.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_41.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_41.png new file mode 100644 index 0000000..d4f530d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_41.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_42.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_42.png new file mode 100644 index 0000000..cb1404d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_42.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_43.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_43.png new file mode 100644 index 0000000..47ebaa7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_43.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_44.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_44.png new file mode 100644 index 0000000..99b2562 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_44.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_45.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_45.png new file mode 100644 index 0000000..d80f6c7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_45.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_46.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_46.png new file mode 100644 index 0000000..9a4cee8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_46.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_47.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_47.png new file mode 100644 index 0000000..8b4a874 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_47.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_48.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_48.png new file mode 100644 index 0000000..7c4c34f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_48.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_49.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_49.png new file mode 100644 index 0000000..e3cfa96 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_49.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_5.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_5.png new file mode 100644 index 0000000..f706d11 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_5.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_50.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_50.png new file mode 100644 index 0000000..0a83f04 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_50.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_51.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_51.png new file mode 100644 index 0000000..b8042bc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_51.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_52.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_52.png new file mode 100644 index 0000000..e42b281 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_52.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_53.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_53.png new file mode 100644 index 0000000..3b3d45a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_53.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_54.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_54.png new file mode 100644 index 0000000..bbba220 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_54.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_55.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_55.png new file mode 100644 index 0000000..8e7ca25 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_55.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_56.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_56.png new file mode 100644 index 0000000..187a0f5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_56.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_57.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_57.png new file mode 100644 index 0000000..2c6edc4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_57.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_58.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_58.png new file mode 100644 index 0000000..99bfc8d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_58.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_59.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_59.png new file mode 100644 index 0000000..29c55a0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_59.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_6.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_6.png new file mode 100644 index 0000000..a2d8e44 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_6.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_60.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_60.png new file mode 100644 index 0000000..0f48a49 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_60.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_61.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_61.png new file mode 100644 index 0000000..df74c62 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_61.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_62.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_62.png new file mode 100644 index 0000000..f11cd5b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_62.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_63.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_63.png new file mode 100644 index 0000000..d48159a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_63.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_64.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_64.png new file mode 100644 index 0000000..e51523a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_64.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_65.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_65.png new file mode 100644 index 0000000..ae98be8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_65.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_66.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_66.png new file mode 100644 index 0000000..c7e8e74 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_66.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_67.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_67.png new file mode 100644 index 0000000..a216d97 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_67.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_68.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_68.png new file mode 100644 index 0000000..c48891c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_68.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_69.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_69.png new file mode 100644 index 0000000..1ab5010 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_69.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_7.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_7.png new file mode 100644 index 0000000..aeb0e28 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_7.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_70.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_70.png new file mode 100644 index 0000000..b92e288 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_70.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_71.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_71.png new file mode 100644 index 0000000..af7a359 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_71.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_72.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_72.png new file mode 100644 index 0000000..acfacab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_72.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_73.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_73.png new file mode 100644 index 0000000..a3f0c7c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_73.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_74.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_74.png new file mode 100644 index 0000000..69599f6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_74.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_75.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_75.png new file mode 100644 index 0000000..f5e4e1c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_75.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_76.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_76.png new file mode 100644 index 0000000..8cd0b2a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_76.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_77.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_77.png new file mode 100644 index 0000000..e00c753 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_77.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_78.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_78.png new file mode 100644 index 0000000..bcb3e8b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_78.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_79.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_79.png new file mode 100644 index 0000000..e8d0418 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_79.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_8.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_8.png new file mode 100644 index 0000000..32d9540 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_8.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_80.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_80.png new file mode 100644 index 0000000..b8427a2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_80.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_81.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_81.png new file mode 100644 index 0000000..8758868 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_81.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_82.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_82.png new file mode 100644 index 0000000..2d18133 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_82.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_83.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_83.png new file mode 100644 index 0000000..7fc3b19 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_83.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_84.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_84.png new file mode 100644 index 0000000..c2159d0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_84.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_85.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_85.png new file mode 100644 index 0000000..39c6092 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_85.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_86.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_86.png new file mode 100644 index 0000000..9029ef3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_86.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_87.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_87.png new file mode 100644 index 0000000..3e1d48a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_87.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_88.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_88.png new file mode 100644 index 0000000..e2a4d53 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_88.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_89.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_89.png new file mode 100644 index 0000000..35a0a77 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_89.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_9.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_9.png new file mode 100644 index 0000000..e19c72f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_9.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_90.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_90.png new file mode 100644 index 0000000..2e5e0a4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_90.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_91.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_91.png new file mode 100644 index 0000000..f2bc34c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_91.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_92.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_92.png new file mode 100644 index 0000000..d24dd04 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_92.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_93.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_93.png new file mode 100644 index 0000000..54cdedb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_93.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_94.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_94.png new file mode 100644 index 0000000..37d6ac3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_94.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_95.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_95.png new file mode 100644 index 0000000..0ef2beb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_95.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_96.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_96.png new file mode 100644 index 0000000..db4f611 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_96.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_97.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_97.png new file mode 100644 index 0000000..8b73c20 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_97.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_98.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_98.png new file mode 100644 index 0000000..760e492 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_98.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_99.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_99.png new file mode 100644 index 0000000..326d6eb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/episode_99.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/index.json b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/index.json new file mode 100644 index 0000000..3695ca2 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/comic/index.json @@ -0,0 +1 @@ +{"1":{"title":"だれのため?","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/ae397a547f41dcbb5c55b07b5c44a544.png?id=1"},"2":{"title":"ケンカはだめっ!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/5dec4d9e975f7b916fcd296a4c1f754e.png?id=2"},"3":{"title":"荷物の中身は","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/b188359b5a6caf8fec4e1f3eb4de3afd.png?id=3"},"4":{"title":"しっかり観察!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/cffde6f906d390dc05aeccb37dea13ff.png?id=4"},"5":{"title":"もりのこえ(前編)","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/fa46349651aa504e0cf0fbc7e7785fe6.png?id=5"},"6":{"title":"もりのこえ(後編)","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/83898de0b8017ce8f860671d69870f6a.png?id=6"},"7":{"title":"正体みたりっ!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/15b1ba8438a0e9b6a72c83d898f1051c.png?id=7"},"8":{"title":"すれちがい","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/91ae1ef284c47a202a241132f156e8c4.png?id=8"},"9":{"title":"カリスマ?","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/ad8f7a34516125de0bf3136385240e89.png?id=9"},"10":{"title":"イマジネーション","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/38b595e0121c343eff137cdcef056ebb.png?id=10"},"11":{"title":"放っておけないっ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/628471617c9c509cab9dc309eb606548.png?id=11"},"12":{"title":"オトナのミリョク?","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/57095e7adaeecf512e63a1f075351c5e.png?id=12"},"13":{"title":"追われ追われて","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/befe66bc735aeceb16add20a2a00730e.png?id=13"},"14":{"title":"幻の4人目","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/9cf74bfe7a73ca1a09d5f680f62a04d6.png?id=14"},"15":{"title":"め・し・あ・が・れ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/0b013c9f0fedd511247c58d8e4377332.png?id=15"},"16":{"title":"レイの休日","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/bf666ef634ca6ef58af470470c35e5d4.png?id=16"},"17":{"title":"立てば芍薬","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/b9689cbdf5316e64f2ae6d6664adfa4c.png?id=17"},"18":{"title":"わくわくバカンス","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/460192e407baee413f88fba96d0bbe8e.png?id=18"},"19":{"title":"きせかえコッコロ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/2c3f726fd8deafb0d31145f78361a809.png?id=19"},"20":{"title":"大事な家族","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/955fbce5fb125752874a6c230ee09ddd.png?id=20"},"21":{"title":"水着でおもてなし","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/94ad8c9df22c1a0e696e261acb507b74.png?id=21"},"22":{"title":"演技派","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/736819e71fbaba1099778dbe3906a7f1.png?id=22"},"23":{"title":"悪夢再び","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/1c2eca6506f990d269678bd231a682e8.png?id=23"},"24":{"title":"ねじねじもふもふ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/5452d2d00b30ddd2104aa3c261e3ab81.png?id=24"},"25":{"title":"必要ないっ!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/a31b80691c6c90c01c2b69ee10de6b7b.png?id=25"},"26":{"title":"おねがい","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/242283ba8241de38f142603dd305bc7d.png?id=26"},"27":{"title":"完璧な計画","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/4613a4eba6420440d85bbec2fd48f327.png?id=27"},"28":{"title":"力の理由","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/cf11917ce4872183ad85e5141f8d2e3b.png?id=28"},"29":{"title":"のみすぎちゅうい","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/4bc3c6ab139b51742a41d826170d463a.png?id=29"},"30":{"title":"苦手なもの","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/0eb816d4939485551fcff4a3de62b311.png?id=30"},"31":{"title":"裏の顔(前編)","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/ee057e488a544fd9d167879b89471517.png?id=31"},"32":{"title":"裏の顔(後編)","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/bcf86d4e8d7ffd3989e84b39173a3124.png?id=32"},"33":{"title":"目覚めの","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/c832bd106bf76e2d00698e724c82bbed.png?id=33"},"34":{"title":"熱烈歓迎モード","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/40964d3afe2d85e4ab44539a739c97d2.png?id=34"},"35":{"title":"調査用アイテム?","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/d33f354bbe0683e6c742867f0452a4fd.png?id=35"},"36":{"title":"悪い癖","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/b3bc7fde799334e6c30b01bbeef572c8.png?id=36"},"37":{"title":"合体技ッス!(前編)","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/9a792aa0a260210ff2575b07086f6d8d.png?id=37"},"38":{"title":"合体技ッス!(後編)","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/25e77187aaf864698886bad0ff8ff8d1.png?id=38"},"39":{"title":"エネルギー切れ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/4f7abb516b61f58d56f270d0bbe0b1ba.png?id=39"},"40":{"title":"鵜の真似をするべからず","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/40b16f54f8c441e85b9c8510d11f2bb2.png?id=40"},"41":{"title":"照れ隠し","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/9ef3f964a6345bd3c61bd36cf46def48.png?id=41"},"42":{"title":"食べ物のうらみ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/90f4ee522b58969987e694bd8d910fbe.png?id=42"},"43":{"title":"しかつもんだい","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/bea625220d452518f10eb2a31c75dee8.png?id=43"},"44":{"title":"居心地良し","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/9a1f6bd8e84d091520a194c51e66ca35.png?id=44"},"45":{"title":"手加減抜き","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/54c095f7d0be3eb20a07b34a408f458d.png?id=45"},"46":{"title":"大人の味","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/9755688b072c068097f295cfc9e82d7b.png?id=46"},"47":{"title":"憧れの放課後","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/ad9f0b34cd9ecc331603cc6eaedbdd41.png?id=47"},"48":{"title":"魅了の魔法?","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/8a66fbc0dfd9ff9b8fa2c8caf74e50f4.png?id=48"},"49":{"title":"進軍!!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/d96c19b5d9bbd899bc2659f71caf4203.png?id=49"},"50":{"title":"その身に刻めッ!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/39c10b1514663ad825c54c6dd03e3051.png?id=50"},"51":{"title":"生粋の","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/e1c5a05525ecc7eaa5bdf2c121dfce94.png?id=51"},"52":{"title":"成敗ッ!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/8a255b26a2c0bbe9346cd9831741e1c2.png?id=52"},"53":{"title":"オーラバトル","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/0eb3c8bab6fa7e1a43a69ccd59b1b159.png?id=53"},"54":{"title":"有名人","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/8ebb6884b73535ef7d96db7cdc365c0f.png?id=54"},"55":{"title":"緊急離脱","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/78094778b29eed92aedae9875e6d3071.png?id=55"},"56":{"title":"抑止力","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/5b3e885a9f4a3ed4afbb3192efac252b.png?id=56"},"57":{"title":"ギャップ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/bc430cd772530da2c633269581bba996.png?id=57"},"58":{"title":"木を隠すなら","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/25ab73cb9856911d0ef48aa7420dc35f.png?id=58"},"59":{"title":"フードをかぶれば","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/5b17c7db4c1195ff4c705f3b85a54f90.png?id=59"},"60":{"title":"マイクを置いて","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/b3ac8bb9011dd751db45b74147dd0c05.png?id=60"},"61":{"title":"アマノジャクハート!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/7c70da3716f8ae6722c0a4cd4b76ff3f.png?id=61"},"62":{"title":"大きな代償","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/67012f1f3a57ede58d329774bcef4e98.png?id=62"},"63":{"title":"幻のケーキ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/784c51122aca62fb085065c4a0f48be8.png?id=63"},"64":{"title":"時には素直に","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/128b6f8504fe7bfeaaf6cfec7828e205.png?id=64"},"65":{"title":"内容が大事","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/f3ec209ee95848a160dfa06bf57ebad7.png?id=65"},"66":{"title":"強さの理由","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/21b395935490aa99e7f812061e6077b8.png?id=66"},"67":{"title":"ヘアアレンジ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/e6424f74b0fe9b2e5261480f3876ed56.png?id=67"},"68":{"title":"強力な助っ人","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/9b6801189cd4885d0e847ade429ffb4b.png?id=68"},"69":{"title":"おままごとアドベンチャー","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/715dd39476865fac385114ac875f500f.png?id=69"},"70":{"title":"風よくうけて","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/0b5fd53de01d0a3505cdc97d175d9d46.png?id=70"},"71":{"title":"解放","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/01e406f4f9f428963f2e607d1861d21d.png?id=71"},"72":{"title":"母なる大地","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/66deb3834faef160fe1d9603e1c946ee.png?id=72"},"73":{"title":"艱難全席","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/17fe13d80bcdf76ab9883d964b8db6a8.png?id=73"},"74":{"title":"藪に向かって乱れ撃ち","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/b6dcbabd59d750b74f5c1cad306ad541.png?id=74"},"75":{"title":"名案","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/9b5533566d0ed4d44c3cccd47a2a8621.png?id=75"},"76":{"title":"隠し味はまだ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/a1d926600da98510a6c739be4aba7dc2.png?id=76"},"77":{"title":"記念品贈呈","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/f355d4c94dc0abdda6f56ce4c03ad5ae.png?id=77"},"78":{"title":"天楼ヲ覇断スル剣","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/b40a1560b2899dca56538ed4bee74bb4.png?id=78"},"79":{"title":"悪の矜持","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/7378e2a46d4cd15097b1ff80351a13f5.png?id=79"},"80":{"title":"負けられない戦い","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/d1357231e0a954cf8cc02bb3074b65e6.png?id=80"},"81":{"title":"どら焼き消失事件(解決編)","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/33d1f55bd3da22072c97fbdc0c82bf7f.png?id=81"},"82":{"title":"容疑者Aの転進","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/33c2b3b33c19cd3bf042787327675ac7.png?id=82"},"83":{"title":"EXIT","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/d93f19b91c92f83d08151780c3355baf.png?id=83"},"84":{"title":"得意を活かして","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/8f4481b639c19904fad9143b805ab76a.png?id=84"},"85":{"title":"足早な補給食","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/15208ccb9c24d636083a3c0de7b87fdc.png?id=86"},"86":{"title":"大事な日課","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/cd565cce487a02bb58c5f48944c8b916.png?id=87"},"87":{"title":"情熱の補給食","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/9945767bcdade7aedaeb60faa2d68903.png?id=88"},"88":{"title":"ずーっと友達!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/fc7a8866793ff4f3216679dc81a61af6.png?id=89"},"89":{"title":"驚いたこと","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/06a0127798859576a76ec99664386429.png?id=90"},"90":{"title":"教えて!!キャル先生","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/f6e580ffdd993035a4cd188a662386e2.png?id=91"},"91":{"title":"お城での生活","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/111d4431195d211e3c0394ecc4e41d22.png?id=93"},"92":{"title":"プランB","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/8a3fc46e3c172a8a6a81841d3f8cdb38.png?id=94"},"93":{"title":"つまみぐい","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/508b4e54530ea3cf4220378534e534f3.png?id=95"},"94":{"title":"あなたのペースで","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/d9d2627eff995f7d06f705cc4205ae14.png?id=96"},"95":{"title":"むすんでひらいて","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/6fbd5433a4b031bb7df0b2430aaf168b.png?id=97"},"96":{"title":"プロジェクトN","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/8fbc8dba3ce81bbf37b0a3d3d40028f9.png?id=98"},"97":{"title":"価値あるもの","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/0720bb188b2c5eb78d202f91216a3ecc.png?id=99"},"98":{"title":"コノフィツムの花","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/02da1410ea24485b853c31c6aee7aae1.png?id=100"},"99":{"title":"シュバッと参上!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/1fbb9997aade6faa035e8fae4848465b.png?id=101"},"100":{"title":"猫まっしぐら","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/07880b94f387c6b717e8b6676df67855.png?id=102"},"101":{"title":"責任転じて","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/6b4adc2faf3beff8475ef0bca9cb5f17.png?id=103"},"102":{"title":"憧れの碧空","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/f605a6032fd69e256b99ff236f9f55cc.png?id=104"},"103":{"title":"安全装置","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/d57765c83acdf8f584ddef6f943f4428.png?id=105"},"104":{"title":"もふもふもふもふ?","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/73b5b58645cec3e59ba217a9a3bef352.png?id=106"},"105":{"title":"本気の訓練","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/9e167d9bc3ddafc0df50c1508e0203e6.png?id=107"},"106":{"title":"ロザリアを探して","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/d8a6f340c0b825bcad759cbb911f4a1c.png?id=108"},"107":{"title":"シスターズテレパシー☆","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/12c37f65dc5b2892705fa58c35d246b5.png?id=109"},"108":{"title":"対価","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/2c26f16ba1721bf50ef87316f416c080.png?id=110"},"109":{"title":"翠色の輝き","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/004ff6d30059172ddb4578a34de8bb96.png?id=111"},"110":{"title":"カリスマファンサービス","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/289df339ce2ca58e097c889306681e08.png?id=112"},"111":{"title":"ツボ押しの達人","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/58182cbb7e8b2a7074e2af4e6acb1900.png?id=113"},"112":{"title":"鉄壁のディフェンス","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/dd9bcfc4a0e90ea94360037639116952.png?id=114"},"113":{"title":"暴風雨警報","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/313b486ef5524b8f308a1b69479de303.png?id=115"},"114":{"title":"血ノ盟約-Blut Bund-","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/559902a0b4c09e847a02451ab6da07a9.png?id=116"},"115":{"title":"ワーカホリック","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/03ca88e903790488974c127d21236013.png?id=117"},"116":{"title":"ライバル登場?","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/656dc460961d8b34bc9b03b867c89fd7.png?id=118"},"117":{"title":"Because it's there.","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/06a20eb5d1215c79d2c5197b48722110.png?id=119"},"118":{"title":"My New Gear!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/b8c35d2d9c505c46824b68895cb70941.png?id=120"},"119":{"title":"美ら海","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/721f0a42435ea82fbb2f3c7b55d15694.png?id=121"},"120":{"title":"泳ぐ時は…","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/4e6a9242be8b0765016739d4a0a4ceda.png?id=122"},"121":{"title":"マホマホブロック","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/ac40e79bd2529b11325bfe41e47297f7.png?id=123"},"122":{"title":"平気だよ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/8d383bfb0a25a5694c15a0398c7098d9.png?id=124"},"123":{"title":"ループコンボ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/63207e823489a109a24e5c41806080f2.png?id=125"},"124":{"title":"ポーカーフェイス","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/589d94616646ca79b7f394dc0f8ca970.png?id=126"},"125":{"title":"イメトレ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/db1855f287347ff4cede15d03458cc49.png?id=127"},"126":{"title":"イメトレの先輩","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/96c7a66e34e52d75985d32718ed7679f.png?id=128"},"127":{"title":"姉は凄技、妹はひ弱","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/2a5002aee33794e2cfe9a9980934d854.png?id=129"},"128":{"title":"イメトレの成果","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/28fb15a7b641646e692325b751f62c69.png?id=130"},"129":{"title":"全力超全開☆","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/7ed6fc8b8c8674c4f7c438fef37df046.png?id=131"},"130":{"title":"耳かきの腕前","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/67c859238f6dc8ce04a36b28f76b4265.png?id=132"},"131":{"title":"勘違いしないで","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/d500a0a41cf88aded231ab710c2be086.png?id=133"},"132":{"title":"トリック・オア・カップケーキ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/66d5325e717e9a73719a76a804a5ff6f.png?id=134"},"133":{"title":"だレもいなイ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/7fefb5264b3e5b2f8f58a90c21f0c295.png?id=135"},"134":{"title":"物足りないっ!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/47f06c1def25b95b4b74231d3f5d5e8c.png?id=136"},"135":{"title":"ミミおねえちゃん","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/c23ab024752358db2ca6071594266c0c.png?id=137"},"136":{"title":"あーん♪","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/cc2fa16caf5c62bb5ff6c3d53bed3a52.png?id=138"},"137":{"title":"編みかけのマフラー","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/5512fdf3d45ea1e1bc372acfe446e7d2.png?id=139"},"138":{"title":"だったら","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/bb11b6b3caa95b7ae620774210bec896.png?id=140"},"139":{"title":"おともだちになりたくて","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/53f2246143c136b9c62b5215ceb678b7.png?id=141"},"140":{"title":"つんつん","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/3649b21816c16adb0a044ba3a2fd87cd.png?id=142"},"141":{"title":"理想の白馬はん","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/3798dce470a117a65d1b7114fba65241.png?id=143"},"142":{"title":"覚醒の条件","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/06636e8a4da36fd3db4a4e88e238be16.png?id=144"},"143":{"title":"どうする?","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/e3367452bd0db1e8b84b3d5cbf054630.png?id=145"},"144":{"title":"一緒におままごと","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/55ca1b3298901ee815c811a024b92d04.png?id=146"},"145":{"title":"大切なのは","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/18fa5ade0d1752a824c5801042022b4f.png?id=147"},"146":{"title":"影武者","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/0a1567c3a890690b59d08ace99a75753.png?id=148"},"147":{"title":"それってつまり…","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/4140540a57aad0cdce37147239deee63.png?id=149"},"148":{"title":"すべての道は","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/1ba7c3ded1f98a075f22e0522db31b0d.png?id=150"},"149":{"title":"普段は","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/ddf85cb39caa18f9cfd0f09c562509c0.png?id=151"},"150":{"title":"支配者として","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/7cc8ef616d813c2bcd070b378119f18a.png?id=152"},"151":{"title":"恋愛相談のプロ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/39d0a1c064c0f59144172572e326bd2e.png?id=153"},"152":{"title":"特別なおせち","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/4468affb06498cd254f922901852d3f8.png?id=154"},"153":{"title":"ぐいぐいぎゅうぎゅう","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/1f8adf7a1fd8c03160407ec30b443ead.png?id=155"},"154":{"title":"スズメの才能","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/82415f9ab591196236c14cfc6eed7a8c.png?id=156"},"155":{"title":"HURRY UP!!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/d10b6a000c7f45c38c6dc493ac6d1e16.png?id=157"},"156":{"title":"行列のできる","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/9f8d3f53ce8cd2296468ffdd1e945be8.png?id=158"},"157":{"title":"共鳴する魂","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/bb7ae03b94d90a20957780abe2b4e610.png?id=159"},"158":{"title":"イメージするのは…","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/719d3df819eee606e22f1d9883ec421f.png?id=160"},"159":{"title":"変わり続けるボク","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/02a9e5809a5e50463cc7c59a41cc9113.png?id=161"},"160":{"title":"ミスティ&ピュアリー","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/1bd885e91d87258798de49f6e99dd341.png?id=162"},"161":{"title":"ミスティの魔法","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/feca603f50f6204ffe2296e2a2b353a0.png?id=163"},"162":{"title":"ピュアリーな魔法","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/9683cefdefbdd3dfbaa2f00935df9889.png?id=164"},"163":{"title":"絆の証?","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/c8896e670d0e3caaad29d1af101ed78d.png?id=165"},"164":{"title":"わくわくクッキング","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/142de2000e54d710f6073c071a9f3c9b.png?id=166"},"165":{"title":"いつの間にかこんなにも","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/b2b31c7c2db790af11e0c1154d868cd7.png?id=167"},"166":{"title":"闇のお姉ちゃん","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/7fe83b1047783b155a2eb3b29ce5d8cf.png?id=168"},"167":{"title":"果て無き冒険魂","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/d3c68d6ccd6ef2d42c30db6d73ad4ce4.png?id=170"},"168":{"title":"スーパースターの素質","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/2fe9cc3f915b94eae8834e4ffd4fe439.png?id=171"},"169":{"title":"道案内","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/c90f2ec8715cd0429b0d6f62f29be379.png?id=172"},"170":{"title":"ゴクアクヒドウ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/705fef8f7b0bd4e70d253c3aa2d89019.png?id=173"},"171":{"title":"応援中!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/8b269eea221ac760620c6dc2db6e583b.png?id=174"},"172":{"title":"もっと聞かせて","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/49db0b37552d0092729a472ac10d29ff.png?id=175"},"173":{"title":"より強く、更に高みへ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/3159ef2c51873bef36ae4ed045a40039.png?id=176"},"174":{"title":"浪漫武器","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/11fac43849d95cb82de245be080dc452.png?id=177"},"175":{"title":"商品開発会議","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/10257d7d6d593ab6b725e35064626eed.png?id=178"},"176":{"title":"足りないもの","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/e5ac8fc9f160986f58fdd17709c57f9e.png?id=179"},"177":{"title":"めちゃちぇる","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/1a123cbdb48df523146747676406f4ea.png?id=180"},"178":{"title":"どんなところでも","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/4078f4cb15a95f29afd842a3293969a6.png?id=181"},"179":{"title":"今回だけ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/9ac67c9962ef875ba5958e73f27a5513.png?id=182"},"180":{"title":"どんと・ぶりーず","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/6837046c545b9b7fff08d1438897cad8.png?id=183"},"181":{"title":"ブカブカピカピカ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/d742dfc13814b34e1a4b10183b24edde.png?id=184"},"182":{"title":"牧場アイドル","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/02f6076b0f6c6b15d0cbd151a3b5d57e.png?id=185"},"183":{"title":"こっちにいます","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/f7cf7386fdfe49d74273cb38289a53cb.png?id=186"},"184":{"title":"燃えてファーマー","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/8b39696dd01be25ab27ceb304c4bccb4.png?id=187"},"185":{"title":"ダンシングキャッツ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/7f6826b483b2c811676d48d9bf0e7761.png?id=188"},"186":{"title":"続くよどこまでも","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/d6457fc7c575d91cbdc56baa6a0641eb.png?id=189"},"187":{"title":"苦手なものと苦手なもの","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/5cd89fecbc19e5f499f2ce035878eccc.png?id=190"},"188":{"title":"仲間との絆","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/f73f8f283142cacbcc8b4b22a341b2c1.png?id=191"},"189":{"title":"あなたの声はどこから?","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/3a13d019d3193887d3269e9b5c6521b0.png?id=192"},"190":{"title":"救世主の力","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/67669d40dda0a98c12d3aaffe4174d13.png?id=193"},"191":{"title":"視認性","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/918c68204e4349fc11012e619bf70ebf.png?id=194"},"192":{"title":"騙されません","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/44f08d5403ca1ddf83c10d153dc8eb64.png?id=195"},"193":{"title":"武勇伝","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/91b14fb6f9192de4ecea001595735c2c.png?id=196"},"194":{"title":"見えなくても","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/301fb94ae6a5dc1baae46acff71e4ccd.png?id=197"},"195":{"title":"胃袋を…","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/879c28a0cb71553cd7170cee097427c1.png?id=198"},"198":{"title":"全海ノ支配者-Leviathan-","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/78be92c45559959f1db03a4cf4a95652.png?id=201"},"199":{"title":"ぐうたら力","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/f142ed7ef869b9249898ff06b4156bef.png?id=202"},"200":{"title":"封印されし邪眼","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/9c439688e78b97640084f38ac2fecdac.png?id=203"},"201":{"title":"おねえちゃんパワー","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/b8a6394167252900977ef5b67fb51ac0.png?id=204"},"209":{"title":"迷宮女王復活","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/01bee34f76c7401118949bd911da8275.png?id=212"},"210":{"title":"エンジェリックアローパワー","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/4938807bf8f581b89891d5c84253f955.png?id=213"},"211":{"title":"エンジェル活動!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/f69cc7e6d567e3461cf5f52dcc92f694.png?id=214"},"212":{"title":"オ・ト・ナ❤コーデ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/10426d451f37b47094eed5375e2b2e3e.png?id=215"},"213":{"title":"闇と光","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/a5659fff37ced44a6ca679475687ba91.png?id=216"},"214":{"title":"お嬢様の苦悩(前編)","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/c71defeda0820c124cc28b9f871a5f4b.png?id=217"},"215":{"title":"お嬢様の苦悩(後編)","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/edad6bc871373bacd970c6519712c4a6.png?id=218"},"216":{"title":"灰燼に帰す","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/a22a75f55dd463e21964b6abe16fbef5.png?id=219"},"217":{"title":"本当の悲鳴","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/773fdf54a233bb9ec1e8bc68c6e151b5.png?id=220"},"218":{"title":"マツリ・タイガーフォーム","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/8acd9d3c4f2aea706c4ca949369081a8.png?id=221"},"219":{"title":"次は……","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/8b1e7b3e6ab8703d2bcc5270071fa144.png?id=222"},"220":{"title":"一点集中","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/8d576bc2412bbcae5953397d6e53a5b0.png?id=223"},"221":{"title":"新しいステップ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/176b962f867e50ee8e90663550c0cafa.png?id=224"},"222":{"title":"おかわり","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/10ba44952438be2beb5decb997828248.png?id=225"},"223":{"title":"歌に合わせて","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/b9d954179d549d9ef3b6e850a88cbb92.png?id=226"},"337":{"title":"美味しいご飯のために","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/7d07939d3e42ea036a1b9c185b30b954.png?id=345"},"338":{"title":"『協力』の大切さ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/a1593e983f604a69576d86cc959e594a.png?id=346"},"339":{"title":"にぎやかな日々の終わり","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/1bf91efbe8dedc4edb89119cf19da1c0.png?id=347"},"340":{"title":"独演会","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/b04fd7a48befb06b8455c6c219b132fb.png?id=348"},"341":{"title":"ワクワク海遊び","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/cb7db1b122c0bd0b17bf19cfc136d8cf.png?id=349"},"342":{"title":"狙われるチーズ","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/3937fd7d5e20e9b8a9acc7cf80312f8a.png?id=350"},"343":{"title":"異世界転生美少女?","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/b4cc8410995c6d7feb9f24e85d76c668.png?id=351"},"344":{"title":"天国かも","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/545fa09b7f6b803d1f24395da2752009.png?id=352"},"345":{"title":"迷子の美少女","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/a9d79dc698e669be014a0a8349960e28.png?id=353"},"346":{"title":"無自覚な?","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/a30c4f896589a546f9e29075844074f4.png?id=354"},"347":{"title":"人探し","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/f3efddf1833dc3bf32c00f601b32db49.png?id=355"},"348":{"title":"やっぱり無自覚な?","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/c3ef25e9a1217877cd0f11bd299fbe4c.png?id=356"},"349":{"title":"新☆決めポーズ!","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/e590bf6983e7e5c0e163b6b78718c0d6.png?id=357"},"350":{"title":"左右のバランス","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/79afab896398de5b1b8d2e3f1cfe71e3.png?id=358"},"351":{"title":"効率的武器利用","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/dde2702cebd796bec812bf7684228013.png?id=359"},"352":{"title":"秘密の乙女たち","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/2cbccbe1be171b0088fc1a3f4d9a4252.png?id=360"},"353":{"title":"特技を活かして","link":"https:\/\/comic.priconne-redive.jp\/media\/cartoon\/image\/abed6dd0b05fea8cda3a86c23f99b131.png?id=361"}} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_0.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_0.png new file mode 100644 index 0000000..2623bc0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_0.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_1.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_1.png new file mode 100644 index 0000000..058fb1a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_1.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_10.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_10.png new file mode 100644 index 0000000..35339dd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_10.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_11.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_11.png new file mode 100644 index 0000000..64dbffd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_11.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_12.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_12.png new file mode 100644 index 0000000..0e4b97c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_12.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_13.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_13.png new file mode 100644 index 0000000..7c79544 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_13.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_14.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_14.png new file mode 100644 index 0000000..0768954 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_14.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_15.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_15.png new file mode 100644 index 0000000..a096f74 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_15.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_16.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_16.png new file mode 100644 index 0000000..bbdff3a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_16.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_17.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_17.png new file mode 100644 index 0000000..c1de20c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_17.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_18.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_18.png new file mode 100644 index 0000000..d15e619 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_18.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_19.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_19.png new file mode 100644 index 0000000..73713bd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_19.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_2.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_2.png new file mode 100644 index 0000000..1613c32 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_2.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_20.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_20.png new file mode 100644 index 0000000..52c4939 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_20.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_21.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_21.png new file mode 100644 index 0000000..dc89322 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_21.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_22.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_22.png new file mode 100644 index 0000000..6f7cbd9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_22.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_23.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_23.png new file mode 100644 index 0000000..7af811c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_23.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_24.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_24.png new file mode 100644 index 0000000..66e2149 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_24.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_25.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_25.png new file mode 100644 index 0000000..c4e2298 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_25.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_3.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_3.png new file mode 100644 index 0000000..952f8ae Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_3.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_4.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_4.png new file mode 100644 index 0000000..4ff045c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_4.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_5.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_5.png new file mode 100644 index 0000000..dfe541e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_5.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_6.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_6.png new file mode 100644 index 0000000..51981df Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_6.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_7.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_7.png new file mode 100644 index 0000000..4ba473a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_7.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_8.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_8.png new file mode 100644 index 0000000..2845a7c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_8.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_9.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_9.png new file mode 100644 index 0000000..7ee731c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/find/icon_unit_9.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/equip.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/equip.png new file mode 100644 index 0000000..72c8e97 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/equip.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/kokkoro_stamp.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/kokkoro_stamp.png new file mode 100644 index 0000000..7e63710 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/kokkoro_stamp.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/star.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/star.png new file mode 100644 index 0000000..3b7e03f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/star.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/star_disabled.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/star_disabled.png new file mode 100644 index 0000000..4914bd0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/star_disabled.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/star_pink.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/star_pink.png new file mode 100644 index 0000000..957de2b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/star_pink.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/thumb-down-a.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/thumb-down-a.png new file mode 100644 index 0000000..672bc77 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/thumb-down-a.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/thumb-down-i.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/thumb-down-i.png new file mode 100644 index 0000000..dd16f78 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/thumb-down-i.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/thumb-up-a.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/thumb-up-a.png new file mode 100644 index 0000000..9f934cc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/thumb-up-a.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/thumb-up-i.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/thumb-up-i.png new file mode 100644 index 0000000..f6b519d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/gadget/thumb-up-i.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/icon_unit_112931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/icon_unit_112931.png new file mode 100644 index 0000000..5e66537 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/icon_unit_112931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/kokkoro_stamp.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/kokkoro_stamp.png new file mode 100644 index 0000000..32acd0d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/kokkoro_stamp.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/newyearburst.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/newyearburst.jpg new file mode 100644 index 0000000..9146be9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/newyearburst.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/R16-4.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/R16-4.png new file mode 100644 index 0000000..2126a56 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/R16-4.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/kokkoro_stamp.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/kokkoro_stamp.png new file mode 100644 index 0000000..7e63710 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/kokkoro_stamp.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/quick.rar b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/quick.rar new file mode 100644 index 0000000..7f1fd97 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/quick.rar differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r15-5-0.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r15-5-0.png new file mode 100644 index 0000000..2287c12 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r15-5-0.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r15-5.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r15-5.png new file mode 100644 index 0000000..df056ab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r15-5.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-4-tw-0.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-4-tw-0.png new file mode 100644 index 0000000..2126a56 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-4-tw-0.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-4-tw-1.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-4-tw-1.png new file mode 100644 index 0000000..6f0ce7c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-4-tw-1.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-5-1.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-5-1.png new file mode 100644 index 0000000..6f49741 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-5-1.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-5-2.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-5-2.png new file mode 100644 index 0000000..ec82bac Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-5-2.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-5-3.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-5-3.png new file mode 100644 index 0000000..ac85693 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r16-5-3.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r17-3-jp-1.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r17-3-jp-1.png new file mode 100644 index 0000000..2bfcd71 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r17-3-jp-1.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r17-3-jp-2.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r17-3-jp-2.png new file mode 100644 index 0000000..272563a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r17-3-jp-2.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r17-3-jp-3.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r17-3-jp-3.png new file mode 100644 index 0000000..1eea3d2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r17-3-jp-3.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r8-3.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r8-3.jpg new file mode 100644 index 0000000..7d99540 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r8-3.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r9-5-cn.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r9-5-cn.png new file mode 100644 index 0000000..b235c1f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/r9-5-cn.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/中卫.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/中卫.png new file mode 100644 index 0000000..4339fcc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/中卫.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/前卫.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/前卫.png new file mode 100644 index 0000000..d1899bc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/前卫.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/台6月rank.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/台6月rank.jpg new file mode 100644 index 0000000..c9feecb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/台6月rank.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/后卫.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/后卫.png new file mode 100644 index 0000000..66b8f24 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/后卫.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/国服.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/国服.png new file mode 100644 index 0000000..51dd8de Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/国服.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/黄骑充电.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/黄骑充电.jpg new file mode 100644 index 0000000..1493126 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/quick/黄骑充电.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/spider.py b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/spider.py new file mode 100644 index 0000000..10d9d72 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/spider.py @@ -0,0 +1,89 @@ +import os +import re +import time +import json +import requests +from urllib.parse import urlparse, urlunparse +from requests.compat import quote, urljoin +from PIL import Image +from io import BytesIO + +class Spider(object): + + def download_img(self, save_path, link): + print('download_img from ', link, end=' ') + resp = requests.get(link, stream=True) + print('status_code=', resp.status_code, end=' ') + if 200 == resp.status_code: + if re.search(r'image', resp.headers['content-type'], re.I): + print(f'is image, saving to {save_path}', end=' ') + img = Image.open(BytesIO(resp.content)) + img.save(save_path) + print('ok', end=' ') + + + def download_icon_unit(self, start=1001, end=1200, star=3): + base = 'https://redive.estertion.win/icon/unit/' + save_dir = './unit/' + os.makedirs(save_dir, exist_ok=True) + + def get_pic_name(pic_id, pre, end): + return f'{pre}{pic_id:0>4d}{end}' + + + for i in range(start, end): + src_n = get_pic_name(i, '', f'{star}1.webp') + dst_n = get_pic_name(i, 'icon_unit_', f'{star}1.png') + self.download_img(os.path.join(save_dir, dst_n), urljoin(base, src_n)) + time.sleep(0.5) + print('\n', end='') + + + def download_comic(self, start=1, end=200, only_index=False): + base = 'https://comic.priconne-redive.jp/api/detail/' + save_dir = './comic/' + os.makedirs(save_dir, exist_ok=True) + + def get_pic_name(id_): + pre = 'episode_' + end = '.png' + return f'{pre}{id_}{end}' + + index = {} + + for i in range(start, end): + print('getting comic', i, '...', end=' ') + url = base + str(i) + print('url=', url, end=' ') + resp = requests.get(url) + print('status_code=', resp.status_code) + if 200 != resp.status_code: + continue + data = resp.json()[0] + + # if data['current_index'] != False: + episode = data['episode_num'] + title = data['title'] + link = data['cartoon'] + index[episode] = {'title': title, 'link': link} + print(index[episode]) + if not only_index: + self.download_img(os.path.join(save_dir, get_pic_name(episode)), link) + time.sleep(0.1) + print('\n', end='') + # else: + # print('current_index not True, ignore') + + with open(os.path.join(save_dir, 'index.json'), 'w', encoding='utf8') as f: + json.dump(index, f, ensure_ascii=False) + + +if __name__ == '__main__': + spider = Spider() + # 运行过程出现404和200属正常情况 + spider.download_icon_unit(start=1700 end=1702, star=3) + #spider.download_icon_unit(start=8999, end=9001, star=1) + #spider.download_icon_unit(start=1030, end=1040, star=6) + #spider.download_icon_unit(start=1804, end=1809, star=3) + # 如果需要爬取漫画,取消掉下面的这行注释 + # spider.download_comic(start=1, end=200, only_index=False) diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/spider_shadow.py b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/spider_shadow.py new file mode 100644 index 0000000..d303643 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/spider_shadow.py @@ -0,0 +1,89 @@ +import os +import re +import time +import json +import requests +from urllib.parse import urlparse, urlunparse +from requests.compat import quote, urljoin +from PIL import Image +from io import BytesIO + +class Spider(object): + + def download_img(self, save_path, link): + print('download_img from ', link, end=' ') + resp = requests.get(link, stream=True) + print('status_code=', resp.status_code, end=' ') + if 200 == resp.status_code: + if re.search(r'image', resp.headers['content-type'], re.I): + print(f'is image, saving to {save_path}', end=' ') + img = Image.open(BytesIO(resp.content)) + img.save(save_path) + print('ok', end=' ') + + + def download_icon_unit(self, start=1001, end=1200, star=3): + base = 'https://redive.estertion.win/icon/unit_shadow/' + save_dir = './unit_shadow/' + os.makedirs(save_dir, exist_ok=True) + + def get_pic_name(pic_id, pre, end): + return f'{pre}{pic_id:0>4d}{end}' + + + for i in range(start, end): + src_n = get_pic_name(i, '', f'{star}1.webp') + dst_n = get_pic_name(i, 'icon_unit_', f'{star}1.png') + self.download_img(os.path.join(save_dir, dst_n), urljoin(base, src_n)) + time.sleep(0.5) + print('\n', end='') + + + def download_comic(self, start=1, end=200, only_index=False): + base = 'https://comic.priconne-redive.jp/api/detail/' + save_dir = './comic/' + os.makedirs(save_dir, exist_ok=True) + + def get_pic_name(id_): + pre = 'episode_' + end = '.png' + return f'{pre}{id_}{end}' + + index = {} + + for i in range(start, end): + print('getting comic', i, '...', end=' ') + url = base + str(i) + print('url=', url, end=' ') + resp = requests.get(url) + print('status_code=', resp.status_code) + if 200 != resp.status_code: + continue + data = resp.json()[0] + + # if data['current_index'] != False: + episode = data['episode_num'] + title = data['title'] + link = data['cartoon'] + index[episode] = {'title': title, 'link': link} + print(index[episode]) + if not only_index: + self.download_img(os.path.join(save_dir, get_pic_name(episode)), link) + time.sleep(0.1) + print('\n', end='') + # else: + # print('current_index not True, ignore') + + with open(os.path.join(save_dir, 'index.json'), 'w', encoding='utf8') as f: + json.dump(index, f, ensure_ascii=False) + + +if __name__ == '__main__': + spider = Spider() + # 运行过程出现404和200属正常情况 + spider.download_icon_unit(start=1113, end=1115, star=3) + #spider.download_icon_unit(start=1001, end=1038, star=1) + #spider.download_icon_unit(start=1001, end=1040, star=6) + #spider.download_icon_unit(start=1800, end=1809, star=3) + # 如果需要爬取漫画,取消掉下面的这行注释 + # spider.download_comic(start=1, end=200, only_index=False) diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/spider_unique.py b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/spider_unique.py new file mode 100644 index 0000000..6ce8383 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/spider_unique.py @@ -0,0 +1,89 @@ +import os +import re +import time +import json +import requests +from urllib.parse import urlparse, urlunparse +from requests.compat import quote, urljoin +from PIL import Image +from io import BytesIO + +class Spider(object): + + def download_img(self, save_path, link): + print('download_img from ', link, end=' ') + resp = requests.get(link, stream=True) + print('status_code=', resp.status_code, end=' ') + if 200 == resp.status_code: + if re.search(r'image', resp.headers['content-type'], re.I): + print(f'is image, saving to {save_path}', end=' ') + img = Image.open(BytesIO(resp.content)) + img.save(save_path) + print('ok', end=' ') + + + def download_icon_unit(self, start=1001, end=1200, star=3): + base = 'https://redive.estertion.win/icon/unit/' + save_dir = './unit/' + os.makedirs(save_dir, exist_ok=True) + + def get_pic_name(pic_id, pre, end): + return f'{pre}{pic_id:0>4d}{end}' + + + for i in range(start, end): + src_n = get_pic_name(i, '', f'{star}0.webp') + dst_n = get_pic_name(i, 'icon_unit_', f'{star}0.png') + self.download_img(os.path.join(save_dir, dst_n), urljoin(base, src_n)) + time.sleep(0.5) + print('\n', end='') + + + def download_comic(self, start=1, end=200, only_index=False): + base = 'https://comic.priconne-redive.jp/api/detail/' + save_dir = './comic/' + os.makedirs(save_dir, exist_ok=True) + + def get_pic_name(id_): + pre = 'episode_' + end = '.png' + return f'{pre}{id_}{end}' + + index = {} + + for i in range(start, end): + print('getting comic', i, '...', end=' ') + url = base + str(i) + print('url=', url, end=' ') + resp = requests.get(url) + print('status_code=', resp.status_code) + if 200 != resp.status_code: + continue + data = resp.json()[0] + + # if data['current_index'] != False: + episode = data['episode_num'] + title = data['title'] + link = data['cartoon'] + index[episode] = {'title': title, 'link': link} + print(index[episode]) + if not only_index: + self.download_img(os.path.join(save_dir, get_pic_name(episode)), link) + time.sleep(0.1) + print('\n', end='') + # else: + # print('current_index not True, ignore') + + with open(os.path.join(save_dir, 'index.json'), 'w', encoding='utf8') as f: + json.dump(index, f, ensure_ascii=False) + + +if __name__ == '__main__': + spider = Spider() + # 运行过程出现404和200属正常情况 + spider.download_icon_unit(start=3901, end=3902, star=0) + #spider.download_icon_unit(start=8999, end=9001, star=1) + #spider.download_icon_unit(start=1030, end=1040, star=6) + #spider.download_icon_unit(start=1804, end=1809, star=3) + # 如果需要爬取漫画,取消掉下面的这行注释 + # spider.download_comic(start=1, end=200, only_index=False) diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/cropped_avatar.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/cropped_avatar.png new file mode 100644 index 0000000..b5d3162 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/cropped_avatar.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_002412.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_002412.png new file mode 100644 index 0000000..91f9ce9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_002412.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100031.png new file mode 100644 index 0000000..df15196 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100111.png new file mode 100644 index 0000000..6d53494 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100131.png new file mode 100644 index 0000000..325c07b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100161.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100161.png new file mode 100644 index 0000000..182add9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100161.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100211.png new file mode 100644 index 0000000..24ac5f2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100231.png new file mode 100644 index 0000000..03f7920 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100261.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100261.png new file mode 100644 index 0000000..fc35680 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100261.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100311.png new file mode 100644 index 0000000..19a3ffb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100331.png new file mode 100644 index 0000000..b8d41dc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100361.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100361.png new file mode 100644 index 0000000..1206316 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100361.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100411.png new file mode 100644 index 0000000..f2783f4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100431.png new file mode 100644 index 0000000..23f3af5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100511.png new file mode 100644 index 0000000..30e12d8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100531.png new file mode 100644 index 0000000..e84fd3e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100611.png new file mode 100644 index 0000000..f82f00c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100631.png new file mode 100644 index 0000000..88977f2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100661.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100661.png new file mode 100644 index 0000000..708bf5e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100661.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100711.png new file mode 100644 index 0000000..f060b9c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100731.png new file mode 100644 index 0000000..2755c8b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100811.png new file mode 100644 index 0000000..c693d28 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100831.png new file mode 100644 index 0000000..55c35f9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100911.png new file mode 100644 index 0000000..2183185 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100931.png new file mode 100644 index 0000000..1e4133a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_100931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101011.png new file mode 100644 index 0000000..07ae6cd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101031.png new file mode 100644 index 0000000..6e08342 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101061.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101061.png new file mode 100644 index 0000000..5c29356 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101061.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101111.png new file mode 100644 index 0000000..c37a120 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101131.png new file mode 100644 index 0000000..29b9064 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101161.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101161.png new file mode 100644 index 0000000..f348c3f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101161.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101211.png new file mode 100644 index 0000000..7a5d207 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101231.png new file mode 100644 index 0000000..dfe2173 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101261.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101261.png new file mode 100644 index 0000000..ebd9dea Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101261.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101311.png new file mode 100644 index 0000000..304b3d0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101331.png new file mode 100644 index 0000000..38d65e8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101411.png new file mode 100644 index 0000000..5d6f5a4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101431.png new file mode 100644 index 0000000..bcb4a4c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101511.png new file mode 100644 index 0000000..87bfc7c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101531.png new file mode 100644 index 0000000..be51aca Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101611.png new file mode 100644 index 0000000..fca1e2a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101631.png new file mode 100644 index 0000000..491deae Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101661.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101661.png new file mode 100644 index 0000000..4186064 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101661.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101711.png new file mode 100644 index 0000000..5dcd529 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101731.png new file mode 100644 index 0000000..cf4e816 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101811.png new file mode 100644 index 0000000..c9e9c16 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101831.png new file mode 100644 index 0000000..15d67d9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101861.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101861.png new file mode 100644 index 0000000..4aa4102 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_101861.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102011.png new file mode 100644 index 0000000..e8fbebe Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102031.png new file mode 100644 index 0000000..7d15560 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102111.png new file mode 100644 index 0000000..bf4a443 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102131.png new file mode 100644 index 0000000..4d2ac47 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102211.png new file mode 100644 index 0000000..b132c4e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102231.png new file mode 100644 index 0000000..73c9f4d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102311.png new file mode 100644 index 0000000..87c3ccc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102331.png new file mode 100644 index 0000000..e3fceb2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102361.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102361.png new file mode 100644 index 0000000..5cdfbb9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102361.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102511.png new file mode 100644 index 0000000..a850bba Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102531.png new file mode 100644 index 0000000..85768ad Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102611.png new file mode 100644 index 0000000..59b8ff2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102631.png new file mode 100644 index 0000000..4579dbd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102711.png new file mode 100644 index 0000000..2afb8cc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102731.png new file mode 100644 index 0000000..c616b74 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102811.png new file mode 100644 index 0000000..91ff648 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102831.png new file mode 100644 index 0000000..3cdedc0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102861.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102861.png new file mode 100644 index 0000000..93c373f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102861.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102911.png new file mode 100644 index 0000000..8443b10 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102931.png new file mode 100644 index 0000000..bee4755 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_102931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103011.png new file mode 100644 index 0000000..b125d42 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103031.png new file mode 100644 index 0000000..3a66352 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103061.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103061.png new file mode 100644 index 0000000..6e919a9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103061.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103111.png new file mode 100644 index 0000000..0349ea7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103131.png new file mode 100644 index 0000000..0fee254 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103211.png new file mode 100644 index 0000000..1e729b9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103231.png new file mode 100644 index 0000000..f2c7f0d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103261.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103261.png new file mode 100644 index 0000000..ab1d52e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103261.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103311.png new file mode 100644 index 0000000..56f2f54 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103331.png new file mode 100644 index 0000000..3fca82f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103361.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103361.png new file mode 100644 index 0000000..aaf1b3e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103361.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103411.png new file mode 100644 index 0000000..b3e8952 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103431.png new file mode 100644 index 0000000..69f04bc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103461.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103461.png new file mode 100644 index 0000000..e5429f6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103461.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103611.png new file mode 100644 index 0000000..b6ed87b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103631.png new file mode 100644 index 0000000..150aaaf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103711.png new file mode 100644 index 0000000..3a5a495 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103731.png new file mode 100644 index 0000000..e4bb48b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103811.png new file mode 100644 index 0000000..fa09e1b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103831.png new file mode 100644 index 0000000..c468c01 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_103831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104011.png new file mode 100644 index 0000000..33197a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104031.png new file mode 100644 index 0000000..889498b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104211.png new file mode 100644 index 0000000..9134b0b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104231.png new file mode 100644 index 0000000..8689de0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104311.png new file mode 100644 index 0000000..fb007fc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104331.png new file mode 100644 index 0000000..64824d0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104411.png new file mode 100644 index 0000000..5529124 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104431.png new file mode 100644 index 0000000..05339f6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104511.png new file mode 100644 index 0000000..5e9d4fe Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104531.png new file mode 100644 index 0000000..be62729 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104611.png new file mode 100644 index 0000000..1efdefb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104631.png new file mode 100644 index 0000000..9068f81 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104661.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104661.png new file mode 100644 index 0000000..419e5bc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104661.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104711.png new file mode 100644 index 0000000..0191bf1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104731.png new file mode 100644 index 0000000..e37d1cd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104811.png new file mode 100644 index 0000000..e7f887f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104831.png new file mode 100644 index 0000000..57f802e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104861.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104861.png new file mode 100644 index 0000000..3594a5d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104861.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104911.png new file mode 100644 index 0000000..a13d445 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104931.png new file mode 100644 index 0000000..c09fecc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104961.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104961.png new file mode 100644 index 0000000..8f1bfb3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_104961.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105011.png new file mode 100644 index 0000000..da3d02d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105031.png new file mode 100644 index 0000000..e128d0a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105111.png new file mode 100644 index 0000000..7b032e5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105131.png new file mode 100644 index 0000000..3cdcede Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105211.png new file mode 100644 index 0000000..db61a27 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105231.png new file mode 100644 index 0000000..01eb3c3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105261.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105261.png new file mode 100644 index 0000000..5ebb9da Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105261.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105311.png new file mode 100644 index 0000000..cc0b5a0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105331.png new file mode 100644 index 0000000..cef3c8e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105411.png new file mode 100644 index 0000000..4e98cc4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105431.png new file mode 100644 index 0000000..c15aa44 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105511.png new file mode 100644 index 0000000..fd204a5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105531.png new file mode 100644 index 0000000..91aba67 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105611.png new file mode 100644 index 0000000..22c59c2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105631.png new file mode 100644 index 0000000..395ffa2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105711.png new file mode 100644 index 0000000..3a5b88f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105731.png new file mode 100644 index 0000000..8ed21e3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105811.png new file mode 100644 index 0000000..485c00f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105831.png new file mode 100644 index 0000000..b4f22b2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105861.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105861.png new file mode 100644 index 0000000..609b407 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105861.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105911.png new file mode 100644 index 0000000..87f53f6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105931.png new file mode 100644 index 0000000..5206cb5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105961.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105961.png new file mode 100644 index 0000000..1d6230a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_105961.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106011.png new file mode 100644 index 0000000..5a5a0a6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106031.png new file mode 100644 index 0000000..966805e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106061.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106061.png new file mode 100644 index 0000000..94c84a4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106061.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106111.png new file mode 100644 index 0000000..6a97228 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106131.png new file mode 100644 index 0000000..8e0d13b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106211.png new file mode 100644 index 0000000..95f5a8e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106231.png new file mode 100644 index 0000000..4094009 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106311.png new file mode 100644 index 0000000..cb8f1a3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106331.png new file mode 100644 index 0000000..4a13514 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106411.png new file mode 100644 index 0000000..5591420 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106431.png new file mode 100644 index 0000000..8b55462 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106511.png new file mode 100644 index 0000000..be83dcd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106531.png new file mode 100644 index 0000000..035b9d2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106611.png new file mode 100644 index 0000000..99016be Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106631.png new file mode 100644 index 0000000..5784644 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106711.png new file mode 100644 index 0000000..18830cf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106731.png new file mode 100644 index 0000000..18830cf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106811.png new file mode 100644 index 0000000..f02571d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106831.png new file mode 100644 index 0000000..4793270 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106911.png new file mode 100644 index 0000000..6d1aa6c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106931.png new file mode 100644 index 0000000..609d880 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_106931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107011.png new file mode 100644 index 0000000..83bb381 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107031.png new file mode 100644 index 0000000..aead89e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107111.png new file mode 100644 index 0000000..6a5ac0f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107131.png new file mode 100644 index 0000000..c7d43e1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107311.png new file mode 100644 index 0000000..dbca915 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107331.png new file mode 100644 index 0000000..b28fb04 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107511.png new file mode 100644 index 0000000..8a0fbf2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107531.png new file mode 100644 index 0000000..34eed3b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107611.png new file mode 100644 index 0000000..1e601a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107631.png new file mode 100644 index 0000000..b4e4b31 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107711.png new file mode 100644 index 0000000..551b53c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107731.png new file mode 100644 index 0000000..110bdc5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107811.png new file mode 100644 index 0000000..c241781 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107831.png new file mode 100644 index 0000000..acbd724 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107911.png new file mode 100644 index 0000000..70ca0b4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107931.png new file mode 100644 index 0000000..159fcc3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_107931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108011.png new file mode 100644 index 0000000..df65fc2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108031.png new file mode 100644 index 0000000..311f8be Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108111.png new file mode 100644 index 0000000..9337769 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108131.png new file mode 100644 index 0000000..39823cc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108211.png new file mode 100644 index 0000000..df34bc6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108231.png new file mode 100644 index 0000000..11e28af Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108311.png new file mode 100644 index 0000000..44c3c3b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108331.png new file mode 100644 index 0000000..e832b09 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108411.png new file mode 100644 index 0000000..abd184e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108431.png new file mode 100644 index 0000000..a2b9a1c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108511.png new file mode 100644 index 0000000..815a00c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108531.png new file mode 100644 index 0000000..ad7572b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108611.png new file mode 100644 index 0000000..06bd3b4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108631.png new file mode 100644 index 0000000..7e85dd2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108711.png new file mode 100644 index 0000000..b8d982d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108731.png new file mode 100644 index 0000000..b3d317b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108811.png new file mode 100644 index 0000000..b8c00ca Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108831.png new file mode 100644 index 0000000..59595de Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108911.png new file mode 100644 index 0000000..89bfc00 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108931.png new file mode 100644 index 0000000..5b36dd0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_108931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109011.png new file mode 100644 index 0000000..79dde67 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109031.png new file mode 100644 index 0000000..1a93531 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109111.png new file mode 100644 index 0000000..ca7c833 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109131.png new file mode 100644 index 0000000..becbc59 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109211.png new file mode 100644 index 0000000..29ee780 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109231.png new file mode 100644 index 0000000..62bd038 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109311.png new file mode 100644 index 0000000..1c1000a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109331.png new file mode 100644 index 0000000..15e6890 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109411.png new file mode 100644 index 0000000..c4a1b38 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109431.png new file mode 100644 index 0000000..700eafc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109511.png new file mode 100644 index 0000000..eeececb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109531.png new file mode 100644 index 0000000..a72b88d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109611.png new file mode 100644 index 0000000..1ada3df Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109631.png new file mode 100644 index 0000000..b84fc9b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109711.png new file mode 100644 index 0000000..da1db26 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109731.png new file mode 100644 index 0000000..00db87f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109811.png new file mode 100644 index 0000000..5ed14e5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109831.png new file mode 100644 index 0000000..9345aa7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109911.png new file mode 100644 index 0000000..971e7cf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109931.png new file mode 100644 index 0000000..22238af Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_109931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110011.png new file mode 100644 index 0000000..33cf572 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110031.png new file mode 100644 index 0000000..049e25c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110111.png new file mode 100644 index 0000000..44c28de Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110131.png new file mode 100644 index 0000000..a7197f6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110231.png new file mode 100644 index 0000000..4d0b0a2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110311.png new file mode 100644 index 0000000..a099c19 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110331.png new file mode 100644 index 0000000..d57c59c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110411.png new file mode 100644 index 0000000..a4ae0bb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110431.png new file mode 100644 index 0000000..3b6ea41 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110511.png new file mode 100644 index 0000000..e0212dd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110531.png new file mode 100644 index 0000000..84b849d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110611.png new file mode 100644 index 0000000..079828c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110631.png new file mode 100644 index 0000000..4b8658b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110711.png new file mode 100644 index 0000000..0cef712 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110731.png new file mode 100644 index 0000000..d644141 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110811.png new file mode 100644 index 0000000..3963d71 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110831.png new file mode 100644 index 0000000..3ae74be Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110911.png new file mode 100644 index 0000000..7542885 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110931.png new file mode 100644 index 0000000..2663909 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_110931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111011.png new file mode 100644 index 0000000..cb138b6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111031.png new file mode 100644 index 0000000..034cb41 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111111.png new file mode 100644 index 0000000..6f64c12 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111131.png new file mode 100644 index 0000000..016c9a9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111211.png new file mode 100644 index 0000000..2393939 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111231.png new file mode 100644 index 0000000..78c82ff Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111311.png new file mode 100644 index 0000000..fbadec6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111331.png new file mode 100644 index 0000000..85ba8da Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111411.png new file mode 100644 index 0000000..1a7d2bf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111431.png new file mode 100644 index 0000000..3d70924 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111511.png new file mode 100644 index 0000000..eacf1cd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111531.png new file mode 100644 index 0000000..4fa8a8e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111611.png new file mode 100644 index 0000000..bf6f726 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111631.png new file mode 100644 index 0000000..bac862c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111711.png new file mode 100644 index 0000000..466c8b6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111731.png new file mode 100644 index 0000000..e012cc9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111811.png new file mode 100644 index 0000000..46e8351 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111831.png new file mode 100644 index 0000000..570a3e2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111911.png new file mode 100644 index 0000000..ac0e411 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111931.png new file mode 100644 index 0000000..4ecbc1b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_111931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112011.png new file mode 100644 index 0000000..f0825f0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112031.png new file mode 100644 index 0000000..b4c0967 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112111.png new file mode 100644 index 0000000..763d4f5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112131.png new file mode 100644 index 0000000..4509e23 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112211.png new file mode 100644 index 0000000..26ff666 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112231.png new file mode 100644 index 0000000..a4a0731 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112311.png new file mode 100644 index 0000000..abf1e5e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112331.png new file mode 100644 index 0000000..11a4157 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112411.png new file mode 100644 index 0000000..f382bec Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112431.png new file mode 100644 index 0000000..6866c9f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112511.png new file mode 100644 index 0000000..e96c0b4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112531.png new file mode 100644 index 0000000..fad25a5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112611.png new file mode 100644 index 0000000..fe2c6be Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112631.png new file mode 100644 index 0000000..04a8010 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112731.png new file mode 100644 index 0000000..44a28d2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112831.png new file mode 100644 index 0000000..a34372c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112931.png new file mode 100644 index 0000000..5e66537 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_112931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113011.png new file mode 100644 index 0000000..e831a69 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113031.png new file mode 100644 index 0000000..6576a97 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113111.png new file mode 100644 index 0000000..edffea9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113131.png new file mode 100644 index 0000000..8a3295a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113211.png new file mode 100644 index 0000000..1c97d1a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113231.png new file mode 100644 index 0000000..6d3f239 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113311.png new file mode 100644 index 0000000..bd8c163 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113331.png new file mode 100644 index 0000000..956943f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113411.png new file mode 100644 index 0000000..a8d4634 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113431.png new file mode 100644 index 0000000..a92805b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113511.png new file mode 100644 index 0000000..33d8f2d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113531.png new file mode 100644 index 0000000..99c249e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113611.png new file mode 100644 index 0000000..37cbaf6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113631.png new file mode 100644 index 0000000..75def3f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113711.png new file mode 100644 index 0000000..248be92 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113731.png new file mode 100644 index 0000000..cda94e3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113811.png new file mode 100644 index 0000000..c16a665 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113831.png new file mode 100644 index 0000000..fb363b7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113911.png new file mode 100644 index 0000000..36531b0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113931.png new file mode 100644 index 0000000..4a43443 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_113931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114011.png new file mode 100644 index 0000000..47284b9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114031.png new file mode 100644 index 0000000..1ac7db6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114111.png new file mode 100644 index 0000000..07e1cfc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114131.png new file mode 100644 index 0000000..a35a8a6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114211.png new file mode 100644 index 0000000..2b28097 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114231.png new file mode 100644 index 0000000..9709f7f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114311.png new file mode 100644 index 0000000..756e629 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114331.png new file mode 100644 index 0000000..95fbc04 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114411.png new file mode 100644 index 0000000..af3d801 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114431.png new file mode 100644 index 0000000..97fb232 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114511.png new file mode 100644 index 0000000..2638796 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114531.png new file mode 100644 index 0000000..1763ab5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114611.png new file mode 100644 index 0000000..11e21c0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114631.png new file mode 100644 index 0000000..9ba4768 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114711.png new file mode 100644 index 0000000..ea0d046 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114731.png new file mode 100644 index 0000000..2fdafe5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_114731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115011.png new file mode 100644 index 0000000..ea6d777 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115031.png new file mode 100644 index 0000000..ea1d7d3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115511.png new file mode 100644 index 0000000..112a478 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115531.png new file mode 100644 index 0000000..86a9caf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115611.png new file mode 100644 index 0000000..f818a83 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115631.png new file mode 100644 index 0000000..a9cb4dd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115711.png new file mode 100644 index 0000000..72fa1f2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115731.png new file mode 100644 index 0000000..91ecb73 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115811.png new file mode 100644 index 0000000..347fba1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115831.png new file mode 100644 index 0000000..a39219a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115911.png new file mode 100644 index 0000000..a7c4a39 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115931.png new file mode 100644 index 0000000..5fb5b17 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_115931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116011.png new file mode 100644 index 0000000..b13c0a4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116031.png new file mode 100644 index 0000000..baba62a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116211.png new file mode 100644 index 0000000..d94761e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116231.png new file mode 100644 index 0000000..f4d03dc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116311.png new file mode 100644 index 0000000..36d3e1b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116331.png new file mode 100644 index 0000000..6cde4f4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116411.png new file mode 100644 index 0000000..de07d17 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116431.png new file mode 100644 index 0000000..3aff124 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116511.png new file mode 100644 index 0000000..100921d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116531.png new file mode 100644 index 0000000..d52de97 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116611.png new file mode 100644 index 0000000..9f199d9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116631.png new file mode 100644 index 0000000..02caf59 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116711.png new file mode 100644 index 0000000..e29d342 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116731.png new file mode 100644 index 0000000..da55105 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116811.png new file mode 100644 index 0000000..fb908d9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116831.png new file mode 100644 index 0000000..141ea6f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116911.png new file mode 100644 index 0000000..b15127f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116931.png new file mode 100644 index 0000000..b3c620b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_116931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117011.png new file mode 100644 index 0000000..adc18a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117031.png new file mode 100644 index 0000000..b87d02b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117111.png new file mode 100644 index 0000000..08c2f45 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117131.png new file mode 100644 index 0000000..7df4615 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117211.png new file mode 100644 index 0000000..f85f0be Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117231.png new file mode 100644 index 0000000..d0cc8c2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117311.png new file mode 100644 index 0000000..501aed9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117331.png new file mode 100644 index 0000000..6caf9f8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117411.png new file mode 100644 index 0000000..2cdb4d4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117431.png new file mode 100644 index 0000000..b6fb3a2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117511.png new file mode 100644 index 0000000..23fb515 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117531.png new file mode 100644 index 0000000..a1ac5b8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117611.png new file mode 100644 index 0000000..61fa171 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117631.png new file mode 100644 index 0000000..f100cfe Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117711.png new file mode 100644 index 0000000..22ae5e0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117731.png new file mode 100644 index 0000000..6080b18 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117811.png new file mode 100644 index 0000000..604a876 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117831.png new file mode 100644 index 0000000..59f6901 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117911.png new file mode 100644 index 0000000..d2f93da Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117931.png new file mode 100644 index 0000000..50a531d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_117931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118011.png new file mode 100644 index 0000000..4f88f88 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118031.png new file mode 100644 index 0000000..98b5f31 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118111.png new file mode 100644 index 0000000..570b2d7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118131.png new file mode 100644 index 0000000..a0c7e6d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118311.png new file mode 100644 index 0000000..a45eb3b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118331.png new file mode 100644 index 0000000..cb1b9d8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118411.png new file mode 100644 index 0000000..33b1aa7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118431.png new file mode 100644 index 0000000..645dbc9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118511.png new file mode 100644 index 0000000..93cb904 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118531.png new file mode 100644 index 0000000..db3d47b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_118531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119011.png new file mode 100644 index 0000000..b71b2a4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119031.png new file mode 100644 index 0000000..f35ec78 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119111.png new file mode 100644 index 0000000..ade3648 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119131.png new file mode 100644 index 0000000..de22fd1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119211.png new file mode 100644 index 0000000..dbcda82 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119231.png new file mode 100644 index 0000000..39e351a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119311.png new file mode 100644 index 0000000..4f906be Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119331.png new file mode 100644 index 0000000..4c9f1ef Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119911.png new file mode 100644 index 0000000..aaedcfc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119931.png new file mode 100644 index 0000000..f81bb9b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_119931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120411.png new file mode 100644 index 0000000..dfdabe0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120431.png new file mode 100644 index 0000000..f14294b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120511.png new file mode 100644 index 0000000..4d5648d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120531.png new file mode 100644 index 0000000..d70b2f6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120611.png new file mode 100644 index 0000000..09e22ab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120631.png new file mode 100644 index 0000000..28cbda9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120711.png new file mode 100644 index 0000000..ab1411e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120731.png new file mode 100644 index 0000000..79a8865 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120811.png new file mode 100644 index 0000000..7958259 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120831.png new file mode 100644 index 0000000..7a053f4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120911.png new file mode 100644 index 0000000..6df6f36 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120931.png new file mode 100644 index 0000000..97167d4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_120931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121011.png new file mode 100644 index 0000000..fd8bc2d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121031.png new file mode 100644 index 0000000..6552f06 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121111.png new file mode 100644 index 0000000..f825560 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121131.png new file mode 100644 index 0000000..6d71bec Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121211.png new file mode 100644 index 0000000..ed64089 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121231.png new file mode 100644 index 0000000..43e6bc0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_121231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_170111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_170111.png new file mode 100644 index 0000000..93a848c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_170111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_170131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_170131.png new file mode 100644 index 0000000..48efaa2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_170131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_170211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_170211.png new file mode 100644 index 0000000..d253047 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_170211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_170231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_170231.png new file mode 100644 index 0000000..09529ea Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_170231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180111.png new file mode 100644 index 0000000..036b257 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180131.png new file mode 100644 index 0000000..271003d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180211.png new file mode 100644 index 0000000..2c3e376 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180231.png new file mode 100644 index 0000000..05bba12 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180311.png new file mode 100644 index 0000000..c861c99 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180331.png new file mode 100644 index 0000000..70b3c9a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180411.png new file mode 100644 index 0000000..8d0d6b6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180431.png new file mode 100644 index 0000000..c5f69e3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180511.png new file mode 100644 index 0000000..4bd028b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180531.png new file mode 100644 index 0000000..5cf78b5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180611.png new file mode 100644 index 0000000..24b92dd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180631.png new file mode 100644 index 0000000..19d16f6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180711.png new file mode 100644 index 0000000..7ca0a84 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180731.png new file mode 100644 index 0000000..9229d95 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180811.png new file mode 100644 index 0000000..74b585e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180831.png new file mode 100644 index 0000000..4eca19f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_180831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190011.png new file mode 100644 index 0000000..7d7e6f6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190111.png new file mode 100644 index 0000000..0a48a44 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190711.png new file mode 100644 index 0000000..af358b2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190811.png new file mode 100644 index 0000000..1d7b12e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190911.png new file mode 100644 index 0000000..75a9b1f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_190911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191011.png new file mode 100644 index 0000000..7f216e5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191111.png new file mode 100644 index 0000000..0a553d4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191311.png new file mode 100644 index 0000000..c2631d2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191411.png new file mode 100644 index 0000000..ff4df17 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191511.png new file mode 100644 index 0000000..ce2eeeb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191611.png new file mode 100644 index 0000000..13eb98f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191711.png new file mode 100644 index 0000000..97f6e5c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191811.png new file mode 100644 index 0000000..31266e1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191911.png new file mode 100644 index 0000000..6f23a62 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_191911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_192011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_192011.png new file mode 100644 index 0000000..d985610 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_192011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_390100.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_390100.png new file mode 100644 index 0000000..ef9413a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_390100.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_700131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_700131.png new file mode 100644 index 0000000..846a036 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_700131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_700231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_700231.png new file mode 100644 index 0000000..ebe2b08 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_700231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_700331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_700331.png new file mode 100644 index 0000000..1a48be2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_700331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_700431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_700431.png new file mode 100644 index 0000000..950bafc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_700431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_900011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_900011.png new file mode 100644 index 0000000..68ccddb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_900011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_900013.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_900013.png new file mode 100644 index 0000000..68ccddb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_900013.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_940131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_940131.png new file mode 100644 index 0000000..f693de9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/icon_unit_940131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/kokkoro_stamp.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/kokkoro_stamp.png new file mode 100644 index 0000000..7e63710 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/kokkoro_stamp.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/template.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/template.png new file mode 100644 index 0000000..7f4bc76 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit/template.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100111.png new file mode 100644 index 0000000..61ad75f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100131.png new file mode 100644 index 0000000..8540259 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100161.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100161.png new file mode 100644 index 0000000..16859ff Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100161.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100211.png new file mode 100644 index 0000000..a86a864 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100231.png new file mode 100644 index 0000000..4227482 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100261.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100261.png new file mode 100644 index 0000000..580bd8d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100261.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100311.png new file mode 100644 index 0000000..dccd9af Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100331.png new file mode 100644 index 0000000..f44b91a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100361.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100361.png new file mode 100644 index 0000000..4a0994f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100361.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100411.png new file mode 100644 index 0000000..9cc5e78 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100431.png new file mode 100644 index 0000000..c7f4582 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100511.png new file mode 100644 index 0000000..a7b6014 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100531.png new file mode 100644 index 0000000..ea85bb6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100611.png new file mode 100644 index 0000000..fed4d2d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100631.png new file mode 100644 index 0000000..c6a1616 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100711.png new file mode 100644 index 0000000..b5bf425 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100731.png new file mode 100644 index 0000000..36513c1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100811.png new file mode 100644 index 0000000..0e42129 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100831.png new file mode 100644 index 0000000..db14a01 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100911.png new file mode 100644 index 0000000..7e529bf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100931.png new file mode 100644 index 0000000..76a275a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_100931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101011.png new file mode 100644 index 0000000..21da5a6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101031.png new file mode 100644 index 0000000..c8e6736 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101061.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101061.png new file mode 100644 index 0000000..aa8beb7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101061.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101111.png new file mode 100644 index 0000000..2481da4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101131.png new file mode 100644 index 0000000..f01f404 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101161.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101161.png new file mode 100644 index 0000000..f0f3d1c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101161.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101211.png new file mode 100644 index 0000000..3595c90 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101231.png new file mode 100644 index 0000000..53fd6aa Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101261.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101261.png new file mode 100644 index 0000000..aaf34db Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101261.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101311.png new file mode 100644 index 0000000..db29258 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101331.png new file mode 100644 index 0000000..2440f6c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101411.png new file mode 100644 index 0000000..919f418 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101431.png new file mode 100644 index 0000000..33cba82 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101511.png new file mode 100644 index 0000000..9af1dac Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101531.png new file mode 100644 index 0000000..e4942fb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101611.png new file mode 100644 index 0000000..7ba87cf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101631.png new file mode 100644 index 0000000..471942a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101711.png new file mode 100644 index 0000000..4d59d97 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101731.png new file mode 100644 index 0000000..8e96bb3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101811.png new file mode 100644 index 0000000..9602baf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101831.png new file mode 100644 index 0000000..b77bf35 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101861.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101861.png new file mode 100644 index 0000000..c57a1b0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_101861.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102011.png new file mode 100644 index 0000000..63f913e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102031.png new file mode 100644 index 0000000..47fccd1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102111.png new file mode 100644 index 0000000..3db6257 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102131.png new file mode 100644 index 0000000..3018719 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102211.png new file mode 100644 index 0000000..8aab22f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102231.png new file mode 100644 index 0000000..8687007 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102311.png new file mode 100644 index 0000000..99314a6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102331.png new file mode 100644 index 0000000..8858ea4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102361.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102361.png new file mode 100644 index 0000000..a4c3111 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102361.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102511.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102511.png new file mode 100644 index 0000000..c7faf9c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102511.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102531.png new file mode 100644 index 0000000..caadba1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102611.png new file mode 100644 index 0000000..d7bfa70 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102631.png new file mode 100644 index 0000000..142b3cd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102711.png new file mode 100644 index 0000000..9377e5a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102731.png new file mode 100644 index 0000000..b3656e8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102811.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102811.png new file mode 100644 index 0000000..312fa53 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102811.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102831.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102831.png new file mode 100644 index 0000000..506b5eb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102831.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102861.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102861.png new file mode 100644 index 0000000..46745cb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102861.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102911.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102911.png new file mode 100644 index 0000000..06b7a93 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102911.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102931.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102931.png new file mode 100644 index 0000000..00da2b5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_102931.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103011.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103011.png new file mode 100644 index 0000000..eb2ac63 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103011.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103031.png new file mode 100644 index 0000000..3162960 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103111.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103111.png new file mode 100644 index 0000000..e471e95 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103111.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103131.png new file mode 100644 index 0000000..3326762 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103211.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103211.png new file mode 100644 index 0000000..e4c7793 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103211.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103231.png new file mode 100644 index 0000000..df2123d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103261.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103261.png new file mode 100644 index 0000000..dac6f50 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103261.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103311.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103311.png new file mode 100644 index 0000000..b8e5965 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103311.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103331.png new file mode 100644 index 0000000..64cab52 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103411.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103411.png new file mode 100644 index 0000000..18a6435 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103411.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103431.png new file mode 100644 index 0000000..c0a234f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103461.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103461.png new file mode 100644 index 0000000..998aafa Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103461.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103611.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103611.png new file mode 100644 index 0000000..dc2ea86 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103611.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103631.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103631.png new file mode 100644 index 0000000..ebe2b08 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103631.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103711.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103711.png new file mode 100644 index 0000000..687b9da Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103711.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103731.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103731.png new file mode 100644 index 0000000..0185d7d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_103731.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_111031.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_111031.png new file mode 100644 index 0000000..96c1efa Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_111031.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_111131.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_111131.png new file mode 100644 index 0000000..1a48be2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_111131.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_111331.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_111331.png new file mode 100644 index 0000000..5c1c1c8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_111331.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_111431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_111431.png new file mode 100644 index 0000000..950bafc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_111431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_180231.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_180231.png new file mode 100644 index 0000000..bff34e7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_180231.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_180431.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_180431.png new file mode 100644 index 0000000..e07c5c0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_180431.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_180531.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_180531.png new file mode 100644 index 0000000..a507923 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/unit_shadow/icon_unit_180531.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/xcw_stamp.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/xcw_stamp.jpg new file mode 100644 index 0000000..32acd0d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/xcw_stamp.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/我的天啊你看看都几度了.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/我的天啊你看看都几度了.jpg new file mode 100644 index 0000000..49df601 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/priconne/我的天啊你看看都几度了.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/1.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/1.png new file mode 100644 index 0000000..a124f05 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/1.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/10.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/10.png new file mode 100644 index 0000000..64d0634 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/10.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/11.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/11.png new file mode 100644 index 0000000..6ed2b81 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/11.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/12.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/12.png new file mode 100644 index 0000000..adaa115 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/12.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/13.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/13.png new file mode 100644 index 0000000..ba1bcec Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/13.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/14.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/14.png new file mode 100644 index 0000000..dbd9179 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/14.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/15.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/15.png new file mode 100644 index 0000000..7900c11 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/15.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/16.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/16.png new file mode 100644 index 0000000..97c4bf6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/16.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/17.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/17.png new file mode 100644 index 0000000..73b0b77 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/17.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/18.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/18.png new file mode 100644 index 0000000..214d48e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/18.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/19.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/19.png new file mode 100644 index 0000000..647be35 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/19.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/2.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/2.png new file mode 100644 index 0000000..1d7e0f1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/2.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/20.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/20.png new file mode 100644 index 0000000..d678128 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/20.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/21.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/21.png new file mode 100644 index 0000000..b638b23 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/21.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/22.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/22.png new file mode 100644 index 0000000..e130783 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/22.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/23.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/23.png new file mode 100644 index 0000000..7d47b97 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/23.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/24.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/24.png new file mode 100644 index 0000000..e066cb7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/24.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/25.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/25.png new file mode 100644 index 0000000..93c8018 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/25.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/26.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/26.png new file mode 100644 index 0000000..12e94ca Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/26.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/27.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/27.png new file mode 100644 index 0000000..980f116 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/27.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/28.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/28.png new file mode 100644 index 0000000..980f116 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/28.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/29.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/29.png new file mode 100644 index 0000000..691a3ba Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/29.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/3.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/3.png new file mode 100644 index 0000000..5a7480c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/3.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/30.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/30.png new file mode 100644 index 0000000..7c957e7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/30.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/31.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/31.png new file mode 100644 index 0000000..44e9b39 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/31.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/32.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/32.png new file mode 100644 index 0000000..299d281 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/32.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/33.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/33.png new file mode 100644 index 0000000..bd3c9e6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/33.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/34.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/34.png new file mode 100644 index 0000000..d6fbea6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/34.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/35.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/35.png new file mode 100644 index 0000000..422f3e5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/35.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/36.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/36.png new file mode 100644 index 0000000..8d50bd6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/36.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/37.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/37.png new file mode 100644 index 0000000..95a39f9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/37.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/38.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/38.png new file mode 100644 index 0000000..c4d6014 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/38.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/39.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/39.png new file mode 100644 index 0000000..39553f8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/39.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/4.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/4.png new file mode 100644 index 0000000..c34ffeb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/4.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/40.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/40.png new file mode 100644 index 0000000..0fb446e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/40.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/41.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/41.png new file mode 100644 index 0000000..a6ab426 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/41.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/5.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/5.png new file mode 100644 index 0000000..f18051c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/5.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/6.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/6.png new file mode 100644 index 0000000..51bf55d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/6.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/7.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/7.png new file mode 100644 index 0000000..9339387 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/7.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/8.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/8.png new file mode 100644 index 0000000..7e63710 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/8.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/9.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/9.png new file mode 100644 index 0000000..2d61c14 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/9.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/去括号.bat b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/去括号.bat new file mode 100644 index 0000000..d33636c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/stamp/去括号.bat @@ -0,0 +1,8 @@ +@Echo Off&SetLocal ENABLEDELAYEDEXPANSION +FOR %%a in (*) do ( +set "name=%%a" +set "name=!name: (=!" +set "name=!name:)=!" +ren "%%a" "!name!" +) +exit \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/0爆.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/0爆.jpg new file mode 100644 index 0000000..8bf0189 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/0爆.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/83766CE7861D533B3C60A085C54F8BAE.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/83766CE7861D533B3C60A085C54F8BAE.jpg new file mode 100644 index 0000000..ead590e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/83766CE7861D533B3C60A085C54F8BAE.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (1).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (1).jpg new file mode 100644 index 0000000..e3fda27 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (1).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (10).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (10).jpg new file mode 100644 index 0000000..7793e1e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (10).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (11).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (11).jpg new file mode 100644 index 0000000..42b86b1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (11).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (12).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (12).jpg new file mode 100644 index 0000000..a08f896 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (12).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (13).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (13).jpg new file mode 100644 index 0000000..3205704 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (13).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (14).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (14).jpg new file mode 100644 index 0000000..3c394cb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (14).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (15).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (15).jpg new file mode 100644 index 0000000..f45fa12 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (15).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (16).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (16).jpg new file mode 100644 index 0000000..c67168f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (16).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (17).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (17).jpg new file mode 100644 index 0000000..14e2210 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (17).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (18).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (18).jpg new file mode 100644 index 0000000..db4d8e4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (18).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (19).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (19).jpg new file mode 100644 index 0000000..3e58e88 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (19).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (2).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (2).jpg new file mode 100644 index 0000000..d1e867f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (2).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (20).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (20).jpg new file mode 100644 index 0000000..d6c406d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (20).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (21).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (21).jpg new file mode 100644 index 0000000..f1147d6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (21).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (22).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (22).jpg new file mode 100644 index 0000000..35174c3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (22).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (23).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (23).jpg new file mode 100644 index 0000000..0ac4fdc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (23).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (24).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (24).jpg new file mode 100644 index 0000000..8cfd6a9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (24).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (25).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (25).jpg new file mode 100644 index 0000000..f111a38 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (25).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (26).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (26).jpg new file mode 100644 index 0000000..804f6ac Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (26).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (27).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (27).jpg new file mode 100644 index 0000000..e52ebd7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (27).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (28).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (28).jpg new file mode 100644 index 0000000..31813dd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (28).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (3).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (3).jpg new file mode 100644 index 0000000..06f9fab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (3).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (4).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (4).jpg new file mode 100644 index 0000000..3bd3e7f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (4).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (5).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (5).jpg new file mode 100644 index 0000000..e471223 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (5).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (6).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (6).jpg new file mode 100644 index 0000000..4167119 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (6).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (7).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (7).jpg new file mode 100644 index 0000000..79fed83 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (7).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (8).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (8).jpg new file mode 100644 index 0000000..34bd59f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (8).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (9).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (9).jpg new file mode 100644 index 0000000..ca61f22 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1 (9).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1.jpg new file mode 100644 index 0000000..d1e867f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/1.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/10.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/10.jpg new file mode 100644 index 0000000..42b86b1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/10.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/11.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/11.jpg new file mode 100644 index 0000000..a08f896 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/11.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/12.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/12.jpg new file mode 100644 index 0000000..3205704 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/12.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/13.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/13.jpg new file mode 100644 index 0000000..3c394cb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/13.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/14.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/14.jpg new file mode 100644 index 0000000..f45fa12 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/14.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/15.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/15.jpg new file mode 100644 index 0000000..c67168f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/15.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/16.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/16.jpg new file mode 100644 index 0000000..14e2210 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/16.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/17.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/17.jpg new file mode 100644 index 0000000..db4d8e4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/17.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/18.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/18.jpg new file mode 100644 index 0000000..3e58e88 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/18.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/19.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/19.jpg new file mode 100644 index 0000000..d6c406d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/19.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/2.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/2.jpg new file mode 100644 index 0000000..06f9fab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/2.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/20.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/20.jpg new file mode 100644 index 0000000..f1147d6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/20.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/21.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/21.jpg new file mode 100644 index 0000000..35174c3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/21.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/22.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/22.jpg new file mode 100644 index 0000000..0ac4fdc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/22.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/23.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/23.jpg new file mode 100644 index 0000000..8cfd6a9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/23.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/24.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/24.jpg new file mode 100644 index 0000000..f111a38 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/24.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/25.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/25.jpg new file mode 100644 index 0000000..804f6ac Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/25.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/26.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/26.jpg new file mode 100644 index 0000000..e52ebd7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/26.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/27.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/27.jpg new file mode 100644 index 0000000..31813dd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/27.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/28.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/28.jpg new file mode 100644 index 0000000..e3fda27 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/28.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/3.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/3.jpg new file mode 100644 index 0000000..3bd3e7f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/3.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/4.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/4.jpg new file mode 100644 index 0000000..e471223 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/4.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/5.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/5.jpg new file mode 100644 index 0000000..4167119 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/5.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/6.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/6.jpg new file mode 100644 index 0000000..79fed83 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/6.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/7.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/7.jpg new file mode 100644 index 0000000..34bd59f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/7.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/8.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/8.jpg new file mode 100644 index 0000000..ca61f22 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/8.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/9.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/9.jpg new file mode 100644 index 0000000..7793e1e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/9.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/QQ图片20210112170726.gif b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/QQ图片20210112170726.gif new file mode 100644 index 0000000..8967eab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/huhuhu/QQ图片20210112170726.gif differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/moring.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/moring.jpg new file mode 100644 index 0000000..3d7caaa Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/moring.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (1).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (1).jpg new file mode 100644 index 0000000..141ca66 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (1).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (1).png b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (1).png new file mode 100644 index 0000000..93f671d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (1).png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (10).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (10).jpg new file mode 100644 index 0000000..3af3965 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (10).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (11).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (11).jpg new file mode 100644 index 0000000..2cf629f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (11).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (12).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (12).jpg new file mode 100644 index 0000000..8dcfe7e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (12).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (13).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (13).jpg new file mode 100644 index 0000000..9920f03 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (13).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (14).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (14).jpg new file mode 100644 index 0000000..b0d5ae0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (14).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (15).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (15).jpg new file mode 100644 index 0000000..2d3c01b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (15).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (16).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (16).jpg new file mode 100644 index 0000000..e308714 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (16).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (17).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (17).jpg new file mode 100644 index 0000000..ea5051c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (17).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (18).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (18).jpg new file mode 100644 index 0000000..350c5c5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (18).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (19).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (19).jpg new file mode 100644 index 0000000..2073291 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (19).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (2).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (2).jpg new file mode 100644 index 0000000..4510d37 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (2).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (20).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (20).jpg new file mode 100644 index 0000000..436d382 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (20).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (21).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (21).jpg new file mode 100644 index 0000000..945f9ad Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (21).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (22).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (22).jpg new file mode 100644 index 0000000..2d98aad Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (22).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (23).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (23).jpg new file mode 100644 index 0000000..a2dbb87 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (23).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (24).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (24).jpg new file mode 100644 index 0000000..9bf965a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (24).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (25).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (25).jpg new file mode 100644 index 0000000..79deb5b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (25).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (26).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (26).jpg new file mode 100644 index 0000000..6d0783f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (26).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (3).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (3).jpg new file mode 100644 index 0000000..8268898 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (3).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (4).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (4).jpg new file mode 100644 index 0000000..8ce941d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (4).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (5).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (5).jpg new file mode 100644 index 0000000..5a2b5b2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (5).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (6).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (6).jpg new file mode 100644 index 0000000..3acdb55 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (6).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (7).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (7).jpg new file mode 100644 index 0000000..bc41e5f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (7).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (8).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (8).jpg new file mode 100644 index 0000000..8f56658 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (8).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (9).jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (9).jpg new file mode 100644 index 0000000..80de6d0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa (9).jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa1.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa1.jpg new file mode 100644 index 0000000..141ca66 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa1.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa1.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa1.png new file mode 100644 index 0000000..93f671d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa1.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa10.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa10.jpg new file mode 100644 index 0000000..3af3965 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa10.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa11.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa11.jpg new file mode 100644 index 0000000..2cf629f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa11.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa12.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa12.jpg new file mode 100644 index 0000000..8dcfe7e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa12.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa13.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa13.jpg new file mode 100644 index 0000000..9920f03 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa13.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa14.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa14.jpg new file mode 100644 index 0000000..b0d5ae0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa14.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa15.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa15.jpg new file mode 100644 index 0000000..2d3c01b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa15.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa16.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa16.jpg new file mode 100644 index 0000000..e308714 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa16.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa17.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa17.jpg new file mode 100644 index 0000000..ea5051c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa17.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa18.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa18.jpg new file mode 100644 index 0000000..350c5c5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa18.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa19.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa19.jpg new file mode 100644 index 0000000..2073291 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa19.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa2.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa2.jpg new file mode 100644 index 0000000..4510d37 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa2.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa20.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa20.jpg new file mode 100644 index 0000000..436d382 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa20.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa21.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa21.jpg new file mode 100644 index 0000000..945f9ad Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa21.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa22.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa22.jpg new file mode 100644 index 0000000..2d98aad Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa22.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa23.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa23.jpg new file mode 100644 index 0000000..a2dbb87 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa23.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa24.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa24.jpg new file mode 100644 index 0000000..9bf965a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa24.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa25.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa25.jpg new file mode 100644 index 0000000..79deb5b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa25.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa26.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa26.jpg new file mode 100644 index 0000000..6d0783f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa26.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa3.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa3.jpg new file mode 100644 index 0000000..8268898 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa3.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa4.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa4.jpg new file mode 100644 index 0000000..8ce941d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa4.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa5.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa5.jpg new file mode 100644 index 0000000..5a2b5b2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa5.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa6.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa6.jpg new file mode 100644 index 0000000..3acdb55 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa6.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa7.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa7.jpg new file mode 100644 index 0000000..bc41e5f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa7.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa8.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa8.jpg new file mode 100644 index 0000000..8f56658 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa8.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa9.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa9.jpg new file mode 100644 index 0000000..80de6d0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/pa/pa9.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/shangke.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/shangke.jpg new file mode 100644 index 0000000..9010dd4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/shangke.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/xcw.py b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/xcw.py new file mode 100644 index 0000000..239c7d1 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/xcw.py @@ -0,0 +1,129 @@ +import os +import random + + +from nonebot.exceptions import CQHttpError +from nonebot import MessageSegment + + +from hoshino import R, Service, priv + + +sv = Service('xcw语音', visible= True, enable_on_default= True, bundle='xcw语音', help_=''' +- [@bot 骂我] xcw就会真的骂你 +'''.strip()) +xcw_folder_mawo = R.get('img/xcw/record/mawo/').path +xcw_folder_pa = R.get('img/xcw/image/pa/').path +xcw_folder_huhuhu = R.get('img/xcw/image/huhuhu/').path +xcw_folder_kkp = R.get('img/xcw/record/kkp/').path +xcw_folder_biantai = R.get('img/xcw/record/biantai/').path + +def get_xcw_mawo(): + files = os.listdir(xcw_folder_mawo) + filename = random.choice(files) + rec = R.get('img/xcw/record/mawo/', filename) + return rec + +def get_xcw_pa(): + files = os.listdir(xcw_folder_pa) + filename = random.choice(files) + rec = R.get('img/xcw/image/pa', filename) + return rec + +def get_xcw_huhuhu(): + files = os.listdir(xcw_folder_huhuhu) + filename = random.choice(files) + rec = R.get('img/xcw/image/huhuhu', filename) + return rec + +@sv.on_fullmatch('骂我', only_to_me=True) +async def xcw_mawo(bot, ev) -> MessageSegment: + # conditions all ok, send a xcw. + file = get_xcw_mawo() + try: + rec = MessageSegment.record(f'file:///{os.path.abspath(file.path)}') + await bot.send(ev, rec) + except CQHttpError: + sv.logger.error("发送失败") + +@sv.on_fullmatch('娇喘', only_to_me=True) +async def xcw_jiaochuan(bot, ev) -> MessageSegment: + filename = '喘息声.mp3' + file = R.get('img/xcw/record', filename) + try: + rec = MessageSegment.record(f'file:///{os.path.abspath(file.path)}') + await bot.send(ev, rec) + except CQHttpError: + sv.logger.error("发送失败") + +@sv.on_keyword('爬', only_to_me=False) +async def xcw_pa(bot, ev) -> MessageSegment: + file = get_xcw_pa() + try: + rec = MessageSegment.image(f'file:///{os.path.abspath(file.path)}') + await bot.send(ev, rec) + except CQHttpError: + sv.logger.error("发送失败") + +@sv.on_keyword('呼呼呼', only_to_me=False) +async def xcw_huhuhu(bot, ev) -> MessageSegment: + file = get_xcw_huhuhu() + try: + rec = MessageSegment.image(f'file:///{os.path.abspath(file.path)}') + await bot.send(ev, rec) + except CQHttpError: + sv.logger.error("发送失败") + +@sv.on_keyword(('0爆','0暴','零爆','零暴')) +async def xcw_huhuhu(bot, ev) -> MessageSegment: + filename = '0爆.jpg' + file = R.get('img/xcw/image', filename) + try: + rec = MessageSegment.image(f'file:///{os.path.abspath(file.path)}') + await bot.send(ev, rec) + except CQHttpError: + sv.logger.error("发送失败") + +dongdong = f'''洞洞还小你们不要~ +{R.img(f"xcw/image/脸红.png").cqcode} +'''.strip() + +@sv.on_keyword(('洞洞')) +async def dongdong(bot, ev): + if random.random() < 0.2: + await bot.send(ev, dongdong) + +@sv.on_fullmatch('啊这', only_to_me=False) +async def az(bot, ev): + if random.random() < 0.5: + await bot.send(ev, R.img('xcw/image/成熟点.jpg').cqcode) + + +@sv.on_keyword(('厉害了','666','斯国一')) +async def shigyi(bot, ev): + if random.random() < 0.2: + filename = '斯国一斯国一.mp3' + file = R.get('img/xcw/record', filename) + try: + rec = MessageSegment.image(f'file:///{os.path.abspath(file.path)}') + await bot.send(ev, rec) + except CQHttpError: + sv.logger.error("发送失败") + +@sv.on_keyword(('kkp')) +async def kkp(bot, ev): + file = xcw_folder_kkp() + try: + rec = MessageSegment.record(f'file:///{os.path.abspath(file.path)}') + await bot.send(ev, rec) + except CQHttpError: + sv.logger.error("发送失败") + +@sv.on_keyword('变态', only_to_me=True) +async def biantai(bot, ev): + file = xcw_folder_biantai() + try: + rec = MessageSegment.record(f'file:///{os.path.abspath(file.path)}') + await bot.send(ev, rec) + except CQHttpError: + sv.logger.error("发送失败") \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/偷笑.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/偷笑.png new file mode 100644 index 0000000..02a5244 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/偷笑.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/成熟点.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/成熟点.jpg new file mode 100644 index 0000000..f384248 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/成熟点.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/脸红.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/脸红.png new file mode 100644 index 0000000..bb4102b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/image/脸红.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/biantai/你是变态可疑分子.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/biantai/你是变态可疑分子.mp3 new file mode 100644 index 0000000..25aebfa Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/biantai/你是变态可疑分子.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/biantai/你是可疑分子.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/biantai/你是可疑分子.mp3 new file mode 100644 index 0000000..bacacbc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/biantai/你是可疑分子.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/biantai/我懂了,你是变态吧.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/biantai/我懂了,你是变态吧.mp3 new file mode 100644 index 0000000..10948a5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/biantai/我懂了,你是变态吧.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/biantai/超级可疑变态.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/biantai/超级可疑变态.mp3 new file mode 100644 index 0000000..252b255 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/biantai/超级可疑变态.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/kkp/呜~~~.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/kkp/呜~~~.mp3 new file mode 100644 index 0000000..66824d1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/kkp/呜~~~.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/kkp/呜~~~~.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/kkp/呜~~~~.mp3 new file mode 100644 index 0000000..405ab65 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/kkp/呜~~~~.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/kkp/唉,太讨厌了.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/kkp/唉,太讨厌了.mp3 new file mode 100644 index 0000000..4225327 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/kkp/唉,太讨厌了.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/kkp/讨厌大哥哥.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/kkp/讨厌大哥哥.mp3 new file mode 100644 index 0000000..feb3da1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/kkp/讨厌大哥哥.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/不要跟我说话,我告老师了.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/不要跟我说话,我告老师了.m4a new file mode 100644 index 0000000..f640f15 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/不要跟我说话,我告老师了.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/从朋友那里听说独自一个人找对话的人有可能是变态.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/从朋友那里听说独自一个人找对话的人有可能是变态.m4a new file mode 100644 index 0000000..03e9a5a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/从朋友那里听说独自一个人找对话的人有可能是变态.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/你怎么回事,无视我.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/你怎么回事,无视我.m4a new file mode 100644 index 0000000..c42b8e4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/你怎么回事,无视我.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/你是可疑分子.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/你是可疑分子.m4a new file mode 100644 index 0000000..54987c8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/你是可疑分子.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/呜,还是算了吧.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/呜,还是算了吧.m4a new file mode 100644 index 0000000..2993a07 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/呜,还是算了吧.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/哭泣声.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/哭泣声.m4a new file mode 100644 index 0000000..34a72f5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/哭泣声.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/唉,太讨厌了.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/唉,太讨厌了.m4a new file mode 100644 index 0000000..34e63ee Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/唉,太讨厌了.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/我懂了,你是变态吧.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/我懂了,你是变态吧.mp3 new file mode 100644 index 0000000..5ea4e79 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/我懂了,你是变态吧.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/放开我.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/放开我.m4a new file mode 100644 index 0000000..2af1e34 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/放开我.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/真的太笨了.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/真的太笨了.m4a new file mode 100644 index 0000000..ae57e0c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/真的太笨了.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/讨厌,都是你的错.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/讨厌,都是你的错.m4a new file mode 100644 index 0000000..3a152a8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/讨厌,都是你的错.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/都怪你,真是的!.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/都怪你,真是的!.m4a new file mode 100644 index 0000000..10b7974 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/mawo/都怪你,真是的!.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/叹气声.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/叹气声.mp3 new file mode 100644 index 0000000..07c3a97 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/叹气声.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/叹气声2.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/叹气声2.mp3 new file mode 100644 index 0000000..36265d2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/叹气声2.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/叹气声3.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/叹气声3.mp3 new file mode 100644 index 0000000..acbf92f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/叹气声3.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/呜~~~.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/呜~~~.mp3 new file mode 100644 index 0000000..66824d1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/呜~~~.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/呜~~~~.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/呜~~~~.mp3 new file mode 100644 index 0000000..405ab65 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/呜~~~~.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/喘息声.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/喘息声.mp3 new file mode 100644 index 0000000..059a2d1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/喘息声.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/斯国一斯国一.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/斯国一斯国一.mp3 new file mode 100644 index 0000000..fc71ea3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/xcw/record/斯国一斯国一.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/yao.jpeg b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao.jpeg new file mode 100644 index 0000000..3959b63 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao.jpeg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/yao.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao.png new file mode 100644 index 0000000..14f8785 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/yao1.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao1.jpg new file mode 100644 index 0000000..14f8785 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao1.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/yao1.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao1.png new file mode 100644 index 0000000..3e86f09 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao1.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/yao2.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao2.jpg new file mode 100644 index 0000000..e365c39 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao2.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/yao2.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao2.png new file mode 100644 index 0000000..938d89f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao2.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/yao3.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao3.jpg new file mode 100644 index 0000000..3959b63 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao3.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/yao3.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao3.png new file mode 100644 index 0000000..041276e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao3.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/yao4.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao4.png new file mode 100644 index 0000000..e365c39 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao4.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/yao5.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao5.png new file mode 100644 index 0000000..5f69993 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/yao5.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/不要以为这样就赢了.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/不要以为这样就赢了.jpg new file mode 100644 index 0000000..a936d2f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/不要以为这样就赢了.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/内鬼.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/内鬼.jpg new file mode 100644 index 0000000..19a43f1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/内鬼.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/内鬼.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/内鬼.png new file mode 100644 index 0000000..583b6d2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/内鬼.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/台6月rank.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/台6月rank.jpg new file mode 100644 index 0000000..c9feecb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/台6月rank.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/喊谁老婆呢.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/喊谁老婆呢.jpg new file mode 100644 index 0000000..effba04 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/喊谁老婆呢.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/我的天啊你看看都几度了.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/我的天啊你看看都几度了.jpg new file mode 100644 index 0000000..49df601 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/我的天啊你看看都几度了.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/我的天啊你看看都几点了.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/我的天啊你看看都几点了.jpg new file mode 100644 index 0000000..72b7e8b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/我的天啊你看看都几点了.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/我觉得吧有一说一确实是这样的.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/我觉得吧有一说一确实是这样的.jpg new file mode 100644 index 0000000..941fe4f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/我觉得吧有一说一确实是这样的.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/星奏.png b/hexi/plugins/nonebot_plugin_group_tools/res/img/星奏.png new file mode 100644 index 0000000..856bd36 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/星奏.png differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/img/确实.jpg b/hexi/plugins/nonebot_plugin_group_tools/res/img/确实.jpg new file mode 100644 index 0000000..9ffb09c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/img/确实.jpg differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/apex/kassa.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/apex/kassa.mp3 new file mode 100644 index 0000000..0a3b964 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/apex/kassa.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/a.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/a.mp3 new file mode 100644 index 0000000..7374851 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/a.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/aini.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/aini.mp3 new file mode 100644 index 0000000..5d31818 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/aini.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/cheche.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/cheche.mp3 new file mode 100644 index 0000000..9685dd0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/cheche.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/dongdongdong.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/dongdongdong.mp3 new file mode 100644 index 0000000..82c54fe Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/dongdongdong.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/dudulu.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/dudulu.mp3 new file mode 100644 index 0000000..bb4c3d6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/dudulu.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/duiya.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/duiya.mp3 new file mode 100644 index 0000000..52f3bbe Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/duiya.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/echohso.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/echohso.mp3 new file mode 100644 index 0000000..07b4feb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/echohso.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/hso.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/hso.mp3 new file mode 100644 index 0000000..8d5237f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/hso.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/jiehun.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/jiehun.mp3 new file mode 100644 index 0000000..d8e344d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/jiehun.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/jiehun2.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/jiehun2.mp3 new file mode 100644 index 0000000..3a373d8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/jiehun2.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/mide.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/mide.mp3 new file mode 100644 index 0000000..a21e1ef Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/mide.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/naozhong.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/naozhong.mp3 new file mode 100644 index 0000000..6e3f0ad Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/naozhong.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/shengri.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/shengri.mp3 new file mode 100644 index 0000000..42c3b03 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/shengri.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/whl.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/whl.mp3 new file mode 100644 index 0000000..c4501d7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/whl.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/woaini.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/woaini.m4a new file mode 100644 index 0000000..9c61fba Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/woaini.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/ywwuyidie.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/ywwuyidie.mp3 new file mode 100644 index 0000000..446a872 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/ywwuyidie.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/zenmehuishi.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/zenmehuishi.mp3 new file mode 100644 index 0000000..34ec070 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/zenmehuishi.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/不想睡觉-n.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/不想睡觉-n.mp3 new file mode 100644 index 0000000..f1eb523 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/不想睡觉-n.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/不想睡觉.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/不想睡觉.mp3 new file mode 100644 index 0000000..4e54112 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/不想睡觉.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/不行不行.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/不行不行.mp3 new file mode 100644 index 0000000..386fb56 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/不行不行.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/心灵震爆.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/心灵震爆.mp3 new file mode 100644 index 0000000..47b6fdd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/心灵震爆.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/晚安.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/晚安.mp3 new file mode 100644 index 0000000..ae8b00c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/echo/晚安.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/不要跟我说话,我告老师了.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/不要跟我说话,我告老师了.m4a new file mode 100644 index 0000000..f640f15 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/不要跟我说话,我告老师了.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/从朋友那里听说独自一个人找对话的人有可能是变态.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/从朋友那里听说独自一个人找对话的人有可能是变态.m4a new file mode 100644 index 0000000..03e9a5a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/从朋友那里听说独自一个人找对话的人有可能是变态.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/你怎么回事,无视我.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/你怎么回事,无视我.m4a new file mode 100644 index 0000000..c42b8e4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/你怎么回事,无视我.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/你是可疑分子.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/你是可疑分子.m4a new file mode 100644 index 0000000..54987c8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/你是可疑分子.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/呜,还是算了吧.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/呜,还是算了吧.m4a new file mode 100644 index 0000000..2993a07 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/呜,还是算了吧.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/哭泣声.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/哭泣声.m4a new file mode 100644 index 0000000..34a72f5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/哭泣声.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/唉,太讨厌了.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/唉,太讨厌了.m4a new file mode 100644 index 0000000..34e63ee Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/唉,太讨厌了.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/我懂了,你是变态吧.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/我懂了,你是变态吧.mp3 new file mode 100644 index 0000000..5ea4e79 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/我懂了,你是变态吧.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/放开我.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/放开我.m4a new file mode 100644 index 0000000..2af1e34 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/放开我.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/真的太笨了.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/真的太笨了.m4a new file mode 100644 index 0000000..ae57e0c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/真的太笨了.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/讨厌,都是你的错.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/讨厌,都是你的错.m4a new file mode 100644 index 0000000..3a152a8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/讨厌,都是你的错.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/都怪你,真是的!.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/都怪你,真是的!.m4a new file mode 100644 index 0000000..10b7974 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/mawo/都怪你,真是的!.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dianlao/颠佬.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dianlao/颠佬.mp3 new file mode 100644 index 0000000..31a34a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dianlao/颠佬.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj1.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj1.mp3 new file mode 100644 index 0000000..fc9a2d4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj1.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj2.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj2.mp3 new file mode 100644 index 0000000..ad7468c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj2.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj3.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj3.mp3 new file mode 100644 index 0000000..8b6a3c6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj3.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj4.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj4.mp3 new file mode 100644 index 0000000..9716565 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj4.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj5.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj5.mp3 new file mode 100644 index 0000000..0ce9163 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj5.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj6.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj6.mp3 new file mode 100644 index 0000000..a956556 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj6.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj7.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj7.mp3 new file mode 100644 index 0000000..f8110a9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/hj7.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/骂谁罕见.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/骂谁罕见.mp3 new file mode 100644 index 0000000..ae2722a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/dxl/骂谁罕见.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/冬雪莲wcnm.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/冬雪莲wcnm.mp3 new file mode 100644 index 0000000..8b6a3c6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/冬雪莲wcnm.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/冬雪莲阿弥诺斯.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/冬雪莲阿弥诺斯.mp3 new file mode 100644 index 0000000..9716565 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/冬雪莲阿弥诺斯.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/噩梦.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/噩梦.mp3 new file mode 100644 index 0000000..49b010d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/噩梦.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/我阐释你的梦.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/我阐释你的梦.wav new file mode 100644 index 0000000..9d68fe5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/我阐释你的梦.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/自私.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/自私.mp3 new file mode 100644 index 0000000..fab1a3f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/自私.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/装逼.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/装逼.mp3 new file mode 100644 index 0000000..bdd094c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/装逼.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/飞起来.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/飞起来.mp3 new file mode 100644 index 0000000..ee4efa0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/heishou/飞起来.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/uzi中国的希望我的希望.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/uzi中国的希望我的希望.wav new file mode 100644 index 0000000..d681ef7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/uzi中国的希望我的希望.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/uzi太强了兄弟们.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/uzi太强了兄弟们.wav new file mode 100644 index 0000000..241edb9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/uzi太强了兄弟们.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/下注中国队.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/下注中国队.wav new file mode 100644 index 0000000..394d962 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/下注中国队.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/优势还得扩大.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/优势还得扩大.wav new file mode 100644 index 0000000..0f6f832 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/优势还得扩大.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/别吵.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/别吵.wav new file mode 100644 index 0000000..bd74852 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/别吵.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/原子弹.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/原子弹.wav new file mode 100644 index 0000000..7c6a704 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/原子弹.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哇袄1.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哇袄1.wav new file mode 100644 index 0000000..8c5d903 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哇袄1.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哇袄2.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哇袄2.wav new file mode 100644 index 0000000..cfbe0f7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哇袄2.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哈比下.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哈比下.wav new file mode 100644 index 0000000..c2a25ec Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哈比下.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哈里路大旋风.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哈里路大旋风.wav new file mode 100644 index 0000000..0d20087 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哈里路大旋风.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哼想逃.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哼想逃.wav new file mode 100644 index 0000000..ddeb468 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/哼想逃.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/奥利安费.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/奥利安费.wav new file mode 100644 index 0000000..76db9b9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/奥利安费.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/我超冰.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/我超冰.wav new file mode 100644 index 0000000..248dfa6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/我超冰.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/我阐释你的梦.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/我阐释你的梦.wav new file mode 100644 index 0000000..9d68fe5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/我阐释你的梦.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/欧内的手.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/欧内的手.wav new file mode 100644 index 0000000..5fc4655 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/欧内的手.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/欧西给.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/欧西给.wav new file mode 100644 index 0000000..c58fed2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/欧西给.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/阿黑路西.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/阿黑路西.wav new file mode 100644 index 0000000..cada3fd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/阿黑路西.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/龟龟.wav b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/龟龟.wav new file mode 100644 index 0000000..4d6eb2f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/ice/龟龟.wav differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/1.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/1.m4a new file mode 100644 index 0000000..89a8631 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/1.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/10.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/10.m4a new file mode 100644 index 0000000..fcb76cb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/10.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/11.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/11.m4a new file mode 100644 index 0000000..d1ec199 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/11.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/12.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/12.m4a new file mode 100644 index 0000000..864ca35 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/12.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/13.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/13.m4a new file mode 100644 index 0000000..942af61 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/13.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/14.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/14.m4a new file mode 100644 index 0000000..25ab587 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/14.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/15.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/15.m4a new file mode 100644 index 0000000..37e9edf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/15.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/2.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/2.m4a new file mode 100644 index 0000000..ddec102 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/2.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/3.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/3.m4a new file mode 100644 index 0000000..17c6b8d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/3.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/4.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/4.m4a new file mode 100644 index 0000000..312db31 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/4.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/5.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/5.m4a new file mode 100644 index 0000000..7e79362 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/5.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/6.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/6.m4a new file mode 100644 index 0000000..5b367df Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/6.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/7.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/7.m4a new file mode 100644 index 0000000..807f597 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/7.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/8.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/8.m4a new file mode 100644 index 0000000..c3741f7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/8.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/9.m4a b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/9.m4a new file mode 100644 index 0000000..9aabc4a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/popy/9.m4a differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/sxc/sxc.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/sxc/sxc.mp3 new file mode 100644 index 0000000..2052c8a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/sxc/sxc.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/th/sxc2.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/th/sxc2.mp3 new file mode 100644 index 0000000..53bde19 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/th/sxc2.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/wangzhiqiang/别打我打他们.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/wangzhiqiang/别打我打他们.mp3 new file mode 100644 index 0000000..30f75ac Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/wangzhiqiang/别打我打他们.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/wangzhiqiang/加油子墨.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/wangzhiqiang/加油子墨.mp3 new file mode 100644 index 0000000..1521093 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/wangzhiqiang/加油子墨.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/wangzhiqiang/天哪那是接近的.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/wangzhiqiang/天哪那是接近的.mp3 new file mode 100644 index 0000000..c481f0b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/wangzhiqiang/天哪那是接近的.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/youzhizhanshi/最优质的战士.mp3 b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/youzhizhanshi/最优质的战士.mp3 new file mode 100644 index 0000000..db21f2b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_group_tools/res/record/voice/youzhizhanshi/最优质的战士.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_group_tools/services/__init__.py b/hexi/plugins/nonebot_plugin_group_tools/services/__init__.py new file mode 100644 index 0000000..4b41414 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/services/__init__.py @@ -0,0 +1 @@ +"""群管理工具插件的业务操作子包。""" diff --git a/hexi/plugins/nonebot_plugin_group_tools/services/moderation.py b/hexi/plugins/nonebot_plugin_group_tools/services/moderation.py new file mode 100644 index 0000000..757217a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/services/moderation.py @@ -0,0 +1,69 @@ +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent + +from nonebot_plugin_alconna import UniMessage + +from hexi.plugins.nonebot_plugin_hexi_core.custom_utils import check_manage + +from ..utils.permissions import is_bot_manage, self_member_info +from ..utils.text import parse_seconds + + +async def group_silence(bot: Bot, ev: GroupMessageEvent, gid: int, status: bool): + """全员禁言(带权限检查)""" + self_info = await self_member_info(bot, gid) + if not is_bot_manage(self_info): + await UniMessage.text("\n不给我管理员还想让我帮忙塞口球?做梦去吧!").send( + at_sender=True + ) + return + if not await check_manage(bot, ev): + await UniMessage.text("只有狗管理才能给大家塞口球哦w").send(at_sender=True) + return + try: + await bot.set_group_whole_ban(group_id=gid, enable=status) + if status: + await UniMessage.text("嘻嘻大家都被塞口球啦~").send() + else: + await UniMessage.text("全员禁言取消啦w").send() + except Exception as e: + await UniMessage.text(f"操作失败惹...\n错误代码:{e}").send(at_sender=True) + + +async def member_silence( + bot: Bot, + ev: GroupMessageEvent, + uid: int, + sid: int, + gid: int, + time: str, + silent: bool = False, +): + """单人禁言(带权限检查;uid == sid 时为禁言自己)""" + self_info = await self_member_info(bot, gid) + if not is_bot_manage(self_info): + await UniMessage.text("\n不给我管理员还想让我帮忙塞口球?做梦去吧!").send( + at_sender=True + ) + return + seconds = parse_seconds(time) + if seconds is None: + await UniMessage.text("憨批,时长都能输错?").send() + return + if uid != sid and not await check_manage(bot, ev): + await UniMessage.text("只有管理员才可以给别人塞口球哦~").send(at_sender=True) + return + try: + await bot.set_group_ban(group_id=gid, user_id=sid, duration=seconds) + if seconds == 0: + await UniMessage.at(user_id=str(sid)).text("的口球已经摘下来啦w").send() + elif not silent: + await UniMessage.at(user_id=str(sid)).text(f"成功禁言{seconds}秒~").send() + except Exception as e: + await UniMessage.text(f"口球失败惹呜呜呜...\n错误代码:{e}").send(at_sender=True) + + +async def silence(bot: Bot, ev: MessageEvent, seconds: int) -> None: + """禁言发送者自己 seconds 秒(娱乐用,bot 需具有群管理权限,静默执行)""" + await member_silence( + bot, ev, ev.user_id, ev.user_id, ev.group_id, str(seconds), silent=True + ) diff --git a/hexi/plugins/nonebot_plugin_group_tools/services/profile.py b/hexi/plugins/nonebot_plugin_group_tools/services/profile.py new file mode 100644 index 0000000..e8f94bc --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/services/profile.py @@ -0,0 +1,76 @@ +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent + +from nonebot_plugin_alconna import UniMessage + +from hexi.plugins.nonebot_plugin_hexi_core.custom_utils import check_manage + +from ..utils.permissions import is_bot_manage, self_member_info + + +async def title_get( + bot: Bot, ev: GroupMessageEvent, uid: int, sid: int, gid: int, title: str | None +): + """头衔申请/删除""" + self_info = await self_member_info(bot, gid) + if not self_info or self_info["role"] != "owner": + await UniMessage.text( + "\n嘻嘻嘻,把群转移给我才能用这个功能哦!\n我才不告诉你可以去qun.qq.com里找回群主权限呢!" + ).send(at_sender=True) + return + if uid != sid and not await check_manage(bot, ev): + await UniMessage.text("只有管理员才可以对别人的头衔进行操作哦~").send(at_sender=True) + return + try: + await bot.set_group_special_title( + group_id=gid, user_id=sid, special_title=title, duration=-1 + ) + if not title: + await UniMessage.at(user_id=str(sid)).text("喜提没有头衔的头衔~").send() + else: + await ( + UniMessage.text("已为") + .at(user_id=str(sid)) + .text(f"发放专属头衔“{title}”~") + .send() + ) + except Exception as e: + await UniMessage.text(f"诶...头衔呢?\n错误代码:{e}").send(at_sender=True) + + +async def card_edit( + bot: Bot, ev: GroupMessageEvent, uid: int, sid: int, gid: int, card_text: str +): + """群名片修改""" + self_info = await self_member_info(bot, gid) + if not is_bot_manage(self_info): + await UniMessage.text("\n我日,不给我管理改锤子名片").send(at_sender=True) + return + if uid != sid and not await check_manage(bot, ev): + await UniMessage.text("只有狗管理才能给别人设置名片了啦!").send(at_sender=True) + return + try: + await bot.set_group_card(group_id=gid, user_id=sid, card=card_text) + await ( + UniMessage.text("已经把") + .at(user_id=str(sid)) + .text(f"的群名片修改为“{card_text}”啦~") + .send() + ) + except Exception as e: + await UniMessage.text(f"修改群名片失败勒...\n错误代码:{e}").send(at_sender=True) + + +async def group_name(bot: Bot, ev: GroupMessageEvent, gid: int, name_text: str): + """群名修改""" + self_info = await self_member_info(bot, gid) + if not is_bot_manage(self_info): + await UniMessage.text("\n我还没获得管理权限呢...").send(at_sender=True) + return + if not await check_manage(bot, ev): + await UniMessage.text("只有狗管理才能修改群名哦!").send(at_sender=True) + return + try: + await bot.set_group_name(group_id=gid, name=name_text) + await UniMessage.text(f"群名已修改为“{name_text}”啦").send() + except Exception as e: + await UniMessage.text(f"群名修改失败惹...\n错误代码:{e}").send(at_sender=True) diff --git a/hexi/plugins/nonebot_plugin_group_tools/services/video.py b/hexi/plugins/nonebot_plugin_group_tools/services/video.py new file mode 100644 index 0000000..916c451 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/services/video.py @@ -0,0 +1,22 @@ +import subprocess +from pathlib import Path + +from nonebot_plugin_alconna import UniMessage + + +def local_video(path: str) -> UniMessage: + """构造本地视频消息(覆盖 Media.__post_init__ 的 https 前缀规范化)""" + msg = UniMessage.video(url=path) + msg[0].url = path + return msg + + +def get_video_info(url: str) -> str: + res = subprocess.run(["you-get", "-i", url], capture_output=True, text=True) + return res.stdout + + +def download_video(url: str, filepath: Path, filename: str) -> None: + subprocess.run( + ["you-get", "-o", str(filepath), "-O", filename, url], capture_output=True + ) diff --git a/hexi/plugins/nonebot_plugin_group_tools/utils/__init__.py b/hexi/plugins/nonebot_plugin_group_tools/utils/__init__.py new file mode 100644 index 0000000..e9d48da --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/utils/__init__.py @@ -0,0 +1 @@ +"""群管理工具插件的通用工具子包。""" diff --git a/hexi/plugins/nonebot_plugin_group_tools/utils/media.py b/hexi/plugins/nonebot_plugin_group_tools/utils/media.py new file mode 100644 index 0000000..3a7dd99 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/utils/media.py @@ -0,0 +1,27 @@ +import base64 +import random +from pathlib import Path + + +def image_to_base64(file_path: Path) -> str | None: + """图片转 base64,文件不存在时返回 None""" + if not file_path.is_file(): + return None + with open(file_path, "rb") as f: + return "base64://" + base64.b64encode(f.read()).decode() + + +def audio_to_base64(file_path: Path) -> str: + """音频转 base64""" + with open(file_path, "rb") as f: + return "base64://" + base64.b64encode(f.read()).decode() + + +def random_audio(dir_path: Path) -> str | None: + """随机取目录下的一个语音文件并转 base64,目录不存在或为空时返回 None""" + if not dir_path.is_dir(): + return None + files = [p for p in dir_path.iterdir() if p.is_file()] + if not files: + return None + return audio_to_base64(random.choice(files)) diff --git a/hexi/plugins/nonebot_plugin_group_tools/utils/message.py b/hexi/plugins/nonebot_plugin_group_tools/utils/message.py new file mode 100644 index 0000000..87b7544 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/utils/message.py @@ -0,0 +1,13 @@ +from nonebot.adapters.onebot.v11 import GroupMessageEvent + + +def get_at_id(ev: GroupMessageEvent) -> int | None: + """提取消息中第一个被 at 的用户(排除 at all)""" + for m in ev.message: + if m.type == "at" and m.data.get("qq") != "all": + return int(m.data["qq"]) + return None + + +def has_at_all(ev: GroupMessageEvent) -> bool: + return any(m.type == "at" and m.data.get("qq") == "all" for m in ev.message) diff --git a/hexi/plugins/nonebot_plugin_group_tools/utils/permissions.py b/hexi/plugins/nonebot_plugin_group_tools/utils/permissions.py new file mode 100644 index 0000000..bff70c9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/utils/permissions.py @@ -0,0 +1,49 @@ +from nonebot import logger +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent + +from nonebot_plugin_alconna import UniMessage + +from hexi.plugins.nonebot_plugin_hexi_core.custom_utils import ( + check_bot_admin, + check_manage, +) + + +async def group_member_info(bot: Bot, gid: int, uid: int): + """获取指定群成员信息,失败返回 None""" + try: + return await bot.get_group_member_info(group_id=gid, user_id=uid, no_cache=True) + except Exception as e: + logger.exception(e) + return None + + +async def self_member_info(bot: Bot, gid: int): + """获取 bot 自身的群成员信息""" + return await group_member_info(bot, gid, bot.self_id) + + +async def honor_info(bot: Bot, gid: int, honor_type: str): + """获取群荣誉信息,失败返回 None""" + try: + return await bot.get_group_honor_info(group_id=gid, type=honor_type) + except Exception as e: + logger.exception(e) + return None + + +def is_bot_manage(self_info) -> bool: + """bot 是否为该群的管理/群主""" + return bool(self_info) and self_info["role"] in ("owner", "admin") + + +async def check_perm(bot: Bot, ev: GroupMessageEvent, silent: bool = False) -> bool: + """检查 bot 为群管理 且 用户为管理以上权限;不通过时按需回复""" + if not await check_bot_admin(bot, ev.group_id): + await UniMessage.text("咱又不是管理,你找错人了").send() + return False + if not await check_manage(bot, ev): + if not silent: + await UniMessage.text("才不听你的呢").send() + return False + return True diff --git a/hexi/plugins/nonebot_plugin_group_tools/utils/text.py b/hexi/plugins/nonebot_plugin_group_tools/utils/text.py new file mode 100644 index 0000000..092e353 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_group_tools/utils/text.py @@ -0,0 +1,37 @@ +import unicodedata + + +def parse_seconds(s: str) -> int | None: + """解析 '30' 或 '3*60' 形式的时长秒数,非法输入返回 None""" + s = s.strip() + if not s or not all(c.isdigit() or c == "*" for c in s): + return None + try: + result = 1 + for part in s.split("*"): + result *= int(part) + return result + except ValueError: + return None + + +def strip_prefix(text: str, prefixes) -> str: + """依次移除前缀后去空白""" + for p in prefixes: + text = text.removeprefix(p) + return text.strip() + + +def is_number(s) -> bool: + """判断字符串是否可视为数字""" + try: + float(s) + return True + except ValueError: + pass + try: + unicodedata.numeric(s) + return True + except (TypeError, ValueError): + pass + return False diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/README.md b/hexi/plugins/nonebot_plugin_helldivers_tools/README.md new file mode 100644 index 0000000..7ad2eb9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/README.md @@ -0,0 +1,145 @@ +# nonebot_plugin_helldivers_tools + +绝地潜兵小助手。命令: + +- `简报`:获取星系战争概况(现在走 **[helldivers-2/api](https://github.com/helldivers-2/api)** 社区接口,用 Playwright 渲染自建 HTML 卡片,**不再打开外部网页截图**)。 +- `随机战备`:随机一套战备(自建 HTML 卡片,与 `简报` 一样用 `nonebot_plugin_htmlrender` 出图)。 + +## 为什么改成 API? + +旧方案用 Playwright 打开 `hd2galaxy.com` 截全页图,要等 `networkidle`(本地化 30s 左右),还要在页面 DOM 里做星球名替换,慢且脆弱。 + +新方案: + +1. 调 `helldivers-2/api` 的 `/api/v1/war`、`/assignments`、`/campaigns`、`/planets`(带缓存,避免触发限流); +2. 用**自己的 HTML 模板**(内联 CSS + base64 logo + 系统字体)渲染一张战况卡片; +3. 交给 **[nonebot_plugin_htmlrender](https://github.com/nonebotjs/nonebot-plugin-htmlrender)** 的 `get_new_page()` 出图。因为模板是本地内容、无外部资源,`set_content` 后秒级完成,不再卡 30s。 + +> 说明:由 `nonebot_plugin_htmlrender` 管理 Playwright 内核(机器人日志里 `HTMLRender Started.` 即已加载)。`简报` 与 `随机战备` 都依赖 `require("nonebot_plugin_htmlrender")`,与 `nonebot_plugin_picstatus` 的做法一致。 + +## 新增/改动文件 + +| 文件 | 作用 | +| --- | --- | +| `config.py` | NoneBot 插件配置 | +| `hd2_api.py` | 异步 API 客户端(httpx + 进程内缓存 + 并发聚合) | +| `war_renderer.py` | 战况 HTML 模板 + 用 `nonebot_plugin_htmlrender` 渲染为 PNG | +| `equipment_renderer.py` | `随机战备` HTML 模板 + 用 `nonebot_plugin_htmlrender` 渲染为 PNG | +| `__init__.py` | `简报` 与 `随机战备` 命令改为走 API / 本地 + 渲染(移除了 `screen_shot` 依赖) | + +## 配置 + +NoneBot 配置(`.env` / `.env.dev`)读取以下环境变量,均为可选,用默认值即可开箱即用: + +| 环境变量 | 默认值 | 说明 | +| --- | --- | --- | +| `hd2_api_base_url` | `https://api.helldivers2.dev` | 自托管 helldivers-2/api 的根地址;不填用公共社区 API | +| `hd2_api_language` | `zh-Hans` | 请求本地化语言(自托管默认支持 zh-Hans / zh-Hant) | +| `hd2_cache_ttl` | `60` | 缓存秒数,避免频繁打接口触发限流(5次/10秒) | +| `hd2_super_client` | `hexi-bot.local` | 请求头,社区 API 必备 | +| `hd2_super_contact` | `https://github.com/sansenhoshi/nonebot_plugin_helldivers_tools` | 请求头,社区 API 必备 | + +> **⚠️ 两个 `X-Super-*` 头必须都存在**:`RateLimitMiddleware` 在 `ValidateClients=true` 时(公共实例默认开启)要求请求**同时**带 `X-Super-Client` 和 `X-Super-Contact`,缺一即返回 `400 Bad Request / "The X-Super-Client and X-Super-Contact headers are required"`。客户端已保证始终发这两个头,`hd2_super_contact` 留空也会用 `hd2_super_client` 兜底。 + +示例: + +```ini +hd2_api_base_url=http://127.0.0.1:8080 +hd2_api_language=zh-Hans +hd2_cache_ttl=60 +``` + +## 自托管 helldivers-2/api + +项目是 .NET 10 + Docker。用 Docker Compose 最省事。 + +### 1) 克隆(务必带子模块) +```bash +git clone --recurse-submodules https://github.com/helldivers-2/api.git +cd api +``` +> `src/Helldivers-2-Models/json` 是子模块,里面是星球名/本地化数据,**不带上它接口会没数据**。 + +### 2) 放一个 `docker-compose.yml`(在 `api` 根目录) + +> 本仓库已写好一份:`HeXi/deploy/helldivers-api/docker-compose.yml`,复制到 `api` 仓库根目录即可。要点:`ASPNETCORE_URLS=http://+:8080`(否则默认监听 5000)、`Helldivers__API__Authentication__Enabled=false`(必须)、`ValidateClients=false`、含健康检查/重启/日志轮转。 + +```yaml +services: + helldivers-api: + build: + context: . + dockerfile: src/Helldivers-2-API/Dockerfile + image: helldivers2-api + container_name: helldivers2-api + ports: + - "8080:8080" + environment: + # 自托管务必关鉴权:默认 Authentication.Enabled=true 但没 SigningKey,直接启动会抛 ArgumentNullException(issue #90) + - Helldivers__API__Authentication__Enabled=false + # 抬高本地限流,多核打也不怕 + - Helldivers__API__RateLimit=300 + - Helldivers__API__RateLimitWindow=10 + # 与 ArrowHead 官方接口同步频率(秒) + - Helldivers__Synchronization__IntervalSeconds=60 + restart: unless-stopped +``` + +### 3) 构建并启动 +```bash +docker compose up -d --build +``` + +### 4) 验证 +```bash +# 应该返回 JSON(当前战争信息) +curl http://127.0.0.1:8080/api/v1/war +curl http://127.0.0.1:8080/api/v1/assignments +``` + +### 5) 让机器人指向它 +在机器人 `.env` / `.env.dev` 里(本项目在 `HeXi/.env`)写: + +```ini +hd2_api_base_url=http://127.0.0.1:8080 +hd2_api_language=zh-Hans +``` + +然后重启机器人,发 `简报` 即可。默认配置的 `Languages` 已含 `zh-Hans`,星球名/大指令就是中文。 + +### 常见问题 +- **`docker compose up` 报 `ArgumentNullException (Parameter 's')`**:忘关鉴权了,确认有 `Helldivers__API__Authentication__Enabled=false`。 +- **`/api/v1/war` 一直是 200 但 `planet.name` 为空**:子模块没拉全,重新 `git submodule update --init --recursive` 后重建。 +- **返回 400 / "X-Super-Client and X-Super-Contact headers are required"**:这是实例开了 `ValidateClients`;我方客户端已永远带这两个头,正常不会触发。 +- **容器能起但数组为空**:容器要联网访问 ArrowHead 官方接口才能同步,检查机器能否访问外网。 +- **想用 Fly.io**:仓库自带 `fly.toml`,直接 `fly deploy`。 + +### 备选部署(不用 Docker) +数据(星球名/本地化)由 `Helldivers-2-SourceGen` 在**编译期**写进二进制,运行时**不读任何 json 文件**,所以直接跑发布产物完全可行。 + +**Windows 本机跑(只需 .NET 10 SDK 构建一次):** +```powershell +git clone --recurse-submodules https://github.com/helldivers-2/api.git && cd api +dotnet publish src/Helldivers-2-API/Helldivers-2-API.csproj ` + -c Release -r win-x64 --self-contained true -p:PublishAot=false -o .\publish +$env:ASPNETCORE_URLS="http://127.0.0.1:8080" +$env:Helldivers__API__Authentication__Enabled="false" +$env:Helldivers__API__RateLimit="300" +.\publish\Helldivers-2-API.exe +``` +> `-p:PublishAot=false`:项目默认 AOT,Windows 上要 VC++ 工具链,关掉避免踩坑。 + +**VPS + systemd**:把发布产物换成 `linux-x64` 上传,用 systemd 挂服务(`Environment=Helldivers__API__Authentication__Enabled=false`)。 + +**Fly.io / 其它 PaaS**:仓库自带 `fly.toml`,`fly deploy` 即可;Render/Railway/Azure 同理。 + +## 接口字段依赖 + +- `war.statistics`:`playerCount`、`missionSuccessRate`、`terminidKills`、`automatonKills`、`illuminateKills`、`deaths` +- `assignments[0]`:`title`、`description`、`briefing`、`reward/rewards`、`expiration` +- `campaigns[]` → `planet`:`name`、`currentOwner`、`health`、`maxHealth`、`statistics.playerCount` +- `planets[]` → `currentOwner`(星系控制统计用) + +## 翻译兜底 + +接口带 `Accept-Language: zh-Hans` 时,`LocalizedMessage` 字段会返回中文。若某字段仍为英文,渲染层会用 `data/plantes_mix.json` 做兜底翻译。 diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/__init__.py b/hexi/plugins/nonebot_plugin_helldivers_tools/__init__.py new file mode 100644 index 0000000..bb10bc9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/__init__.py @@ -0,0 +1,204 @@ +import httpx +from nonebot import logger +from nonebot.internal.params import ArgPlainText +from nonebot.typing import T_State +from nonebot import on_command +from nonebot.adapters.onebot.v11 import MessageEvent, Bot, MessageSegment +from nonebot.plugin import PluginMetadata +from typing import Optional, Union + +from .equipment import get_random_equipment, get_equipment_by_combination +from .hd2_api import get_briefing_data +from .war_renderer import render_war_briefing +from .utils import * +from .equipment_store import init_db as _init_equipment_db +from . import stratagem_admin as _stratagem_admin +from hexi.web_plugin_registry import register_web_plugin +from nonebot.matcher import Matcher + +__plugin_meta__ = PluginMetadata( + name="绝地潜兵小助手", + description="绝地潜兵小助手,提供一些小功能,让超级地球更加美好!", + usage="简报:获取星系战争简要概况(每个阵营取人数前 4 张卡片)\n" + "详报:全量绘制当前进行的战役\n" + "随机战备:让机器人帮你随机一套战备\n" + "战备管理后台:/hub/ 统一管理台内可视化编辑", + type="application", + homepage="https://github.com/sansenhoshi/nonebot_plugin_helldivers_tools" +) + +basic_path = os.path.dirname(__file__) +save_path = os.path.join(basic_path, "temp") +img_path = os.path.join(basic_path, "img") +data_path = os.path.join(basic_path, "data") + + +# 注册到统一 Web:hub 启动时会自动挂载 /api/helldivers,无需手动配置 +_init_equipment_db() +register_web_plugin( + "helldivers", + "战备管理", + "rocket", + lambda: _stratagem_admin.build_admin_app(), + module_name=__name__, +) +logger.info("战备管理 Web 插件已注册(/api/helldivers)") + +# 统一配置标准:把 API 相关配置暴露给 Web 管理台(/hub 插件配置) +from hexi.config_standard import register_model_config # noqa: E402 +from .config import config as _hd2_config # noqa: E402 + +register_model_config( + __name__, + _hd2_config, + fields=[ + "hd2_api_base_url", + "hd2_api_language", + "hd2_cache_ttl", + "hd2_super_client", + "hd2_super_contact", + ], + labels={ + "hd2_api_base_url": "API 根地址", + "hd2_api_language": "本地化语言", + "hd2_cache_ttl": "数据缓存秒数", + "hd2_super_client": "请求头 Client", + "hd2_super_contact": "请求头 Contact", + }, + descriptions={ + "hd2_api_base_url": "自托管 helldivers-2/api 根地址;不填则用公共社区 API", + "hd2_api_language": "请求本地化语言,自托管实例支持 zh-Hans/zh-Hant", + "hd2_cache_ttl": "战况快照约几分钟更新一次,靠这个避免频繁打接口触发限流", + "hd2_super_client": "公共/自托管都要求 X-Super-Client 头", + "hd2_super_contact": "公共/自托管都要求 X-Super-Contact 头", + }, +) + + +async def _send_war_card(matcher: Matcher, ev: MessageEvent, top_per_race: Optional[int]) -> None: + await matcher.send("正在获取前线战况,请民主的等待!") + try: + data = await get_briefing_data() + png = await render_war_briefing(data, top_per_race) + except Exception as e: + logger.exception("获取战况失败") + await matcher.finish( + MessageSegment.reply(ev.message_id) + + f"战况获取失败:{type(e).__name__}:{e}" + ) + return + mes = (MessageSegment.reply(ev.message_id), gen_ms_img(png)) + await matcher.send(mes) + + +war_situation = on_command("简报", aliases={"简报"}) +war_detail = on_command("详报", aliases={"详报"}) + + +@war_situation.handle() +async def get_war_info(ev: MessageEvent): + await _send_war_card(war_situation, ev, top_per_race=4) + + +@war_detail.handle() +async def get_war_detail(ev: MessageEvent): + await _send_war_card(war_detail, ev, top_per_race=None) + + +async def download_url(url: str) -> bytes | None: + async with httpx.AsyncClient() as client: + for i in range(3): + try: + resp = await client.get(url) + if resp.status_code != 200: + continue + return resp.content + except Exception as e: + print(f"Error downloading {url}, retry {i}/3: {str(e)}") + return None + + +random_helldivers = on_command("随机战备", aliases={"随机战备"}, block=True) + +# PROMPT = """ ***超级地球武装部*** +# 请发送你需要的随机规则 +# +# 1:纯随机(不推荐) +# +# 套路随机(按一定规则随机) +# +# 2:2红/1蓝/1绿 +# 3:2绿/1红/1蓝 +# 4:2蓝/1绿/1红 +# +# 5:3红/1蓝 +# 6:3绿/1蓝 +# +# 7:2红/2蓝 +# 8:2蓝/2绿 +# 9:2绿/2红 +# +# 10:4红 +# 11:4绿""" + +board_path = f"{img_path}/board2.png" + +PROMPT = MessageSegment.image(pic2b64(Image.open(board_path))) + +error_count = 0 + + +# 用户选择 +@random_helldivers.got("pick_type", prompt=PROMPT) +async def got_random_helldivers(event: MessageEvent, pick_type: str = ArgPlainText()): + global error_count + if error_count >= 2: + await random_helldivers.finish("已回归平民生活——") + logger.info("持续输错退出随机战备") + error_count = 0 + return + logger.info(f"用户选择的战备类型: {pick_type}") + if not is_number(pick_type): + error_count += 1 + await random_helldivers.reject(f"您输入的 {pick_type} 非数字,请重新输入1到11,或者输入0退出") + elif int(pick_type) not in range(12): + error_count += 1 + await random_helldivers.reject(f"您输入的 {pick_type} 不在范围内,请重新输入1到11,或者输入0退出") + elif int(pick_type) == 0: + await random_helldivers.finish("已回归平民生活——") + logger.info("用户选择退出随机战备") + error_count = 0 + return + + mix_msg = (MessageSegment.reply(event.message_id),) + + type_combinations = { + 2: {'red': 2, 'blue': 1, 'green': 1}, + 3: {'green': 2, 'red': 1, 'blue': 1}, + 4: {'blue': 2, 'green': 1, 'red': 1}, + 5: {'red': 3, 'blue': 1}, + 6: {'green': 3, 'blue': 1}, + 7: {'red': 2, 'blue': 2}, + 8: {'blue': 2, 'green': 2}, + 9: {'green': 2, 'red': 2}, + 10: {'red': 4}, + 11: {'green': 4} + } + + if int(pick_type) == 1: + logger.info("用户选择纯随机战备") + result = await get_random_equipment(4) # 4 random equipments + else: + combination = type_combinations.get(int(pick_type)) + logger.info(f"用户选择的战备组合: {combination}") + result = await get_equipment_by_combination(combination) + + final_msg = MessageSegment.text("您的随机结果是:\n") + image_tuple = gen_ms_img(result) + mix_msg += (final_msg, image_tuple) + + await random_helldivers.finish(mix_msg) + + +def is_number(s): + return bool(re.match(r'^[0-9]+$', s)) \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/brief_preview.html b/hexi/plugins/nonebot_plugin_helldivers_tools/brief_preview.html new file mode 100644 index 0000000..665a970 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/brief_preview.html @@ -0,0 +1,487 @@ + + + + + + + + +
    + +
    + +
    超级地球战况简报
    +
    Galactic War Briefing · 2026-08-28 19:01
    +
    + +
    + +
    +
    + 重要指令 + 剩余:73小时1分 +
    +
    解放指定的敌方星球,这些星球极有可能藏匿着破坏TCS+的异见分子。
    +
    指令目标
    十字架一—
    轧尔哈伦
    90%
    富源—
    +
    奖励:50奖章
    +
    + + +
    +
    星系战况
    +
    56.9K
    参战潜兵
    91%
    任务完成率
    35
    当前战役数
    216.6B
    终结族总击杀
    115.0B
    机器人总击杀
    75.8B
    光能族总击杀
    8.7B
    潜兵总阵亡
    1.0B
    任务完成总数
    +
    + +
    + +
    +
    进行中的战役
    + +
    +
    终结族 · 10玩家 4.9万
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    轧尔哈伦
    +
    终结族 · 解放
    +
    +
    +
    90%
    +
    解放进度
    +
    +
    +
    民主空间站
    行动支持 · 外骨骼装甲储备
    轨道封锁
    +
    + +
    所属星系锦栖分区
    部署潜兵3.5万
    地形特征幽祟沼泽
    环境事件无
    + +
    +
    +
    +
    +
    + + 保卫战 + +
    +
    + +
    +
    +
    水委一次星
    +
    超级地球 · 防守
    +
    +
    +
    72%
    +
    入侵进度
    +
    +
    + +
    +
    剩余时间:1小时3分
    +
    所属星系博格斯分区
    部署潜兵5,416
    地形特征平原
    环境事件无
    +
    星球效果 工厂枢纽 终结族遏制体系+ 掠食变种 超级地球武装部队驻守
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    丈人一湾
    +
    终结族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系锦栖分区
    部署潜兵3,126
    地形特征沙漠沙丘
    环境事件沙暴
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    盖尔崔亚
    +
    终结族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系锦栖分区
    部署潜兵2,414
    地形特征离子绯红之地
    环境事件离子风暴
    + +
    +
    +
    +
    +
    机器人 · 9玩家 4,537
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    玛塔
    +
    机器人 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系仙女座分区
    部署潜兵1,420
    地形特征平原
    环境事件无
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    极光湾
    +
    机器人 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系瓦尔迪斯分区
    部署潜兵661
    地形特征苔原
    环境事件无
    +
    星球效果 喷气旅孵化厂
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    玛尔特
    +
    机器人 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系仙女座分区
    部署潜兵603
    地形特征苔原
    环境事件无
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    丘伊
    +
    机器人 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系拉凯欧分区
    部署潜兵564
    地形特征沙漠沙丘
    环境事件沙暴
    + +
    +
    +
    +
    +
    光能族 · 16玩家 1,905
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    可利亚
    +
    光能族 · 解放
    +
    +
    +
    9%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系欧米茄分区
    部署潜兵564
    地形特征焦土荒原
    环境事件烈焰龙卷
    +
    星球效果 窃票者
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    右执法
    +
    光能族 · 解放
    +
    +
    +
    3%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系阿基拉分区
    部署潜兵254
    地形特征死寂之地
    环境事件无
    +
    星球效果 窃票者
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    格拉夫米尔
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系瑞克图斯分区
    部署潜兵207
    地形特征骸骨之地
    环境事件无
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    新戈23
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系欧米茄分区
    部署潜兵174
    地形特征岩质峡谷
    环境事件地震
    +
    星球效果 入侵舰队 占领者
    +
    +
    +
    +
    + + +
    +
    星系控制
    +
    超级地球 209 终结族 25 机器人 14 光能族 25
    +
    + +
    数据来源:helldivers-2/api 社区接口 · 仅供娱乐
    +
    + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/brief_preview_dss_sim.html b/hexi/plugins/nonebot_plugin_helldivers_tools/brief_preview_dss_sim.html new file mode 100644 index 0000000..b57fcf9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/brief_preview_dss_sim.html @@ -0,0 +1,152 @@ + + + + +
    +
    +
    进行中的战役
    + +
    +
    终结族 · 1玩家 3.3万
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    轧尔哈伦
    +
    终结族 · 解放
    +
    +
    +
    87%
    +
    解放进度
    +
    +
    +
    民主空间站
    行动支持 · 外骨骼装甲储备
    飞鹰风暴轰炸解放推进
    +
    + +
    所属星系锦栖分区
    部署潜兵3.3万
    地形特征幽祟沼泽
    环境事件无
    + +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/brief_preview_full.html b/hexi/plugins/nonebot_plugin_helldivers_tools/brief_preview_full.html new file mode 100644 index 0000000..5f4550f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/brief_preview_full.html @@ -0,0 +1,1085 @@ + + + + + + + + +
    + +
    + +
    超级地球战况简报
    +
    Galactic War Briefing · 2026-08-28 19:01
    +
    + +
    + +
    +
    + 重要指令 + 剩余:73小时1分 +
    +
    解放指定的敌方星球,这些星球极有可能藏匿着破坏TCS+的异见分子。
    +
    指令目标
    十字架一—
    轧尔哈伦
    90%
    富源—
    +
    奖励:50奖章
    +
    + + +
    +
    星系战况
    +
    56.9K
    参战潜兵
    91%
    任务完成率
    35
    当前战役数
    216.6B
    终结族总击杀
    115.0B
    机器人总击杀
    75.8B
    光能族总击杀
    8.7B
    潜兵总阵亡
    1.0B
    任务完成总数
    +
    + +
    + +
    +
    进行中的战役
    + +
    +
    终结族 · 10玩家 4.9万
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    轧尔哈伦
    +
    终结族 · 解放
    +
    +
    +
    90%
    +
    解放进度
    +
    +
    +
    民主空间站
    行动支持 · 外骨骼装甲储备
    轨道封锁
    +
    + +
    所属星系锦栖分区
    部署潜兵3.5万
    地形特征幽祟沼泽
    环境事件无
    + +
    +
    +
    +
    +
    + + 保卫战 + +
    +
    + +
    +
    +
    水委一次星
    +
    超级地球 · 防守
    +
    +
    +
    72%
    +
    入侵进度
    +
    +
    + +
    +
    剩余时间:1小时3分
    +
    所属星系博格斯分区
    部署潜兵5,416
    地形特征平原
    环境事件无
    +
    星球效果 工厂枢纽 终结族遏制体系+ 掠食变种 超级地球武装部队驻守
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    丈人一湾
    +
    终结族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系锦栖分区
    部署潜兵3,126
    地形特征沙漠沙丘
    环境事件沙暴
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    盖尔崔亚
    +
    终结族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系锦栖分区
    部署潜兵2,414
    地形特征离子绯红之地
    环境事件离子风暴
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    璨光
    +
    终结族 · 解放
    +
    +
    +
    13%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系猎户座分区
    部署潜兵1,751
    地形特征落叶林
    环境事件无
    +
    星球效果 终结族遏制体系+ 孢裂变种 超级地球武装部队驻守
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    奥密克戎
    +
    终结族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系莱斯特拉德分区
    部署潜兵642
    地形特征虫窝世界
    环境事件无
    +
    星球效果 重度阴霾笼罩 虫窝世界 霸王虫 蟑龙
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    帕狄恩XXIV
    +
    终结族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系锦栖分区
    部署潜兵261
    地形特征死寂之地
    环境事件无
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    博尔岩
    +
    终结族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系法尔斯塔夫分区
    部署潜兵163
    地形特征沼泽
    环境事件无
    +
    星球效果 阴霾
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    尼维尔43
    +
    终结族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系米琳分区
    部署潜兵145
    地形特征死寂之地
    环境事件无
    +
    星球效果 阴霾
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    帕尔晨
    +
    终结族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系斯坦分区
    部署潜兵132
    地形特征焦土荒原
    环境事件烈焰龙卷
    + +
    +
    +
    +
    +
    机器人 · 9玩家 4,537
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    玛塔
    +
    机器人 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系仙女座分区
    部署潜兵1,420
    地形特征平原
    环境事件无
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    极光湾
    +
    机器人 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系瓦尔迪斯分区
    部署潜兵661
    地形特征苔原
    环境事件无
    +
    星球效果 喷气旅孵化厂
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    玛尔特
    +
    机器人 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系仙女座分区
    部署潜兵603
    地形特征苔原
    环境事件无
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    丘伊
    +
    机器人 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系拉凯欧分区
    部署潜兵564
    地形特征沙漠沙丘
    环境事件沙暴
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    敏托瑞亚
    +
    机器人 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系盖勒特分区
    部署潜兵455
    地形特征平原
    环境事件无
    +
    星球效果 超镁铁矿井 生化人
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    卡戎主星
    +
    机器人 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系仙女座分区
    部署潜兵329
    地形特征离子绯红之地
    环境事件离子风暴
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    玄戈增二IV
    +
    机器人 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系瓦尔迪斯分区
    部署潜兵277
    地形特征幽祟沼泽
    环境事件无
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    查巴尔VII
    +
    机器人 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系仙女座分区
    部署潜兵160
    地形特征酸性恶地
    环境事件酸雨风暴
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    布里斯提卡
    +
    机器人 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系盖勒特分区
    部署潜兵68
    地形特征焦土荒原
    环境事件烈焰龙卷
    + +
    +
    +
    +
    +
    光能族 · 16玩家 1,905
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    可利亚
    +
    光能族 · 解放
    +
    +
    +
    9%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系欧米茄分区
    部署潜兵564
    地形特征焦土荒原
    环境事件烈焰龙卷
    +
    星球效果 窃票者
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    右执法
    +
    光能族 · 解放
    +
    +
    +
    3%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系阿基拉分区
    部署潜兵254
    地形特征死寂之地
    环境事件无
    +
    星球效果 窃票者
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    格拉夫米尔
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系瑞克图斯分区
    部署潜兵207
    地形特征骸骨之地
    环境事件无
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    新戈23
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系欧米茄分区
    部署潜兵174
    地形特征岩质峡谷
    环境事件地震
    +
    星球效果 入侵舰队 占领者
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    席姆纳特
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系金牛座分区
    部署潜兵173
    地形特征离子丛林
    环境事件离子风暴
    +
    星球效果 无脑群氓
    +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    创世主星
    +
    光能族 · 解放
    +
    +
    +
    1%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系瑞克图斯分区
    部署潜兵95
    地形特征离子丛林
    环境事件离子风暴
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    RD4
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系参宿七分区
    部署潜兵77
    地形特征月球
    环境事件流星风暴
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    瓦尔莫克斯
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系瑞克图斯分区
    部署潜兵70
    地形特征离子绯红之地
    环境事件离子风暴
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    新斯德哥尔摩
    +
    光能族 · 解放
    +
    +
    +
    2%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系半藏分区
    部署潜兵60
    地形特征冰封冰川
    环境事件暴风雪
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    阿斯佩洛斯主星
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系阿基拉分区
    部署潜兵53
    地形特征沼泽
    环境事件无
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    海索主星
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系参宿七分区
    部署潜兵44
    地形特征冰封冰川
    环境事件暴风雪
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    角宿二湾
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系半藏分区
    部署潜兵35
    地形特征沙漠沙丘
    环境事件沙暴
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    罗格5
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系参宿七分区
    部署潜兵30
    地形特征火山丛林
    环境事件火山活动
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    海德斯
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系费里斯分区
    部署潜兵28
    地形特征沼泽
    环境事件无
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    赫尔松次星
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系费里斯分区
    部署潜兵23
    地形特征焦土荒原
    环境事件烈焰龙卷
    + +
    +
    +
    +
    +
    + + 解放战 + +
    +
    + +
    +
    +
    泽亚鲁戈西亚
    +
    光能族 · 解放
    +
    +
    +
    0%
    +
    解放进度
    +
    +
    + +
    + +
    所属星系费里斯分区
    部署潜兵18
    地形特征沙漠悬壁
    环境事件地震
    + +
    +
    +
    +
    + + +
    +
    星系控制
    +
    超级地球 209 终结族 25 机器人 14 光能族 25
    +
    + +
    数据来源:helldivers-2/api 社区接口 · 仅供娱乐
    +
    + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/brief_preview_single.html b/hexi/plugins/nonebot_plugin_helldivers_tools/brief_preview_single.html new file mode 100644 index 0000000..f38f67e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/brief_preview_single.html @@ -0,0 +1,178 @@ + + + + + + + +
    +
    + +
    +
    进行中的战役
    + +
    +
    终结族 · 1玩家 5,399
    +
    +
    +
    +
    + + 保卫战 + +
    +
    + +
    +
    +
    水委一次星
    +
    超级地球 · 防守
    +
    +
    +
    100%
    +
    防御进度
    +
    +
    + +
    +
    剩余时间:3小时42分
    +
    所属星系博格斯分区
    部署潜兵5,399
    地形特征平原
    环境事件无
    + +
    +
    + 主要战役:保卫战 + 3小时42分 +
    +
    + 终结族正在进攻,超级地球军民正在保卫该星球 + 73% +
    +
    +
    +
    星球效果 工厂枢纽 终结族遏制体系+ 掠食变种 超级地球武装部队驻守
    +
    +
    +
    +
    + +
    +
    + + \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/config.py b/hexi/plugins/nonebot_plugin_helldivers_tools/config.py new file mode 100644 index 0000000..58740b7 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/config.py @@ -0,0 +1,17 @@ +from nonebot import get_plugin_config +from pydantic import BaseModel + + +class Config(BaseModel): + # 自托管 helldivers-2/api 的根地址;不填则使用公共社区 API + hd2_api_base_url: str = "https://api.helldivers2.dev" + # 请求的本地化语言。自托管实例默认配置支持 zh-Hans(简体)/ zh-Hant(繁体) + hd2_api_language: str = "zh-Hans" + # 数据缓存秒数。战况快照约几分钟更新一次,靠这个避免频繁打接口触发限流(5次/10秒) + hd2_cache_ttl: int = 60 + # 请求头标识。公共/自托管都要求 X-Super-Client 和 X-Super-Contact 两个头同时存在(缺失返回 400) + hd2_super_client: str = "hexi-bot.local" + hd2_super_contact: str = "https://github.com/sansenhoshi/nonebot_plugin_helldivers_tools" + + +config = get_plugin_config(Config) \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/archive/equipment.json b/hexi/plugins/nonebot_plugin_helldivers_tools/data/archive/equipment.json new file mode 100644 index 0000000..4d0d989 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/data/archive/equipment.json @@ -0,0 +1,800 @@ +[ + { + "name": "AC-8 机炮", + "path": "img/helldivers/AC-8 机炮.png", + "type": "blue", + "alias": [ + "机炮" + ], + "backpack": 1 + }, + { + "name": "APW-1 反器材步枪", + "path": "img/helldivers/APW-1 反器材步枪.png", + "type": "blue", + "alias": [ + "反器材" + ], + "backpack": 0 + }, + { + "name": "ARC-3 电弧发射器", + "path": "img/helldivers/ARC-3 电弧发射器.png", + "type": "blue", + "alias": [ + "电弧发射器" + ], + "backpack": 0 + }, + { + "name": "AX-LAS-5 漫游车", + "path": "img/helldivers/AX-LAS-5 漫游车.png", + "type": "blue", + "alias": [ + "激光狗" + ], + "backpack": 1 + }, + { + "name": "AX·AR-23 护卫犬", + "path": "img/helldivers/AX·AR-23 护卫犬.png", + "type": "blue", + "alias": [ + "实弹狗", + "机枪狗" + ], + "backpack": 1 + }, + { + "name": "AX·ARC-3 K-9", + "path": "img/helldivers/AX·ARC-3 K-9.png", + "type": "blue", + "alias": [ + "电狗" + ], + "backpack": 1 + }, + { + "name": "AX·FLAM-75 热狗", + "path": "img/helldivers/AX·FLAM-75 热狗.png", + "type": "blue", + "alias": [ + "火狗" + ], + "backpack": 1 + }, + { + "name": "AX·TX-13 腐息", + "path": "img/helldivers/AX·TX-13 腐息.png", + "type": "blue", + "alias": [ + "毒狗" + ], + "backpack": 1 + }, + { + "name": "A·AC-8 自动哨戒炮", + "path": "img/helldivers/A·AC-8 自动哨戒炮.png", + "type": "green", + "alias": [ + "机炮炮台" + ], + "backpack": 0 + }, + { + "name": "A·ARC-3 特斯拉塔", + "path": "img/helldivers/A·ARC-3 特斯拉塔.png", + "type": "green", + "alias": [ + "电塔" + ], + "backpack": 0 + }, + { + "name": "A·FLAM-40 火焰喷射哨戒炮", + "path": "img/helldivers/A·FLAM-40 火焰喷射哨戒炮.png", + "type": "green", + "alias": [ + "喷火炮台" + ], + "backpack": 0 + }, + { + "name": "A·G-16 加特林哨戒炮", + "path": "img/helldivers/A·G-16 加特林哨戒炮.png", + "type": "green", + "alias": [ + "加特林炮台" + ], + "backpack": 0 + }, + { + "name": "A·GM-17 瓦斯迫击哨戒炮", + "path": "img/helldivers/A·GM-17 瓦斯迫击哨戒炮.png", + "type": "green", + "alias": [ + "毒迫" + ], + "backpack": 0 + }, + { + "name": "A·LAS-98 激光哨戒炮", + "path": "img/helldivers/A·LAS-98 激光哨戒炮.png", + "type": "green", + "alias": [ + "激光炮台" + ], + "backpack": 0 + }, + { + "name": "A·M-12 迫击哨戒炮", + "path": "img/helldivers/A·M-12 迫击哨戒炮.png", + "type": "green", + "alias": [ + "炮击炮" + ], + "backpack": 0 + }, + { + "name": "A·M-23 电磁冲击波迫击哨戒炮", + "path": "img/helldivers/A·M-23 电磁冲击波迫击哨戒炮.png", + "type": "green", + "alias": [ + "电磁迫击炮" + ], + "backpack": 0 + }, + { + "name": "A·MG-43 哨戒机枪", + "path": "img/helldivers/A·MG-43 哨戒机枪.png", + "type": "green", + "alias": [ + "小机枪炮塔" + ], + "backpack": 0 + }, + { + "name": "A·MLS-X 火箭哨戒炮", + "path": "img/helldivers/A·MLS-X 火箭哨戒炮.png", + "type": "green", + "alias": [ + "" + ], + "backpack": 0 + }, + { + "name": "B-1 补给背包", + "path": "img/helldivers/B-1 补给背包.png", + "type": "blue", + "alias": [ + "补包" + ], + "backpack": 1 + }, + { + "name": "B-100 便携式地狱火炸弹", + "path": "img/helldivers/B-100 便携式地狱火炸弹.png", + "type": "blue", + "alias": [ + "地狱火背包" + ], + "backpack": 1 + }, + { + "name": "B·FLAM-80 焚燃者", + "path": "img/helldivers/B·FLAM-80 焚燃者.png", + "type": "blue", + "alias": [ + "背包喷火" + ], + "backpack": 1 + }, + { + "name": "B·MD C4背包", + "path": "img/helldivers/B·MD C4背包.png", + "type": "blue", + "alias": [ + "C4背包" + ], + "backpack": 1 + }, + { + "name": "CQC-1 唯一真旗", + "path": "img/helldivers/CQC-1 唯一真旗.png", + "type": "blue", + "alias": [ + "唯一真旗" + ], + "backpack": 0 + }, + { + "name": "CQC-20 破门锤", + "path": "img/helldivers/CQC-20 破门锤.png", + "type": "blue", + "alias": [ + "锤子" + ], + "backpack": 0 + }, + { + "name": "CQC-9 除叶工具", + "path": "img/helldivers/CQC-9 除叶工具.png", + "type": "blue", + "alias": [ + "电锯" + ], + "backpack": 0 + }, + { + "name": "EAT-17 消耗性反坦克武器", + "path": "img/helldivers/EAT-17 消耗性反坦克武器.png", + "type": "blue", + "alias": [ + "次抛" + ], + "backpack": 0 + }, + { + "name": "EAT-411 荡平者", + "path": "img/helldivers/EAT-411 荡平者.png", + "type": "blue", + "alias": [ + "大通碟" + ], + "backpack": 0 + }, + { + "name": "EAT-700 消耗性凝固汽油弹", + "path": "img/helldivers/EAT-700 消耗性凝固汽油弹.png", + "type": "blue", + "alias": [ + "火次抛" + ], + "backpack": 0 + }, + { + "name": "EXO-45 爱国者外骨骼机甲", + "path": "img/helldivers/EXO-45 爱国者外骨骼机甲.png", + "type": "blue", + "alias": [ + "机枪机甲" + ], + "backpack": 0 + }, + { + "name": "EXO-49 解放者外骨骼机甲", + "path": "img/helldivers/EXO-49 解放者外骨骼机甲.png", + "type": "blue", + "alias": [ + "机炮机甲" + ], + "backpack": 0 + }, + { + "name": "EXO-51 伐木者", + "path": "img/helldivers/EXO-51 伐木者.png", + "type": "blue", + "alias": [ + "喷火机甲" + ], + "backpack": 0 + }, + { + "name": "EXO-55 突破", + "path": "img/helldivers/EXO-55 突破.png", + "type": "blue", + "alias": [ + "大盾机甲", + "突破大人" + ], + "backpack": 0 + }, + { + "name": "E·AT-12 反坦克炮台", + "path": "img/helldivers/E·AT-12 反坦克炮台.png", + "type": "green", + "alias": [ + "轮椅炮" + ], + "backpack": 0 + }, + { + "name": "E·GL-21 掷弹兵防卫墙", + "path": "img/helldivers/E·GL-21 掷弹兵防卫墙.png", + "type": "green", + "alias": [ + "榴弹墙" + ], + "backpack": 0 + }, + { + "name": "E·MG-101 重机枪部署支架", + "path": "img/helldivers/E·MG-101 重机枪部署支架.png", + "type": "green", + "alias": [ + "重机枪支架" + ], + "backpack": 0 + }, + { + "name": "FAF-14 飞矛", + "path": "img/helldivers/FAF-14 飞矛.png", + "type": "blue", + "alias": [ + "飞矛" + ], + "backpack": 1 + }, + { + "name": "FLAM-40 火焰喷射器", + "path": "img/helldivers/FLAM-40 火焰喷射器.png", + "type": "blue", + "alias": [ + "火焰喷射器" + ], + "backpack": 0 + }, + { + "name": "FX-12 防护罩生成中继器", + "path": "img/helldivers/FX-12 防护罩生成中继器.png", + "type": "green", + "alias": [ + "大蛋盾" + ], + "backpack": 0 + }, + { + "name": "GL-21 榴弹发射器", + "path": "img/helldivers/GL-21 榴弹发射器.png", + "type": "blue", + "alias": [ + "榴弹发射器" + ], + "backpack": 0 + }, + { + "name": "GL-28 弹链式榴弹发射器", + "path": "img/helldivers/GL-28 弹链式榴弹发射器.png", + "type": "blue", + "alias": [ + "弹链榴弹" + ], + "backpack": 1 + }, + { + "name": "GL-52 缓和使者", + "path": "img/helldivers/GL-52 缓和使者.png", + "type": "blue", + "alias": [ + "电榴弹" + ], + "backpack": 0 + }, + { + "name": "GR-8 无后坐力炮", + "path": "img/helldivers/GR-8 无后坐力炮.png", + "type": "blue", + "alias": [ + "无后坐" + ], + "backpack": 1 + }, + { + "name": "LAS-98 激光大炮", + "path": "img/helldivers/LAS-98 激光大炮.png", + "type": "blue", + "alias": [ + "激光大炮" + ], + "backpack": 0 + }, + { + "name": "LAS-99 类星体加农炮", + "path": "img/helldivers/LAS-99 类星体加农炮.png", + "type": "blue", + "alias": [ + "类星体" + ], + "backpack": 0 + }, + { + "name": "LIFT-182 传送背包", + "path": "img/helldivers/LIFT-182 传送背包.png", + "type": "blue", + "alias": [ + "传包" + ], + "backpack": 1 + }, + { + "name": "LIFT-850 喷射背包", + "path": "img/helldivers/LIFT-850 喷射背包.png", + "type": "blue", + "alias": [ + "跳包" + ], + "backpack": 1 + }, + { + "name": "LIFT-860 悬浮背包", + "path": "img/helldivers/LIFT-860 悬浮背包.png", + "type": "blue", + "alias": [ + "悬浮背包" + ], + "backpack": 1 + }, + { + "name": "M-1000 重装机枪", + "path": "img/helldivers/M-1000 重装机枪.png", + "type": "blue", + "alias": [ + "弹链机枪" + ], + "backpack": 1 + }, + { + "name": "M-102 快速侦察载具", + "path": "img/helldivers/M-102 快速侦察载具.png", + "type": "blue", + "alias": [ + "FRV", + "小车" + ], + "backpack": 0 + }, + { + "name": "M-105 盟友", + "path": "img/helldivers/M-105 盟友.png", + "type": "blue", + "alias": [ + "盟友" + ], + "backpack": 0 + }, + { + "name": "MD-17 反坦克地雷", + "path": "img/helldivers/MD-17 反坦克地雷.png", + "type": "green", + "alias": [ + "反坦克地雷" + ], + "backpack": 0 + }, + { + "name": "MD-6 反步兵雷区", + "path": "img/helldivers/MD-6 反步兵雷区.png", + "type": "green", + "alias": [ + "反步兵雷区" + ], + "backpack": 0 + }, + { + "name": "MD-8 毒气地雷", + "path": "img/helldivers/MD-8 毒气地雷.png", + "type": "green", + "alias": [ + "毒气地雷", + "阳光青提" + ], + "backpack": 0 + }, + { + "name": "MD-I4 燃烧地雷", + "path": "img/helldivers/MD-I4 燃烧地雷.png", + "type": "green", + "alias": [ + "火地雷" + ], + "backpack": 0 + }, + { + "name": "MG-206 重机枪", + "path": "img/helldivers/MG-206 重机枪.png", + "type": "blue", + "alias": [ + "重机枪" + ], + "backpack": 0 + }, + { + "name": "MG-43 机枪", + "path": "img/helldivers/MG-43 机枪.png", + "type": "blue", + "alias": [ + "中机枪" + ], + "backpack": 0 + }, + { + "name": "MGX-42 子弹风暴", + "path": "img/helldivers/MGX-42 子弹风暴.png", + "type": "blue", + "alias": [ + "子弹风暴" + ], + "backpack": 0 + }, + { + "name": "MLS-4X 突击兵", + "path": "img/helldivers/MLS-4X 突击兵.png", + "type": "blue", + "alias": [ + "突击兵" + ], + "backpack": 0 + }, + { + "name": "MS-11 单兵导弹发射井", + "path": "img/helldivers/MS-11 单兵导弹发射井.png", + "type": "blue", + "alias": [ + "发射井" + ], + "backpack": 0 + }, + { + "name": "PLAS-45 纪元", + "path": "img/helldivers/PLAS-45 纪元.png", + "type": "blue", + "alias": [ + "纪元" + ], + "backpack": 0 + }, + { + "name": "RL-77 空爆火箭弹发射器", + "path": "img/helldivers/RL-77 空爆火箭弹发射器.png", + "type": "blue", + "alias": [ + "空爆" + ], + "backpack": 1 + }, + { + "name": "RS-422 磁轨炮", + "path": "img/helldivers/RS-422 磁轨炮.png", + "type": "blue", + "alias": [ + "磁轨", + "磁小轨" + ], + "backpack": 0 + }, + { + "name": "S-11 矛枪", + "path": "img/helldivers/S-11 矛枪.png", + "type": "blue", + "alias": [ + "毒矛" + ], + "backpack": 0 + }, + { + "name": "SH-20 防弹护盾背包", + "path": "img/helldivers/SH-20 防弹护盾背包.png", + "type": "blue", + "alias": [ + "防弹盾" + ], + "backpack": 1 + }, + { + "name": "SH-32 防护罩生成包", + "path": "img/helldivers/SH-32 防护罩生成包.png", + "type": "blue", + "alias": [ + "蛋盾" + ], + "backpack": 1 + }, + { + "name": "SH-51 定向护盾", + "path": "img/helldivers/SH-51 定向护盾.png", + "type": "blue", + "alias": [ + "定向蛋盾" + ], + "backpack": 1 + }, + { + "name": "StA-X3 W.A.S.P.发射器", + "path": "img/helldivers/StA-X3 W.A.S.P.发射器.png", + "type": "blue", + "alias": [ + "小蜜蜂" + ], + "backpack": 1 + }, + { + "name": "TD-220 堡垒MK XVI", + "path": "img/helldivers/TD-220 堡垒MK XVI.png", + "type": "blue", + "alias": [ + "坦克" + ], + "backpack": 0 + }, + { + "name": "TX-41 灭菌器", + "path": "img/helldivers/TX-41 灭菌器.png", + "type": "blue", + "alias": [ + "毒喷" + ], + "backpack": 0 + }, + { + "name": "轨道120MM高爆弹火力网", + "path": "img/helldivers/轨道120MM高爆弹火力网.png", + "type": "red", + "alias": [ + "120" + ], + "backpack": 0 + }, + { + "name": "轨道380MM高爆弹火力网", + "path": "img/helldivers/轨道380MM高爆弹火力网.png", + "type": "red", + "alias": [ + "380" + ], + "backpack": 0 + }, + { + "name": "轨道凝固汽油弹火力网", + "path": "img/helldivers/轨道凝固汽油弹火力网.png", + "type": "red", + "alias": [ + "轨道火" + ], + "backpack": 0 + }, + { + "name": "轨道加特林火力网", + "path": "img/helldivers/轨道加特林火力网.png", + "type": "red", + "alias": [ + "轨道加特林" + ], + "backpack": 0 + }, + { + "name": "轨道毒气攻击", + "path": "img/helldivers/轨道毒气攻击.png", + "type": "red", + "alias": [ + "轨道毒" + ], + "backpack": 0 + }, + { + "name": "轨道游走火力网", + "path": "img/helldivers/轨道游走火力网.png", + "type": "red", + "alias": [ + "轨道游走" + ], + "backpack": 0 + }, + { + "name": "轨道激光炮", + "path": "img/helldivers/轨道激光炮.png", + "type": "red", + "alias": [ + "轨道激光" + ], + "backpack": 0 + }, + { + "name": "轨道炮攻击", + "path": "img/helldivers/轨道炮攻击.png", + "type": "red", + "alias": [ + "轨道自瞄" + ], + "backpack": 0 + }, + { + "name": "轨道烟雾攻击", + "path": "img/helldivers/轨道烟雾攻击.png", + "type": "red", + "alias": [ + "轨道烟" + ], + "backpack": 0 + }, + { + "name": "轨道电磁冲击波攻击", + "path": "img/helldivers/轨道电磁冲击波攻击.png", + "type": "red", + "alias": [ + "轨道电磁" + ], + "backpack": 0 + }, + { + "name": "轨道空爆攻击", + "path": "img/helldivers/轨道空爆攻击.png", + "type": "red", + "alias": [ + "轨道空爆" + ], + "backpack": 0 + }, + { + "name": "轨道精准攻击", + "path": "img/helldivers/轨道精准攻击.png", + "type": "red", + "alias": [ + "" + ], + "backpack": 0 + }, + { + "name": "飞鹰110MM火箭巢", + "path": "img/helldivers/飞鹰110MM火箭巢.png", + "type": "red", + "alias": [ + "飞鹰110" + ], + "backpack": 0 + }, + { + "name": "飞鹰500KG炸弹", + "path": "img/helldivers/飞鹰500KG炸弹.png", + "type": "red", + "alias": [ + "500", + "飞鹰500" + ], + "backpack": 0 + }, + { + "name": "飞鹰凝固汽油弹空袭", + "path": "img/helldivers/飞鹰凝固汽油弹空袭.png", + "type": "red", + "alias": [ + "飞鹰火" + ], + "backpack": 0 + }, + { + "name": "飞鹰机枪扫射", + "path": "img/helldivers/飞鹰机枪扫射.png", + "type": "red", + "alias": [ + "飞鹰机枪" + ], + "backpack": 0 + }, + { + "name": "飞鹰烟雾攻击", + "path": "img/helldivers/飞鹰烟雾攻击.png", + "type": "red", + "alias": [ + "飞鹰烟" + ], + "backpack": 0 + }, + { + "name": "飞鹰空袭", + "path": "img/helldivers/飞鹰空袭.png", + "type": "red", + "alias": [ + "" + ], + "backpack": 0 + }, + { + "name": "飞鹰集束炸弹", + "path": "img/helldivers/飞鹰集束炸弹.png", + "type": "red", + "alias": [ + "飞鹰集束" + ], + "backpack": 0 + } +] \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/FSSinclair-Bold.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/FSSinclair-Bold.ttf new file mode 100644 index 0000000..87caf61 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/FSSinclair-Bold.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HCSinclair-Bold.woff2 b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HCSinclair-Bold.woff2 new file mode 100644 index 0000000..d0dc0b2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HCSinclair-Bold.woff2 differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HCSinclair-Medium.woff2 b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HCSinclair-Medium.woff2 new file mode 100644 index 0000000..3727ec2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HCSinclair-Medium.woff2 differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HCSinclair-Normal.woff2 b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HCSinclair-Normal.woff2 new file mode 100644 index 0000000..a24a766 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HCSinclair-Normal.woff2 differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Black.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Black.ttf new file mode 100644 index 0000000..487752b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Black.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Bold.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Bold.ttf new file mode 100644 index 0000000..0a081bc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Bold.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-ExtraBold.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-ExtraBold.ttf new file mode 100644 index 0000000..0977ed5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-ExtraBold.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-ExtraLight.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-ExtraLight.ttf new file mode 100644 index 0000000..938fe31 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-ExtraLight.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Light.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Light.ttf new file mode 100644 index 0000000..c18b0c1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Light.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Medium.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Medium.ttf new file mode 100644 index 0000000..7ae796b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Medium.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Regular.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Regular.ttf new file mode 100644 index 0000000..826899c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-Regular.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-SemiBold.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-SemiBold.ttf new file mode 100644 index 0000000..6b37eeb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-SemiBold.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-VariableFont_wght.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-VariableFont_wght.ttf new file mode 100644 index 0000000..96106f0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/Outfit/Outfit-VariableFont_wght.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/一品创享体/一品创享体 1.20.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/一品创享体/一品创享体 1.20.ttf new file mode 100644 index 0000000..6dd3ca3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/一品创享体/一品创享体 1.20.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/余繁离形体/YuFanLixing.otf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/余繁离形体/YuFanLixing.otf new file mode 100644 index 0000000..421fd21 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/余繁离形体/YuFanLixing.otf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/光能雅黑/IlluminateBlack-Heavy.otf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/光能雅黑/IlluminateBlack-Heavy.otf new file mode 100644 index 0000000..10f18f8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/光能雅黑/IlluminateBlack-Heavy.otf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/创客贴金刚体/ChuangKeTieJinGangTi-2.otf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/创客贴金刚体/ChuangKeTieJinGangTi-2.otf new file mode 100644 index 0000000..22c754a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/创客贴金刚体/ChuangKeTieJinGangTi-2.otf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Bold.otf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Bold.otf new file mode 100644 index 0000000..72d6818 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Bold.otf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-ExtraLight.otf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-ExtraLight.otf new file mode 100644 index 0000000..5cad7ff Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-ExtraLight.otf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Heavy.otf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Heavy.otf new file mode 100644 index 0000000..a3dd4e0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Heavy.otf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Light.otf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Light.otf new file mode 100644 index 0000000..1cff8e6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Light.otf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Medium.otf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Medium.otf new file mode 100644 index 0000000..53e03e0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Medium.otf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Normal.otf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Normal.otf new file mode 100644 index 0000000..091f56d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Normal.otf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Regular.otf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Regular.otf new file mode 100644 index 0000000..886f82f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/思源黑体/SourceHanSansCN-Regular.otf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Bold.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Bold.ttf new file mode 100644 index 0000000..feb8720 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Bold.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Heavy.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Heavy.ttf new file mode 100644 index 0000000..5b83774 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Heavy.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Light.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Light.ttf new file mode 100644 index 0000000..4aeb888 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Light.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Medium.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Medium.ttf new file mode 100644 index 0000000..95526f5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Medium.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Regular.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Regular.ttf new file mode 100644 index 0000000..ea957a4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Regular.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Thin.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Thin.ttf new file mode 100644 index 0000000..0bfed26 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/文源圆体/WenYuanRoundedSC-Thin.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/爱点风雅黑/爱点风雅黑.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/爱点风雅黑/爱点风雅黑.ttf new file mode 100644 index 0000000..0d90649 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/爱点风雅黑/爱点风雅黑.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/爱点风雅黑/爱点风雅黑长体(商用免费).ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/爱点风雅黑/爱点风雅黑长体(商用免费).ttf new file mode 100644 index 0000000..3787512 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/爱点风雅黑/爱点风雅黑长体(商用免费).ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/赛博斯坦雅黑/CyberstanBlackAL-Heavy.otf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/赛博斯坦雅黑/CyberstanBlackAL-Heavy.otf new file mode 100644 index 0000000..4193134 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用免费/赛博斯坦雅黑/CyberstanBlackAL-Heavy.otf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/Aa综艺体/AaZongYiYuan-2.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/Aa综艺体/AaZongYiYuan-2.ttf new file mode 100644 index 0000000..c93ca1f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/Aa综艺体/AaZongYiYuan-2.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/FS Sinclair/output (2).ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/FS Sinclair/output (2).ttf new file mode 100644 index 0000000..0f0abcd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/FS Sinclair/output (2).ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/FS Sinclair/output (3).ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/FS Sinclair/output (3).ttf new file mode 100644 index 0000000..0005271 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/FS Sinclair/output (3).ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/FS Sinclair/output (4).ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/FS Sinclair/output (4).ttf new file mode 100644 index 0000000..0667e24 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/FS Sinclair/output (4).ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/NASDAQER/NASDAQER-1.ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/NASDAQER/NASDAQER-1.ttf new file mode 100644 index 0000000..27e0ad7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/NASDAQER/NASDAQER-1.ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/Square721/output (1).ttf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/Square721/output (1).ttf new file mode 100644 index 0000000..90dec7c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/Square721/output (1).ttf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/造字工坊尚黑/ZaoZiGongFangShangHeiG0v1XiChaoChangTi-1.otf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/造字工坊尚黑/ZaoZiGongFangShangHeiG0v1XiChaoChangTi-1.otf new file mode 100644 index 0000000..427560f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/造字工坊尚黑/ZaoZiGongFangShangHeiG0v1XiChaoChangTi-1.otf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/造字工坊尚黑/造字工房尚黑G0v1常规体.otf b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/造字工坊尚黑/造字工房尚黑G0v1常规体.otf new file mode 100644 index 0000000..d2dacb5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/商用授权/造字工坊尚黑/造字工房尚黑G0v1常规体.otf differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/安装前须知.txt b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/安装前须知.txt new file mode 100644 index 0000000..d557076 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/HD2S字体包/安装前须知.txt @@ -0,0 +1,7 @@ +字体仅作为社区分享参考作用 侵权请联系 +如需字体授权请前往字体对应厂商进行联系 + +字体使用建议: +简单字重原理介绍 +字重决定了画面中文字的视觉比重 字重越大越被容易注意 +即 文字越大字重越重 文字越细字重越小 \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/msyh.ttc b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/msyh.ttc new file mode 100644 index 0000000..ddc87b9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/data/font/msyh.ttc differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/i18n.json b/hexi/plugins/nonebot_plugin_helldivers_tools/data/i18n.json new file mode 100644 index 0000000..623cc0a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/data/i18n.json @@ -0,0 +1,567 @@ +{ + "biome": { + "ACCESS DENIED": "拒绝访问", + "Acidic Badlands": "酸性恶地", + "Basic Swamp": "沼泽", + "Black Hole": "黑洞", + "Bleak Oasis": "衰败绿洲", + "Boneyard": "骸骨之地", + "Cyberstan Megafactory": "生化斯坦大型工厂", + "Deadlands": "死寂之地", + "Deciduous Autumn Forest": "秋季落叶林", + "Deciduous Crimson Forest": "绯红落叶林", + "Deciduous Forest": "落叶林", + "Desert Cliffs": "沙漠悬壁", + "Desert Dunes": "沙漠沙丘", + "Desert Oasis": "沙漠绿洲", + "Ethereal Jungle": "缥缈丛林", + "Haunted Swamp": "幽祟沼泽", + "Hive World": "虫窝世界", + "Icy Glaciers": "冰封冰川", + "Ionic Crimson": "离子绯红之地", + "Ionic Jungle": "离子丛林", + "Magma": "岩浆地带", + "Moon": "月球", + "Plains": "平原", + "Rocky Canyons": "岩质峡谷", + "Scorched Moor": "焦土荒原", + "Super Earth": "超级地球", + "Supercolony": "超级拓殖地", + "Tien Kwan Special": "天关特域", + "Tundra": "苔原", + "Volcanic Jungle": "火山丛林" +}, + "sector": { + "AKIRA": "阿基拉分区", + "ALSTRAD": "阿尔斯特拉德分区", + "ALTUS": "阿尔特斯分区", + "ANDROMEDA": "仙女座分区", + "ARTURION": "阿图里昂分区", + "BARNARD": "巴纳德分区", + "BORGUS": "博格斯分区", + "CANCRI": "康古利伊分区", + "CANTOLUS": "坎托鲁斯分区", + "CELESTE": "塞勒斯特分区", + "DRACO": "天龙座分区", + "FALSTAFF": "法尔斯塔夫分区", + "FARSIGHT": "法尔赛特分区", + "FERRIS": "费里斯分区", + "GALLUX": "加卢克斯分区", + "GELLERT": "盖勒特分区", + "GOTHMAR": "戈特玛分区", + "GUANG": "古安分区", + "HANZO": "半藏分区", + "HAWKING": "霍金分区", + "HYDRA": "长蛇座分区", + "IDUN": "伊顿分区", + "IPTUS": "伊普都斯分区", + "JIN XI": "锦栖分区", + "KELVIN": "凯尔文分区", + "KORPUS": "科普斯分区", + "L'ESTRADE": "莱斯特拉德分区", + "LACAILLE": "拉凯欧分区", + "LEO": "狮子座分区", + "MARSPIRA": "马斯皮拉分区", + "MERIDIAN": "默里迪亚分区", + "MIRIN": "米琳分区", + "MORGON": "莫根分区", + "NANOS": "纳诺斯分区", + "OMEGA": "欧米茄分区", + "ORION": "猎户座分区", + "QUINTUS": "昆图斯分区", + "RICTUS": "瑞克图斯分区", + "RIGEL": "参宿七分区", + "SAGAN": "萨根分区", + "SALERIA": "萨勒莉亚分区", + "SEVERIN": "塞弗林分区", + "SOL": "太阳系", + "STEN": "斯坦分区", + "TALUS": "塔洛斯分区", + "TANIS": "塔尼斯分区", + "TARRAGON": "塔拉戈分区", + "TBD": "TBD", + "THESEUS": "忒修斯分区", + "TRIGON": "特里贡分区", + "UMLAUT": "乌姆劳特分区", + "URSA": "大熊座分区", + "VALDIS": "瓦尔迪斯分区", + "XI TAURI": "金牛座分区", + "XZAR": "兹亚尔分区", + "YMIR": "土卫十九分区" + }, + "hazard": { + "Acid Storms": "酸雨风暴", + "Blizzards": "暴风雪", + "Extreme Cold": "极寒", + "Fire Tornadoes": "烈焰龙卷", + "Intense Heat": "极暑", + "Ion Storms": "离子风暴", + "Meteor Storms": "流星风暴", + "Rainstorms": "暴雨", + "Sandstorms": "沙暴", + "Thick Fog": "浓雾", + "Tremors": "地震", + "Volcanic Activity": "火山活动" + }, + "effect": { + "1127": "飞鹰500KG炸弹", + "1128": "飞鹰500KG炸弹", + "1129": "防护罩生成包", + "1130": "特斯拉塔", + "1133": "迫击哨戒炮", + "1137": "磁轨炮", + "1139": "飞鹰凝固汽油弹空袭", + "1142": "飞鹰500KG炸弹", + "1143": "Mg-43 机枪", + "1145": "轨道激光炮", + "1147": "轨道电磁冲击波攻击", + "1148": "爱国者外骨骼装甲", + "1149": "喷射背包", + "1150": "补给背包", + "1152": "反器材步枪", + "1153": "磁轨炮", + "1154": "轨道炮攻击", + "1155": "机炮", + "1156": "飞鹰110MM火箭巢", + "1160": "轨道电磁冲击波攻击", + "1161": "飞鹰凝固汽油弹空袭", + "1162": "爱国者外骨骼装甲", + "1163": "飞鹰110MM火箭巢", + "1165": "喷射背包", + "1166": "飞鹰500KG炸弹", + "1167": "火焰喷射器", + "1168": "激光大炮", + "1169": "消耗性反坦克武器", + "1170": "空爆火箭弹发射器", + "1171": "反坦克地雷", + "1172": "轨道毒气攻击", + "1173": "解放者外骨骼装甲", + "1174": "迫击哨戒炮", + "1175": "加特林哨戒炮", + "1177": "黑洞", + "1179": "机炮", + "1181": "突击兵", + "1184": "燃烧地雷", + "1185": "反步兵雷区", + "1186": "轻度阴霾笼罩", + "1187": "阴霾", + "1188": "重度阴霾笼罩", + "1190": "无法抵达", + "1193": "阴霾边界", + "1194": "轨道凝固汽油弹火力网", + "1195": "DSS建筑工地 - 第1阶段", + "1196": "DSS物流中心", + "1197": "异星昆虫学研究中心", + "1198": "深部地幔铸造复合体", + "1199": "DSS建筑工地 - 第2阶段", + "1200": "特斯拉塔", + "1202": "喷气旅", + "1203": "喷气旅", + "1204": "解放日", + "1205": "DSS建筑工地 - 第3阶段", + "1206": "终结族研究保护区", + "1207": "重机枪部署支架", + "1209": "飞鹰风暴", + "1210": "轨道封锁", + "1211": "星球轰炸", + "1212": "飞鹰风暴 (Marker)", + "1213": "轨道封锁 (Marker)", + "1214": "轨道重火力支援", + "1215": "轨道封锁", + "1216": "飞鹰风暴", + "1217": "民主空间站", + "1222": "雨水覆盖", + "1226": "飞矛", + "1227": "Mg-43 机枪", + "1228": "默里迪恩黑洞 (Old Map Marker)", + "1229": "默里迪恩黑洞", + "1230": "默里迪恩黑洞", + "1231": "毒气地雷", + "1232": "工厂枢纽", + "1233": "W.A.S.P.发射器", + "1234": "科学中心", + "1235": "反坦克地雷", + "1236": "公民监控和安全中心", + "1237": "轨道380MM高爆弹火力网", + "1238": "行动支持", + "1239": "喷气旅孵化厂", + "1240": "濒临毁灭", + "1241": "碎裂星球", + "1242": "移动行星", + "1243": "掠食变种", + "1244": "孢裂变种", + "1245": "掠食变种", + "1246": "战役封锁", + "1247": "毒气地雷", + "1248": "炽灼部队", + "1249": "炽灼部队", + "1252": "碎裂星球", + "1254": "重机枪", + "1256": "掷弹兵防卫墙", + "1261": "外骨骼装甲储备", + "1262": "外骨骼装甲储备", + "1263": "盟友", + "1267": "轨道毒气攻击", + "1268": "负能量实验室", + "1269": "大军", + "1274": "盟友", + "1276": "防护罩生成中继器", + "1277": "轨道凝固汽油弹火力网", + "1279": "快速侦察载具", + "1280": "轨道烟雾攻击", + "1281": "飞鹰烟雾攻击", + "1282": "绝地潜兵训练基地", + "1283": "移动工厂激增", + "1284": "无后坐力炮", + "1285": "穿刺虫暴动", + "1286": "希望新城建造区", + "1287": "希望新城", + "1288": "孢裂食腐虫暴动", + "1291": "志向新城", + "1292": "盛盼新城", + "1293": "强袭虫暴动", + "1295": "第二代暴政公园", + "1303": "爆裂虫族变种", + "1304": "阿尔法哨站", + "1306": "蟑龙", + "1307": "霸王虫", + "1308": "霸王虫", + "1309": "蟑龙", + "1310": "爆裂虫族变种", + "1311": "虫窝世界", + "1324": "超镁铁矿井", + "1329": "解放日庆典", + "1342": "异见监禁中心 (CECOD)", + "1344": "潘多拉基地", + "1352": "常规黑洞", + "1353": "数据中心", + "1355": "重甲敌军激增", + "1357": "巨型者激增", + "1359": "蹂躏者激增", + "1360": "生化人", + "1361": "生化人", + "1373": "1级异界风暴", + "1374": "2级异界风暴", + "1375": "3级异界风暴", + "1376": "寂域", + "1377": "无脑群氓", + "1378": "无脑群氓", + "1379": "占领者", + "1380": "占领者", + "1386": "孢裂变种", + "1387": "通信阵列", + "1395": "TCS+", + "1400": "SEAF驻守", + "1401": "SEAF驻守", + "1402": "窃票者", + "1403": "窃票者", + "1406": "寂域边界", + "1407": "寂域通路", + "1412": "异常地点", + "1413": "光能入侵舰队", + "1414": "光能入侵舰队" + }, + "planet": { + "ACAMAR IV": "天园六IV", + "ACHERNAR SECUNDUS": "水委一次星", + "ACHIRD III": "王良三III", + "ACRAB XI": "房宿四XI", + "ACRUX IX": "十字架二IX", + "ACTIVE PLANETS": "ACTIVE PLANETS", + "ACUBENS PRIME": "柳宿增三主星", + "ADHARA": "弧矢七", + "AERIS PASS": "AERIS PASS", + "AESIR PASS": "亚萨关隘", + "AFOYAY BAY": "艾福亚湾", + "AIN-5": "毕宿一5", + "ALAIRT III": "艾列尔特III", + "ALAMAK VII": "天大将军一VII", + "ALARAPH": "右执法", + "ALATHFAR XI": "织女增三XI", + "ALDERIDGE COVE": "阿尔德里奇湾", + "ALTA V": "奥尔塔V", + "ANDAR": "安达尔", + "ANGEL'S VENTURE": "天使投资", + "ARKTURUS": "阿克图勒斯", + "ASPEROTH PRIME": "阿斯佩洛斯主星", + "ATRAMA": "阿特拉玛", + "AURORA BAY": "极光湾", + "AWAITING MAJOR ORDER": "等待重要指令", + "AZTERRA": "艾孜泰拉", + "AZUR SECUNDUS": "艾热尔次星", + "BALDRICK PRIME": "巴尔德里克主星", + "BARABOS": "巴勒博斯", + "BASHYR": "巴希尔", + "BASQUINE VIII": "巴斯金VIII", + "BEKVAM III": "贝克温III", + "BELLATRIX": "参宿五", + "BIG ROCK": "巨岩", + "BLISTICA": "布里斯提卡", + "BORE ROCK": "博尔岩", + "BOREA": "博瑞亚", + "BOTEIN": "天阴四", + "BRILLIANCE": "璨光", + "BRINK-2": "布林克2", + "BUNDA SECUNDUS": "天垒城一次星", + "CALYPSO": "卡利普索", + "CANOPUS": "老人", + "CAPH": "王良一", + "CARAMOOR": "开勒莫尔", + "CASTOR": "北河二", + "CERBERUS IIIC": "刻耳柏洛斯IIIc", + "CHARBAL-VII": "查巴尔VII", + "CHARON PRIME": "卡戎主星", + "CHOEPESSA IV": "科埃佩萨IV", + "CHOOHE": "丘伊", + "CHORT BAY": "雀特湾", + "CIRRUS": "希勒斯", + "CLAORELL": "可洛尔", + "CLASA": "克拉萨", + "CRIMSICA": "克里姆西卡", + "CRUCIBLE": "熔炉", + "CURIA": "居里亚", + "CYBERSTAN": "生化斯坦", + "DARIUS II": "大流士II", + "DARROWSPORT": "达罗斯波特", + "DEFEND": "保卫", + "DEMIURG": "戴米尔基", + "DENEB SECUNDUS": "天津四次星", + "DIASPORA X": "大流散X", + "DILUVIA": "迪卢维亚", + "DILVUIA": "DILVUIA", + "DOLPH": "多尔夫", + "DRAUPNIR": "德罗普尼尔", + "DUMA TYR": "杜马提尔", + "DURGEN": "德尔根", + "Defended Planets": "保卫行星", + "EAST IRIDIUM TRADING BAY": "东铱贸易湾", + "EFFLUVIA": "艾芙鲁维亚", + "ELECTRA BAY": "昴宿一湾", + "ELYSIAN MEADOWS": "埃律西昂草原", + "EMERIA": "埃梅里亚", + "EMORATH": "艾莫拉斯", + "ENULIALE": "安努力亚", + "EPSILON PHOENCIS VI": "艾普斯林芬赛斯VI", + "ERATA PRIME": "艾拉特主星", + "ERRATA PRIME": "ERRATA PRIME", + "ERSON SANDS": "厄尔森桑兹", + "ESKER": "艾斯克尔", + "ESTANU": "伊斯塔努", + "EUKORIA": "欧科里亚", + "EUPHORIA III": "欧福利亚III", + "FENMIRE": "范迈尔", + "FENRIR III": "芬里尔III", + "FORI PRIME": "佛里主星", + "FORNSKOGUR II": "福恩斯科古尔II", + "FORT JUSTICE": "正义堡", + "FORT SANCTUARY": "庇护堡", + "FORT UNION": "联合堡", + "FREEDOM PEAK": "弗里敦峰", + "FRONTERIA": "边陲", + "FURY": "费里", + "GACRUX": "十字架一", + "GAELLIVARE": "耶利瓦勒", + "GAR HAREN": "轧尔哈伦", + "GATRIA": "盖尔崔亚", + "GEMMA": "贯索四", + "GEMSTONE BLUFFS": "宝石崖", + "GENESIS PRIME": "创世主星", + "GRAFMERE": "格拉夫米尔", + "GRAND ERRANT": "大艾伦特", + "GUNVALD": "古恩瓦尔德", + "Galaxy Stats": "星系状况", + "HADAR": "马腹一", + "HADR": "HADR", + "HAKA": "哈卡", + "HALDUS": "海德斯", + "HALIES PORT": "海利斯港", + "HEETH": "希斯", + "HELLMIRE": "海尔迈尔", + "HERTHON SECUNDUS": "赫尔松次星", + "HESOE PRIME": "海索主星", + "HEZE BAY": "角宿二湾", + "HORT": "哈尔特", + "HYDROBIUS": "哈卓毕亚斯", + "HYDROFALL PRIME": "水瀑主星", + "IGLA": "伊格勒", + "ILDUNA PRIME": "伊尔都纳主星", + "IMBER": "因博尔", + "INARI": "伊纳里", + "INGMAR": "英格玛", + "IRIDICA": "艾丽迪卡", + "IRO": "伊罗", + "IRULTA": "艾鲁尔塔", + "IVIS": "艾维斯", + "JULHEIM": "尤尔海姆", + "K": "K", + "KARLIA": "可利亚", + "KEID": "九州殊口增七", + "KELVINOR": "开尔文奥尔", + "KERTH SECUNDUS": "克斯次星", + "KHANDARK": "勘达尔克", + "KHARST": "喀斯特", + "KIRRIK": "基里克", + "KLAKA 5": "克拉卡5", + "KLEN DAHTH II": "克伦达斯II", + "KNETH PORT": "克奈斯港", + "KRAKABOS": "克拉克博斯", + "KRAKATWO": "克拉克图", + "KRAZ": "轸宿四", + "KUMA": "天棓二", + "KUPER": "库珀", + "LASTOFE": "赖斯斗夫", + "LENG SCUNDUS": "LENG SCUNDUS", + "LENG SECUNDUS": "蓝恩次星", + "LESATH": "尾宿八", + "LIBERTY RIDGE": "解放岭", + "LUXURIANT": "富源", + "MAIA": "昴宿四", + "MAJOR ORDER": "重要指令", + "MALEVELON CREEK": "麦拉芬蒙河", + "MANTES": "蒙特斯", + "MARFARK": "玛尔法克", + "MARRE IV": "马尔IV", + "MARTALE": "玛尔特", + "MARTYR'S BAY": "烈士湾", + "MASTIA": "玛斯蒂亚", + "MATAR BAY": "玛塔", + "MAW": "深渊", + "MEDALS": "MEDALS", + "MEISSA": "觜宿一", + "MEKBUDA": "井宿七", + "MENKENT": "库楼三", + "MERAK": "北斗二", + "MERGA IV": "玄戈增二IV", + "MERIDIA": "默里迪亚", + "MIDASBURG": "弥达斯堡", + "MINCHIR": "敏切尔", + "MINTORIA": "敏托瑞亚", + "MOG": "莫格", + "MORADESH": "莫拉戴什", + "MORDIA 9": "摩帝亚9", + "MORIDA 9": "MORIDA 9", + "MORT": "莫特", + "MORTAX PRIME": "摩尔塔克斯主星", + "MOX": "莫克斯", + "MYRADESH": "米拉戴什", + "MYRIUM": "梅里翁", + "Major Order ends in:": "最高指令结束:", + "NABATEA SECUNDUS": "那贝塔次星", + "NAVI VII": "阁道二", + "NEW HAVEN": "纽黑文", + "NEW INSIGHT": "新悟", + "NEW KIRUNA": "新基鲁纳", + "NEW STOCKHOLM": "新斯德哥尔摩", + "NIVEL 43": "尼维尔43", + "NUBLARIA I": "努布拉里亚I", + "OASIS": "绿洲", + "OBARI": "欧巴里", + "OKUL VI": "欧库VI", + "OMICRON": "奥密克戎", + "OSHAUNE": "欧绍恩", + "OSLO STATION": "奥斯陆站", + "OSUPSAM": "欧苏普森", + "OUTPOST 32": "32号哨站", + "OVERGOE PRIME": "欧维果主星", + "PANDION-XXIV": "帕狄恩XXIV", + "PARSH": "帕尔什", + "PARTION": "帕尔晨", + "PATHFINDER V": "开拓者V", + "PEACOCK": "孔雀十一", + "PENTA": "彭塔", + "PHACT BAY": "丈人一湾", + "PHERKAD SECUNDUS": "北极一次星", + "PILEN V": "皮伦V", + "PIONEER II": "先驱II", + "POLARIS PRIME": "北极星主星", + "POLLUX 31": "北河三31", + "PRASA": "普拉萨", + "PRIMORDIA": "普莱默迪亚", + "PROPUS": "五诸侯三", + "PROSPERITY FALLS": "繁荣瀑布", + "PROVIDENCE": "普罗维登斯", + "PÖPLI IX": "珀普利IX", + "RAS ALGETHI": "帝座", + "RASP": "拉斯普", + "RATCH": "拉奇", + "RD-4": "RD4", + "REAF": "利夫", + "REGNUS": "雷格努斯", + "RIRGA BAY": "里尔加湾", + "ROGUE 5": "罗格5", + "SANGIS": "赤血", + "SEASSE": "西斯", + "SENGE 23": "新戈23", + "SETIA": "赛提亚", + "SEYSHEL BEACH": "塞舌尔海滩", + "SHALLUS": "沙勒斯", + "SHELT": "谢尔特", + "SHETE": "赛特", + "SIEMNOT": "席姆纳特", + "SIRIUS": "天狼星", + "SKAASH": "斯卡什", + "SKAT BAY": "斯卡特湾", + "SKITTER": "斯基特", + "SLIF": "斯利夫", + "SOCORRO III": "索科罗III", + "SOLGHAST": "索尔加斯特", + "SPHERION": "斯飞利昂", + "STOR THA PRIME": "斯特萨主星", + "STOUT": "斯图尔特", + "SULFURA": "萨尔弗拉", + "SUPER EARTH": "超级地球", + "Stand by for further orders from Super Earth High Command": "等待超级地球最高指挥部的进一步指令", + "TARSH": "塔尔什", + "TERMADON": "特尔玛登", + "TERREK": "泰雷克", + "THE WEIR": "维尔", + "TIBIT": "提比特", + "TIEN KWAN": "天关", + "TOTAL PLAYERS:": "参战潜兵:", + "TRANDOR": "特兰道尔", + "TROOST": "特鲁斯特", + "TURING": "图灵", + "UBANEA": "乌巴尼亚", + "URSICA XI": "厄西卡XI", + "USTOTU": "伍斯特图", + "UVP ALPHA": "UVP阿尔法", + "UVP BETA": "UVP贝塔", + "UVP DELTA": "UVP德尔塔", + "UVP GAMMA": "UVP伽马", + "VALGAARD": "瓦尔加德", + "VALMOX": "瓦尔莫克斯", + "VANDALON IV": "万达隆IV", + "VARYLIA 5": "瓦瑞拉亚5", + "VEGA BAY": "织女一湾", + "VEIL": "帷幕", + "VELD": "维尔德", + "VERNEN WELLS": "佛农井", + "VINDEMITARIX PRIME": "文德米塔里克斯主星", + "VIRIDIA PRIME": "维尔伊迪亚主星", + "VOG-SOJOTH": "佛戈索约斯", + "VOLTERRA": "沃尔泰拉", + "WASAT": "天樽二", + "WAYWARD": "逸泊", + "WEZEN": "弧矢一", + "WIDOW'S HARBOR": "寡妇港", + "WILFORD STATION": "威尔福德站", + "WRAITH": "幽灵", + "X-45": "X45", + "YED PRIOR": "天市右垣九", + "ZAGON PRIME": "扎贡主星", + "ZEA RUGOSIA": "泽亚鲁戈西亚", + "ZEFIA": "赛飞亚", + "ZEGEMA PARADISE": "泽格马乐土", + "ZOSMA": "太微右垣五", + "ZYGOS": "齐戈斯", + "ZZANIAH PRIME": "藏尼亚主星" + }, + "campaign_type": { + "0": "解放战役", + "1": "侦察战役", + "2": "Story", + "3": "Conquest", + "4": "防御战", + "5": "Deployment" + } +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/i18n.json.prev b/hexi/plugins/nonebot_plugin_helldivers_tools/data/i18n.json.prev new file mode 100644 index 0000000..fc7270d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/data/i18n.json.prev @@ -0,0 +1,567 @@ +{ + "biome": { + "ACCESS DENIED": "拒绝访问", + "Acidic Badlands": "酸性恶地", + "Basic Swamp": "沼泽", + "Black Hole": "黑洞", + "Bleak Oasis": "衰败绿洲", + "Boneyard": "骸骨之地", + "Cyberstan Megafactory": "生化斯坦大型工厂", + "Deadlands": "死寂之地", + "Deciduous Autumn Forest": "秋季落叶林", + "Deciduous Crimson Forest": "绯红落叶林", + "Deciduous Forest": "落叶林", + "Desert Cliffs": "沙漠悬壁", + "Desert Dunes": "沙漠沙丘", + "Desert Oasis": "沙漠绿洲", + "Ethereal Jungle": "缥缈丛林", + "Haunted Swamp": "幽祟沼泽", + "Hive World": "虫窝世界", + "Icy Glaciers": "冰封冰川", + "Ionic Crimson": "离子绯红之地", + "Ionic Jungle": "离子丛林", + "Magma": "岩浆地带", + "Moon": "月球", + "Plains": "平原", + "Rocky Canyons": "岩质峡谷", + "Scorched Moor": "焦土荒原", + "Super Earth": "超级地球", + "Supercolony": "超级拓殖地", + "Tien Kwan Special": "天关特域", + "Tundra": "苔原", + "Volcanic Jungle": "火山丛林" +}, + "sector": { + "AKIRA": "阿基拉分区", + "ALSTRAD": "阿尔斯特拉德分区", + "ALTUS": "阿尔特斯分区", + "ANDROMEDA": "仙女座分区", + "ARTURION": "阿图里昂分区", + "BARNARD": "巴纳德分区", + "BORGUS": "博格斯分区", + "CANCRI": "康古利伊分区", + "CANTOLUS": "坎托鲁斯分区", + "CELESTE": "塞勒斯特分区", + "DRACO": "天龙座分区", + "FALSTAFF": "法尔斯塔夫分区", + "FARSIGHT": "法尔赛特分区", + "FERRIS": "费里斯分区", + "GALLUX": "加卢克斯分区", + "GELLERT": "盖勒特分区", + "GOTHMAR": "戈特玛分区", + "GUANG": "古安分区", + "HANZO": "半藏分区", + "HAWKING": "霍金分区", + "HYDRA": "长蛇座分区", + "IDUN": "伊顿分区", + "IPTUS": "伊普都斯分区", + "JIN XI": "锦栖分区", + "KELVIN": "凯尔文分区", + "KORPUS": "科普斯分区", + "L'ESTRADE": "莱斯特拉德分区", + "LACAILLE": "拉凯欧分区", + "LEO": "狮子座分区", + "MARSPIRA": "马斯皮拉分区", + "MERIDIAN": "默里迪亚分区", + "MIRIN": "米琳分区", + "MORGON": "莫根分区", + "NANOS": "纳诺斯分区", + "OMEGA": "欧米茄分区", + "ORION": "猎户座分区", + "QUINTUS": "昆图斯分区", + "RICTUS": "瑞克图斯分区", + "RIGEL": "参宿七分区", + "SAGAN": "萨根分区", + "SALERIA": "萨勒莉亚分区", + "SEVERIN": "塞弗林分区", + "SOL": "太阳系", + "STEN": "斯坦分区", + "TALUS": "塔洛斯分区", + "TANIS": "塔尼斯分区", + "TARRAGON": "塔拉戈分区", + "TBD": "TBD", + "THESEUS": "忒修斯分区", + "TRIGON": "特里贡分区", + "UMLAUT": "乌姆劳特分区", + "URSA": "大熊座分区", + "VALDIS": "瓦尔迪斯分区", + "XI TAURI": "金牛座分区", + "XZAR": "兹亚尔分区", + "YMIR": "土卫十九分区" + }, + "hazard": { + "Acid Storms": "酸雨风暴", + "Blizzards": "暴风雪", + "Extreme Cold": "极寒", + "Fire Tornadoes": "烈焰龙卷", + "Intense Heat": "极暑", + "Ion Storms": "离子风暴", + "Meteor Storms": "流星风暴", + "Rainstorms": "暴雨", + "Sandstorms": "沙暴", + "Thick Fog": "浓雾", + "Tremors": "地震", + "Volcanic Activity": "火山活动" + }, + "effect": { + "1127": "飞鹰500KG炸弹", + "1128": "飞鹰500KG炸弹", + "1129": "防护罩生成包", + "1130": "特斯拉塔", + "1133": "迫击哨戒炮", + "1137": "磁轨炮", + "1139": "飞鹰凝固汽油弹空袭", + "1142": "飞鹰500KG炸弹", + "1143": "Mg-43 机枪", + "1145": "轨道激光炮", + "1147": "轨道电磁冲击波攻击", + "1148": "爱国者外骨骼装甲", + "1149": "喷射背包", + "1150": "补给背包", + "1152": "反器材步枪", + "1153": "磁轨炮", + "1154": "轨道炮攻击", + "1155": "Ac-8 机炮", + "1156": "飞鹰110MM火箭巢", + "1160": "轨道电磁冲击波攻击", + "1161": "飞鹰凝固汽油弹空袭", + "1162": "爱国者外骨骼装甲", + "1163": "飞鹰110MM火箭巢", + "1165": "喷射背包", + "1166": "飞鹰500KG炸弹", + "1167": "火焰喷射器", + "1168": "激光大炮", + "1169": "消耗性反坦克武器", + "1170": "空爆火箭弹发射器", + "1171": "反坦克地雷", + "1172": "轨道毒气攻击", + "1173": "解放者外骨骼装甲", + "1174": "迫击哨戒炮", + "1175": "加特林哨戒炮", + "1177": "黑洞", + "1179": "机炮", + "1181": "突击兵", + "1184": "燃烧地雷", + "1185": "反步兵雷区", + "1186": "轻度阴霾笼罩", + "1187": "阴霾", + "1188": "重度阴霾笼罩", + "1190": "无法抵达", + "1193": "阴霾边界", + "1194": "轨道凝固汽油弹火力网", + "1195": "DSS建筑工地 - 第1阶段", + "1196": "DSS物流中心", + "1197": "异星昆虫学研究中心", + "1198": "深部地幔铸造复合体", + "1199": "DSS建筑工地 - 第2阶段", + "1200": "特斯拉塔", + "1202": "喷气旅", + "1203": "喷气旅", + "1204": "解放日", + "1205": "DSS建筑工地 - 第3阶段", + "1206": "终结族研究保护区", + "1207": "重机枪部署支架", + "1209": "飞鹰风暴", + "1210": "轨道封锁", + "1211": "星球轰炸", + "1212": "飞鹰风暴 (Marker)", + "1213": "轨道封锁 (Marker)", + "1214": "轰炸解放推进", + "1215": "轨道封锁", + "1216": "飞鹰风暴", + "1217": "民主空间站", + "1222": "雨水覆盖", + "1226": "飞矛", + "1227": "Mg-43 机枪", + "1228": "默里迪恩黑洞 (Old Map Marker)", + "1229": "默里迪恩黑洞", + "1230": "默里迪恩黑洞", + "1231": "毒气地雷", + "1232": "工厂枢纽", + "1233": "W.A.S.P.发射器", + "1234": "科学中心", + "1235": "反坦克地雷", + "1236": "公民监控和安全中心", + "1237": "轨道380MM高爆弹火力网", + "1238": "行动支持", + "1239": "喷气旅孵化厂", + "1240": "濒临毁灭", + "1241": "碎裂星球", + "1242": "移动行星", + "1243": "掠食变种", + "1244": "孢裂变种", + "1245": "掠食变种", + "1246": "战役封锁", + "1247": "毒气地雷", + "1248": "炽灼部队", + "1249": "炽灼部队", + "1252": "碎裂星球", + "1254": "重机枪", + "1256": "掷弹兵防卫墙", + "1261": "外骨骼装甲储备", + "1262": "外骨骼装甲储备", + "1263": "盟友", + "1267": "轨道毒气攻击", + "1268": "负能量实验室", + "1269": "大军", + "1274": "盟友", + "1276": "防护罩生成中继器", + "1277": "轨道凝固汽油弹火力网", + "1279": "快速侦察载具", + "1280": "轨道烟雾攻击", + "1281": "飞鹰烟雾攻击", + "1282": "绝地潜兵训练基地", + "1283": "移动工厂激增", + "1284": "无后坐力炮", + "1285": "穿刺虫暴动", + "1286": "希望新城建造区", + "1287": "希望新城", + "1288": "孢裂食腐虫暴动", + "1291": "志向新城", + "1292": "盛盼新城", + "1293": "强袭虫暴动", + "1295": "第二代暴政公园", + "1303": "爆裂虫族变种", + "1304": "阿尔法哨站", + "1306": "蟑龙", + "1307": "霸王虫", + "1308": "霸王虫", + "1309": "蟑龙", + "1310": "爆裂虫族变种", + "1311": "虫窝世界", + "1324": "超镁铁矿井", + "1329": "解放日庆典", + "1342": "异见监禁中心 (CECOD)", + "1344": "潘多拉基地", + "1352": "常规黑洞", + "1353": "数据中心", + "1355": "重甲敌军激增", + "1357": "巨型者激增", + "1359": "蹂躏者激增", + "1360": "生化人", + "1361": "生化人", + "1373": "1级异界风暴", + "1374": "2级异界风暴", + "1375": "3级异界风暴", + "1376": "寂域", + "1377": "无脑群氓", + "1378": "无脑群氓", + "1379": "占领者", + "1380": "占领者", + "1386": "孢裂变种", + "1387": "通信阵列", + "1395": "终结族遏制体系+", + "1400": "超级地球武装部队重兵驻守", + "1401": "超级地球武装部队重兵驻守", + "1402": "窃票者", + "1403": "窃票者", + "1406": "寂域边界", + "1407": "寂域通路", + "1412": "异常地点", + "1413": "入侵舰队", + "1414": "入侵舰队" + }, + "planet": { + "ACAMAR IV": "天园六IV", + "ACHERNAR SECUNDUS": "水委一次星", + "ACHIRD III": "王良三III", + "ACRAB XI": "房宿四XI", + "ACRUX IX": "十字架二IX", + "ACTIVE PLANETS": "ACTIVE PLANETS", + "ACUBENS PRIME": "柳宿增三主星", + "ADHARA": "弧矢七", + "AERIS PASS": "AERIS PASS", + "AESIR PASS": "亚萨关隘", + "AFOYAY BAY": "艾福亚湾", + "AIN-5": "毕宿一5", + "ALAIRT III": "艾列尔特III", + "ALAMAK VII": "天大将军一VII", + "ALARAPH": "右执法", + "ALATHFAR XI": "织女增三XI", + "ALDERIDGE COVE": "阿尔德里奇湾", + "ALTA V": "奥尔塔V", + "ANDAR": "安达尔", + "ANGEL'S VENTURE": "天使投资", + "ARKTURUS": "阿克图勒斯", + "ASPEROTH PRIME": "阿斯佩洛斯主星", + "ATRAMA": "阿特拉玛", + "AURORA BAY": "极光湾", + "AWAITING MAJOR ORDER": "等待重要指令", + "AZTERRA": "艾孜泰拉", + "AZUR SECUNDUS": "艾热尔次星", + "BALDRICK PRIME": "巴尔德里克主星", + "BARABOS": "巴勒博斯", + "BASHYR": "巴希尔", + "BASQUINE VIII": "巴斯金VIII", + "BEKVAM III": "贝克温III", + "BELLATRIX": "参宿五", + "BIG ROCK": "巨岩", + "BLISTICA": "布里斯提卡", + "BORE ROCK": "博尔岩", + "BOREA": "博瑞亚", + "BOTEIN": "天阴四", + "BRILLIANCE": "璨光", + "BRINK-2": "布林克2", + "BUNDA SECUNDUS": "天垒城一次星", + "CALYPSO": "卡利普索", + "CANOPUS": "老人", + "CAPH": "王良一", + "CARAMOOR": "开勒莫尔", + "CASTOR": "北河二", + "CERBERUS IIIC": "刻耳柏洛斯IIIc", + "CHARBAL-VII": "查巴尔VII", + "CHARON PRIME": "卡戎主星", + "CHOEPESSA IV": "科埃佩萨IV", + "CHOOHE": "丘伊", + "CHORT BAY": "雀特湾", + "CIRRUS": "希勒斯", + "CLAORELL": "可洛尔", + "CLASA": "克拉萨", + "CRIMSICA": "克里姆西卡", + "CRUCIBLE": "熔炉", + "CURIA": "居里亚", + "CYBERSTAN": "生化斯坦", + "DARIUS II": "大流士II", + "DARROWSPORT": "达罗斯波特", + "DEFEND": "保卫", + "DEMIURG": "戴米尔基", + "DENEB SECUNDUS": "天津四次星", + "DIASPORA X": "大流散X", + "DILUVIA": "迪卢维亚", + "DILVUIA": "DILVUIA", + "DOLPH": "多尔夫", + "DRAUPNIR": "德罗普尼尔", + "DUMA TYR": "杜马提尔", + "DURGEN": "德尔根", + "Defended Planets": "保卫行星", + "EAST IRIDIUM TRADING BAY": "东铱贸易湾", + "EFFLUVIA": "艾芙鲁维亚", + "ELECTRA BAY": "昴宿一湾", + "ELYSIAN MEADOWS": "埃律西昂草原", + "EMERIA": "埃梅里亚", + "EMORATH": "艾莫拉斯", + "ENULIALE": "安努力亚", + "EPSILON PHOENCIS VI": "艾普斯林芬赛斯VI", + "ERATA PRIME": "艾拉特主星", + "ERRATA PRIME": "ERRATA PRIME", + "ERSON SANDS": "厄尔森桑兹", + "ESKER": "艾斯克尔", + "ESTANU": "伊斯塔努", + "EUKORIA": "欧科里亚", + "EUPHORIA III": "欧福利亚III", + "FENMIRE": "范迈尔", + "FENRIR III": "芬里尔III", + "FORI PRIME": "佛里主星", + "FORNSKOGUR II": "福恩斯科古尔II", + "FORT JUSTICE": "正义堡", + "FORT SANCTUARY": "庇护堡", + "FORT UNION": "联合堡", + "FREEDOM PEAK": "弗里敦峰", + "FRONTERIA": "边陲", + "FURY": "费里", + "GACRUX": "十字架一", + "GAELLIVARE": "耶利瓦勒", + "GAR HAREN": "轧尔哈伦", + "GATRIA": "盖尔崔亚", + "GEMMA": "贯索四", + "GEMSTONE BLUFFS": "宝石崖", + "GENESIS PRIME": "创世主星", + "GRAFMERE": "格拉夫米尔", + "GRAND ERRANT": "大艾伦特", + "GUNVALD": "古恩瓦尔德", + "Galaxy Stats": "星系状况", + "HADAR": "马腹一", + "HADR": "HADR", + "HAKA": "哈卡", + "HALDUS": "海德斯", + "HALIES PORT": "海利斯港", + "HEETH": "希斯", + "HELLMIRE": "海尔迈尔", + "HERTHON SECUNDUS": "赫尔松次星", + "HESOE PRIME": "海索主星", + "HEZE BAY": "角宿二湾", + "HORT": "哈尔特", + "HYDROBIUS": "哈卓毕亚斯", + "HYDROFALL PRIME": "水瀑主星", + "IGLA": "伊格勒", + "ILDUNA PRIME": "伊尔都纳主星", + "IMBER": "因博尔", + "INARI": "伊纳里", + "INGMAR": "英格玛", + "IRIDICA": "艾丽迪卡", + "IRO": "伊罗", + "IRULTA": "艾鲁尔塔", + "IVIS": "艾维斯", + "JULHEIM": "尤尔海姆", + "K": "K", + "KARLIA": "可利亚", + "KEID": "九州殊口增七", + "KELVINOR": "开尔文奥尔", + "KERTH SECUNDUS": "克斯次星", + "KHANDARK": "勘达尔克", + "KHARST": "喀斯特", + "KIRRIK": "基里克", + "KLAKA 5": "克拉卡5", + "KLEN DAHTH II": "克伦达斯II", + "KNETH PORT": "克奈斯港", + "KRAKABOS": "克拉克博斯", + "KRAKATWO": "克拉克图", + "KRAZ": "轸宿四", + "KUMA": "天棓二", + "KUPER": "库珀", + "LASTOFE": "赖斯斗夫", + "LENG SCUNDUS": "LENG SCUNDUS", + "LENG SECUNDUS": "蓝恩次星", + "LESATH": "尾宿八", + "LIBERTY RIDGE": "解放岭", + "LUXURIANT": "富源", + "MAIA": "昴宿四", + "MAJOR ORDER": "重要指令", + "MALEVELON CREEK": "麦拉芬蒙河", + "MANTES": "蒙特斯", + "MARFARK": "玛尔法克", + "MARRE IV": "马尔IV", + "MARTALE": "玛尔特", + "MARTYR'S BAY": "烈士湾", + "MASTIA": "玛斯蒂亚", + "MATAR BAY": "玛塔", + "MAW": "深渊", + "MEDALS": "MEDALS", + "MEISSA": "觜宿一", + "MEKBUDA": "井宿七", + "MENKENT": "库楼三", + "MERAK": "北斗二", + "MERGA IV": "玄戈增二IV", + "MERIDIA": "默里迪亚", + "MIDASBURG": "弥达斯堡", + "MINCHIR": "敏切尔", + "MINTORIA": "敏托瑞亚", + "MOG": "莫格", + "MORADESH": "莫拉戴什", + "MORDIA 9": "摩帝亚9", + "MORIDA 9": "MORIDA 9", + "MORT": "莫特", + "MORTAX PRIME": "摩尔塔克斯主星", + "MOX": "莫克斯", + "MYRADESH": "米拉戴什", + "MYRIUM": "梅里翁", + "Major Order ends in:": "最高指令结束:", + "NABATEA SECUNDUS": "那贝塔次星", + "NAVI VII": "阁道二", + "NEW HAVEN": "纽黑文", + "NEW INSIGHT": "新悟", + "NEW KIRUNA": "新基鲁纳", + "NEW STOCKHOLM": "新斯德哥尔摩", + "NIVEL 43": "尼维尔43", + "NUBLARIA I": "努布拉里亚I", + "OASIS": "绿洲", + "OBARI": "欧巴里", + "OKUL VI": "欧库VI", + "OMICRON": "奥密克戎", + "OSHAUNE": "欧绍恩", + "OSLO STATION": "奥斯陆站", + "OSUPSAM": "欧苏普森", + "OUTPOST 32": "32号哨站", + "OVERGOE PRIME": "欧维果主星", + "PANDION-XXIV": "帕狄恩XXIV", + "PARSH": "帕尔什", + "PARTION": "帕尔晨", + "PATHFINDER V": "开拓者V", + "PEACOCK": "孔雀十一", + "PENTA": "彭塔", + "PHACT BAY": "丈人一湾", + "PHERKAD SECUNDUS": "北极一次星", + "PILEN V": "皮伦V", + "PIONEER II": "先驱II", + "POLARIS PRIME": "北极星主星", + "POLLUX 31": "北河三31", + "PRASA": "普拉萨", + "PRIMORDIA": "普莱默迪亚", + "PROPUS": "五诸侯三", + "PROSPERITY FALLS": "繁荣瀑布", + "PROVIDENCE": "普罗维登斯", + "PÖPLI IX": "珀普利IX", + "RAS ALGETHI": "帝座", + "RASP": "拉斯普", + "RATCH": "拉奇", + "RD-4": "RD4", + "REAF": "利夫", + "REGNUS": "雷格努斯", + "RIRGA BAY": "里尔加湾", + "ROGUE 5": "罗格5", + "SANGIS": "赤血", + "SEASSE": "西斯", + "SENGE 23": "新戈23", + "SETIA": "赛提亚", + "SEYSHEL BEACH": "塞舌尔海滩", + "SHALLUS": "沙勒斯", + "SHELT": "谢尔特", + "SHETE": "赛特", + "SIEMNOT": "席姆纳特", + "SIRIUS": "天狼星", + "SKAASH": "斯卡什", + "SKAT BAY": "斯卡特湾", + "SKITTER": "斯基特", + "SLIF": "斯利夫", + "SOCORRO III": "索科罗III", + "SOLGHAST": "索尔加斯特", + "SPHERION": "斯飞利昂", + "STOR THA PRIME": "斯特萨主星", + "STOUT": "斯图尔特", + "SULFURA": "萨尔弗拉", + "SUPER EARTH": "超级地球", + "Stand by for further orders from Super Earth High Command": "等待超级地球最高指挥部的进一步指令", + "TARSH": "塔尔什", + "TERMADON": "特尔玛登", + "TERREK": "泰雷克", + "THE WEIR": "维尔", + "TIBIT": "提比特", + "TIEN KWAN": "天关", + "TOTAL PLAYERS:": "参战潜兵:", + "TRANDOR": "特兰道尔", + "TROOST": "特鲁斯特", + "TURING": "图灵", + "UBANEA": "乌巴尼亚", + "URSICA XI": "厄西卡XI", + "USTOTU": "伍斯特图", + "UVP ALPHA": "UVP阿尔法", + "UVP BETA": "UVP贝塔", + "UVP DELTA": "UVP德尔塔", + "UVP GAMMA": "UVP伽马", + "VALGAARD": "瓦尔加德", + "VALMOX": "瓦尔莫克斯", + "VANDALON IV": "万达隆IV", + "VARYLIA 5": "瓦瑞拉亚5", + "VEGA BAY": "织女一湾", + "VEIL": "帷幕", + "VELD": "维尔德", + "VERNEN WELLS": "佛农井", + "VINDEMITARIX PRIME": "文德米塔里克斯主星", + "VIRIDIA PRIME": "维尔伊迪亚主星", + "VOG-SOJOTH": "佛戈索约斯", + "VOLTERRA": "沃尔泰拉", + "WASAT": "天樽二", + "WAYWARD": "逸泊", + "WEZEN": "弧矢一", + "WIDOW'S HARBOR": "寡妇港", + "WILFORD STATION": "威尔福德站", + "WRAITH": "幽灵", + "X-45": "X45", + "YED PRIOR": "天市右垣九", + "ZAGON PRIME": "扎贡主星", + "ZEA RUGOSIA": "泽亚鲁戈西亚", + "ZEFIA": "赛飞亚", + "ZEGEMA PARADISE": "泽格马乐土", + "ZOSMA": "太微右垣五", + "ZYGOS": "齐戈斯", + "ZZANIAH PRIME": "藏尼亚主星" + }, + "campaign_type": { + "0": "解放战役", + "1": "侦察战役", + "2": "Story", + "3": "Conquest", + "4": "防御战", + "5": "Deployment" + } +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/planetEffects.json b/hexi/plugins/nonebot_plugin_helldivers_tools/data/planetEffects.json new file mode 100644 index 0000000..3b17a6c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/data/planetEffects.json @@ -0,0 +1,782 @@ +{ + "1127": { + "galacticEffectId": 1127, + "name": "ARSENAL AUGMENTATION: EAGLE 500KG BOMB", + "description": "High Command has authorized the temporary addition of the Eagle 500kg Bomb Stratagem to all Helldiver loadouts." + }, + "1128": { + "galacticEffectId": 1128, + "name": "ARSENAL AUGMENTATION: EAGLE 500KG BOMB", + "description": "High Command has authorized the temporary addition of the Eagle 500kg Bomb Stratagem to all Helldiver loadouts." + }, + "1129": { + "galacticEffectId": 1129, + "name": "ARSENAL AUGMENTATION: SH-32 SHIELD GENERATOR PACK", + "description": "High Command has authorized the temporary addition of the SH-32 Shield Generator Pack Stratagem to all Helldiver loadouts." + }, + "1130": { + "galacticEffectId": 1130, + "name": "ARSENAL AUGMENTATION: A/ARC-3 TESLA TOWER", + "description": "High Command has authorized the temporary addition of the A/ARC-3 Tesla Tower Stratagem to all Helldiver loadouts." + }, + "1133": { + "galacticEffectId": 1133, + "name": "ARSENAL AUGMENTATION: A/M-12 MORTAR SENTRY", + "description": "High Command has authorized the temporary addition of the A/M-12 Mortar Sentry Stratagem to all Helldiver loadouts." + }, + "1137": { + "galacticEffectId": 1137, + "name": "ARSENAL AUGMENTATION: RS-422 RAILGUN", + "description": "High Command has authorized the temporary addition of the RS-422 Railgun Stratagem to all Helldiver loadouts." + }, + "1139": { + "galacticEffectId": 1139, + "name": "ARSENAL AUGMENTATION: EAGLE NAPALM AIRSTRIKE", + "description": "High Command has authorized the temporary addition of the Eagle Napalm Airstrike Stratagem to all Helldiver loadouts." + }, + "1142": { + "galacticEffectId": 1142, + "name": "ARSENAL AUGMENTATION: EAGLE 500KG BOMB", + "description": "High Command has authorized the temporary addition of the Eagle 500kg Bomb Stratagem to all Helldiver loadouts." + }, + "1143": { + "galacticEffectId": 1143, + "name": "ARSENAL AUGMENTATION: MG-43 MACHINE GUN", + "description": "High Command has authorized the temporary addition of the MG-43 Machine Gun Stratagem to all Helldiver loadouts." + }, + "1145": { + "galacticEffectId": 1145, + "name": "ARSENAL AUGMENTATION: ORBITAL LASER", + "description": "High Command has authorized the temporary addition of the Orbital Laser Stratagem to all Helldiver loadouts." + }, + "1147": { + "galacticEffectId": 1147, + "name": "ARSENAL AUGMENTATION: ORBITAL EMS STRIKE", + "description": "High Command has authorized the temporary addition of the Orbital EMS Strike Stratagem to all Helldiver loadouts." + }, + "1148": { + "galacticEffectId": 1148, + "name": "ARSENAL AUGMENTATION: EXO-45 PATRIOT EXOSUIT", + "description": "High Command has authorized the temporary addition of the EXO-45 Patriot Exosuit Stratagem to all Helldiver loadouts." + }, + "1149": { + "galacticEffectId": 1149, + "name": "ARSENAL AUGMENTATION: LIFT-850 JUMP PACK", + "description": "High Command has authorized the temporary addition of the LIFT-850 Jump Pack Stratagem to all Helldiver loadouts." + }, + "1150": { + "galacticEffectId": 1150, + "name": "ARSENAL AUGMENTATION: B-1 SUPPLY PACK", + "description": "High Command has authorized the temporary addition of the B-1 Supply Pack Stratagem to all Helldiver loadouts." + }, + "1152": { + "galacticEffectId": 1152, + "name": "ARSENAL AUGMENTATION: APW-1 ANTI-MATERIEL RIFLE", + "description": "High Command has authorized the temporary addition of the APW-1 Anti-Materiel Rifle Stratagem to all Helldiver loadouts." + }, + "1153": { + "galacticEffectId": 1153, + "name": "ARSENAL AUGMENTATION: RS-422 RAILGUN", + "description": "High Command has authorized the temporary addition of the RS-422 Railgun Stratagem to all Helldiver loadouts." + }, + "1154": { + "galacticEffectId": 1154, + "name": "ARSENAL AUGMENTATION: ORBITAL RAILCANNON STRIKE", + "description": "High Command has authorized the temporary addition of the Orbital Railcannon Strike Stratagem to all Helldiver loadouts." + }, + "1155": { + "galacticEffectId": 1155, + "name": "ARSENAL AUGMENTATION: AC-8 AUTOCANNON", + "description": "High Command has authorized the temporary addition of the AC-8 Autocannon Stratagem to all Helldiver loadouts." + }, + "1156": { + "galacticEffectId": 1156, + "name": "ARSENAL AUGMENTATION: EAGLE 110MM ROCKET PODS", + "description": "High Command has authorized the temporary addition of the Eagle 110mm Rocket Pods Stratagem to all Helldiver loadouts." + }, + "1160": { + "galacticEffectId": 1160, + "name": "ARSENAL AUGMENTATION: ORBITAL EMS STRIKE", + "description": "High Command has authorized the temporary addition of the Orbital EMS Strike Stratagem to all Helldiver loadouts." + }, + "1161": { + "galacticEffectId": 1161, + "name": "ARSENAL AUGMENTATION: EAGLE NAPALM AIRSTRIKE", + "description": "High Command has authorized the temporary addition of the Eagle Napalm Airstrike Stratagem to all Helldiver loadouts." + }, + "1162": { + "galacticEffectId": 1162, + "name": "ARSENAL AUGMENTATION: EXO-45 PATRIOT EXOSUIT", + "description": "High Command has authorized the temporary addition of the EXO-45 Patriot Exosuit Stratagem to all Helldiver loadouts." + }, + "1163": { + "galacticEffectId": 1163, + "name": "ARSENAL AUGMENTATION: EAGLE 110MM ROCKET PODS", + "description": "High Command has authorized the temporary addition of the Eagle 110mm Rocket Pods Stratagem to all Helldiver loadouts." + }, + "1165": { + "galacticEffectId": 1165, + "name": "ARSENAL AUGMENTATION: LIFT-850 JUMP PACK", + "description": "High Command has authorized the temporary addition of the LIFT-850 Jump Pack Stratagem to all Helldiver loadouts." + }, + "1166": { + "galacticEffectId": 1166, + "name": "ARSENAL AUGMENTATION: EAGLE 500KG BOMB", + "description": "High Command has authorized the temporary addition of the Eagle 500kg Bomb Stratagem to all Helldiver loadouts." + }, + "1167": { + "galacticEffectId": 1167, + "name": "ARSENAL AUGMENTATION: FLAM-40 FLAMETHROWER", + "description": "High Command has authorized the temporary addition of the FLAM-40 Flamethrower Stratagem to all Helldiver loadouts." + }, + "1168": { + "galacticEffectId": 1168, + "name": "ARSENAL AUGMENTATION: LAS-98 LASER CANNON", + "description": "High Command has authorized the temporary addition of the LAS-98 Laser Cannon Stratagem to all Helldiver loadouts." + }, + "1169": { + "galacticEffectId": 1169, + "name": "ARSENAL AUGMENTATION: EAT-17 EXPENDABLE ANTI-TANK", + "description": "High Command has authorized the temporary addition of the EAT-17 Expendable Anti-Tank Stratagem to all Helldiver loadouts." + }, + "1170": { + "galacticEffectId": 1170, + "name": "ARSENAL AUGMENTATION: RL-77 AIRBURST ROCKET LAUNCHER", + "description": "High Command has authorized the temporary addition of the RL-77 Airburst Rocket Launcher Stratagem to all Helldiver loadouts." + }, + "1171": { + "galacticEffectId": 1171, + "name": "ARSENAL AUGMENTATION: MD-17 ANTI-TANK MINES", + "description": "High Command has authorized the temporary addition of the MD-17 Anti-Tank Mines Stratagem to all Helldiver loadouts." + }, + "1172": { + "galacticEffectId": 1172, + "name": "ARSENAL AUGMENTATION: ORBITAL GAS STRIKE", + "description": "High Command has authorized the temporary addition of the Orbital Gas Strike Stratagem to all Helldiver loadouts." + }, + "1173": { + "galacticEffectId": 1173, + "name": "ARSENAL AUGMENTATION: EXO-49 EMANCIPATOR EXOSUIT", + "description": "High Command has authorized the temporary addition of the EXO-49 Emancipator Exosuit Stratagem to all Helldiver loadouts." + }, + "1174": { + "galacticEffectId": 1174, + "name": "ARSENAL AUGMENTATION: A/M-12 MORTAR SENTRY", + "description": "High Command has authorized the temporary addition of the A/M-12 Mortar Sentry Stratagem to all Helldiver loadouts." + }, + "1175": { + "galacticEffectId": 1175, + "name": "ARSENAL AUGMENTATION: A/G-16 GATLING SENTRY", + "description": "High Command has authorized the temporary addition of the A/G-16 Gatling Sentry Stratagem to all Helldiver loadouts." + }, + "1177": { + "galacticEffectId": 1177, + "name": "Black Hole", + "description": "This planet has been turned into a black hole." + }, + "1179": { + "galacticEffectId": 1179, + "name": "ARSENAL AUGMENTATION: AC-8 AUTOCANNON", + "description": "High Command has authorized the temporary addition of the AC-8 Autocannon Stratagem to all Helldiver loadouts." + }, + "1181": { + "galacticEffectId": 1181, + "name": "ARSENAL AUGMENTATION: MLS-4X COMMANDO", + "description": "High Command has authorized the temporary addition of the MLS-4X Commando Stratagem to all Helldiver loadouts." + }, + "1184": { + "galacticEffectId": 1184, + "name": "ARSENAL AUGMENTATION: MD-I4 INCENDIARY MINES", + "description": "High Command has authorized the temporary addition of the MD-I4 Incendiary Mines Stratagem to all Helldiver loadouts." + }, + "1185": { + "galacticEffectId": 1185, + "name": "ARSENAL AUGMENTATION: MD-6 ANTI-PERSONNEL MINEFIELD", + "description": "High Command has authorized the temporary addition of the MD-6 Anti-Personnel Minefield Stratagem to all Helldiver loadouts." + }, + "1186": { + "galacticEffectId": 1186, + "name": "Light Gloom", + "description": "This world is lightly obscured by a gloom cloud." + }, + "1187": { + "galacticEffectId": 1187, + "name": "Gloom", + "description": "A gloom cloud enveloped this world." + }, + "1188": { + "galacticEffectId": 1188, + "name": "Dense Gloom", + "description": "A thick gloom cloud obscures this world from view." + }, + "1190": { + "galacticEffectId": 1190, + "name": "Unreachable", + "description": "Our sensors can no longer monitor this planet." + }, + "1193": { + "galacticEffectId": 1193, + "name": "Gloom Border", + "description": "This world is on the border of the interstellar wall of gloom." + }, + "1194": { + "galacticEffectId": 1194, + "name": "ARSENAL AUGMENTATION: ORBITAL NAPALM BARRAGE", + "description": "High Command has authorized the temporary addition of the Orbital Napalm Barrage Stratagem to all Helldiver loadouts." + }, + "1195": { + "galacticEffectId": 1195, + "name": "DSS Construction Site- Phase 1", + "description": "Construction has began on the Democracy Space Station. The local populace is honored to host thousands of construction crews for this historic event." + }, + "1196": { + "galacticEffectId": 1196, + "name": "DSS Logistics Hub", + "description": "Parts for the Democracy Space Station are prefabricated all over the Galaxy, then shipped here to await assembly." + }, + "1197": { + "galacticEffectId": 1197, + "name": "Xenoentomology Center", + "description": "Those who study Terminid behavior, ecology and E-710 potential gather here for cross-disciplinary research." + }, + "1198": { + "galacticEffectId": 1198, + "name": "Deep Mantle Forge Complex", + "description": "The smelters and refineries on this planet turn crude materials into usable hardware." + }, + "1199": { + "galacticEffectId": 1199, + "name": "DSS Construction Site- Phase 2", + "description": "Democracy Space Station construction is well underway. The local economy is flourishing as the planet's populace has centupled, and all the Galaxy can feel their democratic fervor." + }, + "1200": { + "galacticEffectId": 1200, + "name": "ARSENAL AUGMENTATION: A/ARC-3 TESLA TOWER", + "description": "High Command has authorized the temporary addition of the A/ARC-3 Tesla Tower Stratagem to all Helldiver loadouts." + }, + "1202": { + "galacticEffectId": 1202, + "name": "THE JET BRIGADE (Enemies)", + "description": "The Automatons have deployed a new series of specialized models on this planet. These upgraded bots utilize stolen Jump Pack technology, heartlessly pillaged from the bodies of fallen Helldivers and reverse-engineered into something nearly unrecognizeable." + }, + "1203": { + "galacticEffectId": 1203, + "name": "THE JET BRIGADE", + "description": "The Automatons have deployed a new series of specialized models on this planet. These upgraded bots utilize stolen Jump Pack technology, heartlessly pillaged from the bodies of fallen Helldivers and reverse-engineered into something nearly unrecognizeable." + }, + "1204": { + "galacticEffectId": 1204, + "name": "LIBERTY DAY", + "description": "This planet is celebrating Liberty Day." + }, + "1205": { + "galacticEffectId": 1205, + "name": "DSS CONSTRUCTION SITE - PHASE 3", + "description": "Construction of the Democracy Space Station is nearing completion. This project, which has employed millions, will soon take its place among the greatest achievements of Democracy." + }, + "1206": { + "galacticEffectId": 1206, + "name": "TERMINID RESEARCH PRESERVE", + "description": "Terminids are held safely within massive compounts on this planet for study and E-710 extraction." + }, + "1207": { + "galacticEffectId": 1207, + "name": "ARSENAL AUGMENTATION: E/MG-101 HMG EMPLACEMENT", + "description": "High Command has authorized the temporary addition of the E/MG-101 HMG Emplacement Stratagem to all Helldiver loadouts." + }, + "1209": { + "galacticEffectId": 1209, + "name": "EAGLE STORM", + "description": "The DSS deploys Eagle Strafing Runs during missions." + }, + "1210": { + "galacticEffectId": 1210, + "name": "ORBITAL BLOCKADE", + "description": "Hellpod Space Optimization Booster is automatically active for all missions." + }, + "1211": { + "galacticEffectId": 1211, + "name": "PLANETARY BOMBARDMENT", + "description": "The DSS fires nonstop orbital bombardments from its suite of 77 PRESIDENTIAL-Class Cannons, providing planetwide artillery support and accelerating liberation efforts. Temporarily, also increases Reinforcement Budget by +1 per squad member and augments all loadouts with FX-12 Shield Generator Relay Stratagem." + }, + "1212": { + "galacticEffectId": 1212, + "name": "EAGLE STORM (Marker)", + "description": "Map marker for the Eagle Storm effect." + }, + "1213": { + "galacticEffectId": 1213, + "name": "ORBITAL BLOCKADE (Marker)", + "description": "Map marker for the Orbital Blockade effect." + }, + "1214": { + "galacticEffectId": 1214, + "name": "BOMBARDMENT LIBERATION BOOST", + "description": "Progress in Liberation Campaigns is accelerated by 150%." + }, + "1215": { + "galacticEffectId": 1215, + "name": "ORBITAL BLOCKADE", + "description": "Defense Campaigns cannot originate from this planet." + }, + "1216": { + "galacticEffectId": 1216, + "name": "EAGLE STORM", + "description": "Enemy progress in Defense Campaigns is slowed." + }, + "1217": { + "galacticEffectId": 1217, + "name": "DEMOCRACY SPACE STATION", + "description": "A Helldiver-operated weapon of mass liberation. Paid for with the blood of soldiers and the credits of taxpayers, this technological marvel is Democracy made manifest." + }, + "1222": { + "galacticEffectId": 1222, + "name": "Regen Override", + "description": "Regen Rate is set to a fixed 10000 per hour." + }, + "1226": { + "galacticEffectId": 1226, + "name": "ARSENAL AUGMENTATION: FAF-14 SPEAR", + "description": "High Command has authorized the temporary addition of the FAF-14 Spear Stratagem to all Helldiver loadouts." + }, + "1227": { + "galacticEffectId": 1227, + "name": "ARSENAL AUGMENTATION: MG-43 MACHINE GUN", + "description": "High Command has authorized the temporary addition of the MG-43 Machine Gun Stratagem to all Helldiver loadouts." + }, + "1228": { + "galacticEffectId": 1228, + "name": "MERIDIAN BLACK HOLE (old map marker)", + "description": "The prosperous Meridia was corrupted into a Terminid Supercolony, necessitating its destruction using the mysterious Dark Fluid. This galactic scar is all that remains." + }, + "1229": { + "galacticEffectId": 1229, + "name": "MERIDIAN BLACK HOLE", + "description": "The prosperous Meridia was corrupted into a Terminid Supercolony, necessitating its destruction using the mysterious Dark Fluid. This galactic scar is all that remains." + }, + "1230": { + "galacticEffectId": 1230, + "name": "MERIDIAN BLACK HOLE", + "description": "The prosperous Meridia was corrupted into a Terminid Supercolony, necessitating its destruction using the mysterious Dark Fluid. This galactic scar is all that remains. Advisory: volatile spacetime fluctuations currently prohibit FTL travel to the Meridian Black Hole." + }, + "1231": { + "galacticEffectId": 1231, + "name": "ARSENAL AUGMENTATION: MD-8 GAS MINES", + "description": "High Command has authorized the temporary addition of the MD-8 Gas Mines Stratagem to all Helldiver loadouts." + }, + "1232": { + "galacticEffectId": 1232, + "name": "FACTORY HUB", + "description": "The hard workers on this planet produce goods vital to the war effort, as well as to the prosperity of Super Earth." + }, + "1233": { + "galacticEffectId": 1233, + "name": "ARSENAL AUGMENTATION: STA-X3 W.A.S.P. LAUNCHER", + "description": "High Command has authorized the temporary addition of the StA-X3 W.A.S.P. Launcher Stratagem to all Helldiver loadouts." + }, + "1234": { + "galacticEffectId": 1234, + "name": "CENTER OF SCIENCE", + "description": "On this planet, the Ministry of Science's best and brightest work on their next breakthrough." + }, + "1235": { + "galacticEffectId": 1235, + "name": "ARSENAL AUGMENTATION: MD-17 ANTI-TANK MINES", + "description": "High Command has authorized the temporary addition of the MD-17 Anti-Tank Mines Stratagem to all Helldiver loadouts." + }, + "1236": { + "galacticEffectId": 1236, + "name": "CENTER FOR CIVILIAN SURVEILLANCE AND SAFETY", + "description": "The Ministry of Truth analyzes citizens' activity, speech, data, DNA, RNA, and neural topology here." + }, + "1237": { + "galacticEffectId": 1237, + "name": "ARSENAL AUGMENTATION: ORBITAL 380MM HE BARRAGE", + "description": "High Command has authorized the temporary addition of the Orbital 380mm HE Barrage Stratagem to all Helldiver loadouts." + }, + "1238": { + "galacticEffectId": 1238, + "name": "OPERATIONAL SUPPORT", + "description": "The presence of the DSS near this planet provides a slight boost to Liberation Campaign progress." + }, + "1239": { + "galacticEffectId": 1239, + "name": "JET BRIGADE FACTORIES", + "description": "Vertically enhanced Jet Brigade soldiers are produced here." + }, + "1240": { + "galacticEffectId": 1240, + "name": "VERGE OF DESTRUCTION", + "description": "This planet is under threat of destruction." + }, + "1241": { + "galacticEffectId": 1241, + "name": "FRACTURED PLANET", + "description": "All that remains of a planet torn apart by the Meridian singularity. A solemn reminder of the desolation Tyranny leaves in its wake." + }, + "1242": { + "galacticEffectId": 1242, + "name": "MOVING PLANET", + "description": "This planet is moving and is estimated to impact Super Earth." + }, + "1243": { + "galacticEffectId": 1243, + "name": "PREDATOR STRAIN (Enemies)", + "description": "A Gloom-enhanced strain of Terminids has been reported on this planet. SEAF patrols have been lured into ambushes, and picked off by unseen assailants. Every ounce of a Helldiver's superior senses will be required to hunt down this dangerous threat." + }, + "1244": { + "galacticEffectId": 1244, + "name": "Spore Burst Strain (Enemies)", + "description": "A Gloom-enhanced strain of Terminids has been reported on this planet. They can explode into spores." + }, + "1245": { + "galacticEffectId": 1245, + "name": "PREDATOR STRAIN", + "description": "A Gloom-enhanced strain of Terminids has been reported on this planet. SEAF patrols have been lured into ambushes, and picked off by unseen assailants. Every ounce of a Helldiver's superior senses will be required to hunt down this dangerous threat." + }, + "1246": { + "galacticEffectId": 1246, + "name": "CAMPAIGN BLOCKER", + "description": "Campaigns cannot be launched." + }, + "1247": { + "galacticEffectId": 1247, + "name": "ARSENAL AUGMENTATION: MD-8 GAS MINES", + "description": "High Command has authorized the temporary addition of the MD-8 Gas Mines Stratagem to all Helldiver loadouts." + }, + "1248": { + "galacticEffectId": 1248, + "name": "THE INCINERATION CORPS (Enemies)", + "description": "An Automaton unit equipped with flame throwers and incendiary ammunition is active on this planet. These wanton arsonists will not rest until they have razed all that humankind holds dear." + }, + "1249": { + "galacticEffectId": 1249, + "name": "THE INCINERATION CORPS", + "description": "An Automaton unit equipped with flame throwers and incendiary ammunition is active on this planet. These wanton arsonists will not rest until they have razed all that humankind holds dear." + }, + "1252": { + "galacticEffectId": 1252, + "name": "FRACTURED PLANET", + "description": "All that remains of a planet torn apart by the Meridian singularity. A solemn reminder of the desolation Tyranny leaves in its wake." + }, + "1254": { + "galacticEffectId": 1254, + "name": "ARSENAL AUGMENTATION: MG-206 HEAVY MACHINE GUN", + "description": "High Command has authorized the temporary addition of the MG-206 Heavy Machine Gun Stratagem to all Helldiver loadouts." + }, + "1256": { + "galacticEffectId": 1256, + "name": "ARSENAL AUGMENTATION: E/GL-21 GRENADIER BATTLEMENT", + "description": "High Command has authorized the temporary addition of the E/GL-21 Grenadier Battlement Stratagem to all Helldiver loadouts." + }, + "1261": { + "galacticEffectId": 1261, + "name": "EXOSUIT RESERVES", + "description": "The presence of the DSS near this planet provides a -35% cooldown reduction to the EXO-45 Patriot Exosuit stratagem." + }, + "1262": { + "galacticEffectId": 1262, + "name": "EXOSUIT RESERVES", + "description": "The presence of the DSS near this planet provides a -35% cooldown reduction to the EXO-49 Emancipator Exosuit stratagem." + }, + "1263": { + "galacticEffectId": 1263, + "name": "ARSENAL AUGMENTATION: M-105 STALWART", + "description": "High Command has authorized the temporary addition of the M-105 Stalwart Stratagem to all Helldiver loadouts." + }, + "1267": { + "galacticEffectId": 1267, + "name": "ARSENAL AUGMENTATION: ORBITAL GAS STRIKE", + "description": "High Command has authorized the temporary addition of the Orbital Gas Strike Stratagem to all Helldiver loadouts." + }, + "1268": { + "galacticEffectId": 1268, + "name": "NEGATIVE ENERGY LABORATORY", + "description": "Scientists without fear of implosion or spaghettification study negative energy here." + }, + "1269": { + "galacticEffectId": 1269, + "name": "The Great Host", + "description": "The Illuminate invasion fleet, constructed in secret behind the veil of the Meridian Wormhole. It is headed for Super Earth itself." + }, + "1274": { + "galacticEffectId": 1274, + "name": "ARSENAL AUGMENTATION: M-105 STALWART", + "description": "High Command has authorized the temporary addition of the M-105 Stalwart Stratagem to all Helldiver loadouts." + }, + "1276": { + "galacticEffectId": 1276, + "name": "ARSENAL AUGMENTATION: FX-12 SHIELD GENERATOR RELAY", + "description": "High Command has authorized the temporary addition of the FX-12 Shield Generator Relay Stratagem to all Helldiver loadouts." + }, + "1277": { + "galacticEffectId": 1277, + "name": "ARSENAL AUGMENTATION: ORBITAL NAPALM BARRAGE", + "description": "High Command has authorized the temporary addition of the Orbital Napalm Barrage Stratagem to all Helldiver loadouts." + }, + "1279": { + "galacticEffectId": 1279, + "name": "ARSENAL AUGMENTATION: M-102 FAST RECONNAISSANCE VEHICLE", + "description": "High Command has authorized the temporary addition of the M-102 Fast Reconnaissance Vehicle Stratagem to all Helldiver loadouts." + }, + "1280": { + "galacticEffectId": 1280, + "name": "ARSENAL AUGMENTATION: ORBITAL SMOKE STRIKE", + "description": "High Command has authorized the temporary addition of the Orbital Smoke Strike Stratagem to all Helldiver loadouts." + }, + "1281": { + "galacticEffectId": 1281, + "name": "ARSENAL AUGMENTATION: EAGLE SMOKE STRIKE", + "description": "High Command has authorized the temporary addition of the Eagle Smoke Strike Stratagem to all Helldiver loadouts." + }, + "1282": { + "galacticEffectId": 1282, + "name": "HELLDIVER TRAINING FACILITIES", + "description": "Here, the best of the best go through the rigorous Helldiver training that will earn them their capes." + }, + "1283": { + "galacticEffectId": 1283, + "name": "FACTORY STRIDER SURGE", + "description": "Significantly higher Factory Strider numbers have been observed on this planet." + }, + "1284": { + "galacticEffectId": 1284, + "name": "ARSENAL AUGMENTATION: GR-8 RECOILLESS RIFLE", + "description": "High Command has authorized the temporary addition of the GR-8 Recoilless Rifle Stratagem to all Helldiver loadouts." + }, + "1285": { + "galacticEffectId": 1285, + "name": "IMPALER RAMPAGE", + "description": "Significantly higher Impaler numbers have been observed on this planet." + }, + "1286": { + "galacticEffectId": 1286, + "name": "NEW HOPE CONSTRUCTION SITE", + "description": "One of 3 Maximum Security Cities is under construction here." + }, + "1287": { + "galacticEffectId": 1287, + "name": "NEW HOPE CITY", + "description": "The flagship Maximum Security City. Impregnable to Tyranny; the future of the Federation." + }, + "1288": { + "galacticEffectId": 1288, + "name": "SPORE BURST SCAVENGER RAMPAGE", + "description": "Significantly increased levels of Spore Burst Scavengers have been reported on this planet." + }, + "1291": { + "galacticEffectId": 1291, + "name": "NEW ASPIRATION CITY", + "description": "One of 3 Maximum Security Cities. Impregnable to Tyranny; the future of the Federation." + }, + "1292": { + "galacticEffectId": 1292, + "name": "NEW YEARNING CITY", + "description": "One of 3 Maximum Security Cities. Impregnable to Tyranny; the future of the Federation." + }, + "1293": { + "galacticEffectId": 1293, + "name": "CHARGER RAMPAGE", + "description": "Significantly increased levels of Chargers have been reported on this planet." + }, + "1295": { + "galacticEffectId": 1295, + "name": "TYRANNY PARK 2", + "description": "The extensive Terminid enclosures here allow scientists to study Terminid behavior, and civilians to take pictures with Brood Commanders." + }, + "1303": { + "galacticEffectId": 1303, + "name": "RUPTURE STRAIN (ENEMIES)", + "description": "A deadly strain of ground-bursting Terminids is present on this planet." + }, + "1304": { + "galacticEffectId": 1304, + "name": "OUTPOST ALPHA", + "description": "The first manned site established in Gloom-infested space." + }, + "1306": { + "galacticEffectId": 1306, + "name": "DRAGONROACHES (Enemies)", + "description": "Terminid Dragonroaches menace the skies of this planet." + }, + "1307": { + "galacticEffectId": 1307, + "name": "HIVE LORDS (Enemies)", + "description": "Terminid Hive Lords have been detected on this planet." + }, + "1308": { + "galacticEffectId": 1308, + "name": "HIVE LORDS", + "description": "Terminid Hive Lords have been detected on this planet." + }, + "1309": { + "galacticEffectId": 1309, + "name": "DRAGONROACHES", + "description": "Terminid Dragonroaches menace the skies of this planet." + }, + "1310": { + "galacticEffectId": 1310, + "name": "RUPTURE STRAIN", + "description": "A deadly strain of ground-bursting Terminids is present on this planet." + }, + "1311": { + "galacticEffectId": 1311, + "name": "HIVE WORLD", + "description": "This planet has been completely infested by the Terminids, transformed inside and out into a hive of Tyranny. It is a source of Gloom spores." + }, + "1324": { + "galacticEffectId": 1324, + "name": "ULTRAMAFIC MINE", + "description": "A mine extracting platinum from deep-seated deposits of igneous rock." + }, + "1329": { + "galacticEffectId": 1329, + "name": "LIBERTY DAY CELEBRATION", + "description": "Super Earth, our home, is the center of Liberty Day Festivities. Together, all citizens can watch on television the annual Defense Parade, the Justice Executions, and of course, the Freedom Fireworks. \n\nOn this special day, Helldivers are encouraged to visit Super Earth and watch this year's fireworks from their Super Destroyers." + }, + "1342": { + "galacticEffectId": 1342, + "name": "CENTER FOR THE CONFINEMENT OF DISSIDENCE (CECOD)", + "description": "This planet-wide ultra-high-security facility provides ample space for the secure confinement of terrorist dissidents until they are fully rehabilitated and re-educated." + }, + "1344": { + "galacticEffectId": 1344, + "name": "PANDORA BASE", + "description": "The top-secret site where augmentations to the DSS are constructed." + }, + "1352": { + "galacticEffectId": 1352, + "name": "CONVENTIONAL BLACK HOLE", + "description": "This former planet is now nothing but a normal, stable black hole." + }, + "1353": { + "galacticEffectId": 1353, + "name": "DATA CENTER", + "description": "The Automatons store large amounts of encrypted information here." + }, + "1355": { + "galacticEffectId": 1355, + "name": "HEAVY ARMOR SURGE", + "description": "Prepare to counter high numbers of heavily armored enemies." + }, + "1357": { + "galacticEffectId": 1357, + "name": "HULK SURGE", + "description": "High numbers of enemy Hulks have been reported on this planet. Prepare to counter heavily armored enemies." + }, + "1359": { + "galacticEffectId": 1359, + "name": "DEVASTATOR SURGE", + "description": "The Automatons have deployed high numbers of Devastators to this planet." + }, + "1360": { + "description": "Cyborgs are deployed to the battlefield of this planet, leading their Automaton armies.", + "galacticEffectId": 1360, + "name": "CYBORGS (Enemies)" + }, + "1361": { + "description": "Cyborgs are deployed to the battlefield of this planet, leading their Automaton armies.", + "galacticEffectId": 1361, + "name": "CYBORGS" + }, + "1373": { + "galacticEffectId": 1373, + "name": "CLASS 1 EXOSTORM", + "description": "Isolated Exostorm pockets are materializing across the planet and rapidly gaining momentum." + }, + "1374": { + "galacticEffectId": 1374, + "name": "CLASS 2 EXOSTORM", + "description": "Exostorm fronts are coalescing into a dense system that threatens to engulf the entire planet." + }, + "1375": { + "galacticEffectId": 1375, + "name": "CLASS 3 EXOSTORM", + "description": "The Exostorm has reached critical mass, enveloping the planet in an ominous tempest that defies atmospheric physics." + }, + "1376": { + "galacticEffectId": 1376, + "name": "The Void", + "description": "This world is enveloped by The Void." + }, + "1377": { + "galacticEffectId": 1377, + "name": "MINDLESS MASSES (Enemies)", + "description": "The Illuminate are converting large numbers of Super Earth citizens into Voteless-type enemies on this planet. Prepare to face a twisted, indoctrinated horde." + }, + "1378": { + "galacticEffectId": 1378, + "name": "MINDLESS MASSES", + "description": "The Illuminate are converting large numbers of Super Earth citizens into Voteless-type enemies on this planet. Prepare to face a twisted, indoctrinated horde." + }, + "1379": { + "galacticEffectId": 1379, + "name": "APPROPRIATORS", + "description": "The Illuminate are deploying only their own kind to this planet, a clear indication of the operation's importance and/or xenophobic nature. Prepare to face foot soldiers, drones, and piloted mechanical constructs." + }, + "1380": { + "galacticEffectId": 1380, + "name": "APPROPRIATORS (Enemies)", + "description": "The Illuminate are deploying only their own kind to this planet, a clear indication of the operation's importance and/or xenophobic nature. Prepare to face foot soldiers, drones, and piloted mechanical constructs." + }, + "1386": { + "galacticEffectId": 1386, + "name": "SPORE BURST STRAIN", + "description": "A mutation causes Terminids on this planet to generate excess hormonal spores, which drive other similarly mutated Terminids into a frenzy. Prepare to face enemies that bolster each others' speed." + }, + "1387": { + "galacticEffectId": 1387, + "name": "COMMUNICATIONS ARRAY", + "description": "The relay towers on this planet are important to Automaton communications." + }, + "1395": { + "galacticEffectId": 1395, + "name": "TERMINID CONTROL SYSTEM+", + "description": "On this planet, a network of Termicide-dispensing towers repels Terminids emerging from the Gloom." + }, + "1400": { + "galacticEffectId": 1400, + "name": "Heavy SEAF Presence", + "description": "Conventional SEAF forces are heavily deployed across this planet, and may directly support Helldiver missions." + }, + "1401": { + "galacticEffectId": 1401, + "name": "Heavy SEAF Presence (Enemies)", + "description": "Conventional SEAF forces are heavily deployed across this planet, and may directly support Helldiver missions." + }, + "1402": { + "galacticEffectId": 1402, + "name": "VOTE SNATCHERS (Enemies)", + "description": "The Illuminate have unleashed the next wave of their democratically voided thralls on this planet. Expect violent voter suppression tactics." + }, + "1403": { + "galacticEffectId": 1403, + "name": "VOTE SNATCHERS", + "description": "The Illuminate have unleashed the next wave of their democratically voided thralls on this planet. Expect violent voter suppression tactics." + }, + "1406": { + "galacticEffectId": 1406, + "name": "SIDEBOARD VOID", + "description": "This planet is within a SIDEBOARD area, specifically SIDEBOARD VOID" + }, + "1407": { + "galacticEffectId": 1407, + "name": "VOID GATEWAY", + "description": "This planet serves as a connective point between this galaxy and the Void, allowing travel between the two spaces." + }, + "1412": { + "galacticEffectId": 1412, + "name": "ANOMALY LOCATION", + "description": "All readings, or the notable lack thereof, indicate that the source of the Void anomaly is located here. All effort must go to enabling FTL travel to these coordinates." + }, + "1413": { + "galacticEffectId": 1413, + "name": "INVASION FLEET (Enemies)", + "description": "The main invasion fleet of the Illuminate, from arrogant Overseers to throngs of brainwashed Super Earth civilians, are present on this planet. Exterminate on sight or else risk violent resistance, or worse, treasonous propaganda." + }, + "1414": { + "galacticEffectId": 1414, + "name": "INVASION FLEET", + "description": "The main invasion fleet of the Illuminate, from arrogant Overseers to throngs of brainwashed Super Earth civilians, are present on this planet. Exterminate on sight or else risk violent resistance, or worse, treasonous propaganda." + } +} diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/data/plantes_mix.json b/hexi/plugins/nonebot_plugin_helldivers_tools/data/plantes_mix.json new file mode 100644 index 0000000..c2685ed --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/data/plantes_mix.json @@ -0,0 +1,531 @@ +{ + "ACTIVE PLANETS": "活跃行星", + "AWAITING MAJOR ORDER": "等待重要指令", + "TOTAL PLAYERS:": "玩家总数:", + "Stand by for further orders from Super Earth High Command": "等待超级地球最高指挥部下发重要指令", + "Major Order ends in:": "重要指令结束时间:", + "MAJOR ORDER": "重要指令", + "Defended Planets": "防守星球", + "MEDALS": "奖章", + "DEFEND": "防守", + "Galaxy Stats": "星系状态", + "Oshaune": "欧绍恩", + "Martale": "玛尔特", + "Hellmire": "海尔迈尔", + "Matar Bay": "玛塔", + "Penta": "彭塔", + "Estanu": "伊斯塔努", + "Choohe": "丘伊", + "Chort Bay": "雀特湾", + "Fori Prime": "佛里主星", + "Super Earth": "超级地球", + "Marfark": "玛尔法克", + "Crimsica": "克里姆西卡", + "Menkent": "库楼三", + "Lesath": "尾宿八", + "Vernen Wells": "佛农井", + "Nivel 43": "尼维尔43", + "Durgen": "德尔根", + "Tibit": "提比特", + "Draupnir": "德罗普尼尔", + "Malevelon Creek": "麦拉芬蒙河", + "Maia": "昂宿四", + "Fenrir III": "芬里尔III", + "Errata Prime": "艾拉特主星", + "Troost": "特鲁斯特", + "Ustotu": "伍斯特图", + "Turing": "图灵", + "Angel's Venture": "天使投资", + "Ingmar": "英格玛", + "Tien Kwan": "天关", + "Ubanea": "乌巴尼亚", + "Vandalon IV": "万达隆IV", + "Meridia": "默里迪亚", + "Veld": "维尔德", + "Mantes": "蒙特斯", + "Klen Dahth II": "克伦达斯II", + "Pathfinder V": "开拓者V", + "Widow's Harbor": "寡妇港", + "New Haven": "纽黑文", + "Pilen V": "皮伦V", + "Hydrofall Prime": "水瀑主星", + "Zea Rugosia": "泽亚鲁戈西亚", + "Darrowsport": "达罗斯波特", + "Fornskogur II": "福恩斯科古尔", + "Midasburg": "弥达斯堡", + "Cerberus IIIc": "刻耳帕洛斯IIIc", + "Prosperity Falls": "繁荣瀑布", + "Okul VI": "欧库VI", + "Martyr's Bay": "烈士湾", + "Freedom Peak": "弗里敦峰", + "Fort Union": "联合堡", + "Kelvinor": "开尔文奥尔", + "Wraith": "幽灵", + "Igla": "伊格勒", + "New Kiruna": "新基鲁纳", + "Fort Justice": "正义堡", + "Zegema Paradise": "泽格马乐土", + "Providence": "普罗维登斯", + "Primordia": "普莱默迪亚", + "Sulfura": "萨尔弗拉", + "Nublaria I": "努布拉里亚I", + "Krakatwo": "克拉克图", + "Volterra": "沃尔泰拉", + "Crucible": "熔炉", + "Veil": "帷幕", + "Marre IV": "马尔IV", + "Fort Sanctuary": "庇护堡", + "Seyshel Beach": "塞舌尔海滩", + "Effluvia": "艾芙鲁维亚", + "Solghast": "索尔加斯特", + "Dilvuia": "迪卢维亚", + "Viridia Prime": "维尔伊迪主星", + "Obari": "欧巴里", + "Myradesh": "米拉戴什", + "Atrama": "阿特拉玛", + "Emeria": "埃梅里亚", + "Barabos": "巴勒博斯", + "Fenmire": "范迈尔", + "Mastia": "玛斯蒂亚", + "Shallus": "沙勒斯", + "Krakabos": "克拉克博斯", + "Iridica": "艾丽迪卡", + "Azterra": "艾孜泰拉", + "Azur Secundus": "艾热尔次星", + "Ivis": "艾维斯", + "Slif": "斯利夫", + "Caramoor": "开勒莫尔", + "Kharst": "喀斯特", + "Eukoria": "欧科里亚", + "Myrium": "梅里翁", + "Kerth Secundus": "克斯次星", + "Parsh": "帕尔什", + "Reaf": "利夫", + "Irulta": "艾鲁尔塔", + "Emorath": "艾莫拉斯", + "Ilduna Prime": "伊尔都纳主星", + "Maw": "深渊", + "Borea": "博瑞亚", + "Curia": "居里亚", + "Tarsh": "塔尔什", + "Shelt": "谢尔特", + "Imber": "因博尔", + "Blistica": "布里斯提卡", + "Ratch": "拉奇", + "Julheim": "尤尔海姆", + "Valgaard": "瓦尔加德", + "Arkturus": "阿克图勒斯", + "Esker": "艾斯克尔", + "Terrek": "泰雷克", + "Cirrus": "希勒斯", + "Heeth": "希斯", + "Alta V": "奥尔塔V", + "Ursica XI": "厄西卡XI", + "Inari": "伊纳里", + "Skaash": "斯卡什", + "Moradesh": "莫拉戴什", + "Rasp": "拉斯普", + "Bashyr": "巴希尔", + "Regnus": "雷格努斯", + "Mog": "莫格", + "Valmox": "瓦尔莫克斯", + "Iro": "伊罗", + "Grafmere": "格拉夫米尔", + "New Stockholm": "新斯德哥尔摩", + "Oasis": "绿洲", + "Genesis Prime": "创世主星", + "Outpost 32": "32号哨站", + "Calypso": "卡利普索", + "Elysian Meadows": "埃律西昂草原", + "Alderidge Cove": "阿尔德里奇湾", + "Trandor": "特兰道尔", + "East Iridium Trading Bay": "东铱贸易湾", + "Liberty Ridge": "解放岭", + "Baldrick Prime": "巴尔德里克主星", + "The Weir": "维尔", + "Kuper": "库珀", + "Oslo Station": "奥斯陆站", + "Pöpli IX": "珀普利IX", + "Gunvald": "古恩瓦尔德", + "Dolph": "多尔夫", + "Bekvam III": "贝克温III", + "Duma Tyr": "杜马提尔", + "Aeris Pass": "亚萨关隘", + "Aurora Bay": "极光湾", + "Gaellivare": "耶利瓦勒", + "Vog-Sojoth": "佛戈索约斯", + "Kirrik": "基里克", + "Mortax Prime": "摩尔塔克斯主星", + "Wilford Station": "威尔福德站", + "Pioneer II": "先驱II", + "Erson Sands": "厄尔森桑兹", + "Socorro III": "索科罗III", + "Bore Rock": "博尔岩", + "Darius II": "大流士II", + "Acamar IV": "天园六IV", + "Achernar Secundus": "水委一次星", + "Achird III": "王良三III", + "Acrab XI": "房宿四XI", + "Acrux IX": "十字架二IX", + "Acubens Prime": "柳宿增三主星", + "Adhara": "弧矢七", + "Afoyay Bay": "艾福亚湾", + "Alairt III": "艾列尔特III", + "Alamak VII": "天大将军——VII", + "Alaraph": "右执法", + "Alathfar XI": "织女增三XI", + "Andar": "安达尔", + "Asperoth Prime": "阿斯佩洛斯主星", + "Bellatrix": "参宿五", + "Botein": "天阴四", + "Osupsam": "欧苏普森", + "Brink-2": "布林克2", + "Bunda Secundus": "天垒城一次星", + "Canopus": "老人", + "Caph": "王良一", + "Castor": "北河二", + "Mort": "莫特", + "Charbal-VII": "查巴尔VII", + "Charon Prime": "卡戎主星", + "Choepessa IV": "科埃佩萨IV", + "Claorell": "可洛尔", + "Clasa": "克拉萨", + "Demiurg": "戴米尔基", + "Deneb Secundus": "天津四次星", + "Electra Bay": "昂宿一湾", + "Enuliale": "安努力亚", + "Epsilon Phoencis VI": "艾普斯林芬赛斯VI", + "Gacrux": "十字架一", + "Gar Haren": "轧尔哈伦", + "Gatria": "盖尔崔亚", + "Gemma": "贯索四", + "Grand Errant": "大艾伦特", + "Hadr": "马腹一", + "Haka": "哈卡", + "Haldus": "海德斯", + "Halies Port": "海利斯港", + "Herthon Secundus": "赫尔松次主星", + "Hesoe Prime": "海索主星", + "Heze Bay": "角宿二湾", + "Hort": "霍尔特", + "Hydrobius": "海德罗毕亚斯", + "Karlia": "卡利亚", + "Keid": "九州殊口增七", + "Khandark": "勘达尔克", + "Klaka 5": "克拉卡5", + "Kneth Port": "克奈斯港", + "Kraz": "轸宿四", + "Kuma": "天棓二", + "Lastofe": "赖斯斗夫", + "Leng Scundus": "蓝恩次星", + "Meissa": "觜宿一", + "Mekbuda": "井宿七", + "Merak": "北斗二", + "Merga IV": "玄戈增二IV", + "Minchir": "敏切尔", + "Mintoria": "敏托瑞亚", + "Morida 9": "摩帝亚9", + "Nabatea Secundus": "那贝塔次星", + "Navi VII": "阁道二", + "Overgoe Prime": "欧维果主星", + "Pandion-XXIV": "帕狄恩XXIV", + "Partion": "帕尔晨", + "Peacock": "孔雀十一", + "Phact Bay": "丈人一湾", + "Pherkad Secundus": "北极一次星", + "Polaris Prime": "北极星主星", + "Pollux 31": "北河三31", + "Prasa": "普拉萨", + "Propus": "五诸侯三", + "Ras Algethi": "帝坐", + "RD-4": "RD4", + "Rogue 5": "罗格5", + "Rirga Bay": "里尔加湾", + "Seasse": "西斯", + "Senge 23": "新戈23", + "Setia": "赛提亚", + "Shete": "赛特", + "Siemnot": "席姆纳特", + "Sirius": "天狼星", + "Skat bay": "斯卡特湾", + "Spherion": "斯飞利昂", + "Stor Tha Prime": "斯特萨主星", + "Stout": "斯图尔特", + "Termadon": "特尔玛登", + "Varylia 5": "瓦瑞拉亚", + "Wasat": "天樽二", + "Vega Bay": "织女一湾", + "Wezen": "弧矢一", + "Vindemitarix Prime": "文德米塔里克斯主星", + "X-45": "X45", + "Yed Prior": "天市右垣九", + "Zefia": "塞飞亚", + "Zosma": "太微右垣五", + "Zzaniah Prime": "藏尼亚主星", + "Skitter": "斯基特", + "Euphoria III": "欧福利亚III", + "Diaspora X": "大流散X", + "Gemstone Bluffs": "宝石崖", + "Zagon Prime": "扎贡主星", + "Omicron": "奥密克戎", + "Cyberstan": "生化斯坦", + "OSHAUNE": "欧绍恩", + "MARTALE": "玛尔特", + "HELLMIRE": "海尔迈尔", + "MATAR BAY": "玛塔", + "PENTA": "彭塔", + "ESTANU": "伊斯塔努", + "CHOOHE": "丘伊", + "CHORT BAY": "雀特湾", + "FORI PRIME": "佛里主星", + "SUPER EARTH": "超级地球", + "MARFARK": "玛尔法克", + "CRIMSICA": "克里姆西卡", + "MENKENT": "库楼三", + "LESATH": "尾宿八", + "VERNEN WELLS": "佛农井", + "NIVEL 43": "尼维尔43", + "DURGEN": "德尔根", + "TIBIT": "提比特", + "DRAUPNIR": "德罗普尼尔", + "MALEVELON CREEK": "麦拉芬蒙河", + "MAIA": "昂宿四", + "FENRIR III": "芬里尔III", + "ERRATA PRIME": "艾拉特主星", + "TROOST": "特鲁斯特", + "USTOTU": "伍斯特图", + "TURING": "图灵", + "ANGEL'S VENTURE": "天使投资", + "INGMAR": "英格玛", + "TIEN KWAN": "天关", + "UBANEA": "乌巴尼亚", + "VANDALON IV": "万达隆IV", + "MERIDIA": "默里迪亚", + "VELD": "维尔德", + "MANTES": "蒙特斯", + "KLEN DAHTH II": "克伦达斯II", + "PATHFINDER V": "开拓者V", + "WIDOW'S HARBOR": "寡妇港", + "NEW HAVEN": "纽黑文", + "PILEN V": "皮伦V", + "HYDROFALL PRIME": "水瀑主星", + "ZEA RUGOSIA": "泽亚鲁戈西亚", + "DARROWSPORT": "达罗斯波特", + "FORNSKOGUR II": "福恩斯科古尔", + "MIDASBURG": "弥达斯堡", + "CERBERUS IIIC": "刻耳帕洛斯IIIc", + "PROSPERITY FALLS": "繁荣瀑布", + "OKUL VI": "欧库VI", + "MARTYR'S BAY": "烈士湾", + "FREEDOM PEAK": "弗里敦峰", + "FORT UNION": "联合堡", + "KELVINOR": "开尔文奥尔", + "WRAITH": "幽灵", + "IGLA": "伊格勒", + "NEW KIRUNA": "新基鲁纳", + "FORT JUSTICE": "正义堡", + "ZEGEMA PARADISE": "泽格马乐土", + "PROVIDENCE": "普罗维登斯", + "PRIMORDIA": "普莱默迪亚", + "SULFURA": "萨尔弗拉", + "NUBLARIA I": "努布拉里亚I", + "KRAKATWO": "克拉克图", + "VOLTERRA": "沃尔泰拉", + "CRUCIBLE": "熔炉", + "VEIL": "帷幕", + "MARRE IV": "马尔IV", + "FORT SANCTUARY": "庇护堡", + "SEYSHEL BEACH": "塞舌尔海滩", + "EFFLUVIA": "艾芙鲁维亚", + "SOLGHAST": "索尔加斯特", + "DILVUIA": "迪卢维亚", + "VIRIDIA PRIME": "维尔伊迪主星", + "OBARI": "欧巴里", + "MYRADESH": "米拉戴什", + "ATRAMA": "阿特拉玛", + "EMERIA": "埃梅里亚", + "BARABOS": "巴勒博斯", + "FENMIRE": "范迈尔", + "MASTIA": "玛斯蒂亚", + "SHALLUS": "沙勒斯", + "KRAKABOS": "克拉克博斯", + "IRIDICA": "艾丽迪卡", + "AZTERRA": "艾孜泰拉", + "AZUR SECUNDUS": "艾热尔次星", + "IVIS": "艾维斯", + "SLIF": "斯利夫", + "CARAMOOR": "开勒莫尔", + "KHARST": "喀斯特", + "EUKORIA": "欧科里亚", + "MYRIUM": "梅里翁", + "KERTH SECUNDUS": "克斯次星", + "PARSH": "帕尔什", + "REAF": "利夫", + "IRULTA": "艾鲁尔塔", + "EMORATH": "艾莫拉斯", + "ILDUNA PRIME": "伊尔都纳主星", + "MAW": "深渊", + "BOREA": "博瑞亚", + "CURIA": "居里亚", + "TARSH": "塔尔什", + "SHELT": "谢尔特", + "IMBER": "因博尔", + "BLISTICA": "布里斯提卡", + "RATCH": "拉奇", + "JULHEIM": "尤尔海姆", + "VALGAARD": "瓦尔加德", + "ARKTURUS": "阿克图勒斯", + "ESKER": "艾斯克尔", + "TERREK": "泰雷克", + "CIRRUS": "希勒斯", + "HEETH": "希斯", + "ALTA V": "奥尔塔V", + "URSICA XI": "厄西卡XI", + "INARI": "伊纳里", + "SKAASH": "斯卡什", + "MORADESH": "莫拉戴什", + "RASP": "拉斯普", + "BASHYR": "巴希尔", + "REGNUS": "雷格努斯", + "MOG": "莫格", + "VALMOX": "瓦尔莫克斯", + "IRO": "伊罗", + "GRAFMERE": "格拉夫米尔", + "NEW STOCKHOLM": "新斯德哥尔摩", + "OASIS": "绿洲", + "GENESIS PRIME": "创世主星", + "OUTPOST 32": "32号哨站", + "CALYPSO": "卡利普索", + "ELYSIAN MEADOWS": "埃律西昂草原", + "ALDERIDGE COVE": "阿尔德里奇湾", + "TRANDOR": "特兰道尔", + "EAST IRIDIUM TRADING BAY": "东铱贸易湾", + "LIBERTY RIDGE": "解放岭", + "BALDRICK PRIME": "巴尔德里克主星", + "THE WEIR": "维尔", + "KUPER": "库珀", + "OSLO STATION": "奥斯陆站", + "PÖPLI IX": "珀普利IX", + "GUNVALD": "古恩瓦尔德", + "DOLPH": "多尔夫", + "BEKVAM III": "贝克温III", + "DUMA TYR": "杜马提尔", + "AERIS PASS": "亚萨关隘", + "AURORA BAY": "极光湾", + "GAELLIVARE": "耶利瓦勒", + "VOG-SOJOTH": "佛戈索约斯", + "KIRRIK": "基里克", + "MORTAX PRIME": "摩尔塔克斯主星", + "WILFORD STATION": "威尔福德站", + "PIONEER II": "先驱II", + "ERSON SANDS": "厄尔森桑兹", + "SOCORRO III": "索科罗III", + "BORE ROCK": "博尔岩", + "DARIUS II": "大流士II", + "ACAMAR IV": "天园六IV", + "ACHERNAR SECUNDUS": "水委一次星", + "ACHIRD III": "王良三III", + "ACRAB XI": "房宿四XI", + "ACRUX IX": "十字架二IX", + "ACUBENS PRIME": "柳宿增三主星", + "ADHARA": "弧矢七", + "AFOYAY BAY": "艾福亚湾", + "AIN-5": "毕宿—5", + "ALAIRT III": "艾列尔特III", + "ALAMAK VII": "天大将军——VII", + "ALARAPH": "右执法", + "ALATHFAR XI": "织女增三XI", + "ANDAR": "安达尔", + "ASPEROTH PRIME": "阿斯佩洛斯主星", + "BELLATRIX": "参宿五", + "BOTEIN": "天阴四", + "OSUPSAM": "欧苏普森", + "BRINK-2": "布林克2", + "BUNDA SECUNDUS": "天垒城一次星", + "CANOPUS": "老人", + "CAPH": "王良一", + "CASTOR": "北河二", + "MORT": "莫特", + "CHARBAL-VII": "查巴尔VII", + "CHARON PRIME": "卡戎主星", + "CHOEPESSA IV": "科埃佩萨IV", + "CLAORELL": "可洛尔", + "CLASA": "克拉萨", + "DEMIURG": "戴米尔基", + "DENEB SECUNDUS": "天津四次星", + "ELECTRA BAY": "昂宿一湾", + "ENULIALE": "安努力亚", + "EPSILON PHOENCIS VI": "艾普斯林芬赛斯VI", + "GACRUX": "十字架一", + "GAR HAREN": "轧尔哈伦", + "GATRIA": "盖尔崔亚", + "GEMMA": "贯索四", + "GRAND ERRANT": "大艾伦特", + "HADR": "马腹一", + "HAKA": "哈卡", + "HALDUS": "海德斯", + "HALIES PORT": "海利斯港", + "HERTHON SECUNDUS": "赫尔松次主星", + "HESOE PRIME": "海索主星", + "HEZE BAY": "角宿二湾", + "HORT": "霍尔特", + "HYDROBIUS": "海德罗毕亚斯", + "KARLIA": "卡利亚", + "KEID": "九州殊口增七", + "KHANDARK": "勘达尔克", + "KLAKA 5": "克拉卡5", + "KNETH PORT": "克奈斯港", + "KRAZ": "轸宿四", + "KUMA": "天棓二", + "LASTOFE": "赖斯斗夫", + "LENG SCUNDUS": "蓝恩次星", + "MEISSA": "觜宿一", + "MEKBUDA": "井宿七", + "MERAK": "北斗二", + "MERGA IV": "玄戈增二IV", + "MINCHIR": "敏切尔", + "MINTORIA": "敏托瑞亚", + "MORIDA 9": "摩帝亚9", + "NABATEA SECUNDUS": "那贝塔次星", + "NAVI VII": "阁道二", + "OVERGOE PRIME": "欧维果主星", + "PANDION-XXIV": "帕狄恩XXIV", + "PARTION": "帕尔晨", + "PEACOCK": "孔雀十一", + "PHACT BAY": "丈人一湾", + "PHERKAD SECUNDUS": "北极一次星", + "POLARIS PRIME": "北极星主星", + "POLLUX 31": "北河三31", + "PRASA": "普拉萨", + "PROPUS": "五诸侯三", + "RAS ALGETHI": "帝坐", + "ROGUE 5": "罗格5", + "RIRGA BAY": "里尔加湾", + "SEASSE": "西斯", + "SENGE 23": "新戈23", + "SETIA": "赛提亚", + "SHETE": "赛特", + "SIEMNOT": "席姆纳特", + "SIRIUS": "天狼星", + "SKAT BAY": "斯卡特湾", + "SPHERION": "斯飞利昂", + "STOR THA PRIME": "斯特萨主星", + "STOUT": "斯图尔特", + "TERMADON": "特尔玛登", + "VARYLIA 5": "瓦瑞拉亚", + "WASAT": "天樽二", + "VEGA BAY": "织女一湾", + "WEZEN": "弧矢一", + "VINDEMITARIX PRIME": "文德米塔里克斯主星", + "YED PRIOR": "天市右垣九", + "ZEFIA": "塞飞亚", + "ZOSMA": "太微右垣五", + "ZZANIAH PRIME": "藏尼亚主星", + "SKITTER": "斯基特", + "EUPHORIA III": "欧福利亚III", + "DIASPORA X": "大流散X", + "GEMSTONE BLUFFS": "宝石崖", + "ZAGON PRIME": "扎贡主星", + "OMICRON": "奥密克戎", + "CYBERSTAN": "生化斯坦" +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/doc/api.md b/hexi/plugins/nonebot_plugin_helldivers_tools/doc/api.md new file mode 100644 index 0000000..10cadb6 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/doc/api.md @@ -0,0 +1,231 @@ +# Helldivers 自部署 API 说明 + +> 本文档基于对自部署实例 **`http://192.168.2.15:18080`** 的实际探测整理(字段以真实返回为准)。 +> 用途:弄清这个代理能拿到哪些数据,以及战报卡片**还没利用**的部分。 + +--- + +## 0. 基础信息 + +**Base URL**:`http://192.168.2.15:18080` + +**请求头**(两个 `X-Super-*` 必须都带,否则公共实例会直接 400): + +```http +Accept-Language: en-US,zh-Hans;q=0.5 +X-Super-Client: <你的客户端名> +X-Super-Contact: <联系方式> +``` + +- `Accept-Language` 决定返回文案语言(`en-US` / `zh-Hans`/`zh-Hant` 等)。 +- 返回均为 JSON。 + +**注意(坑)**: +- `/api/v1/war` 的 `now` 返回 `1972-...`,疑似该代理的数据有误(`started/ended` 是 2024→2028 也偏大)。用真实时间请自己取 `time.time()`,别信 `war.now`。 +- `/api/v1/planet-events` 返回的是**单颗星球对象**(数组里只有 index 130),不是事件列表——疑似别名或代理异常。真正的星球事件在 `/raw/.../Status` 的 `planetEvents`。 +- 接口返回可能被外层包裹成 `{data:[...]}` 或 `{planets:[...]}`,`/api/v1/*` 目前探测到是**裸数组/裸对象**。 + +--- + +## 1. 接口总览 + +| 端点 | 形状 | 说明 | +|---|---|---| +| `GET /api/v1/war` | `object` | 星系战况概要 | +| `GET /api/v1/assignments` | `array[1]` | 重要指令(最高指令 MAJOR ORDER) | +| `GET /api/v1/campaigns` | `array[35]` | 当前战役(参战星球) | +| `GET /api/v1/planets` | `array[273]` | 全星球表 | +| `GET /api/v1/planets/{index}` | `object` | 单星球详细情况 | +| `GET /raw/api/WarSeason/801/Status` | `object` | 原始战争状态(最全) | + +> 以下 `/api/v1/*` 均 **404**:`attacks`、`galaxy`、`galaxy-war`、`global-events`、`news`、`statistics`、`space-stations`、`space_stations`、`war/status`、`war/statistics`、`war/summary`、`planet-effects`、`steam/war`、`version`。 +> `/raw/api/WarSeason/801/*` 只有 `Status` 可用(`Planets`、`Assignments`、`Campaigns`、`News`、`Statistics`、`GlobalEvents`、`SuperEarthWarResults`、`Planets/224`、`Planet/224/Statistics` 均 404)。 + +--- + +## 2. 各端点字段详解 + +### 2.1 `GET /api/v1/war` — 星系战况概要 + +```json +{ + "started": "2024-01-23T20:05:13Z", + "ended": "2028-02-08T20:04:55Z", + "now": "1972-07-14T16:19:50Z", + "clientVersion": "0.3.0", + "factions": ["Humans", "Terminids", "Automaton", "Illuminate"], + "impactMultiplier": 0.019517466, + "statistics": { + "missionsWon": 1011049334, "missionsLost": 98505230, "missionTime": 3325809094530, + "terminidKills": 216600333572, "automatonKills": 114998420419, "illuminateKills": 75823458605, + "bulletsFired": 1944890521255, "bulletsHit": 2131033542437, "timePlayed": 3325809094530, + "deaths": 8728394343, "revives": 2, "friendlies": 1009517116, + "missionSuccessRate": 91, "accuracy": 100, "playerCount": 57302 + } +} +``` + +| 字段 | 说明 | +|---|---| +| `factions` | 参战阵营英文名(Humans/Terminids/Automaton/Illuminate) | +| `impactMultiplier` | 全局影响倍数 | +| `statistics` | 全局累计统计(任务/击杀/子弹/命中/死亡/胜率/命中率/玩家数) | + +**可自定义用途**:顶部全局统计、累计击杀对比、胜利/失败率。 + +### 2.2 `GET /api/v1/assignments` — 重要指令(最高指令) + +```json +{ + "id": 3348823937, + "progress": [1, 0, 0], + "title": "MAJOR ORDER", + "briefing": "Liberate the designated enemy planets, ...", + "description": null, + "tasks": [ + { "type": 11, "values": [1, 1, 171], "valueTypes": [3, 11, 12] }, + { "type": 11, "values": [1, 1, 172], "valueTypes": [3, 11, 12] }, + { "type": 11, "values": [1, 1, 268], "valueTypes": [3, 11, 12] } + ], + "reward": { "type": 1, "amount": 50 }, + "rewards": [ { "type": 1, "amount": 50 } ], + "expiration": "2026-08-31T12:03:32.7346799Z", + "flags": 0 +} +``` + +| 字段 | 说明 | +|---|---| +| `title` | 指令名(MAJOR ORDER / 玩家自定义战役等) | +| `briefing` | 指令说明文本(英文) | +| `progress` | 各目标进度(与 `tasks` 对位) | +| `tasks[].type` | 任务类型(11 = 解放/进攻某星球类) | +| `tasks[].values` | 与 `valueTypes` 对位:如 `[1,1,171]`,其中 `171/172/268` 为目标星球 index | +| `tasks[].valueTypes` | 各 `values` 的含义(3 疑似星球 index,11/12 为计数类;**需再对照官方定义**) | +| `reward` / `rewards` | 奖励:`type`(1=奖章/2=征用券/3=超级货币/4=补助/5=经验) + `amount` | +| `expiration` | 指令截止时间 | + +**说明**:战报卡片的「重要指令」已用 `title/briefing/expiration`;`progress/tasks/rewards` 目前基本没用上,可用来做**进度条**(解放了 1/3 颗目标星)和**奖励展示**。 + +### 2.3 `GET /api/v1/campaigns` — 当前战役(参战星球) + +```json +{ + "id": 51413, + "type": 0, + "count": 10, + "faction": "Humans", + "planet": { + "index": 7, "name": "...", "sector": "...", + "biome": { "name": "...", "description": "..." }, + "hazards": [ { "name": "Tremors", "description": "..." } ], + "maxHealth": ..., "health": ..., "regenPerSecond": ..., + "currentOwner": "...", "initialOwner": "...", + "event": null, + "statistics": { ... }, "attacking": [], "regions": [] + } +} +``` + +| 字段 | 说明 | +|---|---| +| `faction` | 战役阵营(Humans/Terminids/Automaton/Illuminate)。**解放战**=当前占据的敌方;**防守战**=进攻的敌方 | +| `type` | 战役类型(0 = 解放/常规;`campaign.type` 1 可能 = 防守) | +| `count` | 战役数量(参与该星球的战役条目数,通常为 1) | +| `planet` | **完整星球对象**(同 `/api/v1/planets/{index}`,含 biome/hazards/event/statistics/attacking/regions) | + +**可自定义用途**:`faction` 决定阵营色、`type` 区分解放/防守、`planet.hazards` 是危害来源(卡片已用)、`planet.event` 是侵攻事件。 + +### 2.4 `GET /api/v1/planets` / `GET /api/v1/planets/{index}` — 星球 + +```json +{ + "index": 224, "name": "RD-4", "sector": "Orion", + "biome": { "name": "Moon", "description": "...", "icon": "..." }, + "hazards": [ { "name": "Meteor Storms", "description": "...", "icon": "..." } ], + "hash": 1234567890, + "position": { "x": 0.29, "y": -0.87 }, + "waypoints": [], + "maxHealth": 1000000, "health": 1000000, + "disabled": false, "initialOwner": "Illuminate", "currentOwner": "Illuminate", + "regenPerSecond": 1.1111112, + "event": null, + "statistics": { + "missionsWon": 1290109, "missionsLost": 152477, "missionTime": 4488281762, + "terminidKills": 1344, "automatonKills": 3656, "illuminateKills": 604567039, + "bulletsFired": 3286403648, "bulletsHit": 3218310824, "timePlayed": 4488281762, + "deaths": 9153248, "revives": 0, "friendlies": 1324721, + "missionSuccessRate": 89, "accuracy": 97, "playerCount": 71 + }, + "attacking": [], + "regions": [] +} +``` + +| 字段 | 说明 | +|---|---| +| `index` / `name` | 星球编号 / 英文名 | +| `sector` | 星区英文名(战报里显示中文分区名) | +| `biome` | 地形(英文名 + 描述;`_translate` 加 i18n→中文) | +| `hazards[]` | **气象危害**(每颗星一个数组,可能多个;`name` 为英文,加 i18n→中文) | +| `maxHealth/health/regenPerSecond` | 战役血量 / 现值 / 回复速度(解放进度 = `(max-health)/max`) | +| `currentOwner/initialOwner` | 当前/初始阵营(英文名) | +| `event` | 进攻事件(空则无) | +| `statistics` | 星球累计统计(击杀/胜率/命中率/玩家数) | +| `attacking` | 正在进攻的条目(当前数据为空数组) | +| `regions` | 行星区域权属(当前为空数组) | + +**提示**:`hazards` 才是「环境事件」,且**一个星球可出现多个**;战报卡片的「环境事件」槽位已支持多危害图标+名称展示。 + +### 2.5 `GET /raw/api/WarSeason/801/Status` — 原始战争状态(最全) + +顶层键:`warId, time, impactMultiplier, storyBeatId32, planetStatus, planetAttacks, campaigns, communityTargets, jointOperations, planetEvents, planetActiveEffects, planetRegions, activeElectionPolicyEffects, globalEvents, superEarthWarResults, spaceStations, layoutVersion` + +| 子数组 | 形状 | 样例 / 字段 | +|---|---|---| +| `planetStatus` `[273]` | `{index, owner, health, regenPerSecond, players, position:{x,y}}` | 每颗星实时状态(比 `/api/v1/planets` 更轻、更新) | +| `planetAttacks` `[50]` | `{source, target}` | 进攻路线(source 星 → target 星) | +| `campaigns` `[35]` | `{id, planetIndex, type, count, race}` | 战役(`race` 数字阵营、`type` 0/1) | +| `planetEvents` `[1]` | `{id, planetIndex, eventType, race, health, maxHealth, startTime, expireTime, campaignId, jointOperationIds, potentialBuildUp}` | **被攻星球的进攻事件**(最完整:含 maxHealth / expireTime / 联合作战) | +| `planetActiveEffects` `[154]` | `{index, galacticEffectId}` | 星球生效效果(`galacticEffectId` → 效果图标) | +| `planetRegions` `[40]` | `{planetIndex, regionIndex, owner, health, regerPerSecond, availabilityFactor, isAvailable, players}` | **行星区域**权属/血量/玩家(可做区域细览) | +| `spaceStations` `[1]` | `{id32, planetIndex, activeEffectIds[], currentElectionEndWarTime, flags}` | 空间站(DSS):所在星 + 生效效果列表 | +| `jointOperations` `[1]` | `{id, planetIndex, hqNodeIndex}` | 联合作战节点 | +| `globalEvents` `[2]` | `{eventId, id32, portraitId32, title, titleId32, message, ...}` | 战争级事件公告(战役成功等) | +| `communityTargets` | `[]`(空) | 社区目标(当前无) | +| `activeElectionPolicyEffects` | `[]`(空) | 选举政策效果(当前无) | +| `superEarthWarResults` | `[]`(空) | 战争结果(当前无) | + +**说明**:`planetStatus[].owner` 是数字阵营(0=人类/1=终结族/2=机器人/3=光能族 之类),与 `/api/v1/planets` 的英文字符串阵营对应关系需要你确认——原生 HD2 里 `owner` 数字:`1=Humans, 2=Terminids, 3=Automaton, 4=Illuminate`。 + +--- + +## 3. 战报卡片:已用 / 未利用 + +### 已利用 +- `war` → 顶部标题信息 +- `assignments` → 重要指令(title/briefing/expiration) +- `campaigns[].planet` → 战役卡片(进度/危害/地形/效果) +- `planets`(en-US 星名)→ 匹配高清地形背景 +- `raw.planetActiveEffects` → `planet_effects`(星球效果槽位) +- `raw.spaceStations` → `space_stations`(DSS 增益) + +### 还有可利用(建议关注) +| 数据 | 来源 | 可做什么 | +|---|---|---| +| `planetEvents`(maxHealth/expireTime) | `/raw/Status` | **更准的入侵进度 + 倒计时**(目前卡片从 `campaign.planet.event` 取,缺 maxHealth/expireTime 时精度差) | +| `planetAttacks`(source→target) | `/raw/Status` | **战线图/进攻箭头**:可视化谁正在打谁 | +| `planetRegions` | `/raw/Status` | **星球区域占领细览**(每区域 owner/health/players) | +| `globalEvents` | `/raw/Status` | **战报滚动公告**(战役成功/事件推送) | +| `planetStatus[].owner/regen/players` | `/raw/Status` | 全星系战况概览(比全量星球更轻) | +| `planet.statistics` | `/api/v1/planets/{i}` | 星球数据卡(击杀/胜率/命中率/玩家数) | +| `war.statistics` | `/api/v1/war` | 顶部全局累计统计 | +| `assignment.progress/tasks/rewards` | `/api/v1/assignments` | **重要指令进度条**(解放了几颗目标星)+ 奖励展示 | + +--- + +## 4. 状态码 / 异常 +- `200`:正常(返回 JSON)。 +- `400`:缺 `X-Super-Client` / `X-Super-Contact`(或头格式错误)。 +- `404`:接口不存在(见上表 404 清单)。 +- 某些异常时可能返回 JSON `{error: ...}` 或带 `Message` 字段;建议调用方对非 200 抛出带 `resp.text[:400]` 的错误(`hd2_api._get_json` 已如此处理)。 diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/doc/hd2_zh.json b/hexi/plugins/nonebot_plugin_helldivers_tools/doc/hd2_zh.json new file mode 100644 index 0000000..434f0d8 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/doc/hd2_zh.json @@ -0,0 +1,17064 @@ +{ + "biome": { + "ARCTIC": "雪地", + "ARCTIC PLANET": "雪地星球", + "FOREST": "森林", + "FOREST PLANET": "森林星球", + "GRASSLAND": "草原", + "GRASSLAND PLANET": "草原星球", + "ROCKY": "岩地", + "ROCKY PLANET": "岩地星球", + "SANDY": "沙地", + "SANDY PLANET": "沙地星球", + "SAVANNA": "稀树", + "SAVANNA PLANET": "稀树星球", + "SWAMP": "沼泽", + "SWAMP PLANET": "湿地星球", + "MOOR": "荒地", + "MOOR PLANET": "荒地星球", + "PRIMORDIAL": "原始", + "PRIMORDIAL PLANET": "原始星球", + "HIVE WORLD": "虫窝世界" + }, + "hazard": { + "ACID STORMS": "酸雨风暴", + "ION STORMS": "离子风暴", + "FIRE TORNADOS": "烈焰龙卷", + "BLIZZARDS": "暴风雪", + "EAGLE STORM": "“飞鹰”风暴", + "SANDSTORMS": "沙暴", + "Acid Storm In Progress": "酸雨风暴正在形成", + "Ion Storm In Progress": "离子风暴正在形成", + "Blizzard In Progress": "暴风雪正在形成", + "Fire Tornado Warning": "烈焰龙卷风警告" + }, + "effect": { + "PREDATOR STRAIN": "掠食变种", + "SPORE BURST STRAIN": "孢裂变种", + "SPORE BURST HUNTER": "孢裂追猎虫", + "THE JET BRIGADE": "喷气旅", + "TERMINID CONTROL SYSTEM+": "终结族遏制体系+", + "ACTIVATE TERMINID CONTROL SYSTEM": "启动终结族遏制体系", + "DEACTIVATE TERMINID CONTROL SYSTEM": "关闭终结族遏制体系", + "AMMO SHORTAGE": "弹药短缺", + "AMMO SURPLUS": "弹药过剩", + "AERIAL DOMINANCE": "制霸高空", + "ATTRITION": "消耗战", + "ATMOSPHERIC SPORES": "孢子气体", + "ATMOSPHERIC INTERFERENCE": "大气干扰", + "AUTOMATON OVERDRIVE": "机器人超载驱动", + "APPROPRIATORS": "占领者", + "AA DEFENSES": "对空防御" + }, + "planet": { + "MALEVELON CREEK": "麦拉芬蒙河", + "ANGEL'S VENTURE": "天使投资", + "ACAMAR IV": "天园六IV", + "KLEN DAHTH II": "克伦达斯II" + }, + "ui": { + "MISSION INCOMPLETE": "任务未完成", + "Pick up and use EXPENDABLE ANTI-TANK against ARMORED ENEMIES.": "拾取并使用消耗性反坦克武器对付装备护甲的敌人。", + "to throw a Grenade": "投掷榴弹", + "HEAVY COMBAT (BUGS)": "重型作战(虫族)", + "COMMUNICATIONS": "通讯", + "SENTRY": "哨戒炮", + "SELECT AND ADJUST": "选择并调整", + "Welcome to the Galactic Map - This is where you navigate your Destroyer to the frontlines and select Missions to play.\n\nIn the galactic war, the entire Helldivers Community fights together against the enemies of Super Earth.": "欢迎查看银河地图 - 你将在此指挥驱逐舰奔赴前线,并且选择你要执行的任务。\n\n在星系战争中,整个绝地潜兵社区都在共同对抗超级地球的敌人。", + "FIRING": "开火", + "USE": "使用", + "WEAPON EXPERIMENTATION\nThe GL-6 Grenade Launcher stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“GL-6榴弹发射器”战略配备暂时获准供全体绝地潜兵使用。", + "Major Place of Interest": "主要特殊地点", + "Moving makes it harder to aim - Stand still for maximum accuracy!": "移动过程中难以瞄准,站立不动才能最大限度提高命中率!", + "CONSUMING VOID": "吞噬寂域", + "Heavy Encampment": "重型营地", + "MISSION COMPLETED": "任务完成", + "CLAIMING ITEM": "领取物品", + "THE RESOURCES OF PROGRESS": "进步的资源", + "Terminid Kills": "终结族击杀数", + "AUTOMATON FORTRESS": "机器人堡垒", + "STUN": "眩晕弹", + "#COUNTm": "#COUNT米", + "Requisition GRENADE LAUNCHER stratagem.": "申购榴弹发射器战略配备。", + "FF81ACFE": "FF81ACFE", + "Destroy Illuminate Ships": "摧毁光能者舰船", + "ALL": "全部", + "INTEL ACQUIRED! Bring it back to the ship to unlock OPPORTUNITY MISSION.": "取得情报!将情报带回舰船,解锁机遇任务。", + "OBJECTIVE COMPLETED": "目标达成", + "WEAPON EXPERIMENTATION\nThe ST-1 Stinger stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“ST-1毒刺”战略配备暂时获准供全体绝地潜兵使用。", + "ROCK": "石头", + "MOVE SELECTION AND SWITCH NUMBERS": "行动选择和切换号码", + "Armor": "盔甲", + "to dial stratagem": "拨通战略配备", + "Chest Hemorrhage": "胸腔出血", + "The unthinking, amoral bots may now violate the very air as well. Keep an eye to the skies, Helldivers. Reports are suggesting the presence of flying Automaton threats.": "毫无思考能力和道德底线的机器人现在甚至开始侵犯空中领域。绝地潜兵,务必留意天空的情况。报告显示,战场上出现了飞行机器人。", + "The left side of the skull should be barely visible.": "请将亮度调至骷髅头左侧勉强可见的程度。", + "Out of consumable #SLOT: #NAME.": "消耗品#SLOT耗尽:#NAME。", + "No reinforcement point available.": "暂无增援点。", + "Use COMPUTER TERMINAL.": "使用计算机终端。", + "PHASE 3": "第3阶段", + "PLAY": "开始游戏", + "LIBERATION FAILED\nWe have failed to reclaim a planet from the Automatons.": "解放失败\n我们未能从机器人手上夺回星球。", + "Bot Drop Detected": "侦测发现机器人", + "CANNOT EDIT": "无法编辑", + "DAMAGED": "受损", + "Rare Sample": "稀有样本", + "Find and destroy all Automaton Fabricators": "找到并消灭所有机器人构筑者", + "RESPOND": "回答", + "Unable to login into PlayFab, try again in a few minutes. Contact support if the problem persists.\n\nStatus code: #STATUSCODE \nError code: #ERRORCODE": "无法登录PlayFab,请过几分钟后再试。如果问题仍未解决,请联系客服。\n\n状态代码:#STATUSCODE \n错误代码:#ERRORCODE", + "SUPPORT WEAPON": "支援武器", + "Projectile": "投射", + "Steam AppId supplied is invalid or not allowed": "提供的Steam AppId无效或遭到禁止", + "BACKPACK": "背包", + "CLAIM STANDARD WARBOND": "领取标准战争债券", + "to go prone": "匍匐", + "DIFFICULTY 4 TRIAL": "难度4级考验", + "Helldivers on PlanetX have defeated waves of the Mindless Masses. Genetic material from the Voteless sent to the Ministry of Science show clear markers of adaptation to a rapidly changing environment, potentially giving clues about organisms inside the Void.": "镇守X星的绝地潜兵已击溃一波又一波无脑群氓。送往科学部的无票者遗传物质显示出可适应快速变化环境的清晰标记,这或许能为我们提供有关寂域生物的线索。", + "SPECIAL": "特殊", + "Active": "已激活", + "Base": "基地", + "FALLBACK": "撤退", + "AREA SECURED": "区域现已安全", + "Boosts Requisition and XP awards by 50% to address accounting errors (responsible parties undergoing re-education).": "申购点和经验奖励增加50%以修正核算错误(负责人正接受二次教育)。", + "SUPPLIES": "物资", + "CYCLE WEAPON CONFIG": "循环选择武器配置", + "DIFFICULTY": "难度", + "Game session is no longer available.": "本场游戏已无法加入。", + "WEAPON CUSTOMIZATION now available in the ARMORY.": "武器自定义内容已在军械库中解锁。", + "REWARDS": "奖励", + "IN LOADOUT": "正在进行武装配置", + "Avoid DROWNING by getting out of the water.": "脱离水体,避免淹溺。", + "PATTERN": "涂装", + "Amount": "数量", + "FF13D460": "FF13D460", + "#VALUE": "#VALUE", + "Cycle Pose": "切换姿态", + "Select your gear and Stratagems.": "选择你的装备和战略配备。", + "TURING LOST\nTuring has fallen to the Terminid Menace. We cannot allow this infestation to continue to spread.": "图灵沦陷\n在终结族的威胁下,图灵已沦陷。我们不能容许虫族继续扩张。", + "#ITEM FULL": "#ITEM已满", + "Medium Nest": "中型巢穴", + "UNDERBARREL": "下挂", + "FIRE": "开火", + "CONVOY HAS LEFT MISSION AREA": "车队已离开任务区域", + "Fortress Destroyed": "堡垒成功摧毁", + "RICOCHET": "跳弹", + "ITEM RECEIVED": "已收到物品", + "Shrieker Swarms Traverse the Skies": "尖啸虫群穿过空域", + "OFFLINE": "损毁", + "COMMON SAMPLES": "普通样本", + "ENEMY SURGE": "敌军激增", + "Failed to join lobby. The lobby host is not logged into PlayFab.": "无法进入大厅。大厅主办者尚未登录至PlayFab。", + "REINFORCE AVAILABLE IN:": "增援就位倒计时:", + "Toggle Headlight Power": "切换大灯供能源", + "BUY LEGENDARY WARBOND": "购买传奇战争债券", + "GAME OVER": "游戏结束", + "MANUALLY adjust FLOW RATE VALVES.": "手动调整流量阀。", + "Intel PDA": "情报PDA", + "LIBERATION FAILED\nThe bots retain their iron grip on Mantes.": "解放失败\n机器人依然牢牢掌控着蒙特斯。", + "Invalid Authorization for PlayStation™Network - Token Format": "PlayStation™Network的授权无效 - 令牌格式", + "Requisition MACHINE GUN SENTRY Stratagem permit.": "申购哨戒机枪战略配备许可证。", + "VELD LOST\nWe have failed to repel the bugs from Veld, and now they multiply in deep hives across the planet. We will return, to free it once more.": "维尔德沦陷\n我们没能将虫族赶出维尔德,现在它们在遍布整颗星球的虫窝深处不断繁殖壮大。我们定会回转,重新解放维尔德。", + "Terrain features like water and foliage will slow the Helldiver down.": "积水覆盖和满地枝叶等地形状况会拖慢绝地潜兵的前进速度。", + "SEASON III": "第III赛季", + "Unable to establish a connection to game.": "无法连接至游戏。", + "HELMET": "头盔", + "SELECT MISSION": "选择任务", + "VELD UNDER ATTACK\nThe Terminids are attempting to spread to Veld. All Helldivers are called upon to deploy immediately to the planet's defense.": "维尔德遭到袭击\n终结族企图扩张至维尔德。呼唤全体绝地潜兵,立即前去保卫该星球。", + "OPT": "准镜", + "PISTOL": "手枪", + "The Automatons' losses have begun to impact their ability to supply fresh units. Their resistance is crumbling. Press the assault!": "机器人的落败开始影响它们补充新兵力的能力。它们的抵抗逐渐崩溃,请乘胜追击!", + "Mission": "任务", + "WAIT": "等等", + "Net Worth": "生涯收入", + "DIFFICULTY 9 TRIAL": "难度9级考验", + "Failed to join as target host is running a different game version.": "加入失败,你与目标主办者的游戏版本不同。", + "CARRIABLE": "可携带", + "+#POINTS": "+#POINTS", + "Waiting for Host": "正在等待主办者", + "ONE HANDED": "单手操作", + "Activate extraction terminal.": "激活撤离终端。", + "Complete Missions to help push the enemies of Super Earth back.\n\nYou can do Missions on any contested Planet in any of the contested Sectors.": "完成任务,协助击退超级地球的敌人。\n\n你可以前往处于争夺状态的分区,在任意一颗处于争夺状态的星球上执行任务。", + "SINKING IN #SECONDS SECONDS": "沉没倒计时:#SECONDS秒", + "Shuttle incoming.\nDefend extraction zone.": "运输船接近中。\n请在撤离区坚守。", + "#NAME is the new squad leader": "#NAME成为新的小队长", + "ITEM INFO": "物品信息", + "Enter any Stratagem Input to Start!": "输入任意战略配备代码即可开始!", + "Successful Extractions": "成功撤离次数", + "Atmospheric Spores": "孢子气体", + "INFORMATION ON THE ENEMY": "敌方情报", + "#COUNT/#TOTAL": "#COUNT/#TOTAL", + "Melee Kills": "近战击杀数", + "NEED SUPPLIES": "我需要补给", + "ANGEL'S VENTURE LOST\nThe defense of Angel's Venture has failed. Terminids now run amok on its surface. We cannot allow this corruption of Liberty to stand.": "天使投资星系沦陷\n天使投资星系保卫战已宣告失败。终结族现在正四处肆虐。我们不能任由它们继续侵犯自由伟业。", + "Take Health Pack": "获得生命包", + "Rejoining mission": "正在重新加入任务", + "Light Nest": "轻型巢穴", + "(#MINUTES #MIN_UNIT#SEPARATOR#SECONDS #SEC_UNIT)": "(#MINUTES #MIN_UNIT#SEPARATOR#SECONDS #SEC_UNIT)", + "while map is open to look around the map": "在地图打开时浏览地图", + "ROTATING ITEMS": "轮换物品", + "Razor Sharp Claws": "利爪", + "STRATEGIC ADVISORY\n\nThe Automaton Jet Brigade has been spotted in the #SECTOR Sector.": "战略警报\n\n#SECTOR发现机器人喷气旅。", + "LIGHT ARMOR PENETRATING": "轻甲穿透", + "STIMS": "治疗剂", + "WEAPON EXPERIMENTATION\nThe Guard Dog Rover stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“‘护卫犬’漫游车”战略配备暂时获准供全体绝地潜兵使用。", + "BOOSTER": "强化资源", + "CAPES": "披肩", + "REQUEST REINFORCE": "请求增援", + "SCANNING...": "正在扫描……", + "#NAME DIED": "#NAME阵亡", + "Jammed": "受到干扰", + "FLASH": "闪光弹", + "#NAME": "#NAME", + "PLEASE WAIT": "请稍候", + "ITEM CLAIMED": "已领取物品", + "Too Far From Extraction - Shuttle Aborting In T-#MINUTES:#SECONDS:#MILLI": "距离撤离点太远 — 运输船中止倒计时 #MINUTES:#SECONDS:#MILLI", + "MALEVELON CREEK LOST\nThe defense of Malevelon Creek has failed. The Automatons spread their despotic industry across its surface.": "麦拉芬蒙河沦陷\n麦拉芬蒙河的防线已经崩溃,而机器人也将它们暴虐的产业扩张到了该星球的地表。", + "SW": "西南", + "#NAME has joined the mission": "#NAME加入任务", + "ENERGY-BASED": "能量武器", + "Tap": "轻按", + "ACQUIRED": "已获取", + "MEDIUM ARMOR PENETRATING": "中甲穿透", + "Go to the DESTROYER BRIDGE and use the WAR TABLE to START A MISSION": "前往驱逐舰舰桥,使用议战桌开始任务。", + "EXPERIMENTATION PERIOD ENDED\nThe previous authorization period for global stratagem usage has ended.": "试验周期结束\n上一项战略配备获准开放全体使用的周期已结束。", + "The quick brown fox jumps over the lazy dog.": "The quick brown fox jumps over the lazy dog.", + "CANCEL": "取消", + "Call the Helldivers": "呼叫绝地潜兵", + "Casual Salute": "敬礼", + "#NAME has timed out": "#NAME已超时", + "ESE (#COUNT°)": "东南偏东#COUNT°", + "FFFF9D42": "FFFF9D42", + "Shuttle Landing": "运输船即将着陆", + "Atmospheric Interference": "大气干扰", + "Spectating:": "正在观战:", + "LIBERATION FAILED\nOur efforts to purge Fenrir III of the Terminid presence have failed.": "解放失败\n我们将终结族彻底驱逐出芬里尔III的行动宣告失败。", + "CRIMSICA LOST\nThe defense of Crimsica has failed. Terminids now infest its once-pristine surface.": "克里姆西卡沦陷\n克里姆西卡保卫战已宣告失败。终结族现在令这块曾经的纯净乐土不得安宁。", + "Helldivers will soon have even more tools with which to bring Managed Democracy to the enemy. Shipments of new equipment are under way.": "绝地潜兵很快将拥有更多工具,向敌人传播管理式民主。全新装备正在运输途中。", + "HEETH FREED\nHeeth has been cleansed of all Terminid infestation. Well done, Helldivers. Keep pressing forward.": "希斯已解放\n肆虐希斯的终结族已被全数剿灭。很好,各位绝地潜兵。再接再厉,继续前进。", + "Signal Right Turn": "指示右转", + "The loadout for this mission has already been selected. Any loadout changes will be applied to the next mission.": "此任务使用的武装配置已经选定。对武装配置作出的更改将在下一场任务中生效。", + "Tier 1": "1阶", + "Dust Devils Detected": "侦测到尘卷风", + "ANGEL'S VENTURE UNDER ATTACK\nThe Terminids have attacked Angel's Venture. All available Helldivers are called to defend it.": "天使投资星系遭到袭击\n终结族对天使投资星系发动了袭击。呼唤全体可行动的绝地潜兵前去防卫。", + "Character": "角色", + "VANDALON IV LOST\nVandalon IV has fallen to the Automatons. We cannot allow this travesty to go unanswered.": "万达隆IV沦陷\n万达隆IV已落入机器人的铁爪。我们不能任由这一闹剧继续发展。", + "Something went wrong, invalid upgrade.": "发生意外,升级无效。", + "Reinforce available": "增援就位", + "INGMAR FREED\nIngmar has been freed from the Automatons. Take the fight to the next planet.": "英格玛已解放\n英格玛已经挣脱了机器人的铁爪。该去下一颗星球作战了。", + "High-Five": "击掌", + "Approaching edge of mission area. Return to the mission, or be branded a traitor.": "正接近任务区域边缘。请折返执行任务,否则你将被认定为叛徒。", + "ACCOUNTING CORRECTIONS": "核算修正", + "Current Major Order": "当前重要指令", + "Pick up BACKPACK.": "拾起背包。", + "SEASON I": "第I赛季", + "STORAGE": "存储", + "Steam account not allowed to login. Please contact Community managers": "Steam账号禁止登录。请联系社区管理员", + "SMOKE": "烟雾弹", + "PROGRESS IS MANDATORY": "必须进步", + "Helmet": "头盔", + "INTEL": "情报", + "#NAME has been court-martialed": "#NAME已被移交军事法庭", + "INCENDIARY": "燃烧弹", + "MEDIUM": "中型", + "SHUTTLE DEPARTING": "运输船即将出发", + "Drop #ENTITY": "投放#ENTITY", + "DIFFICULTY 6 TRIAL": "难度6级考验", + "#NAME: #MESSAGE": "#NAME: #MESSAGE", + "An ENCOUNTER is approaching. Use your STRATAGEMS!": "一场遭遇战即将开始。使用你的战略配备吧!", + "TRAITOR DETECTED": "发现叛徒", + "HOLD": "按住", + "Enter a HELLPOD to start the mission.": "进入绝地喷射舱,开始任务。", + "L. ARM": "左臂", + "Unavailable": "不可用", + "WEAPON EXPERIMENTATION\nThe Orbital EMS Strike stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“轨道电磁冲击波攻击”战略配备暂时获准供全体绝地潜兵使用。", + "HEAVY ARMOR PENETRATING": "重甲穿透", + "DRAUPNIR UNDER ATTACK\nThe Automatons are invading Draupnir. Rally to its defense!": "德罗普尼尔遭到袭击\n机器人当前正在入侵德罗普尼尔,速速集结,前去保卫该星球!", + "FRACTURED": "骨折", + "W (#COUNT°)": "西#COUNT°", + "Squad Saves": "小队救援次数", + "S": "南", + "CRIMSICA FREED\nCrimsica has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet.": "克里姆西卡已解放\n克里姆西卡挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。", + "READY": "就位", + "READY UP": "准备就绪", + "Total XP Earned": "所获总经验值", + "Injecting Freedom Protocols (#COUNT remaining)": "注入自由协定(还剩#COUNT)", + "LOCAL STORAGE": "本地存储", + "QUIT GAME": "退出游戏", + "Extract as soon as possible. When the SUPER DESTROYER departs, you will no longer have access to STRATAGEMS.": "尽快撤离。超级驱逐舰离开后,你将无法再使用战略配备。", + "Deploying without ammo will force you to scavenge it during the mission.": "如果部署时不携带弹药,你将被迫在任务期间设法搜集弹药。", + "WEAPON EXPERIMENTATION\nThe Orbital Railcannon stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“轨道炮”战略配备暂时获准供全体绝地潜兵使用。", + "PLANET SAVED\nThanks to the unfailed valor of the Helldivers, the Automatons have been repelled from one of our planets. A glorious day for Freedom.": "星球已获救\n在从不失手的绝地潜兵的英勇付出下,我们已将机器人从我方的其中一颗星球逐出。今天又是自由伟业光荣的一天。", + "Difficulty": "难度", + "Inside of PLACES OF INTEREST you can find SUPPLIES and SAMPLES.": "你可以在特殊地点找到补给和样本。", + "Exit": "退出", + "Dropping in": "正在降落", + "STRIKE": "打击武器", + "MUTATED EGG": "变异虫卵", + "MARKSMAN RIFLE": "精确射手步枪", + "PREPARING DEMOCRACY": "准备播撒民主", + "HEAVY": "重型", + "Debug UI": "测试UI", + "SHUTTLE DISPATCHED FROM SHIP": "运输船离开飞船", + "MAGAZINE": "弹匣", + "RETURN TO THE COMBAT ZONE: #SECONDS": "返回作战区域:#SECONDS", + "Medium": "中型", + "A new Major Order has been issued. Check the Galactic Map for more information.": "一项重要指令已发布。查看星系地图了解更多信息。", + "FENRIR III DEFENDED\nAfter countless noble and unavoidable sacrifices, Fenrir III has been defended from the Terminids.": "成功保卫芬里尔III\n无数不可避免的光荣牺牲终于换来回报,我们顺利从终结族手下守住了芬里尔III。", + "VANDALON IV FREED\nVandalon IV has been freed from the Automatons. Take the fight to the next planet.": "万达隆IV已解放\n万达隆IV已经挣脱了机器人的铁爪。该去下一颗星球作战了。", + "LOADOUT": "武装配置", + "TORSO": "躯干", + "Signed in as:": "登录身份:", + "Light Illuminate Encampment Cleared": "光能者轻型营地成功摧毁", + "Fire": "灼烧", + "DELIVER": "送达", + "SIGNAL LOST": "信号丢失", + "Confidential Data": "机密数据", + "EMOTE": "表情", + "HOLD TO CLAIM ITEM": "按住领取物品", + "MISSION FAILED": "任务失败", + "Fighting Terminids": "抗击终结族", + "Unsafe": "不安全", + "Thorns": "尖刺", + "SCROLL": "滚动", + "Civilian resistance units have taken significant ground from the enemy on Planet #V_ONE. The freedom fighters have been recognized for their duty and rewarded with proper drafting into the SEAF.": "平民抵抗组织在#V_ONE星球上从敌方手上夺下重要阵地。这群自由战士的功绩得到了认可,也获得了适当的奖赏:收编进入超级地球武装部队。", + "MUZZLE": "枪口", + "Both of your legs are injured, severely impairing your movement.": "你的双腿都受伤了,你的移动能力将受到严重影响。", + "Call in a RESUPPLY to refill your AMMUNITION and STIMS.": "呼叫重新补给,补充弹药和治疗剂。", + "ERATA PRIME SECURED\nThe Terminid Control System is now fully activated on Erata Prime.": "成功占领艾拉特主星\n终结族遏制体系已经在艾拉特主星全面启动。", + "SSW": "西南偏南", + "+#COUNT SAMPLE": "+#COUNT份样本", + "ENTER TURRET": "进入炮台", + "TEAM WEAPON BACKPACKS allow you to reload support weapons. This is most efficient when working with a teammate.": "携带团队武器背包可以为支援武器重新装填弹药。这是与队友合作时效率最高的做法。", + "Bleeding": "出血", + "Failed to establish network connection.": "无法建立网络连接。", + "Complex Stratagem Plotting": "复杂的战略配备部署流程", + "Syncing Server Data": "正在同步服务器数据", + "Dead": "死亡", + "NW": "西北", + "You have commended other players five times during this mission. You can offer more commendations in the next mission.": "本次任务你已称赞了其他玩家五次,下一次任务可以继续称赞他人。", + "Out of Grenades! Call in a Resupply to replenish.": "榴弹耗尽!呼叫重新补给进行补充。", + "Increase your contribution to The War and your opportunities for additional rewards!": "增加你对战争的贡献和获得额外奖励的机会!", + "EQUIPPED BY": "已装备", + "A SAMPLE FOR YOUR TROUBLES": "浅尝麻烦", + "#WEAPON LVL #CURRENT/#MAX": "#WEAPON等级#CURRENT/#MAX", + "TURING DEFENDED\nThe bugs have been repelled from Turing. Citizens across the planet hold celebrations in honor of the Helldivers' heroism.": "成功保卫图灵\n我们已将虫族逐出图灵。全星球的公民一起举办了庆典活动,纪念绝地潜兵的英勇之举。", + "#COUNT Medals": "#COUNT枚奖章", + "ESTANU UNDER ATTACK\nTerminid spores fill the skies of Estanu. All Helldivers are called to the planet's defense!": "伊斯塔努遭到袭击\n终结族孢子遍布伊斯塔努上空。呼唤全体绝地潜兵,前去保卫该星球!", + "INSERT AMMO": "插入弹药", + "DIFFICULTY 3 TRIAL": "难度3级考验", + "SHOW KEYBOARD BINDINGS": "显示键位绑定", + "MELEE": "近战", + "ENEMY UNIT": "敌方单位", + "LIBERATION FAILED\nThe bots retain their iron grip on Draupnir.": "解放失败\n机器人依然牢牢掌控着德罗普尼尔。", + "Common Sample": "普通样本", + "MAJOR ORDERS": "重要指令", + "TURING SECURED\nThe Terminid Control System is now fully activated on Turing.": "成功占领图灵\n终结族遏制体系已经在图灵全面启动。", + "TERMINID SURGE\nMinistry of Science reports an unanticipated spike in Terminid spore counts. Expect a severe increase in resistance on Terminid planets.": "终结族势力激增\n科学部通报,终结族孢子数量意外激增,预计各终结族星球的反抗力度将大幅加剧。", + "FFB1B1B1": "FFB1B1B1", + "RESET": "重置", + "100 SC": "100超级货币", + "The Illuminate invasion fleet, constructed in secret behind the veil of the Meridian Wormhole. It is headed for Super Earth itself.": "在默里迪恩虫洞掩护下秘密建造的光能者入侵舰队。目前正向超级地球进发。", + "Call in a Resupply when low on ammo.": "弹药不足时可呼叫重新补给。", + "x10 Rare Samples": "x10稀有样本", + "SELECT OPERATION": "选择行动", + "Cape": "披肩", + "#COUNT": "#COUNT", + "This item is already owned.": "你已拥有此物品。", + "COMBAT (BOTS)": "作战(机器人)", + "You have insufficient funds to purchase this item.": "资金不足,无法购买此商品。", + "#AMOUNT": "#AMOUNT", + "DSS Orbital Bombardment in #MINUTES:#SECONDS": "民主空间站轨道轰炸来袭倒计时:#MINUTES:#SECONDS", + "Throw GRENADE into FACTORY to destroy it.": "把榴弹丢进工厂,将其摧毁。", + "#COUNT km": "#COUNT公里", + "990C0A05": "990C0A05", + "Unable to authenticate your account on Microsoft, please try again later or contact support if this error persists.": "无法验证你的Microsoft账号,请稍后重试。如果问题仍未解决,请联系客服。", + "Failed to get a Token for PlayStation™Network": "无法获得PlayStation™Network令牌", + "You are able to requisition STRATAGEM PERMITS. Exit the menu when you're done.": "你现在可以申购战略配备许可证。完成后退出菜单。", + "CHANGE BUTTON AND ACTIVATE": "更改按键并启动", + "RECEIVED: TODAY": "接收:今天", + "WEAPON EXPERIMENTATION\nThe Mortar Sentry stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“迫击哨戒炮”战略配备暂时获准供全体绝地潜兵使用。", + "The Advanced Liberation Tools Research Agency (ALTRA) has completed final approval of a new combat asset: the EXO-45 PATRIOT EXOSUIT. Models are anticipated to be available for requisition within a week.": "先进解放工具研究局(ALTRA)开发的新型作战装备:EXO-45“爱国者”外骨骼装甲已通过最终审核,样机将在一周内开放申购。", + "STRATEGIC ADVISORY\n\nThe Automaton Jet Brigade has been spotted on several planets.": "战略警报\n\n在数个星球发现机器人喷气旅。", + "Underbarrel": "下挂", + "R/G/B": "R/G/B", + "This is where you upgrade your Destroyer to better support you in the field. Upgrading modules will improve the effectiveness of stratagems you already own.": "你可以在这里升级自己的驱逐舰,以便在战场上为你提供更有利的支援。升级模块将提高已有战略配备的效能。", + "Make Snowball": "捏雪球", + "EQUIPPING": "正在装备", + "/ #CAP": "/ #CAP", + "Season I": "第I赛季", + "MERIDIA DEFENDED\nAfter countless noble and unavoidable sacrifices, Meridia has been defended from the Terminids.": "成功保卫默里迪亚\n无数不可避免的光荣牺牲终于换来回报,我们顺利从终结族手下守住了默里迪亚。", + "Convoy Destination": "车队目的地", + "Safe": "安全", + "ESE": "东南偏东", + "#SECONDS sec": "#SECONDS秒", + "WEAPON EXPERIMENTATION\nThe FLAM-40 Flamethrower stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“FLAM-40火焰喷射器”战略配备暂时获准供全体绝地潜兵使用。", + "WEAPON EXPERIMENTATION\nThe Tesla Tower stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“特斯拉塔”战略配备暂时获准供全体绝地潜兵使用。", + "#MINS:#SECS": "#MINS:#SECS", + "Switch Headlight Mode": "切换大灯模式", + "Mutated Egg": "变异虫卵", + "SCISSORS": "剪刀", + "sudden loss of health": "生命值骤减", + "You have insufficient progression to purchase this item.": "进度不足,无法购买此商品。", + "Unanticipated Automaton reinforcements have taken significant ground on Planet #V_ONE.": "突如其来的机器人增援部队在#V_ONE星球上占领了重要阵地。", + "DESTROYER": "驱逐舰", + "The unjust wave of Illuminate migration following the Void surge has been slowed, thanks to the quick response of Helldivers in the region. No additional planets have fallen, but little information about how to penetrate the Void has been revealed. The Ministry of Science indicates that the mindless masses that come from the Void may have valuable information about what lies on the other side.": "多亏了该地区绝地潜兵的快速响应,伴随寂域激增的不义光能者移民浪潮已放缓。没有更多星球陷入寂域,但关于穿透寂域的方法几乎没有新信息。科学部指出,源自寂域的无脑群氓可能掌握着关于“另一边”的宝贵情报。", + "Fresh SEAF recruits filled with patriotic fervor for the destruction of the Automatons have surged to take significant ground on Maia.": "满腔爱国热情、誓要摧毁机器人的超级地球武装部队新进后备军已经在昴宿四占领了重要阵地。", + "[THIS TEXT IS NOT IMPLEMENTED]": "[文本未应用]", + "LIBERATION FAILED\nOur efforts to purge Hellmire of the Terminid presence have failed.": "解放失败\n我们将终结族彻底驱逐出海尔迈尔的行动宣告失败。", + "Toxic Gas": "毒气", + "MANUALLY raise SILO LOCKS.": "手动拉起舱门锁。", + "Enemy Wave Detected": "侦测发现敌人来袭", + "Disintigration Beam": "裂解激光", + "Use REINFORCE to call in dead teammates.": "使用增援呼叫已牺牲的队友。", + "Arm Patch": "手臂贴布", + "Activating these Reinforcement Pods increases your Reinforcement Budget. \n\nReinforcements will deploy directly from a Reinforcement Pod site.": "启动增援太空舱会增加你的增援预算。\n\n增援部队将直接从增援太空舱的位置部署。", + "You have attained the rank of ASPIRANT.": "你已成为志士。", + "Illuminate Kills": "光能者击杀数", + "TRIGGER": "扳机", + "DRAUPNIR LOST\nThe Automatons have taken Draupnir. A dark day for Managed Democracy.": "德罗普尼尔沦陷\n机器人已然占领德罗普尼尔,这是管理式民主史上黑暗的一天。", + "DOUBLE TAP": "连按两次", + "Medium Illuminate Encampment Cleared": "光能者中型营地成功摧毁", + "ACHERNAR SECUNDUS FALLEN\n\nAchernar Secundus has fallen to the Terminids. The AM Defense Factory Hub has been evacuated; FRV cooldown will be increased for #VALUE hours.": "水委一次星沦陷\n\n水委一次星不幸被终结族攻占。虎将国防工厂中心已完成撤离,快速侦察载具的冷却时间将延长#VALUE小时。", + "Deaths": "死亡次数", + "PLANET LOST\nOur defenses have failed. The Terminids infest another Super Earth planet.": "星球沦陷\n我们的防线崩溃,终结族又占领了超级地球的一颗星球。", + "STATS": "数据", + "WARBOND PROGRESSION": "战争债券进度", + "An internal error occurred during the purchase, please try again later or contact support if this error persists.": "购买过程中发生内部错误,请稍后重试。如果问题仍未解决,请联系客服。", + "R&D UPDATE": "研发更新", + "REVERTING": "撤销中", + "XP": "经验", + "debug damage": "测试伤害", + "Burning": "灼烧", + "RIGHT SHOULDER": "右肩", + "INSUFFICIENT CURRENCY": "货币不足", + "DEPLETED": "耗尽", + "Requisition: #COUNT": "征用:#COUNT", + "Enter combination to equip STRATAGEM, then throw the BEACON to activate.": "输入密码,装备战略配备,然后投掷信标将其启动。", + "#PERCENTAGE%": "#PERCENTAGE%", + "D-pad": "方向键", + "Heavy": "重型", + "B3FFFBD8": "B3FFFBD8", + "ERROR #ID": "错误#ID", + "Legend": "传奇", + "Dispatch": "报告", + "This massive infestation contains a rare mutated egg of high value to Terminid research. Extract with it, and your support of scientific advancement will be rewarded.": "此处大型侵染扩张的虫群里有一颗稀有的变异虫卵,对终结族的研究价值颇高。携带该虫卵撤离,你对科研的支持工作将获得相应回报。", + "SHUTTLE ARRIVES IN T-#MINS:#SECS:#HUNDREDTHS": "运输船抵达倒计时 #MINS:#SECS:#HUNDREDTHS", + "You've unlocked a new PRIMARY WEAPON. Return to the DEMOCRACY OFFICER for your next MISSION.": "你已解锁一件新的主武器。返回民主官处开展下一项任务。", + "Establishing Up-link to Host Ship": "正在建立上链以加入主办者舰船", + "WEAPON EXPERIMENTATION\nThe Heavy Machine Gun Emplacement stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“重机枪部署支架”战略配备暂时获准供全体绝地潜兵使用。", + "If no Helldiver is alive to reinforce you, additional reinforcements will automatically be dispatched, if the budget allows.": "如果增援的绝地潜兵全部阵亡,在预算允许的情况下,会自动派遣额外的增援。", + "EXTRACTION LANDED": "撤离飞船着陆", + "Radar Wagon": "雷达车", + "From this terminal you can acquire new stratagems and upgrade your destroyer. \nYou can use this terminal to manage your Destroyer regardless of which vessel you are currently on.": "通过此终端可以获取新战略配备并升级你的驱逐舰。\n无论身处哪艘舰船,你都可以使用此终端管理自己的驱逐舰。", + "#NAME invited you to join a Clan": "#NAME邀你加入中队", + "HEETH UNDER ATTACK\nThe bugs have attacked Heeth. Rally to its defense, before they are able to permanently infest it.": "希斯遭到袭击\n虫族对希斯发动了袭击。立即集结,前去防卫,避免领地永远落入敌人手里。", + "Hive": "虫窝", + "INGMAR UNDER ATTACK\nThe Automatons are attempting to steal Ingmar from our noble citizens. Do not let them, Helldivers.": "英格玛遭到袭击\n机器人企图从我们高贵的公民手中窃走英格玛,不要让它们得逞,绝地潜兵。", + "Mission starting, Helldivers to Hellpods!": "任务开始,请绝地潜兵到喷射舱集合!", + "Super Earth's price index is undergoing fluctuation; please review the current pricing info and re-issue your requisition.": "超级地球的物价指数目前忽起忽落。请核实当前的价格信息,然后重新申购。", + "KNOW YOUR ENEMY": "知己知彼", + "SIGNAL STRENGTH": "信号强度", + "NEW TARGET": "新目标", + "Change Button": "更改按键", + "#CURRENT_XP / #NEXT_XP": "#CURRENT_XP / #NEXT_XP", + "#NAME left the mission": "#NAME退出任务", + "EXTRACTION TAKEOFF": "撤离飞船起飞", + "CYBERSECURITY UPDATE\nA recent systems security breach has resulted in Galactic War tables displaying inaccurate information. The breach has been addressed, and all systems have been returned to normal operation. Any discrepancies are to be considered the result of dissident misinformation.\n\nRest assured that the parties responsible have been identified, arrested, tried, and executed.": "网络安全更新\n最近发生的系统安全漏洞攻击事件导致星系战争的议战桌显示信息有误。该漏洞现已修复,所有系统均已恢复正常运行。任何不一致之处均将被视为异见者扭曲信息的结果。\n\n肇事者已探明、逮捕、审判和处决,敬请放心。", + "MUTATED EGGS": "变异虫卵", + "NNW": "西北偏北", + "Resuming Hosting.": "正在恢复主办者状态。", + "Super Destroyer withdraws in #MINUTES:#SECONDS": "超级驱逐舰撤离倒计时 #MINUTES:#SECONDS", + "Planetary Bombardment": "星球轰炸", + "CHARGE": "充能", + "NNE (#COUNT°)": "东北偏北#COUNT°", + "ONGOING #MM#M:#SS#S": "正在进行 #MM#M:#SS#S", + "INTELLIGENCE BRIEF\n\nAs anticipated, the Automatons have deployed a new gunship-style unit on all battlefronts. It was only a matter of time before their totalitarian conquest expanded skyward. \n\nFortunately, due to the advance warning provided by the communication array on Troost, Helldiver arsenals have been augmented to combat this threat. Helldivers will continue to find the EAT-17 Expendable Anti-Tank Stratagem included in all loadouts for the near future.": "情报简报\n \n不出所料,机器人已在所有战场前线部署一种新型炮舰式单位。它们迟早会把极权主义的铁爪伸向我们的领空。\n \n万幸的是,特鲁斯特上的通讯阵列已提前发出警告,绝地潜兵武器库得以及时扩充,以应对此次危机。未来一段时间内,绝地潜兵的全部武装配置都将继续追加“EAT-17消耗性反坦克武器”战略配备。", + "Mutated Eggs": "变异虫卵", + "Buy (RQ)": "购买(申购点)", + "SKN": "涂装", + "POISON": "剧毒", + "SLOWED": "减速", + "Barbed Wire": "倒刺铁丝网", + "Hold": "按住", + "x10 RARE SAMPLES": "x10稀有样本", + "ERATA PRIME LOST\nThe defense of Erata Prime has failed. Terminids now run amok on its surface. We cannot allow this corruption of Liberty to stand.": "艾拉特主星沦陷\n艾拉特主星保卫战已宣告失败。终结族现在正四处肆虐。我们不能任由它们继续侵犯自由伟业。", + "TERMINID INVASION\nThe bugs are attempting to spread to another one of our planets. We must drive them off! Report to the Galactic Map for more information.": "终结族入侵\n虫族企图扩张至我们的另一颗星球。我们必须驱逐它们!通过星系地图报到,了解更多信息。", + "WEAPON EXPERIMENTATION\nThe Eagle 500kg Bomb stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“‘飞鹰’500kg炸弹”战略配备暂时获准供全体绝地潜兵使用。", + "Tier 2": "2阶", + "Requisition ORBITAL SHELL stratagem.": "申购轨道炮弹战略配备。", + "Helldivers operate against the clock. Complete your mission before the SUPER DESTROYER leaves low orbit.": "绝地潜兵的行动必须争分夺秒。要在超级驱逐舰离开低空轨道前完成任务。", + "Return to the DEMOCRACY OFFICER.": "返回民主官处。", + "NOT ENOUGH MEDALS": "奖章不足", + "PHASE 1": "第1阶段", + "RELEASE": "松开", + "Account for PlayStation™Network not allowed to login. Please contact Community managers": "账号禁止登录PlayStation™Network。请联系社区管理员", + "Playfab Session Ticket Validation Error": "Playfab会话票据验证错误", + "GALACTIC WAR": "星系战争", + "INTERACT": "互动", + "Shuttle approaching.\nDefend extraction zone.": "运输船即将驶近。\n请在撤离区坚守。", + "[#NAME]": "[#NAME]", + "Open the SOCIAL MENU. Here you can see your friends' activities and JOIN A MISSION.": "打开社交菜单。你可以在这里查看好友的动态,并且加入任务。", + "Searching for active SOS beacons...": "正在寻找激活的S.O.S.求救信标…", + "LEGENDARY WARBOND NEEDED": "需要传奇战争债券", + "On Main Menu": "浏览主菜单", + "WEAPON EXPERIMENTATION\nThe Orbital 380mm HE Barrage stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“轨道380mm高爆弹火力网”战略配备暂时获准供全体绝地潜兵使用。", + "to adjust relay dish": "调整中继天线", + "LEGENDARY": "传奇", + "Level #LEVEL | #TITLE": "#LEVEL级 | #TITLE", + "Failed to join game lobby, Timed out.": "无法进入游戏大厅,已超时。", + "ATTACKING": "攻击", + "PRESS": "按下", + "SELECT REINFORCEMENT LOCATION": "选择增援地点", + "GRENADE": "榴弹", + "NOTICE": "通知", + "#ITEM": "#ITEM", + "REWARD": "奖励", + "MOVE CURSOR": "移动光标", + "ENCYCLOPEDIA": "百科全书", + "There is already another upgrade request on flight, try again in a few seconds.": "正在处理另一项升级请求,请稍后再试。", + "ARC": "电弧", + "COMING SOON!": "即将上线!", + "AMMO TYPE": "弹药种类", + "HEAVY COMBAT (BOTS)": "重型作战(机器人)", + "ANGEL'S VENTURE DEFENDED\nThanks to the selfless valor of the Helldivers, the citizens of Angel's Venture are safe from the Terminid Menace.": "成功保卫天使投资星系\n在无私的绝地潜兵的英勇付出下,天使投资星系的公民终于摆脱了终结族的威胁。", + "Mk5b 'Tactical'": "Mk5b“战术”", + "NEW": "全新", + "Release": "松开", + "Unable to join game": "无法加入游戏", + "ERATA PRIME UNDER ATTACK\nTerminid spores fill the skies of Erata Prime. All Helldivers are called to the planet's defense!": "艾拉特主星遭到袭击\n终结族孢子遍布艾拉特主星上空。呼唤全体绝地潜兵,前去保卫该星球!", + "New equipment has now been deployed to every Super Destroyer in the galaxy. Use it to deliver Freedom, Helldivers.": "新装备现已部署至银河系所有的超级驱逐舰上。绝地潜兵,请尽情使用,传播自由。", + "MAJOR ORDER FAILED": "未完成重要指令", + "WEAPONS": "武器", + "ERATA PRIME DEFENDED\nThe bugs have been repelled from Erata Prime. Citizens across the planet hold celebrations in honor of the Helldivers' heroism.": "成功保卫艾拉特主星\n我们已将虫族逐出艾拉特主星。全星球的公民一起举办了庆典活动,纪念绝地潜兵的英勇之举。", + "FF71F5FF": "FF71F5FF", + "FEWER STIMS": "治疗剂减少", + "Grenade Kills": "榴弹击杀数", + "RECEIVED: YESTERDAY": "接收:昨天", + "300 SC": "300超级货币", + "Patrols sound the alarm which causes ENCOUNTERS!": "巡逻队会发出警报,引发遭遇战!", + "NO AMMO": "没有弹药", + "PURCHASE MEDALS": "购买奖章", + "Do you want to replay the tutorial mission?": "要重新执行教程任务吗?", + "DIFFICULTY 7 TRIAL": "难度7级考验", + "Some targets are HEAVILY ARMORED. Hit weak spots or use armor-piercing weapons!": "部分目标装备了重型护甲。要攻其弱点或是使用穿甲武器!", + "ABANDON MISSION WITH SQUAD": "与小队放弃任务", + "Select your Drop Location anywhere on the mission map - Try to avoid dangerous locations.": "在任务地图上选择任意降落地点,尽量避开危险地点。", + "#SECONDS SEC": "#SECONDS秒", + "COMBAT (ILLUMINATE)": "作战(光能者)", + "VELD DEFENDED\nThe defense of Veld has succeeded. The Terminids have been repelled.": "成功保卫维尔德\n维尔德保卫战以胜利告终,终结族已被击退。", + "ENEMY RETREAT": "敌军撤退", + "Light Bug Nest Eradicated": "轻型巢穴成功摧毁", + "You have new rewards to collect!": "你有新的奖励可以领取!", + "MAIN MENU": "主菜单", + "Medium Automaton Outpost Destroyed": "中型机器人哨站成功摧毁", + "Premium": "尊享", + "Fangs": "尖牙", + "The Illuminate masses overwhelmed the Helldiver forces and spread unchecked to planetX. The loss of these planets mean that strategic resources to Helldivers may encounter logistic issues, please report to your Ship Master for more information. \n\nIf the spread is not contained here, it is not an exaggeration to assume that mindless masses could be walking the streets of Super Earth within weeks.": "光能者群氓势头力压绝地潜兵部队,并肆无忌惮地蔓延至X星。这些星球的沦陷可能导致战略资源的后勤供应受阻,请向您的舰长报告以获取更多信息。\n\n如果不遏止这一蔓延,数周之内,无脑群氓大军可能会出现在超级地球的街道。", + "Perfect Bonus": "完美加分", + "Samples Collected": "收集样本数", + "NO SERVERS": "无服务器", + "Damage Type: #DAMAGE_TYPE": "伤害类型:#DAMAGE_TYPE", + "DECIMATING THE ENEMY": "横扫千军", + "PAGE_#PAGE_NUMBER": "第#PAGE_NUMBER页", + "Auto": "自动", + "Drowning": "淹溺", + "Explosive Handshake": "热烈握手", + "Throw GRENADES into bug nests to destroy them.": "把榴弹丢进虫族巢穴,将其摧毁。", + "Failed to join game lobby, Helldiver in training.": "无法进入游戏大厅,绝地潜兵正在训练。", + "Failed to join as target host is currently in a single-player session.": "目标主办者当前设定为单人游戏模式,加入失败。", + "BACK-PACKING A PUNCH": "重拳出击", + "VEHICLE PATTERN": "载具涂装", + "Each Planet has a number Operations available. Complete Operations to reduce enemy presence and earn rewards.": "每颗星球都设有一定数量的行动。完成行动即可削弱敌方势力,获得奖励。", + "ARMORY": "防具", + "OPACITY": "不透明度", + "to switch between PRIMARY and SUPPORT WEAPON.": "切换主武器和支援武器。", + "Distribute Ballots": "派发选票", + "STANDARD WARBOND": "标准战争债券", + "#COUNT DAYS AGO": "#COUNT天前", + "Up Button": "上方向键", + "FLY LIKE AN EAGLE": "鹰击长空", + "[none]": "[无]", + "DEMOCRACY TERMINAL": "民主终端", + "ERROR": "错误", + "W": "西", + "MANTES LOST\nThe defense of Mantes has failed. We cannot allow the Automaton aggression to continue.": "蒙特斯沦陷\n蒙特斯的防线已经崩溃,我们不能任由机器人继续进犯。", + "Common Samples": "普通样本", + "Exalted Hero": "伟人", + "Environment": "环境", + "RECHARGING": "正在充能", + "Defend Area": "守卫区域", + "to place a waypoint on the map": "在地图上标记路径点", + "SELECT SLOT": "选择槽位", + "SEAF Artillery Ammo Rack": "超级地球武装部队炮弹挂架", + "Join this server and travel to their ship?": "要加入本服务器并登上对方的飞船吗?", + "CONTROL CENTER": "控制中心", + "WEAPON PROGRESSION": "武器进阶", + "OBJECTIVE UPDATED": "目标已更新", + "INBOUND #MM#M:#SS#S": "即将抵达 #MM#M:#SS#S", + "#COUNTrpm": "#COUNT RPM", + "COLOR PICKER": "选取颜色", + "JOIN FAILED": "加入失败", + "R. LEG": "右腿", + "Reinforce Stratagems Used": "增援战略配备使用次数", + "INTO THE GALAXY": "向星系进发", + "WNW": "西北偏西", + "NNE": "东北偏北", + "SUPERSTORE": "超级商店", + "The voteless have taken planetX and planetY by sheer numbers, but they haven’t broken the spirit of the Helldiver resistance. \n\nThe Illuminate, who will only be satisfied when the galaxy bends to their liberal will, may think that they are victorious against the forces of Super Earth - but they could never know the hot-blooded Democratic drive for vengeance. That will be their downfall. Helldivers take back what is ours and if that means cleaning squid guts from the tire tracks of our FRV fleet, so be it.": "无票者凭借绝对的数量优势占领了X星和Y星,但未能击垮绝地潜兵的抵抗意志。\n\n只有当整个星系都屈服于光能者的自由意志时,他们才会心满意足。他们或许认为已经战胜超级地球的军队——但他们永远无法理解激荡着热血的民主复仇渴望。而这将令他们走向覆灭。绝地潜兵定会夺回属于我们的东西。如果需要从快速侦察载具车队的轮胎印里清理鱿鱼内脏,那就这么办吧。", + "CONFIRM": "确认", + "Platoon": "特战排", + "Talk to the DECK OFFICER.": "与舱面事务官对话。", + "Spend your RESEARCH POINT to ADVANCE your HELLDIVER PROGRESSION TRACK.": "花费研究点数,推进绝地潜兵进度条。", + "EXPLOSIVE": "炸弹", + "STIM": "治疗剂", + "HIGH-FIVE": "击掌", + "Extraction Zone": "撤离区", + "Due to an unexpected pilot shortage, extraction times will be longer than normal for the near future.": "由于驾驶员意外短缺,近期的撤离行动耗时较平时有所延长。", + "SUPER CREDITS": "超级货币", + "TEMPORARY PERMIT": "临时许可", + "to aim": "瞄准", + "Optics": "准镜", + "LIBERATION FAILED\nWe have failed to cleanse Heeth of the Terminid infestation.": "解放失败\n我们未能彻底剿灭占据希斯的终结族。", + "LEFT SHOULDER": "左肩", + "TRANSFER STATION": "中转站", + "#COUNT/#TOTAL": "#COUNT/#TOTAL", + "TOGGLE INFO": "切换详情", + "Connection regained.": "连接已恢复。", + "No Broken Limbs": "四肢没有受伤", + "DROP LOCATION": "降落地点", + "HELLMIRE DEFENDED\nAfter countless noble and unavoidable sacrifices, Hellmire has been defended from the Terminids.": "成功保卫海尔迈尔\n无数不可避免的光荣牺牲终于换来回报,我们顺利从终结族手下守住了海尔迈尔。", + "MAP PING": "地图标记", + "MALEVELON CREEK HAS BEEN LIBERATED\nAt long last, Malevelon Creek is free. The Automaton's iron grip on the planet has been pried loose. The war-torn planet will forever bear the scars of its struggle, and the sacrifices of the countless heroes lost there will never be forgotten.\n\nColonists are returning to the ruins of their settlements, but with hope in their chests. For at last, sunlight dawns upon a free Creek.": "麦拉芬蒙河已得到解放\n麦拉芬蒙河终于得到解放,从机器人的铁爪掌控下挣脱。这颗饱受战争折磨的星球将永远背负血汗的疮疤,无数陨落英雄的牺牲也将被铭记。\n\n拓殖地居民陆续返回定居点的废墟,但此刻,他们心怀希望。阳光总算照亮了这方大地。", + "Out of Stims! Call in a Resupply to replenish.": "治疗剂耗尽!呼叫重新补给进行补充。", + "FFFFFF5E": "FFFFFF5E", + "Due to unmet Helldiver training quotas, personnel loss will need to be decreased for the short term. Therefore, Helldivers will deploy with increased stims until further notice.": "由于绝地潜兵训练指标未能达成,短期内需要减少人员损失。因此,绝地潜兵将携带更多治疗剂奔赴战场,直至另行通知为止。", + "RESUME": "继续游戏", + "Go to the Ship Management Terminal to acquire new Stratagems and upgrade your Destroyer.": "前往舰船管理终端获取新的战略配备,以及升级驱逐舰。", + "MAJOR ORDER FAILED\nWe have failed to fully activate the Terminid Control System. Until we do, the Terminids will continue to slip through the cracks, spreading their tyranny to the backyards of our innocent citizens.": "重要指令未完成\n终结族遏制体系未能全面启动。终结族将继续穿过裂缝,将暴政传播至无辜公民的后院,直至遏制体系成功启动为止。", + "SKIP": "跳过", + "MEDALS RECEIVED": "已收到奖章", + "33FFFEE1": "33FFFEE1", + "RESPAWN IN": "复活倒计时:", + "Do you want to quit the game?": "要退出游戏吗?", + "Left Stick": "左摇杆", + "Are you sure you want to use your Warbond Token to unlock \"#WARBOND\" Premium Warbond?": "是否确定要使用战争债券代币解锁“#WARBOND”尊享战争债券?", + "RESET TO DEFAULT": "重置为默认", + "Throwable Weapon": "投掷武器", + "Mouse Wheel": "鼠标滑轮", + "TRAVEL": "前往", + "This is the ship's armory. Here you can get an overview of the ship's arsenal and prepare for the next mission.": "这里是舰船的军械库。在这里你可以了解这艘舰船上的军火储备概况,为下一项任务做准备。", + "LASER GUIDE": "激光制导", + "STRATAGEMS": "战略配备", + "MULTIPLAYER": "多人游戏", + "Bug Breach Detected": "侦测发现虫族入侵", + "to use a Stim on yourself": "对自己使用治疗剂", + "HELLDIVERS TO HELLPODS": "绝地潜兵进入绝地喷射舱", + "BUY PREMIUM WARBOND": "购买尊享战争债券", + "You have sustained an INJURY. Injuries make you move slower, aim worse or can even make you bleed to death.": "你受到了损伤。损伤会降低你的移动速度,削弱你的瞄准能力,甚至有可能导致流血至死。", + "The Mindless Masses continue to emerge from the Void with persistent arrogance. Continue to cull the voteless near the Void while holding planetX and planetY against the Illuminate. The more Illuminates that fall, the greater chance Super Earth scientists will be able to find a way to penetrate the Void and bring the fight to them. \n\nThe FRV campaign has been highly effective against the mindless masses. However, Helldivers are needed to acquire precious metals to support production demands of FRVs called to the front. These resources are found by melting down the carcasses of the unfeeling Automaton units - for every Bot cut down in combat, a Helldiver is that much closer to joyriding a new FRV over the bodies of countless Illuminate. A cause worth fighting for.": "无脑群氓带着傲慢不停地从寂域中涌出。在寂域周边继续剿杀无票者,同时坚守X星和Y星,抵御光能者侵略。倒下的光能者越多,超级地球的科学家们就越有可能找到穿透寂域、直捣其大本营的方法。\n\n快速侦察载具在对抗无脑群氓方面卓有成效。为了支持前线的生产需求,我们需要绝地潜兵获取贵金属。通过熔毁冷血机器人部队的残骸可以获得这些资源——每砍翻一个机器人,绝地潜兵就更接近驾驶崭新快速侦察载具,体验碾压光能者尸体的快感。这是一项值得为之战斗的事业。", + "EQUIP": "装备", + "Paste in a friend code to start searching.": "粘贴好友代码,开始搜索。", + "Player Card": "玩家名片", + "RPM": "转速", + "OVERRIDE HELLPOD STEERING": "取得绝地喷射舱控制权限", + "#SECONDS UNTIL MISSION EXPIRES": "距离任务过期还有#SECONDS", + "Claim rewards": "领取奖励", + "Semi": "半自动", + "50% bonus to Requisition and XP awarded per mission": "每项任务额外奖励50%申购点和经验", + "CALL": "呼叫", + "FFFF4752": "FFFF4752", + "Dispatches": "快件", + "to equip your Grenades": "装备榴弹", + "MAJOR ORDER FAILED\nOperation Swift Disassembly has failed. Though we have made great gains against the Automatons, still their factories remain, fabricating ever-more threats to Liberty.\n\nThe fight does not end here. We will not rest until their despotic presence is utterly annihilated. Our citizens deserve no less. Await further orders.": "重要指令失败\n急速拆解行动已宣告失败。虽然我们在对抗机器人的战斗中取得了巨大胜利,但敌方孵化厂依然坚挺,源源不断制造出更多威胁自由之敌。\n\n战斗尚未结束。在将它们的暴虐专制彻底消灭前,我们绝不会偃旗息鼓。我们的公民值得享有彻底的和平。等待进一步的命令。", + "Heavy Illuminate Encampment Cleared": "光能者重型营地成功摧毁", + "FUEL OUTPUT": "燃料输出点", + "Sort": "排序", + "Ammunition depleted, switch weapon!": "弹药耗尽,切换武器!", + "MACHINE GUN": "机枪", + "AMMO": "弹药", + "GETTING SERVERS": "正在获取服务器", + "More Info": "其他详情", + "Customize": "自定义", + "EXTRACTION": "撤离", + "SE": "东南", + "The Advanced Liberation Tools Research Agency (ALTRA) has tested successful prototypes of a new combat asset. Helldivers are advised to review proper mechanical operation procedures in preparation for the incoming asset.": "先进解放工具研究局(ALTRA)开发的新型作战装备样机顺利通过测试。建议绝地潜兵提前复习正确的机械操作步骤,准备将来使用该装备。", + "Game version mismatch, please update your game": "游戏版本不匹配,请更新游戏", + "The Great Host": "大军", + "Phase-Beam": "相位光束", + "Are you sure you want to use your Warbond Token to unlock '#WARBOND' standard Warbond?": "是否确定要使用战争债券代币解锁“#WARBOND”标准战争债券?", + "Double Tap": "连按两次", + "Steel Foot": "钢足", + "Assignments": "分派任务", + "Claws": "螯爪", + "ANGEL'S VENTURE FREED\nAngel's Venture has been freed from the Terminids, thanks to your unhesitating sacrifice. It is now under Super Earth control, where it belongs.": "天使投资星系已解放\n在你们毫无迟疑的牺牲下,天使投资星系摆脱了终结族的掌控。它现在已经回到超级地球治下,重返家园。", + "NE": "东北", + "Total Stratagems Used": "战略配备总使用次数", + "CRIMSICA UNDER ATTACK\nThe Terminids are attempting to spread to Crimsica. All Helldivers are called upon to deploy immediately to the planet's defense.": "克里姆西卡遭到袭击\n终结族企图扩张至克里姆西卡。呼唤全体绝地潜兵,立即前去保卫该星球。", + "#CURR of #TOTAL": "#CURR/#TOTAL", + "THREAT": "威胁", + "GEAR: #GEAR": "装备:#GEAR", + "AWAITING REINFORCEMENT": "正在等待增援", + "Venerate": "敬仰", + "Fresh SEAF recruits filled with patriotic fervor for the destruction of the Automatons have surged to take significant ground on Durgen.": "满腔爱国热情、誓要摧毁机器人的超级地球武装部队新进后备军已经在德尔根占领了重要阵地。", + "NEW MAJOR ORDER\nTien Kwan is home to the sole arsenal of new Exosuit technology. It is only a matter of time before the Automatons discover the arsenal and steal it for themselves. Liberate Tien Kwan, before it's too late.": "新重要指令\n天关坐落着唯一一家掌握新型外骨骼装甲科技的军械厂。机器人迟早会发现这座军械厂,窃取相关技术,为己所用。立即解放天关,以免为时过晚。", + "Currently onboard:": "目前已登船:", + "Are you sure you want to purchase #COUNT #ITEM Medals for": "是否确定购买#COUNT枚#ITEM奖章并花费", + "ALL BOOSTERS": "所有强化资源", + "x20 COMMON SAMPLES": "x20普通样本", + "Change aim mode while aiming to use WEAPON SCOPE.": "瞄准时切换瞄准模式可使用武器瞄准镜。", + "Off": "关", + "Filter visible Missions based on difficulty.": "根据难度筛选显示的任务。", + "DROP #ITEM": "投放#ITEM", + "(#MINSm #SECSs)": "(#MINSm #SECSs)", + "The Void, a region of space that has gone completely dark under Illuminate control, expanded without warning. Two planets are gone and nearby planets are overrun with deceitful Illuminate interlopers. The Void surge must be stopped before any additional planets fall.": "数个银河标准小时前,受到光能者控制、陷入彻底黑暗的星域——寂域,在毫无预警的情况下发生了扩张。两颗星球已消失,而邻近星球则被狡诈的光能者入侵者淹没。我们必须在更多星球惨遭吞噬之前,遏止寂域的扩张。", + "EMOTES": "表情", + "CRIMSICA DEFENDED\nThe defense of Crimsica has succeeded. The Terminids have been repelled.": "成功保卫克里姆西卡\n克里姆西卡保卫战以胜利告终,终结族已被击退。", + "Account must be logged in with Playfab to use this functionality": "必须通过Playfab登录账号才能使用该功能", + "Your game version is out of date, please update your game": "你的游戏版本过低,请更新游戏", + "Messages": "消息", + "Select the Equipment and Stratagems to bring on this Mission.": "选择你要在此次任务中携带的装备和战略配备。", + "A HELPING HAND": "施以援手", + "Enter a REQUISITION TERMINAL and requisition more STRATAGEMS.": "进入申购终端,申购更多战略配备。", + "Illuminate Staff": "光能者长杖", + "ASPIRANT": "志士", + "Your chest is bleeding, causing continuous health loss.": "你的胸腔在出血,将导致你持续损失生命值。", + "When the enemy successfully calls for reinforcements, threat level increases.\n\nThis means higher enemy presence for the duration of the mission.": "当敌人成功呼叫增援,威胁等级便会提升。\n\n也就是说,任务期间敌人数量更多。", + "Enter an ARMORY STATION and ADVANCE your current PROGRESSION TRACK.": "进入军械库站点,推进当前的进度条。", + "Joining Session.": "正在加入游戏。", + "Requisition RESUPPLY Stratagem permit.": "申购重新补给战略配备许可证。", + "Select": "选择", + "#OBJECTIVE_NAME\n#TIME_REMAINING": "#OBJECTIVE_NAME\n#TIME_REMAINING", + "SAVE & CLOSE": "保存并关闭", + "WEAPON EXPERIMENTATION\nThe Ballistic Shield Backpack stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“防弹护盾背包”战略配备暂时获准供全体绝地潜兵使用。", + "ADJUST BRIGHTNESS": "调节亮度", + "Interact": "互动", + "Incoming DSS Orbital Bombardment": "民主空间站轨道轰炸来袭", + "SEASON II": "第II赛季", + "Requires another item you do not yet own.": "需要另一件你尚未拥有的物品。", + "Next Reward": "下一项奖励", + "An unusually large Terminid spawning has led to sudden, significant loss of ground on Planet #V_ONE.": "终结族孵化规模异常激增,突如其来的变化导致我方在#V_ONE星球上损失重要阵地。", + "R#RANK": "级别#RANK", + "STOP": "暂停", + "CREDITS": "工作人员名单", + "Obstructed by Anti-Air": "被防空系统阻拦", + "New STRATAGEMS available for REQUISITION.": "全新战略配备可供申购。", + "EXTRA IS REQUIRED": "尚需努力", + "There are unsaved changes to your weapon config. Would you like to accept these changes or continue without saving?": "武器配置存在未保存的更改。是否接受这些更改,或放弃保存以继续?", + "BACK": "返回", + "Intel": "情报", + "Shuttle landed.\nBoard shuttle.": "运输船着陆。\n请迅速登船。", + "DIFFICULTY 8 TRIAL": "难度8级考验", + "Rotate": "旋转", + "#ITEM Medals x#COUNT": "#ITEM奖章 x#COUNT", + "50 SC": "50超级货币", + "FFFFFFEE": "FFFFFFEE", + "HOLD TO PURCHASE": "按住购买", + "LIGHT COMBAT (BUGS)": "轻型作战(虫族)", + "AN UNKNOWN SERVER ERROR HAS OCCURRED": "服务器发生未知错误", + "FF666666": "FF666666", + "Some DualSense® wireless controller and DUALSHOCK®4 wireless controller features may not work as intended with Steam Input enabled, and the default layout may not work as expected. We recommend disabling Steam Input for these controller types.": "启用Steam Input后 DualSense®无线控制器和DUALSHOCK®4无线控制器的部分功能可能无法正常运行,默认布局也可能无法正常运作。我们建议禁用这类控制器的Steam Input功能。", + "ROCK PAPER SCISSORS": "石头剪刀布", + "Quickly navigate between available Missions.": "快速浏览各项可选任务。", + "SUBMACHINE GUN": "冲锋枪", + "#CURRENT / #TARGET": "#CURRENT / #TARGET", + "CONFIRM JOIN": "确认加入", + "WEAPON EXPERIMENTATION\nThe Shield Generator Relay stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“防护罩生成中继器”战略配备暂时获准供全体绝地潜兵使用。", + "CONFIDENTIAL DATA": "机密数据", + "#COMMAND": "#COMMAND", + "INVENTORY OPTIONS": "物品栏选项", + "Inspect (Hold)": "查看(按住)", + "REINFORCE READY": "增援就绪", + "to check map waypoint": "查看地图路径点", + "EQUAL-OPPORTUNITY LIBERATION": "平等、机遇、解放", + "#NAME DIED": "#NAME阵亡", + "YOUR FIRST DIVE": "第一次作战", + "RARE SAMPLE": "稀有样本", + "Select a location where you want to drop in on the mission.": "选择你计划在任务中降落的位置。", + "Give Refill": "提供补给", + "COMBAT STIMS": "作战治疗剂", + "WEAPON EXPERIMENTATION\nThe LAS-98 Laser Cannon stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“LAS-98激光大炮”战略配备暂时获准供全体绝地潜兵使用。", + "Adjust Tilt": "调整倾斜角度", + "MORT LOST\nThe defense of Mort has failed. We cannot allow the Automaton aggression to continue.": "莫特沦陷\n莫特的防线已经崩溃,我们不能任由机器人继续进犯。", + "Inactive": "未激活", + "AUTOMATON INVASION\nThe Automatons have launched another cowardly assault. All available Helldivers are called to fight them off! Report to the Galactic Map for more information.": "机器人入侵\n机器人发动了另一场懦弱的袭击。呼叫所有可行动的绝地潜兵,立刻前去应战!通过星系地图报到,了解更多信息。", + "PLANT": "插旗", + "A Major Order has been failed. Check the Galactic Map for more information.": "一项重要指令未能完成。查看星系地图了解更多信息。", + "HELLMIRE FREED\nHellmire has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet.": "海尔迈尔已解放\n海尔迈尔挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。", + "Operator:": "操作员:", + "Are you sure you want to unlock '#WARBOND' standard Warbond for": "是否确定要解锁“#WARBOND”标准战争债券并花费", + "#COUNT°": "#COUNT°", + "OFFENSIVE": "进攻", + "SORRY": "对不起", + "SATURATION": "饱和度", + "EXPLOSIVE BARREL": "爆炸桶", + "PREPARE FOR FTL JUMP": "准备启动超光速跃迁", + "Failed to join as target host is running a different network config.": "加入失败,你与目标主办者的网络配置不同。", + "Waiting For Players": "等待玩家加入。", + "WSW (#COUNT°)": "西南偏西#COUNT°", + "TOGGLE READY": "切换准备状态", + "Serrated Claws": "锯齿螯爪", + "Electric Shock": "电击", + "ORBITAL": "轨道武器", + "59FF4752": "59FF4752", + "Mega Nest": "超巨巢穴", + "VEHICLE": "载具", + "Damage Over Time": "持续伤害", + "CONTINUE": "继续", + "Jump to Current Level": "跳到当前关卡", + "INT": "枪内", + "Illuminate Ships Incoming": "光能者舰船即将抵达", + "N": "北", + "Select a Mission and get ready to dive.": "选择一项任务,准备深潜绝地。", + "OPTIONS": "游戏设置", + "MANUALLY align RADAR DISH.": "手动校准雷达天线。", + "MISSION TIMER EXPIRED - REINFORCE NO LONGER POSSIBLE": "任务过期,无法再呼叫增援", + "N/A": "不适用", + "MERIDIA UNDER ATTACK\nThe Terminids are attempting to spread to Meridia. All Helldivers are called upon to deploy immediately to the planet's defense.": "默里迪亚遭到袭击\n终结族企图扩张至默里迪亚。呼唤全体绝地潜兵,立即前去保卫该星球。", + "OK": "确定", + "A Major Order has been completed. Check the Galactic Map for more information.": "一项重要指令已完成。查看星系地图了解更多信息。", + "SHUTTLE PATTERN": "运输船涂装", + "Velocity": "速率", + "All Barrels": "全枪管", + "SAVE": "保存", + "MARK": "标记", + "MISSIONS": "任务", + "Mission stats could not be displayed due to a network issue. Mission completion rewards and extracted resources are unaffected and have been handed out normally.": "由于网络问题,无法显示任务数据。完成任务的奖励和提取的资源没受到影响,已正常发放。", + "WEAPON CUSTOMIZATION UNLOCKED": "武器自定义已解锁", + "You have attained the rank of HERO.": "你已成为英雄。", + "BOOSTING SIGNAL... #COUNT": "正在增强信号……#COUNT", + "You do not meet the level requirements to unlock this item.": "等级不符,无法解锁此物品。", + "EXAMINE": "观察", + "LOCKING DRILL POSITION": "正在锁定钻机位置", + "ORDERS": "指示", + "SPECIAL THROWABLE": "特殊投掷武器", + "Supply Stratagems Used": "补给战略配备使用次数", + "OBJECTIVE FAILED": "目标未达成", + "Invite to Platoon": "邀请加入特战排", + "Extraction is now available! Head towards the EXTRACTION BEACON to end the mission.": "现在可以撤离!前往撤离信标结束任务。", + "GALACTIC WAR CONNECTION ERROR": "星系战争连接出错", + "Meat Saw": "肉锯", + "Commend other Helldivers for good behavior!": "多多称赞其他绝地潜兵的优秀表现!", + "You have attained the rank of EXALTED HERO! You have a 5% discount on all premium items.": "你已成为伟人!购买所有尊享物品均可享受5%的折扣优惠。", + "The path has been cleared to the Barrier Planets. SEAF Engineers will now begin constructing the Terminid Control System. Well done, Helldivers.": "前往屏障星球的路线已经打通。超级地球武装部队的工兵即将着手建设终结族遏制体系。干得好,绝地潜兵。", + "CHARGING": "正在充能", + "#NAME returned to civilian life": "#NAME已回归平民生活", + "Toggle View": "切换视图", + "RELOAD": "装填弹药", + "Retrieve WEAPON.": "取回武器。", + "If you don't have a RESUPPLY, scavenge for ammunition or request help from your teammates.": "如果你没有重新补给,那就要设法搜集弹药或是向队友寻求帮助。", + "Explosive Barrel": "爆炸桶", + "Invite": "邀请", + "SAMPLES": "样本", + "Enemy Anti-Aircraft": "敌方防空范围", + "Connection to server failed": "未能连接至服务器", + "Options": "游戏设置", + "COMBAT (BUGS)": "作战(虫族)", + "to sprint": "冲刺", + "DROPPING IN": "正在降落", + "You have almost taken all planets en route to ANGEL'S VENTURE. We are on the verge of clearing the way for construction of the Terminid Control System. Press on!": "你们几乎已经占领通往天使投资星系的所有星球。我们即将为构建终结族遏制体系扫清所有障碍。继续努力!", + "MAG": "弹匣", + "MORE EFFECTIVE MISSIONS": "任务效率提高", + "Eagle Storm": "“飞鹰”风暴", + "In-Mission Time": "任务执行时长", + "YOUR FINAL SCORE": "你的最终得分", + "OPERATIONS": "行动", + "#STATUS on #PLANET": "在#PLANET上#STATUS", + "PREMIUM": "尊享", + "Rotate Antenna": "旋转天线", + "Level #COUNT": "#COUNT级", + "LIBERATION FAILED\nDespite innumerable sacrifices, we have failed to liberate Erata Prime from the Terminid's tyrannical clutches.": "解放失败\n尽管付出了无数的牺牲,我们还是未能将艾拉特主星从终结族的暴虐魔爪中解放出来。", + "Are you sure you want to unlock \"#WARBOND\" Legendary Warbond for": "是否确定要解锁“#WARBOND”传奇战争债券并花费", + "These are the active missions that you must complete to succeed in the operation.\n\nSelect your first mission in the operation.": "你必须完成已激活的任务才能顺利完成这次行动。\n\n请选择你在本次行动中的第一项任务。", + "A SAMPLE CONTAINER was dropped. Pick it up to retrieve the SAMPLES it contains.": "一个样本容器掉落。把它捡起来,收回里面的样本。", + "GROWING STRONGER": "茁壮成长", + "Requisition GRENADE LAUNCHER Stratagem permit.": "申购榴弹发射器战略配备许可证。", + "Preview": "预览", + "Missions": "任务", + "AUTOMATON COUNTERATTACK\nIntercepted messages indicate bot plans for a significant push. Increased resistance on Automaton planets is anticipated.": "机器人反攻\n截获的情报显示,机器人计划大举反攻。预计各机器人星球的反抗力度将大幅加剧。", + "#ONLINE ONLINE  #COUNT IN GAME": "#ONLINE人在线 #COUNT人正在游戏", + "RATE OF FIRE": "射速", + "Search": "搜索", + "YES": "是", + "NEW MAJOR ORDER\nThe Automatons have menaced our citizenry long enough. With the Terminids in check, the time has come at last to eradicate this robot scum from our galaxy.\n\nEradicate the Automatons from every single planet they occupy. Leave none in operation.": "新重要指令\n长久以来,机器人一直威胁着我们的公民。鉴于终结族已为我方所控制,是时候将这些机器人渣滓彻底逐出我们的星系了。\n\n在机器人占据的每一颗星球上,将它们全数剿灭,一个不留。", + "ZOOM": "缩放", + "EXTRACT": "撤离", + "#NAME leveled up #WEAPON to level #LEVEL": "#NAME已升级#WEAPON至#LEVEL级", + "or sprint to climb obstacles": "或冲刺攀爬障碍物", + "Switch Number": "切换号码", + "#NAME": "#NAME", + "LIBERATION FAILED\nDespite great sacrifice, Malevelon Creek remains under Automaton control.": "解放失败\n尽管我方付出了巨大的牺牲,但仍未能让麦拉芬蒙河脱离机器人的铁爪。", + "WAITING FOR BEACON": "正在等待信标", + "JUST NOW": "刚刚", + "LIBERATION FAILED\nWe have failed to cleanse Estanu of the Terminid infestation.": "解放失败\n我们未能彻底剿灭占据伊斯塔努的终结族。", + "TRG": "扳机", + "Hug": "拥抱", + "BOOSTED": "已强化", + "1 DAY AGO": "1天前", + "Right Stick": "右摇杆", + "HELLPOD": "绝地喷射舱", + "SPECIALTY": "特别资源", + "STATS SCREEN": "数据界面", + "Travel to this Campaign to participate in planetary liberation.": "前去参加这场战役,共同解放星球。", + "Automaton Kills": "机器人击杀数", + "SQUAD": "小队", + "KNOWLEDGE IS POWER": "知识就是力量", + "ACTIVE THROUGH THE DEMOCRACY SPACE STATION": "通过民主空间站激活", + "Invalid Authorization response from PlayStation™Network, no Identity received": "来自PlayStation™Network的授权响应无效,未收到验证信息。", + "#COUNT/#TOTAL Claimed": "已领取#COUNT/#TOTAL", + "Recent": "最近", + "Dropped #COUNT samples!": "掉落#COUNT份样本!", + "INTELLIGENCE BRIEF": "情报简报", + "Helldiver": "绝地潜兵", + "Assist Bonus x#COUNT": "助攻加成x#COUNT", + "(optional)": "(可选)", + "Acid": "腐蚀酸", + "MALEVELON CREEK UNDER ATTACK\nThe Automatons have launched yet another cowardly assault on Malevelon Creek. We cannot allow it to fall into their metallic hands.": "麦拉芬蒙河遭到袭击\n机器人向麦拉芬蒙河发动了又一场懦弱的袭击。我们不能任由星球落入它们的铁手。", + "VELD FREED\nVeld has been liberated from the Terminid Menace. Take the fight to the next planet.": "维尔德已解放\n维尔德已经挣脱终结族的魔爪。该去下一颗星球作战了。", + "Back": "返回", + "AUTOMATONS ERADICATED\nCitizens across the Federation celebrate in the streets, hailing the great victory of the Helldivers over the Automatons. Even now, SEAF Engineers dismantle the last of their factories and melt them down into scrap to build new colonial homes. \n\nSoon, we will no doubt discover where this threat originated. For now, let us celebrate the Freedom that the total annihilation of the Automatons has won, in the best way there is: by pursuing the total annihilation of the Terminids.": "机器人已经毁灭\n全联邦的公民走上大街,交相庆贺,为绝地潜兵胜利剿灭机器人而欢呼雀跃。超级地球武装部队工程师直到现在仍在奋力拆除机器人最后的孵化厂,将其融为废料,用于兴建拓殖地的新住宅。\n\n我们定将在不久后找到这一威胁的来源。现在,让我们尽情享受彻底剿灭机器人而赢来的自由,最好的庆祝方式莫过于:彻底消灭终结族。", + "Missions Played": "任务执行数", + "T-: #MINS:#SECS:#HUNDREDTHS": "倒计时:#MINS:#SECS:#HUNDREDTHS", + "RETURN TO SHIP ALONE": "独自返回飞船", + "Orbital Defenses": "轨道防御", + "Artillery": "大炮", + "Territory #COUNT": "领地#COUNT", + "Waiting for players 00:#MINS": "等待其他玩家加入 00:#MINS", + "Failed to create lobby - Contact support if problem persists": "大厅创建失败 - 如果问题仍未解决,请联系客服。", + "Some stratagems have limited uses per mission.": "部分战略配备在一场任务中的使用次数有限。", + "Rare Samples": "稀有样本", + "MANTES UNDER ATTACK\nThe Automatons are invading Mantes. Rally to its defense!": "蒙特斯遭到袭击\n机器人当前正在入侵蒙特斯,速速集结,前去保卫该星球!", + "Stronghold Cleared": "要塞成功摧毁", + "#COUNT meters": "#COUNT米", + "Check your current ammo and weapon settings in the WEAPON FUNCTIONS MENU.": "在武器功能菜单查看当前弹药和武器设置。", + "Show Details": "显示详情", + "TAP": "轻按", + "to fire your weapon": "武器开火", + "FFE8E5CF": "FFE8E5CF", + "Down Button": "下方向键", + "E": "东", + "Objectives Completed": "目标达成数", + "Various Ministries report that the Void expanded rapidly without any warning from monitoring systems. Rirga Bay and Hort are assumed to have been consumed by the Void as Super Earth loses all communications with the planets.": "各部委报告称,寂域正迅速扩张,尽管监测系统未发出任何警告。由于超级地球与这些星球全然失去联系,推测里尔加湾和哈尔特已被寂域吞噬。", + "Heavy Nest": "重型巢穴", + "TURING FREED\nTuring is free at last from the bugs, thanks to your dauntless efforts. Press the fight onward.": "图灵已解放\n在你们英勇无畏的努力下,图灵终于摆脱了虫族。再接再厉,继续战斗。", + "TURING FALLEN\n\nTuring has fallen to the Terminids, and with it the illustrious Xenoentomology Center. Due to the tragic and unavoidable rupture of several high-pressure #ENEMY1 pheromone tanks, #ENEMY2 presence on Turing is expected to increase substantially.": "图灵星沦陷\n\n图灵星已落入终结族手中,连同著名的异星昆虫学研究中心也已沦陷。祸不单行,数台#ENEMY1高压信息素储罐发生不可控的破裂事故,图灵星的#ENEMY2活跃度预计将大幅提高。", + "#NAME joined": "#NAME加入", + "CAPE": "披肩", + "CRYSTALLIZED E-710": "710元素晶体", + "ACTIVATE WARBOND": "激活债券", + "Shots Fired": "开火次数", + "BETTER THAN BARE MINIMUM": "勉强及格", + "FUELING": "正在补充燃料", + "Private Game": "私人游戏", + "Player": "玩家", + "FASTER EXTRACTION": "撤离加快", + "CUSTOMIZABLE": "可定制", + "Crossplay enabled. You may encounter cross-network players.": "跨平台游玩已开启。您可能会遇到跨平台玩家。", + "WEAPON EXPERIMENTATION\nThe SAR-1 Sniper Rifle stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“SAR-1狙击步枪”战略配备暂时获准供全体绝地潜兵使用。", + "Sample": "样本", + "SSW (#COUNT°)": "西南偏南#COUNT°", + "Your commendation level has increased.": "你的嘉赞等级现已提高。", + "to throw stratagem ball": "投掷战略配备球", + "Mega Nest Eradicated": "超巨巢穴成功摧毁", + "OPPORTUNITY TO EXCEL": "趁机超越", + "Failed to join as target host is running a different engine version.": "加入失败,你与目标主办者的引擎版本不同。", + "Something unexpected went wrong while trying to communicate with our server. Try again in a few seconds.": "尝试与服务器通讯时出错,请稍后再试。", + "Electrocution": "触电", + "to melee": "近战", + "WEAPON EXPERIMENTATION\nThe TS-4 Arc Thrower stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“ ARC-3电弧发射器”战略配备暂时获准供全体绝地潜兵使用。", + "FF6ED754": "FF6ED754", + "ORDERS [#COUNT]": "指令[#COUNT]", + "Crushing Claws": "猛爪", + "New WEAPON CUSTOMIZATION available to purchase in the ARMORY": "全新武器自定义内容已在军械库中开放购买", + "FENRIR III FREED\nFenrir III has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet.": "芬里尔III已解放\n芬里尔III挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。", + "PLANET SAVED\nThanks to the selfless valor of the Helldivers, the Terminids' attempt to spread their vile tyranny to another one of our planets has been repelled.": "星球已获救\n在无私的绝地潜兵的英勇付出下,企图将暴政的种子再次散播到我们其中一颗星球的终结族已被击退。", + "SUPER DESTROYER departure imminent! STRATAGEMS will become unavailable. Extract now!": "超级驱逐舰即将离开!你将无法再使用战略配备。立即撤离!", + "Ship": "舰船", + "VEHICLES can traverse the mission area quickly and provide extra firepower.": "载具可以帮助你在任务区域快速移动,也可以提供额外的火力。", + "RR NEWS": "RR新闻", + "Toggle Emergency Lights": "切换紧急照明", + "DESIGNATED TARGET COORDINATES:": "指定目标坐标:", + "UPGRADE COST": "升级消耗", + "One leg is injured, slowing you down and making you unable to sprint.": "有一条腿受伤,减慢了你的移动速度,导致你无法冲刺。", + "Time Bonus": "时间加分", + "#COUNT HOURS AGO": "#COUNT小时前", + "Level up!": "升级!", + ".LOG": "日志", + "HIGH-VALUE TARGET DESTROYED": "高价值目标已摧毁", + "GALACTIC NETWORK UPDATE\n\nHigh Command acknowledges recent issues in the Integrated Realtime Galactic Visibility Aid. The cause has been identified as a network systems Team Member who became disoriented in the server farm, leading to decomposition of organic material on critical network components. \n\nThe issue has been resolved and the system has been returned to normal status. Rest assured that the cost of the repair was borne solely by the family of the team member responsible for the issue.": "星系网络更新\n\n最高指挥部得知集成式星系实时视觉辅助近期出现问题。事故原因已确定,是由于一名网络系统团队成员在服务器农场中迷失方向,导致关键网络元件的有机材料分解。\n\n此问题现已修复,系统也已经恢复正常状态。维修费用全部由涉事团队成员及其家人承担,无需担心。", + "Destroying OUTPOSTS gives XP and REQUISITION.": "摧毁哨站可以获得经验值和申购点。", + "DAY #COUNT": "第#COUNT天", + "HELLDIVERS 2 must be updated to use network features.": "必须更新才能使用《HELLDIVERS™ 2》的联网功能。", + "#NAME": "#NAME", + "Melee": "近战", + "Stronghold": "要塞", + "HERO": "英雄", + "The player or squad you want to join has crossplay disabled.": "你要加入的玩家或小队没有开启跨平台游玩。", + "INTELLIGENCE BRIEF\nBe advised: we have received reports of Terminid hives spawning bugs with limited airborne capabilities. This is likely a random and short-lived genetic anomaly. Nevertheless, Helldivers are ordered to exterminate these strains completely, in the unlikely event they are encountered.": "简报\n注意:我们接到报告,发现终结族虫窝正在孕育拥有一定飞行能力的虫族。这很可能是短暂出现的随机基因异变。无论如何,如若遇到这类突变种,绝地潜兵必须将其完全歼灭。", + "Patriot of Super Earth, your hard work and dedication has not gone unnoticed. This Destroyer has now been automatically enrolled in the Helldiver Weapon Customization Programme!\n\nHelldiver Primary Weapons can now be leveled up and customized, to adjust each weapon's look and feel.": "超级地球爱国者,你的辛勤付出和奉献有目共睹。这艘驱逐舰现已自动加入绝地潜兵武器自定义计划!\n\n绝地潜兵主要武器现在支持升级和定制,可自由调整每件武器的外观手感。", + "Mouse Move": "鼠标移动", + "EXTRACURRICULAR ACTIVITY": "课外活动", + "DIVING increases your chances of surviving an explosion.": "扑倒在地可增加你在爆炸中幸存的机会。", + "CALL THE HELLDIVERS": "呼叫绝地潜兵", + "Super Destroyer Unavailable": "超级驱逐舰不可用", + "FENRIR III LOST\nThe defense of Fenrir III has failed. Terminids now infest its once-pristine surface.": "芬里尔III沦陷\n芬里尔III保卫战已宣告失败。终结族现在令这块曾经的纯净乐土不得安宁。", + "Squad is full. Matchmaking aborted.": "小队已满员,匹配中止。", + "Login limit reached. Please wait to be let in.": "大厅人数已满,请稍等。", + "Activating": "正在启动", + "Shuttle Inbound In T-#MINUTES:#SECONDS:#MILLI": "运输船抵达倒计时 #MINUTES:#SECONDS:#MILLI", + "Sample Container": "样本容器", + "80FF4752": "80FF4752", + "to open the Stratagem menu": "打开战略配备菜单", + "#NAME has timed out": "#NAME已超时", + "to crouch": "蹲下", + "R.SHLD": "右肩", + "You have been kicked from the game.": "你已被移出游戏。", + "Failed to get a profile from a Legacy Login token": "无法从遗留登录令牌中获取资料", + "PLANET LIBERATED\nWe have cleansed a planet of the vile Terminid infestation, returning it to Super Earth's warm embrace.": "星球已解放\n我们已彻底剿灭占领星球的邪恶终结族,让它重回超级地球的温暖怀抱。", + "Receiving Data": "正在接收数据", + "We have failed to clear the way to the Barrier Planets in time. This will severely impact implementation of the Terminid Control System. A disappointing outcome.": "我们未能及时打通前往屏障星球的路线。终结族遏制体系的构建会受到严重的影响。这个结果实在是令人失望。", + "#NAME discovered #DISCOVERY": "#NAME已发现#DISCOVERY", + "DIFFICULTY 2 TRIAL": "难度2级考验", + "SCOUT HANDSHAKE": "侦察兵式握手", + "RELATE TERMINAL TEXT": "叙述终端文本", + "SNIPER RIFLE": "狙击步枪", + "Without the Destroyer nearby, normal Reinforcements are unavailable.\n\nClusters of Reinforcement Pods have been deployed throughout the area. Once activated, you will be able to utilize those reinforcements.": "如果驱逐舰不在附近,就无法使用常规增援。\n\n我方已在该区域各处部署多部增援舱。激活后即可使用这些增援。", + "#NAME joined": "#NAME加入", + "Are you sure you want to use your Warbond Token to unlock \"#WARBOND\" Legendary Warbond?": "是否确定要使用战争债券代币解锁“#WARBOND”传奇战争债券?", + "Armored enemies are expected on this mission. Anti-tank weaponry is recommended.": "本次任务预计会遭遇装备护甲的敌人。建议携带反坦克武器。", + "REARM stratagem sends your Eagle back to reload its weapons.": "重新武装战略配备会派你的“飞鹰”返回补充武器弹药。", + "BFFF4752": "BFFF4752", + "WAITING FOR PLAYERS": "正在等待玩家", + "CASUAL SALUTE": "敬礼", + "Light": "轻型", + "to maneuver Hellpod": "操纵绝地喷射舱", + "RECEIVED: #MINS DAYS AGO": "接收:#MINS天前", + "No unclaimed rewards": "没有尚未领取的奖励", + "CUSTOMIZE": "自定义", + "SUPER EARTH": "超级地球", + "NEW MAJOR ORDER\nActivate the TCS on all Barrier Planets.": "新重要指令\n启动所有屏障星球上的TCS。", + "READY IN #MINS:#SECS": "准备倒计时 #MINS:#SECS", + "Servers at capacity. Please try again later.": "服务器爆满,请稍后再试。", + "The current network connection has been lost.": "当前网络连接已断开。", + "Stratagem Failed": "战略配备失败", + "Burst": "连射", + "Ammo Type": "弹药种类", + "Are you sure you want to unlock \"#WARBOND\" Premium Warbond for": "是否确定要解锁“#WARBOND”尊享战争债券并花费", + "#COUNTm/s": "#COUNT米/秒", + "RIGHT SHOULDERS": "右肩", + "Square Button": "正方键", + "NO": "否", + "Kill Score #COUNT": "击杀得分#COUNT", + "Tutorial Mission": "教程任务", + "SELECT PLANET": "选择星球", + "Eagle Stratagems Used": "“飞鹰”战略配备使用次数", + "OPERATION COMPLETE": "行动完成", + "PARTIAL REINFORCEMENT, YOU ARE NOW #QUEUE_POS IN QUEUE": "部分增援到位,你正在排队,当前位置:#QUEUE_POS", + "The Ministry of Defense has announced increased production of FRV units to support a quick response on the Illuminate front. Increased munitions available to Helldivers effective immediately.": "国防部宣布增加快速侦察载具的产量,以支持在光能者前线的快速响应。增拨绝地潜兵的弹药供应即刻生效。", + "Toggle Laser Designator": "切换激光指示器", + "MISSION": "任务", + "Medium Outpost": "中型哨站", + "ESTANU FREED\nEstanu is free at last from the bugs, thanks to your dauntless efforts. Press the fight onward.": "伊斯塔努已解放\n在你们英勇无畏的努力下,伊斯塔努终于摆脱了虫族。再接再厉,继续战斗。", + "PRESS ANY BUTTON": "按任意按钮", + "RARE": "稀有", + "Bring up the MAP to view objectives and orient yourself.": "调出地图查看目标,确认自己的位置。", + "Don't warn me again": "不必再提醒我", + "Current Personal Order": "当前个人指令", + "REINFORCEMENT AVAILABLE IN #SECONDS SECONDS": "增援就位倒计时:#SECONDS秒", + "HEETH DEFENDED\nAfter countless noble and unavoidable sacrifices, Heeth has been defended from the Terminids.": "成功保卫希斯\n无数不可避免的光荣牺牲终于换来回报,我们顺利从终结族手下守住了希斯。", + "GRENADES": "榴弹", + "Sandstorm In Progress": "沙尘暴正在形成", + "x#COUNT": "x#COUNT", + "OVERWHELMING FIREPOWER": "火力碾压", + "completed task in [#ASSIGNMENT_TITLE]": "已完成[#ASSIGNMENT_TITLE]中的任务", + "Light Outpost": "轻型哨站", + "NEWS FEED": "新闻动态", + "Weapons": "武器", + "EXTRACTION FAILED": "撤离失败", + "Adjust zoom level.": "调节缩放距离。", + "Failed to join lobby. You're not logged into PlayFab; please restart the application.": "无法进入大厅。你尚未登录至PlayFab,请重启应用。", + "MUZ": "枪口", + "L.SHLD": "左肩", + "Heavy Outpost": "重型哨站", + "Enemy defenses have unexpectedly collapsed on Planet #V_ONE, allowing significant ground to be rapidly gained.": "#V_ONE星球上的敌方防线意外崩溃,我方得以快速占领重要阵地。", + "or sprint to traverse multiple obstacles": "或冲刺穿过多处障碍", + "The Mindless Masses have overrun planetX. Any information that the enemy forces may have had is now irretrievable.": "无脑群氓大军已经淹没X星。任何敌军可能掌握的情报现已无法追回。", + "Magazine": "弹匣", + "Low Orbit Compromised": "低轨道失守", + "Do you want to leave this game?\n\nYou will be returned to your own ship and leave the current squad.": "要离开游戏吗?\n\n你将离开当前小队并回到自己的飞船。", + "Give Supplies": "给出物资", + "HELLMIRE LOST\nThe defense of Hellmire has failed. Terminids now run amok on its surface. We cannot allow this corruption of Liberty to stand.": "海尔迈尔沦陷\n海尔迈尔保卫战已宣告失败。终结族现在正四处肆虐。我们不能允许任由它们继续侵犯自由伟业。", + "to dive into prone": "飞扑进入匍匐姿态", + "SEST #HOURS:#MINUTES:#SECONDS": "超级地球标准时间#HOURS:#MINUTES:#SECONDS", + "Matchmaking aborted.": "匹配中止。", + "THE EXTRA MILE": "锲而不舍", + "HELMETS": "头盔", + "Already at maximum capacity.": "容量已满。", + "to throw": "投掷", + "HELLDIVER FRIENDS": "绝地潜兵好友", + "Killed by #KILLER": "已被#KILLER击杀", + "DIFFICULTY 5 TRIAL": "难度5级考验", + "WEAPON EXPERIMENTATION\nThe RS-422 Railgun stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“RS-422磁轨炮”战略配备暂时获准供全体绝地潜兵使用。", + "AMO": "弹药", + "DISCARD": "放弃", + "Confirmed": "已确认", + "Here you expand your ships arsenal of firearms and grenades.": "你可以在这里扩充舰船上储备的枪械和榴弹。", + "SCANNER RECHARGING... #COUNT": "扫描仪正在充能……#COUNT", + "RARE SAMPLES": "稀有样本", + "Pattern": "涂装", + "Round Bonus": "本轮加分", + "Call in EXTRACTION SHUTTLE.": "呼叫撤离运输船。", + "#NAME has joined the mission": "#NAME加入任务", + "An unknown error has occurred.": "发生未知错误。", + "66FFFEE1": "66FFFEE1", + "Requisition may be earned by completing missions": "完成任务可以赚取申购点", + "SAMPLE CONTAINER": "样本容器", + "UPGRADE \nAVAILABLE": "升级\n可用", + "WEAPON EXPERIMENTATION\nThe Guard Dog stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“护卫犬”战略配备暂时获准供全体绝地潜兵使用。", + "ATTACHMENTS": "配件", + "FULL": "已满", + "Failed to join game lobby.": "无法进入游戏大厅。", + "PLANET LIBERATED\nWe have driven the Automatons completely from a planet, rightfully reclaiming it for Super Earth.": "星球已解放\n我们彻底将机器人逐出了星球,光明正大地夺回超级地球的领地。", + "Failed to join because you have been banned from this session.": "已被禁止加入本场游戏,加入失败。", + "Extraction in T-#MINS:#SECS:#HUNDREDTHS": "撤离倒计时 #MINS:#SECS:#HUNDREDTHS", + "FOR SCIENCE!": "为了科学!", + "DEFENSIVE": "防御", + "ACQUISITIONS": "采购", + "STEAM NOT DETECTED": "未检测到STEAM", + "Search Friends List": "搜索好友列表", + "MERIDIA SECURED\nThe Terminid Control System is now fully activated on Meridia.": "成功占领默里迪亚\n终结族遏制体系已经在默里迪亚全面启动。", + "Impact": "着陆", + "Request: #REQ, Error: #ERR, Status: #STAT": "请求:#REQ,错误:#ERR,状态:#STAT", + "#NAME is the new squad leader": "#NAME成为新的小队长", + "Search Recently Played": "搜索近期共同游戏的玩家", + "PRICE INDEX #COUNT%": "物价指数#COUNT%", + "Incoming Bombardment": "轰击来袭", + "1 HOUR AGO": "1小时前", + "AUTOMATED TURRETS fire at hostile targets. Stay clear of the field of fire!": "自动炮台会朝敌方目标开火。注意避开射击范围!", + "TOO FAR FROM EXTRACTION": "距离撤离点太远", + "Server request failed - Error code:": "服务器请求失败 - 错误代码:", + "WARBONDS": "战争债券", + "Request: #REQ\nError: #ERR\nStatus: #STAT": "请求:#REQ\n错误:#ERR\n状态:#STAT", + "WEAPON EXPERIMENTATION\nThe Orbital Laser stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“轨道激光炮”战略配备暂时获准供全体绝地潜兵使用。", + "L. LEG": "左腿", + "CONFIRM PURCHASE": "确认购买", + "MERIDIA LOST\nThe defense of Meridia has failed. Terminids now infest its once-pristine surface.": "默里迪亚沦陷\n默里迪亚保卫战已宣告失败。终结族现在令这块曾经的纯净乐土不得安宁。", + "DESTROY AUTOMATON OUTPOST": "摧毁机器人哨站", + "VEHICULAR VENGEANCE": "载具式复仇", + "Heal teammate with STIMS.": "用治疗剂治疗队友。", + "LIBERATION FAILED\nWe have failed to liberate Mort from the Automatons.": "解放失败\n我们未能从机器人手上解放莫特。", + "+#COUNT": "+#COUNT", + "REINFORCE UNAVAILABLE": "增援不可用", + "Ready": "就位", + "SOCIAL": "社交", + "ALT. AMMO": "备用弹药", + "Interior": "内部", + "MORE AMMO": "弹药增加", + "STALWART": "轻机枪", + "Wave #WAVE_NUMBER": "第#WAVE_NUMBER波攻势", + "Shoulder (R)": "右肩", + "INTELLIGENCE BRIEF\nStrains of flying Terminids are becoming more prevalent, especially in vicinity of TCS installations. It is fortunate that the TCS was implemented in time, or this problem would undoubtedly have been much worse. Helldivers are advised to vertically expand their situational awareness when on Terminid planets.": "简报\n飞行终结族的突变种越来越普遍,尤其在部署TCS附近的区域。幸好TCS已及时完成部署,否则情况必将更为严峻。在终结族占领的星球上,请绝地潜兵留意垂直方向上的状况,以便掌握战场动态。", + "VENERATE": "敬仰", + "A contingent of Helldivers have taken the initiative to push for the liberation of Malevelon Creek, even as the activation of the TCS remains an objective.\n\nAs is already understood, Helldivers are peerless strategists, fully entrusted to exercise force wherever they deem Liberty can be best served. Super Earth High Command has total confidence in the ability of the Helldivers to fully consider the relevant risks involved, and whatever consequences may occur, as a result of their strategic decisions.": "一支绝地潜兵分遣队已经主动出征,推动麦拉芬蒙河的解放大业发展,与此同时,启动TCS依然是我方的目标。\n \n众所周知,绝地潜兵精于战略,能全权决定在其认为适合散播自由精神的任何地方使用武力。超级地球最高指挥部完全相信绝地潜兵有能力充分考虑其战略决策带来的风险,以及可能产生的任何后果。", + "EQUIPMENT": "装备", + "GET READY": "准备", + "MAJOR ORDER COMPLETED": "已完成重要指令", + "Iron Fist": "铁拳", + "Cooldown T-#MINUTES:#SECONDS": "冷却倒计时 #MINUTES:#SECONDS", + "R. ARM": "右臂", + "DIVE to extinguish fire!": "飞扑可以灭火!", + "KNOW THEIR SECRETS": "洞察一切", + "to equip your Support Weapon": "装备支援武器", + "Close BUG HOLES using GRENADES.": "用榴弹封闭虫穴。", + "EXTRACTION COMPLETE": "撤离完成", + "to find new missions": "寻找新的任务", + "A catastrophic weather event has decimated enemy forces, leading to a significant friendly advance on #V_ONE.": "灾难性天气事件重挫了敌军力量,让我方在#V_ONE上取得重大进展。", + "#NAME is no longer part of the team": "#NAME不再是团队一员", + "Press": "按下", + "Emotes": "表情", + "Operations on higher difficulties are more challenging and contain new Enemies and Missions.\n \nComplete an Operation on your highest unlocked difficulty to unlock the one above it.": "行动难度越高,挑战性越高,还会出现新的敌人和任务。\n\n完成已解锁的最高难度行动即可解锁更高难度。", + "MORE STIMS": "治疗剂增加", + "ESTANU LOST\nThe defense of Estanu has failed. Terminids now run amok on its surface. We cannot allow this corruption of Liberty to stand.": "伊斯塔努沦陷\n伊斯塔努保卫战已宣告失败。终结族现在正四处肆虐。我们不能允许任由它们继续侵犯自由伟业。", + "#DISTANCEm": "#DISTANCE米", + "Blunt force trauma": "钝性创伤", + "Tongue": "虫舌", + "HIT 'EM WHERE IT HURTS": "直击痛处", + "User is not currently signed in.": "用户尚未登录。", + "Do you want to skip the rest of the credits?": "要跳过余下的工作人员名单吗?", + "SIDE ARM": "副武器", + "SUPER DESTROYER has departed. STRATAGEMS unavailable. EXTRACTION SHUTTLE enroute.": "超级驱逐舰已离开。战略配备无法使用。撤离运输船已经出动。", + "Left Button": "左方向键", + "NOT READY": "尚未就位", + "NO SPACE": "没有空间", + "NEW DIFFICULTY UNLOCKED": "已解锁新难度", + "The account has a session token for PlayStation™Network but it's not authenticated": "该账号在PlayStation™Network上有一个会话令牌,但未经验证", + "INITIATE EXTRACTION": "开始撤离", + "UBR": "下挂", + "Synchronizing Spacetime": "正在同步时空", + "Use the WAR TABLE to travel to a war front.": "使用议战桌前往战争前线。", + "You have commended this player five times today. Further commendations will not count towards their score.": "今天你已称赞了这名玩家五次,继续称赞也无法提高其分数。", + "Septic Breath": "脓毒吐息", + "ISSUED BY THE MINISTRY OF PROSPERITY": "由真理部颁发", + "Buy": "购买", + "MISSION DEBUG": "任务测试", + "Out Of Stims": "治疗剂已用尽", + "The way to HEETH is nearly clear. Push now to clear the way for construction of the Terminid Control System.": "通往希斯星系的路线即将打通。继续推进,为构建终结族遏制体系清除所有障碍。", + "WEAPON CUSTOMIZATION": "武器自定义", + "SEAF scouts have reported contact with airborne enemy units. The enemies of Freedom now terrorize the sky itself. Helldivers are advised to stay alert for aerial threats, and to free the sky of terrorism whenever possible.": "超级地球武装部队的侦察兵报告称曾与敌方空军交火。威胁自由的大敌现在染指了天空。建议绝地潜兵警惕空中威胁,并尽可能肃清天空的威胁。", + "Hellpod": "绝地喷射舱", + "ESTANU DEFENDED\nThanks to the selfless valor of the Helldivers, the citizens of Estanu are safe from the Terminid Menace.": "成功保卫伊斯塔努\n在无私的绝地潜兵的英勇付出下,伊斯塔努的公民终于摆脱了终结族的威胁。", + "FFAA000A": "FFAA000A", + "Total Score": "总分", + "PAGE LOCKED": "未解锁页面", + "Exterior": "外部", + "CONNECTION ERROR": "连接错误", + "Find and collect SAMPLES! These resources are shared by the entire squad and are used to upgrade your Destroyer.": "注意搜集样本!这是由整个小队共享的资源,可以用来升级驱逐舰。", + "Shoulder (L)": "左肩", + "Light Automaton Outpost Destroyed": "轻型机器人哨站成功摧毁", + "Shuttle leaving.\nBoard shuttle.": "运输船即将驶离。\n请迅速登船。", + "ASSAULT RIFLE": "突击步枪", + "TALK": "对话", + "TOGGLE AMMO": "切换弹药", + "MINIMIZE STATS": "最小化数据", + "Shuttle landing.\nClear landing zone.": "运输船即将着陆。\n请肃清降落点。", + "Defensive Stratagems Used": "防御型战略配备使用次数", + "SSE (#COUNT°)": "东南偏南#COUNT°", + "CALCULATING TRAJECTORY": "正在计算轨迹", + "Are you sure you want to unlock #ITEM?": "确定要解锁#ITEM吗?", + "Talk to the HELLBOT.": "与绝地机械兵对话。", + "LIBERATION FAILED\nDespite innumerable sacrifices, we have failed to liberate Meridia from the Terminid's tyrannical clutches.": "解放失败\n尽管付出了无数的牺牲,我们还是未能将默里迪亚从终结族的暴虐魔爪中解放出来。", + "Inbound T-#MINUTES:#SECONDS": "抵达倒计时 #MINUTES:#SECONDS", + "LIBERATING THE ENEMY": "解放敌人", + "Perform ASSISTED RELOAD.": "执行协助装填弹药。", + "discovered": "已发现", + "Tier 3": "3阶", + "WEAPON EXPERIMENTATION\nThe Eagle Napalm Airstrike stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“‘飞鹰”凝固汽油弹空袭”战略配备暂时获准供全体绝地潜兵使用。", + "Go to the Armory to view your inventory.": "前往军械库查看物品。", + "ENTER THE VOID": "进入寂域", + "In order to conserve medical supplies, Helldivers will deploy with fewer stims until further notice.": "为了节约医疗补给,绝地潜兵将携带较少的治疗剂奔赴战场,直至另行通知为止。", + "Medals may be earned by completing missions or purchased with Super Credits": "奖章可以通过完成任务获得或使用超级货币购买", + "ENE (#COUNT°)": "东北偏东#COUNT°", + "Explosion": "爆炸", + "Purchase Upgrade": "购买升级", + "Pick up BLACK BOX.": "拾取黑匣子。", + "Different Game Version": "游戏版本不同", + "Fighting Automatons": "抗击机器人", + "STANDARD": "标准", + "+ #PING_AMOUNT Pings": "+ #PING_AMOUNT延迟值", + "Provided Legacy login token is not valid": "提供的遗留登录令牌无效", + "Hover over available Campaigns to get more information.": "悬停在可选战役上方可以查看更多信息。", + "Season II": "第II赛季", + "MAJOR ORDER UPDATE": "重要指令更新", + "Destroyer has left orbit!": "驱逐舰已离开轨道!", + "LIBERATION FAILED\nWe have failed to cleanse a planet of the bugs' infestation.": "解放失败\n我们未能彻底剿灭占据星球的虫族。", + "Do you want to leave this game?\n\nYou will be returned to your own ship and bring the rest of the squad with you.": "要离开游戏吗?\n\n你将与小队其他成员一同回到自己的飞船。", + "FFC0BEB7": "FFC0BEB7", + "RETURN TO SHIP": "返回飞船", + "CLAIM PREMIUM WARBOND": "领取尊享战争债券", + "SQUADRON": "中队", + "Helldivers are instructed to report to their ship's tailor for measurements. As development of the Advanced Liberation Tools Research Agency (ALTRA)'s new combat asset nears completion, we must ensure that every Helldiver can fit within it. For the good of Managed Democracy.": "绝地潜兵在指引下将尺码数据汇报给舰船裁缝师。先进解放工具研究局的新战斗装备开发工作即将完成,我们必须确保每一位绝地潜兵都能穿上装备。管理式民主万岁。", + "MAJOR ORDER SUCCEEDED\nThe Terminid Control System is now fully activated on all barrier planets. The Terminids are quarantined, and our citizens are forever safe from their ravenous tyranny. You have achieved a great victory for all posterity, Helldivers.": "重要指令已完成\n终结族遏制体系已经在所有屏障星球上全面启动。终结族已被隔离,我们的公民亦从此不再受它们贪婪暴政的威胁。绝地潜兵,你们为子孙后代取得了伟大的胜利。", + "Today we praise the steadfast logistics operators. They have just deployed new equipment to all Super Destroyers. Perhaps one day, they too can reach the heights of loyalty that our Helldivers demonstrate every single day.": "今天,我们赞美忠诚的物流操作员,他们已顺利将全新装备送达各艘超级驱逐舰。或许有一天,他们也会达到绝地潜兵那样的高度,时刻都会彰显内心的忠诚。", + "HEETH LOST\nHeeth has fallen to the Terminid Menace. We cannot allow this infestation to continue to spread.": "希斯沦陷\n在终结族的威胁下,希斯已沦陷。我们不能容许虫族继续扩张。", + "Circle Button": "圆圈键", + "Close all bug holes": "封闭所有虫穴", + "BRIEFING": "简介", + "Anti-Aircraft Defenses": "对空防御", + "Shoot the TARGETS.": "射击目标。", + "LEFT SHOULDERS": "左肩", + "SAVE WEAPON CONFIG": "保存武器配置", + "NETWORK ERROR": "网络出错", + "Here you can expand your ships arsenal of helmets, armors and capes.": "你可以在这里扩充舰船上储备的头盔、盔甲和披肩。", + "THE HIVE": "虫窝", + "DEFROSTING HELLDIVER": "正在解冻绝地潜兵", + "Failed to join game lobby, Public Key mismatch.": "无法进入游戏大厅,公钥不匹配。", + "STOP SEARCH": "停止搜索", + "Triangle Button": "三角键", + "to switch weapon": "切换武器", + "INTERNAL BLEEDING": "内出血", + "LIGHT COMBAT (ILLUMINATE)": "轻型作战(光能者)", + "to salute the Flag": "向旗帜敬礼", + "QUICKPLAY": "快速匹配", + "Commends": "获赞", + "CUT OFF REINFORCEMENTS": "切断增援", + "Right Button": "右方向键", + "CITIZEN KILLED": "误杀公民", + "Error": "错误", + "Client Platform not supported": "不支持客户端平台", + "Ministry of Intelligence cryptographers have decoded Automaton chatter including mention of a new \"HUMAN KILLING MACHINE.\" While further analysis is underway, Helldivers combatting the Automatons in high-complexity missions are urged to remain vigilant.": "情报部密码学家破译了机器人的通信记录,得知对方掌握一种新型“杀人机器”。尽管该情报有待进一步分析,但是执行复杂任务并与机器人交手的绝地潜兵务必保持警惕。", + "You are able to requisition STRATAGEMS. Exit the menu when you're done.": "你现在可以申购战略配备。完成后退出菜单。", + "This item is not available for sale at this time.": "这件商品目前未上架。", + "Fog Generator": "雾气生成器", + "Fighting Illuminate": "抗击光能者", + "#CURRENT / #TOTAL": "#CURRENT / #TOTAL", + "CLEAR ILLUMINATE STRONGHOLD": "摧毁光能者要塞", + "Shuttle aborting.\nReturn to extraction zone.": "运输船将中止接送。\n请返回撤离区域。", + "to switch between PRIMARY-, SECONDARY-, and SUPPORT WEAPONS.": "切换主武器、副武器和支援武器。", + "Toxic gas": "毒气", + "CLERICAL ERROR RESOLVED - ITEM RECEIVED": "文书错误已修正 - 已收到物品", + "Shuttle": "运输船", + "Dropped intel!": "掉落情报!", + "GALACTIC WAR UPDATE\nOperation Swift Disassembly continues as planned. The Automatons are in retreat. Press the advantage. Their final resistance will no doubt be fierce, as their anti-annihilation subprotocols activate. Show them no quarter. Remember the fallen. Remember the Creek. And remember that they are unequivocally non-sentient, so all acts of violence are wholly justified.": "星系战争战况更新\n急速拆解行动如期进行中。机器人正在撤退,宜乘胜追击。它们最后无疑将负隅顽抗,启动反覆灭次级协议。绝不能对它们手软。铭记陨落的同袍。记住麦拉芬蒙河。别忘了它们毫无感知能力,因此施以任何形式的暴击都是理所当然。", + "Move cursor to pan map.": "移动光标可以拖动地图。", + "Eagle Kills": "“飞鹰”击杀数", + "CLEAR ILLUMINATE ENCAMPMENT": "摧毁光能者营地", + "Crushing Charge": "强冲", + "Shots Hit": "命中次数", + "SELECT DROP ZONE": "选择空投地点", + "THANKS": "谢谢", + "Incoming Meteor Storm": "流星风暴即将来袭", + "A unanticipated rush of Terminids has overwhelmed SEAF defenses on #V_ONE, leading to a large loss of territory.": "突如其来的终结族袭击令#V_ONE上的超级地球武装部队防线崩溃,导致大面积阵地落入敌手。", + "Here you can unlock new stratagems to use on the battlefield. Initially, your Destroyer only has access to a limited catalog of stratagem permits, but as you level up, more stratagems will become available for purchase.": "你可以在这里解锁全新的战略配备,供你在战场上使用。你的驱逐舰最初只能访问有限的战略配备许可目录,但只要升级就能购买更多战略配备。", + "WSW": "西南偏西", + "MAJOR ORDER ISSUED": "重要指令已发布", + "ERADICATE BUG NEST": "摧毁虫族巢穴", + "Notifying others to follow.": "正在通知其他人员跟进。", + "TEAM WEAPON": "团队武器", + "REVERT": "撤销", + "DRIVE OF DEMOCRACY": "民主渴望", + "Light Encampment": "轻型营地", + "STEAM FRIENDS": "STEAM好友", + "WRESTLE": "掰手腕", + "STRATAGEM HERO": "战略配备英雄", + "LOCKING TARGET": "正在锁定目标", + "ALREADY IN USE BY TEAMMATE": "队友正在使用", + "Pick up OBJECTIVE ASSET.": "拾取目标资产。", + "Super Credits may be purchased from the Super Credits tab": "超级货币可以在相应的标签页中购买", + "BOOSTERS": "强化资源", + "COMMON SAMPLE": "普通样本", + "SSE": "东南偏南", + "Online": "在线", + "x20 Common Samples": "x20普通样本", + "to view the map": "查看地图", + "The host has left the game.": "主办者已退出游戏。", + "Provided PlayFab token belongs to a different platform than the one the client is currently using": "提供的Playfab令牌不属于客户端当前使用的平台", + "Complete all PRIMARY OBJECTIVES to enable extraction.": "完成所有主要目标即可撤离。", + "OPERATED BY #NAME": "操作员:#NAME", + "COMPARE INFO": "对比信息", + "Friendly Kills": "友方击杀数", + "Intense Heat": "极暑", + "E (#COUNT°)": "东#COUNT°", + "APPLY": "应用", + "Medium Encampment": "中型营地", + "Spend RESEARCH POINTS in the ARMORY.": "在军械库使用研究点数。", + "MARKER FROM #NAME": "#NAME的标记", + "Missions Won": "任务完成数", + "Volcanic Activity Detected": "侦测到火山活动迹象", + "HUE": "色调", + "PLAY TUTORIAL": "开始教程", + "TAKE #ITEM": "拿起#ITEM", + "You can use STIMS on your teammates.": "你可以对队友使用治疗剂。", + "SW (#COUNT°)": "西南#COUNT°", + "LESS AMMO": "弹药减少", + "#NAME discovered #DISCOVERY": "#NAME已发现#DISCOVERY", + "EAGLE": "飞鹰", + "GALACTIC WAR UPDATE\nOperation Swift Disassembly faces fierce resistance. Clearly, the Automatons' anti-annihilation subprotocols have activated, as they calculate the inevitability of their doom. Redouble your efforts. Press the assault. Show them no mercy. Remember the fallen. Remember the Creek. And remember that they are unequivocally non-sentient, so all acts of violence are wholly justified.": "星系战争战况更新\n急速拆解行动如期面临激烈的反噬。机器人显然已启动反覆灭次级协议,因为它们已经测算出厄运无可避免。诸君须加倍努力,压制顽抗,毫不留情。铭记阵亡的同袍。记住麦拉芬蒙河。别忘了它们毫无感知能力,因此施以任何形式的暴击都是理所当然。", + "BUY CHARGES": "购买炸药", + "ADJUST ROTATION AND TILT": "调整旋转和倾斜角度", + "Changing the ATTACHMENTS on your weapon will affect its stats and properties. Changing the PATTERN will affect its visuals. \n\nUse your weapon in order to level it up and unlock more mods using REQUISITION": "更换武器配件会影响武器数据和属性。更换涂装会影响武器外观。\n\n使用武器可提升其等级,消耗申购点可解锁更多改装模组", + "LEGENDARY WARBOND UNLOCKED": "已解锁传奇战争债券", + "Invalid": "无效", + "Tremors Detected": "侦测到地震", + "Signal Left Turn": "指示左转", + "Inspect (Toggle)": "查看(切换)", + "You have been disconnected due to inactivity": "你处于不活跃状态,已断开连接", + "STANDARD THROWABLE": "标配投掷武器", + "Mouse Cursor": "鼠标光标", + "The Helldivers successfully fended off the Automaton invasion. Our citizens thank you.": "绝地潜兵成功击退了机器人的入侵。无数公民对你们感激不尽。", + "EXOSUIT PATTERN": "外骨骼装甲涂装", + "Fallen Helldivers will drop any held samples and weapons. Those items can be retrieved.": "绝地潜兵持有的样本和武器会在阵亡时全部掉落。你可以取回这些掉落物品。", + "Avoid killing citizens. Escort them to safety to complete the Objective.": "避免伤及公民。护送他们到安全地点才能完成目标。", + "Victory Pose": "胜利姿势", + "Death is a natural part of being a Helldiver.": "绝地潜兵必须时刻准备迎接死亡。", + "FIND ONGOING MISSIONS": "查找进行中的任务", + "Failed to connect to server - Contact support if problem persists": "未能连接至服务器 - 如果问题仍未解决,请联系客服。", + "Buy (SC)": "购买(超级货币)", + "Extreme Cold": "极寒", + "REINFORCE DEAD TEAMMATES": "增援已牺牲的队友", + "JOIN MISSION": "加入任务", + "PRESIDENTIAL DECREE\n\nThe President of Super Earth has officially recognized this day as Malevelon Creek Memorial Day. Every year on this day, Super Earth citizens will unite for a full 3 minutes of their lunch break in solemn remembrance of those who gave their lives to free Malevelon Creek. \n\nIn addition, all Helldivers have been issued a special commemorative cape, so they may carry the memory of their fallen companions into battle.": "总统令\n\n\n超级地球总统已正式将这一天定为 \"麦拉芬蒙河纪念日\"。每年的这一天,超级地球的公民们都会在午餐时间一起为解放麦拉芬蒙河而牺牲的战士默哀三分钟。\n\n此外,所有绝地潜兵都会获得一件特殊的纪念披肩,让他们带着牺牲同伴的遗志投身战斗。", + "to use a Stim on a wounded squad member": "对受伤的队友使用治疗剂", + "You have attained the rank of CHAMPION.": "你已成为斗士。", + "Spot Available": "可用点位", + "#HUNDREDTHS:#MINS:#SECS": "#HUNDREDTHS:#MINS:#SECS", + "#SHIP_PREFIX #SHIP_NAME_A #SHIP_NAME_B": "#SHIP_PREFIX#SHIP_NAME_B#SHIP_NAME_A", + "BLACK SAFFRON": "番黑花", + "REVOLVER": "左轮手枪", + "Give Health Pack": "给出生命包", + "Failed to login to PlayFab. Crossplay is disabled.": "无法登录至PlayFab。已禁用跨平台游玩。", + "TURING UNDER ATTACK\nThe bugs have attacked Turing. Rally to its defense, before they are able to permanently infest it.": "图灵遭到袭击\n虫族对图灵发动了袭击。立即集结,前去防卫,避免领地永远落入敌人手里。", + "INTEREST": "特殊地点", + "DESTROYER HAS LEFT ORBIT!": "驱逐舰已离开轨道!", + "LEGEND": "传奇", + "FOLLOW ME": "跟我走", + "On": "开", + "5913D460": "5913D460", + "MANTES FREED\nThe Automaton presence on Mantes is no more. Push the fight onward.": "蒙特斯已解放\n机器人不再染指蒙特斯的大地。让我们再接再厉,继续战斗。", + "HERO RATING": "英雄评分", + "Close orbit superiority will allow faster extractions than normal for the near future": "由于我方掌控近地轨道,近期撤离行动效率较平时有所提高", + "Thick Fog": "浓雾", + "Muzzle": "枪口", + "WEAPON EXPERIMENTATION\nThe Autocannon Sentry stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“自动哨戒炮”战略配备暂时获准供全体绝地潜兵使用。", + "MEGA NEST": "超巨巢穴", + "When playing solo, auto-reinforce is active and you will automatically drop down in a Hellpod on death.": "单人游戏启用自动增援。阵亡后,你将自动乘坐绝地喷射舱降落。", + "Cross Button": "交叉键", + "SHIP MANAGEMENT": "舰船管理", + "Reloading discards any remaining ammunition. Plan your reloads wisely!": "重新装填弹药会丢弃所有剩余弹药。请规划好装弹时机!", + "L": "升", + "MORT UNDER ATTACK\nThe bots seek to add Mort to their despotic domain. We cannot allow this illegal territorial expansion.": "莫特遭到袭击\n机器人企图将莫特纳入它们的暴政领域,我们不能放任它们非法扩张领地。", + "ACTIVATE": "启动", + "Additional Extraction Zone": "其他撤离区", + "Adjust Wires": "调整线路", + "Toggle Info": "切换详情", + "Waypoints you have placed on the map are visible on your compass": "你在地图上设置的路径点会显示在罗盘上", + "DROP": "放下", + "destroyed a sample!": "摧毁了一份样本!", + "Colony": "拓殖地", + "Directional Buttons": "方向键", + "#COUNT Medal(s) spent": "已花费#COUNT枚奖章", + "Add all available STRATAGEMS to your loadout.": "将所有可用的战略配备添加至武装配置。", + "HELLPOD PATTERN": "绝地喷射舱涂装", + "PAPER": "布", + "Heavy Bug Nest Eradicated": "重型巢穴成功摧毁", + "Move to the SHOOTING RANGE to start the exercise.": "前往靶场开始训练。", + "PLANET LOST\nWe have failed to repel the Automatons from one of our planets. We will remember the fallen, and return to take it back.": "星球沦陷\n我们未能将机器人从我方的其中一颗星球逐出。我们将铭记陨落的英雄,并发誓收复失地。", + "Super Sample": "超级样本", + "CLAIM ITEM": "领取物品", + "EFFECTS [#COUNT]": "效果[#COUNT]", + "SCORE": "得分", + "Incoming DSS Eagle Strike": "民主空间站“飞鹰”攻击来袭", + "DRAUPNIR FREED\nThe Automaton presence on Draupnir is no more. Push the fight onward.": "德罗普尼尔已解放\n机器人不再染指德罗普尼尔的大地。让我们再接再厉,继续战斗。", + "SEISMIC SCAN RESULT:": "地震扫描结果:", + "DROPPED": "掉落", + "Rank #RANK - #RANKNAME": "级别#RANK - #RANKNAME", + "MILITARY OPS": "军事行动", + "#NAME - #STATE [#MEMBERS/#MAXMEMBERS]": "#NAME - #STATE [#MEMBERS/#MAXMEMBERS]", + "SUPER SAMPLE": "超级样本", + "to equip your Sidearm": "装备随身武器", + "LIBERATION FAILED\nDespite innumerable sacrifices, we have failed to liberate Turing from the Terminid's tyrannical clutches.": "解放失败\n尽管付出了无数的牺牲,我们还是未能将图灵从终结族的暴虐魔爪中解放出来。", + "PERSONAL ORDER COMPLETED": "已完成个人指令", + "Minor Place of Interest": "次要特殊地点", + "Backend version mismatch - You must update the game to the latest version.": "后端版本不匹配 - 你必须将游戏更新至最新版本。", + "Open STRATAGEM MENU and enter code for ORBITAL PRECISION STRIKE and throw BEACON at target.": "打开战略配备菜单,输入轨道精准攻击的代码,然后朝目标投掷信标。", + "This is a Commando Mission.\nThis far behind enemy lines, hostiles are everywhere. Every time they call for reinforcements, the threat level is increased. Higher threat level means more hostile units in the area.": "这是突击兵任务。\n深入敌后,群敌环伺。每当敌军呼叫增援时,威胁等级就会提升。威胁等级越高,该区域内出现的敌方数量越多。", + "APPLY NAME": "应用名称", + "LIGHT": "轻型", + "FIRE MODE": "开火模式", + "ITEMS DROPPED": "掉落物品", + "#NAME didn't make the cut": "#NAME已被淘汰出局", + "Tried to log in using a platform id the game does not support": "请勿使用游戏不支持的平台ID进行登录", + "PREMIUM WARBOND UNLOCKED": "已解锁尊享战争债券", + "to request reinforcement": "请求增援", + "AMMUNITION": "弹药", + "Failed to maintain session connection.": "游戏连接无法维持。", + "In Mission": "执行任务", + "#NAME: #MESSAGE": "#NAME:#MESSAGE", + "Receiving Confirmation": "正在接收确认信息", + "PRESS TO ACTIVATE": "按下按键即可启动", + "PURCHASE": "购买", + "In order to support fiscal responsibility, deployment magazine allocation for all weapons will be decreased for a short period of time.": "出于履行财政责任的需要,所有武器的弹匣配额都将在短期内降低。", + "No Helldivers on standby": "无绝地潜兵待命", + "Game found, preparing to travel...": "发现游戏,准备前往…", + "INTERNALS": "枪内", + "VANDALON IV UNDER ATTACK\nAutomaton dropships fill the skies of Vandelon IV. All Helldivers are called to its defense!": "万达隆IV遭到袭击\n机器人的运输舰遍布万达隆IV上空。呼唤全体绝地潜兵,前去保卫该星球!", + "Season III": "第III赛季", + "BUY MEDALS": "购买奖章", + "Select an Operation area to do Missions in - You can either join an ongoing Operation or start a new one.": "选择行动区域,前去执行任务 - 你既可以参加正在进行中的行动,也可以发起新的行动。", + "Steel Fist": "钢拳", + "ERATA PRIME FREED\nErata Prime has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet.": "艾拉特主星已解放\n艾拉特主星挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。", + "EXPLOSIVE HANDSHAKE": "热烈握手", + "Go to the Shipmaster and hand in your Orders.": "去找舰长提交指派任务。", + "to quick throw a Grenade": "快速投掷榴弹", + "Radiation Poisoning": "辐射中毒", + "MERIDIA FREED\nMeridia has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet.": "默里迪亚已解放\n默里迪亚挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。", + "STRATAGEM AVAILABLE": "战略配备可用", + "BARRAGE": "火力网", + "FENRIR III UNDER ATTACK\nThe Terminids are attempting to spread to Fenrir III. All Helldivers are called upon to deploy immediately to the planet's defense.": "芬里尔III遭到袭击\n终结族企图扩张至芬里尔III。呼唤全体绝地潜兵,立即前去保卫该星球。", + "Cannot While In Prone": "趴下时无法使用", + "Offline": "离线", + "WEAPON EXPERIMENTATION\nThe Jump Pack stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“喷射背包”战略配备暂时获准供全体绝地潜兵使用。", + "The Super Destroyer cannot remain in this area for long.\n\nEach Helldiver may call it back once per mission using the CALL IN SUPER DESTROYER Stratagem.": "超级驱逐舰无法在此区域长时间停留。\n\n每位绝地潜兵在单场任务中可使用呼叫超级驱逐舰战略配备召回驱逐舰一次。", + "Steam Login denied by the remote party": "远端拒绝登录Steam", + "#NAME has been court-martialed": "#NAME已被移交军事法庭", + "INTELLIGENCE BRIEF\n\nA new gunship-style unit has been reported across all Automaton battlefronts. No intel indicated the deployment of new Automatons units. Had the Communications Array on Troost been captured, we may have had adequate forewarning to prepare effective countermeasures. \n\nAs it stands, Helldivers will have to rely on currently available resources and their peerless tactical ingenuity to combat this new threat.": "情报简报\n\n据报告,所有机器人战斗前线都出现了一种新型炮舰单位。没有情报显示有新的机器人单位部署。如果顺利占领特鲁斯特的通讯阵列,我们可能会有足够的预警来准备有效的反击措施。\n\n目前的情况是,绝地潜兵将不得不依靠现有的资源和他们无与伦比的战术智慧来对抗这一新的威胁。", + "COMMON": "普通", + "Join": "加入", + "Extraction available.": "撤离飞船就位。", + "NNW (#COUNT°)": "西北偏北#COUNT°", + "With the borders of the Void contained and the Mindless Masses pushed back, Helldivers drove Democracy into the skulls of the Illuminate. The Ministry of Science has ample material from Voteless who emerged from the Void and will begin learning what they can about conditions within the Void. \n\nVictory belongs to Super Earth. \n\nAny damages to allocated FRVs will be taken from Helldiver pay.": "随着寂域的边界得到控制,无脑群氓被击退,绝地潜兵将民主狠狠砸入光能者的脑壳。科学部已经从寂域中涌出的无票者身上取得充足的材料,并将开始尽其所能地研究寂域内部的情况。\n\n胜利属于超级地球。\n\n配给快速侦察载具的损坏费用将从绝地潜兵的薪水中扣除。", + "Aspirant": "志士", + "LIBERATION FAILED\nAngel's Venture remains infested by the Terminid Menace.": "解放失败\n天使投资星系依然为终结族所侵占。", + "The TCS has been fully activated on half of the Barrier Planets.": "半数屏障星球上的TCS已经全面启动。", + "MINE": "地雷", + "#WEAPON_NAME MAGS": "#WEAPON_NAME弹匣", + "PREPARING": "正在准备", + "CONSTRUCTING GEOGRAPHIC MODEL": "正在构建地理模型", + "Message": "消息", + "DISTRIBUTE BALLOTS": "派发选票", + "NEXT": "继续", + "CLAIM LEGENDARY WARBOND": "领取传奇战争债券", + "PHASE 2": "第2阶段", + "Playfab Session Ticket has expired. Login to Playfab again": "Playfab会话票据已过期。请重新登录Playfab", + "Spend #COUNT more medals to unlock": "再花费#COUNT枚奖章解锁", + "INTELLIGENCE BRIEF\nA new strain of flying Terminids has suddenly appeared across all Terminid planets, with no prior warning or indication of any kind. While the Ministry of Intelligence has always known this was a possibility, the abruptness of the evolution indicates a high possibility of dissident concealment.\n\nThe deployment of Termicide was fortuitously timed—doubtlessly, it averted an even worse evolution. Helldivers are advised to exterminate these mutations whenever encountered.": "情报简报\n所有终结族星球上突然毫无预兆地进化出全新的飞行种终结族。情报部一直知晓终结族的突变可能,如今情况突然发生,表明其内部极可能隐藏了异见分子。\n \n我们意外凑巧地部署了灭虫终结剂,无疑给终结族的突变加了一道障碍,防止产生更严重的后果。但凡碰上这些突变体,建议绝地潜兵都要及时扑杀。", + "LIGHT COMBAT (BOTS)": "轻型作战(机器人)", + "OPERATION CONSUMING VOID SUCCESS": "吞噬寂域行动成功完成", + "OPTICS": "准镜", + "New CUSTOMIZATION available in the ARMORY.": "军械库现已开放全新自定义选项。", + "ENE": "东北偏东", + "BUSY": "忙碌", + "PERMANENT ITEMS": "永久物品", + "MISSION PAYOUT": "任务收益", + "Crystallized E-710": "710元素晶体", + "RADAR activated. Map details revealed.": "雷达启动。已显示地图细节。", + "Delivery Point": "交付点", + "Invalid Authorization response from PlayStation™Network, no Claims received": "来自PlayStation™Network的授权响应无效,未收到验证声明。", + "FENRIR III SECURED\nThe Terminid Control System is now fully activated on Fenrir III.": "成功占领芬里尔III\n终结族遏制体系已经在芬里尔III全面启动。", + "Black Saffron": "番黑花", + "Requires base stratagem": "需要基础战略配备", + "Destroy MALFUNCTIONING HELLPODS for gear.": "摧毁发生故障的绝地喷射舱,获得装备。", + "CALCULATING EVACUATION FLIGHT PATH": "正在计算疏散飞行路线", + "#NAME returned to civilian life": "#NAME已回归平民生活", + "Wrestle (MASH)": "摔角(MASH)", + "Killed x#AMOUNT": "成功击杀x#AMOUNT", + "Show PATRIOTISM.": "展现爱国精神。", + "WNW (#COUNT°)": "西北偏西#COUNT°", + "EVADING": "躲避", + "CALCULATING MISSILE TRAJECTORY": "正在计算导弹弹道", + "Electronic Countermeasures": "电子对抗", + "Throw": "投掷", + "PLANETARY BLACKOUT": "星球失联", + "The account has a Steam session token but it's not authenticated": "账号拥有Steam会话令牌,但是该令牌尚未验证", + "DISPATCHES": "报告", + "EMERGENCY": "紧急情况", + "LAMBS TO THE SLAUGHTER": "待宰羔羊", + "When you're prone you fire more accurately.": "匍匐姿态下射击更精准。", + "Poor Intel": "缺乏情报", + "Search Platoon Members": "搜索特战排成员", + "WEAPON EXPERIMENTATION\nThe Orbital Gas Strike stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“轨道毒气攻击”战略配备暂时获准供全体绝地潜兵使用。", + "Non-Guided": "非制导", + "HIGH SCORES": "最高分", + "Board the EXTRACTION SHUTTLE!": "登上撤离运输船!", + "Weapon Customization is now available. Click the CUSTOMIZE button to begin adjusting your weapon.": "武器自定义内容现已解锁。点击自定义键开始调整武器。", + "SUPPLY": "补给", + "Your right arm is injured, impacting your ability to aim and throw.": "你的右臂受伤了,你瞄准和投掷的能力将受到影响。", + "Support Weapons can be carried in addition to your primary weapon. Call in a MACHINE GUN.": "你可以同时携带主武器和支援武器。呼叫机枪吧。", + "Joined.": "加入成功。", + "SHIP": "舰船", + "E-710 OUTFLOW": "710元素外流", + "HELLBOMB": "地狱火炸弹", + "Orbital Fluctuations": "轨道波动", + "#NAME is no longer part of the team": "#NAME不再是团队一员", + "Playfab account not allowed to login. Please contact Community managers": "Playfab账号禁止登录。请联系社区管理员", + "Melee Kill": "近战击杀", + "ALERT": "警告", + "CAMPAIGN UPDATE\nDue to successful intelligence operations, each completed operation will contribute more than normal to planetary liberation.": "战役动态\n由于情报行动大获成功,完成的每一场行动都会比平时更加有效地推动星球的解放大业。", + "S (#COUNT°)": "南#COUNT°", + "#COUNTx": "#COUNTx", + "Open STRATAGEM MENU and call in a ORBITAL 120MM HE STRIKE at the remaining targets.": "打开战略配备菜单,呼叫轨道120MM高爆弹攻击,瞄准剩下的目标。", + "All of these reviews have been devised by Super Earth's Ministry of Truth after an analysis to reflect the most accurate possible opinions of loyal Super Earth citizenry. In other words, these are not real reviews.": "所有评论均由超级地球真理部经过分析后构思编成,以便尽可能准确地反映超级地球忠实公民的意见。换言之,这些都不是真实的评论。", + "PRIMARY": "主武器", + "The Automatons have established footholds on many Super Earth planets. Citizens have lost their homes, and now significant resources must be expended to regain the lost territory.": "机器人在许多属于超级地球的星球上建立了据点。无数公民因此流离失所。现在我们不得不耗费大量资源才能收复失地。", + "PlayStation®Plus is required to play this game.": "游玩本游戏需要PlayStation®Plus。", + "HUG": "拥抱", + "ARMORS": "盔甲", + "DENYING A BASE OF POWER": "绝不让步", + "Guided": "制导", + "FFF68AFF": "FFF68AFF", + "WEAPON EXPERIMENTATION\nThe Shield Generator Pack stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“防护罩生成包”战略配备暂时获准供全体绝地潜兵使用。", + "NW (#COUNT°)": "西北#COUNT°", + "SHOW PLAYER PROFILE": "显示玩家个人资料", + "Retrying In #TIME": "将在#TIME秒后重试", + "MORT FREED\nMort is finally free from the oppressive Automaton presence. Our hopeful citizens look forward to the commencement of colonization efforts.": "莫特已解放\n暴虐的机器人终于从莫特的土地上消失。满怀希冀的公民此刻开始期待启动拓殖任务。", + "Requisition RESUPPLY stratagem.": "申购重新补给战略配备。", + "RAIN DOWN FROM ABOVE": "天降民主雨露", + "#NAME left the mission": "#NAME退出任务", + "LIBERATION FAILED\nDespite great sacrifice, Ingmar remains under Automaton control.": "解放失败\n尽管我方付出了巨大的牺牲,但仍未能让英格玛脱离机器人的铁爪。", + "Alt. Ammo": "备用弹药", + "MISSION STARTING": "任务即将开始", + "You are already in this game session.": "已加入本场游戏。", + "Your left arm is injured, impacting your ability to aim.": "你的左臂受伤了,你瞄准的能力将受到影响。", + "Orbitals Used": "轨道攻击次数", + "ELIMINATED": "阵亡", + "Electro-Whip": "电鞭", + "Requisition MACHINE GUN SENTRY stratagem.": "申购哨戒机枪战略配备。", + "Legendary": "传奇", + "#NAME left": "#NAME已退出", + "SLOWER EXTRACTION": "撤离减慢", + "REFRESH": "刷新", + "#NAME didn't make the cut": "#NAME已被淘汰出局", + "NE (#COUNT°)": "东北#COUNT°", + "The Destroyer has left orbit": "驱逐舰已离开轨道", + "FORTIFICATION": "防御工事", + "NO ROOM": "空间不足", + "to move": "移动", + "Trying to upgrade an already fully upgraded weapon/stratagem.": "你正在尝试升级一项已经升至满级的武器/战略配备。", + "NO FUEL": "没有燃料", + "MISSION STRATAGEMS": "任务所需战略配备", + "SPREADING DEMOCRACY": "播撒民主", + "ARMOR": "盔甲", + "Idle hands are a fascist's playthings": "怠惰是法西斯的陋习", + "Enemy Kills": "敌方击杀数", + "Stats": "数据", + "SUPER URANIUM": "超铀", + "MIME INSTRUMENTATION": "弹空气吉他", + "The EXO-45 PATRIOT EXOSUIT is ready for use. Helldivers are advised to familiarize themselves with its features—ideally during live combat situations—as quickly as possible.": "EXO-45“爱国者”外骨骼装甲已经准备就绪。建议绝地潜兵尽快熟悉装甲的功能特性(最好是在实战环境中)。", + "ENTER": "进入", + "MISSION STATS UNAVAILABLE": "任务数据无法显示", + "Medium Bug Nest Eradicated": "中型巢穴成功摧毁", + "WEAPON EXPERIMENTATION\nThe AC-8 Autocannon stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“AC-8机炮”战略配备暂时获准供全体绝地潜兵使用。", + "RESTART": "重新开始", + "WAR INFLUENCE: #WAR_INFLUENCE": "战争影响力:#WAR_INFLUENCE", + "Rock Paper Scissors": "石头剪刀布", + "SUPER RARE": "超稀有", + "to equip your Primary Weapon": "装备主要武器", + "HELLMIRE UNDER ATTACK\nThe bugs have attacked Hellmire. Rally to its defense, before they are able to permanently infest it.": "海尔迈尔遭到袭击\n虫族对海尔迈尔发动了袭击。立即集结,前去防卫,避免领地永远落入敌人手里。", + "#X/#Y": "#X/#Y", + "TEAM WEAPONS can be reloaded by teammates.": "团队武器可由队友装填弹药。", + "LOAD SHELL": "填弹", + "LIBERATION FAILED\nCrimsica remains infested by the Terminid Menace.": "解放失败\n克里姆西卡依然为终结族所侵占。", + "On Ship": "在船舰上", + "Equip": "装备", + "DEAD": "死亡", + "Hero": "英雄", + "TIMEOUT IN #MINS:#SECS": "超时倒计时 #MINS:#SECS", + "Failed to validate the Steam token provided by the client": "无法验证客户端提供的Steam令牌", + "VEHICLES #COUNT/#TOTAL": "载具 #COUNT/#TOTAL", + "Invalid Authorization for PlayStation™Network - Token Empty": "PlayStation™Network的授权无效 - 令牌为空", + "Target Account Profile is not found": "未找到目标账号资料", + "Failed to join because the session is full.": "游戏已满员,加入失败。", + "LIBERATION FAILED\nWe have failed to liberate Vandalon IV from the Automatons.": "解放失败\n我们未能从机器人手上解放万达隆IV。", + "TIMEOUT IMMINENT": "即将超时", + "ZEROING": "归零", + "Use Backpack": "使用背包", + "ACQUISITION CENTER": "采购中心", + "Scout Handshake": "侦察兵式握手", + "Tried to log in using legacy login with a non-test account": "请勿使用非测试账号执行遗留登录", + "Waiting for Super Earth approval of purchase...": "正在等待超级地球批准购买…", + "to reload your weapon": "为武器装弹", + "Test account not allowed to login. Please contact Community managers": "测试账号禁止登录。请联系社区管理员", + "INTELLIGENCE BRIEF\nThe Aerial Terminid Subvariant, dubbed \"Shriekers,\" has become a significant and pervasive strain, spreading across all Terminid planets. The Terminid's tyrannical instinct defies even the laws of nature, and now they infest our spacious skies. Helldivers are advised to stay vigilant for Shrieker nests and purge any they come across.": "简报\n飞行终结族亚种,别称为“尖啸虫”,它们已成为随处可见的变异个体且构成严重威胁,蔓延至终结族占领星球的各个角落。终结族凭借暴政本能藐视自然的规则,如今还侵袭了我们广阔的天空。请绝地潜兵警惕尖啸虫的巢穴,一旦遇上这类敌人,立即将其清除。", + "to look around": "环顾四周", + "LASER PRISM": "激光棱镜", + "FLASHLIGHT": "照明", + "EXALTED HERO": "伟人", + "Heavy Automaton Outpost Destroyed": "重型机器人哨站成功摧毁", + "#NAME left": "#NAME已退出", + "INGMAR LOST\nThe Automatons have taken Ingmar. A dark day for Managed Democracy.": "英格玛沦陷\n机器人已然占领英格玛,这是管理式民主史上黑暗的一天。", + "Round": "回合", + "to adjust valve": "调整阀门", + "Super Uranium": "超铀", + "Gunships are Patroling the Area": "炮舰正在巡逻此区域", + "SELECT": "选择", + "A heavily fortified Automaton position containing an Automaton CPU with valuable secret data. Extract with it, and your counterintelligence support will be rewarded.": "防卫森严的机器人据点,内部设置了机器人CPU,存有宝贵的机密数据。携带该CPU撤离,你的反情报支持工作将获得相应回报。", + "HEAVY COMBAT (ILLUMINATE)": "重型作战(光能者)", + "#SECONDSs": "#SECONDS秒", + "Lobby is private. You do not have permission to join.": "私密大厅,没有加入权限。", + "Inventory Value": "生涯消费", + "Self inflicted": "自伤", + "Reward: #TYPE": "奖励:#TYPE", + "LIBERATION FAILED\nDespite innumerable sacrifices, we have failed to liberate Veld from the Terminid's claws.": "解放失败\n尽管付出了无数的牺牲,我们还是未能将维尔德从终结族的暴虐魔爪中解放出来。", + "REINFORCE AVAILABLE": "增援就位", + "Shuttle Departing In T-#MINUTES:#SECONDS:#MILLI": "运输船出发倒计时 #MINUTES:#SECONDS:#MILLI", + "SE (#COUNT°)": "东南#COUNT°", + "Volley": "齐射", + "KMH": "公里/时", + "SHIP MODULES": "舰船模块", + "START UP": "出发", + "MISSION SUCCESSFUL": "任务成功", + "EXTRACTION AVAILABLE": "撤离飞船就位", + "#NAME": "#NAME", + "Mime Instrumentation": "弹空气吉他", + "N (#COUNT°)": "北#COUNT°", + "VALUE": "色值", + "Samples": "样本", + "When carrying something in one hand, you can only wield one-handed weapons.": "其中一只手携带物体时,你只能持有单手武器。", + "COMPLETED": "已完成", + "SUPPLY BACKPACK can carry extra ammo. Use the BACKPACK FUNCTION to resupply yourself.": "补给背包可以装载额外的弹药。使用背包功能为自己补充弹药。", + "TARGET DESTINATION": "目的地", + "to use stim": "使用治疗剂", + "Friends": "好友", + "Beacon must be under constant supervision once activated.": "信标一旦启动,必须一直监控。", + "Deployment magazine allocation will be temporarily increased, in order to expend excess inventory.": "为消耗过剩库存,弹匣配额将暂时提高。", + "Total": "全射", + "SHOTGUN": "霰弹枪", + "#NAME": "#NAME", + "PREMIUM WARBOND NEEDED": "需要尊享战争债券", + "Approaching OUTPOST. Call in a GATLING SENTRY for extra firepower.": "正在接近哨站。呼叫加特林哨戒炮提供额外火力。", + "INTEL PDA": "情报PDA", + "FRIENDS ON PLAYSTATION®": "PlayStation®的朋友", + "Fortress": "堡垒", + "MUTE": "静音", + "VOLUME: #COUNT": "音量:#COUNT", + "PLEASE WAIT DEMOCRATICALLY": "请民主地等待", + "INVITE SENT": "已邀请", + "UNMUTE": "取消静音", + "KICK (HOLD)": "移除(长按)", + "Requisition slips": "申购单", + "Medal": "奖章", + "Vote": "投票", + "VOTE SUCCESSFUL": "投票成功", + "You have performed your democratic duty\nWELL DONE!": "你已履行你的民主职责\n干得漂亮!", + "#DAYS DAYS #HOURS HOURS #MINUTES MIN": "#DAYS日#HOURS小时#MINUTES分", + "CANDIDATE NOT ELIGIBLE FOR VOTES": "候选人没有投票资格", + "BIOGRAPHY:": "生平事迹:", + "Please wait while Super Earth democratically processes your ballot.": "超级地球正在进行民主计票,请稍候。", + "Term #TERM": "任期:#TERM", + "ELECTION STARTS IN:": "选举开始倒计时:", + "ELECTION ENDS IN:": "选举结束倒计时:", + "POLICY:": "政策:", + "VOTE FAILED": "投票失败", + "TERM #TERM": "任期:#TERM", + "The uncanny illumination seeping from the bulb stains the surroundings with its tyranny.": "灯泡中散发出的诡异光芒让周围笼罩在暴政的阴影之中。", + "From the graceful typography to the elegant use of space, this sign is a masterwork of patriotic craftsmanship.": "排版优雅、留白高明,这个标牌堪称爱国主义艺术品的杰作。", + "\"Congratulations on Procreation Approval for [1] child. May you multiply the love of Democracy for generations to come.\"": "“祝贺你获准生育[1]个孩子。愿你将对民主的热爱传承给后世子孙。”", + "AUTOMATON REMAINS": "机器人的遗骸", + "A message is etched into the surface: \"In everlasting gratitude to the loyal soldiers who gave their lives in the defense of Managed Democracy.\"": "雕像表面刻着一句话:“永远感谢为捍卫管理式民主而牺牲的烈士。”", + "Without power, this vendor of beverages is only a lifeless husk. Another innocent casualty of Tyranny.": "没了电,这台自动饮料售货机不过是一具空壳,也是暴政的无辜受害者。", + "COMMUNICATIONS DEVICE": "通信设备", + "\"Cache Inventory:\n-300 rounds Liberator ammo\n-14 stims\n-12 gallons water\n-3 frag grenades\"": "“隐藏库存:\n- 300发“解放者”弹药\n- 14支治疗剂\n- 12加仑水\n- 3枚榴弹”", + "\"HELLDIVER TRAINING FACILITY\nWelcome to Helldiver Training\nEARN YOUR CAPE\nCHECK YOUR MAP TO FIND THE HELLDIVER FACILITY\"": "“绝地潜兵训练基地\n欢迎接受绝地潜兵的训练\n努力赢得披肩吧\n查看地图,寻找绝地潜兵基地设施”", + "GREENHOUSE - TYPE 203": "温室 - 203型", + "The crimson glow, no doubt with nefarious intention, is now used by discerning Helldivers as a indicator of this device's explosive nature.": "绯红的光芒赫然彰显着邪恶意图,但敏锐的绝地潜兵一眼就能看出这个装置属于炸弹。", + "\"For alien scum\"": "“致异形渣滓”", + "VENDING MACHINE": "自动售货机", + "A tool is missing from its spot. Likely pilfered by the enemy for some iniquitous application.": "工具不翼而飞。很可能是心怀不轨的敌人偷走的。", + "The voltage of these batteries has been temporarily saved from being yoked to the expansion of the Automaton menace.": "这些电池暂时得救了,不必在机器人威胁扩张之下遭受奴役。", + "\"Welcome! Please note: failure to feel sufficiently welcomed should be reported immediately.\"": "“欢迎!请注意:如果未能感受到足够热烈的欢迎,请立即举报。”", + "\"Please present this certificate as proof of approval to perform a left-handed salute for the duration of your injury.\"": "“请出示这张许可,证明你已获准在受伤期间用左手敬礼。”", + "The greenhouse maintains an atmosphere nearly identical to that of Super Earth.": "这间温室维持着与超级地球几乎相同的空气成分。", + "The cascade of sparks is like a patriotic celebration of triumph over this threat to Democracy.": "星火流瀑,仿佛是战胜民主威胁的爱国庆祝活动。", + "Its unclear if this Automaton can still perceive external stimuli. There's no telling how long it will remain in this state before its battery expires.": "这个机器人是否还能感知外部刺激是个未知数。不知道它在电池耗尽之前能保持这种状态多久。", + "\"Happy Liberty Day, bugs!\"": "“虫子们,解放日快乐!”", + "The machine appears to be empty of its delicious, refreshing beverages.": "售货机里清爽可口的饮料似乎已售罄。", + "The pale gleam of the lamp is sinister and alien, doubtlessly due to its un-Democratic fashioning.": "这盏灯苍白的微光十分邪恶和诡异。毫无疑问,这是非民主设计方式导致的。", + "The Gateways at Giza. Modern living with an age-old charm. Units available.": "吉扎之门。古色古香的现代生活。正在出售。", + "\"Eulogy Template—Soldier, friendly fire variation 016: [Name] devoted many hours to the prosperity of Super Earth. They may rest easy in the knowledge that the [bullets/shrapnel/concussive force] that took their life was Democratic in origin and fired in the service of Liberty.\"": "“悼词模板 - 士兵,友军误伤016版:[姓名]为超级地球的繁荣鞠躬尽瘁,将安然长眠,因为夺走其生命的[子弹/弹片/武装]是为民主而发,是为解放而战。”", + "The screen is frozen on a rousing reminder of the value of strenuous labor.": "画面定格在一条宣扬辛勤劳动价值的提醒上。", + "It only takes ONE TRAITOR to destroy Utopia.\n\nThe Ministry of Unity.": "一个叛徒足以瓦解乌托邦。\n\n团结部", + "A rack containing every tool one needs to construct a better tomorrow.": "一副支架,上面放着构建美好明天所需的所有工具。", + "\"The Charger continues to display increased agitation upon exposure to imagery of Helldivers. Possible evolved response?\"": "“强袭虫在看到绝地潜兵的图像后越来越躁动不安。可能是进化后的反应?”", + "Not in my backyard.\n\nEnlist.": "绝不能危及家园。\n\n应征入伍。", + "\"The Colonial Overseer's Handbook. A guide to Planetary Terraforming, Resource Extraction, and Colonist Management. Approved by the Ministry of Expansion.\"": "“《拓殖地监督员手册》,行星地球化、资源开采和拓殖地居民管理指南。经扩张部审核通过。”", + "\"Next!\n\nBuy war bonds.\"": "“下一个目标!\n\n购买战争债券。”", + "PUBLIC SERVICE POSTER": "公共服务海报", + "DESPOTIC EXPLOSIVE": "专制炸药", + "\"The Ministry of Science reminds all citizens of the numerous citizenship benefits to enrolling yourself and you family in medical studies. Could your body be of greater use to Liberty?\"": "“科学部提醒各级公民全体成员,全家加入医学研究,益处良多。你愿意全身心贡献给解放事业吗?”", + "\"Next week's delivery:\n -4 Liberators\n -2 cases prefab meals\n-Fuel drum\"": "“下周交付:\n- 4把“解放者”\n- 2箱预制饭菜\n- 燃料桶”", + "These batteries fuel the Automaton war machine.": "这些电池为机器人的战争机器补充能源。", + "\"Concerns of mine safety, including long hours, dim tunnels, insufficient supports, rickety ladders, etc., have been noted, considered, and addressed. Please continue with renewed confidence in your safety.\"": "“工作时间长、隧道昏暗、支援不足、梯子摇晃等矿井安全问题已获关注、斟酌和解决。请重拾对人身安全的信心,继续作业。”", + "HASTILY WRITTEN NOTE": "匆匆写下的便条", + "The glow of the interior bulb is out, leaving the artful branding a pale shadow of its former vivid glory.": "内部灯泡不再发光,这份精致的宣传仅剩往昔熠熠光辉余留的一丝苍白残影。", + "PATRIOTIC POSTER": "爱国海报", + "The 11th in the \"Loyalty\" series, this sign is a return to form after the extravagance of version 10.": "“忠诚”系列的第11版标牌。相比华丽的第10版,这一版标牌可谓返璞归真。", + "Who can say what heinous deeds this machine was intended to carry out?": "谁知道它们打算用这台机器干出何等令人发指的罪行?", + "\"EMERGENCY WARNING: Hostile forces incoming. Evacuate immediately. EMERGENCY WARNING: Hostile forces incoming. Evacuate immediately.\"": "“紧急警告:敌方军队即将抵达。立即撤离。紧急警告:敌方军队即将抵达。立即撤离。”", + "HANDWRITTEN NOTE": "手写便条", + "FORKLIFT": "叉车", + "\"The Ministry of Humanity regrets to learn of the tragic loss of your family member. Please follow the enclosed instructions for proper patriot disposal and tax forms.\"": "“得知你痛失家人,人道部深表遗憾。请按照随附的说明妥善处理爱国者的遗体及纳税表格。”", + "OPPRESSIVE MACHINE": "压迫机器", + "\"Colonial alert: due to budgetary constraints, dwelling temperatures will be lowered by [13%].\"": "“拓殖地警告:由于预算受限,住宅温度将降低[13%]。”", + "BLOOD-STAINED LIBRARY CARD": "血迹斑斑的借书证", + "AUTHORITARIAN LIGHT": "独裁之光", + "\"Congratulations on your acceptance to Trailblazer University, the premier online educational institution for tomorrow's colonial leaders.\"": "“祝贺你被开拓者大学录取,这是培养拓殖地未来领袖的一流在线教育机构。”", + "A message is etched into the surface: \"In eternal remembrance of the innumerable Helldivers who made the ultimate sacrifice in the First Galactic War.\"": "雕像表面刻着一句话:“永远怀念第一次星系战争中献身的无数绝地潜兵。”", + "The purpose of this machine is unknown, it is as irredeemable as its creators.": "这台机器用途不明,跟它的制造者一样无药可救。", + "WORDS SCRIBBLED ON BOMB": "炸弹上的潦草文字", + "Truth: the backbone of Democracy.\n\nThe Ministry of Truth.": "真理乃民主之本。\n\n真理部", + "Used to transport ore, modular dwellings, and dissident holding pens.": "用于运输矿石、模块化住房和异见分子的关押栏。", + "Tyranny contained within a matrix of anodes and cathodes.": "暴政就在阳极和阴极组成的矩阵之内。", + "Half a message is typed on this blood-spattered tablet: \"Request immediate fire support. Taking heavy ca-\"": "留有血迹的平板上残留着输入到一半的消息:“请求立刻提供火力支援。伤亡惨…”", + "\"Deliver to Terminids ASAP\"": "“尽快送至终结族”", + "ADVERTISEMENT": "广告", + "Automaton glyphs mark the exterior, menacing and power-hungry in their contortions.": "电池表面刻着机器人的符号。歪歪扭扭的笔画暴露了它们凶恶的本性以及对能源的渴望。", + "RE: MINE SAFETY": "回复:矿山安全", + "\"Remember: late returns steal from us all.\"": "“切记:逾期归还等同于偷窃公共财物。”", + "\"Don't forget to vote on YOUR colony's Patriot of the Month!\"": "“别忘了投出宝贵一票,选出你所在拓殖地的‘本月爱国者’!”", + "A twisted distortion of one of Humanity's greatest inventions.": "人类最伟大的发明之一,现已扭曲变形。", + "\"Handle with care\"": "“小心轻放”", + "\"Eulogy Template—Soldier, variation 004: [Rank] [Name] joined the service at [age]. They served [noble adverb] and perished heroically while fighting [enemy]. We will never forget their [unique trait].\"": "“悼词模板 - 士兵,004版:[军衔][姓名]在[年龄]时入伍,[体现崇高品质的副词]服役,在与[敌人]作战时英勇牺牲。我们永远不会忘记这位英雄的[独特品质]。”", + "These plants are beginning to wilt in the absence of Democracy's tender care.": "没有了民主的呵护,这些植物便开始枯萎。", + "Everything you need to know.\n\nThe Ministry of Truth.": "了解你需要知晓的一切。\n\n真理部", + "\"Diet Democracy. Free yourself.\"": "“饮食民主。解放自我。”", + "We stay INFORMED to inform YOU.\n\nThe Ministry of Truth.": "追求真理,传播真理。\n\n真理部", + "Tools are hung neatly, in accordance with governmental guidelines.": "工具摆放得整整齐齐,严格遵守政府规定。", + "\"Do not operate without a ground guide.\"": "“必须有地勤人员指引。”", + "Divorced from it's tyrannical programming, the metal of this former Automaton is free once more.": "摆脱了专制程序,用来构建这个机器人的金属材料重获自由。", + "\"Alert: due to increased local hostile activity, all funerals are to use Expedited Internment Procedures until further notice.\"": "“警告:由于当地敌对活动激增,全部葬礼须使用加急安葬程序,直至另行通知。”", + "\"Don't forget! Catch the bi-weekly State of the Federation announcement at 8PM tonight (absence must be pre-approved).\"": "“别忘了!请准时收看今晚8点播出的双周联邦政府通报(需获批准才能缺席)。”", + "Keep their tentacles off our children!": "不能让它们将触手伸向我们的孩子!", + "\"Offerings include: Dr. Democracy, Mr. Taste, Prof. Delicious, & Yummm, Esq.\"": "“供应:民主博士、美味先生、好吃教授与可口先生。”", + "A standard-issue rack of standard-issue tools.": "收纳制式工具的制式支架。", + "\"Please refrain from operating heavy machinery while consuming this beverage.\"": "“享用这种饮料时,请勿操作重型机械。”", + "ENTRY ##64": "第64条", + "\"Reminder: Planetary Overseer elections are just around the corner!\"": "“提醒:行星监督员选举已近在眉睫!”", + "A message is etched into the surface: \"In memory of Liberty's servants who perished heroically in unavoidable friendly fire incidents.\"": "雕像表面刻着一句话:“纪念因难以避免的友军误伤而英勇阵亡的解放忠仆。”", + "\"Get some!\"": "“尝尝我们的厉害!”", + "\"Eulogy Template—Soldier, Exemplary Service 121: The heroism of [Rank] [Name] cannot be understated. They did not lose their life in the defense of Super Earth. They gave it, willingly.\"": "“悼词模板 - 士兵,模范军人121版:[军衔][姓名]的英勇精神不可估量。这位英雄并非因为保卫超级地球而丧命,而是心甘情愿献出生命。”", + "\"Memo to all SEAF forces: Moving forward, frontline mail services will be reserved for soldiers of exceptional democratic service only.\"": "“发送给超级地球武装部队全体成员的备忘录:随着部队的推进,前线邮政服务将仅对作出特殊民主贡献的军人开放。”", + "A smoldering heap of scrap. It got what it deserved.": "一堆闷烧的废料。总算是恶有恶报。", + "\"Note to Grave Preparation Specialist: due to high hostile activity in the area, graves may be required to accomodate more personnel than usual.\"": "“墓地整备专员注意事项:由于该区敌对活动频繁,需要下葬的人数多于正常水平。”", + "Raises your mission priority to all other Helldivers, increasing the odds of others joining your squad.": "将你的任务优先级提升到所有其他绝地潜兵之前,增加其他士兵加入你小队的几率。", + "\"Please report immediately to your Loyalty Officer for investigation. Reason: [Citizen Report of Dissident Speech].\"": "“请立即向你的忠诚事务官举报以便展开调查。理由:[公民举报异见分子言论]。”", + "The robotic manipulators at the end of the arm can grasp nothing, save oppression.": "在背后操控这支机械臂的那些家伙除了施加压迫以外,什么也抓不住。", + "\"Local hostile activity is currently assessed as LOW THREAT. All citizens are to continue duties until further notice.\"": "“当地敌对活动目前被评估为‘低威胁’。所有公民继续履行职责,直至另行通知。”", + "\"The Ministry of Humanity has processed your missing persons report. Result: [CLOSED.] Conclusion: [Mine mishap.]\"": "“人道部已处理你的失踪人口报告。结果:[已结案。]结论:[矿井事故。]”", + "\"Not suitable for traitors of democracy.\"": "“不适合民主的叛徒。”", + "\"Please select which delicious flavor you would like to see included in our colony's next seasonal rations: Blueberry, Chocolate, Cinnamon, Birthday Cake.\" Birthday Cake is selected.": "“请选择你希望在拓殖地下一季口粮中尝到的口味:蓝莓、巧克力、肉桂、生日蛋糕。”已选择生日蛋糕。", + "SUPER EARTH ISSUED TOOL RACK": "超级地球常规工具架", + "CASE OF \"DEMOCRACY DRAFTS\" PREMIUM LIGHT BEER": "“民主之风”至尊淡味啤酒的外包装", + "MONUMENT TO LIBERTY": "解放纪念碑", + "The screen is frozen on one final message: \"Hold.\"": "画面定格在最后一条消息:“坚持住。”", + "SOS Beacon": "S.O.S.求救信标", + "\"Memo to Colonial Overseer: Be sure to calibrate the productivity output of your workers in accordance with your Compliance Index.\"": "“拓殖地监督员备忘录:务必按照服从指数校准工人的生产力输出。”", + "\"The Ministry of Humanity would like to congrulate you on approval for marriage. Enclosed are instructions for consolidating domiciles.\"": "“人道部祝贺你们获得婚姻许可。随函附上住所合并说明。”", + "SEAF COMMUNICATIONS DEVICE": "超级地球武装部队通信设备", + "In this abundant garden of flora native to Super Earth, Liberty has taken root on an alien planet.": "这花园里长满了超级地球的各种原生植物,有如解放精神在这颗外星球上稳稳扎根。", + "\"Due to the exceptional hazard of the current posting, all SEAF soldier's and their approved domestic family units will be granted Class C citizenship following mission completion or death.\"": "“由于目前外派任务特别危险,所有参加任务的超级地球武装部队士兵与其获批家属都将在任务完成或阵亡后获得C级公民身份。”", + "\"Memo to Colonial Overseer: In order to best serve Freedom, the security budget for your colony will be reduced by [23.7%] for the next fiscal term.\"": "“拓殖地监督员备忘录:为了更好地为自由服务,你所在拓殖地的安全预算将在下一个财政任期内减少[23.7%]。”", + "\"Took stash. Needed it. Sorry. \n P.S. This man was dead when I got here. \n-D\"": "“拿走了隐蔽装备。急需。抱歉。\n注:我到的时候这个男人就已经死了。\n-D”", + "The screen shows a picture of what must be a SEAF soldier's family, holding a banner saying \"Defend our Freedom.\"": "画面的照片里想必是超级地球武装部队士兵的家人,他们手举带有“捍卫自由”字样的横幅。", + "\"Was low on supplies. Took ammo. Left oatmeal. Good luck -D\"": "“补给短缺。拿走了弹药。留下了燕麦片。祝你好运 -D”", + "WELCOME SIGN - HOMELY VARIANT 02": "欢迎标牌 - 家常版02", + "This forklift is the red blood cell of Managed Democracy, conveying vital necessities to wherever they are needed.": "这辆叉车是管理式民主的红细胞。哪里需要重要物资,哪里就有它们的身影。", + "A pair of safety goggles hang by a strap, the frames spattered with blood. They seem to have failed their purpose.": "一副安全护目镜挂在带子上,镜框上有血迹。看来它没能完成自己的使命。", + "\"Ministry of Truth Library Branch 301C\"": "“真理部图书馆301C分馆”", + "LIBERTY OUTLETS\n\nWorld's Longest Shopping Mall": "解放奥特莱斯\n\n全世界历史最悠久的购物中心", + "Billions of stars. One Federation.\n\nThe Ministry of Expansion.": "亿万星辰归属一个联邦。\n\n扩张部", + "Whether this Automaton can ever have been said to be alive is a question for the philosophers. In either case, it is definitely dead now.": "这个机器人能否算得上“活着”是个哲学问题。但不论它有没有“活过”,现在肯定已经死透了。", + "A tool of tyranny.": "实施暴政的工具。", + "\"Notice to Colonists: A military operation is being conducted in your vicinity. There is no need for alarm. Please remain indoors until further notice.\"": "“拓殖地居民请注意:附近正在执行军事行动。不必担心。请留在室内,等待另行通知。”", + "\"Have a taste of freedom!\"": "“这就是自由的力量!”", + "The cracked device displays a photo of a smiling child with a pickaxe over their shoulder.": "被破解的设备上显示一张照片,上面是肩扛鹤嘴锄、露出微笑的孩子。", + "CAPTAIN'S LOG": "少校的日志", + "We defend Democracy's Future.\n\nThe Ministry of Defense.": "捍卫民主的未来。\n\n国防部", + "Keep an ear open for TREASON.": "时刻警惕叛国。", + "\"From Super Earth With Love\"": "“来自超级地球,饱含热爱”", + "The synthetic marble figure communicates a message of proud freedom that crosses all boundaries of species and sapience.": "这座人造大理石雕像传达以自由为傲的理念,已超越一切种族与智慧界限。", + "The Ministry of Prosperity ensures every colony has access to the latest beverages, extending libationary ingenuity to all Super Earth's citizens.": "繁荣部保证每一个拓殖地都能享用最新的饮品,让向全体超级地球公民传播独创的饮料文化。", + "An abomination constructed by abominations, with abominable intent.": "可恶的机器人怀着可恶的用心制造的可恶机械。", + "Loyalty is Rewarded. Report any dissident activity.\n\nThe Ministry of Unity.": "忠诚有奖。请及时举报任何异见分子活动。\n\n团结部", + "Inspect": "查看", + "\"Attention: Your Animal Companion Request for [1] [hamster] has been denied at this time.\"": "“注意:你对圈养[1]只[仓鼠]作为陪伴动物的申请本次已拒绝。”", + "Remember Outpost 32": "铭记32号哨站", + "On the surface, only a lamp, but any true patriot recognizes this for what it is: an abomination.": "看似一盏灯,但真正的爱国者都能认出它那面目可憎的本质。", + "\"HELLDIVER TRAINING FACILITY\"": "“绝地潜兵训练基地”", + "Scratched into the pedestal: \"They will save us.\"": "底座上刻着:“他们会救我们。”", + "A frantic final harvest appears to have been attempted during evacuation.": "撤离期间似乎有人试图疯狂收割最后一波。", + "Transporting a large shipment of flamethrowers. Heavy enemy presence - delivery expected to take the whole day. Derek forgot the fire extinguisher but I'm sure we'll be fi-": "正在运输大量火焰喷射器。敌人攻势强劲,预计要花一整天才能送到。德里克忘了带灭火器,但肯定不会出意……", + "A device used to communicate between the Department of Expansion and Colonial Overseers.": "拓殖地监督员和扩张部之间的通信设备。", + "\"To Whichever Terminids It May Concern\"": "“至拿到此物的终结族”", + "\"Pesticide\"": "“杀虫剂”", + "This machine gives no sign of sapience, but one can never be too sure.": "这台机器看起来不具备智慧,但是世上没有绝对之事。", + "PERSONAL DEVICE": "个人设备", + "\"You are legally required to report any Terminid attacks to the authorities!\"": "“依照法规,只要终结族发动攻击,你必须向当局汇报!”", + "\"ORDER: Do not retreat. Defend Liberty at all costs.\"": "“命令:不要撤退。不惜一切捍卫解放事业。”", + "Once alive with a calming hum, the abandoned machine now lies dormant.": "这台机器曾经能发出让人安心的嗡嗡声,现在则遭到遗忘,在此长眠。", + "\"Ministry of Defense study indicates enemy morale reaching new, unprecedented lows.\"": "“国防部研究显示,敌人的士气正达到前所未有的低点。”", + "The eerie calm of the exterior masks the autocratic potential energy trapped within.": "平凡却怪异的外表下掩藏着束缚在内的专制能量。", + "\"Remember: complaints are the gateway to dissidence.\"": "“记住:抱怨是通往异见之门。”", + "\"Dr. Democracy: With 17 seasonings and additives\"": "“民主博士:包含17种配料和添加剂”", + "What are you waiting for?": "你还在等什么?", + "The patriotic hues are enough to stir the heart of any true patriot.": "浓厚的爱国色彩足以打动每一个真正爱国者的心。", + "\"The Ministry of Truth would like to remind all citizens that un-Democratic reading material must be reported immediately.\"": "“真理部温馨提醒全体公民,如果发现非民主读物,务必立即上报。”", + "Stop the infestation!": "制止侵袭!", + "REPRODUCTION": "繁殖速度", + "TCS FULLY OPERATIONAL": "TCS全面运作", + "MINISTRY OF PROSPERITY ANNOUNCES CLOSURE OF MIDASBURG MINT AFTER 75 YEARS OF OPERATION": "繁荣部宣布关闭运营75年的弥达斯堡造币厂", + "AUTOMATON INCURSION": "机器人入侵", + "BUG CONTAINMENT": "虫族管控", + "TCS ACTIVATION UNDERWAY": "TCS启动工作进行中", + "GALAXY IN CELEBRATION": "全星系欢庆", + "TERMICIDE EXTREMELY EFFECTIVE": "灭虫终结剂极其有效", + "\"IT IS PAST TIME WE RESPONDED TO THIS UNPROVOKED INCURSION AGAINST DEMOCRACY. THE HELLDIVERS ARE DEPLOYING AS WE SPEAK TO STRIKE A NUMBER OF AUTOMATON MILITARY INSTALLATIONS. THESE INVADERS WILL SOON DISCOVER THE STEEL OF SUPER EARTH RESOLVE.\"": "“我们早该对这种无端侵犯民主的行为加以还击。就在此时此刻,绝地潜兵已经出动,针对机器人的多处军事设施发起攻击。这些入侵者很快就会发现,超级地球的决心坚如钢铁。”", + "Dr. Pauline Dupont": "波林·杜邦博士", + "SS LIBERTY": "星舰解放号", + "DISSIDENT": "异见分子", + "Spaghettification Visualization": "面条化影像", + "TERMICIDE SCIENTISTS RECOGNIZED": "灭虫终结剂科学家身份确认", + "NEW BILL WOULD TEMPORARILY GRANT PET FISH AUTHORIZATION TO CLASS C CITIZENS AND ABOVE": "新法案将暂时批准C级及以上公民饲养宠物鱼", + "SUPERCOLONY DESTROYED": "超级拓殖地毁灭", + "Barely able-bodied Citizens": "体弱的公民", + "20X FASTER": "加快20倍", + "SONNTAG": "松塔格", + "CATCHY TUNE": "洗脑旋律", + "ENLISTMENTS RATES SOAR": "入伍率飙升", + "ARE PROGRAMMED FOR 2 THINGS: VIOLENCE,": "这些机器人的程序里只写了两样东西:", + "DUPONT": "杜邦", + "PAULINE": "波林", + "APPROVED BY THE MINISTRY OF TRUTH": "经真理部审核通过", + "REMAINING PLANETS COULD BECOME SUPERCOLONIES": "剩余星球可能成为超级拓殖地", + "—MINISTRY OF DEFENSE": "——国防部", + "OVERALL BIRTH RATE TARGET INCREASED TO 1.4% FROM 1.35%": "总出生率目标从1.35%提高至1.4%", + "STROHMANN NEWS": "斯托曼新闻", + "ENLIST TODAY": "立即入伍", + "HELLDIVERS TO STRIKE AUTOMATONS": "绝地潜兵即将出击机器人", + "OPERATION \"VALIANT ENCLOSURE\" BEGINS": "“英勇围合”行动开始", + "TCS FAILURE: WHAT WE KNOW": "TCS的失败:我们掌握的信息", + "RESTRICTED AREA": "禁区", + "\"PEACE IS NOT AN OPTION. THE AUTOMATONS ARE PROGRAMMED FOR 2 THINGS: VIOLENCE, AND HATING FREEDOM.\"": "“和平共存是不可能的。这些机器人的程序里只写了两样东西:暴力,以及憎恨自由。”", + "TOILET STALLS: DISSIDENT HIDEOUTS?": "厕所隔间:异见分子的秘密基地?", + "Bullets": "子弹", + "\"SUPERCOLONY\"": "“超级拓殖地”", + "HELLDIVERS DEPLOY TO RETAKE CYBERSTAN": "绝地潜兵出动,重夺生化斯坦", + "ALL YOU\nNEED TO KNOW": "通晓\n天下", + "ILLUMINATE RETURNED?": "光能者回归?", + "—PRESIDENT OF SUPER EARTH": "——超级地球总统", + "SPIKE IN SALES OF HELLDIVER TOYS ATTRIBUTED TO NEW DEPLOYMENT": "近期新行动部署推动绝地潜兵玩具销量剧增", + "MULTIPLE PLANETS INVADED": "多颗星球遭到入侵", + "Production Rate": "生产率", + "HARBER": "哈珀", + "AUTOMATONS ATTACK DEVELOPED WORLDS": "机器人袭击发达星球", + "WITH CORETTA KELLY": "主持人:科雷塔·凯利", + "RUMORS OF ILLUMINATE SIGHTINGS ARE WORK OF DISSIDENTS": "目击光能者的谣言属异见分子所为", + "TERMINID OUTBREAK": "终结族暴乱", + "MOBILIZATION": "动员行动", + "FREDA": "弗雷达", + "Grenades": "榴弹", + "BREAKING NEWS": "突发新闻", + "Termicide effect": "灭虫终结剂效果", + "DARK FLUID INCIDENT": "暗液体事故", + "NEWLY IDENTIFIED SOLAR SYSTEM MAY HAVE UP TO 3 SUITABLE PLANETS FOR COLONIZATION, ACCORDING TO MINISTRY OF SCIENCE REPORT": "根据科学部报告,在新发现的恒星系中,适合建造拓殖地的星球可能多达3个", + "EGON": "埃贡", + "TERMICIDE 2.0 RESEARCH UNDERWAY": "灭虫终结剂2.0研究正在进行中", + "TOP SECRET RESEARCH FACILITY": "高度机密研究设施", + "TERMICIDE CAUSED INCREASED REPRODUCTION": "灭虫终结剂导致繁殖加速", + "Barrier planets": "屏障星球", + "NOW, IT IS CLEAR THAT THERE CAN BE NO PEACE UNTIL": "现在,显而易见,我们必须彻底摧毁", + "CITIZENS EAGER TO HELP": "公民迫切贡献力量", + "I ALREADY HAVE": "我已入伍", + "OPERATION SWIFT DISASSEMBLY CONTINUES": "急速拆解行动继续进行中", + "AUTOMATON SURPRISE ATTACK": "机器人突然来袭", + "GALAXY IN MOURNING": "全星系哀悼", + "Lead Scientist": "首席科学家", + "SEAF": "超级地球武装部队", + "WAR SONG TOPS CHARTS": "战歌高居音乐榜首", + "DR. DISSIDENTS?": "异见分子博士?", + "REVOKED": "已撤销", + "\"FOR THE DISCOVERY AND SYNTHESIS OF TERMICIDE\"": "“发现并合成灭虫终结剂”", + "PERMANENT END OF CONFLICT WITH THE AUTOMATONS.": "即将与机器人永久结束冲突之际。", + "WOULD YOU ENLIST TO FIGHT THE AUTOMATONS?": "你是否愿意应征入伍,对抗机器人?", + "CANNOT - MEDICALLY DISQUALIFIED": "否,体检不合格", + "EVERY AUTOMATON IS UTTERLY DESTROYED.\"": "所有机器人才有可能实现和平。”", + "BREAKING NEWS: FIRST AUTOMATON FOOTAGE": "突发新闻:首获机器人影片", + "HEARTWARMING STORY": "暖心故事", + "GALACTIC FRINGE": "星系边缘", + "SEARCH FOR SURVIVORS ONGOING": "生还者搜索行动仍在进行中", + "HELLDIVERS REDIRECTED": "绝地潜兵重新调配", + "COUNTEROFFENSIVE AGAINST AUTOMATONS COMING": "反攻机器人行动即将开启", + "TCS SCIENTISTS UNDER INVESTIGATION": "TCS科学家正在接受调查", + "SICK CHILD'S WISH GRANTED": "病童愿望成真", + "PRESIDENT PROMISES RETRIBUTION": "总统承诺发动反击", + "Can't Ration My Love": "我的爱无法定量配给", + "HELLDIVERS PUSH TO SUPERCOLONY": "绝地潜兵攻向超级拓殖地", + "Dr. Freda Harber": "弗雷达·哈珀博士", + "VIOLATION PUNISHABLE BY DEATH OR WORSE": "违法者可处以死刑或更严厉的处罚", + "Helmets": "头盔", + "TCS FAILURE": "TCS的失败", + "LOOK OUT": "当心", + "Able-bodied Citizens": "健全的公民", + "Chemist": "化学家", + "\"CLOSE CALL\" AT DARK FLUID FACILITY": "暗液体设施发生“惊险”事件", + "CYBERSTAN": "生化斯坦", + "TCS SHOWS PROMISE": "TCS未来可期", + "AND HATING FREEDOM.\"": "暴力,以及憎恨自由。”", + "M.O.D. RELEASES VIDEO OF POSSIBLE ILLUMINATE VOID SHIP": "国防部公开疑似光能者虚空舰船的录像", + "Terminid Biologist": "终结族生物学家", + "MINISTRY OF SCIENCE REVEALS SWEEPING ARTIFICIAL INTELLIGENCE RESEARCH PLAN": "科学部公开人工智能全面研究计划", + "\"THIS ATTACK OCCURRED AS WE WERE NEARING A": "“此次袭击的发生时间正值我们", + "TERMINIDS OUT OF CONTROL": "终结族失控", + "AUTOMATON THREAT": "机器人危机", + "STROHMANN": "斯托曼", + "Dr. Egon Sonntag": "埃贡·松塔格博士", + "TERMINID": "终结族", + "\"PEACE IS NOT AN OPTION. THE AUTOMATONS": "“和平共存是不可能的。", + "[Stuff in the hospital scene, maybe]": "[疑似医院内物品的场景]", + "#VALUE SECOND": "#VALUE秒", + "#COUNT m/s": "#COUNT米/秒", + "#COUNTdB": "#COUNTdB", + "#X / #Y": "#X / #Y", + "#HOURSh #MINUTESm": "#HOURS小时#MINUTES分钟", + "#VALUE HOURS": "#VALUE小时", + "(#COUNT)": "(#COUNT)", + "#LEADIN #DAY #HOUR #MINUTE": "#LEADIN #DAY #HOUR #MINUTE", + "[#X/#Y]": "[#X/#Y]", + "#HOURS:#MINUTES:#SECONDS": "#HOURS:#MINUTES:#SECONDS", + "#COUNT s": "#COUNT秒", + "#MINUTES:#SECONDS": "#MINUTES:#SECONDS", + "#X/#Y": "#X/#Y", + "#HOUR_ZEROS#HOURSH #MINUTE_ZEROS#MINUTESM": "#HOUR_ZEROS#HOURS小时 #MINUTE_ZEROS#MINUTES分钟", + "T-#MINUTES:#SECONDS:#MILLI": "倒计时#MINUTES:#SECONDS:#MILLI", + "#VALUEmin": "#VALUE分钟", + "#SUBTITLE": "#SUBTITLE", + "'#TEXT'": "“#TEXT”", + "#VALUEd": "#VALUE天", + "#VALUE day": "#VALUE天", + "#MINUTE_ZEROS#MINUTESM #SECOND_ZEROS#SECONDSS": "#MINUTE_ZEROS#MINUTES分钟 #SECOND_ZEROS#SECONDS秒", + "#VALUE SECONDS": "#VALUE秒", + "#VALUE DAYS": "#VALUE天", + "#VALUE DAY": "#VALUE天", + "#MINUTES:#SECONDS:#MILLI": "#MINUTES:#SECONDS:#MILLI", + "#X - #Y": "#X - #Y", + "#DAYSD": "#DAYS天", + "#VALUE Second": "#VALUE秒", + "#COUNT mrad": "#COUNT毫弧度", + "#ZEROES#COUNT": "#ZEROES#COUNT", + "#VALUE HOURS": "#VALUE小时", + "#VALUE Hours": "#VALUE小时", + "T-": "倒计时", + "#VALUE DAYS": "#VALUE天", + "T-#SECONDS": "倒计时#SECONDS", + "#VALUE HOUR": "#VALUE小时", + "[#MINUTES:#SECONDS]": "[#MINUTES:#SECONDS]", + "#VALUE MINUTE": "#VALUE分钟", + "#VALUE HOUR": "#VALUE小时", + "#A (#PERCENT%)": "#A (#PERCENT%)", + "T- #DAYSd:#HOURS:#MINUTES:#SECONDS": "倒计时#DAYSd:#HOURS:#MINUTES:#SECONDS", + "#X #Y #Z": "#X #Y #Z", + "#A/#B (#PERCENT%)": "#A/#B (#PERCENT%)", + "#VALUE Seconds": "#VALUE秒", + "#VALUE SECONDS": "#VALUE秒", + "#LEADIN #DAY #HOUR #MINUTE #SECOND": "#LEADIN #DAY #HOUR #MINUTE #SECOND", + "#HOURSh #MINUTESm #SECONDSs": "#HOURS小时#MINUTES分钟#SECONDS秒", + "T- #HOURS:#MINUTES:#SECONDS": "倒计时#HOURS:#MINUTES:#SECONDS", + "#VALUE Days": "#VALUE天", + "#VALUE DAY": "#VALUE天", + "#COUNTs": "#COUNT秒", + "#VALUE Day": "#VALUE天", + "#VALUE Minutes": "#VALUE分钟", + "#DAY_ZEROS#DAYSD #HOUR_ZEROS#HOURSH": "#DAY_ZEROS#DAYS天 #HOUR_ZEROS#HOURS小时", + "#COUNT m": "#COUNT米", + "#X/#Y": "#X/#Y", + "#A • #B • #C": "#A • #B • #C", + "#VALUE MINUTES": "#VALUE分钟", + "#SPEAKER: #SUBTITLE": "#SPEAKER:#SUBTITLE", + "#VALUEh": "#VALUE小时", + "#VALUEs": "#VALUE秒", + "#MINUTESm #SECONDSs": "#MINUTES分钟#SECONDS秒", + "#VALUE Hour": "#VALUE小时", + "#X #Y": "#X #Y", + "#VALUE Minute": "#VALUE分钟", + "T - #SECONDS": "倒计时#SECONDS", + "#VALUE SECOND": "#VALUE秒", + "#LEADIN #DAY": "#LEADIN #DAY", + "#VALUE MINUTE": "#VALUE分钟", + "Option #NUMBER": "选项#NUMBER", + "#VALUE MINUTES": "#VALUE分钟", + "#A • #B": "#A • #B", + "#VALUE days": "#VALUE天", + "#PERCENT%": "#PERCENT%", + "SUPERIOR PACKING METHODOLOGY": "高级装填法", + "Heads Up Display (HUD) Curve": "HUD弧度", + "COMMUNICATION": "通信", + "EXPERIMENTAL INFUSION": "试验性注射剂", + "Decreases time to initiate deployment of Support Weapon Stratagems by removing dialog box confirming intent to fire.": "通过移除确认发射意图的对话框,缩短支援武器战略配备的部署启动时间。", + "Mature - Violence": "成人 - 暴力", + "Render Scale": "渲染比例", + "You have reached the approved generosity limit. Please wait #DAYS d #HOURS h before donating again.": "你已达到批准的捐赠上限。请在#DAYS天#HOURS小时后再尝试。", + "Offensive Language": "冒犯性言辞", + "Scientists without fear of implosion or spaghettification study negative energy here.": "无惧内爆与意大利面条化风险的科学家在这里研究负能量。", + "Adjusts the sensitivity of vertical camera movement relative to horizontal movement.": "调整视角垂直移动相对水平移动的灵敏度。", + "Crossplay": "跨平台游玩", + "While the Helldiver training program is undeniably infallible, you can always repeat your training from the game menu.": "绝地潜兵训练项目当然是完美无缺的,但是你随时可以在游戏菜单中再次参加训练。", + "COMPARE": "对比", + "Music Preview": "音乐预览", + "RADIAL MENU RIGHT": "圆盘菜单右", + "Amazing quality, I bought one for me and TWO for my kid. She loves them.": "质量超好。我不仅自己买了一件,还给我女儿买了两件。她爱不释手。", + "Invert Motion Sensor (Vertical)": "动态感测器翻转(垂直)", + "Acquisition data downlink from Super Earth has failed. Please check for Automaton interference and try again at a later time.": "源自超级地球的数据采集下链发生故障。请检查是否有机器人的干扰,并稍后重试。", + "Inverts left and right of Motion Sensor control direction.": "动态感测器左右方向翻转。", + "When in doubt, don't think—simply shout \"For Democracy!\" and charge head-first into your problems.": "困惑之时,不要思考——只需大喊 “为了民主!”,然后勇敢地冲锋陷阵。", + "This setting increases the amount of grass, rocks, etc that are scattered on the ground.": "该设置可提高散布在地面的草和岩石等元素的数量。", + "For more information on the Payment Services Act: https://pscom.jp/lgp": "-", + "ACTIVE FOR: #HOURS h #MINUTES m": "激活时长:#HOURS小时#MINUTES分", + "DSS CONSTRUCTION SITE - PHASE 3": "DSS建筑工地 - 第3阶段", + "Something went wrong while trying to add the currency to your account. Please contact our support team.": "尝试将货币添加到账号时出错。请联系我们的支持团队。", + "Rare Samples are only available on more challenging missions.": "稀有样本只能在挑战性较高的任务中获得。", + "HUD Edge Offset": "HUD边缘偏移", + "Caught on fire? Stims will heal you, but won't douse the flames. Instead: stop, drop, and roll!": "着火了?治疗剂可以治愈你的伤势,但无法扑灭火焰。不过,你可以立刻停下脚步,扑到地面翻滚起来!", + "The Ministry of Science has relocated its best and brightest here to study the interstellar spore cloud known as The Gloom.": "科学部将绝顶聪明的精英安排到这里研究名为“阴霾”的星际孢子云。", + "CUSTOMIZATION UNAVAILABLE": "自定义内容无法使用", + "INVERTED": "已翻转", + "Stealing Resources": "偷取资源", + "SETUP": "设置", + "Ultra Quality Plus": "超高画质+", + "Determines how you want to navigate the map screen.\n\nHybrid: Allows you to move and look around while the map is open. Additional controls are needed in order to navigate the map.\nSeparated: Allows you to only move while the map is open, relies on your look controls to navigate the map.": "决定你浏览地图窗口的方式。\n\n混合:可以在打开地图的同时移动和观察四周,需要使用其他按键拖动地图。\n独立:在打开地图的同时只能移动,需要通过视角的操控按键拖动地图。", + "If the enemies just keep coming, find out where they're coming from and unleash hell. Bug hive? Destroy! Bot factory? Destroy!": "如果敌人源源不断地涌来,那就找出它们的老巢,将其斩草除根。虫窝?毁掉!机器人工厂?毁掉!", + "March": "3月", + "HELLPOD SPACE OPTIMIZATION": "绝地喷射舱空间优化", + "HANGAR": "机库", + "ON SHIP": "在舰船上", + "STAMINA BOOST": "耐力提升", + "If you play one of our games, we will always access data from and / or store data on the device that you are using. This data is necessary to deliver our games, and includes:\n• Content Data: Game content data, such as video, audio, graphic, text, and game level information that is requested and downloaded for the game that you are accessing online. If you are playing an online game, this includes your online interactions as necessary to reflect those interactions on our game servers.\n• Account Data: Information required to sign you into your account for PlayStation™Network. \n• Configuration Data: Information about the configuration of your device and the game you are playing , such as the device date, time and language settings and your in-game preference and settings. \n• Security Data: Information necessary to detect and investigate malicious, unauthorized or fraudulent activity.\n• Legal Data: Information required by applicable law and to demonstrate compliance.\nIf you agree, we may collect more detailed information about how you interact with our games.\nThis may include when and how you use the game’s user interface, which parts of the game you visit, which weapons you use, which characters you interact with and any errors that you encounter.\nGame Data is usually sent to us and stored with one or more unique network, device and/or account identifiers.": "Wenn du eines unserer Spiele spielst, greifen wir immer auf Daten von dem Gerät zu, das du verwendest, und/oder speichern Daten auf diesem Gerät. Diese Daten sind für die Durchführung unserer Spiele erforderlich und umfassen:\n• Inhaltsdaten: Spiel-Inhaltsdaten, darunter Video-, Audio-, Grafik-, Text- und Level-Informationen, die für das Spiel, auf das du online zugreifst, angefordert und heruntergeladen werden. Wenn du ein Online-Spiel spielst, schließt dies deine Online-Interaktionen ein, die notwendig sind, um diese Interaktionen auf unseren Spielservern wiederzugeben.\n• Kontodaten: Informationen, die erforderlich sind, um dich bei deinem Konto für PlayStation™Network anzumelden. \n• Konfigurationsdaten: Informationen über die Konfiguration deines Geräts und des Spiels, das du gerade spielst, wie z. B. die Einstellungen für Datum, Uhrzeit und Sprache des Geräts sowie deine Präferenzen und Einstellungen im Spiel. \n• Sicherheitsdaten: Informationen, die erforderlich sind, um schädliche, unbefugte oder betrügerische Aktivitäten aufzudecken und zu untersuchen.\n• Rechtliche Daten: Informationen, die nach geltendem Recht und zum Nachweis der Einhaltung der Vorschriften erforderlich sind.\nWenn du zustimmst, können wir detailliertere Informationen darüber sammeln, wie du mit unseren Spielen interagierst.\nDazu kann gehören, wann und wie du die Benutzeroberfläche des Spiels verwendest, welche Teile des Spiels du besuchst, welche Waffen du benutzt, mit welchen Charakteren du interagierst und welche Fehler bei dir auftreten.\nDie Spieldaten werden in der Regel mit einer oder mehreren eindeutigen Netzwerk-, Geräte- und/oder Kontokennungen an uns gesendet und gespeichert.", + "Look Sensitivity Vertical Multiplier": "视角灵敏度垂直乘数", + "SHIP LOG": "舰船日志", + "ACCESSIBILITY": "协助工具", + "Select the screen device where the game will be displayed.": "选择用以显示本游戏的屏幕设备。", + "PAST CAMPAIGNS": "过往战役", + "There's no one right way to skin a bug. Experiment with different tactics and see what works!": "一千个人有一千种对付虫族的办法。尽情尝试不同的战术,看看效果如何!", + "#NAME - LEVEL #LEVEL": "#NAME - #LEVEL级", + "Modifies how far light from certain light sources reaches. Alters some materials and lighting features.": "更改部分光源的光线照射距离。更改部分材质和光照功能。", + "HelldiVR_91": "绝地深潜VR_91", + "Top-of-the-line accounting software automates payroll calculations, freeing up HR associates to lubricate support weapons in their spare time.": "顶级会计系统软件实现自动化薪金计算,让人力资源助理腾出空余时间为支援武器上油润滑。", + "Gives access to the Orbital 380mm HE Barrage stratagem during missions. Accelerates progress in Liberation Campaigns.": "执行任务时可使用轨道380mm高爆弹火力网战略配备。加快解放战役的进程。", + "Sentries take #VALUE% less damage from explosions.": "哨戒炮受到的爆炸伤害减少#VALUE%。", + "Vibration Strength": "震动强度", + "Provides hand carts which can carry multiple backpack stratagems from storage, decreasing both reload time and crew lumbar injuries.": "手推车可从库存中装载多个背包战略配备,缩短重新装弹的时间,还可以降低船员腰部受伤的几率。", + "TYPE": "种类", + "Reduces reload time for all support weapons by #VALUE%.": "所有支援武器的装填时间缩短#VALUE%。", + "Sentries rotate towards new targets more quickly.": "哨戒炮可更快地转向新目标。", + "Dismiss": "忽略", + "Camera Shake Strength": "视角摇晃强度", + "MUTED": "静音", + "The first manned site established in Gloom-infested space.": "首个在“阴霾”侵蚀星域建立的人类驻军据点。", + "Disrupting Gameplay": "破坏游戏体验", + "PixiePyxie555": "调皮妖精555", + "REQUIREMENT: #MODULE": "条件:#MODULE", + "NAME YOUR SUPER DESTROYER SHIP": "为你的超级驱逐舰命名", + "RESTART REQUIRED": "需要重启", + "Compass Width": "罗盘宽度", + "Mounts a modified AR-23 Liberator to all resupply pods, allowing them to double as automatic turrets.": "为所有重新补给舱搭载改良版AR-23“解放者”,可充当自动炮台。", + "SEND FRIEND REQUEST": "发送好友申请", + "#COUNT%": "#COUNT%", + "Controls the quality of the bloom filter. Affects GPU performance.": "控制全屏泛光过滤质量。影响GPU性能。", + "SHIP NAME": "舰船名称", + "MOVE RIGHT": "向右移动", + "BRAKE / REVERSE": "刹车/倒车", + "Voice Chat Transcription": "语音聊天转录", + "RepeatCustomer: Nice improvement on the previous identical model": "回头客:比上一代版本做得更好", + "Improves steering for Helldivers during Hellpod deployment.": "帮助绝地潜兵在部署绝地喷射舱时更好地把控转向。", + "EXPLODING SHRAPNEL": "高爆弹片", + "HEADER VISIBLE": "显示标题", + "Secondary Objective Visibility": "次要目标可视度", + "Difficulty 4-6": "难度4-6", + "DEFENSIVE STRATAGEM PERMIT": "防御型战略配备许可证", + "I've used this every day for the past few weeks!": "我已经用了几周,天天都用!", + "MORE INFO": "更多详情", + "January": "1月", + "OUTCOME": "结果", + "OPEN WEAPON WHEEL": "打开武器轮盘", + "Karen0057": "卡伦0057", + "#PERCENTAGE% of Votes": "得票率:#PERCENTAGE%", + "Injury Widget Visibility": "伤势轮盘可视度", + "DISCREET": "简洁", + "Mission Info Position": "任务信息位置", + "CONCERNING NUMBER OF MONOLITHS": "巨石数量令人担忧", + "Parts for the Democracy Space Station are prefabricated all over the Galaxy, then shipped here to await assembly.": "民主空间站(DSS)的部件在星系各地完成预制,然后运往这里等待组装。", + "SUMMARY": "总结", + "Real_NovaStarz": "真_新星", + "Deadzone": "盲区", + "SHIFT UP": "升档", + "Key": "键", + "Select level of detail of shadows, as well as the amount of lights that cast.": "选择阴影细节层次,以及投射的光照数量。", + "ACCEPT": "接受", + "UAV RECON SUPPORT": "UAV侦察支援", + "RECENT PLAYERS": "近期玩家", + "TLdyHero": "乱室英雄", + "Enables automatic climbing and vaulting while the Helldiver is sprinting.": "在绝地潜兵冲刺时,开启自动攀爬或翻越的动作。", + "WHAT DO THE GAME SETTINGS CONTROL?": "游戏设置可以控制什么?", + "SHIFT DOWN": "降档", + "SPECIAL STRATAGEM PERMIT": "特殊战略配备许可证", + "LOOK RIGHT": "向右看", + "New Difficulty Level": "新难度", + "TOGGLE MICROPHONE": "切换麦克风", + "GLOOM BASE BRAVO": "“阴霾”布拉沃基地", + "STAMINA REGEN": "耐力恢复", + "You have reached the approved generosity limit. Please wait #MINUTES m #SECONDS s before donating again.": "你已达到批准的捐赠上限。请在#MINUTES分#SECONDS秒后再尝试。", + "ACCELERATE": "加速", + "Not Enough Data To Estimate": "数据不足,无法估算", + "Democracy Space Station construction is well underway. The local economy is flourishing as the planet’s populace has centupled, and all the Galaxy can feel their democratic fervor.": "民主空间站(DSS)的建设进展顺利。随着该星球的人口增长,经济也飞速蓬勃发展起来,全星系都能感受到他们的民主热情。", + "Increases minimap enemy ping radius by #VALUE%.": "小地图上标记敌人的半径范围扩大#VALUE%。", + "Commend your squadmates on a job well done. We're all on the right side of history!": "多多称赞队友的出色表现。我们都走在历史的康庄大道上!", + "Deploys periodic Eagle Airstrikes during missions. Slows enemy progress in Defense Campaigns.": "在任务中部署周期性“飞鹰”空袭。减缓敌人在保卫战役中的进展。", + "DEFENSE HELD BY DSS": "DSS守住防线", + "X+ AXIS": "X+轴", + "Use adaptive controller stick ranges.": "使用自适应游戏控制器摇杆范围。", + "COPY FRIEND CODE": "复制好友代码", + "After years of research into improving the Super Destroyer's firepower, the Ministry of Science concluded that the most effective method was adding more guns.": "经过多年对超级驱逐舰火力改进的研究,科学部得出结论,最有效的方法是增加枪炮数量。", + "Enemy Indicator Visibility": "敌人指示可视度", + "DEMOCRACY SPACE STATION": "民主空间站", + "UAV RECON BOOSTER": "UAV侦察强化资源", + "Inverts up and down of camera direction in First Person View (FPV).": "在第一人称视角(FPV)下,视角上下方向翻转。", + "Toggles the outline on your aiming reticle on or off, for greater visibility.": "显示或隐藏准星轮廓,更好地调整可视度。", + "ON": "开", + "ACTIONS": "行动", + "PLATFORM": "平台", + "INCREASED REINFORCEMENT BUDGET": "提高增援预算", + "Most weapons have different fire modes or functions—hold Reload to access them.": "大多数武器都设有不同的开火模式或功能,按住装填弹药键可切换模式或功能。", + "Requisition": "申购点", + "A significant SEAF military outpost is present on this planet.": "此星球上坐落着超级地球武装部队的重要军事哨站。", + "Rude, Vulgar Language": "语言粗鲁、粗俗", + "Gear": "装备", + "Super Earth has many holidays, but the most important is October 26th—Liberty Day!": "在超级地球的众多节日当中,最重要的当属10月26日——解放日!", + "Super Earth recommends spending at least 2.4 seconds per mission enjoying the scenery. A happy Helldiver is a deadly Helldiver.": "超级地球建议你每次执行任务时,至少花2.4秒欣赏景色。心情舒畅的绝地潜兵会变得更加强大。", + "AUDIO": "声音", + "PRONE": "趴下", + "UNLINKING": "正在解除绑定", + "TRIGGER TYPE": "触发方式", + "You can change and customize these settings at any time during gameplay.": "你可以在游戏期间随时更改或自定义这些设置。", + "Spam": "滥发消息", + "HIGH-QUALITY LUBRICANT": "优质润滑剂", + "Dead Sprint": "死亡冲刺", + "Select the angle range of the compass.": "选择罗盘的角度范围。", + "PURCHASE ERROR": "购买出错", + "STRATAGEM PERMIT": "战略配备许可证", + "Advertising": "广告", + "Okane_82": "冈根_82", + "Window Notifications": "窗口通知", + "Adjust the overall brightness of the game.": "调整游戏的总体亮度。", + "Map Navigation Mode": "地图浏览模式", + "REQUISITION": "申购点", + "DISPLAY": "显示", + "Modifies the resolution of the space backdrop when on missions. Primarily affects stars.": "更改执行任务时的太空背景的分辨率,主要会影响太空里的行星。", + "Collect medals to progress your Warbond. No rush though—Warbonds can be completed at any time.": "收集奖章,推进战争债券的进度。但是不用着急,你随时可以完成战争债券进度。", + "Account Link": "账户绑定", + "SQUADS IN MISSION": "正在执行任务的小队", + "Include the last #COUNT message(s) from the text chat.": "附上文字聊天的最近#COUNT条消息。", + "SWITCH SEAT (NEXT)": "切换座位(下一个)", + "#BOOSTER is active during missions.": "任务期间,#BOOSTER已激活。", + "REPORT PLAYER": "举报玩家", + "Specctrei": "幽灵子", + "Estimated time until ready: #HOURS h #MINUTES m": "预计准备时间:#HOURS时#MINUTES分", + "LOW FUNDS": "资金不足", + "LOWEST": "最低", + "Auto-Climb during Sprint": "冲刺时自动攀爬", + "A player cannot be reported for this action. You can take any of the following actions instead.": "无法以此行为为由举报玩家,你可以另行选择下列操作。", + "DOWNLINK FAILED": "下链出错", + "QUICK WEAPON WHEEL LEFT": "快速向左转动武器轮盘", + "Adjusts the sensitivity of camera movement.": "调整视角移动的灵敏度。", + "Audio Device": "音频设备", + "Triggers as soon as a button is pushed down.": "只要按下按键就立即触发操作。", + "STRATAGEM": "战略配备", + "August": "8月", + "GLOBAL": "全局应用", + "ZERO-G BREECH LOADING": "零重力后膛装弹", + "Mortar Sentries prioritize fire at marked targets.": "迫击哨戒炮优先射击标记的目标。", + "CLASS 1 EXOSTORM": "1级异界风暴", + "Vehicle Info Visibility": "载具信息可视度", + "VOICE 2": "声音 2", + "The Automatons store large amounts of encrypted information here.": "机器人将大量加密信息储存在这里。", + "CIRCUIT EXPANSION": "扩建电路", + "Enables closed captions, which provides text descriptions of sounds other than dialogue.": "启用隐藏式字幕,以文字形式描述对话以外的声音。", + "NEXT UPGRADE:": "下一次升级:", + "CROUCH": "蹲下", + "ADMIN": "管理员", + "HIGH": "高", + "WEAPON WHEEL LEFT": "向左转动武器轮盘", + "COMMUNICATIONS ARRAY": "通信阵列", + "Select when an on-screen option will be shown. Default behavior is to only display the on-screen keyboard if a keyboard was not used to enter the text input state.": "选择何时显示屏幕选项。默认是仅在未使用键盘输入文本时才显示屏幕键盘。", + "This will unlink your accounts.\nAre you sure you want to continue?": "此操作将解绑账号。\n确定要继续吗?", + "PUBLIC": "公开", + "GLOOM BASE ALPHA": "“阴霾”阿尔法基地", + "EMOTE OPTION B": "表情B", + "Excellent quality! Resistent even against the most gross bug goo.": "质量超棒!再恶心的毒虫黏液也不怕了。", + "Select the visibility of player markers during gameplay.": "选择游戏过程中的玩家标记可视度。", + "Muscle Enhancement": "肌肉强化", + "Something went wrong while attempting to establish the connection to PlayStation™Network. Error codes:": "尝试与PlayStation™Network建立连接时出现问题。错误代码:", + "CURRENTLY UNAVAILABLE": "目前无法使用", + "CANCEL SQUAD INVITE": "取消小队邀请", + "Managed Democracy is a cornerstone of advanced civilization.": "管理式民主是先进文明的支柱。", + "Body Type": "体型", + "Mature - Drugs": "成人 - 毒品", + "DirectX 12": "DirectX 12", + "CHANGE EQUIPMENT (LONG)": "更换装备(长)", + "Feb": "2月", + "CURRENT LOCATION": "当前地点", + "Use Raw Mouse Input": "使用原始鼠标输入", + "BLOCK": "屏蔽", + "Sales of Super Credits are disabled because the Steam Overlay is disabled. Please enable the Steam Overlay in your Steam settings. If this error persists after enabling the overlay and restarting the game, please refer to Steam support for assistance.": "由于尚未开启Steam界面,你无法购买超级货币。请在你的Steam设置中开启Steam界面。如果启用界面并重启游戏后,问题仍未解决,请联系Steam客服寻求帮助。", + "Account link is active.": "账号绑定已开启。", + "Kill bugs before they get close. Remember, nothing protects your personal space better than bullets.": "要在虫族靠近之前将其击杀。要记住,子弹最能保护你的个人空间。", + "REASON": "理由", + "PRIMARY OBJECTIVE": "主要目标", + "Motion Sensor Sensitivity": "动态感测器启用模式", + "ORBITAL CANNONS": "轨道加农炮", + "Select the visibility of mission information.": "选择任务信息的可视度。", + "Asking for Personal Information": "询问个人信息", + "AIM": "瞄准", + "EXOSUIT": "外骨骼装甲", + "Select level of quality of reflections. Most noticeable on glossy surfaces. The high setting enables Screen Space Reflections, which improves the appearance of shiny surfaces.": "选择反射质量的等级。效果常见于光滑表面。设置为高等级将启用屏幕空间反射,优化光亮表面的显示效果。", + "No recent players, yet.": "暂时还没有近期玩家。", + "PURCHASE FAILED": "购买失败", + "SUPER GLOOM BASE ALPHA": "超级“阴霾”阿尔法基地", + "Adjusts how much acceleration is applied to the controller camera control. Higher values mean much higher sensitivity when the sticks are at max range.": "调整游戏控制器操控视角的加速数值。上调数值可提高操作杆在极限位置时的灵敏度。", + "TURN SIGNAL RIGHT": "右转向灯", + "750 SC": "750超级货币", + "BUYING ITEM": "正在购买物品", + "GENERATE": "显示", + "FSR3": "FSR3", + "The former site of the Deep Mantle Forge Complex, stolen by the Automatons and destroyed.": "深部地幔铸造复合体遗址,被机器人窃取并摧毁。", + "TOGGLE HEADLIGHTS": "切换大灯", + "ON-SCREEN ONLY": "仅显示游戏指示文字", + "DATA OPT-IN": "同意使用的数据", + "The Game Data settings allow you to control what Game Data we access and store from this device. \n\nYou can change your settings at any time.": "你可以通过游戏数据的设置控制我们从本设备访问和存储的游戏数据。\n\n你可以随时更改设置。", + "Tooltip Visibility": "提示信息可视度", + "Weapon Function Visibility": "武器功能可视度", + "Knittingiscool111": "编织好酷111", + "The speed at which the cursor movement increases as the controller is moved.": "光标随游戏控制器移动的加速度。", + "AMD Anti-Lag 2 tries to reduce the system latency and increases responsiveness.": "AMD Anti-Lag 2旨在降低系统延迟并提升响应速度。", + "Scales the distance and screen sizes at which objects are drawn. Reducing this improves CPU performance.": "调整绘制物体的距离和屏幕尺寸。下调该数值可以改善CPU性能。", + "CENTER OF SCIENCE (DESTROYED)": "科学中心(遗址)", + "Choose your loadout carefully to ensure your squad has all the resources it needs. Democracy depends on it!": "谨慎选择武装配置,确保小队具备所有必要资源。这是捍卫民主的基石!", + "CUSTOM": "自定义", + "Select the default audio language spoken by characters.": "选择角色音频的默认语言。", + "PERFORMANCE": "性能", + "Helldivers come out of the Hellpod fully stocked on Ammo, Grenades and Stims.": "绝地潜兵携带充足的弹药、榴弹和治疗剂补给走出绝地喷射舱。", + "Select the default language for the text that appears in menus, subtitles and captions.": "选择菜单、字幕和隐藏式字幕的默认语言。", + "PREVIOUS ARC": "上一段剧情", + "Specifies the maximum framerate.": "限定最高帧率。", + "Stratagem Visibility": "战略配备可视度", + "If enabled, Helldivers II will utilize data collected from your account to improve player experience.": "启用时, 《HELLDIVERS™ 2》将使用从你账户中收集的数据来改善玩家的游戏体验。", + "Trims excess leg space in the cockpit, allowing the Eagle to carry additional payloads.": "削减驾驶舱内多余的腿部空间,增加“飞鹰”的有效载荷。", + "RADIAL MENU RELATIVE SELECTION": "圆盘菜单相对选取", + "Failed to accept friend request.": "未能接受好友申请。", + "The number of frame buffers to use. Lower values yield more responsive input, while higher values yield smoother frame rates.": "要使用的帧缓冲数值。数值越小,输入响应越快,数值越大,帧率越平稳。", + "SUOMALAINEN (Unsupported)": "SUOMALAINEN (Unsupported)", + "Screen-Space Global Illumination": "屏幕空间全局光照", + "Select the default language for text and audio.": "选择文本和音频的默认语言。", + "This setting modifies the fidelity of the terrain. The lowest setting disables faded transitions between some objects and the terrain.": "该设置可调整地形的逼真度。设为最低将禁用部分物体与地形之间的渐变过渡。", + "Difficulty 10+": "难度10+", + "Select the visibility of interaction prompts during gameplay.": "选择游戏过程中的互动提示可视度。", + "CLOSE": "关闭", + "No friend lobbies found": "未找到好友大厅", + "QUICK STIM": "快速使用治疗剂", + "A mine extracting platinum from deep-seated deposits of igneous rock.": "从深层火成岩中开采铂金的矿井。", + "NEXT EVENT": "下一战事", + "INPUT TYPE": "输入类型", + "BONUS SUPER CREDITS": "额外超级货币", + "#VALUE-second reduction in call-in time for all Orbital stratagems.": "所有轨道武器战略配备呼叫时间缩短#VALUE秒。", + "Remember that armored enemies require heavy weapons. Bring the appropriate equipment for your selected difficulty.": "记住,对付装备护甲的敌人要用重型武器。根据选定的难度挑选合适的装备。", + "Select the visibility of sample count during gameplay.": "选择游戏过程中的样本数量可视度。", + "NEXT ARC": "下一段剧情", + "Allows all Helldivers to recover faster after being slowed by an attack, such as acid. Does not mitigate \"area effects,\" such as EMS strikes.": "加快所有绝地潜兵在因遭受攻击(如腐蚀酸)而减速后的恢复速度。无法减轻“范围效果”的影响,如电磁冲击波攻击。", + "Braking when still will shift the vehicle into reverse.": "静止时刹车,载具将进入倒车状态。", + "DATA CENTER": "数据中心", + "The top-secret site where augmentations to the DSS are constructed.": "DSS强化设施的绝密搭建地点。", + "Compass Angle Range": "罗盘角度范围", + "This will unbind another action. Continue?": "该操作将取消另一项动作的键位绑定。是否要继续?", + "WIDE": "宽", + "VISUALS": "图像", + "Lightning arcs, fired from weapons and turrets, jump to one additional enemy.": "从武器和炮塔发射的闪电弧可额外跳到一名敌人身上。", + "Select the visibility of hints during gameplay.": "选择游戏过程中的游戏提示可视度。", + "Too many requests coming in. Please wait a moment. Error codes:": "请求过多,请稍等片刻。错误代码:", + "I'm [redacted] and this is my favorite product in the acquisition center!": "我是[已编辑]。这是采购中心里我最喜欢的产品!", + "Compass Small Notches": "罗盘小刻度", + "The best thing I've bought since my Combat Knife!": "少有的优质产品,仅次于我上次买的格斗匕首!", + "Quality Profile": "画质设置", + "E-710 FARMS": "710元素农场", + "CANCEL FRIEND REQUEST": "取消好友申请", + "DONATE RESOURCES": "捐赠资源", + "COMMEND": "称赞", + "GO TO LOADOUT": "前往武装配置界面", + "TYRANNY PARK 2": "第二代暴政公园", + "Adjusts the sensitivity of touch pad inputs for map movement.": "调整地图移动的触摸板输入灵敏度。", + "LINKING": "正在绑定", + "MOVE DOWN": "向下移动", + "Increases the time between enemy encounters.": "延长敌人遭遇战之间的时间间隔。", + "You do not have enough funds to make this donation.": "你的资源不足,无法完成这次捐赠。", + "HEADPHONES": "耳机", + "Defense Campaigns cannot originate from this planet. The #BOOSTER Booster is automatically active for all missions.": "此星球无法发起保卫战役。#BOOSTER强化资源在全部任务中自动激活。", + "SUBTITLES": "字幕", + "Lighting Quality": "光照质量", + "DESCRIPTION": "描述", + "DSS crews maintain deployment of a 24-hour rotating fleet of Eagle Fighters from the massive three-tiered Convocation Bay, supporting all Helldiver operations on the planet with close air support and halting enemy offensives for a short time.": "民主空间站的工作人员在大型三层结构集结湾部署了一支“飞鹰”驾驶员舰队,采取24小时轮班制,为绝地潜兵在星球上的行动提供近距离空中支援,短暂阻止敌人进攻。", + "Don't forget to take breaks!\n…\nThat is, if you want to be remembered as a coward.": "注意休息!\n…\n前提是你想被当作懦夫的话。", + "EMOTE / VICTORY POSE": "表情 / 胜利姿势", + "Impersonating a Representative": "冒充代表", + "PUSH-TO-TALK": "按键说话", + "This setting determines what resolution the game will render at, before scaling it to your selected display resolution. Decreasing this value may improve performance while increasing it will improve visual quality.": "该设置将决定了游戏在等比缩放至你选中的显示分辨率之前将以多高分辨率完成渲染。降低该数值或许可以改善性能,而增加该数值将提高画质。", + "WHAT IS GAME DATA?": "游戏数据是指什么数据?", + "Voice Chat Volume": "语音聊天音量", + "ACTIVE FOR: #DAYS d #HOURS h": "激活时长:#DAYS天#HOURS小时", + "Variable Rate Shading": "可变速率着色", + "Helldivers traveling the galaxy might come across ancient ruins and other curiosities. Just remember: Only a traitor is curious about alien artifacts!": "遨游银河的绝地潜兵可能会遇见古代遗迹或其他奇特物品。记住:只有叛徒才会对外星古物好奇!", + "Reverse Gear Inverts Throttle": "倒挡反转油门", + "STAMINA ENHANCEMENT": "耐力强化", + "LVL #LEVEL": "#LEVEL级", + "Bronko_P4triot": "我心向国_布兰科", + "You have been temporarily suspended.": "你已暂时被封禁。", + "Don't panic.": "不要惊慌失措。", + "INCOMING ONLY": "仅输入", + "PANDORA BASE": "潘多拉基地", + "BUY ITEM": "购买物品", + "Performance Monitor": "性能监视器", + "FLEXIBLE REINFORCEMENT BUDGET": "灵活增援预算", + "ADD TO FAVORITES": "收藏", + "The amount of stablization applied to the aim cursor in order to compensate for small unintentional movements.": "用以抵消瞄准光标小幅意外移动的稳定量。", + "Freedom isn't free, but this lets you dispense it with glee!": "自由不是免费的,但是花在这上面感觉很值!", + "OUTPOST ALPHA II": "二级阿尔法哨站", + "Cast your vote to influence where the DSS will be stationed during its next cycle.\n\nDonate resources to activate the Station's Tactical Actions: powerful abilities that can dramatically alter the fight for a planet's freedom. Only one Tactical Action can be active at a time.": "投票决定民主空间站在下一周期的停靠地点。\n\n捐赠资源以激活空间站的战术行动:可扭转星球自由之战局势的强大力量。每次只能激活一场战术行动。", + "DEFAULT": "默认", + "PLAYER": "玩家", + "Something went wrong while trying to add the currency to your account. We will retry in a few seconds.": "尝试将货币添加到账号时出错。我们将在几秒后重试。", + "WarwLzard66": "战争诬师66", + "GAMEPLAY": "游戏", + "EMOTE OPTION A": "表情A", + "If enabled, surveys will be occasionally displayed.": "如果开启此功能,系统将偶尔显示问卷调查。", + "Start Searching": "开始搜索", + "WEAPON FUNCTION 1": "武器功能1", + "ENGINEERING": "工程", + "Emote": "表情", + "TURN SIGNAL LEFT": "左转向灯", + "Motivational Shocks": "激励性冲击", + "The Ministry of Expansion tirelessly works to expand the reach of Freedom and secures vital resources for our society to thrive.": "扩张部在不眠不休地设法扩张解放大业的势力,为我们的社会获取繁荣发展的必要资源。", + "Don't go it alone—join a squad in order to unleash maximum liberation!": "不要孤军奋战——加入小队,助敌人实现最大限度的解放!", + "Vertical Field of View": "垂直视野", + "Mouse Sensitivity": "鼠标灵敏度", + "PATRIOTIC ADMINISTRATION CENTER": "爱国行政中心", + "Practice your daily desensitization exercises to ensure you remain unfazed by enemy atrocities.": "每天进行脱敏训练,确保你能冷静面对敌人的暴行。", + "GREAT EXPEDITIONARY FLEET YARD": "远征舰队港", + "Perfect for a true patriot of Super Earth!": "真正的超级地球爱国者绝配之选!", + "Automatons": "机器人", + "TOGGLE HUD": "切换HUD", + "The former site of the Center of Science. Once a beacon of technology, it now lies in ruins following a violent Terminid assault.": "科学中心遗址。曾经的科技灯塔,在一次终结族的猛烈进攻下沦为废墟。", + "Enabling this setting makes bright surfaces glow.": "启用该设置可令明亮的表面发光。", + "Failed to remove friend request.": "无法删除好友请求。", + "HELLDIVER TRAINING FACILITIES": "绝地潜兵训练基地", + "DETAILS": "详情", + "Armed Resupply Pods": "武装重新补给舱", + "RADIAL MENU DOWN": "圆盘菜单下", + "PUSH-TO-MUTE": "按键静音", + "Weapon Switch Mode": "武器切换模式", + "Legal": "法律条款", + "Grants subscription to data stream of live weather conditions, allowing for increased accuracy in orbital targeting.": "可订阅实时天气状况的数据流,提高轨道目标定位的准确性。", + "Select the visibility of the info feed during gameplay.": "选择游戏过程中的动态信息可视度。", + "Harrassment or Hate Speech": "骚扰或仇恨言论", + "Reinforces sentries with expanded polystyrene pieces (peanut-shaped variety), which absorb thermal and blast energy.": "利用可吸收热量和爆炸能量的膨胀聚苯乙烯片(形如花生)强化哨戒炮。", + "OFFENSIVE STRATAGEM PERMIT": "进攻型战略配备许可证", + "TANK": "坦克", + "DISABLE CROSSPLAY": "关闭跨平台游玩", + "Armor isn't just for looks—heavier armor makes you more resilient to attacks but slows you down and affects your stamina.": "盔甲不只是美观而已——盔甲越重,你的抗击能力越强,但是你的速度会相应变慢,耐力也会受到影响。", + "WARBOND MEDAL": "战争债券奖章", + "Invert Mouse (Horizontal)": "鼠标翻转(水平)", + "Sharpness": "锐度", + "Construction of the Democracy Space Station is nearing completion. This project, which has employed millions, will soon take its place among the greatest achievements of Democracy.": "民主空间站(DSS)将近完工。这个数百万人参与建设的项目将是民主伟业最伟大的成就之一。", + "Select the visibility of teammate status during gameplay.": "选择游戏中的队友状态可视度。", + "Volumetric Fog Quality": "体积雾质量", + "The Democracy Space Station is a strategic tool that gives Helldivers more power in the Galactic War.": "民主空间站是在星系战争中赋予绝地潜兵更大力量的战略利器。", + "GO TO LINK": "前往绑定", + "Large enemies now have a small chance of dropping Samples on death. Capped at #VALUE drops per mission.": "大型敌人死亡时有小概率掉落样本。每次任务最多掉落#VALUE。", + "Increases the damage radius on explosions caused by orbital Stratagems by #VALUE%.": "轨道战略配备引爆时的伤害半径扩大#VALUE%。", + "Reflection Quality": "反射质量", + "CONFIRM VOTE": "确认投票", + "May": "5月", + "MOVE LEFT": "向左移动", + "HOLD TO BUY ITEM": "按住购买物品", + "ADVANCED CREW TRAINING": "高级船员训练", + "Help us build the best Helldivers 2 experience!\nWhen you play this game, Sony Interactive Entertainment collects data that is necessary to operate the game. \nIf you agree, Sony Interactive Entertainment may also collect data about your interaction with the game and errors that occur. This data will be used as explained in our privacy policy. \nYou can change this setting at any time to allow full or limited data collection.": "协助我们打造最佳的《Helldivers 2》游戏体验!\n在您游玩本游戏时,索尼互动娱乐会收集本游戏运行所需的必要数据。\n如果您同意,索尼互动娱乐可能还会收集其他数据,以便了解您与游戏互动的方式以及期间发生的错误。这些数据的使用方式皆遵守我们的隐私政策。\n您可以随时更改该设置,选择提供全部或部分数据。", + "Invert Look (Horizontal)": "视角翻转(水平)", + "Upgrades Helldiver uniforms with form-fitting, automated, rapid-response fire suppression systems. Significantly reduces the time it takes for a burning Helldiver to naturally extinguish flames without the need to conduct rapid ground-aided smothering maneuvers.": "为绝地潜兵制服升级贴合体型的自动快速反应灭火系统。显著缩短炽灼小队绝地潜兵自然熄灭火焰时间,无需通过在地面上快速打滚来执行灭火动作。", + "If enabled, tapping the aim button will put you in/out of first person view.\n\nThis only works while the aim trigger type is set to Hold and when not using a controller.": "启用之后,轻按瞄准键可以进入/离开第一人称视角。\n\n前提是瞄准触发方式设为“按住”,且没有使用控制器。", + "Choose which device to use as your microphone.": "选择用作麦克风的设备。", + "The Ministry of Unity ensures that all of mankind is united as one by protecting us from internal threats, such as deviant behavior and expression of dangerous ideas.": "团结部负责保护我们免受内部威胁,例如反常行为以及表达危险思想,继而确保所有人类团结一致。", + "If enabled, the system tray icon will flash to notify you of important in-game developments, such as players joining your session or a game being found through matchmaking. This will mostly be noticeable when the game window is not in focus or active.": "启用后,如果游戏窗口在后台运行或不是当前活跃窗口,系统托盘图标会在游戏内发生重要事件时闪烁提醒,例如有玩家加入游戏或是匹配成功。", + "Voice Pack": "语音包", + "The size of the area where the right stick and left stick input is not registered.": "左摇杆和右摇杆输入的区域大小无效。", + "TRAINING MANUAL TIPS": "训练手册提示", + "LOCALIZATION CONFUSION": "定位混淆", + "Master Volume": "主音量", + "Enabling this setting approximates bounce lighting from nearby objects. Disabling may slightly improve GPU performance.": "启用该设置可概略估算附近物体的反射光。禁用设置或许可以略微改善GPU性能。", + "CHANGE EQUIPMENT (SHORT)": "更换装备(短)", + "An experimental lab has been constructed on this planet to synthesize Dark Fluid from E-711.": "实验室已经在此星球上建造,用以合成来自711元素的暗液体。", + "SPECTATE NEXT": "观战下一个玩家", + "#NAME has invited you to their squad.": "#NAME邀请你加入他们的队伍。", + "Lines Sentry pods with shock-absorbing hydrogel, allowing extra ammunition to be packed in the space previously occupied by shock-absorbing springs.": "在哨戒炮的弹药筒内涂抹减震水凝胶,即可在减震弹簧原本占用的空间内装入更多弹药。", + "SHUTTLE REPAIR BAYS": "运输船维修坞", + "Check your ship's TV for news on the war, combat tips, and advertisements for the hottest products in the galaxy.": "观看舰船的电视,可以掌握战争的最新动态,了解战斗技巧,以及观赏星系人气产品的广告。", + "Don't worry—stims have zero addictive properties!*\n*Study paid for by Permacura. Permacura: put your life in our hands.": "不必担心,治疗剂不具备成瘾性!*\n*佩玛丘拉资助研究。佩玛丘拉:放心把生命托付给我们。", + "Eagle stratagems that drop multiple bombs will drop #VALUE additional bomb(s).": "具备投掷多枚炸弹功能的“飞鹰”战略配备可额外投掷#VALUE枚炸弹。", + "You are not authorized to access the Acquisition Center until you've completed your first mission.": "你必须完成首次任务才能前往采购中心。", + "VOICE PACK": "语音包", + "Failed to unblock player.": "无法对玩家解除屏蔽。", + "Screen-Space Ambient Occlusion": "屏幕空间环境光遮蔽", + "Failed to send friend request.": "未能发送好友申请。", + "Speech Language": "音频语言", + "HIDE": "隐藏", + "This item is temporarily disabled": "这件商品被暂时禁用", + "Unable to initialize the purchase, please try again later or contact support if this error persists.": "无法开始购买,请稍后重试。如果问题仍未解决,请联系客服。", + "The volume of text to speech.": "文字转语音时的音量。", + "For budgetary reasons, Hellbombs require manual arming. But don't stick around unless you're looking for a spot on the wall of martyrs.": "由于预算原因,地狱火炸弹需要手动瞄准。但是千万别愣在原地,除非你想在英烈墙上抢个位置。", + "XXL WEAPONS BAY": "XXL号武器舱", + "ADJUST PRIVACY SETTING": "调整隐私设置", + "You do not have access to ship management yet. Complete missions and collect resources to upgrade the Destroyer.": "你现在还不能进行舰船管理。请先完成任务并收集资源来升级驱逐舰。", + "Strive_to_Dive_16": "使劲_俯冲_16", + "Mar": "3月", + "VOICE 1": "声音 1", + "Adjusts the brightness of the UI on HDR monitors.": "调整HDR显示器上的UI亮度。", + "The Democracy Space Station is currently unavailable.": "民主空间站目前无法使用。", + "SHOCK ABSORPTION GEL": "减震凝胶", + "Acceleration Speed": "加速度", + "This input is bound to another action. Proceeding will bind several actions to the same input. Continue?": "该输入键已与其他操作绑定。如果继续,则会将多个操作绑定至同一输入键。是否继续?", + "SUPPLY STRATAGEM PERMIT": "补给型战略配备许可证", + "Do you want to keep these display settings?": "要保留这些显示设置吗?", + "NEDERLANDS (Unsupported)": "NEDERLANDS (Unsupported)", + "MOVE UP": "向上移动", + "DSS CONSTRUCTION SITE - PHASE 1": "DSS建筑工地 - 第1阶段", + "Enable account linking to get started.": "启用账号绑定即可开始。", + "Select the visibility of the player's health status during gameplay.": "选择游戏过程中的玩家生命值状态可视度。", + "VIEW": "查看", + "THROWABLE": "投掷武器", + "CONTROLS": "控制项", + "SPRINT": "冲刺", + "EXIT": "退出", + "Your account has been suspended for breaching the terms of service.\nFor more information about account suspensions, visit\nhttps://www.playstation.com/support/account/suspensions-psn/": "你的账号因违反服务条款而被封禁。\n有关账号封禁的更多信息,请访问https://www.playstation.com/support/account/suspensions-psn/", + "Motion Sensor Steadying Threshold": "动态感测器稳定阈值", + "Fires periodic Orbital Barrages during missions. Accelerates progress in Liberation Campaigns.": "在任务期间定期发射轨道火力网。加快解放战役的进程。", + "Replaces the current method of loading cannons—manual shell insertion down the front of the barrel—with rear loading, which is much faster.": "更替目前的装弹方式,用更迅速的枪管后部装弹方式取代目前在枪管前部手动装弹的方式。", + "TOGGLE MENU": "切换界面", + "This setting modifies the resolution of the volumetric fog to create clearer light shafts. Lower settings remove some light influence.": "该设置可调整体积雾的分辨率,进而创造出更清晰的光束。较低的设置值将消除部分光照的影响。", + "Adjust the field of view to allow a wider view around the player.": "调整视野,允许玩家拓宽视野。", + "Anti-Aliasing": "抗锯齿", + "Every citizen is equally important to the war effort, but Helldivers are the most important.": "对于战争而言,每一位公民的贡献都是同样重要的,但是绝地潜兵最为重要。", + "Team Killing": "击杀队友", + "JUMP PACK": "喷射背包", + "Super Earth's ancient enemy, the Illuminate, have returned to menace our peaceful colonies. Our innocent colonists are being abducted, and turned into the mindless monstrosities known as the Voteless. What the Illuminate want, we do not know—but they must be stopped.": "超级地球的宿敌“光能者”卷土重来,威胁到我们拓殖地的和平。无辜的拓殖地居民遭到掳掠,被转变为名叫“无票者”的无脑怪物。虽然我们不清楚光能者的意图,但必须立即阻止它们。", + "Trains pit crew members to employ situational protocol adaptations, such as leaving unused ammo loaded instead of replacing it.": "训练维修组成员,让他们采用情景协议调整机制,例如保留已上膛但尚未使用的弹药,不进行替换。", + "CALL-IN TIME": "呼叫时间", + "Some systems may see a performance boost from using async compute while others may experience reduced performance. This setting does not affect visual quality.": "使用异步计算可能会提高某些系统的性能,而其他系统的性能则可能会降低。此设置不影响视觉质量。", + "CHARACTER": "角色", + "Other": "其他", + "INTER-GALACTIC NETWORK NODE": "星际网络节点", + "The Ministry of Truth is responsible for keeping all citizens well-informed and mentally equipped to withstand our enemies' vile propaganda.": "真理部负责为所有公民提供最新动态,武装公民的头脑,抵挡敌人居心不良的宣传攻势。", + "Jump-starts Hellpod firing with an immediate TNT detonation at the time of launch.": "快速启动绝地喷射舱发射程序的同时引爆TNT。", + "SHUTTLE": "运输船", + "Graphics Device": "图形设备", + "LONG HOLD": "长按", + "Invert Scope (Vertical)": "开镜视角翻转(垂直)", + "Shadow Quality": "阴影质量", + "The extensive Terminid enclosures here allow scientists to study Terminid behavior, and civilians to take pictures with Brood Commanders.": "大量终结族圈养在这里,方便科学家研究它们的行为,公民也可以和虫族指挥官拍照留念。", + "Beyond 50m, you'll be out of contact range from your squadmates. Stay in proximity to maintain full situational awareness.": "和队友相距超过50米就会失联。请避免远离队友,以便全面掌握战场动态。", + "Texture Quality": "贴图质量", + "HIDE FRIEND CODE": "隐藏好友代码", + "Estimated time until ready: #MINUTES m #SECONDS s": "预计准备时间:#MINUTES分#SECONDS秒", + "WEAPON SKIN": "武器涂装", + "SuperCitizen_2": "超级公民_2", + "Active for: #HOURS h #MINUTES m": "激活时长:#HOURS小时#MINUTES分", + "CANNONS": "加农炮", + "April": "4月", + "Did you know tips are shown during these transition sequences?": "你知道传输途中会显示提示吗?", + "MAP": "地图", + "Increases the range of the Helldiver Radar by equipping it with a high-powered Plutonium-210 battery.": "配备高能钚-210电池,装备后可扩大绝地潜兵的雷达探测范围。", + "Compass Ordinal Directions": "罗盘方位", + "STREAMLINED REQUEST PROCESS": "简化申请流程", + "on #PLANET": "在#PLANET上", + "OPEN MICROPHONE": "打开麦克风", + "Repurposed surveillance technology allows the Sentry Deployment Cannon to closely track the user at all times, no matter where they go or what they do, ready to fire at any second.": "重新改造监控技术的用途,使哨戒部署炮能够随时密切追踪使用者,无论他们去哪里或在做什么,炮台随时都能开火。", + "375 SC": "375超级货币", + "Station moves in:": "空间站即将移动:", + "ITALIANO": "ITALIANO", + "Super Earth Mandatory Reading": "超级地球必读事项", + "No Booster": "无强化资源", + "Allows Helldivers to keep sprinting even when they are out of stamina, draining their health instead.": "通过消耗生命值,让绝地潜兵在耐力耗尽时仍能继续冲刺。", + "Friendly Fire isn't.": "友军误伤不算作友好行为。", + "September": "9月", + "Adjusts the relative sensitivity of camera movement in First Person View (FPV).": "调整第一人称视角(FPV)下,视角移动的相对灵敏度。", + "Motion Sensor Acceleration Threshold": "动态感测器加速阈值", + "Text Chat": "文字聊天", + "SPEED": "速度", + "Input Device": "输入设备", + "Invert Mouse Scope (Horizontal)": "开镜视角鼠标翻转(水平)", + "Select the visibility of tooltips during gameplay.": "选择游戏过程中的提示信息可视度。", + "TERMINID RESEARCH PRESERVE": "终结族研究保护区", + "Military watchdog groups have called exploding shrapnel \"savage,\" \"merciless,\" and \"well-suited for spreading Democracy.\"": "军事监督组织认为高爆弹片“野蛮”、“无情”,“非常适合传播民主”。", + "Please observe the following Patriotic Service Announcement.\nDeviations in attention will be considered treason.\n\n\nThank you for your cooperation.": "请遵守以下爱国服务公告。\n注意力不集中将被视为叛国。\n\n\n谢谢配合。", + "Extraction Timer Visibility": "撤离计时器可视度", + "The volume of the in-game voice chat.": "游戏内语音聊天的音量。", + "Supported modes are:\n\nOpen Microphone\nPush-To-Talk (PTT)\nPush-To-Mute (PTM)\nMuted\nDisabled (not recommended)\nToggle Microphone": "支持以下模式:\n\n打开麦克风\n按键说话\n按键静音\n静音\n禁用(不推荐)\n切换麦克风", + "CONTROLLER": "控制器", + "ITEM TRAITS": "物品特性", + "Triggers on the second press if you quickly push down the same button twice.": "如果连续两次快速按下同一按钮,第二次按下时触发操作。", + "DROP CARRYABLE": "放下携带的物品", + "Closed Caption Mode": "隐藏式字幕模式", + "When enabled, voice transcription is used as an input source for text chat. Enabling this may cause additional configuration windows to appear for initial setup on a new device.": "启用时,语音转录将被用作文字聊天的输入源。启用该选项后可能会出现额外的设置窗口,用于在新设备上完成初始设置。", + "On a mission alone and dying to have someone liberating by your side? Use an SOS beacon to call in a fellow Helldiver.": "你是否在独自执行任务,企盼有战友加入你的解放之旅?使用SOS信标呼叫其他绝地潜兵吧。", + "ULTRA PERFORMANCE": "超高性能", + "My only complaint is that I wish I had another one": "我唯一不满意的就是我怎么没再买一件", + "#COUNT SC": "#COUNT超级货币", + "Mature - Sexual Content": "成人 - 性内容", + "Controls the strength of the bloom filter. Contributes to the feeling of brightness on highlights.": "控制全屏泛光过滤强度。影响玩家对光亮环境的亮度感受。", + "Continuous barrages rain down during missions.": "任务期间,连续炮击倾泻而下。", + "Describes, Depicts Illegal Act": "描述、描绘非法行为", + "Ambient Occlusion": "环境光遮蔽", + "ITEM REVIEWS": "商品评价", + "Don't worry, if you fail an objective, you will NOT be sent to a freedom camp. This is merely a dissident rumor.": "不要担心,就算你没能完成目标,你也绝对不会被送入自由营。那只是异见分子散播的谣言。", + "Auto Reverse Vehicles": "载具自动倒车", + "Dynamic Resolution Scaling": "动态分辨率缩放", + "IRREGULAR VOTELESS BEHAVIOR": "异常无票者行为", + "You can pick up active grenades and toss them away before they explode. Give it a try, it's fun!": "你可以捡起已激活的榴弹,在它爆炸前丢出去。很有意思,值得一试!", + "It pays to be a straight shooter—angled fire might glance off your target or even ricochet into your squadmates.": "直线射击效果更好,而斜射可能会让子弹从目标身上擦过,甚至有可能反弹到队友身上。", + "Increases health of Sentry stratagems by #VALUE%.": "哨戒炮战略配备的生命值提升#VALUE%。", + "QUALITY": "画质", + "ULTRA SUPERSAMPLING": "强化超级采样", + "Enabling this setting produces more realistic shadows by calculating ambient lighting, touching surfaces and objects that are blocking the light. Disabling may slightly improve GPU performance.": "启用该设置可计算环境光、接触面和遮光物体,从而产生更加逼真的阴影效果。禁用设置或许可以略微改善GPU性能。", + "Voting failed, please try again.": "投票失败,请重试。", + "FAILED TO FILE REPORT!\nTry again later.": "发送举报失败!\n请稍后重试。", + "Determines how non-linear mouse movement should be. If non-zero, the sensitivity ramps up with the speed of mouse movement. The higher the value, the more pronounced this acceleration is.": "设定非线性鼠标移动的方式。如果不为零,鼠标灵敏度会随移动速度上升。数值越高,加速越明显。", + "VOTED": "已投票", + "No event lobbies found": "未找到战事大厅", + "The Exostorm has reached critical mass, enveloping the planet in an ominous tempest that defies atmospheric physics.": "异界风暴已达到临界质量,整颗星球都被这场不祥的风暴所裹挟,彻底颠覆大气物理定律。", + "Boost overall crew efficiency with a suite of proven enthusiasm enhancement initiatives, such as citizenship anniversary celebrations and paid lavatory breaks.": "采取一系列行之有效的措施调动积极性,提高船员的总体效率。采取的措施包括举办公民纪念日庆典活动,以及允许带薪如厕等。", + "COOLDOWN TIME": "冷却时间", + "A Helldiver-operated weapon of mass liberation. Paid for with the blood of soldiers and the credits of taxpayers, this technological marvel is Democracy made manifest.": "绝地潜兵操纵的大规模解放武器。用士兵鲜血和纳税人税款铸就的这一技术奇迹堪称民主的象征。", + "If enabled, replace your currently held weapon to the one you have picked up.": "启用时,将你当前所持武器切换为拾取的武器。", + "Every member of the squad can view the Galactic War table, not just the host of the Super Destroyer.": "除了超级驱逐舰的主办者,小队的所有成员都可以查看星系战争的议战桌。", + "Y- AXIS": "Y-轴", + "Turning V-Sync on synchronizes the frame rate to the display device's refresh rate. Enabling this setting prevents visual artifacts such as screen tearing, but can cause lower framerate if your computer cannot keep up with the monitor.": "开启垂直同步会将帧率同步为显示器的刷新率,可以防止画面撕裂等画面现象,但如果电脑性能无法与显示器保持同步,则可能会导致帧率降低。", + "MORALE AUGMENTATION": "提升士气", + "Account Link Succeeded": "成功绑定账户", + "Dec": "12月", + "MOVEMENT": "移动", + "Change size of subtitles as they are displayed on screen.": "选择屏幕上显示的字幕尺寸。", + "Jul": "7月", + "The hard workers on this planet produce goods vital to the war effort, as well as to the prosperity of Super Earth.": "此星球上的辛勤工人生产重要物资,用于支援战争以及超级地球的光明未来。", + "The second manned site established in Gloom-infested space.": "第二个在“阴霾”侵蚀星域建立的人类驻军据点。", + "The relay towers on this planet are important to Automaton communications.": "这颗星球上的中继塔是机器人通信的重要工具。", + "Integrated Extinguishers": "集成灭火器", + "Selects the graphics API used.": "选择使用的图形API。", + "ABOVE PRIMARY": "主要目标上方", + "SEAF BASIC TRAINING FACILITIES": "超级地球武装部队基础训练基地", + "Equips Hellpods to deploy smokescreens on impact, obscuring Helldiver deployment.": "为绝地喷射舱配备烟雾弹,在撞击时释放烟幕,掩护绝地潜兵上场。", + "THROW": "投掷", + "Subtitle Mode": "字幕模式", + "Would you like to reconnect to your last squad?": "你希望与上个小队重新建立连接吗?", + "SECONDARY WEAPON": "次要武器", + "UAV Recon Booster": "UAV侦察强化资源", + "###COUNT": "###COUNT", + "LOCATION": "地点", + "REVEAL FRIEND CODE": "显示好友代码", + "Touch Pad Map Sensitivity": "触摸板地图灵敏度", + "Particle Quality": "粒子质量", + "Pre-approves the following forms in the Support Weapon Approval Process: Form 99-C (Justification for Munitions), Form 88-1 (Democratic Impact Worksheet), & Form 104 (Collateral Damage Risk Waiver).": "在支援武器审批流程中预先通过以下表格的审批:99-C表格(使用弹药的正当理由)、 88-1表格(民主影响说明工作表)和104表格(附带损害风险弃权声明)。", + "TURN RIGHT": "右转", + "Motion Blur": "动态模糊", + "Previous Category": "上一个类别", + "Cursor Sensitivity": "光标灵敏度", + "UNKNOWN": "未知", + "ABOUT US": "关于我们", + "If enabled, the camera will automatically center itself behind a player-controlled vehicle when not otherwise receiving input.": "启用之后,如果没有收到其他输入,会自动将玩家控制的载具置于视角中央。", + "Each faction presents unique challenges. Mix up your gear and try new tactics!": "不同阵营各有独特的挑战。混合使用装备,尝试新战术吧!", + "WEAPON TRAITS": "武器特性", + "At this research facility, recovered Voteless are given a fresh chance to aid Managed Democracy. Through processing and analysis of their biomass, our understanding of the Void stands to be significantly advanced.": "在这座研究设施中,被回收的“无票者”将获得为管理式民主添砖加瓦的新机会。通过对其生物质进行处理分析,我们定可大幅深化对寂域的了解。", + "Display On-Screen Keyboard": "显示屏幕键盘", + "After a button has been pushed down for a set amount of time, this starts triggering continuously.": "按下按键一定时间后开始连续触发操作。", + "Watch out for alien storms. Super Earth scientists have officially classified many of them as dangerous. And freaky.": "小心外星风暴。超级地球的科学家们已经正式宣布许多种风暴不仅危险,而且十分反常。", + "CLIMB": "攀爬", + "You need to link your Steam account to a PSN ID in order to report another player.": "你需要将Steam账户与PSN ID绑定才能举报其他玩家。", + "Exposes Hellpod wiring upon surface contact, stunning any units in the vicinity of the drop site.": "在绝地喷射舱落地时露出其电线,电晕空投地点附近的所有单位。", + "The Terminids on this planet have evolved to yield more E-710 than other specimens.": "此星球上的终结族经过进化,能产出比其他虫族更多的710元素。", + "The DSS activates its Zero G Anti-Ship Missile System, targeting all large enemy spacecraft attempting to exit the planet's atmosphere. In addition, diverts excess manpower to Super Destroyer logistical support.": "民主空间站启动零重力反舰导弹系统,瞄准所有试图离开星球大气层的敌方舰船。此外,将多余战力投入到超级驱逐舰的后勤支援。", + "Hold a grenade before throwing to \"cook\" it. Time your throw for an air-burst detonation! (Note: waiting too long may lead to unintended death.)": "可以将榴弹握在手中进行“温雷”操作,之后再将其丢出。掌握好投掷时间,让榴弹在空中爆炸!(注意:温雷时间过长可能会导致意外死亡。)", + "Hand in to #NAME": "上交给#NAME", + "AVATAR": "游戏形象", + "SAMPLE SCANNER": "样本扫描仪", + "The Super Destroyer can only stay in low orbit for a limited time—watch that mission clock!": "超级驱逐舰在低空轨道上停留时间有限——注意任务时长!", + "#FIRST #LAST": "#LAST#FIRST", + "WEAPON WHEEL UP": "向上转动武器轮盘", + "OFFERS VALID FOR": "优惠有效期:", + "DUAL WIELD FIRE RIGHT": "双持武器右手开火", + "Barrage orbitals fire #VALUE additional salvo(s) per barrage.": "火力网轨道武器每次可额外进行#VALUE次齐射。", + "Concealed Insertion": "隐蔽上阵", + "MISSION STRATAGEM PERMIT": "任务战略配备许可证", + "ENGLISH (UK)": "ENGLISH (UK)", + "OPTIONAL OBJECTIVE": "可选目标", + "Graphics Preset": "图像预设", + "AN OLD ENEMY EMERGES": "宿敌现身", + "Cheating/Glitching": "作弊/利用游戏漏洞", + "All Support Weapon stratagems launch immediately once called in, reducing overall deployment time.": "所有支援武器战略配备在呼叫后即时发射,缩短整体部署时间。", + "All samples extracted with are shared by the entire squad. Work together to advance the science of Super Earth!": "全部提取的样本均由整支小队共享。携手推进超级地球的科学发展吧!", + "Solicitation for Personal Info": "诱导收集个人信息", + "mike__the_spike": "马克__不马虎", + "Adjusts the controller vibration strength.": "调整控制器振动强度。", + "AFFECTED STRATAGEMS": "受影响的战略配备", + "Scope Sensitivity": "开镜灵敏度", + "Further expands Eagle weapons bay by removing unnecessary systems such as fire suppression, ejection, and airbags.": "通过移除火力抑制、弹射和安全气囊等不必要的系统,进一步扩大“飞鹰”的武器舱。", + "Insufficient donation funds": "捐赠资源不足", + "Account Link Failed": "账户绑定失败", + "MilitaryBeefHunk99": "军用牛肉块99", + "KEY + MOUSE": "键盘+鼠标", + "Terminids are held safely within massive compounds on this planet for study and E-710 extraction.": "此星球上设有安全管控的大型终结族保护区,专门用于研究终结族并提取710元素。", + "How quickly the cursor transitions from moving to stabilizing.": "光标从移动到稳定的过渡速度。", + "Decreases cooldown for all Backpack stratagems by #VALUE%.": "所有背包战略配备的冷却时间缩短#VALUE%。", + "STRATAGEM ACQUIRED": "已获取战略配备", + "Aim Sensitivity": "瞄准灵敏度", + "FRIENDS ONLY": "仅限好友", + "Adjusts how quickly acceleration is applied to the controller camera control. If set to zero, the movement is linear.": "调整控制器操控视角的加速生效速度。设置为零则视角线性移动。", + "This fully-upgraded facility enables deep operations within the Gloom. Operations on surrounding planets will be significantly supported.": "该设施全面升级,能在“阴霾”内展开深入运作。在周围星球的行动将得到大力支援。", + "Display Mode": "显示模式", + "Adjust the opacity of text backgrounds in the HUD.": "调整HUD文字背景的不透明度。", + "The purchase has already been authorized by Steam, but we are currently experiencing a high volume of requests. \nWe haven’t been able to add the currency to your account yet, but we will continue retrying in the background. \n\nThank you for your patience!\nIf the issue persists, please contact our support team.\n\nNext attempt in #TIME seconds.": "购买操作已获得Steam授权,但目前存在大量请求等待处理。\n暂时无法将货币添加到账号,我们会在后台继续重试。\n\n感谢您的耐心等待!\n如果问题仍然存在,请联系我们的支持团队。\n\n#TIME秒后将重试。", + "PARTY": "队伍", + "Next Category": "下一个类别", + "WEAPON WHEEL RIGHT": "向右转动武器轮盘", + "©2024 Sony Interactive Entertainment LLC. Developed by Arrowhead Game Studios AB. Helldivers 2 is a registered trademark of Sony Interactive Entertainment LLC and related companies in the U.S. and other countries.": "©2024 Sony Interactive Entertainment LLC. Developed by Arrowhead Game Studios AB. Helldivers 2 is a registered trademark of Sony Interactive Entertainment LLC and related companies in the U.S. and other countries.", + "The former site of the AM Defense Factory Hub. AM Defense was fortuitously able to reclaim its losses through insurance; the lives that were lost, however, can never be adequately compensated for.": "虎将国防工厂中心遗址。虎将国防尚有保险弥补损失,但那些逝去的生命如何弥补?", + "Players associated with an online ID can be reported for breaching the terms of service. This player is not associated with an online ID.": "如果关联在线ID的玩家违反服务条款,可将其举报。此玩家并未关联在线ID。", + "Teammate Status Visibility": "队友状态可视度", + "Active for: #DAYS d #HOURS h": "激活时长:#DAYS天#HOURS小时", + "CENTER": "中心", + "Getting Kicked": "被踢出", + "PIT CREW HAZARD PAY": "维修人员危险津贴", + "Voice Chat": "语音聊天", + "LONG RELEASE": "长按松开", + "CENTER FOR THE CONFINEMENT OF DISSIDENCE (CECOD)": "异见监禁中心 (CECOD)", + "All Emplacement stratagems launch immediately once called in, reducing overall deployment time.": "所有炮台战略配备在呼叫后即时发射,缩短整体部署时间。", + "SWITCH AIM MODE": "切换瞄准模式", + "Select the visibility of primary objectives.": "选择主要目标的可视度。", + "Adjusts the speed of the cursor when controlled by controller.": "调整游戏控制器操控下的光标速度。", + "Inverts up and down of Motion Sensor control direction.": "动态感测器上下方向翻转。", + "Midnight Mode": "午夜模式", + "Inverts left and right control of mouse direction.": "鼠标左右方向翻转。", + "AVAILABLE IN: #MINUTES m #SECONDS s": "就位倒计时:#MINUTES分#SECONDS秒", + "Adjusts the strength of the trigger effect function.": "调整扳机效果功能的强度。", + "You can change and customize these settings at any time during gameplay": "您可以在游戏期间随时更改或自定义这些设置", + "Reduces cooldown time for Sentry, Emplacement, and Resupply stratagems by #VALUE%.": "哨戒炮、炮台和补给战略配备的冷却时间缩短#VALUE%。", + "Increases all Helldivers' stamina capacity and recovery.": "提高所有绝地潜兵的耐力上限和恢复力。", + "EXPANDED WEAPONS BAY": "武器舱扩容", + "Subtitle Size": "字幕字号", + "If enabled, whenever you equip a weapon, it will recall the last weapon functions you had used, such as the firing mode.": "启用该选项后,每次装备的武器都将应用上一次使用过的武器功能,如开火模式等。", + "Struggling to input a code while in a distracting and/or stressful war zone? Just remember: Countless civilian lives are in your hands!": "战区的环境令你难以集中注意力并且紧张焦虑,难以输入代码?此刻只需记住:无数公民的性命就掌握在你的手中!", + "Send chat logs (optional)": "发送聊天记录(可选)", + "Invert Mouse Scope (Vertical)": "开镜视角鼠标翻转(垂直)", + "TAA Sharpness": "TAA锐度", + "Love this item, shipping A+++++++. Would purchase again. Highly recommended!!!!": "超级喜欢,A+++++++级物流。还会回购,强烈推荐!!!!", + "Ammunition for the Guard Dog stratagem can run out and be replenished with ammo packs.": "“护卫犬”战略配备的弹药会耗尽,可以通过弹药包进行补充。", + "When enabled, raw mouse input is used. At low frame rates disabling this may lead to smoother mouse input at the cost of slightly higher latency.": "启用时,使用原始鼠标输入。在低帧数下禁用该选项可能会导致鼠标输入变得更加流畅,但也会略微增加延迟。", + "The volume of the in-game dialogue.": "游戏内对话的音量。", + "This value controls the tradeoff between flicker and ghosting. Higher values reduce ghosting and may help with motion sickness, while lower values offer smoother edges.": "该数值可以协调闪烁和重像。上调数值可以减少重像,或许也可以缓解晕动症。下调数值则可以让边缘变得更加平滑。", + "Increases burning temperature of incendiary weapons by lacing fuel with a precisely-formulated compound of thermite, white phosphorus, capsaicin, allyl isothiocyanate, and 19 other accelerants.": "在燃料中加入精确配制的铝热剂、白磷、辣椒素、异硫氰酸烯丙酯和19种其他助燃剂,提高燃烧型武器的燃烧温度。", + "DirectX 11": "DirectX 11", + "Increases all Helldivers' effective radar range.": "扩大所有绝地潜兵的雷达有效范围。", + "BOOSTER PACK": "强化资源包", + "HONK": "鸣笛", + "Lines all Hellpods with volatile incendiaries that detonate upon impact, igniting any units in vicinity of the drop site.": "在所有绝地喷射舱中装载易爆燃烧弹,使其在撞击后爆炸,点燃空投地点周围的所有单位。", + "Adjust sensitivity of mouse movement. A lower setting moves the mouse more slowly, while higher settings move the mouse more quickly.": "调整鼠标移动的灵敏度。下调该设置可以降低鼠标移动的速度,上调则会加快速度。", + "HEADER HIDDEN": "隐藏标题", + "Invert Motion Sensor (Horizontal)": "动态感测器翻转(水平)", + "You can change the name of your Super Destroyer through the Ship Management menu.": "你可以通过舰船管理菜单更改超级驱逐舰的名称。", + "VEHICLE BAY": "载具停靠港", + "Adjust the intensity of the blur effect applied to moving objects and when rotating the camera. Decreasing motion blur might help with motion sickness as well as seeing moving objects.": "调整物体移动和视角旋转时的模糊效果的强度。减少动态模糊或许可以缓解晕动症,有助于看清移动中的物体。", + "By clicking 'Agree and Continue', you are bound to the terms in the EULA.\n\nhttps://www.playstation.com/legal/op-eula/": "点击“同意并继续”即表示你愿意遵守最终用户许可协议的规定。\n\nhttps://www.playstation.com/legal/op-eula/", + "DISABLED": "禁用", + "Change the color of your aiming reticle, for greater visibility.": "更改准星颜色,更好地调整可视度。", + "SECONDARY WEAPONS": "次要武器", + "DIVE": "闪躲", + "MOVE FORWARD": "向前移动", + "Construction has begun on the Democracy Space Station. The local populace is honored to host thousands of construction crews for this historic event.": "民主空间站(DSS)的建设工作已经开始。当地居民荣幸地接待了参与此次历史性活动的数千名建筑工人。", + "Difficult terrain inhibits your movement. Best practices recommend avoiding Snow, Mud, Water, Shrubberies, and Lava. For a complete list, see Manual Section D.198-2.": "复杂地形会阻碍你移动。最好避开雪地、泥地、水面、灌木丛和岩浆。如需查看完整列表,请翻阅手册D部分198-2。", + "BRIDGE": "舰桥", + "LEFT": "左", + "Info Feed Visibility": "动态信息可视度", + "DSS Tactical Actions become activated when they have met their donation goals.": "捐赠目标达成时,相应的DSS战术行动就会激活。", + "Vehicle Camera Centering": "载具视角居中", + "Terrain Quality": "地形质量", + "DONATION ACCESS LICENSE": "捐赠物资使用许可", + "UNBLOCK": "取消屏蔽", + "SECONDARY": "次要", + "Controller only. Selecting Default will swap between primary and secondary weapon when tapping the swap button, whilst holding the swap button will change to your support weapon. \nHelldivers Classic will swap between primary and support weapon when tapping the swap button, whilst holding the swap button will change to your secondary weapon.": "仅限控制器。选择“默认”时,轻点切换按钮切换主要或次要武器,按住切换按钮切换为支援武器。\n选择“绝地潜兵 经典”时,请点切换按钮切换主要武器或支援武器,按住切换按钮切换为次要武器。", + "The longer a mission takes, the heavier the enemy presence gets.": "任务耗时越久,敌方兵力越强。", + "Democracy Officers are direct representatives of Super Earth High Command. They augment and enhance the loyalty of all Super Destroyer crew members.": "民主官是超级地球最高指挥部的直接代表,他们将增强和提升所有超级驱逐舰船员的忠诚度。", + "If a squadmate dies during a mission, make sure you pick up their dropped samples. There will be time for mourning later!": "若队友在执行任务期间阵亡,请务必捡起他们掉落的样本。以后还会有时间供你追悼他们!", + "#COUNT/#TOTAL (MAX)": "#COUNT/#TOTAL(最多)", + "FAST RECON VEHICLE": "快速侦察载具", + "UP": "上", + "PURCHASE SUCCESSFUL": "购买成功", + "Tired of missing your target? Use First Person View (FPV) to make long-distance shots.": "不想再打空了?使用第一人称视角(FPV)进行远距离射击吧。", + "Framerate Limit": "帧率限制", + "[ Press": "[ 按下", + "Triggers when the button is released after being pressed down.": "按下按键后松开时触发。", + "SCOPED": "开镜", + "CLASS 3 EXOSTORM": "3级异界风暴", + "UI Brightness": "UI亮度", + "Lowers the time it takes for the extraction shuttle to reach the extraction beacon.": "缩短撤离运输船抵达撤离信标所需的时间。", + "ESPAÑOL": "ESPAÑOL", + "The Ministry of Defense is responsible for the defense of Liberty against all enemies, human and non-human, realized and potential.": "国防部负责保卫自由精神,抵御所有已知和潜在的外敌,不论是人类或是非人类。", + "SMALL": "小", + "ARMOR RATING": "盔甲等级", + "Support Weapons deploy with the maximum number of carriable magazines.": "支援武器配给的可携带弹匣数增加至最大数量。", + "NEW HOPE CONSTRUCTION SITE": "希望新城建造区", + "FSR": "FSR", + "Make sure to pick up your fallen squadmates' sample containers. They're critical for our collective scientific progress!": "务必捡起阵亡队友的样本容器。样本对于推动我们的集体科学进步至关重要!", + "The threshold at which stabilization stops being applied.": "不再启用稳定量的阈值。", + "REPORT": "举报", + "FACTORY HUB (DESTROYED)": "工厂中心(遗址)", + "Cheating": "作弊", + "Completion Est: #HOURS h": "预计用时:#HOURS小时", + "Reduces time until new reinforcements are granted once they've been depleted.": "缩短增援耗尽后获得新增援的时间。", + "Mouse Aim Sensitivity": "鼠标瞄准灵敏度", + "VICTORY POSE": "胜利姿势", + "Low light and poor weather reduce your vision. (But never fear—they also reduce the vision of our enemies)": "光线不足和天气恶劣都会影响视野。(但是完全不必担心,因为敌方视野同样会受到影响)", + "Always": "总是显示", + "RADIAL MENU LEFT": "圆盘菜单左", + "ACTIVE ACTION": "进行中的行动", + "PapaPatrioot": "爱国老爹爹", + "BLOCKED PLAYERS": "已屏蔽玩家", + "Enables an extensive logistics network to operate within the Gloom, negating adverse Gloom effects on surrounding planets.": "促进庞大的后勤网络在“阴霾”内运作,彻底消除“阴霾”对周边行星的负面影响。", + "Weapon Status Visibility": "武器状态可视度", + "VOTE": "投票", + "Dialogue Volume": "对话音量", + "ACTIVE": "已启动", + "NEXT WEAPON": "下一件武器", + "MUSCLE ENHANCEMENT": "肌肉强化", + "Mission difficulty is determined in part by the types of enemy units in the area. Make sure you bring the appropriate weaponry!": "任务难度也和当地敌方部队的类型有关。一定要带上合适的武器!", + "TACTICAL OBJECTIVE (OPTIONAL)": "战术目标(可选)", + "IN-WORLD ONLY": "仅显示剧情相关文字", + "Diving to the ground can be a life-saver, but it also makes you an easy target for melee units.": "扑倒在地或许可以救命,但是也会让你变成近战单位的活靶子。", + "Window": "窗口", + "SQUAD RECONNECT": "小队重连", + "SHIP MODULE": "舰船模块", + "LtBadazz500": "暴躁中尉500", + "Are you sure you want to unbind this input?": "确定要解除绑定该键位吗?", + "Paradise": "乐土", + "Text To Speech Voice": "文字转语音的声音", + "Adjusts the overall sharpness of the final image.": "调整最终图像的总体锐度。", + "Enable Performance Monitor. The Discreet version will show framerate, memory and network statistics in the top left corner, ideal for general gameplay without distraction. While the Base, Graph and Advanced versions will show framerate statistics in the top right corner.": "启用性能监视器。简洁版会在左上角显示帧率、内存和网络数据,适合常规游戏,能避免干扰体验。基础版、图表版和高级版则会在右上角显示帧率数据。", + "ORDER OUTCOME": "指令结果", + "BINDINGS": "键位绑定", + "Experimental Infusion": "试验性注射剂", + "ROTATE": "旋转", + "Place markers on the map to help your squad navigate.": "在地图上放置标记可以为队友指路。", + "UNABLE TO REPORT": "无法举报", + "When your stamina is depleted, your sprint speed is slower and your accuracy is worse.": "耐力耗尽以后,你的冲刺速度和命中率都会下降。", + "The Automatons are equipped with hyper reactive protocols, making them susceptible to suppressive fire. The more you shoot at them, the less accurate they'll be.": "机器人配备过度反应协议,因此,火力压制对付它们格外有效。你击中它们的次数越多,它们还击的命中率越低。", + "The structures on this planet allow the Illuminate to communicate outside the galaxy.": "光能者利用星球上的这种建筑与星系外的同类通讯。", + "Download starting": "开始下载", + "Expert Extraction Pilot": "专业撤离飞行员", + "SAMPLE EXTRICATOR": "样本拯救者", + "MOVE DISABLED": "移动禁用", + "DONATE": "捐赠", + "LOOK LEFT": "向左看", + "EXTRA LARGE": "特大", + "Eagle stratagem cooldown time reduced by #VALUE%.": "“飞鹰”战略配备的冷却时间缩短#VALUE%。", + "Democracy Space Station": "民主空间站", + "SHIP MODULE LEVEL UNLOCKED": "已解锁舰船模块等级", + "VITALITY BOOST": "生命力增强", + "Available in: #MINUTES m #SECONDS s": "就位倒计时:#MINUTES分#SECONDS秒", + "Reinforces sentries with state-of-the-art cyanoacrylate adhesives, greatly improving their durability under fire.": "利用先进的氰基丙烯酸酯粘合剂加固哨戒炮,大幅提升其在炮火攻击下的耐久度。", + "DEAD SPRINT": "死亡冲刺", + "The quality of atmospheric lighting. Reducing this may introduce noise and ghosting but improve GPU performance.": "氛围光照的质量。下调该选项或许会导致出现噪点和重像,但是可以改善GPU性能。", + "Planet Biome": "星球生物群落", + "IN GAME": "正在游戏", + "GENERAL": "其他", + "SEARCH RESULT": "搜索结果", + "Map Position": "地图位置", + "HIGH-DENSITY EXPLOSIVES": "高密度炸药", + "JET BRIGADE FACTORIES": "喷气旅孵化厂", + "The Ministry of Humanity maintains healthy, productive voters by managing education, healthcare, social grading, and gene management.": "人道部通过教育、医疗保健、社会分级和基因管理,培育生产能力较高的健康投票人。", + "Sep": "9月", + "PREVIOUS EVENT": "前一战事", + "HEAVY ORDNANCE DISTRIBUTION": "重型军械分发", + "ESPAÑOL (LATINOAMÉRICA)": "ESPAÑOL (LATINOAMÉRICA)", + "Select when an on-screen option will be shown. Default behavior is to only display the on-screen keyboard if a keyboard was not used to enter the text input state. May require Steam Big Picture mode on PC.": "选择何时显示屏幕选项。默认是仅在未使用键盘输入文本时才显示屏幕键盘。可能要在PC上使用Steam的大屏幕模式。", + "CONCEALED INSERTION": "隐蔽上阵", + "Allows Helldivers to traverse difficult terrain with ease.": "让绝地潜兵能够轻松穿过复杂地形。", + "Active for: #MINUTES m #SECONDS s": "激活时长:#MINUTES分#SECONDS秒", + "Allows Mortar Targeting Platform to access Helldiver HUD ecosystem through use of third-party conversion software.": "利用第三方转换软件,允许迫击炮瞄准平台接入绝地潜兵的HUD生态系统。", + "E-710 RICH STRAIN": "富含710元素的突变种", + "Select the visibility of ordinal directions on the compass.": "选择罗盘的方位可视度。", + "Want to show off how firmly you support capitalism? Spend medals on a Warbond!": "想要展示你支持资本主义的决心?为战争债券多花费一些奖章吧!", + "SEND REPORT": "发送举报", + "Select the visibility of weapon status during gameplay.": "选择游戏过程中的武器状态可视度。", + "Triggers only when a button is pushed down and released quickly.": "仅在快速按下并松开按键时触发操作。", + "WEAPON WHEEL DOWN": "向下转动武器轮盘", + "How sensitive the motion sensor should be in relation to moving the controller.": "移动控制器时动态感测器的灵敏度。", + "Firebomb Hellpods": "火焰炸弹绝地喷射舱", + "LOCKED": "未解锁", + "HOME CINEMA": "家庭影院", + "FACTION": "阵营", + "Select the display resolution. This is the pixel count of the final image. Lower values will have less detail. In windowed mode this setting also dictates the size of the window, in the other modes we recommend using the resolution of the display device and adjusting the Render Scale setting to achieve desired performance.": "选择显示的分辨率。该数值为最终图像的像素点总数。数值越低,显示的细节越少。在窗口模式中,该选项也会决定窗口的尺寸。在其他模式中,我们推荐使用与显示设备相同的分辨率,然后调整渲染比例,从而实现理想的性能。", + "The volume of all audio combined.": "所有声音的总音量。", + "Select if anti-aliasing will be applied to smoothen jagged edges.": "选择是否启用抗锯齿处理锯齿状边缘。", + "No chat messages to include.": "无聊天消息可附加。", + "Select level of geometry detail. Lower values increase GPU performance, at the cost of silhouette detail on objects.": "选择几何图形细节层次。下调数值可以改善GPU性能,但是会弱化物体的轮廓细节。", + "This is the best thing I've ever seen in my life! Can not live without!": "从没见过这么棒的产品!没有它我就活不下去!", + "Received #TIME ago...": "#TIME前收到…", + "This planet has been completely infested by the Terminids, transformed inside and out into a hive of Tyranny. It is a source of Gloom spores.": "这颗星球已被终结族彻底侵占,从内到外被改造成了暴政的虫巢。现已变成了“阴霾”孢子的来源。", + "CAREER": "生涯", + "Booster Pack": "强化资源包", + "DSS CONSTRUCTION SITE - PHASE 2": "DSS建筑工地 - 第2阶段", + "Select the visibility of the compass.": "选择罗盘可视度。", + "Difficulty 1-3": "难度1-3", + "TACTICAL ACTION": "战术行动", + "See a planet that's on the brink of falling under enemy control? Rally your fellow Helldivers and mount a defense. Every mission counts!": "一颗星球即将落入敌人的铁蹄之下,你看见了吗?快号召其他绝地潜兵一起建立防线。每一场任务都至关重要!", + "Input Callouts": "输入口令", + "Stratagem": "战略配备", + "TIER #COUNT COMPLETED": "已完成#COUNT阶", + "Triggers continuously while a button is being pushed down.": "只要按下按键就连续触发操作。", + "QUICK WEAPON WHEEL DOWN": "快速向下转动武器轮盘", + "TIER #COUNT": "#COUNT阶", + "Increases grenade carrying capacity for all Helldivers.": "提高所有绝地潜兵的榴弹携带容量。", + "NVIDIA Reflex tries to reduce the system latency and increases responsiveness. When enabled, NVIDIA Reflex will reduce latency from the GPU. Boost mode will try to also reduce latency from the CPU.": "NVIDIA Reflex旨在降低系统延迟并提升响应速度。启用后,NVIDIA Reflex将降低GPU的延迟。增强模式也将尽可能降低CPU的延迟。", + "Arm injuries reduce your ability to handle recoil and will cause your aim to sway more.": "手臂受伤会令你难以应对后坐力,使得瞄准动作摆动幅度增大。", + "TV SPEAKERS": "电视喇叭", + "Upgrade your ship modules to enhance the capabilities of your Stratagems! It's the perfect way to turn samples into Liberty.": "升级舰船模块可提升战略配备的性能!这是将样本转化为解放之火的完美渠道。", + "DARK FLUID SYNTHESIS LABORATORY": "暗液体合成实验室", + "CENTER FOR CITIZEN SURVEILLANCE (DESTROYED)": "公民监控中心(遗址)", + "Increases orbital targeting speed by updating cannon targeting software to premium version.": "轨道加农炮用于瞄准目标的软件更新到高级版本,提高轨道锁定目标的速度。", + "Impersonating Another User": "冒充其他用户", + "Your Friend Code": "你的好友代码", + "JOIN SQUAD": "加入小队", + "If you get knocked down while holding a stratagem beacon, it will deploy where you were standing.": "如果你在手执战略配备信标的时候被击倒,战略配备将部署在你倒地之前站立的位置。", + "Your Contribution: #COUNT": "你的贡献:#COUNT", + "JUMP": "跳跃", + "This planet-wide, ultra-high-security facility provides ample space for the secure confinement of terrorist dissidents until they are fully rehabilitated and re-educated.": "这座覆盖全星球的超高安全设施收容空间充足,信奉恐怖主义的异见分子可以在这里接受安全监禁,直到全面改造并接受再教育。", + "July": "7月", + "Season ends in: #DAYS Days #HOURS Hours": "赛季倒计时:#DAYS天#HOURS小时", + "Motion Sensor Enable Mode": "动态感测器启用模式", + "Difficulty 7-9": "难度7-9", + "Eagles are fast-response strike craft, with much shorter call-in times than Orbital fire support.": "“飞鹰”是快速反应攻击机,其呼叫时间显著短于轨道火力支援。", + "If an enemy ever attempts to engage in diplomacy, SHOOT THEM. We musn't believe their lies.": "对于试图对话的敌人,要毫不犹豫地开枪击毙。一定不能为花言巧语所欺骗。", + "So easy to use even my grandma loves it": "简单易用,就连我奶奶都很喜欢。", + "Enables a depth of field effect in certain camera views. Disabling depth of field will mean that all parts of the game are in focus at all times.": "在特定视角中启用景深效果。禁用景深即表示游戏内的一切将始终呈现清晰对焦状态。", + "Adjust the scale of your HUD.": "调整HUD的尺寸。", + "Unlimited": "无限", + "This will reset all settings in this tab to default.\nAre you sure you want to continue?": "该操作将把本页面设置重置为默认状态。\n是否确定要继续?", + "ULTRA": "超高", + "SVENSKA (Unsupported)": "SVENSKA (Unsupported)", + "HUD": "HUD", + "X- AXIS": "X-轴", + "Select the visibility of your destroyer marker during gameplay on city maps.": "选择游戏过程中城市地图上你的驱逐舰标记的可视度。", + "USES": "使用次数", + "No player found": "没有找到玩家", + "Teammate Stratagem Visibility": "队友战略配备可视度", + "DOWNLOADING LANGUAGE PACK": "正在下载语言包", + "Fullscreen": "全屏", + "ACCOUNT": "账户", + "Account Linked": "已绑定账户", + "You have a limited amount of reinforcements available in a mission. If you run out they will be replenished slowly on a timer.": "在一次任务中,你能获得的增援数量有限。一旦耗尽就必须等待计时,缓慢补充。", + "Equip a booster to increase the chance of a successful liberation! Boosters apply to your entire squad.": "装备强化资源,提升解放行动的成功率!强化资源对全队成员生效。", + "ACTIVE FOR: #MINUTES m #SECONDS s": "激活时长:#MINUTES分#SECONDS秒", + "Your changes have not been applied.": "你的更改尚未应用。", + "BOTTOM RIGHT": "右下", + "Sample Pickup Visibility": "样本拾取可视度", + "GLOOM OUTPOST BRAVO": "“阴霾”布拉沃哨站", + "SITE FOR VENGEFUL CONTEMPLATION OF TYRANNY'S CRIMES": "暴政罪行警示地", + "MOVE BACK": "向后移动", + "DSS LOGISTICS HUB": "DSS物流中心", + "Scan the QR code to participate in the post match survey.": "扫描二维码参与战后调查。", + "#DAYSd #HOURSh #MINSm Left": "还剩#DAYSd #HOURSh #MINSm", + "Cancel Search": "取消搜索", + "More challenging missions yield greater rewards.": "越具挑战性的任务奖励越丰厚。", + "RECOIL SIM": "后坐力模拟", + "#READY MB/#TOTAL MB - #PERCENTAGE% complete": "#READY MB/#TOTAL MB - 已完成#PERCENTAGE%", + "Dynamic Aim Mode": "动态瞄准模式", + "Heads Up Display (HUD) Scale": "HUD大小", + "Stamina Enhancement": "耐力强化", + "A highly secure facility for the safe growth and breeding of Terminids and low-risk extraction of E-710 is located here.": "高度戒备设施,用于安全繁育终结族和低风险提取710元素。", + "NATIVE": "原始", + "Are you sure you want to unlink your accounts?": "确定要解除账户绑定吗?", + "OFF": "关", + "Enabling this setting produces more realistic ambient lighting, making nearby surfaces occlude some of the light.": "启用该设置可让附近的表面遮挡部分光线,从而产生更加逼真的环境阴影效果。", + "Select the intensity of sudden camera movements.": "选择视角突然移动的幅度。", + "SAMPLE": "样本", + "Purchase Super Credits to access premium content.": "购买超级货币,解锁尊享内容。", + "Something went wrong while attempting to reach PlayStation™Network. Error codes:": "尝试访问PlayStation™Network时出现问题。错误代码:", + "Search Territory #TERRITORY on Planet #PLANET": "搜索#PLANET星球上位于#TERRITORY的敌方领地", + "Bloom": "泛光", + "Recommended by 9 out of 10 dentists": "90%的牙医鼎力推荐", + "STRATAGEM TRAITS": "战略配备特性", + "BLAST ABSORPTION": "爆炸吸收", + "Inverts up and down control of mouse direction in First Person View (FPV).": "在第一人称视角(FPV)下,鼠标上下方向翻转。", + "The former site of the Center for Citizen Surveillance. The tragic loss of the facility further evidences the critical imperative of comprehensive domestic surveillance.": "公民监控中心遗址设施的惨重损失进一步证明了全面监控的迫切必要性。", + "Your stance has a significant impact on accuracy. The SEAF manual lists the following stances in order of least to most accurate: Moving < Standing < Crouching < Prone.": "你的姿势会显著影响命中率。超级地球武装部队手册按照命中率从低到高的顺序列出了以下姿势:移动<站立<蹲下<趴下。", + "Here, the best of the best go through the rigorous Helldiver training that will earn them their capes.": "万里挑一的精英在这里接受严格的绝地潜兵训练,争取赢得披肩。", + "V-Sync": "垂直同步", + "AXIS": "坐标轴", + "Hellpods have basic steering capabilities. Try to drop in on your enemies!": "绝地喷射舱具备基础转向功能。尽量降落在敌人周围!", + "Select the behaviour of the crosshair visibility during gameplay.": "选择游戏过程中十字准星可视度的变化方式。", + "Select the width of the stamina bar during gameplay.": "选择游戏过程中的耐力槽宽度。", + "DUAL WIELD FIRE LEFT": "双持武器左手开火", + "There is currently no active action": "目前没有进行中的行动", + "CENTER OF SCIENCE": "科学中心", + "FACTORY HUB": "工厂枢纽", + "Enables smoothing of mouse inputs. Can make tracking targets easier at the cost of responsiveness.": "启用鼠标输入平滑化。有助于跟踪目标,但是会影响灵敏度。", + "UNDER COMPASS": "罗盘下方", + "LINK ACCOUNT": "绑定账户", + "GRAPHICS": "图像", + "If you notice a squadmate sympathizing with an enemy, report them to your Democracy Officer. Thoughtcrimes kill!": "如果你发现队友同情敌人,请向民主官举报。思想犯罪是会害死人的!", + "MODULES UNLOCKED": "模块已解锁", + "Volumetric Clouds Quality": "体积云质量", + "ENGLISH (US)": "ENGLISH (US)", + "The smelters and refineries on this planet turn crude materials into usable hardware.": "此星球上的冶炼厂和精炼厂可将原料变为实用的硬件。", + "Sample Scanner": "样本扫描仪", + "DEEP MANTLE FORGE COMPLEX": "深部地幔铸造复合体", + "Unable to finalize the purchase, please try again later or contact support if this error persists.": "无法完成购买,请稍后重试。如果问题仍未解决,请联系客服。", + "Select the game display mode. Fullscreen has the fastest response time, but may make switching to other applications slower.": "选择游戏的显示模式。全屏模式响应速度最快,但是可能会导致切换至其他应用程序的速度变慢。", + "UPGRADE EFFECT": "升级效果", + "On + Boost": "开启 + 增强", + "Adjusts the relative sensitivity of camera movement while aiming.": "调整瞄准时视角移动的相对灵敏度。", + "OK.": "确定", + "Some stratagems have unlimited uses, while others do not.": "部分战略配备拥有无限使用次数,而其他则是有限的。", + "Matchmaking Privacy": "匹配隐私", + "MOUSE & KEYBOARD": "鼠标及键盘", + "Please see the \"Information Pursuant to the Specified Commercial Transactions Act\" (https://www.playstation.com/ja-jp/legal/games/specified-commercial-transactions-act-jp/##helldivers2) for details on the timing and method of payment, delivery time of the product, application deadlines, and cancellation or withdrawal of an application.": "-", + "DELIVERY SYSTEM": "配送系统", + "Installs electronic actuators that augment the standard method of manual, foot-operated Hellpod steering.": "安装电子致动器,增强脚踏式手动转向型绝地喷射舱的标准操作。", + "OPEN COMMS WHEEL": "打开通信轮盘", + "FIREBOMB HELLPODS": "火焰炸弹绝地喷射舱", + "Authorizes hazard pay for pit crews, allowing them to reload the Eagle Fighter in-spaceflight.": "批准向维修人员支付危险津贴,以便他们放心在航天飞行期间重新武装“飞鹰”战斗机。", + "In addition to restoring health, Stims temporarily increase movement speed and damage reduction.": "治疗剂除恢复生命值以外,还可以暂时提升移动速度和伤害减免。", + "Decreases Support Weapon stratagem cooldown by #VALUE%.": "支援武器战略配备的冷却时间缩短#VALUE%。", + "Super Credits": "超级货币", + "Gives Helldivers a #VALUE chance to retrieve twice the samples on sample pickup.": "绝地潜兵有#VALUE的几率可在拾取样本时获得双倍样本。", + "Mutual Friends": "共同好友", + "Applies the near-frictionless lubricant known as \"Super Jelly\" to sentry ring mounts, facilitating extremely smooth mechanical operation.": "被称为“超级果冻”的润滑剂近乎无摩擦力,将其涂抹在哨戒炮的旋转式支架上,机械操作将变得极为流畅。", + "Reloading discards the remaining rounds in your magazine.": "重新装填弹药会丢弃弹匣内所有剩余弹药。", + "BASIC": "基础", + "ZOOM OUT": "视角拉远", + "The former site of the Xenoentomology Center, destroyed by the Terminids. Many scientists were horrifically massacred in the unprovoked attack.": "异星昆虫学研究中心遗址,被终结族摧毁。在这次无端袭击中,许多科学家遭到惨绝人寰的屠杀。", + "HIDDEN": "隐藏", + "Controller Sticky Aim": "控制器粘滞瞄准", + "EXPERT EXTRACTION PILOT": "专业撤离飞行员", + "Use Async Compute": "使用异步计算", + "Mouse Map Sensitivity": "鼠标地图灵敏度", + "VEHICLE CUSTOMIZATION": "载具自定义", + "DROP SUPPORT WEAPON": "放下支援武器", + "Eagle strikes fire at enemies.": "“飞鹰”空袭向敌人猛烈开火。", + "Provides minor damage reduction from all sources for all Helldivers.": "为全体绝地潜兵提供轻微的减伤效果(伤害来源不限)。", + "June": "6月", + "UNAPPLIED CHANGES": "未应用更改", + "Controls the quality of the scene lighting calculation": "控制场景光照计算质量", + "Z- AXIS": "Z-轴", + "FRANÇAIS": "FRANÇAIS", + "Narrates menus, popups and incoming chat messages.": "朗读菜单、弹出窗口和接收的聊天消息。", + "Space Quality": "太空画质", + "PLANETARY BOMBARDMENT": "星球轰炸", + "Framerate targeted by Dynamic Resolution Scaling.": "动态分辨率缩放调整达到的帧率。", + "ORDER DETAILS": "指令详情", + "Reticle Color": "准星颜色", + "AMD Anti-Lag 2": "AMD Anti-Lag 2", + "Select the visibility of vehicle info during gameplay.": "选择游戏过程中的载具信息可视度。", + "Selects the text to speech narrator voice type": "选择文字转语音的旁白声音类型", + "Remember Aim Mode": "记住瞄准模式", + "Invert Scope (Horizontal)": "开镜视角翻转(水平)", + "This player is currently your friend on Xbox network and/or other Helldivers 2 platforms. They must be removed from your friends list on those services before they can be removed from your in-game friend list.": "该玩家目前是你在Xbox 网络和/或其他《Helldivers 2》平台的好友。必须先将其从这些服务平台的好友列表中删除,然后才能从游戏内的好友列表删除该玩家。", + "November": "11月", + "Orbital HE barrage spread reduced by #VALUE%.": "轨道高爆弹火力网覆盖面减少#VALUE%。", + "Very authentic and easy to put on. I am very satisfied!": "货真价实,穿脱便捷。我很满意!", + "NEW FRIEND REQUEST": "新好友申请", + "SHORT": "短", + "Extensive mining and drilling operations are taking place to comb this former Hive World for all traces of the highly valuable substance known as E-711.": "目前大规模采矿与钻探作业正在进行,旨在从这个前虫窝世界的地方找到高价值物质711元素的踪迹。", + "INVITE ONLY": "仅限邀请", + "VOICE CHAT ACTIVATION": "启动语音聊天", + "HUD Background Opacity": "HUD背景不透明度", + "WEAPON FUNCTION 3": "武器功能3", + "Players can be reported if they have written something in chat that breaches the terms of service. This player has no chat messages to include in a report.": "如果玩家在聊天中发表了违反服务条款的内容,可将其举报。此玩家没有可举报的聊天信息。", + "Inverts left and right of camera direction.": "视角左右方向翻转。", + "Can't start this activity while in a mission": "正在执行任务,无法开启这项活动", + "Missions are filled with unexplored points of interest. Check them out—you never know what you might find.": "任务过程中有许多未经探索的特殊地点。去看一看吧,或许你会发现些什么呢!", + "Screen Brightness": "画面亮度", + "GRAPH": "图表", + "This player is not associated with an ID on PlayStation™Network and cannot be moderated. You can take any of the following actions instead.": "这位玩家没有关联PlayStation™Network上的ID,无法对其进行审核。你可以另行选择下列操作。", + "CROSSPLAY": "跨平台游玩", + "EVENT DETAILS": "战事详情", + "Assignment Notifications": "任务分派通知", + "Determines where the map is placed.": "设定地图所在位置。", + "Enables motion sensor controls while using a controller.": "使用控制器时启用动态感测器控制项。", + "Having trouble spreading Democracy in the darkness? Some weapons include top-of-the-line illumination aids. Hold \"Reload\" to turn them on!": "在黑暗中难以传播民主?部分武器配有尖端照明辅助设备,按住“装填弹药”键即可开启照明!", + "February": "2月", + "STUN PODS": "眩晕喷射舱", + "The Illuminate monoliths on this planet use Dark Fluid to affect the gravity of other celestial bodies.": "该星球上的光能者巨石利用暗液体影响其他天体的引力。", + "Adjusts the sensitivity of map movement.": "调整地图移动的灵敏度。", + "Sample Extricator": "样本拯救者", + "FRIEND REQUESTS": "好友申请", + "OPEN MAP": "打开地图", + "#HUNDREDTHS:#MINUTES:#SECONDS": "#HUNDREDTHS:#MINUTES:#SECONDS", + "EMOTE OPTION D": "表情D", + "DOWN": "下", + "Don't die!": "别死!", + "Amazing quality. It even survived atmospheric re-entry... twice!": "品质过硬。甚至能顶住穿越大气层的损耗…而且是两次!", + "Remember: Freedom!": "牢记自由!", + "SQUAD INVITE": "小队邀请", + "Select quality level of reflections on certain surfaces. Higher settings allow for more accurate reflections but may affect performance.": "选择特定表面的反射质量等级。上调该设置可以提高反射的精确度,但是可能会影响性能。", + "CLASS 2 EXOSTORM": "2级异界风暴", + "If at first you don't succeed, dive, dive again. And again. And again. And again. And again. And again. And again. And again. And again. And again. And again. And again. And again. And again.": "如果你在一开始失败了,那就再度空投参战,不断空投。不断、不断、不断、不断、不断、不断、不断、不断、不断、不断、不断、不断、不断空投。", + "Patriot_251": "爱国者_251", + "AGREE & CONTINUE": "同意并继续", + "UPGRADE #MODULE FOR MORE": "升级#MODULE解锁更多", + "ORBITAL BLOCKADE": "轨道封锁", + "LEARN MORE": "了解更多", + "The Illuminate have erected more monoliths than usual on this planet.": "光能者在这颗星球上立起的巨石数量超乎寻常。", + "POST MATCH SURVEY": "战后调查", + "Look Sensitivity": "视角灵敏度", + "ENGINEERING BAY": "工程港", + "RADIAL MENU ABSOLUTE SELECTION": "圆盘菜单绝对选取", + "Bullying/Harassment": "霸凌/骚扰", + "There is a SEAF aircraft repair facility present on this planet.": "此星球上坐落着超级地球武装部队的飞行器维修设施。", + "The volume of the in-game sound effects.": "游戏内音效的音量。", + "SWITCH SEAT (PREVIOUS)": "切换座位(上一个)", + "No blocked players.": "没有被屏蔽的玩家。", + "QUICK WEAPON WHEEL RIGHT": "快速向右转动武器轮盘", + "Comms Wheel Visibility": "通信轮盘可视度", + "Allow Data Collection": "允许收集数据", + "Defamation": "诽谤", + "Set the default audio language spoken by characters.": "设置角色音频的默认语言。", + "Reduces cooldown time for all Stratagems by #VALUE%.": "所有战略配备的冷却时间缩短#VALUE%。", + "Help us build the best PlayStation® experience!\nWhen you play this game, Sony Interactive Entertainment collects data that is necessary to operate the game. \nIf you agree, Sony Interactive Entertainment may also collect data about your interaction with the game and errors that occur. This data will be used as explained in our privacy policy. \nYou can change this setting at any time to allow full or limited data collection.": "帮助我们打造PlayStation®最佳游戏体验!\n在您游玩本游戏时,索尼互动娱乐会收集本游戏运行所需的必要数据。\n如果您同意,索尼互动娱乐可能还会收集其他数据,以便了解您与游戏互动的方式以及期间发生的错误。这些数据的使用方式皆遵守我们的隐私政策。\n您可以随时更改该设置,选择提供全部或部分数据。", + "PORTUGUÊS (BR)": "PORTUGUÊS (BR)", + "No friend requests.": "没有好友申请。", + "Here, fresh-faced recruits learn what it takes to defend Super Earth and her values.": "面带稚气的新兵在这里学会如何捍卫超级地球及其价值观。", + "REQUEST REINFORCEMENT": "请求增援", + "Resolution": "分辨率", + "Download failed.\nTry again, or select a different language.": "下载失败。\n再试一次,或选择其他语言。", + "VISIBLE": "显示", + "OPEN VEHICLE FUNCTION WHEEL": "打开载具功能轮盘", + "PLATOON & FRIENDS": "特战排与好友", + "LEVEL #LEVEL": "#LEVEL级", + "NVIDIA Reflex Low Latency": "NVIDIA Reflex低延迟", + "TOGGLE LASER GUIDANCE SYSTEM": "切换激光制导系统", + "[Redacted]": "[已编辑]", + "All Stratagems have their strengths and weaknesses. Choose your Stratagem loadout to best fit the mission and your squad composition.": "战略配备全部各有优劣。要根据任务需要和小队阵容来挑选最合适的战略配备。", + "CHANGE SHIP NAME": "更改舰船名称", + "Mouse Smoothing": "鼠标平滑", + "The first manned site established in Gloom-infested space, standing steadfast against all forces who would tear it down.": "首个在“阴霾”侵蚀星域建立的人类驻军据点,仍然巍然屹立着抗击一切妄图将其摧毁的势力。", + "Impersonating developer": "冒充官方工作人员", + "Selectively lower resolution where detail is less necessary.": "在细节需求不高时,选择性降低分辨率。", + "You have reached the approved generosity limit. Please wait #HOURS h #MINUTES m before donating again.": "你已达到批准的捐赠上限。请在#HOURS小时#MINUTES分后再尝试。", + "CHANGE BINDINGS": "更改键位绑定", + "Removes stabilizing phlematizer agents from explosive material used to pack orbital shells, allowing for more powerful payloads.": "从装填轨道炮弹的炸药物质中移除稳定减敏剂,增强炮弹的威力。", + "INSPECT": "查看", + "Select the visibility of secondary objectives.": "选择次要目标的可视度。", + "Compass Visibility": "罗盘可视度", + "SEARCH": "搜索", + "Select the visibility of Stratagems during gameplay.": "选择游戏过程中的战略配备可视度。", + "An abundant source of E-711, carefully harvested by experienced hands.": "富含711元素,由经验丰富的采集人员精心开采。", + "Jun": "6月", + "Nine out of ten doctors agree that a wound to the chest will make you bleed out if unattended.": "九成医生一致认为,如果不处理胸部的伤口,你就会流血致死。", + "RIGHT": "右", + "Failed to find player.": "未能找到玩家。", + "Winganon_59": "温加农_59", + "BRIEFING TRANSMISSION": "简报通讯", + "SEPARATED": "独立", + "You are Super Earth's elite. Never forget that.": "你是超级地球的精英,时刻牢记这一点。", + "Stamina Width": "耐力槽宽度", + "Select quality profile.\nQuality targets the highest visual fidelity at a lower framerate.\nPerformance targets a higher framerate for a smoother experience at a lower rendering resolution.": "选择画质设置。\n“画质”会以降低帧率为代价,提供最逼真的视觉效果。\n“性能”会追求较高的帧率带来更顺畅的体验,但是会降低渲染分辨率。", + "When you're up against the bots, remember the 3 Cs:\nCover, Courage, and more Cover.": "对抗机器人要牢记三大准则:\n找掩体,要勇敢,然后继续找掩体。", + "The DSS fires nonstop orbital bombardments from its suite of 77 PRESIDENTIAL-Class Cannons, providing planetwide artillery support and accelerating liberation efforts. Temporarily, also increases Reinforcement Budget by +1 per squad member and augments all loadouts with FX-12 Shield Generator Relay Stratagem.": "民主空间站利用其77门总统级加农炮不间断地进行轨道轰炸,为整个星球提供炮火支援,加速解放进程。同时提高增援预算,每位队员增援+1,此外利用“FX-12防护罩生成中继器”战略配备强化所有武装配置。", + "HAND CARTS": "手推车", + "If enabled, crossplay allows you to play with players on other platforms.": "启用跨平台游玩后,你可以和其他平台的玩家一起游戏。", + "The following stratagems can now be purchased from the stratagems tab:": "现可从战略配备页面购买以下战略配备:", + "Pay attention to these tips. They've been carefully calibrated to ensure your success.": "请认真阅读提示。这都是精心总结的经验,能确保你夺得成功。", + "Reticle Visibility": "十字线可视度", + "Available in: #DAYS d #HOURS h": "就位倒计时:#DAYS天#HOURS小时", + "USE BACKPACK FUNCTION": "使用背包功能", + "As a last resort, you can use melee attacks to fend off enemies. Remember: death is better than cowardice!": "万不得已时,近战攻击是你对抗敌人的最后手段。要记住:苟且偷生不如慷慨赴死!", + "Support weapons have long cooldown periods. Make sure to retrieve them should the wielder die.": "支援武器冷却时间较长。使用者阵亡以后,务必将其取回。", + "ROBOTICS": "机械", + "#COUNT / #TOTAL": "#COUNT / #TOTAL", + "When enemy infrastructure is in need of destruction, Super Earth helpfully provides a Hellbomb stratagem to all Helldivers, free of charge.": "如果有敌方的基建亟需摧毁,超级地球会施以援助,为所有绝地潜兵提供一枚地狱火炸弹,不收取任何费用。", + "SUBMIT": "提交", + "Illuminate": "光能者", + "Stun Pods": "眩晕喷射舱", + "THANK YOU FOR REPORTING!": "感谢你的举报!", + "The degree to which the aim sticks to a target when passing over it.": "准星经过目标时附着在目标上的程度。", + "Reticle Outline": "准星轮廓", + "The Galactic War is a united effort. Only by working together can we ensure planets don't fall to the enemy.": "星系战争是我们共同的责任。只有团结一致,才能确保我们的星球不会落入敌人手中。", + "Determines how voice chat transcription is used. Available options:\nOff: No voice chat transcription \nIncoming only: Transcribe incoming voice chat as text\nOutgoing only: Outgoing voice chat is synthesized from text\nFull: Combines both of the previous options": "决定语音聊天转录的使用方式。可用选项:\n关闭:不启用语音聊天转录\n仅输入:将输入设备的语音聊天转录为文字\n仅输出:根据文字合成语音聊天,从设备中输出\n完整功能:结合以上两个选项", + "DECLINE": "拒绝", + "Season ends in: #DAYS Days #HOURS Hours": "赛季倒计时:#DAYS天#HOURS小时", + "The volume of the in-game music.": "游戏内音乐的音量。", + "Apr": "4月", + "ULTRAMAFIC MINE": "超镁铁矿井", + "VITALITY ENHANCEMENT": "生命力强化", + "AVAILABLE IN: #DAYS d #HOURS h": "就位倒计时:#DAYS天#HOURS小时", + "VOTING FAILED": "投票失败", + "ITEM OWNED": "已拥有物品", + "Select the visibility of the grid lines in the top compass.": "选择顶部罗盘的网格线可视度。", + "TURN LEFT": "左转", + "Use Stims to heal your injuries and replenish your stamina—or that of your fellow Helldivers, in a pinch!": "使用治疗剂可治疗伤势,补充耐力。危急关头,也可以救助绝地潜兵同伴!", + "Triggers after a button has been pushed down for a set amount of time.": "按下按键一定时间后触发操作。", + "SEAF MILITARY OUTPOST": "超级地球武装部队军事哨站", + "Adjusts the intensity of the curved visual effect applied to the Heads Up Display (HUD).": "调整抬头显示(HUD)的弧形视觉效果的强度。", + "Select the visibility of the injury widget during gameplay.": "选择游戏中的伤势轮盘可视度。", + "We are Sony Interactive Entertainment. Please see our privacy policy for further information on how we collect and process your Personal Information, and how to contact us at www.playstation.com/legal/privacy-policy.": "我们是索尼互动娱乐有限公司。有关我们如何收集和处理你的个人信息以及如何通过 www.playstation.com/legal/privacy-policy与我们联系,请参阅我们的隐私政策了解详情。", + "Adjusts the position of the HUD relative to the edge of your screen.": "调整HUD与屏幕边缘的相对位置。", + "NEW DIFFICULTY LEVEL": "新难度", + "HYBRID": "混合", + "Mission Info Visibility": "任务信息可视度", + "Next Location (Current Majority Vote):": "下个地点(当前多数得票):", + "Choose whether you go into matchmaking with other players on the network when looking for a game, or whether you keep your session private and between friends.\n\nNOTE: The \"Invite Only\" setting only works with invites sent from the in-game menu": "选择匹配寻找游戏时是公开匹配在线玩家,还是只和好友匹配。\n\n注意:“仅限邀请”设置只适用于从游戏内菜单发起的邀请", + "Fire damage from Stratagems increased by #VALUE%.": "战略配备造成的灼烧伤害提高#VALUE%。", + "This planet shows clear signs of Illuminate construction.": "光能者的建筑活动迹象在该星球明显可见。", + "My wife said it's this or her. She will be missed.": "我老婆说我买了她就走人。那只能好走不送了。", + "REVOLVING CYLINDERS": "旋转弹巢", + "Most enemies have both weak spots and armored spots. The SEAF training manual recommends aiming for the weak spots.": "大多数敌人既有弱点也有披甲部位。超级地球武装部队训练手册建议你瞄准弱点进行攻击。", + "PLATOON": "特战排", + "Select the graphics device that will be used to render the game. This should normally be set to the highest performance graphics device in your system.": "选择用于渲染本游戏的图形设备。通常应将此项设置为系统内性能最高的图形设备。", + "LINK": "绑定", + "Oct": "10月", + "Sound Effects Volume": "音效音量", + "Excessive Vulgar Language": "言辞过分粗俗", + "Switch Weapon On Pickup": "武器即捡即用", + "This setting will only take effect after restarting the game": "该设置必须重启游戏才能生效", + "AIMING": "瞄准", + "Booster": "强化资源", + "POWER STEERING": "电动转向", + "FamllyMan123": "固家男人123", + "OPEN DROP WHEEL": "打开弃置轮盘", + "Are you sure you want to use your vote?": "确定要投票吗?", + "Z+ AXIS": "Z+轴", + "VOTELESS PROCESSING PLANT": "无票者转化处理厂", + "Reduces Eagle Rearm time by #VALUE%.": "“飞鹰”重新武装的时间缩短#VALUE%。", + "A new fleet of Super Destroyers is under construction here.": "这里正在打造超级驱逐舰的新舰队。", + "Off: Aiming always starts in third person view aim mode. \nGlobal: All weapons use the last selected aim mode.\nPer Weapon: The last used aim mode is stored per weapon.": "关:始终默认为第三人称瞄准模式。\n全局应用:所有武器都会使用玩家最后选择的瞄准模式。\n视武器而异:每件武器都会使用玩家上一次使用这件武器时选择的瞄准模式。", + "Increases the number of available reinforcements.": "增加可用增援次数。", + "The Ministry of Science is responsible for continuous scientific progress, augmenting our moral superiority over our enemies with technological superiority.": "科学部负责不断推动科技进步,利用技术优势增强我们压倒敌人的道德优越感。", + "Failed to retrieve blocked players.": "未能检索已屏蔽的玩家。", + "PRICE:": "价格:", + "Inverts up and down of camera direction.": "视角上下方向翻转。", + "ACCOUNT LINK STATUS": "关于账户绑定状态", + "Veteran Controller Mode": "老兵控制器模式", + "If you play one of our games, we will always access data from and/or store data on the device that you are using. This data is necessary to deliver our games, and includes:\n• Content Data: Game content data, such as video, audio, graphic, text, and game level information that is requested and downloaded for the game that you are accessing online. If you are playing an online game, this includes your online interactions as necessary to reflect those interactions on our game servers.\n• Account Data: Information required to sign you into your account. \n• Configuration Data: Information about the configuration of your device and the game you are playing , such as the device date, time and language settings and your in-game preference and settings. \n• Security Data: Information necessary to detect and investigate malicious, unauthorized or fraudulent activity.\n• Legal Data: Information required by applicable law and to demonstrate compliance.\nIf you agree, we may collect more detailed information about how you interact with our games.\nThis may include when and how you use the game’s user interface, which parts of the game you visit, which weapons you use, which characters you interact with and any errors that you encounter.\nGame Data is usually sent to us and stored with one or more unique network, device and/or account identifiers.": "在您游玩我们的游戏期间,我们需要一直处理您使用的设备的数据,并/或在您的设备上储存数据。这些数据是提供游戏服务的必要数据,包括:\n• 内容数据:访问在线功能时需要请求并下载的游戏内容数据,例如视频、音频、图像、文本及游戏关卡信息。如果您在线游玩,还将包括在线互动记录,以便游戏服务器处理这些互动操作。\n• 账户数据:您登录账户的必要数据。\n• 设置数据:所用设备以及所玩游戏的设置信息,例如设备日期、时间和语言设置、游戏内的偏好与设置。\n• 安全数据:检测及调查恶意、未经授权或作弊行为所需的必要信息。\n• 法律数据:适用法律所要求以及证明合规的信息。\n如果您同意,我们可能还会针对您与游戏互动的方式收集更详细的信息。\n该类信息可能包括您使用本游戏用户界面的时间与方式、体验过的游戏板块、使用过的武器、有互动的角色以及遇到的错误问题。\n游戏数据通常会发送给我们并使用一个或以上的专属网络、设备和/或账户标识符储存。", + "Failed to unfriend player.": "未能解除好友关系。", + "Switch between predefined graphics setting configurations.": "切换预定义的图像设定配置。", + "ROBOTICS WORKSHOP": "机械工坊", + "Inverts left and right control of mouse direction in First Person View (FPV).": "在第一人称视角(FPV)下,鼠标左右方向翻转。", + "Please see the \"Information Pursuant to the Specified Commercial Transactions Act\"\n(https://www.playstation.com/ja-jp/legal/games/specified-commercial-transactions-act-jp/##helldivers2)\nfor details regarding the timing and method of payment, delivery time of the product,\napplication deadlines, and cancellation or withdrawal of an application.": "-\n-\n-\n-", + "Select the desired anti-aliasing and upscaling algorithm. These are used to provide improved visuals as well as to improve performance. This includes TAA, NVIDIA DLSS, AMD FSR and Intel XeSS, if supported.": "选择所需的抗锯齿与增强算法模式。这些技术用于提升画质并改善游戏性能。包括TAA、NVIDIA DLSS、AMD FSR以及Intel XeSS(如果设备支持)。", + "NEGATIVE ENERGY LABORATORY": "负能量实验室", + "MORE GUNS": "增强枪炮火力", + "Select the visibility of the stamina bar during gameplay.": "选择游戏过程中的耐力槽可视度。", + "DEEP MANTLE FORGE COMPLEX (DESTROYED)": "深部地幔铸造复合体(遗址)", + "Render Distance": "渲染距离", + "GRAVITATIONAL ANCHOR": "引力锚点", + "Invert Look (Vertical)": "视角翻转(垂直)", + "Primary Objective Visibility": "主要目标可视度", + "The Meridian Wormhole was created by the Illuminate and wielded to destroy entire planets and threaten Super Earth itself. Here, authorized visitors may view the destructive singularity and remind themselves why our enemies deserve total annihilation.": "默里迪恩虫洞出自光能者之手,用于摧毁整颗星球,一度威胁到超级地球。在此,获准访客可观摩毁灭性奇点,提醒自己我们的敌人为何应被彻底歼灭。", + "#PLAYER sent a friend request!": "来自#PLAYER的好友申请!", + "The glory of Super Earth is mirrored in it's production value!": "它的产品价值映照出了超级地球的荣光!", + "Quality is out of this world! Sometimes I put it on just to wear around the house.": "质量真是没的说!有时候穿起来只是为了在家附近逛逛。", + "Atmospheric Lighting Quality": "氛围光照质量", + "Off (Diagnostics)": "关(诊断)", + "Jan": "1月", + "Destroyer Marker Visibility": "驱逐舰标记可视度", + "The Ministry of Truth analyzes citizens' activity, speech, data, DNA, RNA, and neural topology here.": "真理部在这里分析公民的活动、言论、数据、DNA、RNA和神经拓扑结构。", + "Music Volume": "音乐音量", + "SPREAD": "散射", + "LEG-MUSCLE ENHANCERS": "腿部肌肉强化", + "NEW MISSION DIFFICULTY AVAILABLE": "已开放全新任务难度", + "GLOOM RESEARCH FACILITIES": "“阴霾”现象研究设施", + "EMOTE OPTION C": "表情C", + "Vertically enhanced Jet Brigade soldiers are produced here.": "经过垂直强化的喷气旅士兵就在这里出产。", + "MOTIVATIONAL SHOCKS": "激励性冲击", + "Requires Level #COUNT": "需要达到等级#COUNT", + "Orbital stratagem cooldown time reduced by #VALUE%.": "轨道战略配备的冷却时间缩短#VALUE%。", + "LOOK UP": "向上看", + "Nameplate Visibility": "名牌可视度", + "HEADLIGHTS MODE": "大灯模式", + "The number of Voteless on this planet appears to increase more quickly than on other planets.": "该星球无票者的增速似乎高于其他星球。", + "GAME": "游戏", + "Never": "从不显示", + "Game Data is used as explained in our Privacy Policy (www.playstation.com/legal/privacy-policy).\n\nThis includes use of Game Data to:\n• Provide you with our games.\n• Understand the usage and performance of the game you are playing, and to develop improvements to the game.\n• Develop new products and services.\n• Detect, investigate, and minimise malicious, unauthorised or fraudulent behaviour.\n• Audit, compliance and legal purposes (for example, making or defending claims or activities that are required to comply with a law).": "我们将按隐私政策(www.playstation.com/legal/privacy-policy)的规定使用游戏数据。\n\n游戏数据的用途包括:\n• 为你提供游戏服务。\n• 了解你正在玩的游戏的使用情况和性能,并改良游戏体验。\n• 开发新产品和服务。\n• 检测和调查恶意、未经授权或欺诈的行为,并将这些情况的出现次数降至最低。\n• 审计、合规和法律用途(如提出索赔或为索赔辩护,或为遵守法律规定开展活动)。", + "NEW SHIPMENT OF ITEMS IS INCOMING...": "全新商品即将上架…", + "Bloom Quality": "全屏泛光质量", + "STRONG": "强", + "XeSS": "XeSS", + "/ #TOTAL": "/ #TOTAL", + "ABOUT GAME DATA": "关于游戏数据", + "Motion Sensor Acceleration": "动态感测器加速", + "PLACE MARKER": "放置标记", + "SOUNDBAR": "回音壁", + "Purchases permanent access to ammo provided by the \"Support Our Heroes\" fund, which allows patriotic family members to donate supplies to their loved ones in the field.": "购买由“支援英雄”基金会提供的弹药的永久使用权。爱国的家庭成员可通过该基金会向战场上的亲人捐赠物资。", + "Those who study Terminid behavior, ecology and E-710 potential gather here for cross-disciplinary research.": "研究终结族行为、生态学以及710元素潜能的学者在此汇集进行跨学科研究。", + "Mine arrived with some real sweat of heroes still inside it!": "收到货时,里面甚至还残留英雄的汗水!", + "Text To Speech Volume": "文字转语音的音量", + "HELLDIVERS CLASSIC": "HELLDIVERS 经典", + "Golf_Dad22": "高尔夫_大爹22", + "Exostorm fronts are coalescing into a dense system that threatens to engulf the entire planet.": "异界风暴锋面正在汇聚,形成质密的风暴系统,恐将吞噬整颗星球。", + "ULTRA QUALITY": "超高画质", + "Y+ AXIS": "Y+轴", + "ZOOM IN": "视角推近", + "Hint Visibility": "提示可视度", + "#COUNT / #TOTAL STREAK": "#COUNT / #TOTAL次连续击杀", + "Day and night sides of a planet are visible during mission selection, allowing you to choose the mission that's right for you!": "选择任务时你可以根据星球上的昼夜区域挑选合适的任务!", + "Motion Sensor Steadying Amount": "动态感测器稳定量", + "Unhappy with who you are? Change your appearance and voice in the customization chamber. It's that easy!": "想要改变自己?前往自定义房间,更改外貌和声音。一切就是那么简单!", + "Display Surveys": "显示调查", + "Select the visibility of teammate direction during gameplay.": "选择游戏中的队友方位可视度。", + "CROSS-PLATFORM COMPATIBILITY": "跨平台兼容", + "Drop Wheel Visibility": "弃置轮盘可视度", + "Increases ammo for all Sentry stratagems by #VALUE%.": "所有哨戒炮战略配备的弹药量增加#VALUE%。", + "Max Frame Rate": "最大帧率", + "Super Earth Ministry of Truth": "超级地球真理部", + "Here, citizens in well-insulated worksuits operate facilities liberated from the Automatons, and repurposed to sustainably extract rare materials from the highly volcanic planet.": "在这里,身着强隔热工作服的公民操作着从机器人手中解放出来的设施。这些设施经过改造,能够在这颗火山活动频繁的星球上可持续地开采稀有资源。", + "AVAILABLE AT LEVEL #RANK": "达到级别#RANK时开放", + "PLAYER CARD": "玩家名片", + "Super Earth thanks you for your generous support of Managed Democracy.": "超级地球感谢你对管理式民主的慷慨支援。", + "INTEGRATED EXTINGUISHERS": "集成灭火器", + "DONATION LIMIT REACHED": "已达到捐赠上限", + "It will feel like you're out there, fighting beside them from your home!": "你会感觉虽然身在家中,心却在前线和他们并肩作战!", + "PER WEAPON": "视武器而异", + "Teammate Direction Visibility": "队友方位可视度", + "HUD HIDDEN": "隐藏HUD", + "Stratagem Permit": "战略配备许可证", + "Inverts up and down control of mouse direction.": "鼠标上下方向翻转。", + "Use the Eagle Rearm stratagem during calmer periods to ensure you have those Eagle Strikes available when you need them.": "在比较空闲的时段使用重新武装“飞鹰”的战略配备,可以确保关键时刻你能呼叫“飞鹰”空袭。", + "ADVANCED": "高级", + "DONE": "已完成", + "GLOOM RESEARCH EXPEDITION": "“阴霾”研究考察", + "Optimizes the audio experience for the device you are listening on.": "优化你使用的音频设备的听觉体验。", + "Don't drink and drive.": "喝酒不开船。", + "StarfQtr_97": "星战之_97", + "BALANCED": "平衡", + "OWNED": "已拥有", + "SWITCH CAMERA SIDE": "视角换边", + "Mouse Scope Sensitivity": "鼠标开镜灵敏度", + "LOW": "低", + "Vegetation and Rubble Density": "植被与碎石密度", + "ATMOSPHERIC MONITORING": "大气监测", + "MAP ONLY": "仅在地图显示", + "ADVANCED CONSTRUCTION": "高级构造", + "EMERGENCY LIGHTS": "应急照明", + "WEAPONRY": "武器", + "Stamina Visibility": "耐力槽可视度", + "Authorizes an 8-week crew training course in Superior Packing Methodology (SPM), resulting in increased supply box capacity.": "授权开展为期8周的高级装填法(SPM)船员培训课程,从而提高补给箱容量。", + "Offensive - Discrimination": "冒犯性 - 歧视", + "DrSpindleshanks": "长腿博士", + "Eagle Rearm cooldown further reduced by #VALUE% if called in while Eagle uses still remain.": "在“飞鹰”仍有使用次数时,如果呼叫“飞鹰”,重新武装的冷却时间缩短#VALUE%。", + "Select the level of quality for particle effects.": "选择粒子效果的质量等级。", + "When on, automatically adjusts render resolution to achieve target framerate.": "开启后将自动调整渲染分辨率以达到目标帧率。", + "Interaction Visibility": "互动可视度", + "NORSK (Unsupported)": "NORSK (Unsupported)", + "DEUTSCH": "DEUTSCH", + "FRIENDS": "好友", + "Reduces the dynamic range of in-game audio. Beneficial if you are listening at a low volume, quiet sounds become louder.": "缩小游戏内音频的动态范围。有利于低音量的玩家,因为较轻的声音会变响。", + "GRENADE BANDOLIERS": "榴弹背带", + "Enemy resistance on this Hive World is lowered.": "这个虫窝世界的敌军抵抗强度降低。", + "E-711 EXTRACTION FACILITY": "711元素开采设施", + "Language": "语言", + "PORTUGUÊS (PT)": "PORTUGUÊS (PT)", + "Reduces damage falloff from center of explosions caused by orbital Stratagems.": "轨道战略配备引爆后从中心向外扩散的伤害衰减有所下降。", + "Nov": "11月", + "On this planet is one of 3 Maximum Security Cities: impregnable bastions against Tyranny.": "三大最高安全级别城市之一坐落在这颗星球上:这是对抗暴政的堡垒,坚不可摧。", + "Installs a revolving cylinder loading system, with each chamber housing a different ammunition type.": "安装旋转弹巢装填系统,每一个弹膛都装载一种不同的弹药。", + "Target Framerate": "目标帧率", + "150 SC": "150超级货币", + "Trigger Effect Strength": "扳机效果强度", + "Graphics API": "图形API", + "MENU": "菜单", + "HUB OF INDETERMINATE PURPOSE": "用途不明的中心", + "CHAT ONLY": "仅聊天", + "WEAK": "弱", + "Pending...": "正在等待…", + "EXTREME TEMPERATURE EXTRACTION PLANT": "极温开采厂", + "SPECTATE PREVIOUS": "观战上一个玩家", + "UNLINK": "解除绑定", + "SHIP PROGRESSION": "舰船进度", + "PREVIEW WEAPON": "预览武器", + "BODY ARMOR": "躯体盔甲", + "This setting modifies the resolution of the volumetric clouds to render a more realistic sky.": "该设置可调整体积云的分辨率,进而渲染出更逼真的天空。", + "Fills cockpits with breathable liquid perfluorocarbons, which absorb g-forces and thereby enable pilots to conduct tighter turns without losing consciousness.": "在驾驶舱内填充可呼吸的液态全氟化碳,以便吸收重力,使驾驶员能够完成更急促的转向且不会失去知觉。", + "OUTGOING ONLY": "仅输出", + "INSUFFICIENT SUPER CREDITS": "超级货币不足", + "ARMED RESUPPLY PODS": "武装重新补给舱", + "Augments electrical weaponry by safely connecting multiple interior arc extenders into one long linear chain.": "可通过安全方式将多个内部电弧扩展器连接成线性长链,起到增强电子武器威力的作用。", + "This planet appears to have been monstrously transformed by the Terminids. It may be a source of Gloom spores. Exercise caution.": "这颗星球似乎遭到了终结族骇人的改造。有可能变成“阴霾”孢子的来源。务必小心行事。", + "Adjusts how quickly acceleration is applied to the wireless controller camera control. If set to zero, the movement is linear.": "调整无线控制器操控视角的加速生效速度。设置为零则视角线性移动。", + "OPEN CHAT": "开启聊天", + "DYNAMIC TRACKING": "动态追踪", + "Flexible Reinforcement Budget": "灵活增援预算", + "Vitality Enhancement": "生命力强化", + "The account link failed, please try again.": "账户绑定失败,请重试", + "Check your Ammo by holding the Reload button.": "按住装填弹药按钮查看弹药数量。", + "NUCLEAR RADAR": "核动力雷达", + "Text To Speech": "文字转语音", + "QUICK THROWABLE": "快速投掷武器", + "WEAPON FUNCTION 2": "武器功能2", + "High Dynamic Range": "高动态范围", + "The facilities on this planet help the Illuminate turn citizens into Voteless.": "光能者在这颗星球上利用这类设施将公民转化为无票者。", + "Copyright": "版权", + "ALWAYS": "常驻", + "On this planet, the Ministry of Science’s best and brightest work on their next breakthrough.": "在此星球上,科学部的顶尖人才正在全力推动下一项突破。", + "Remember to fill in your C-01 permit before any act that could result in a child.": "进行可能产生孩子的行为之前,记得先填好C-1授权表格。", + "TARGETING SOFTWARE UPGRADE": "目标瞄准软件升级", + "UNBIND INPUT": "解绑键位", + "#DAYS Days Left": "还剩#DAYS天", + "XENOENTOMOLOGY CENTER (DESTROYED)": "异星昆虫学研究中心(遗址)", + "AVAILABLE IN: #HOURS h #MINUTES m": "就位倒计时:#HOURS小时#MINUTES分", + "PAYROLL MANAGEMENT SYSTEM": "薪金管理系统", + "RESET CAMERA LOOK": "重置视角", + "When the mission timer runs out, the Super Destroyer will leave low orbit and you'll lose access to stratagems and reinforcements.": "任务倒计时结束后,超级驱逐舰就会离开低空轨道。之后,你无法再使用战略配备,也无法呼叫增援。", + "Enable High Dynamic Range (HDR) to your monitor or TV. This can only be enabled on supported devices.": "在你的显示器或电视上启用高动态范围(HDR)。受支持的设备才能启用此设置。", + "STEAM DECK™": "STEAM DECK™", + "DONATION SUCCESSFUL": "捐赠成功", + "LONG PRESS": "长按", + "A limited-time expedition is being conducted into the Gloom on this planet, at significant cost.": "该星球上正在开展限时“阴霾”探索行动,代价巨大。", + "SUPER GLOOM BASE BRAVO": "超级“阴霾”布拉沃基地", + "Acceleration Exponent": "加速指数", + "Scan the QR code or press the button below to begin linking your accounts from Steam and PlayStation™Network": "扫描二维码或按下方按键即可开始将你的Steam账户与PlayStation™Network账户绑定", + "Increased Reinforcement Budget": "提高增援预算", + "ADVANCED GRAPHICS": "高级图像", + "Motion Sensor Steadying Transition Duration": "动态感测器稳定过渡持续时间", + "Screen-Space Reflections": "屏幕空间反射", + "ADVANCED SETTINGS": "高级设置", + "SUPERSAMPLING": "超级采样", + "All Sentry stratagems launch immediately once called in, reducing overall deployment time.": "所有哨戒炮战略配备在呼叫后即时发射,缩短整体部署时间。", + "Reloading...": "正在装弹……", + "#COUNT BONUS SC": "#COUNT额外超级货币", + "JOG": "小跑", + "Sample Count Visibility": "样本数量可视度", + "NO SPECIAL TRAITS": "无特殊特性", + "DLSS": "DLSS", + "The Ministry of Prosperity manages Super Earth's economy and ensures a steady flow of resources to the most deserving.": "繁荣部负责管理超级地球的经济,确保资源能够源源不断地流往最有价值的地方。", + "RAPID LAUNCH SYSTEM": "疾速发射系统", + "Integrates moderate doses of amphetamines and androgenic steroids into diet of loading crew, leading to increased pace, focus, & stamina, among other effects.": "将适量安非他明和雄激素类固醇加入船员的饮食中,获得各方面的提升效果,包括速度、专注力和耐力等。", + "Player Marker Visibility": "玩家标记可视度", + "No friends, yet.": "暂时还没有好友。", + "On this planet, workers are constructing one of 3 Maximum Security Cities: impregnable bastions against Tyranny.": "工人正在这颗星球上建设三大最高安全级别城市的其中一座:这是对抗暴政的堡垒,坚不可摧。", + "x_Roocketman_x": "x_火箭新手_x", + "Object Detail Quality": "物体细节质量", + "FSR4": "FSR4", + "The Super Store is currently undergoing maintenance, and is unavailable. Please try again later. Thank you for your understanding.": "超级商店正在进行维护,暂时无法使用。请稍后再试。感谢你的理解。", + "COMBAT": "战斗", + "HIGHLIGHT": "高亮", + "OUTPOST ALPHA": "阿尔法哨站", + "Text Language": "文本语言", + "B1qBeefEater": "大囗吃牛肉", + "Resupply Stratagem boxes refill Support Weapons with the maximum number of carriable magazines.": "“重新补给”战略配备的补给箱为支援武器补充的可携带弹匣数增加至最大数量。", + "OPEN EMOTE WHEEL": "打开表情轮盘", + "Good for stealth. Bad for enemy.": "潜行好助手。敌人的噩梦。", + "NO BOOSTER": "无强化资源", + "Borderless Window": "无边框窗口", + "Failed to block player.": "未能屏蔽玩家。", + "Inappropriate Online ID": "不得体的在线ID", + "STAY": "原地待命", + "NORMAL": "普通", + "PRIMARY WEAPON": "主要武器", + "QUICK WEAPON WHEEL UP": "快速向上转动武器轮盘", + "Select the width of the compass.": "选择罗盘宽度。", + "Frame buffering": "帧缓冲", + "CHANGE CAMERA MODE": "更改视角模式", + "I bought this for my husband and he loves it.": "我给我老公买了这个东西,他非常满意。", + "December": "12月", + "Reduces call-in time for all orbital stratagems by#VALUE seconds.": "所有轨道武器战略配备的呼叫时间缩短#VALUE秒。", + "OPEN STRATAGEM LIST": "打开战略配备列表", + "NEW ASPIRATION CONSTRUCTION SITE": "志向新城建造区", + "POLSKI": "POLSKI", + "XENOENTOMOLOGY CENTER": "异星昆虫学研究中心", + "Increases number of Eagle stratagem uses per Rearm by #VALUE.": "每次重新武装后,“飞鹰”战略配备的可使用次数增加#VALUE次。", + "DROP BACKPACK": "放下背包", + "Invert Mouse (Vertical)": "鼠标翻转(垂直)", + "Mouse Acceleration": "鼠标加速", + "DYNAMIC": "动态", + "SWITCH AIM SIDE": "瞄准换边", + "Unable to authenticate your account on PlayStation™Network, please try again later or contact support if this error persists.": "无法验证你的PlayStation™Network账号,请稍后重试。如果问题仍未解决,请联系客服。", + "Default": "默认", + "Great for camping trips with the kids! A bit heavy for them though.": "很适合跟孩子野营的时候用!虽然对他们来说稍微有点重了。", + "SKIP DIALOGUE": "跳过对话", + "Bugs": "虫族", + "INSUFFICIENT FUNDS": "资源不足", + "Inverts left and right of camera direction in First Person View (FPV).": "在第一人称视角(FPV)下,视角左右方向翻转。", + "The player has no messages in the chat so they cannot be reported. You can take any of the following actions instead.": "这位玩家没有在聊天中发送消息,无法举报。你可以另行选择下列操作。", + "INVITE TO SQUAD": "邀请入队", + "CURRENT CUSTOMIZATION": "当前自定义", + "Remember Weapon Functions": "记住武器功能", + "Account Not Linked": "未绑定账户", + "If the problem persist contact support.": "如果问题仍未解决,请联系客服。", + "I already own one but I bought it again to support our heroes out there!": "我已经有一件了,但为了支持前线的英雄,我又买了一件!", + "Ship Module": "舰船模块", + "SUB-OBJECTIVE": "次要目标", + "1,500 SC": "1,500超级货币", + "DROP NEXT INVENTORY ITEM": "放下下一件物品", + "TAA": "TAA", + "Localization Confusion": "定位混淆", + "ARMOR PASSIVE": "盔甲被动加成", + "Hellpod Space Optimization": "绝地喷射舱空间优化", + "The DSS Logistics Armada supplies all Super Destroyers orbiting the planet with surplus 380mm shells. Ordnance support is also provided to SEAF operations, accelerating liberation efforts.": "民主空间站后勤舰队为环绕星球的各艘超级驱逐舰提供富余的380mm爆弹。超级地球武装部队的行动也将获得军械支援,从而加速解放进程。", + "You can tell by just touching it, that this was made for real heroes.": "摸一摸就能感觉到这是给真英雄打造的。", + "Faction": "阵营", + "LARGE": "大", + "PLAYER INTERACTION": "玩家互动", + "SHIP MODULE UNLOCKED": "舰船模块已解锁", + "Weapons like pistols and submachine guns can be used with one hand—perfect for when you need to carry objects in the other hand.": "手枪和冲锋枪等武器是可以单手使用的,非常适合在另一只手执物体时使用。", + "BAHASA INDONESIAN (Unsupported)": "BAHASA INDONESIAN (Unsupported)", + "Select the resolution of textures. Higher settings provide more detail at the cost of memory (VRAM) and performance. This is the primary setting to adjust on devices with lower than recommended VRAM. Recommended VRAM for each setting:\nUltra - 10GB\nHigh - 8GB\nMedium - 6GB\nLow - 3GB": "选择贴图分辨率。较高的选项可以提供更加细致的图像,但是会占用显存(VRAM),影响性能。在VRAM未达到推荐值的设备上,这是首先需要调整的设置选项。各项设置推荐VRAM:\n超高 - 10GB\n高 - 8GB\n适中 - 6GB\n低 - 3GB", + "Screen Device": "屏幕设备", + "Linking your Steam account to a PlayStation™Network account is required for playing the game.": "如需游玩该游戏,请将你的Steam账户与PlayStation™Network账户绑定。", + "Bloom Strength": "全屏泛光强度", + "The threshold at which the cursor movements stop increasing in speed.": "光标停止提高移动速度的阈值。", + "October": "10月", + "UNLIMITED": "无限", + "All": "全部", + "Available in: #HOURS h #MINUTES m": "就位倒计时:#HOURS小时#MINUTES分", + "Review under investigation for treason": "该评论涉嫌叛国,正在接受调查", + "Vehicle Action Wheel Visibility": "载具行动轮盘可视度", + "TITLE": "头衔", + "Isolated Exostorm pockets are materializing across the planet and rapidly gaining momentum.": "多个异界风暴区分别在星球各地出现,迅速积聚势头。", + "BODY TYPE": "体型", + "OPEN BACK HATCH": "打开后盖", + "REMOVE FRIEND": "移除好友", + "LIQUID-VENTILATED COCKPIT": "液态通风驾驶舱", + "Aug": "8月", + "M0o0ns22": "月月欲试22", + "Estimated time until ready: #DAYS d #HOURS h": "预计准备时间:#DAYS天#HOURS小时", + "RADIAL MENU UP": "圆盘菜单上", + "The closer you are to the edge of the map, the steeper the angle of incoming orbital bombardments. Physics!": "你越接近地图边缘,轨道轰炸的角度就越高。这就是物理!", + "DANSK (Unsupported)": "DANSK (Unsupported)", + "This player is currently your friend on PC, Xbox and/or PlayStation™Network. They must be removed from your friends list on those services before they can be removed from your in-game friend list.": "该玩家目前是您的PC、Xbox和/或PlayStation™Network好友,必须先将其从这些服务平台的好友列表中删除,然后才能从游戏内的好友列表删除该玩家。", + "Health Visibility": "生命值可视度", + "Depth of Field": "景深", + "While in reverse, braking input will throttle, and throttling will brake.": "倒车时,刹车变油门,油门变刹车。", + "CENTER FOR CIVILIAN SURVEILLANCE AND SAFETY": "公民监控和安全中心", + "Speech To Text": "语音转文字", + "#READY MB/#TOTAL MB - #PERCENTAGE % complete\nTime Remaining: #SECONDS s": "#READY MB/#TOTAL MB - 已完成#PERCENTAGE%\n剩余时间:#SECONDS秒", + "LOOK DOWN": "向下看", + "Choose in what context subtitles are displayed.": "选择在哪些情况下显示字幕。", + "E-711 WELLSPRING": "711元素之源", + "REMOVE FROM FAVORITES": "取消收藏", + "Your Steam and PSN accounts are now linked.": "你的Steam和PSN账户现已绑定", + "Data Collection": "数据收集", + "Being prone makes you less susceptible to explosions. When in imminent danger, dive!": "扑倒在地可以躲避爆炸。面对迫在眉睫的危险,记得及时闪躲!", + "Hellpod deployment tips are a collaboration of the Ministry of Defense and Ministry of Truth.": "绝地喷射舱的部署技巧由国防部和真理部联合编写。", + "SYNTHETIC SUPPLEMENTATION": "合成补给", + "HANDBRAKE": "手刹", + "CURRENT MAJOR ORDER": "当前重要指令", + "STREAMLINED LAUNCH PROCESS": "简化发射流程", + "ENHANCED COMBUSTION": "强化燃烧", + "NEW YEARNING CONSTRUCTION SITE": "盛盼新城建造区", + "WHAT DO WE USE GAME DATA FOR?": "我们使用游戏数据的目的是什么?", + "Select the visibility of player nameplates during gameplay.": "选择游戏过程中的玩家名牌可视度。", + "15x100mm TOXIC": "15x100mm毒弹", + "B-22 MODEL CITIZEN": "B-22“模范公民”", + "COOKOUT": "野炊", + "AC-8": "AC-8", + "Incendiary Mines": "燃烧地雷", + "A throwable anti-personnel mine, capable of adhering to most surfaces. Upon deployment, emits lights and sounds which attract nearby hostiles to its proximity-activated detonator.": "可投掷式反步兵地雷,能附着在大部分表面。部署后发出光和声音,吸引附近敌人靠近它的感应引爆装置。", + "G-109": "G-109", + "Combat Engineer": "战斗工兵", + "NO UNDERBARREL": "无下挂", + "Faster Lock-On Time": "缩短锁定目标用时", + "Holographic Sight": "全息瞄准镜", + "STUN TIME": "眩晕时间", + "SLUGGER": "重炮手", + "Capable of firing a suite of space-to-ground indirect fire that can quickly free an entire battlefield from oppression.": "能发射一组空对地间接火力,快速解救整个受到压制的战场。", + "Engineering Bay": "工程港", + "PROTECTOR OF THE HEART": "民主之心捍卫者", + "Larger Gatling Magazine": "扩容加特林弹匣", + "OUTER RADIUS": "外半径", + "THUMB OF APPROVAL": "赞许之指", + "Commemorating the bold pioneers who first successfully navigated High Command’s newest tactical mechanisms. The distinctive replication of visor scarring represents a close-range ideological exchange with the Terminid scourge, proving that Managed Democracy shall remain unblinded by fascist aggression.": "旨在纪念那些最先成功驾驭最高指挥部最新战术机制的英勇先驱。头盔面甲疤痕的独特复刻,代表着与终结族毒瘤进行近距离意识形态交锋,彰显管理式民主绝不会被法西斯侵略蒙蔽双眼。", + "110mm E.M.S. CANNON ROUND": "110mm电磁冲击波炮弹", + "MORE DAMAGE": "提高伤害", + "LONGER GRENADE BELT": "加长榴弹腰带", + "SG-8": "SG-8", + "BRAWNY": "健壮", + "Heel Kick": "踢踏步", + "12g FLECHETTE SHELLS": "12g飞镖霰弹", + "EX-00 Prototype X": "EX-00“原型X”", + "500kg Bomb Mk2": "500KG炸弹 MK2", + "THUMPER": "桩锤", + "5.5x50mm Ripper": "5.5x50mm撕裂弹", + "Pushing the boundaries of bionic engineering, this armor collects and dispenses a number of vital fluids, several of which are soon to be declassified.": "这套盔甲突破了仿生工程学的极限,能收集并分配多种重要体液,其中几种即将解密。", + "MULTI-LAUNCH PROTOCOL": "多管发射协议", + "Standby": "随时待命", + "40MM HE": "40mm高爆弹", + "Sidearm draw/holster speed increased by #BONUS.": "副武器拔枪/收枪速度提高#BONUS。", + "CM-21 Trench Paramedic": "CM-21“战壕护理员”", + "IMPROVED ROUNDS": "改良弹药", + "R-63": "R-63", + "GS-17 FRONTIER MARSHAL": "GS-17“边境元帅”", + "[REDACTED]": "[已涂黑]", + "CPR-80 BULWARK": "CPR-80 “壁垒”", + "Armor explodes #BONUS after the wearer dies.": "盔甲会在穿戴者死后#BONUS引爆。", + "85mm Armor-Piercing Grenade": "85mm穿甲榴弹", + "HMG Emplacement": "重机枪部署支架", + "B-22 Model Citizen": "B-22“模范公民”", + "INCREASED STORAGE": "可携带数量升级", + "VERY SHORT": "非常短", + "A welcome sight in all Democratic neighborhoods, this armor inspires both civil pride and civic obedience.": "这款盔甲在所有民主社区都备受欢迎,既能激发公民自豪感,又能促进公民服从命令。", + "NAPALM BOMB MK2": "凝固汽油弹 MK2", + "Natural Gas Extraction": "提炼天然气", + "AMMUNITION OPTIMIZATION": "弹药优化", + "Expanded Bomb Racks": "扩展炸弹挂架", + "40-K": "40-K", + "COMMANDO": "突击兵", + "G/40-K": "G/40-K", + "500kg Bomb Mk3": "500KG炸弹 MK3", + "This ancient, likely allegorical, illustration of Might triumphing over the Anguiform is seen by scholars as a symbol of humankind's supremacy in the art of violence.": "这幅可能深藏寓意的古老插图描绘了力量战胜蛇形生物的场景,学者认为这象征着人类在暴力艺术的至高地位。", + "10-STAR GENERAL": "十星将军", + "HYENA": "鬣狗", + "Based on the uniform of Jackle 6, a veteran of the Viper Commandos who held off an entire Terminid brood on Nublaria in the First Galactic War with nothing but a machine gun, pocket knife, and Orbital Laser Strikes.": "以毒蛇突击队老兵“杰克尔六号”的制服为基础设计而成。第一次星系战争期间,这位老兵仅凭机枪、小刀和轨道激光炮就拦下了努布拉里亚的整支终结族大军。", + "15x100mm Toxic": "15x100mm毒弹", + "Increases melee damage by #BONUS.": "近战伤害提高#BONUS。", + "Large Ammo-Drum": "大容量弹鼓", + "PROSPECTING DRILL": "勘探钻机", + "An advanced, mostly self-operating prospecting drill fitted into a Hellpod. Handles soil sample extraction, analysis and data upload with minimal necessary input from an operator.": "一款安装在绝地喷射舱内的先进自动操作勘探钻机。操作员只需手动完成最基本的操作,钻机就能处理土壤样本提取、分析和数据上传的工作。", + "The horrors of Tyranny are manifold, their minions many, but they are naught before Democracy's twin swords: overwhelming firepower, and those trained elite who unquestioningly wield it.": "暴政恐怖千变万化且爪牙众多,但对于民主的“雌雄双剑”——压制性火力以及训练有素、坚定驾驭这股力量的精英而言,一切皆不足为惧。", + "Crew Training": "船员训练", + "MORE AUTOCANNON TURRET AMMO": "增加机炮炮台弹药数", + "Hellbomb": "地狱火炸弹", + "85mm High-Explosive Grenade Mk2": "85mm高爆榴弹 MK2", + "A domestic version of this armor is available for citizens who wish to perform efficient home renovation projects.": "希望提高住宅装修效率的公民可以购买这套盔甲的家用版本。", + "No muzzle attachment.": "无枪口配件。", + "Boxer": "拳击手", + "A lightly-armored Fast Recon Vehicle mounted with a heavy machinegun.": "轻型装甲快速侦察载具,搭载重机枪。", + "A longer revolver barrel that results in a higher muzzle velocity and lower recoil at the cost of worse handling.": "加长版左轮枪管,可有效提升枪口初速并降低后坐力,代价是操控性下降。", + "Orbital Gas Round Mk2": "轨道毒气弹 Mk2", + "SUPER CITIZEN": "超级公民", + "BOLT PISTOL": "爆弹手枪", + "TIER #TIER UPGRADES": "#TIER阶升级项目", + "DE-FORESTER'S SAILCLOTH": "伐木工帆布", + "A powerful dual magazine pump-action shotgun, with limited armor penetration. Ideal for small and fast targets.": "强大的双弹夹泵动式霰弹枪,穿甲力有限,这是攻击小型和快速目标的理想之选。", + "A single-use weapon firing a high-yield missile. Discarded after every use.": "发射大当量导弹的一次性武器。用后即弃。", + "SUPPRESSOR": "消音器", + "CONCUSSIVE PADDING, GRENADIER": "防震内衬(掷弹兵型)", + "15x100mm Plasma": "15x100mm等离子弹", + "SERVO-ASSISTED": "伺服辅助", + "KDM-73 DRAGOON": "KDM-73“龙骑兵”", + "This armor pays tribute to the immoveable heroes of the front line—those who refuse to acknowledge incoming fire, and consider \"dodging\" to be an abstract concept akin to cowardice.": "这套盔甲旨在致敬那些岿然不动的前线英雄——他们毫不畏惧来袭火力,并将“闪避”视为与怯懦无异的抽象概念。", + "Triangulation Veil": "三角定位披纱", + "A high-caliber submachine gun which can be fired with one hand. Has a relatively low rate of fire.": "可单手操控的大口径冲锋枪。射速相对较低。", + "An automated turret with an extremely high rate of fire. Caution: does not check if friendly units are in line of fire.": "射速极其高的自动炮台。当心:炮台不会侦测火线内是否存在友方单位。", + "Redeemer": "救世主", + "Breaker Nailspitter": "尖钉喷射“破裂者”", + "Singe": "焦痕", + "15x100mm HIGH EXPLOSIVE": "15x100mm高爆弹", + "SEAF ARTILLERY: SMOKE": "超级地球武装部队大炮:烟雾弹", + "REPRIMAND": "训斥", + "Protector of the Heart": "民主之心捍卫者", + "CRISPER": "迅击", + "Helps prevent Helldivers from flinching when hit.": "有助于防止绝地潜兵遭受攻击后产生畏缩反应。", + "HELLDIVER": "绝地潜兵", + "MARK OF THE CONSTRICTOR": "缚暴印记", + "VERDICT": "裁决", + "TG-8 Sharpshooter": "TG-8“神枪手”", + "Truth Whisperer": "真理低诉者", + "Loaded with jet-assisted rounds, this pistol is calibrated for creating and maintaining tactical distance from encroaching hostiles.": "这款手枪装填喷气助推弹,经过特别校准,可在敌人逼近时与其保持战术距离。", + "Speargun": "矛枪", + "Improved Ammo Storage": "弹药存储量升级", + "A heavy-duty submachine gun that fires large-caliber rounds, with a slower rate of fire to manage the high recoil. Ideal for use at close to medium range.": "重型冲锋枪,可发射大口径子弹,但由于后坐力较大,射速较慢。适合中近距离使用。", + "Orbital Gas Strike": "轨道毒气攻击", + "TRAINING MANEUVERS": "军事演习", + "Orbital Laser": "轨道激光炮", + "M-105": "M-105", + "Emancipator Exosuit": "“解放者”外骨骼装甲", + "A high-damage revolver, which can be reloaded with single rounds. A heavy-hitting and reliable sidearm.": "伤害较高的左轮手枪,可以装填单发弹药。此随身武器攻击力强大,相当可靠。", + "75mm HEAT Grenade": "75mm高爆反坦克榴弹", + "Orbital Precision Strike": "轨道精准攻击", + "A stationary ballistic cover with a mounted grenade launcher. Can protect multiple Helldivers from small arms fire.": "固定式防弹掩体,架设有榴弹发射器。可抵挡轻型武器的射击,保护多名绝地潜兵。", + "This cape depicts the inner workings of a medical device submitted to the Ministry of Science 70 years ago, and is bound to clear their patent approval process any day now.": "这件披肩绘制了70年前提交到科学部的医疗设备内部构造,相信很快就能通过专利审批流程了。", + "Increases the speed and duration of slides.": "可提升滑铲的速度与持续时间。", + "This high-visibility armor allows it's bearer to be easily seen through smoke, fog, and spewing viscera.": "穿上这套可见度极高的盔甲,缭绕烟雾和喷溅的内脏都挡不住你的风采。", + "GUNNER FRV": "炮手快速侦察载具", + "The experimental weapons R&D corporation Zizer has unveiled this altered \"Senator\" revolver, with a longer barrel that is clinically proven to make its wielder up to 23% more secure in themselves.": "实验性武器研发企业“自捷”推出改装版“参议员”左轮手枪,配备加长枪管,经临床验证可为使用者带来多达23%的自信心加成。", + "A common magazine type in the Super Earth military, favoring sustained fire over handling.": "超级地球军队常用弹匣,适合持续提供火力,但操控性较差。", + "AR-23P": "AR-23P", + "4x COMBAT SCOPE": "4倍战斗瞄准镜", + "KINETIC DISPLACEMENT MITIGATION": "动能位移减缓", + "HOMING GROUND MISSILE": "追踪式地面导弹", + "PUMMELER": "暴击斗士", + "GRENADE STATS": "榴弹数据", + "8x60mm DOUBLE POWER": "8x60mm双效子弹", + "SOLICIT TRANSPORTATION": "请求运输", + "EXTRA CAPACITY": "额外容量", + "Shorter Cooldown": "冷却用时缩短", + "9x70mm Socom Assassin": "9x70mm“刺客”特种作战弹", + "SALVOS": "齐射", + "IMPROVED PROJECTILES": "改良射弹", + "Hover Pack": "悬浮背包", + "PRESENTABLE": "像模像样", + "5.5x50mm HIGH VELOCITY": "5.5x50mm高速弹", + "Red Planet's Memory": "红星回忆", + "This suit's plutonium-238 nuclear battery enables environmental scanning long after the user has ceased operation.": "这套服装配备钚238核能电池,在穿戴者失去体征很长时间之后,电池依然能支撑设备完成环境扫描。", + "Loyalist": "忠诚者", + "AR-23A": "AR-23A", + "Stalwart": "盟友", + "Podium of Prosperity": "繁荣领奖台", + "IMPROVED AIMING SERVOS": "改良瞄准伺服系统", + "ROCK-SOLID": "坚如磐石", + "THE CAPE OF STARS AND SUFFRAGE": "群星与选举之披肩", + "100kg Bomb Mk3": "100KG炸弹 MK3", + "HIVE SCANNER": "虫窝扫描仪", + "MANUAL TARGETING": "手动锁定目标", + "SIGNAL: GROUP UP": "信号:集合", + "P-11": "P-11", + "Senator": "参议员", + "G-8": "G-8", + "First deployed in the mines of Cyberstan, where it offered protection against explosions in the hydrogen-rich caverns.": "最初投用于生化斯坦的矿区,帮助穿戴者在富含氢气的矿洞中抵挡爆炸的伤害。", + "CM-17 Butcher": "CM-17“屠夫”", + "PREPARED CRATES": "预备弹药箱", + "W.A.S.P. LAUNCHER BACKPACK": "W.A.S.P.发射器背包", + "This cape celebrates the one Veridical Ideology—Managed Democracy—a truth so self-evident, it requires no proof beyond the unwavering obedience of its champions.": "披肩颂扬唯一的真理意识形态:管理式民主。此中真理不言自明,也无需证明,只需要拥护者绝对服从。", + "INCREASED SHIELD POWER": "提升护盾能量", + "EAGLE'S FURY": "飞鹰之怒", + "Further reduces recoil when crouching or prone by #BONUS.": "蹲伏或匍匐姿态下,后坐力进一步降低#BONUS。", + "8x60mm HIGH VELOCITY": "8x60mm高速弹", + "INGRESS-81": "进军-81", + "P-33": "P-33", + "12x25mm HOLLOW POINT": "12x25mm空尖弹", + "SA-32 Dynamo": "SA-32“精力充沛”", + "Provides #BONUS damage resistance to fire, allowing bearer to rest assured in their inflammability.": "提供#BONUS的火焰伤害抗性,穿戴者无需再担心自身的易燃问题。", + "EYE OF THE CLANDESTINE": "隐匿之眼", + "12g SCATTER SHOT": "12g散射弹", + "Mortar Sentry": "迫击哨戒炮", + "BIG STRETCH": "用力舒展", + "Immediate Auto Loader": "即时自动装填", + "AF-52 Lockdown": "AF-52“禁锢”", + "Improved Ammunition Feed": "改良供弹系统", + "Disarmingly scrappy and viciously disarming, this armor is a staple of the Balayage FW/2185 collection \"Frontline Moxie\".": "这盔甲看起来破烂,令人放下戒心,实则凶悍得让敌人缴械投降。这套盔甲是巴拉雅奇2185秋冬系列“前线胆魄”的经典款式。", + "AR-20L": "AR-20L", + "An autonomous drone equipped with a flamethrower. Returns to backpack to refill fuel canisters.": "配备火焰喷射器的自主无人机。收回到背包可补充燃料罐。", + "Wings of Valor": "勇气之翼", + "EX-03 Prototype 3": "EX-03“原型 3”", + "KNIGHT": "骑士", + "Reflex Sight Mk2": "反射式瞄准镜Mk2", + "20mm APHET Rounds": "20mm穿甲高爆曳光弹", + "380mm HE Cannon Round": "380mm高爆炮弹", + "GUNSLINGER": "神枪手", + "Thermite": "铝热弹", + "LIBERATOR CARBINE": "“解放者”卡宾枪", + "HEAT MK2": "高爆反坦克榴弹 MK2", + "This Data Jack is carefully engineered to slot seamlessly into Illuminate Access Nodes. Once engaged, it initiates a sophisticated system disruption sequence, requiring little more than user confirmation.": "这个精心设计的数据接口可完美插入光能者的接入节点。一旦成功对接,就会发起复杂的系统破坏程序,几乎仅需用户确认即可完成。", + "ORBITAL WALKING BARRAGE": "轨道游走火力网", + "TALON": "猛爪", + "MANNED": "载人", + "SEISMIC PROBE": "地震探测仪", + "A turret which fires electrical charges at targets in close range. To avoid friendly fire, remain prone.": "向近程目标释放电击的炮台。为避免误伤,请保持匍匐姿势。", + "70mm LASER-GUIDED MISSILE MK2": "70mm激光制导导弹 MK2", + "A high-caliber sniper rifle effective over long distances against light vehicle armor. This rifle must be aimed downscope.": "大口径狙击步枪,在远程范围内可有效对付轻型载具装甲。此步枪必须开镜瞄准。", + "110mm Gas Cannon Round Mk3": "110mm毒气炮弹 MK3", + "LIGHTENED CASING": "轻薄弹壳", + "Offering camouflage in snowy environments, surplus sets of this armor are used by nature photographers and keen hunters alike.": "适用于雪地环境的迷彩,富余的盔甲在户外摄影师和打猎爱好者手中也相当实用。", + "Fre Liberam": "求自由", + "IMPROVED RECOIL": "改善后座力", + "Draw!": "拔枪!", + "Promotional armor made by SUMY Corp. as part of a highly successful marketing campaign for frozen yogurt.": "SUMY公司制作的促销盔甲,是大获成功的冷冻酸奶营销策略的一部分。", + "KDM-500 Outrider": "KDM-500“先驱骑兵”", + "Tech Specialist": "技术专家", + "FREEDOM'S TAPESTRY": "自由织锦", + "110mm GAS CANNON ROUND MK2": "110mm毒气炮弹 MK2", + "PUNISHER": "制裁者", + "13x40mm Ripper": "13x40mm撕裂弹", + "10g Fragmentation": "10g破片弹", + "Increases reload speed of support weapons by #BONUS.": "支援武器的装弹速度提高#BONUS。", + "Additional Rocket Pods": "附加火箭巢", + "Anti-Personnel Minefield": "反步兵雷区", + "10g Buckshot Shells": "10g鹿弹霰弹", + "CW-4 Arctic Ranger": "CW-4“极地游骑兵”", + "9x70mm SELF PROPELLED": "9x70mm自走弹", + "RANDOM": "随机", + "10x Sniper Scope": "10倍狙击瞄准镜", + "Dab": "嘻哈超人舞", + "Liberty's Herald": "解放预兆", + "No underbarrel attachment.": "无下挂配件。", + "MAXIGUN": "重装机枪", + "The suit was once designed to hold a variety of battlefield medical equipment. Now it holds a generous supply of stims.": "按照原本的设计,这套盔甲应该配备多种战地医疗设备,现在则是携带了大量的治疗剂。", + "LOCKSTEP": "齐步行进", + "10x SNIPER SCOPE": "10倍狙击瞄准镜", + "A-9 HELLJUMPER": "A-9“地狱伞兵”", + "R-72": "R-72", + "Foe Rent Asunder": "敌分四裂", + "A/G-16": "A/G-16", + "30mm APHE Cannon": "30mm穿甲高爆炮弹", + "VALIANT ENCLOSER": "英勇围合战士", + "110mm GAS CANNON ROUND MK3": "110mm毒气炮弹 MK3", + "Eruptor": "爆裂铳", + "Verdict": "裁决", + "THIS IS DEMOCRACY": "恭迎民主", + "Eagle Air-to-Air Missiles": "“飞鹰”空对空导弹", + "A heatsink calibrated to purposely generate heat faster than standard heatsinks.": "经过特殊校准,这种散热器的发热速度快于标准散热器。", + "The end result of several billion Super Credits and 12 years of research into creating \"the Soldier of Tomorrow.\"": "这是为打造“明日战士”而投入数十亿超级货币并耗费12年研究得出的最终成果。", + "DS-10 BIG GAME HUNTER": "DS-10“巨兽猎手”", + "Combat Blend": "混合作战", + "MOTHER EAGLE'S WINGS": "母鹰之翼", + "STURDIER WHEELS": "加固轮胎", + "An automated assembly line where all Hellpod armaments are constructed by precise, non-sentient robotic arms.": "自动化装配流水线,所有绝地喷射舱军备均由无感知的精密机械臂所建造。", + "12x25mm Plasma": "12x25mm等离子弹", + "BUNTING OF THE PARTY PARTICIPANT": "派对彩饰", + "SPEAR BACKPACK": "飞矛背包", + "MORE BOMBS": "增加炸弹数", + "TR-117 ALPHA COMMANDER": "TR-117“阿尔法指挥官”", + "When the wearer takes damage, they regain some stamina.": "穿戴者受到伤害时恢复部分体力。", + "LIFT-860": "LIFT-860", + "FREE-SPIRITED SPANGLES": "自由之魂的辉映", + "Embodies the ethos of Manifest Democracy—that it is our voter-given responsibility to emancipate the savage, un-Liberated galaxy. To rest only when every planet is safe, civilized, and Free.": "这套盔甲彰显了天定民主的信条:解放蛮荒、未获解放的银河系是选民赋予我们的神圣职责。唯有确保每个星球安全、文明、自由,我们才能功成身退。", + "EYE OF LIBERTY": "解放之眼", + "45-Degree Vertical Foregrip": "45度垂直前握把", + "12.5mm STANDARD RIFLE ROUNDS": "12.5mm标准步枪子弹", + "5.5x50mm PENETRATOR": "5.5x50mm穿甲弹", + "PH-9 PREDATOR": "PH-9“掠食者”", + "RAILGUN STUN ROUND": "磁轨炮眩晕弹", + "Signal: Group Up": "信号:集合", + "BALLISTIC SHIELD BACKPACK": "防弹护盾背包", + "A modified Punisher shotgun firing exploding plasma rounds. Fire carefully - exploding plasma can injure squadmates.": "改良后的“制裁者”霰弹枪,可发射会引爆的等离子弹。射击时务必小心,爆炸的等离子体可能会伤及队友。", + "TESTAMENT TO ATTRITION": "百战不殆的明证", + "Wearers of this cape know that even enemies of Freedom deserve to be equal. Equally dead.": "穿上这件披肩的战士都明白,即使是自由的敌人,也值得平等对待,让他们平等地死去。", + "NO OPTICS": "无准镜", + "MS-11": "MS-11", + "SPACE CADET": "太空军校生", + "DAMAGE ALT": "其他伤害", + "LARGER MAGAZINE": "扩容弹匣", + "A humane grenade launcher firing high-powered arc grenades.": "发射高能电弧榴弹的人道主义榴弹发射器。", + "Pistol": "手枪", + "A high-precision burst-fire plasma rifle that must be charged to fire.": "高精度连发等离子步枪,需充能才能开火。", + "20mm HVAP Rounds": "20mm高速穿甲弹", + "More LMG Mount Mags": "增加架设型轻机枪弹匣", + "ETERNAL CORONA": "永恒日冕", + "ARC THROWER": "电弧发射器", + "With genuine gold accents, 74% of colonists voted this armor the set they would most like to be buried in.": "真金装饰。74%拓殖地居民投票表示死后最希望穿这套盔甲下葬。", + "Grenade Launcher": "榴弹发射器", + "R-2": "R-2", + "UF-16 Inspector": "UF-16“督察员”", + "A/GM-17": "A/GM-17", + "A barrage of napalm bombs, creating a wall of fire which will stop the enemy in their tracks.": "凝固汽油弹火力网,可形成一道火墙,阻止敌人进攻。", + "AC-1 DUTIFUL": "AC-1“恪尽职守”", + "FIRE SAFETY OFFICER": "消防安全官", + "PEAK PHYSIQUE": "健壮体格", + "Presentable": "像模像样", + "PROOF OF FAULTLESS VIRTUE": "无瑕德行之证", + "The design of the Demo-Trooper armor has been a corporate secret since ST Construction first issued it to the Charan Colonial Guard in the early days of the Galactic Federation. Now, STC has contracted with the Ministry of Defense to issue the storied armor of its fallen homeworld to the Helldivers.": "自星系联邦初期,ST建筑公司首次将“爆破兵”护甲配发给常陈四拓殖卫队以来,其设计一直属于该公司的商业机密。如今,ST建筑公司已与国防部签订合同,将这套承载着传奇历史、来自其沦陷母星的护甲配发给绝地潜兵。", + "SEAF Artillery": "超级地球武装部队大炮", + "RED PLANET'S MEMORY": "红星回忆", + "HEAVY RECOIL SPRING": "重型复进簧", + "B-04 DEVELOPER OF DEMOCRACY": "B-04“民主缔造者”", + "200kg Bomb": "200KG炸弹", + "NO STRATAGEM": "没有战略配备", + "SA-8 Ram": "SA-8“蛮悍”", + "A high explosive grenade which detonates on first impact.": "一旦碰撞立即引爆的高爆榴弹。", + "SA-25 Steel Trooper": "SA-25“钢铁士兵”", + "SG-225": "SG-225", + "With its two barrels, one trigger, and vintage feel, this shotgun is perfect for historical reenactments.": "双管单扳机的复古设计,这把霰弹枪是重现历史场景的绝佳道具。", + "15x100mm STANDARD ROCKET": "15x100mm标准火箭弹", + "FS-23 BATTLE MASTER": "FS-23“战斗大师”", + "A submachine gun with a helical-feed magazine, which gives the weapon a higher ammo capacity while making it more front-heavy. Produced by Stål Arms.": "冲锋枪,配备螺旋式供弹弹匣,弹药容量增加,但前重后轻。由斯塔尔武装生产。", + "Eagle Gas Airstrike": "“飞鹰”毒气空袭", + "FASTER MISSILES": "提升导弹速度", + "110mm Gas Cannon Round Mk2": "110mm毒气炮弹 MK2", + "COMPRESSED EXPLOSIVES": "压缩炸药", + "GREATCLOAK OF REBAR RESOLVE": "钢筋意志大氅", + "SC-15 DRONE MASTER": "SC-15“无人机大师”", + "CM-09 Bonesnapper": "CM-09“碎骨杀手”", + "A vertical foregrip with an integrated tactical light.": "配备集成战术灯的垂直前握把。", + "RS-6 FIEND DESTROYER": "RS-6“歼魔者”", + "DEFAULT HELLDIVER VOICE 4": "绝地潜兵默认声音 4", + "Badge of Order": "秩序徽章", + "Salvaged from a deep-storage vault, this well-ventilated cape symbolizes tenacious survival. Its visible scars bestow immediate veteran status, reminding all onlookers that the spirit of tireless service is immortal.": "回收自一座长期储藏库,这款“千疮百孔”的披风象征着顽强的生存意志。清晰可见的“战损伤疤”平添资深行伍光环,并时刻警醒旁观者:百战不殆的奉献精神永垂不朽。", + "15x100mm Standard Rocket": "15x100mm标准火箭弹", + "IMPROVED RELOADING PROCESS": "改良装弹流程", + "RS-20 Constrictor": "RS-20“绞杀者”", + "Pineapple": "菠萝", + "Orbital Napalm Barrage": "轨道凝固汽油弹火力网", + "Crafted to deliver Justice to the darkest crevices of the galaxy.": "为将正义传递到银河系最黑暗的缝隙而设计。", + "RIFLE": "步枪", + "Deadeye": "鹰眼", + "Proof of Faultless Virtue": "无瑕德行之证", + "TARGETING SENSORS": "目标锁定传感器", + "Cremator": "焚燃者", + "10g Magnum": "10g马格南霰弹", + "Solo Silo": "单兵导弹发射井", + "TG-8 SHARPSHOOTER": "TG-8“神枪手”", + "Manual Function Trigger": "手动操作触发", + "Drape of Glory": "荣光加身", + "Mother Eagle's Wings": "母鹰之翼", + "PATIENT ZERO'S REMEMBERANCE": "零号病人遗思", + "5.5x50mm Full Metal Jacket": "5.5x50mm全金属被甲弹", + "A high-torque laser rifle that fires a continuous beam of thermal energy. If allowed to fully overheat, the weapon discharges a massive, explosive energy burst before requiring a heat sink replacement.": "一款高转矩激光步枪,可发射持续的热能光束。若允许其完全过热,该武器在需要更换散热器前会释放出一股巨大的爆炸性能量脉冲。", + "VERTICAL RECOIL": "垂直后坐力", + "This cape's cropped length symbolizes the brevity of galactic conflicts, thanks to the efficiency of the Helldivers.": "这款披肩的剪裁长度象征着星系冲突之短暂,一切归功于绝地潜兵的作战效率。", + "Fires concussive rounds that stagger enemies. Slower rate of fire than other SMGs.": "可连续发射震荡弹击退敌人。射速比其他冲锋枪慢。", + "The two stripes serve as a reminder of the two pillars of successful military campaigns: attack, and further attack.": "双条纹代表着成功的军事行动有两大支柱:进攻,以及进一步进攻。", + "LOADING DRILLS": "熟练装载配备", + "Stone-Wrought Perseverance": "磐石毅力", + "Awarded to those promoted to their point of greatest competency, and beyond.": "仅授予已达至臻之境并突破自我极限的战士。", + "EFFICIENT RELOADING": "高效装弹", + "Random": "随机", + "PROGRESSIVE TRIGGER": "渐进式扳机", + "10g HIGH VELOCITY SABOT": "10g高速萨博特式霰弹", + "An automated cannon turret firing anti-tank ammunition over long ranges. Sacrifices agility for range and power.": "远程发射反坦克弹药的自动加农炮台。以牺牲灵活性为代价,扩大攻击范围,提升火力。", + "SPECIALIST": "专家", + "15x100mm High Velocity": "15x100mm高速弹", + "O-44 BONDED PILOT": "O-44“契约驾驶员”", + "The classic Helldiver paint job.": "经典绝地潜兵涂装", + "A/MG-43": "A/MG-43", + "HE": "高爆弹", + "9x20mm Hollow Point": "9x20mm空尖弹", + "A laser weapon firing a continuous beam. Doesn't require ammunition, but will need heat sink replaced if it overheats.": "发射连续光束的激光武器。无需弹药,但武器过热时需要更换散热器。", + "GS-11 Democracy's Deputy": "GS-11“民主代理人”", + "Armor inspired by the legend of the Sanctioner, a figure known only through a bizarrely unanimous patchwork of stifled whispers. As told, this fearsome, covert arbiter of primeval Justice delivered final, state-approved verdicts in the chaotic years before the Federation's founding.": "以制裁者的传说为灵感设计的盔甲,虽然这位人物的形象仅由隐蔽的只言片语拼凑而成,但却诡异地一致。据传,这位令人敬畏的隐蔽制裁者在联邦成立前的混乱年代伸张早期的正义,下达国家认可的最终判决。", + "High-Speed Servos": "高速伺服系统", + "Gatling Sentry": "加特林哨戒炮", + "85mm ARMOR-PIERCING GRENADE": "85mm穿甲榴弹", + "Loading Optimizations": "优化配备装载", + "While early prototypes used shock-absorbing gels, this armor stabilizes aim with the use of internal gyroscopes.": "早期原型曾使用减震凝胶,而此盔甲利用内置陀螺仪稳定瞄准动作。", + "LONG REVOLVER BARREL": "左轮手枪长枪管", + "LIGHT ANTI-TANK": "轻质反坦克", + "Crest of the Unsullied": "无垢徽章", + "CE-27 Ground Breaker": "CE-27“裂地者”", + "HIGH-PRESSURE NOZZLE": "高压喷嘴", + "EAGLE AIR-TO-AIR MISSILES": "“飞鹰”空对空导弹", + "At the edge of the Federation, sometimes Democracy has only one representative.": "在联邦的边境线,有时民主只有一位代理人。", + "AUTONOMOUS": "自动", + "HIVE BREAKER DRILL": "“虫窝破裂者”钻机", + "FREE OF THOUGHT": "思想自由", + "Faster Recharge": "加速充能", + "EXO-45": "EXO-45", + "Suppressor": "消音器", + "HEAT": "高爆反坦克弹", + "Accelerator Rifle": "加速步枪", + "ADDITIONAL HARDPOINTS": "附加挂载点", + "Camo Cloak": "迷彩斗篷", + "Seal of General Consensus": "康森瑟斯将军之印", + "City Fighter's Resolve": "城市战士的决意", + "This armor's nostalgic color scheme brings to mind beloved trappings of colonial yesteryear: concrete frontier domiciles, slate-colored civilian jumpsuits, and Space Settlers' Pie.": "这套盔甲的怀旧配色让人联想到昔日拓殖地时期的时尚潮流:混凝土筑成的边境住所,石板色平民连体服,太空居民馅饼。", + "15x100mm Fragmentation": "15x100mm破片弹", + "VENUS": "维纳斯", + "Auto Loader": "自动装载", + "Standard of Safe Distance": "安全距离标准", + "Double Machinegun Pod": "双机枪喷射舱", + "ORBITAL AIRBURST STRIKE": "轨道空爆攻击", + "Muzzle Brake": "枪口制退器", + "SERVANT OF FREEDOM": "自由公仆", + "ONE-TWO": "幺二", + "GL-28": "GL-28", + "10g Magnum Triball": "10g马格南三连弹", + "Airburst Rocket Backpack": "空爆火箭弹背包", + "RECOIL": "后坐力", + "COMPENSATOR": "补偿器", + "SMG-37": "SMG-37", + "More Explosive Filler": "增加爆炸物填料", + "BLAZING SAMARITAN": "慈心闪耀", + "A/ARC-3": "A/ARC-3", + "More Autocannon Turret Ammo": "增加机炮炮台弹药数", + "12x25mm FULL METAL JACKET": "12x25mm全金属被甲弹", + "All Hail the Helldivers, whose devotion to Managed Democracy has never faltered.": "向绝地潜兵致敬,他们对管理式民主的忠诚从未动摇。", + "EAGLE CLUSTER BOMB": "“飞鹰”集束炸弹", + "8x60mm SUBSONIC": "8x60mm亚音速弹", + "TR-40 Gold Eagle": "TR-40“金鹰”", + "CREWSPACE REMOVAL": "移除船员舱", + "One of the most durable engineer armors available, each set is quality tested by an impact with a full-grown Charger.": "最耐用的工兵盔甲之一。每一套盔甲的质量检测流程都是抵挡一只成年强袭虫的冲撞。", + "An incendiary grenade which ignites any targets and terrain within the blast radius. Use with caution.": "燃烧榴弹,可点燃爆炸范围内任何目标和地面。请谨慎使用。", + "An assault rifle with a high-capacity drum magazine, good for providing sustained fire. \nProduced by Stål Arms.": "突击步枪,配备大容量弹鼓,适合持续提供火力。\n由斯塔尔武装公司生产。", + "FASTER LOCK-ON TIME": "缩短锁定目标用时", + "I-92 Fire Fighter": "I-92“消防队”", + "Maxigun Backpack": "重装机枪背包", + "Assigns a random voice to your Helldiver when you die.": "在死亡时,为你的绝地潜兵随机分配一种声音。", + "SLUGS": "独头弹", + "An SMG that fires caseless ammunition and is equipped with a non-removable suppressor. \nProduced by Martian Armory.": "发射无壳弹药的冲锋枪,且配备了不可拆卸的消音器。\n由火星军械库生产。", + "Eagle 110mm Rocket Pods": "“飞鹰”110mm火箭巢", + "Our heroic fallen live on in this cape, guiding its bearer's aim to the heart of those who killed them.": "这款披肩承载着陨落的烈士之魂,引导穿戴者瞄准凶手的要害,为他们复仇。", + "FRE LIBERAM": "求自由", + "THUNDERING HOOVES OF LOYALTY": "忠诚惊雷之蹄", + "A modified Breaker shotgun offering improved armor penetration and accuracy, with exceptionally high levels of recoil.": "改良后的“破裂者”霰弹枪,穿甲性能和精准度有所提升,后坐力尤其高。", + "Rebar Resolve": "钢筋意志", + "STANDBY": "随时待命", + "Bastion Mk XVI": "堡垒Mk XVI", + "RECOILLESS RIFLE": "无后坐力炮", + "Display of Brawn": "肌肉展示", + "A lightweight flamethrower. Shoots pressurized fuel through a dispersion nozzle into an open flame. Safe.": "轻型火焰喷射器。通过扩散喷嘴喷射加压燃料,形成明火。相当安全。", + "EXO-51": "EXO-51", + "A cape that strikes a subroutine emulating fear into the CPUs of all Automatons who conduct visual scans of it.": "所有扫描此披肩的机器人,其CPU都将被植入模拟恐惧情绪的子程序。", + "New Explosive Filler": "新式爆炸物填料", + "Provides #BONUS resistance to chest damage.": "提供#BONUS的胸部伤害抗性。", + "EXTRA MAGAZINE": "额外弹匣", + "ORBITAL SMOKE STRIKE": "轨道烟雾攻击", + "Cremator Backpack": "焚燃者背包", + "A versatile submachine gun equipped with iron sights and frontline incineration capabilities.": "一款多用途冲锋枪,配备机械瞄具,具备前线炽灼能力。", + "Atomizes caustic chemicals into a fine mist that liquifies sensitive electronics and tissues. Blinds and slows most enemies.": "将腐蚀性化学物质雾化成细密雾气状,使敏感的电子设备和组织液化。可使大多数敌人致盲并减速。", + "Thumb of Approval": "赞许之指", + "A backpack containing six adhesive C4 charges and a handheld wireless electronic detonator. Charges can be deployed and detonated individually, or as multiple simultaneous blasts.": "背包内装有6枚粘性C4炸药和一个手持式无线电子起爆器。炸药可单独部署并引爆,也可多枚同时引爆。", + "More Salvoes": "增加齐射炮弹数", + "DRILLING CHARGE": "强钻炸药", + "BUNKER BUSTER": "碉堡克星", + "CONTACT MINE": "水雷", + "Backup Vehicle": "备用载具", + "ANTI-TANK MINES": "反坦克地雷", + "Autocannon": "机炮", + "Hangar": "机库", + "APW-1": "APW-1", + "Raider's Cheer": "奇袭者的欢呼", + "Patriot Exosuit": "“爱国者”外骨骼装甲", + "Solicit Transportation": "请求运输", + "A fully-automatic shotgun with a high rate of fire, excellent for controlling crowds. Requires frequent reloading.": "高射速的全自动霰弹枪是群体控制的绝佳选择。需要频繁装弹。", + "BREAKER INCENDIARY": "高燃“破裂者”", + "I-09 Heatseeker": "I-09“热力追踪”", + "ROLL 'EM": "骰子定胜负", + "SUPER PRIVATE": "超级列兵", + "StA-11": "StA-11", + "VETO": "否决者", + "Drum Magazine": "弹鼓", + "Artists and sculptors have made countless attempts at depicting the face of Liberty, but the truth is that any citizen can see it—they need only requisition a mirror.": "艺术家和雕塑家曾无数次试图勾勒自由的轮廓,但事实上,任何人只需照照镜子,便能一睹自由的风采。", + "A scope with 10x magnification, good for long range on high accuracy weapons.": "10倍放大瞄准镜,适合高精度武器远程打击使用。", + "FLAM-40": "FLAM-40", + "G-48": "G-48", + "BP-32 JACKBOOT": "BP-32“杰克军靴”", + "This cape honors the Eagle pilots who would follow a Stratagem beacon into the very jaws of tyranny, even when the beacon's placement seems inscrutable to the non-Helldiver mind.": "这件披肩旨在纪念那些追随战略配备信标直捣暴政巢穴的飞鹰飞行员,即便信标位置在非绝地潜兵者看来难以理解也义无反顾。", + "MORE BACKPACK AMMO": "增加备用弹药", + "BP-77 GRAND JUROR": "BP-77“大陪审员”", + "Improved Recoil": "改善后座力", + "BP-20 Correct Officer": "BP-20“思想矫正官”", + "Assembled from pieces of recovered Helldiver armor and SEAF gear, for those who won't let a lack of full body protection keep them from the battlefront.": "这件披肩由回收的绝地潜兵装甲和超级地球武装部队装备碎片组装而成,专为那些即使缺乏全身防护装备也要奔赴战场的勇士设计。", + "Deploys mines that release gas on activation, temporarily blinding and slowing most enemies.": "部署地雷,触发后会释放毒气,可使大多数敌人暂时致盲并减速。", + "Longer Fire Time": "射击时间延长", + "I-44 SALAMANDER": "I-44“火蜥”", + "WEAPON STATS": "武器数据", + "Brawny": "健壮", + "A compact, low caliber machine gun. Trades power for ease of use, with faster reloading than heavier machine guns.": "小口径紧凑型机枪。牺牲火力,换取便利性,装弹速度比更重型机枪更快。", + "COMMANDER": "上尉", + "Good for medium to long range and the maximum magnification normally used for general weapons.": "常规武器常用的最高倍率瞄准镜,适合中远程打击。", + "A heavy, large-caliber marksman rifle bridging the gap between precision and sheer stopping power. Fires armor-piercing rounds coated in a high-ignition thermite compound to ignite targets.": "一款重型大口径精确射手步枪,完美兼顾精准度与强劲的停止作用。发射涂有高燃铝热剂化合物的穿甲弹,可引燃目标。", + "PINIONS OF EVERLASTING GLORY": "永恒荣耀之羽", + "MASTER SERGEANT": "军士长", + "Windswept Wayfinder": "风驰引路者", + "AMENDMENT": "修正", + "Painted by visionary artist Silas Garm during an intense fever, this symbol represents Humanity's great Galactic endeavor: the blood-soaked dawn of Lasting Peace.": "这个符号由远见卓识的艺术家西拉斯·加姆在高烧中绘制,象征着人类在银河系卓绝奋斗的痕迹:他们为持久和平的曙光而挥洒的鲜血。", + "SA-7 Headfirst": "SA-7“冲锋者”", + "Railgun Stun Round": "磁轨炮眩晕弹", + "Deploys a defensive incendiary minefield, which will set both terrain and targets alight when triggered.": "部署一片燃烧式防御雷区,一旦触发便会点燃地面和目标。", + "LAS-22": "LAS-22", + "Efficient Reloading": "高效装弹", + "INCINERATOR FRV": "炽灼型快速侦察载具", + "MASTER DIVEMASTER MAJOR OMEGA": "终极大师潜兵长少校", + "Expanded Heat Capacity": "提升热容量", + "CE-101 GUERILLA GORILLA": "CE-101“游击猩猩”", + "MAX RANK INFINITY +1": "无限最高等级+1", + "G-16": "G-16", + "No optic attachment": "无准镜配件", + "Improved Servos": "改良伺服系统", + "EAGLE 110MM ROCKET PODS": "“飞鹰”110MM火箭巢", + "TED-63": "TED-63", + "This cape's retro print, first made popular in GW1 cereal merchandising, helps children remember that not all machines are twisted mechano-socialists; some are piloted by true-hearted humans, and we can all rest easy in their gaze.": "这款披风的复古印花最初作为第一次星系战争的麦片周边商品而爆红,它能帮助孩子们牢记这一事实:并非所有机器的操控者都是扭曲的机械党同伐异者;有些机器由诚挚人类所驾驶,而我们正是在它们的注视下得以安然入睡。", + "Pyrotech": "烟花术", + "VERTICAL FOREGRIP": "垂直前握把", + "Extraction": "撤离", + "The Helldiver Skull is said to strike fear in the hearts of foes attempting to sneak up on those wearing this cape.": "据说,妄图偷袭穿戴此披肩之人的敌人,都会被绝地潜兵的骷髅头图案所震慑。", + "Scraps of Sovereignty": "主权碎片", + "A faithful replica of the armor worn at The Battle of Liberty Peak. Honor their legacy, and wear it with pride.": "如实还原解放峰之战的盔甲。尊重他们的遗产,骄傲地将其穿在身上。", + "ORBITAL RAILCANNON STRIKE": "轨道炮攻击", + "SUPPLEMENTAL ADRENALINE": "肾上腺素补充剂", + "ULTIMATUM": "最后通牒", + "Order the Eagle Fighter to return to the ship, where it can restock its armaments.": "可指派“飞鹰”战斗机返回飞船,重新补充军备物资。", + "Orbital Walking Barrage": "轨道游走火力网", + "LUMBERER EXOSUIT": "“伐木者”外骨骼装甲", + "SHORTER RECHARGE DELAY": "缩短充能延迟", + "Explosive Rounds": "增加爆炸弹", + "IX-VOIDWALKER": "IX-寂域行者", + "BUSHWHACKER": "游击兵", + "ERUPTOR": "爆裂铳", + "Compact and flexible, this kevlar armor adds minimal mass, making it a common choice for Helldiver fitness tests.": "此芳纶纤维盔甲坚实又灵活,几乎不增加额外重量,是绝地潜兵体能测试的常用配备。", + "A choir of patriotic schoolchildren sings the Super Earth anthem to each cape as the final step in its production.": "此披肩制作过程的最后一步,是由爱国儿童唱诗班向着每一件披肩唱超级地球国歌。", + "DE-ESCALATOR": "缓和使者", + "Programmable Prism Effect": "智能棱镜效果", + "HAIR TRIGGER": "微力扳机", + "DEVELOPER": "DEVELOPER", + "5.5x50mm Explosive": "5.5x50mm爆炸子弹", + "A fully-automatic cannon effective against light vehicle armor. Includes support backpack required for reloading.": "全自动加农炮,可有效对付轻型载具装甲。包含支援背包,用于装填弹药。", + "RS-100 SANCTIONER": "RS-100“制裁者”", + "MISSILE PERFORMANCE": "导弹性能", + "MAX RANK": "最高等级", + "Entrenchment Tool": "堑壕工具", + "HOLDER OF THE YELLOW LINE": "黄线捍卫者", + "DIVEMASTER MAJOR": "潜兵长少校", + "A plasma pistol that charges each shot until the trigger is released. Plasma projectiles explode on impact.": "等离子手枪,每发射击都可充能,松开扳机即可开火。等离子弹触碰着弹点后会爆炸。", + "Vision of Freedom": "自由愿景", + "PORTABLE HELLBOMB": "便携式地狱火炸弹", + "Eagle Strafing Run": "“飞鹰”机枪扫射", + "15x100mm FRAGMENTATION": "15x100mm破片弹", + "P-69": "P-69", + "GILDED QUILL": "镀金羽毛笔", + "An expendable missile launcher equipped with four laser-guided missiles.": "消耗性导弹发射器,配有四枚激光制导导弹。", + "A laser pistol that fires a continuous beam. Does not require ammo but can overheat and need to change batteries.": "发射连续激光束的激光手枪。无需装弹,但如果手枪过热,必须更换电池。", + "The clasps on this cape are made from melted down Automaton housings—evidence of Democracy's inevitable triumph.": "披肩上的扣子是通过熔化机器人外壳制作而成的,有力证明了民主的胜利势不可挡。", + "MACHINE GUN SENTRY": "哨戒机枪", + "Vertical Foregrip": "垂直前握把", + "A heavy-hitting, one-handed melee weapon.": "重型单手近战武器。", + "Slightly increases weapon ergonomics to reduce drag on weapon movement.": "通过小幅提升武器的人体工学性能,降低携带武器移动的阻力。", + "Lightweight Materials": "轻质材料", + "DESERT CAMO": "沙漠迷彩", + "Scythe": "长柄镰", + "Detonates on impact, covering the immediate vicinity in self-igniting white phosphorus.": "受到撞击即引爆,以可自燃的白磷覆盖周边区域。", + "110mm STANDARD ROCKET": "110mm标准火箭弹", + "85mm HEAT Grenade Mk2": "85mm高爆反坦克榴弹 MK2", + "ORBITAL GAS STRIKE": "轨道毒气攻击", + "No Optics": "无准镜", + "FLAMES MK2": "喷射火焰 MK2", + "A large bomb obliterating almost any target close to impact. Make sure to clear the area.": "一枚大型炸弹,可湮灭靠近爆炸范围的近乎所有目标。请确保所有人员撤离爆炸区域。", + "ENTHUSIASTIC MIRTH": "开怀大笑", + "DEFAULT INTERNAL PART": "默认内部零件", + "40mm HE MORTAR": "40mm高爆迫击炮弹", + "Against the Tyrant Cloud": "破除暴瘴", + "A precision artillery salvo over a small area, perfect for taking out concentrated enemy units.": "向小范围区域齐射的精准火力打击,可完美解决集中在一起的敌方单位。", + "#PREFIX #NAME": "#PREFIX #NAME", + "When the Illuminate threatened Super Earth, the very Heart of Democracy, the Helldivers answered the call.": "当光能者威胁超级地球这颗民主之心时,绝地潜兵应召而战。", + "MANUAL FUNCTION TRIGGER": "手动操作触发", + "B-1": "B-1", + "40mm PROXIMITY GRENADE": "40mm感应榴弹", + "RS-40 Beast of Prey": "RS-40“掠食凶兽”", + "A turret firing static field generators that slow the advance of enemies.": "炮台可发射静电场发生器,拖延敌人前进的脚步。", + "IMPROVED AMMUNITION FEED": "改良供弹系统", + "SEAF ARTILLERY: MINI NUKE": "超级地球武装部队大炮:迷你核弹", + "RS-422": "RS-422", + "EXPLOSIVE ROUNDS": "增加爆炸弹", + "ADMIRABLE ADMIRAL": "承敬上将", + "STERILIZER": "灭菌器", + "10g SCATTER SHOT": "10g散射弹", + "RANGER": "游骑兵", + "10g FLECHETTES": "10g飞镖弹", + "HVAP ROUNDS": "高速穿甲弹", + "THROWING KNIFE": "飞刀", + "Slugger": "重炮手", + "Super Person": "超人", + "Giga Grenade": "千兆级榴弹", + "GP-20": "GP-20", + "FS-55 Devastator": "FS-55“蹂躏者”", + "RS-6 Fiend Destroyer": "RS-6“歼魔者”", + "13x40mm HOLLOW POINT": "13x40mm空尖弹", + "Rightful Occupier": "正当占领者", + "P-72": "P-72", + "AD-49 APOLLONIAN": "AD-49“阿波罗神”", + "SEAF ARTILLERY: NAPALM": "超级地球武装部队大炮:凝固汽油弹", + "110mm AIRBURST CANNON ROUND": "110mm空爆炮弹", + "G-3": "G-3", + "P/40-K": "P/40-K", + "A \"compliance weapon\" to modify enemy behavior. The projectile temporarily stuns all targets within the strike radius.": "改变敌人行为的“慑敌武器”。射弹可短时眩晕攻击范围内的所有目标。", + "LASER SIGHT W/ FLASHLIGHT": "激光瞄准器带照明", + "The fire rate of the autocannons is increased from 200 to 300 rounds per minute.": "机炮的射速从每分钟200发提升至每分钟300发。", + "DESERT": "沙漠", + "SR-24 STREET SCOUT": "SR-24“街头侦察兵”", + "Gas Mines": "毒气地雷", + "This high-caliber marksman rifle trades magazine capacity and rate of fire for powerful, accurate shots.": "大口径狙击步枪,虽然牺牲了弹匣容量和射速,却提高了射击精准度和威力。", + "WATCHFUL COMPATRIOT": "守望同胞", + "8x60mm Penetrator": "8x60mm穿甲弹", + "A compact handgun-style flamethrower, able to project a jet of fire over short distances.": "手枪式便携火焰喷射器,能够喷射近程火焰。", + "110mm E.M.S. CANNON ROUND MK2": "110mm电磁冲击波炮弹 MK2", + "Provides #BONUS resistance to arc damage.": "提供#BONUS的电弧伤害抗性。", + "FS-40 DIPLOMAT": "FS-40“外交官”", + "An Exosuit equipped with a flak cannon and ballistic shield, optimized for mid-to-close combat range.": "配备高射炮与防弹护盾的外骨骼装甲,专为中近距离战斗而优化。", + "Firing jet-propelled rounds, the Dominator trades fire rate and magazine capacity for increased damage per projectile.": "发射喷气推进式子弹,这把“主宰”虽然牺牲了射速和弹匣容量属性,却提高了每颗弹丸的伤害。", + "FLASH HIDER": "消焰器", + "BULLET STORM": "子弹风暴", + "G-11": "G-11", + "15x100mm Emp-Rounds": "15x100mm电磁脉冲弹", + "SR-18 ROADBLOCK": "SR-18“路障”", + "For optimal performance, the manufacturer recommends avoiding immersing this armor in salt water for prolonged periods.": "为维持盔甲的良好性能,制造者建议避免长时间将盔甲浸入咸水。", + "PLASMA BOLT": "等离子弹", + "SOLID BLACK": "纯黑", + "The eternal colors of Super Earth can never be tainted. Only quenched, by the blood of its enemies.": "超级地球的永恒颜色绝不能被玷污。唯有沾染敌人的鲜血方可罢休。", + "ENTRENCHMENT TOOL": "堑壕工具", + "SOLO SILO": "单兵导弹发射井", + "SMG": "冲锋枪", + "FASTER DEPLOYMENT": "加快部署", + "RS-89 SHADOW PARAGON": "RS-89“暗影典范”", + "Extra Capacity": "额外容量", + "O-44 Bonded Pilot": "O-44“契约驾驶员”", + "FLAMETHROWER": "火焰喷射器", + "Although bulkier, it provides the effects of both a laser sight and a flashlight.": "虽然体积更大,但能同时提供激光瞄准器和照明效果。", + "5.5x50mm DEVASTATOR": "5.5x50mm“毁灭者”子弹", + "ARCTIC CAMO": "雪地迷彩", + "Issued to the rapid-response enforcement wings of the Ministry of Prosperity. This armor provides the structural integrity necessary for aggressive pursuit maneuvers and the forceful redirection of traffic—whether civilian, military, dissident or hostile.": "配发给繁荣部下属快速响应执法支队。这套护甲提供侵略性追击机动和强行疏导交通所需的结构强度——无论对方是平民、军人、异见分子还是敌军。", + "SG-451": "SG-451", + "Standard Drum": "标准弹鼓", + "A single-use target-seeking anti-aircraft missile launcher. Must be locked to target before firing.": "一次性寻的防空导弹发射器。发射前必须锁定目标。", + "Charges up to fire a powerful, explosive energy burst. Has a long cooldown period after firing.": "充能后可发射爆炸性的强力能量炮。发射后的冷却时间较长。", + "A mark of stalwart loyalty bestowed only to those who have proved themselves worthy through unquestioning dedication.": "坚定忠诚的标志,仅授予那些通过绝对的奉献来证明自身资格的战士。", + "EW": "好臭", + "500kg BOMB": "500KG炸弹", + "Napalm Bomb": "凝固汽油弹", + "An angled foregrip with an integrated laser sight.": "配备集成激光瞄准器的直角前握把。", + "Dissident's Nightmare": "异见者梦魇", + "This classic armor set is recognized by every citizen: worn by the heroic Helldivers who battled and forever defeated the Terminids, Cyborgs, and Illuminate in the First Galactic War.": "每位市民都认识这套经典盔甲:在第一次星系战争,绝地潜兵英雄就是穿着它彻底击败终结族、生化人和光能者。", + "EAT-411": "EAT-411", + "Because this prototype's wires operate at 400,000 volts, it also includes a handy rubber underlayer for insulation.": "此原型的电线需要在400,000伏特的电压下运行,因此盔甲配有便利的橡胶绝缘内衬。", + "5.5x50mm RIPPER": "5.5x50mm撕裂弹", + "GRENADE LAUNCHER": "榴弹发射器", + "12x25mm TOXIC": "12x25mm毒弹", + "12g Buckshot": "12g鹿弹", + "DP-00 TACTICAL": "DP-00“战术”", + "HEAD TAP": "动动脑", + "Stoker": "司炉者", + "Increased Storage": "可携带数量升级", + "GRENADIER BATTLEMENT": "掷弹兵防卫墙", + "SEAF ARTILLERY": "超级地球武装部队大炮", + "MORE FUEL": "增加燃料", + "This armor celebrates the wearer's close relationship to their Exosuit---as intimate as is possible without succumbing to cyborgry.": "此套盔甲旨在彰显穿着者与外骨骼装甲之间的紧密羁绊——极致亲密贴合,但不至于堕入生化人之境。", + "Per Democrasum": "于民主", + "A mighty rifle with a signature lever-action enabling single round reload. Powerful precision suited to mid- and long-range combat.": "威力强大的步枪,经典拉柄式设计支持单发装填。精准度极高,适合中远程作战。", + "A tribute to the Liberation of Choepessa IV in the First Galactic War, in which so much orbital ordnance was detonated that its sun was occluded by ash for an entire lunar cycle.": "纪念第一次星系战争的科埃佩萨IV解放战役。彼时投射的轨道火力留下了漫天烟尘,将恒星的光芒遮蔽了整整一个月。", + "Standard plasma bolt": "标准等离子弹", + "Default Helldiver Voice 2": "绝地潜兵默认声音 2", + "INCREASED FUEL CAPACITY": "提升燃料容量", + "B-24 Enforcer": "B-24“执行者”", + "Enables melee attacks to remove larger obstacles, such as fences.": "近战攻击可拆除更大型的障碍物,例如栅栏。", + "RAPID HEATSINK": "快速散热器", + "A paint job for use in desert environments.": "适用于沙漠环境的涂装。", + "EAGLE 500KG BOMB": "“飞鹰”500KG炸弹", + "SA-8 RAM": "SA-8“蛮悍”", + "8x60mm FULL METAL JACKET": "8x60mm全金属被甲弹", + "ORBITAL ILLUMINATION FLARE": "轨道照明弹", + "Forged for those watchful protectors who silently guide all Helldivers, asking no recognition whatsoever, besides a simple custom-made suit of armor only they get to wear.": "为默默引导所有绝地潜兵的保护者打造,除了简单的专属定制盔甲以外,他们不求得到任何形式的认可。", + "5.5x50mm Self Propelled": "5.5x50mm自走弹", + "A paint job that dares to stand out.": "敢于引人注目的涂装。", + "B-24 ENFORCER": "B-24“执行者”", + "W.A.S.P. LAUNCHER": "W.A.S.P.发射器", + "EMBLEM OF FREEDOM": "自由象征", + "LONG": "长", + "Impatient": "急躁", + "Scorcher": "焦土", + "Reload Drills": "熟练装弹", + "110mm Airburst Cannon Round": "110mm空爆炮弹", + "A powerful manned gun emplacement, capable of taking out armored targets at long ranges.": "威力强大的手动炮台,可摧毁远距离装甲目标。", + "Railgun Round": "磁轨炮弹", + "Shield Generator Pack": "防护罩生成包", + "RANGER, BALD EAGLE CLASS": "白头鹰级游骑兵", + "M-102": "M-102", + "Provides #BONUS resistance to fire, gas, acid, and electrical damage.": "获得#BONUS抵御火焰、毒气、酸液以及电击伤害的能力。", + "A stationary ballistic cover with a mounted light machine gun. Can protect multiple Helldivers from small arms fire.": "固定式防弹掩体,架设有轻机枪。可抵挡轻型武器的射击,保护多名绝地潜兵。", + "AD-26 Bleeding Edge": "AD-26“血刃科技”", + "FLASHLIGHT VERTICAL FOREGRIP": "手电筒垂直前握把", + "\"Prowl like a jaguar, strike like a viper.\" -Motto of the storied SEAF special operations unit whose real exploits were portrayed in the classic comic book series \"Tales of the Viper Commandos.\"": "“巡如豹,袭如蛇。”这是传奇超级地球武装部队特别行动组的座右铭。经典漫画《毒蛇突击队的故事》真实描绘了他们的丰功伟绩。", + "In mountainous colonies, domestic variants of this armor are used to throw weather monitoring equipment uphill.": "在山区殖民地,这套盔甲的家用版本是用来把天气监测设备丢到山上的好帮手。", + "INCREASED MAGAZINE CAPACITY": "提升弹匣容量", + "12g MAGNUM": "12g马格南霰弹", + "An agile automated machine gun turret. Will fire at targets even if Helldivers will be caught in the crossfire.": "灵活的自动机枪炮台,即便绝地潜兵在交火期间受伤,它依然会向目标射击。", + "RELOAD DRILLS": "熟练装弹", + "A speed-loaded volley gun with three different firing modes and three different RPM options. Warning: recoil varies significantly between firing modes.": "快速装填的齐射枪,具备三种不同的射击模式,以及三种不同射速选项。警告:不同射击模式之间的后坐力差异巨大。", + "A barrage of high explosive rounds, fired from the Destroyer's high speed rotary autocannons.": "驱逐舰的高速旋转式机炮发射高爆弹,形成火力网。", + "TR-62 Knight": "TR-62“骑士”", + "15x100mm HIGH VELOCITY": "15x100mm高速弹", + "GATLING SENTRY": "加特林哨戒炮", + "DIRECTIONAL SHIELD": "定向护盾", + "STUN EXPLOSION": "眩晕爆炸", + "At Ease": "稍息", + "A fully automatic assault rifle featuring a non-removable suppressor and subsonic ammunition. Slower rounds allow low-profile operation.": "配备不可拆卸消音器和亚音速弹药的全自动突击步枪。弹药速度较低,便于执行隐蔽行动。", + "Beacon of Mercy": "仁慈信标", + "No Attachment": "无配件", + "VISION OF FREEDOM": "自由愿景", + "PODIUM OF PROSPERITY": "繁荣领奖台", + "The SEAF standard pistol - offering a high fire rate, generous capacity, and fast reloading.": "超级地球武装部队制式手枪。射速较高、弹药容量理想,装弹速度也比较快。", + "Domestic versions of this armor enable colonial farmers to plant crops and mines side by side, safely.": "殖民地农民可以购买这套盔甲的家用版本,确保自己和同伴可以紧贴着彼此,安全地种植农作物以及布设地雷。", + "8x60mm SNIPER ARMOR PIERCING": "8x60mm穿甲狙击弹", + "SA-04 COMBAT TECHNICIAN": "SA-04“技术兵”", + "ANTI-TANK EMPLACEMENT": "反坦克炮台", + "PLAS-15": "PLAS-15", + "SC-34 Infiltrator": "SC-34“深入敌阵”", + "Gilded Quill": "镀金羽毛笔", + "Stun Rounds": "眩晕弹", + "G-31": "G-31", + "Data Jack": "数据接口", + "ENGINEERING KIT": "工程包", + "AR-23C": "AR-23C", + "100kg Cluster Bomb": "100KG集束炸弹", + "Focused Prism": "聚焦棱镜", + "ANGLED FOREGRIP": "直角前握把", + "WINGS OF VALOR": "勇气之翼", + "Extraction Beacon": "撤离信标", + "Solid Black": "纯黑", + "An autonomous drone equipped with a laser rifle, providing 360° cover. Returns to backpack to cool down.": "配备激光步枪的自主无人机,可提供全方位掩护。需要冷却时会返回背包。", + "IRON SIGHT": "机械瞄具", + "\"We fear not poison, fear not death; spite our foes with every breath.\" From the beloved classic Hazard Pay: The Musical.": "“我们不惧毒药,不畏死亡;每一次呼吸都让敌人破防”。选自广受喜爱的经典作品音乐剧《危险津贴》。", + "ADDITIONAL CANISTERS": "附加燃料罐", + "B-27 FORTIFIED COMMANDO": "B-27“强化突击兵”", + "A dart-firing pistol. Each of its six rounds administers a gaseous chemical agent, harmful to hostiles whether organic or artificial, that also induces a state of delirium in the target.": "发射飞镖的手枪。其六发飞镖均含有气态化学制剂,对有机或人造敌人都能造成伤害,还会令目标陷入神志不清的状态。", + "12x25mm Explosive": "12x25mm爆炸子弹", + "Heavy Recoil Spring": "重型复进簧", + "The utilitarian sidearm that was standard-issue to the Charan Colonial Guard in the early days of the Galactic Federation. \n\nProduced by ST Construction.": "在星系联邦初期,这种实用的随身武器曾是常陈四拓殖卫队的制式装备。\n\n由ST建筑公司生产。", + "Pinions of Everlasting Glory": "永恒荣耀之羽", + "PER DEMOCRASUM": "于民主", + "Spear Backpack": "飞矛背包", + "2x Support Scope": "2倍支援瞄准镜", + "The Destroyer's laser cannon will sweep over the designated area, vaporizing all targets within the effective radius.": "驱逐舰的激光加农炮扫射指定区域,令效果范围内的目标全数蒸发。", + "Raise Weapon": "高举武器", + "Order of the Venerated Ballot": "神圣投票团", + "8x60mm DEVASTATOR": "8x60mm“毁灭者”子弹", + "SPECIMEN VESSEL": "样本容器", + "IMMOLATION": "焚身", + "DEFENSE WALL": "防御墙", + "STANDARD BARREL": "标准枪管", + "Full Choke": "全喉缩", + "Sterilizer": "灭菌器", + "Bridge": "舰桥", + "A humane compliance weapon with two separate magazines: one for armor-penetrating flechette rounds and one for stun rounds.": "符合人道主义的武器,共有两个独立弹匣:一个装备穿甲飞镖霰弹,另一个装备眩晕弹。", + "EX-16 Prototype 16": "EX-16“原型 16”", + "SHORTER SHOT COOLDOWN": "缩短射击冷却用时", + "9x20mm Toxic": "9x20mm毒弹", + "SCOURGE OF TYRANNY": "暴政克星", + "LIGHT ARMORED VEHICLE": "轻甲载具", + "DEMOCRACY PROTECTS": "民主护佑", + "70mm Laser-Guided Missile": "70mm激光制导导弹", + "1.5x TUBE RED DOT": "1.5倍红点瞄准镜", + "HIGH-SPEED SERVOS": "高速伺服系统", + "OXYGENATOR": "供氧器", + "An Exosuit equipped with a rocket launcher and a gatling gun, offering reliable flexibility against both heavy units and swarms of small targets.": "搭载火箭发射器和加特林机枪的外骨骼装甲,能够可靠灵活地应对重型单位和成群小型目标。", + "Featuring a vibrant, high-visibility pattern to signify the inevitable victory of the Federation. This cape reminds all observers that while the road to Liberty is paved with sacrifice, the \"podium\" at the end is reserved exclusively for the compliant.": "采用鲜艳的高可见度图案,预示联邦必定赢得胜利。它提醒所有观察者:通往自由的道路由牺牲铺就,但尽头的“领奖台”专属于顺民。", + "Orbital Gatling Barrage": "轨道加特林火力网", + "85mm HIGH-EXPLOSIVE GRENADE MK2": "85mm高爆榴弹 MK2", + "Double-Edge Sickle": "双刃镰刀", + "A top-loaded shotgun prominently featured in the final episode of \"Obedient Democracy Support Troopers.\"\nProduced by Martian Armory.": "顶部装弹的霰弹枪,在《民主光环驰援部队》大结局中有突出表现。\n由火星军械库生产。", + "I-102 DRACONAUGHT": "I-102“龙行者”", + "A semi-automatic ceremonial rifle equipped with a bayonet. Can be set to fire in three-shot bursts, to easily conduct the Fallen Hero's Salute.": "配备刺刀的半自动礼仪步枪。可设置为三连发模式,轻松鸣枪致敬陨落的英雄。", + "Wide Prism": "加宽棱镜", + "10g Rifled Slugs": "10g线膛独头弹", + "A cluster fragmentation grenade. The shrapnel submunition allows it to inflict damage over a large area.": "一种集束破片手榴弹。弹片能够在大范围内造成伤害。", + "PURIFYING ECLIPSE": "净化日食", + "8x60mm Subsonic": "8x60mm亚音速弹", + "RESUPPLY": "重新补给", + "A high-caliber rifle with high damage and penetration.": "大口径步枪,拥有超高的伤害和穿透力。", + "CARPET BOMB": "地毯式轰炸", + "CE-35 Trench Engineer": "CE-35“战壕工程师”", + "Larger Canister": "扩容燃料罐", + "DEATH CAPTAIN": "死神少校", + "75mm HEAT GRENADE": "75mm高爆反坦克榴弹", + "More Fuel": "增加燃料", + "HALF CHOKE": "半喉缩", + "Incendiary": "燃烧弹", + "5.5x50mm Hollow-Point": "5.5x50mm空尖弹", + "Proud Gold": "傲金", + "Eagle Napalm Airstrike": "“飞鹰”凝固汽油弹空袭", + "20mm HE CANNON": "20mm高爆炮弹", + "Plasma Igniter Choke": "等离子点火器喉缩", + "Even among the most depraved of dissidents, the mere sight of this armor is enough to inspire a change of heart.": "即使是最顽固的异见分子,只要看到这套盔甲,就会弃暗投明。", + "A quality product, this armor can destroy over 300,000 kilometers of fencing with no decline in operational efficiency.": "即使撞破30万公里的栅栏,这套高品质盔甲的使用效率也丝毫不会下降。", + "Compensator": "补偿器", + "SEAF ARTILLERY: EXPLOSIVE": "超级地球武装部队大炮:炸弹", + "B-04 Developer Of Democracy": "B-04“民主缔造者”", + "UF-16 INSPECTOR": "UF-16“督察员”", + "13x40mm FULL METAL JACKET": "13x40mm全金属被甲弹", + "SG-97": "SG-97", + "No Muzzle": "无枪口配件", + "GALLANT": "英勇无畏", + "An accurate, armor-penetrating rifle, the BR-14 Adjudicator delivers righteous judgement to medium-sized enemies, though its restrictive magazine limits its effectiveness against large groups.": "“审判者”是精准度较高的穿甲步枪,可对中等体型的敌人进行正义审判,但由于弹匣容量有限,对大群敌人的攻击效果也相对受限。", + "B-01 TACTICAL": "B-01“战术”", + "Apex Protector": "巅峰护卫", + "15x100mm THERMITE": "15x100mm铝热弹", + "Blitzer": "雷霆", + "Commemorating the New Stockholm treaty on prisoners of war, this cape celebrates the right of all enemy combatants to a swift and merciful execution.": "该披肩旨在纪念关于战俘的《新斯德哥尔摩公约》,颂扬了敌方战斗人员享有的被迅速、仁慈处决的权利。", + "A drone that defends its user by firing caustic gas at nearby enemies, blinding and slowing them temporarily. Returns to backpack to refill.": "通过向周遭敌人发射腐蚀气体保护使用者的无人机,可使敌人暂时致盲并减速。收回背包可补充气体。", + "Belt-Fed Grenade Launcher Backpack": "弹链式榴弹发射器背包", + "Bearers of this armor ride no equine mount, but are nonetheless borne to battle atop the trusty steed of Liberty.": "穿上这套盔甲后虽然不能骑真正的马,却仿佛驾驭自由精神的良驹奔赴战场。", + "9x20mm RIPPER": "9x20mm撕裂弹", + "12g BUCKSHOT SHELLS": "12g鹿弹霰弹", + "DOMINATOR": "主宰", + "Upgraded Afterburner": "升级后燃器", + "ERGONOMICS": "人体工学性能", + "Liberator Carbine": "“解放者”卡宾枪", + "UF-50 BLOODHOUND": "UF-50“猎犬”", + "BASTION OF INTEGRITY": "忠义堡垒", + "Ultimatum": "最后通牒", + "ORBITAL 120MM HE BARRAGE": "轨道120MM高爆弹火力网", + "Compressed Explosives": "压缩炸药", + "B-16 Battle-Scarred Veteran": "B-16“百战老兵”", + "Longer Arc Range": "扩大电弧攻击范围", + "VOICE OF THE PEOPLE": "人民之声", + "RAIDER'S CHEER": "奇袭者的欢呼", + "NIGHT": "暗夜", + "Shotgun Show": "霰弹枪表演", + "URBAN CAMO": "城市迷彩", + "PATRIOT BLUE": "爱国蓝", + "A modified Liberator fitted with a scope and firing armor-piercing rounds, to help users take down armored targets.": "改装后的“解放者”搭配瞄准镜,可发射穿甲弹,助力使用者击倒装备护甲的目标。", + "A useful field-clearing tool for removing trees, obstacles, and unlucky foes.": "用于清除树木、障碍物和倒霉敌人的实用野外清理工具。", + "Orbital Illumination Flare": "轨道照明弹", + "HMG EMPLACEMENT": "重机枪部署支架", + "SC-34 INFILTRATOR": "SC-34“深入敌阵”", + "A barrage of gas bombs that leave a corrosive gas cloud in their wake.": "连续发射多枚毒气弹,爆炸后形成腐蚀性气团。", + "PILLARS OF DEMOCRACY": "民主之柱", + "Veil of the Valorous Vagabond": "英勇游侠之披纱", + "RECOILLESS RIFLE BACKPACK": "无后坐力炮背包", + "IE-57 HELL-BENT": "IE-57“奋不顾身”", + "FS-23 Battle Master": "FS-23“战斗大师”", + "M7S": "M7S", + "12mm": "12mm", + "A projectile which explodes while airborne, creating a deadly rain of shrapnel. Not effective against heavy armor.": "射弹在空中引爆,而后弹片散落,如同致命的雨点。对重型装甲无效。", + "A machine gun designed for stationary use. Trades higher power for increased recoil and reduced accuracy.": "为固定使用而设计的机枪。提高了火力,但后坐力增加,精准度也降低了。", + "9x70mm Self Propelled": "9x70mm自走弹", + "BREAKTHROUGH EXOSUIT": "“突破”外骨骼装甲", + "Anti-Tank Emplacement": "反坦克炮台", + "Each servo-assisted limb contains 138 miniature motors, to support a natural gait and long-term spinal health.": "各伺服辅助肢体包含138个微型马达,以实现自然步态,从长远角度保障脊柱健康。", + "SCYTHE": "长柄镰", + "Rail Cannon Round": "轨道炮弹", + "RS-67 NULL CIPHER": "RS-67“空密码”", + "MIRANDA'S LEGACY": "米兰达的遗志", + "BP-77 Grand Juror": "BP-77“大陪审员”", + "A flare that illuminates the battlefield.": "可以照亮战场的照明弹。", + "Urchin": "海胆", + "Upon initial impact, the deployer scatters a wide field of proximity-detonated submunitions. These charges deal minimal damage, but will heavily stun and decelerate encroaching hostiles.": "刚落地时,部署器会撒布大片近炸子弹药场。这些炸药造成的伤害极小,但能对逼近的敌军产生强力眩晕和减速效果。", + "Shear": "切变", + "SHOCK AND AWE IMPROVEMENT": "提高震慑威力", + "CE-74 Breaker": "CE-74“破裂者”", + "INCENDIARY IMPACT": "燃烧冲击弹", + "Dagger": "匕首", + "A replacement for a fallen comrade.": "阵亡战友的替补兵员。", + "MARTYRIS REX": "殉道之王", + "AGAINST THE TYRANT CLOUD": "破除暴瘴", + "REDEEMER": "救世主", + "United in Equality": "仰齐与共", + "UPLOAD DATA": "上传数据", + "TRUTH WHISPERER": "真理低诉者", + "A targeted air strike unable to destroy buildings, but efficient at clearing smaller targets.": "定向空袭,无法摧毁建筑,但可以有效清除较小型目标。", + "Way of the Bandolier": "弹带之道", + "FLAK": "高射炮弹", + "R-4": "R-4", + "Lean": "清瘦", + "Provides one-time, short-lived resuscitation upon death, given that the Helldiver's body is still intact.": "在绝地潜兵躯体完好的前提下,死亡后可获得一次短暂的复活机会。", + "Larger Magazine": "扩容弹匣", + "Tip Hat": "脱帽致意", + "A laser rifle, firing in short bursts. Does not need reloading, but if it overheats a new heat sink must be fitted.": "可瞬间喷射高能激光束的激光步枪。无需重新装弹,但如果步枪过热,必须安装新的散热器。", + "PURIFIER": "净化者", + "CQC-73": "CQC-73", + "MD-8": "MD-8", + "P-113": "P-113", + "Higher Missile Damage": "提升导弹伤害", + "ARC-12": "ARC-12", + "Crisper": "迅击", + "Advanced Vertical Foregrip": "高级垂直前握把", + "LAS-7": "LAS-7", + "VERIDICAL IDEOLOGY": "真理意识形态", + "AR-59": "AR-59", + "A single-use weapon sporting caseless ammunition stacked in multiple barrels. An electrical firing mechanism releases the rounds in rapid succession upon firing, after which the weapon is to be discarded.": "采用无壳弹药与多枪管叠加设计的一次性武器。开火时,电控击发装置会快速清空弹药,弹药清空后即可丢弃该武器。", + "Orbital EMS Strike": "轨道电磁冲击波攻击", + "Tighter Breech Lock": "收紧枪闩锁", + "Creates a #BONUS chance of surviving a lethal hit.": "在受到致命一击后有#BONUS的几率存活。", + "SHOTGUN SHOW": "霰弹枪表演", + "SEAF Squad": "超级地球武装小队", + "A paint job for use in arctic environments.": "适用于雪地环境的涂装。", + "A submachine gun with an extremely high rate of fire, which can be operated with one hand. Ideal for multitasking.": "射速极高的冲锋枪,可单手操控。同时处理多重任务时的理想之选。", + "The breathing apparatus built into this equipment helps both soldiers and colonists thrive, even when assigned to planets with atmospheres rated \"suboptimal,\" \"extreme,\" and \"character building.\"": "这套装备的内置呼吸装置能帮助士兵和拓殖地居民畅快呼吸,即使被派往评级为“次优”、“恶劣”和“磨练性格”的星球也应付自如。", + "Shorter Recharge Delay": "缩短充能延迟", + "The dauntless pioneers of the Great Expansion, facing the un-Democratic unknown, adopted the Way of the Bandolier. With the gusto of their covering fire making up for their modest accuracy, they strived to be perfectly aligned in their shared values, and ready to serve when called upon by the machine gun of civic duty.": "面对尚未民主化的未知世界,大扩张时期的无畏先驱者践行弹带之道。他们用狂热的火力掩护弥补射击准度的不足,奋力追求共同价值观的完美统一,并时刻响应公民责任机枪的召唤,随时准备投身战斗。", + "A-9 Helljumper": "A-9“地狱伞兵”", + "SA-12 Servo-Assisted": "SA-12“伺服辅助”", + "STOCKED HELLPODS": "备量充足的喷射舱", + "CQC-1": "CQC-1", + "CQC-19": "CQC-19", + "70mm Standard Rocket": "70mm标准火箭弹", + "12g TRI-BALL": "12g三连弹", + "Command Center of the Super Destroyer. The helm from which Helldivers deliver Freedom's mercy.": "超级驱逐舰的指挥中心,绝地潜兵通过这个船舵传递自由精神的仁慈。", + "Stocked Hellpods": "备量充足的喷射舱", + "AF-91 Field Chemist": "AF-91“实地化学家”", + "AR-32": "AR-32", + "8x60mm SUPER URANIUM CORE": "8x60mm超铀芯弹", + "FOREST CAMO": "森林迷彩", + "URCHIN": "海胆", + "Drilling Charge": "强钻炸药", + "CE-64 GRENADIER": "CE-64“掷弹兵”", + "9x20mm TOXIC": "9x20mm毒弹", + "COURTLY BOW": "恭敬鞠躬", + "ANTI-TANK MISSILES": "反坦克导弹", + "EAGLE AIRSTRIKE": "“飞鹰”空袭", + "This vision-disruptive pattern cloaks the silent crusaders whose untraceable deeds are a pure expression of true Freedom: freedom from accountability.": "这种干扰视觉的图案能够有效掩护寂静无声的圣战士,他们难以捉摸的行踪纯粹地展现了真正的自由,即免责的自由。", + "12g Flechettes": "12g飞镖弹", + "INDEPENDENCE BRINGER": "独立先驱", + "Smoke": "烟雾弹", + "Training Maneuvers": "军事演习", + "G-23": "G-23", + "ROUNDS RELOAD": "逐发装弹", + "DEFAULT HELLDIVER VOICE 2": "绝地潜兵默认声音 2", + "GS-66 Lawmaker": "GS-66“立法者”", + "A LAS-16 Sickle model with all overheating protections conveniently removed, allowing for far longer bursts of fire. Does more damage when overheated, at the cost of slightly burning the user.": "移除所有过热保护机制的LAS-16“镰刀”型号,显著延长连射时间。 过热时会造成更大伤害,但会轻微灼伤使用者。", + "STUN ROUNDS": "眩晕弹", + "12x25mm PLASMA": "12x25mm等离子弹", + "SIEGE-READY": "蓄势出击", + "O-2 Heavy Operator": "O-2“重装操作者”", + "A Dark Fluid-powered backpack that generates a portable micro-wormhole. This safe and well-understood technology allows the wearer to warp short distances. Warning: do not use while pack is overloaded.": "暗液体驱动的背包,可生成便携式微型虫洞。这项安全且成熟的技术可助使用者进行短距离传送。警告:背包过载时请勿使用。", + "SR-64 Cinderblock": "SR-64“煤渣砖”", + "Laser Sight Angled Foregrip": "激光瞄准器与直角前握把", + "12x25mm Full Metal Jacket": "12x25mm全金属被甲弹", + "Wide Spread": "扩散", + "Cresting Honor": "荣誉之巅", + "A representation of the thankfulness of those infinite descendants whose liberated existence we strive to ensure.": "我们竭尽全力让无数后代过上解放的生活,而这代表了他们的感激之心。", + "An angled vertical foregrip to improve the maneuverability of the weapon.": "直角垂直前握把,可提升武器操控性。", + "INCREASED FIRE RATE": "提升射速", + "Enthusiastic Mirth": "开怀大笑", + "5.5x50mm Penetrator": "5.5x50mm穿甲弹", + "A submachine gun with a longer barrel, allowing for higher muzzle velocity and increased armor penetration.": "配备加长枪管的冲锋枪,枪口初速更高且具备更强的护甲穿透能力。", + "\"The Helldivers are all that stand between Democracy and the Fascist hordes. Trained since birth in the art of Defensive Warfare, they meet mindless legions with the steady aim of one who has seen countless battles.\" —Excerpt from the journal of a Charan Democracy Officer, ca. 2082 SE": "“绝地潜兵是阻挡在民主与法西斯暴民之间的唯一屏障。他们自出生起就接受防御战争的训练,以久经沙场的沉稳精准迎击无脑军团。”——摘自常陈四民主官日记,超级地球历2082年前后", + "More Backpack Ammo": "增加备用弹药", + "DIGNITY OF TOIL": "劳作的荣光", + "EMANCIPATOR EXOSUIT": "“解放者”外骨骼装甲", + "In field tests, 84% of users said that the armor improved their posture and self-esteem.": "实地测试中,有84%的使用者表示此盔甲改善了他们的体态,也提升了他们的自尊心。", + "CREST OF THE UNSULLIED": "无垢徽章", + "B-02 GLOOM WARDEN": "B-02阴霾守望者", + "STANDARD ISSUE": "标准制式", + "Composed of reclaimed industrial mesh and salvaged banners. This cape celebrates the beauty found in the aftermath of purging Tyranny at high-speeds. The debris of these successes, and those like it, remind us all of the sanctity of Sovereignty.": "由回收的工业网格和残破旗帜组成。这件披肩赞美了疾速肃清暴政后产生的美感。这些成功的残骸提醒所有人:主权神圣不可侵犯。", + "SHIELD GENERATOR RELAY": "防护罩生成中继器", + "A heavy one-handed blade. Slower to swing than other melee weapons, but deals more damage.": "沉重的单手刀。挥舞速度比其他近战武器慢,但造成的伤害更高。", + "CURTSY": "屈膝礼", + "FLASHIELD": "闪光护盾", + "BOTSLAYER": "机械屠戮者", + "A symbol of Super Earth's Astral Promise: that every star shall one day illuminate throngs of joyous voters.": "超级地球星之承诺的象征:终有一日,每一颗星都将因快乐的选民而闪亮。", + "RE-1861 PARADE COMMANDER": "RE-1861“阅兵指挥官”", + "Incendiary Impact": "燃烧冲击弹", + "DOUBLE MACHINEGUN POD": "双机枪喷射舱", + "Sidearm recoil reduced by #BONUS.": "副武器后坐力降低#BONUS。", + "STICKY": "粘性", + "Commonly replicated in stage adaptions of \"Lady Liberty's Tower\", in which young Diver Beatrick dons this armor to slay Oppressio, the Tyrant Rex.": "这套盔甲常见于《自由女神塔》的舞台剧版本,剧中年轻的绝地潜兵比特里克正是身着这套盔甲,斩杀暴君王奥普雷西奥。", + "FIRE MODES": "开火模式", + "STILL STANDING": "屹立不倒", + "Eagle Airstrike": "“飞鹰”空袭", + "SMOKESCREEN": "烟幕", + "100kg Bomb": "100KG炸弹", + "Clapping": "鼓掌", + "Although Super Citizen Miranda's true identity has been lost to time, most legal historians agree that she was once a patron of highly-efficient interrogation techniques.": "尽管超级公民米兰达的真实身份已被时间湮没,但大多数法律史学家一致认为,她曾是高效审讯技术的赞助人。", + "HONORED HEIRLOOM": "荣耀传家宝", + "This armor was designed by PFC Rodney A. Carmichael, the first Helldiver to use a stim on an ally instead of himself.": "此盔甲由一等兵罗德尼·A.·卡迈克尔设计,他是首位将治疗剂用在队友身上(而不是自用)的绝地潜兵。", + "AUTOCANNON BACKPACK": "机炮背包", + "Fires powerful exploding bolts which do maximum damage upon direct impact. Gravity must be accounted for when aiming.": "发射威力强大的爆炸弩箭,对直接命中的目标造成最大伤害。瞄准时必须考虑重力因素。", + "Bushwhacker": "游击兵", + "HELL COMMANDER": "地狱上尉", + "9x20mm PLASMA": "9x20mm等离子弹", + "SR-64 CINDERBLOCK": "SR-64“煤渣砖”", + "Increased Magazine Capacity": "提升弹匣容量", + "A grenade launcher that can be fired continuously to deliver a nonstop barrage of explosives.": "可持续射击的榴弹发射器,能够不间断地倾泻火力。", + "Improved Ammo Storage Mk2": "弹药存储量升级 MK2", + "GUARD DOG": "“护卫犬”", + "CW-36 Winter Warrior": "CW-36“冬日战兵”", + "SHORT MAGAZINE": "短弹匣", + "EXO-55": "EXO-55", + "FS-37 RAVAGER": "FS-37“破坏者”", + "STANDARD PRISM": "标准棱镜", + "PROSPEROUS GREEN": "繁荣绿", + "40mm HE Grenade": "40mm高爆榴弹", + "PUNISHER PLASMA": "等离子“制裁者”", + "P-35": "P-35", + "IMPROVED TARGETING SYSTEM": "改良目标锁定系统", + "PH-9 Predator": "PH-9“掠食者”", + "#NAME #TYPE": "#NAME#TYPE", + "When donning the One True Flag, one must face the direction of Super Earth, recite the Super Earth Anthem, and salute one's own image in the nearest reflective surface. Wrongful discarding of this cape is a capital offense.": "身披这件印有“唯一真旗”的披肩时,必须面朝超级地球,唱响超级地球国歌,并向最近反光面中的自己敬礼。错误丢弃此披肩者,罪当处死。", + "A paint job for use in forest environments.": "适用于森林环境的涂装。", + "Orbital 120mm HE Barrage": "轨道120mm高爆弹火力网", + "CQC-72": "CQC-72", + "IE-12 Righteous": "IE-12“义士”", + "Let the Second Anniversary of the Second Galactic War be witnessed by the lidless eye of Liberty, that ever-watchful orb which provides safety through its ceaseless surveillance.": "自由之眼永不阖目,它将见证第二次星系战争进入两周年,并通过无休止的监视为我们提供安全。", + "ROUNDS": "弹药", + "SMG-72": "SMG-72", + "A holographic sight.": "全息瞄准镜。", + "Resupply": "重新补给", + "DEEP REFLECTION": "沉思", + "Carpet Bomb": "地毯式轰炸", + "After extensive testing in Patriotic Rehabilitation Centers, this design was proved most terrifying to dissent-afflicted individuals.": "爱国康复中心的详尽测试证明,这是最令异见分子感到恐惧的设计。", + "Gas Mortar Sentry": "瓦斯迫击哨戒炮", + "SSSD DELIVERY": "运送超级固态硬盘", + "Creates a large, thick smoke screen to block targets' line of sight.": "可形成一道厚重的大型烟幕,遮挡目标的视线。", + "CB-9": "CB-9", + "HEAVY MACHINE GUN": "重机枪", + "Designed by fashion legend RH Gant, the pattern seen on this cape also appears on domestic dresses and gun-warmers.": "由时尚传奇RH·甘特设计,披肩上的图案同时也用于家居服和暖枪套。", + "ADDITIONAL ROCKET PODS": "附加火箭巢", + "HIGH DISSIPATION HEATSINK": "高功率散热器", + "LAS-16": "LAS-16", + "Plasma Igniter Compensator": "等离子点火器补偿器", + "Immolation": "焚身", + "5.5x50mm Super Uranium Core": "5.5x50mm超铀芯弹", + "TM-1": "TM-1", + "P-2": "P-2", + "STUN BATON": "眩晕短棍", + "66mm Missile": "66mm导弹", + "VIPER COMMANDO": "毒蛇突击兵", + "The symbol on this cape represents the pillars of freedom: duty, obedience, and loyalty.": "披肩上的标志象征着自由的三大支柱:责任、服从、忠诚。", + "Additional Canisters": "附加燃料罐", + "COLONY SAVIOR": "拓殖地救星", + "LARGER SHIELD": "延展护盾", + "G/SH-39": "G/SH-39", + "MAX RANK INFINITY": "无限最高等级", + "Fire Rate Selection": "可选射速", + "JUDGMENT DAY": "审判日", + "De-Escalator": "缓和使者", + "Gallant": "英勇无畏", + "Rags of the Fashionable": "时尚褴褛", + "AF-52 LOCKDOWN": "AF-52“禁锢”", + "CREW TRAINING": "船员训练", + "ELECTRICAL CONDUIT": "电路导管", + "This modest cape has been worn by those guarding the Chamber of Unanimous Decision since time immemorial.": "这件简朴的披肩自古便由统一决策大厅的守卫佩戴。", + "5.5x50mm Devastator": "5.5x50mm“毁灭者”子弹", + "BADGE OF ORDER": "秩序徽章", + "5.5x50mm Double Power": "5.5x50mm双效子弹", + "SHRAPNEL": "榴霰弹", + "BP-20 CORRECT OFFICER": "BP-20“思想矫正官”", + "PROGRAMMABLE AMMUNITION": "智能弹药", + "DS-191 SCORPION": "DS-191“天蝎”", + "SA-25 STEEL TROOPER": "SA-25“钢铁士兵”", + "9x70mm Full Metal Jacket": "9x70mm全金属被甲弹", + "SEAF ARTILLERY: HIGH-YIELD EXPLOSIVE": "超级地球武装部队大炮:高爆弹", + "110mm E.M.S. CANNON ROUND MK3": "110mm电磁冲击波炮弹 MK3", + "5.5x50mm Subsonic": "5.5x50mm亚音速弹", + "COMBAT BLEND": "混合作战", + "12g MAGNUM TRIBALL": "12g马格南三连弹", + "Anti-tank Mines": "反坦克地雷", + "RELOAD TIME": "装弹时间", + "UF-84 Doubt Killer": "UF-84“疑虑克星”", + "Coyote": "野狼", + "CREMATOR BACKPACK": "焚燃者背包", + "Durable, waterproof, and thermally-lined, surplus units of this cape are favored by domestic campers, to make tents.": "耐用、防水,搭配保暖内衬,这款披肩的剩余布料也受到了国内露营爱好者的青睐,用于制作帐篷。", + "WEDGEFUL TRICORN": "楔形三角披肩", + "Recoilless Rifle Backpack": "无后坐力炮背包", + "M6C/SOCOM": "M6C/特种作战", + "12g BUCKSHOT MAGNUM SHELLS": "12g鹿弹马格南霰弹", + "PYTHON COMMANDO": "蟒蛇突击兵", + "Foesmasher": "歼敌战士", + "Stuns enemies performing melee attacks. Must recharge for #BONUS.": "眩晕发动近战攻击的敌人。必须充能#BONUS。", + "CM-10 CLINICIAN": "CM-10“临床医师”", + "One True Flag": "唯一真旗", + "Tideturner": "力挽狂澜", + "Recoilless Rifle": "无后坐力炮", + "66mm MISSILE": "66mm导弹", + "DEFAULT TRIGGER": "默认扳机", + "Orbital Walking Barrage Smoke": "轨道游走烟雾火力网", + "Covering Fire": "火力掩护", + "Cookout": "野炊", + "A powerful automated turret, effective against armored targets. The turret will primarily aim at larger enemies.": "强力自动炮台,可有效对付装甲目标。炮台主要瞄准攻击较大型的敌人。", + "TD-220": "TD-220", + "Flex": "炫耀", + "Honored Heirloom": "荣耀传家宝", + "9x70mm Super Uranium Core": "9x70mm超铀芯弹", + "High Explosive": "高爆弹", + "9x20mm Plasma": "9x20mm等离子弹", + "MUDSKIPPER": "弹涂鱼", + "FS-40 Diplomat": "FS-40“外交官”", + "Developed by the Ministry of Science while investigating the phenomenon known as The Gloom, this armor is non-permeable and squeak resistant.": "科学部在调查“阴霾”现象时研制而成,该盔甲防渗透性佳,穿上后也不会吱吱作响。", + "Diplomatic Handshake": "外交礼节式握手", + "Cover of Darkness": "黑夜守护", + "\"Where lesser soldiers break, Helldivers obey. When Tyranny's horrors swarm, Helldivers obey. When death is certain, and hope and sense have fled, Helldivers obey.\" — Last Lord Governor of Chara.": "“寻常士兵溃不成军之时,绝地潜兵谨遵号令。暴政恐怖肆虐之际,绝地潜谨遵号令。当死亡已成定局、希望与理智破灭,绝地潜兵谨遵号令。”——常陈四最后一任总督。", + "UNBLEMISHED ALLEGIANCE": "无瑕忠诚", + "Shrapnel": "榴霰弹", + "Provides a higher armor rating.": "提供较高的盔甲等级。", + "SG-8S": "SG-8S", + "B-100": "B-100", + "Napalm Bomb Mk3": "凝固汽油弹 MK3", + "Features a utility belt with pockets that can be filled with any number of things, such as pocket knives, mementos from home, and interesting rocks.": "配有带口袋的实用腰带,可装入各式各样的物品,如便携刀具、家乡的纪念品和有意思的石头。", + "JAR-5": "JAR-5", + "I-09 HEATSEEKER": "I-09“热力追踪”", + "ORDER OF THE VENERATED BALLOT": "神圣投票团", + "A backpack which can be wielded as a one-handed ballistic shield, protecting against small arms fire.": "可用作单手防弹护盾的背包,能抵挡轻型武器的射击。", + "DETONATE": "引爆", + "This patriotic armor comes recommended by the Ministry of Expansion, empowering the wearer to re-seize from our enemies any territory that any human has laid claim to, at any point in time.": "扩张部强烈推荐这款宣扬爱国主义的装甲,它将赋予穿戴者力量,帮助他们从敌人手中夺回人类在各历史时间节点曾宣称主权的领土。", + "SA-04 Combat Technician": "SA-04“技术兵”", + "EAGLE NAPALM AIRSTRIKE": "“飞鹰”凝固汽油弹空袭", + "Designed in homage to the triangle—the most immovable of shapes—this cape digs its heels into the eye of the observer, leaving a lasting impression.": "这款披肩的设计致敬了三角形这一最稳固的几何形状,以其坚定不移的姿态直击观者眼球,留下深刻印象。", + "AD-11 LIVEWIRE": "AD-11“生龙活虎”", + "DRAPE OF GLORY": "荣光加身", + "The three stripes on the pauldrons stand for the three principles of Super Earth: Liberty, Democracy, and Prosperity.": "护肩上的三条纹象征着超级地球的三大原则:解放、民主与繁荣。", + "It is well-documented that soldiers raised on harsh planets have an advantage when fighting in similar environments; this insight is foundational to the Democratic Youth Scouts Exchange Program.": "有充分记录表明,在恶劣星球上成长的士兵在类似环境中作战时具有优势。这样的洞察为民主青少年童子军交流计划奠定了基础。", + "This cape recalls the popular folk tale of the \"Freedomslingers\": re-educated dissidents, seeking redemption on the Federation's Borderline, hunting dangerous thought-traitors in exchange for ballot bounties.": "这件披肩让人想起民间广为流传的“自由神枪手”的故事:接受过再教育的异见分子在联邦边境线上寻求救赎,通过追捕危险的思想叛徒换取选票赏金。", + "A modern reinvention of the Lumberers of the first Galactic War, this Exosuit is equipped with a flamethrower and an anti-tank cannon.": "这款外骨骼装甲是第一次星系战争中“伐木者”机甲的现代重制版,配备火焰喷射器和反坦克炮。", + "Scrambler": "扰频器", + "TYRANNY'S BANE": "暴政的毁灭", + "Reprimand": "训斥", + "SG-20": "SG-20", + "MARSHAL": "元帅", + "EAGLE GAS AIRSTRIKE": "“飞鹰”毒气空袭", + "Featuring an ancient sun symbol and a distressed look, this cape reminds us that the light of Liberty is everlasting, and will keep shining even when we ourselves have become tattered and frayed.": "这件破旧的披肩饰有古老的太阳符号,提醒我们自由之光永存不灭,即使我们自身变得残破不堪,它也将继续闪耀。", + "Default Helldiver Voice 1": "绝地潜兵默认声音 1", + "BP-32 Jackboot": "BP-32“杰克军靴”", + "BLAST RADIUS": "爆炸半径", + "RE-824 BEARER OF THE STANDARD": "RE-824“执旗手”", + "ADJUDICATOR": "审判者", + "MORE AMMO IN BACKPACK": "增加背包弹药数量", + "SCRAMBLER": "扰频器", + "The memory of the Martian training grounds will endure, even after all the Helldivers who trained there have passed, some day in the far future.": "即使在遥远的未来,所有曾在火星训练场接受训练的绝地潜兵都已逝去,关于那里的记忆也永远不会褪色。", + "VARIABLE": "变数", + "CAUSTIC": "腐蚀气体", + "An automated turret that fires gas shells. Its targeting system prioritizes hostiles not yet exhibiting symptoms caused by gas inhalation. Users are advised to stay significantly upwind of the resulting crowd control.": "一种发射毒气弹的自动炮塔。其瞄准系统优先锁定尚未中毒的敌对目标。使用者应保持上风方位,避免被群体控制影响。", + "NEW EXPLOSIVE FILLER": "新式爆炸物填料", + "Named for Helldiver Jack Boote, who shut down 908 illegal broadcasts before retiring with honors.": "以绝地潜兵杰克·布特命名,他在光荣退役前曾查封了908个非法广播。", + "As documented in the bestselling graphic novel \"The Breach,\" the final mission of the 361st \"Freedom's Flame\" saw the storied unit deploy straight into the heart of a Supervolcano, sacrificing themselves to trigger an eruption and wipe out a massive Terminid swarm.": "根据畅销图像小说《突破》的描述,大名鼎鼎的361“自由烈焰”部队最后一次执行的任务是直接部署到超级火山的核心地带,英勇地牺牲自我,引发火山喷发,消灭数量庞大的终结族虫群。", + "LIBERATOR PENETRATOR": "穿甲“解放者”", + "ANTI-AIR MISSILE": "防空导弹", + "A modified Breaker shotgun firing incendiary projectiles. Generates heat during use, so limited to burst fire.": "改良后的“破裂者”霰弹枪,可发射燃烧弹。在使用过程中会产生热量,因此会限制连发射击。", + "A modified Liberator firing concussive rounds which do less damage but stagger enemies.": "改良版“解放者”,可连续发射震荡弹。虽然造成的伤害不大,但可击退敌人。", + "Pillar of the Abyss": "深渊支柱", + "12g Magnum": "12g马格南霰弹", + "STINGER": "毒刺", + "FLECHETTES": "飞镖弹", + "Expendable Anti-Tank": "消耗性反坦克武器", + "Voice of the People": "人民之声", + "13x40mm RIPPER": "13x40mm撕裂弹", + "FS-61 Dreadnought": "FS-61“无畏”", + "TIDETURNER": "力挽狂澜", + "A magazine with a very high capacity at the cost of being bulky and heavy.": "该弹匣的弹药容量极大,但较笨重。", + "Seeker": "寻踪者", + "A single-use weapon that fires a missile containing napalm cluster bombs that release upon impact.": "一次性武器,发射的导弹会在撞击时释放凝固汽油集束炸弹。", + "Frag": "破片弹", + "Standard Plasma Container": "标准等离子弹药匣", + "BASTION MK XVI": "堡垒MK XVI", + "PRIVATE": "列兵", + "CAMO CLOAK": "迷彩斗篷", + "Thumper": "桩锤", + "Independence Bringer": "独立先驱", + "EAT-700": "EAT-700", + "A/LAS-98": "A/LAS-98", + "Cluster Bomb": "集束炸弹", + "SUPPRESSED": "消音", + "MED-KIT": "急救包", + "HE MK2": "高爆弹 Mk2", + "Programmable Ammunition": "智能弹药", + "Flamethrower": "火焰喷射器", + "CAPACITY": "容量", + "LARGE AMMO-DRUM": "大容量弹鼓", + "CPG-48 SAPPER": "CPG-48“工兵”", + "DEFAULT HELLDIVER VOICE 1": "绝地潜兵默认声音 1", + "POSTERITY'S GRATITUDE": "后族怀恩", + "IMPROVED SERVOS": "改良伺服系统", + "30mm APHE CANNON": "30mm穿甲高爆炮弹", + "10g Tri-Ball": "10g三连弹", + "Users are advised not to scratch at the lacquer, as the Red 20,000 pigment that gives this armor its signature sheen may be correlated with rapid DNA unspooling.": "赋予盔甲标志性光泽的红色20,000颜料恐会导致DNA快速解旋,建议用户不要划伤漆面。", + "20mm Flak Rounds": "20mm高射炮弹", + "EXEMPLARY SUBJECT": "模范试验体", + "An advanced angled foregrip to improve weapon stability.": "高级直角前握把,可提升武器稳定性。", + "A shorter magazine with lower capacity, making it lighter and easier to handle.": "弹药容量较小的短弹匣,重量更轻,操控更方便。", + "12x25mm EXPLOSIVE": "12x25mm爆炸子弹", + "WIDE PRISM": "加宽棱镜", + "12.5mm BCHP RIFLE ROUNDS": "12.5mm粘合弹芯空尖弹", + "LASER SIGHT ANGLED FOREGRIP": "激光瞄准器与直角前握把", + "Inside the collar is embroidered: \"Wherever I may plant my shield, know that I will never yield,\" and \"machine washable.\"": "衣领内侧绣有“无论护盾所立何方,我绝不会屈膝投降”和“可机洗”字样。", + "Censor": "审查官", + "Courtly Bow": "恭敬鞠躬", + "MANTLE OF TRUE CITIZENSHIP": "忠诚公民之斗篷", + "10g DUAL SABOT": "10g双萨博特式霰弹", + "A Hellpod containing a Super Solid State Drive, the peak of secure data storage. Used by Helldivers for everything from transfer of patriotic data to the sabotage of enemy mainframes.": "装有最为安全的数据存储,超级固态硬盘的绝地喷射舱。从传输爱国数据到破坏敌人主机,绝地潜兵将其用于各种用途。", + "LIFT-850": "LIFT-850", + "MEDIUM PLASMA BOLT": "中型等离子弹", + "ONE-HANDED": "单手操作", + "8x60mm High Velocity": "8x60mm高速弹", + "The muted colors and relaxed, high-mobility fit make this a favorite among long-distance snipers and hide-and-seek champions alike.": "这套装备还采用暗沉色调与宽松灵活的版型,深受远程狙击手和潜行高手的喜爱。", + "A smoke grenade that rapidly deploys a small, dense cloud. Allows for rapid personal concealment and exfiltration.": "快速在小范围内释放高密度烟雾的烟雾弹。有助于隐蔽个人行踪和掩护撤离行动。", + "Flames Mk2": "喷射火焰 MK2", + "Better Racks": "提高挂架质量", + "12.5mm BCHP Rifle Rounds": "12.5mm粘合弹芯空尖弹", + "This armor uses repurposed metal from verified sources, such as vending machine packaging and Automaton scrap, making it a sustainable choice for the environmentally conscious Helldiver.": "这套盔甲采用来源经核实的回收金属材料,如自动售货机外壳和机器人废料,是具有环保意识的绝地潜兵的可持续之选。", + "O-3 FREE SPIRIT": "O-3“自由之魂”", + "SCORCHER": "焦土", + "SA-7 HEADFIRST": "SA-7“冲锋者”", + "Maxigun": "重装机枪", + "BREAKER BUGBITER": "噬虫“破裂者”", + "Advanced Angled Foregrip": "高级直角前握把", + "15x100mm PLASMA": "15x100mm等离子弹", + "ORBITAL EMS STRIKE": "轨道电磁冲击波攻击", + "KDM-763 Pacesetter": "KDM-763“领跑者”", + "Flame Sentry": "火焰喷射哨戒炮", + "AR-2": "AR-2", + "12MM": "12MM", + "Commando": "突击兵", + "Extra Backpacks": "额外补给", + "Thundering Hooves of Loyalty": "忠诚惊雷之蹄", + "CE-67 Titan": "CE-67“泰坦”", + "ORBITAL GATLING BARRAGE": "轨道加特林火力网", + "SR-18 Roadblock": "SR-18“路障”", + "Pillars of Democracy": "民主之柱", + "MGX-42": "MGX-42", + "StA-52": "StA-52", + "B-01 Tactical": "B-01“战术”", + "FASTER DEPLOY TIME": "缩短部署用时", + "DS-42 FEDERATION'S BLADE": "DS-42“联邦之刃”", + "A sledgehammer that can be wielded with or without an explosive charge attached to its head.": "大锤头部可安装炸药,也可单独使用。", + "PH-202 Twigsnapper": "PH-202“折枝”", + "DP-8 Mountain-Scaled": "DP-8“山峦鳞甲”", + "Wedgeful Tricorn": "楔形三角披肩", + "Flames": "喷射火焰", + "Improved Durability": "提升耐久度", + "JUSTICE FOR ALL": "全民正义", + "INTEGRATED EXPLOSIVES": "集成炸药", + "COVER OF DARKNESS": "黑夜守护", + "110mm GAS CANNON ROUND": "110mm毒气炮弹", + "The understated color scheme and precision-molded armor plates make this armor a sensible choice for the Helldiver on the go.": "精密铸造的护甲板加上低调的配色,这套护甲是绝地潜兵在配置行动装备时的明智之选。", + "An automated flamethrower turret. Warning: fuel canister prone to explosion when ruptured.": "自动火焰喷射器炮台。警告:燃料罐破裂时易爆炸。", + "Made famous by the \"Truth Enforcers: Enforcers of Truth\" mystery novels, this armor calls to mind those paragons of patriotism who protect us from treasonous lies.": "这套盔甲因《真理执行者:真理的执行者》悬疑小说而闻名,让人想起那些保护我们免受叛国谎言蛊惑的爱国典范。", + "Heavy Machine Gun": "重机枪", + "A combination assault rifle/grenade launcher. Versatile, but heavy to wield.": "突击步枪与榴弹发射器的组合武器。用途广泛,但比较像重型武器的操控手感。", + "CHIEF": "军督", + "Markers placed on the map will generate radar scans every #BONUS.": "地图上的标记每隔#BONUS进行一次雷达扫描。", + "8x60mm Devastator": "8x60mm“毁灭者”子弹", + "STOKER": "司炉者", + "More Rounds": "增加弹药", + "VEIL OF THE VALOROUS VAGABOND": "英勇游侠之披纱", + "A very powerful but difficult-to-wield machine gun with intense recoil.": "火力凶猛的机枪,但后坐力强,较难操控。", + "A single-use weapon specialized for damaging vehicle armor. Discarded after every use.": "专门破坏载具装甲的一次性武器。用后即弃。", + "10-STAR SUPER PRIVATE": "十星超级列兵", + "9x70mm PENETRATOR": "9x70mm穿甲弹", + "Flashlight": "照明", + "DIPLOMATIC HANDSHAKE": "外交礼节式握手", + "Larger Search Radius": "扩大搜索半径", + "TRIANGULATION VEIL": "三角定位披纱", + "ANTI-AIR": "防空", + "StA-X3": "StA-X3", + "MELTA MINE": "热熔地雷", + "The cape's shredded hem presages the unrelenting savagery its wielder will visit upon the nemeses of Freedom.": "此披风的碎边预示着穿戴者将对自由死敌发动无情蛮攻。", + "SHIELD": "盾雷", + "MORE DURABLE CHASSIS": "提升底盘耐久度", + "A variation on the reflex sight.": "改良版反射式瞄准镜", + "Upload Data": "上传数据", + "Eagle Smoke Strike": "“飞鹰”烟雾攻击", + "DILIGENCE COUNTER SNIPER": "反狙击“勤勉”", + "Laser Cannon": "激光大炮", + "The crest on this armor's shoulder shows friendlies that safety is near, and foes that they have reached the end of the road.": "盔甲肩部的徽章向友军传递安全已近在咫尺的信息,同时向敌人宣告它们已走投无路。", + "40mm FLAK CANNON": "40mm高射炮弹", + "This armor, coated in radar-absorbent polymers and a null-signature heat baffle, reportedly turns its wearer into a sensor ghost—a claim attributed to individuals who, curiously, appear to have never existed.": "盔甲的外层是雷达吸波聚合物和匿迹热隔板,据称能让穿戴者变成传感器探测不到的幽灵,有趣的是,如此声称的人似乎从未存在过。", + "EXPENDABLE ANTI-TANK": "消耗性反坦克武器", + "Ranger": "游骑兵", + "A projectile which releases a cloud of caustic gas, blinding and slowing most enemies.": "释放腐蚀性气团的射弹,可使大多数敌人致盲并减速。", + "CM-06 Combat Medic": "CM-06“医疗兵”", + "ADVANCED FILTRATION": "高级过滤能力", + "Breaker": "破裂者", + "A camo paint job for use in desert environments.": "适用于沙漠环境的迷彩涂装。", + "The CW-22 Kodiak armor was thoroughly pressure-tested by patriotic volunteers, as part of the \"Test Subjects for Super-Earth\" Citizen Advancement Program.": "该“科迪亚克”盔甲作为“超级地球测试对象”公民进步计划的一部分,其经过了爱国志愿者全面的压力测试。", + "HIGHER MISSILE DAMAGE": "提升导弹伤害", + "12x25mm Hollow Point": "12x25mm空尖弹", + "The pattern used for this armor is the result of the Winter Camouflage Improvement Effort, which considered 136 entrants before determining the color white would best blend in with snow.": "此盔甲的图案是冬季迷彩优化工作的成果。在综合考虑136位参与者的提案后,最终决定白色与雪地的融合度最高。", + "Targeting Sensors": "目标锁定传感器", + "Epoch": "纪元", + "Eagle Rearm": "重新武装“飞鹰”", + "SH-32": "SH-32", + "With its rustic charm and huntsmanlike detailing, this armor evokes those heroic expansionists who braved the alien wilds and ushered in our current age of bio-uniformity.": "这套盔甲充满猎装细节,质朴的风格另有一番魅力,唤起人们对英雄开拓者的敬意,正是前辈勇闯异星荒野,引领我们迈入当今的生物统一时代。", + "10g Dual Sabot": "10g双萨博特式霰弹", + "9x70mm Penetrator": "9x70mm穿甲弹", + "E/M-105": "E/M-105", + "SHORTER COOLDOWN": "冷却用时缩短", + "Extra Magazines": "额外弹匣", + "CLOAK OF POSTERITY'S GRATITUDE": "后族怀恩披风", + "Silencer": "消音器", + "MELTAGUN": "热熔枪", + "110mm E.M.S. Cannon Round": "110mm电磁冲击波炮弹", + "Robotics Workshop": "机械工坊", + "By reminding Chemical Agents of proper distancing rules, this extraordinary innovation in cape design ensures that they never cause another unfortunate outbreak of Carcino-Plague.": "提醒化学专家保持适当距离的创新披肩设计可确保他们不会再引发卡西诺瘟疫灾难。", + "The signature orange pauldron allows easy battlefield detection of the bearer, alive or dead, on ash-strewn battlefields.": "橘黄色护肩非常醒目,哪怕在遍布灰烬的战场上也能让你轻易找到穿戴者,无论他们是生是死。", + "BALLISTIC PADDING": "防弹内衬", + "Armor befitting infiltrators of all caliber. Inspired by mythical Democracy-dispensers, whose meticulously undocumented operations remain an inspiration to all students of stealth.": "此盔甲适合水平各异的渗透人员。以传说中的民主精神传播者为灵感设计,他们不留痕迹的缜密行动至今仍激励着所有潜行术学员。", + "B-08 Light Gunner": "B-08“轻装枪手”", + "A reliable assault rifle with an antique iron sight, firing incendiary ammunition.": "可靠的突击步枪,配备老式机械瞄具,可发射燃烧弹药。", + "More Arc Splits": "增加电弧分裂数", + "RS-11": "RS-11", + "CW-36 WINTER WARRIOR": "CW-36“冬日战兵”", + "Volatile Plasma Bolt": "易气化等离子弹", + "DRUM MAGAZINE": "弹鼓", + "G-13": "G-13", + "AFFECTED AREA": "影响范围", + "TR-9 Cavalier of Democracy": "TR-9“民主骑兵”", + "\"The ground is just another obstacle that hasn't yet been cleared.\" - SGM Janet Jones, Excavation Corps Founder.": "“大地不过是另一道有待清除的阻碍。”——上士珍妮特·琼斯,挖掘部队创始人。", + "GR-8": "GR-8", + "P-19": "P-19", + "The patented fabric absorbs visible, infrared, and ultraviolet radiation, to prevent detection by all known species.": "享有专利的纤维材料可吸收可见光、红外线和紫外线辐射,躲过所有已知物种的侦测。", + "Fire Support": "火力支援", + "FIRST DIVEMASTER": "一等潜兵长", + "This armor, together with its friendly-faced helmet, is instantly recognizable from the beloved children's show \"Jen Shriver the Science Diver.\"": "这套盔甲配套看似友好的头盔,一眼就能辨别灵感源自深受孩童喜爱的节目“科研潜兵珍·施莱佛 ”。", + "A humane, autonomous drone equipped with a modified Arc Thrower. Capable of projecting arcs of lightning through multiple targets. Does not need to recharge between shots.": "配备改良版电弧发射器的人道主义自主无人机。能够向多个目标发射电弧闪电。每次射击前无需充能。", + "With sharp geometric angles to symbolize the rigid chain of command, this cape embodies the sanctity and moral fortitude of unblemished leadership over the mud-caked warriors they direct.": "用锐利的几何棱角象征严苛的指挥链,这件披风体现了完美无瑕的将领在统御满身泥泞的战士时,所闪耀的神圣光辉与道德毅力。", + "A powerful, single-use, proximity-detonated heat energy mine. During the Fall of Chara, it is said enough Melta Mines were detonated to outshine the planet's sun. \n\nProduced by ST Construction.": "一种威力强大的一次性近炸热能地雷。据说在常陈四陷落期间,巨量热熔地雷被引爆,散发出的光芒甚至比该星系中的恒星更耀眼。\n\n由ST建筑公司生产。", + "LONGER LIFETIME": "提高耐久度", + "BEAM": "激光束", + "Extra Magazine": "额外弹匣", + "DEADEYE": "鹰眼", + "Volatile Plasma Igniter": "易气化等离子点火器", + "The SEAF standard assault rifle, balancing power, fire rate, and weight for a reliable weapon against smaller targets.": "超级地球武装部队的制式突击步枪,火力、射速和重量各方面均较为平衡,是对付小型目标的可靠武器。", + "Gifted to Helldivers whose civilian lives were distinguished by exemplary citizenship, patriotism, and service to the Federation.": "授予具有爱国、效忠联邦等优秀品质、为平民竖立楷模的模范公民绝地潜兵。", + "CM-17 BUTCHER": "CM-17“屠夫”", + "Grenade Pistol": "榴弹手枪", + "Hot Dog": "热狗", + "Warrant": "法令", + "10g MAGNUM": "10g马格南霰弹", + "FX-12": "FX-12", + "DISTANCE #DISTm": "距离#DIST米", + "9x20mm Thermite": "9x20mm铝热弹", + "PACIFIER": "安抚者", + "Contact Mine": "水雷", + "A thermite grenade designed to adhere to surfaces before burning at 2000°C. Capable of burning through some armor.": "铝热榴弹,经过专门设计,可附着于表面,燃烧温度高达2000°C,能烧穿部分装甲。", + "Spear": "飞矛", + "Eternal Corona": "永恒日冕", + "ADRENO-DEFIBRILLATOR": "肾上腺素除颤器", + "Lightened Casing": "轻薄弹壳", + "Missile Pistol": "制导手枪", + "B-08 LIGHT GUNNER": "B-08“轻装枪手”", + "Will of the People": "人民的意志", + "NO ATTACHMENT": "无配件", + "More Bombs": "增加炸弹数", + "PEACEMAKER": "和平制造者", + "A backpack-mounted Hellbomb that can be armed by the wearer or an ally, starting a countdown. Users are recommended to remove the backpack before the countdown reaches zero.": "背包式地狱火炸弹,穿戴者或盟友激活后将开启倒计时。建议在倒计时归零前移除背包。", + "AF-50 Noxious Ranger": "AF-50“毒瘴游骑兵”", + "DP-00 Tactical": "DP-00“战术”", + "Punisher": "制裁者", + "Machete": "砍刀", + "CLUSTER BOMB": "集束炸弹", + "High-Velocity Shrapnel": "高速榴霰弹", + "HIGH-VELOCITY SHRAPNEL": "高速榴霰弹", + "GS-11 DEMOCRACY'S DEPUTY": "GS-11“民主代理人”", + "Meltagun": "热熔枪", + "DEPLOY": "部署", + "110mm Standard Rocket Mk2": "110mm标准火箭弹 MK2", + "Increases stim effect duration by #BONUS.": "治疗剂效果持续时间延长#BONUS。", + "FS-05 MARKSMAN": "FS-05“神射手”", + "Torcher": "火炬手", + "Equipped with the latest computational systems, subsystems, and supersystems, this armor is worth the equivalent of a small Megacity.": "这套盔甲配备最新的计算系统、子系统和超级系统,价值相当于一座小型特大城市。", + "Dignity of Toil": "劳作的荣光", + "EFFICIENT FUEL": "高效燃料", + "SA-32 DYNAMO": "SA-32“精力充沛”", + "A/MLS-4X": "A/MLS-4X", + "ANTI-PERSONNEL MINEFIELD": "反步兵雷区", + "A barrage of bombs creating a non-targeted carpet of explosions.": "发动无目标地毯式轰炸的炸弹火力网。", + "MD-17": "MD-17", + "Supply Pack": "补给背包", + "Fires a short-ranged superheated blast of thermal energy that melts the heaviest armor and thickest chitin into slag. \n\nProduced by ST Construction.": "发射的短程超高温热能冲击,能够熔融最厚重的装甲和最厚实的甲壳。\n\n由ST建筑公司生产。", + "CW-9 WHITE WOLF": "CW-9“白狼”", + "Reckoning's Cheer": "清算颂歌", + "VETERAN'S BANNER": "老兵旗帜", + "MEDICAL SUPPLIES": "医疗补给", + "Sturdier Wheels": "加固轮胎", + "DEFENDER": "防卫者", + "FLAM-66": "FLAM-66", + "PENETRATION": "穿透攻击", + "9x20mm FULL METAL JACKET": "9x20mm全金属被甲弹", + "Prevents all damage from bleeding if chest hemorrhages.": "如果胸腔出血,则避免其他所有来自出血的伤害。", + "A manned gun emplacement offering superior firepower against lightly armored targets. Slow to turn, so place it wisely.": "手动炮台,强悍的火力能有效对付轻型装甲目标。转向速度较慢,请明智选择部署位置。", + "DS-10 Big Game Hunter": "DS-10“巨兽猎手”", + "Super Earth Flag": "超级地球旗帜", + "SPIRE STERILIZER": "虫塔杀菌器", + "Ammunition Optimization": "弹药优化", + "15x100mm High Explosive": "15x100mm高爆弹", + "SOS BEACON": "S.O.S.求救信标", + "9x20mm THERMITE": "9x20mm铝热弹", + "SALUTE": "敬礼", + "12x25mm RIPPER": "12x25mm撕裂弹", + "Scourge of Tyranny": "暴政克星", + "Hive Scanner": "虫窝扫描仪", + "COOLDOWN": "冷却时间", + "GS-66 LAWMAKER": "GS-66“立法者”", + "Fires a ballistic dart at near-supersonic speeds, allowing the user to stim allies from a distance. Might sting.": "以接近超音速的速度发射飞镖,可远程救治盟友。被射中时可能会感到刺痛。", + "Extended Magazine": "加长弹匣", + "AIRBURST ROCKET LAUNCHER": "空爆火箭弹发射器", + "The standard heatsink for laser rifles.": "激光步枪的标准散热器。", + "K-2": "K-2", + "MA5C": "MA5C", + "SHORT REVOLVER BARREL": "左轮手枪短枪管", + "Faster Missiles": "提升导弹速度", + "Airburst Rocket Launcher": "空爆火箭弹发射器", + "CHARGEUP": "充能", + "SC-28 Stealth Ranger": "SC-28“潜行游侠”", + "TR-117 Alpha Commander": "TR-117“阿尔法指挥官”", + "Laser Sentry": "激光哨戒炮", + "Breakthrough Exosuit": "“突破”外骨骼装甲", + "PROGRAMMABLE PRISM EFFECT": "智能棱镜效果", + "Portable Hellbomb": "便携式地狱火炸弹", + "EAGLE REARM": "重新武装“飞鹰”", + "APEX PROTECTOR": "巅峰护卫", + "110mm E.M.S. Cannon Round Mk3": "110mm电磁冲击波炮弹 MK3", + "Featuring patented reverse-seam technology, to reduce the likelihood of bodily fluids entering the armor's interior.": "运用专利反向缝合技术,减少体液进入盔甲内部的可能性。", + "SC-15 Drone Master": "SC-15“无人机大师”", + "100kg Bomb Mk2": "100KG炸弹 MK2", + "This Is Democracy": "恭迎民主", + "500kg BOMB MK2": "500KG炸弹 MK2", + "5.5x50mm EXPLOSIVE": "5.5x50mm爆炸子弹", + "INFLAMMABLE": "易燃易爆", + "CADET": "军校生", + "SG-22": "SG-22", + "R-2124": "R-2124", + "110mm AIRBURST CANNON ROUND MK2": "110mm空爆炮弹 MK2", + "Wearer makes #BONUS less noise when moving.": "穿戴者移动时产生的噪音减少#BONUS。", + "CM-09 BONESNAPPER": "CM-09“碎骨杀手”", + "DBS-2": "DBS-2", + "IMPROVED READY RACKS": "改良预备弹药挂架", + "Longer Lifetime": "提高耐久度", + "LAS-13 Trident": "LAS-13“三叉戟”", + "Increases weapon ergonomics to reduce drag on weapon movement.": "通过提升武器的人体工学性能,降低携带武器移动的阻力。", + "Ew": "好臭", + "85mm HEAT Grenade": "85mm高爆反坦克榴弹", + "10g LIBERTY FIRE": "10g“解放之火”霰弹", + "GIGA GRENADE": "千兆级榴弹", + "Made famous by the SEAF commander of the same name, this seal reminds us that only perfect Unity can ensure perfect Freedom.": "此印因同名的超级地球武装部队指挥官而闻名,时刻提醒着我们,唯有绝对的团结,方能确保绝对的自由。", + "MUZZLE BRAKE": "枪口制退器", + "STANDARD DRUM": "标准弹鼓", + "A linear artillery barrage which moves at intervals, driving the enemy out from cover while allowing an advance.": "间歇性移动的线形火力网,可将敌人逐离掩体,同时让我方前进。", + "All Hail the Helldivers, whose resplendent honor makes Tyrants tremble.": "向绝地潜兵致敬,他们的荣耀光辉令暴政颤栗。", + "Bolt Pistol": "爆弹手枪", + "The omission of upper-limb coverings allows for optimized freedom of movement, perspiration, and communication of upper body strength to squadmates.": "省去覆盖上肢的布料,自由行动的空间、排汗,以及与队友之间的上肢力量交流都将得到优化。", + "All Hail the Helldivers, who bring untold abundance to Super Earth's citizens.": "向绝地潜兵致敬,正是他们为超级地球公民带来了无尽的财富。", + "A subdued cape, for those who need no recognition—save that of their enemies, as their executioner.": "为不愿被认出的战士而设计的低调披肩。但敌人一眼就能认出,因为披肩的出现,代表他们死期已到。", + "SUPER EARTH FLAG": "超级地球旗帜", + "EAT-17": "EAT-17", + "Patient Zero's Rememberance": "零号病人遗思", + "SUPER PERSON": "超人", + "15x100mm Thermite": "15x100mm铝热弹", + "Shafts of Despair": "绝望之柱", + "De-Forester's Sailcloth": "伐木工帆布", + "12g Bugshot": "12g虫弹", + "110mm Standard Rocket": "110mm标准火箭弹", + "Often showcased in the \"Obedient Democracy Support Troopers\" cartoon, this assault rifle comes with a convenient ammo counter and compass.\nProduced by Martian Armory.": "这款突击步枪经常在《民主光环驰援部队》卡通片中出现,配备了便捷的弹药计数器和指南针。\n由火星军械库生产。", + "Half Choke": "半喉缩", + "Increased Shield Power": "提升护盾能量", + "This grenade delivery drone follows the user until it detects an enemy nearby, then flies toward it and explodes on impact. Has a limited battery life.": "这款榴弹投掷无人机会紧跟使用者飞行,探测到附近敌人后飞向目标,撞击后引爆。电池续航时间有限。", + "Based on a SEAF Signaller's Cape, which was intended to enable easy location of fallen heroes by aerial recovery crews.": "设计原型是超级地球武装部队的披肩,目的是帮助空中救援小队轻松找到阵亡的英雄。", + "Provides #SIGN#BONUS limb health.": "提供#SIGN#BONUS的四肢生命值。", + "BIG WHOOP": "喝彩", + "Throwing Knife": "飞刀", + "CM-14 Physician": "CM-14“医师”", + "ST-1": "ST-1", + "Diligence": "勤勉", + "12g BUCKSHOT": "12g鹿弹", + "MORE ROUNDS": "增加弹药", + "SQUAT": "蹲坐", + "SUPPLY PACK": "补给背包", + "SOLO SILO TARGETING REMOTE": "单兵导弹发射井定位遥控器", + "SCRAPS OF SOVEREIGNTY": "主权碎片", + "With extra capacity for storing throwable munitions, this armor ensures every enemy stronghold can be tactically ventilated, as per forceful de-fortification protocols.": "这套盔甲具备收纳投掷弹药的额外空间,可确保对每个敌军据点以符合“强制去工事化协议”的方式进行“战术通风”。", + "EXTENDED MAGAZINE": "加长弹匣", + "B/MD": "B/MD", + "TORCHER": "火炬手", + "IE-57 Hell-Bent": "IE-57“奋不顾身”", + "A symbol of fierce commitment to Liberty and Democracy, this cape celebrates the Helldivers who have held true to Super Earth values through rain or shine.": "这件披肩象征着对自由和民主的坚定承诺,颂扬那些风雨无阻地坚守超级地球价值观的绝地潜兵。", + "A Hellpod containing four supply packs, to replenish personal ammunition and stims in the field.": "装有四个补给背包的绝地喷射舱,可在战场上补充个人弹药和治疗剂储备。", + "PLAS-45": "PLAS-45", + "A melee weapon tipped with electrified prongs that temporarily stun targets. Can be wielded one-handed.": "近战武器,矛头带电刺,可暂时眩晕目标。支持单手操作。", + "HOT-SHOT MARKSMAN RIFLE": "高能精确射手步枪", + "ERGONOMIC DRUM": "人体工学弹鼓", + "High-Pressure Napalm": "高压凝固汽油弹", + "A sight with thin features to maximize visibility of the target.": "纤薄设计的瞄准镜,可最大限度地提升目标可见度。", + "The featherlight construction belies the heavy burden this cape entails—to live the Creed of the True Citizen.": "轻如鸿毛的结构掩盖了此披风的沉重意义:践行忠诚公民的信条。", + "Default Helldiver Voice 3": "绝地潜兵默认声音 3", + "Randomize Voice": "随机分配声音", + "The heavy rubber tunic and reflective limb guards, originally designed to save citizens from burning buildings, now enable the liberal application of the cleansing fires of Justice.": "这厚重的橡胶外衣和反射隔热的肢体护具原本是用来在火场中营救公民的,如今则让穿戴者可以毫无顾忌地喷射正义的净化烈焰。", + "Small Plasma Bolt": "小型等离子弹", + "A modified Breaker shotgun firing birdshot, small pellets which saturate an area to clear up smaller targets.": "改良后的“破裂者”霰弹枪,可发射鸟弹,分散的细小弹丸足以清除一定区域内的小型目标。", + "FOESMASHER": "歼敌战士", + "HARBINGER OF TRUE EQUALITY": "真正的平等先锋", + "Tenderizer": "肉锤", + "8x60mm AIRBURST": "8x60mm空爆弹", + "MD-I4": "MD-I4", + "FEET FIRST": "护腿为上", + "Autocannon Sentry": "自动哨戒炮", + "12x25mm Thermite": "12x25mm铝热弹", + "13x40mm PENETRATOR": "13x40mm穿甲弹", + "Arc": "电弧", + "Vigorous Thrusting": "盛气凌人", + "AR-61": "AR-61", + "A shovel that can be used as a melee weapon or, more conventionally, to dig holes in the ground.": "铲子,除了能在地上挖洞,还可用作近战武器。", + "DIAGRAM OF THE NOBLEST PAYLOAD": "至高使命图谱", + "9x20mm Explosive": "9x20mm爆炸子弹", + "Modeled after the myriad Statues of Judicious Liberty, who keep a watchful eye on checkout lines, schoolyards, perpetual rehabilitation communities, and public confession theaters.": "这套盔甲的灵感来自不计其数的“公正自由女神像”,她们警惕地注视着收银台、学校操场、永久性矫正社区和公共忏悔剧场。", + "Default Trigger": "默认扳机", + "IMPROVED AMMO STORAGE": "弹药存储量升级", + "STONE-WROUGHT PERSEVERANCE": "磐石毅力", + "When wearers stand shoulder to shoulder, this cape shows them as they truly are: an unbreakable defense, keeping Freedom safe behind an impregnable wall.": "肩并肩穿戴披肩站立时,便会展现真实风采:化身坚不可摧的防线,将自由守护在固若金汤的墙后。", + "Head Tap": "动动脑", + "E/GL-21": "E/GL-21", + "GAS MORTAR SENTRY": "瓦斯迫击哨戒炮", + "CALTROPS": "铁蒺藜", + "Allows the swift completion of Liberty's administrative tasks in an invigorating atmosphere.": "在鼓舞人心的氛围下,快速完成解放伟业的行政工作。", + "LEVELLER": "荡平者", + "40mm APHE Cannon": "40mm穿甲高爆炮弹", + "DRAW!": "拔枪!", + "TESLA TOWER": "特斯拉塔", + "45-DEGREE VERTICAL FOREGRIP": "45度垂直前握把", + "LIGHTWEIGHT MATERIALS": "轻质材料", + "Gas": "毒气榴弹", + "10g Bugshot": "10g虫弹", + "Command Input": "指令输入", + "DOG BREATH": "腐息", + "SA-12 SERVO ASSISTED": "SA-12“伺服辅助”", + "CE-35 TRENCH ENGINEER": "CE-35“战壕工程师”", + "Granted to the Truth Enforcers' Informant of the Month, this tasteful cape conjures images of dissident blood on asphalt.": "这件品味非凡的披肩属于真理执行者的“月度最佳告密者”,令人联想到沥青路面上异见分子的鲜血。", + "A throwable device engineered to bounce when hitting the ground, releasing bursts of electricity on each impact. Warning: may bounce unpredictably.": "经过特殊设计的投掷设备,击中地面时会弹起,每次撞击都会释放电流。警告:弹跳方向可能难以预测。", + "NOISE": "噪声", + "PILLARS OF FREEDOM": "自由支柱", + "E/MG-101": "E/MG-101", + "Curtsy": "屈膝礼", + "SHORTER COOLDOWN MK2": "冷却用时缩短 Mk2", + "AIRBURST ROCKET BACKPACK": "空爆火箭弹背包", + "R-36": "R-36", + "DYNAMITE": "炸药", + "A cape commemorating the Helldivers who paved the way for the successful launch of the improved TCS+. An enduring reminder of Super Earth’s engineering power and commitment to suppressing the Terminid horde.": "这款披肩旨在铭记为成功启动升级版TCS+扫清障碍的绝地潜兵。它是超级地球工程伟力与誓要消灭终结族决心的永恒见证。", + "EXPERT EXTERMINATOR": "顶级灭杀者", + "LAS-99": "LAS-99", + "Punisher Plasma": "等离子“制裁者”", + "Heavily insulated from animal bites, enemy fire, and the histrionic diatribes of anarchists.": "对野兽啃咬、敌方火攻以及扰乱分子的嬉笑怒骂完全绝缘。", + "High-Pressure Nozzle": "高压喷嘴", + "INFILTRATOR": "深入敌阵", + "NATURAL GAS EXTRACTION": "提炼天然气", + "LURE MINE": "诱饵地雷", + "MISSILE PISTOL": "制导手枪", + "HIGH EXPLOSIVE": "高爆弹", + "A prolonged barrage, wreaking extended destruction over a large area. Communication with teammates is advised.": "持续输出火力网,可大面积范围造成破坏。使用前建议与队友进行通信。", + "Strength in Our Arms": "武器之力", + "LIBERTY'S HERALD": "解放预兆", + "Quasar Cannon": "类星体加农炮", + "SMG/FLAM-34": "SMG/FLAM-34", + "5.5x50mm SUBSONIC": "5.5x50mm亚音速弹", + "G-7": "G-7", + "M-1000": "M-1000", + "An anti-tank homing missile which must lock onto its target before launch. Effective against large and armored enemies.": "反坦克追踪式导弹,发射前必须锁定目标。可有效对付大型装甲敌人。", + "B-27 Fortified Commando": "B-27“强化突击兵”", + "LASER": "激光", + "A barrage of smoke grenades, creating a thick smoke screen to block enemies' line of sight.": "烟雾弹火力网,可形成一道厚重的烟幕,阻挡敌人的视线。", + "A silo that fits one single, powerful missile. Comes with a handheld targeting remote.": "发射井可容纳一枚强力导弹。配备手持定位遥控器。", + "Double Freedom": "双重自由", + "A symbol of the constant, forward-moving propulsive force of Managed Democracy. This cape honors those who understand that in the race for Freedom, there are no brakes—only degrees of momentum.": "胜利矢量象征管理式民主恒定前进的驱动力。这件披肩向那些明白在自由竞赛中没有刹车、唯有动力强弱之分的人致敬。", + "40mm Proximity Grenade": "40mm感应榴弹", + "100KG BOMB": "100KG炸弹", + "Signal: Hold": "信号:等待", + "SCHEMA LAID BARE": "解封蓝图", + "LARGER CANISTER": "扩容燃料罐", + "Light of Eternal Liberty": "永恒自由之光", + "OVER ARTIFICE TRIUMPHANT": "巧取豪夺", + "IMPROVED AIR BRAKES": "改良空气制动器", + "Evoking legendary Helldiver Ronald Mambo on the eve of his untimely disappearance, the striking silhouette projects power, burliness, and strength.": "极具冲击力的轮廓展现出力量、悍勇与威压,令人不禁想起意外失踪前夕的传奇绝地潜兵罗纳德·曼波。", + "Peacemaker": "和平制造者", + "MORTAR SENTRY": "迫击哨戒炮", + "SEEKER": "寻踪者", + "IMPROVED DURABILITY": "提升耐久度", + "Belt-Fed Grenade Launcher": "弹链式榴弹发射器", + "LARGER FUEL TANK": "扩容燃料罐", + "A laser rifle firing a continuous beam. Does not need reloading, but if it overheats a new heat sink must be fitted.": "发射连续激光束的激光步枪。无需重新装弹,但如果步枪过热,必须安装新的散热器。", + "Amendment": "修正", + "Provides #BONUS resistance to gas damage and effects.": "对毒气伤害和效果的抗性增加#BONUS。", + "MG-43": "MG-43", + "No muzzle choke.": "无枪口喉缩。", + "Streamlined for maximum velocity, this armor was inspired by long-distance couriers who prioritized the delivery of ballots over personal safety, exemplifying our patriotic bonds. Features reinforced joints to withstand the violent transitions between high-speed travel and abrupt, unplanned stops.": "为追求极致速度,这套护甲采用流线型设计,其灵感源于将递送选票置于个人安全之上的长距离运送者,彰显我们的爱国纽带。其特点是对关节连接处进行了强化处理,可承受高速行驶与突发或计划外停靠之间的剧烈转换。", + "10g BUGSHOT": "10g虫弹", + "EXPANDED HEAT CAPACITY": "提升热容量", + "Efficient Fuel": "高效燃料", + "STATIONARY RELOAD": "固定填弹", + "MD-6": "MD-6", + "B/FLAM-80": "B/FLAM-80", + "Prospecting Drill": "勘探钻机", + "CONCUSSIVE PADDING, HAZMAT": "防震内衬(防化型)", + "UPGRADED AFTERBURNER": "升级后燃器", + "Inspired by the trailblazing agents of the Super Earth Terraforming Company. These rugged adventurers surveyed hostile new planets during the post-GW1 Great Expansion era, preparing the untamed frontier for rapid and efficient assimilation.": "设计灵感源自超级地球行星地球化公司的先驱者。在第一次星系战争后的大扩张时期,这些坚韧的冒险家勘测了许多充满敌意的新星球,为快速高效地同化未开发边境奠定基础。", + "A mid-range precision rifle. Equipped with an integrated suppressor and subsonic rounds for barely-detectable operation.": "这是一支中程精准步枪。配备集成式消音器和亚音速弹药,方便执行难以被察觉的行动。", + "IE-12 RIGHTEOUS": "IE-12“义士”", + "BUG QUARANTINER": "虫族清道夫", + "This time-honored shotgun-like weapon has been improved since the First Galactic War, and now fires six beams instead of three.": "这款霰弹枪式经典武器自第一次星系战争以来历经改良,射出的激光束从三道增加到了六道。", + "Jammed Piñata": "满载惊喜的皮纳塔", + "FIRE RATE SELECTION": "可选射速", + "The standard scope for most weapons, provides a good and accurate scope picture.": "适配多数武器的标准瞄准镜,提供清晰精准的瞄准视野。", + "BREAKER NAILSPITTER": "尖钉喷射“破裂者”", + "LIGHT OF ETERNAL LIBERTY": "永恒自由之光", + "A/M-23": "A/M-23", + "Miranda's Legacy": "米兰达的遗志", + "With this cape we honor the bio-warfare pioneers of Division Zero, conscripted from quarantine zones and hospices to spread their Carcino-Plague on the battlefield.": "我们设计这件披肩是为了向“零号”师的生物战先驱致敬。他们从隔离区和临终关怀医院应征入伍,在战场上传播他们携带的卡西诺瘟疫病毒。", + "I-44 Salamander": "I-44“火蜥”", + "P-92": "P-92", + "Salute": "敬礼", + "Saber": "军刀", + "SG-225BB": "SG-225BB", + "SIGNAL: SILENCE": "信号:安静", + "TIGHTER BREECH LOCK": "收紧枪闩锁", + "Medical Supplies": "医疗补给", + "5-STAR GENERAL": "五星将军", + "Pacifier": "安抚者", + "Those who serve Liberty from the shadows often elect to stay anonymous, moving like traceless specters through the night. May they watch over us always.": "那些在黑暗中为自由而战的人往往选择隐姓埋名,如同幽灵般穿行于夜色之中,不留一丝痕迹。愿他们永远守护着我们。", + "A plasma rifle that fires bolts of superheated gas, which can be charged by holding down the trigger. Charging up a shot fully makes the bolt explode on impact.": "等离子步枪,可发射过热气体,按住扳机即可为其充能。每发射击完全充能后,触及着弹点后引爆。", + "40mm HE Mortar": "40mm高爆迫击炮弹", + "THE BREACH": "突破", + "FRONT-LEANING REST POSITION": "俯卧撑姿势", + "DAB": "嘻哈超人舞", + "A pistol firing guided, jet-propelled ammunition. It's lock-on feature ensures high accuracy, but the weapon must be reloaded after every round fired.": "一款发射喷气推进式制导弹药的手枪。具备锁定功能,可确保高射击精度,但每次开火后均须重新装填弹药。", + "120mm HE CANNON ROUND": "120mm高爆炮弹", + "Bunting of the Party Participant": "派对彩饰", + "ADVANCED VERTICAL FOREGRIP": "高级垂直前握把", + "9x70mm HIGH VELOCITY": "9x70mm高速弹", + "Fires a rocket that detonates within proximity of a target, and deploys a cluster of explosive bomblets.": "发射火箭弹,在目标附近引爆,并部署一组小型爆弹。", + "This armor recalls the legendary heroes who scared a ravenous Hive Lord away from a colony village, using only the village's battery of patriotic fireworks.": "这套盔甲纪念的是那些传奇英雄,他们仅凭村里的一批爱国烟花,就吓退了一只贪婪的霸王虫,拯救了拓殖地的村落。", + "FS-38 ERADICATOR": "FS-38“根除者”", + "K-9": "K-9", + "A silenced assault rifle with a built-in suppressor, which won't alert distant targets to the user's position.": "内置抑制器的消音突击步枪,可避免向远处的目标暴露使用者的位置。", + "TEST OF CONVICTION": "信念试炼", + "AD-26 BLEEDING EDGE": "AD-26“血刃科技”", + "KDM-73 Dragoon": "KDM-73“龙骑兵”", + "The gas-operated, semiautomatic P-113 chambers the 14mm \"Rapid Deliberation,\" the largest centerfire cartridge of any magazine-fed pistol.": "这支半自动P-113型气动式手枪采用14毫米的“速决”子弹,这是弹匣式手枪中最大的中心底火子弹。", + "23mm HE Cannon": "23mm高爆炮弹", + "DIVEMASTER": "潜兵长", + "5.5x50mm SUPER URANIUM CORE": "5.5x50mm超铀芯弹", + "Contains a grain of sand from Super Earth—so its bearers carry a small piece of Liberty with them, wherever they go.": "载有一粒来自超级地球的沙子,让不论穿戴者身在何处,心中都承载着自由。", + "LASER SENTRY": "激光哨戒炮", + "Encloses the wearer in a spherical shield which blocks high-speed projectiles.": "以球状护盾包裹佩戴者,抵挡高速射弹。", + "Faster Deploy Time": "缩短部署用时", + "No additional bonuses.": "无额外加成。", + "Narrow Spread": "集中", + "This armor is the required uniform for many Super Earth Citizens operating heavy machinery. Long-time users will be delighted to learn that as of this year's Efficiency in Machine Operation Symposium and Gala, wearing this armor is no longer itself considered operating heavy machinery.": "这套盔甲是许多操作重型机械的超级地球公民的必备制服。从本年度“机械操作效能研讨会暨晚宴”举办之日起,穿戴这套盔甲将不再被视为操作重型机械,这对于长期穿着者而言无疑是个好消息。", + "70mm STANDARD ROCKET": "70mm标准火箭弹", + "FS-37 Ravager": "FS-37“破坏者”", + "PLASMA IGNITER COMPENSATOR": "等离子点火器补偿器", + "LAS-98": "LAS-98", + "RE-1861 Parade Commander": "RE-1861“阅兵指挥官”", + "Protect Eardrums": "保护耳膜", + "SPEARGUN": "矛枪", + "40mm Flak Cannon": "40mm高射炮弹", + "10g Liberty Fire": "10g“解放之火”霰弹", + "O-3 Free Spirit": "O-3“自由之魂”", + "Homing Anti-Air Missile": "追踪式防空导弹", + "12.5mm EIT Rounds": "12.5mm爆炸燃烧曳光弹", + "DS-191 Scorpion": "DS-191“天蝎”", + "Plasma Bolt": "等离子弹", + "Justice": "正义", + "DP-11 Champion of the People": "DP-11“人民捍卫者”", + "FALLEN HERO'S VENGEANCE": "陨落英雄之崛起", + "Standard Heatsink": "标准散热器", + "GALACTIC COMMANDER": "星系指挥官", + "CQC-30": "CQC-30", + "A basic iron sight for Helldivers who want to relive the glorious struggles of their ancestors.": "基础机械瞄具,适合希望重温先辈辉煌奋斗历程的绝地潜兵。", + "TRUCKER'S TRIUMPH": "卡车司机的胜利", + "Featuring a high collar scientifically designed to deflect mud, blood, and indirect non-lethal projectiles, this pristine armor bestows the authority to overcome close-quarters combat through a time-honored tradition: the delegation—or court-martialing—of subordinates.": "采用科学实用的高领设计,可弹开泥浆、血污以及间接袭来的非致命投射物。这套一尘不染的盔甲赋予使用者在应对近战时实践久经验证传统的权威:委派下属充当肉盾(亦或将其军法处置)。", + "8x60mm Liberty Fire": "8x60mm“解放之火”子弹", + "LOYALIST": "忠诚者", + "GP-31": "GP-31", + "10g BIRDSHOT": "10g鸟弹", + "9x70mm High Velocity": "9x70mm高速弹", + "LEAN": "清瘦", + "UF-50 Bloodhound": "UF-50“猎犬”", + "A triple-barreled, break-action, sawed-off shotgun. Switch firing modes to fire all three barrels at once.": "三枪管中折式截短霰弹枪。可将开火模式切换为同时使用三枪管开火。", + "Orbital Smoke Strike": "轨道烟雾攻击", + "RS-100 Sanctioner": "RS-100“制裁者”", + "Stun Baton": "眩晕短棍", + "Warp Pack": "传送背包", + "INCENDIARY MINES": "燃烧地雷", + "C4 Pack": "C4背包", + "A half-constricted muzzle that forces the shotgun pellets together into a somewhat tighter group.": "半收束枪口,迫使霰弹较密集地发射。", + "13x40mm Full Metal Jacket": "13x40mm全金属被甲弹", + "Sickle": "镰刀", + "Gently stonewashed by experienced hands, this luxury cape exudes the essence of state-approved attitude.": "由资深工匠精心水洗做旧,这款奢华披肩散发着经国家认证的气质精髓。", + "HOMING ANTI-AIR MISSILE": "追踪式防空导弹", + "100KG BOMB MK2": "100KG炸弹 MK2", + "CM-10 Clinician": "CM-10“临床医师”", + "Modeled after the Statue of Mournful Liberty, who weeps over the existence of tyranny, this armor is worn by those who would give their lives to dry her tears.": "这套盔甲的灵感来自因暴政肆虐而哭泣的“哀恸自由女神像”,穿戴者愿以生命拂去自由女神的眼泪。", + "EXO-49": "EXO-49", + "AR-23": "AR-23", + "Ergonomic Drum": "人体工学弹鼓", + "G-89": "G-89", + "Woven from coarse, industrial fibers designed to absorb sweat and oil, this cape features a spade emblem to honor Super Earth's groundbreakers, who ensure Liberty’s light finds its way through any planet’s crust.": "采用粗糙的工业纤维织就,旨在吸收汗水与油污。这款披风饰有铁锹纹章,致敬为超级地球“破土奠基”的先辈们——感谢他们确保自由之光能穿透任何星球的地壳。", + "CPG-48 Sapper": "CPG-48“工兵”", + "BLITZER": "雷霆", + "SC-28 STEALTH RANGER": "SC-28“潜行游侠”", + "No dissident or alien, no creature big or small, can ever hope to stand against the furious stampede of Managed Democracy.": "无论是异见分子还是外星敌人,无论生物体型大小,都休想抵挡管理式民主狂怒奔涌的热潮。", + "AF-50 NOXIOUS RANGER": "AF-50“毒瘴游骑兵”", + "Marks the most Free of the Free, those who will seize tyranny by the neck and squeeze until no oppression remains.": "最自由者的印记,他们必将扼住暴政咽喉,碾尽世间一切压迫。", + "MORE LMG MOUNT MAGS": "增加架设型轻机枪弹匣", + "COMBAT HATCHET": "战斗短柄斧", + "BELT-FED GRENADE LAUNCHER BACKPACK": "弹链式榴弹发射器背包", + "A lightweight melee weapon that temporarily stuns enemies.": "轻型近战武器,可暂时眩晕敌人。", + "FLAME SENTRY": "火焰喷射哨戒炮", + "SICKLE": "镰刀", + "Anti-Tank Missiles": "反坦克导弹", + "SALVO FIRE": "炮弹齐射", + "PROTECT EARDRUMS": "保护耳膜", + "GL-21": "GL-21", + "Signal: Silence": "信号:安静", + "ACCELERATOR RIFLE": "加速步枪", + "CLAPPING": "鼓掌", + "110mm STANDARD ROCKET MK2": "110mm标准火箭弹 MK2", + "CRESTING HONOR": "荣誉之巅", + "REINFORCED EPAULETTES": "强化肩章", + "W.A.S.P. Launcher": "W.A.S.P.发射器", + "Spattered gore marks those heroes who braved the harrowing first days of the war for Managed Democracy.": "飞溅的血迹代表着那些为实现管理式民主而在早年战争中英勇奋战的英雄。", + "Since ancient times, the yellow line has symbolized an uncrossable boundary. To don this cape is to draw that line between tyranny and liberty, between alien monstrosities and Super Earth property, and never yield the right of way.": "自古以来,黄线就象征着不可逾越的边界。穿上这件披肩,意味着在暴政与解放、外星怪物与超级地球财产之间划清界线,并发誓绝不退让。", + "Upgraded Ammunition Feed": "升级供弹系统", + "FASTER RECHARGE": "加速充能", + "TR-7 AMBASSADOR OF THE BRAND": "TR-7“形象大使”", + "G-12": "G-12", + "STANDARD OF SAFE DISTANCE": "安全距离标准", + "KDM-763 PACESETTER": "KDM-763“领跑者”", + "All but ensures ascension to the immortal ranks of those enshrined in the Super Earth Digital Archive of Valorous Acts.": "必将收录至超级地球英勇之举数字档案,比肩珍藏其中的不朽藏品。", + "M-103": "M-103", + "Laser Sight w/ Flashlight": "激光瞄准器带照明", + "The set's classic advertising campaign \"Have you tried a grenade?\" has remained unchanged for over 70 years.": "70多年以来,本套装的广告词一直都是:“试过手雷了吗?”", + "0.05% of profits are donated to Superstone National Park, as part of the Ministry of Unity's \"Greener Galaxy\" campaign.": "为支持团结部的“更绿星系”活动,0.05%的利润将捐赠给超石国家公园。", + "Orbital 380mm HE Barrage": "轨道380mm高爆弹火力网", + "Duckbill": "鸭嘴枪口", + "Though originally intended solely for ceremonial use, its inspirational energy proved equally useful on the battlefield.": "设计初衷是用于仪式,但事实证明,它鼓舞人心的力量在战场上同样奏效。", + "A speargun firing heavy-duty projectiles. These projectiles release a cloud of gas on impact, and must be carefully loaded one at a time.": "一种发射重型短矛的矛枪。这些短矛在命中时会释放一团气体,装填时必须小心操作,每次装一枚。", + "Improved Ready Racks": "改良预备弹药挂架", + "Shorter Shot Cooldown": "缩短射击冷却用时", + "RE-2310 Honorary Guard": "RE-2310“荣誉卫队”", + "Reduces damage taken from impact and collisions by #BONUS.": "将撞击和碰撞造成的伤害降低#BONUS。", + "Woven in honor of our loyal Helldivers, whose commitment to Democracy, through rain or shine, is an inspiration to all.": "这件披肩旨在纪念忠诚的绝地潜兵,他们风雨无阻地坚守对民主的承诺,激励着所有人。", + "66mm Missile Mk2": "66mm导弹 MK2", + "A constricted muzzle that forces the shotgun pellets together into a tighter group.": "收束枪口,迫使霰弹十分密集地发射。", + "CE-101 Guerilla Gorilla": "CE-101“游击猩猩”", + "A heatsink with thinner cooling elements, improving cooling rate.": "配备更薄冷却元件的散热器,降温速率更快。", + "Angled Foregrip": "直角前握把", + "A fully-automatic pistol with an extremely high fire rate, allowing for efficient crowd control.": "射速极高的全自动手枪,可以有效对敌人实施群体控制。", + "SHIELD GENERATOR PACK": "防护罩生成包", + "AX/LAS-5": "AX/LAS-5", + "CW-22 KODIAK": "CW-22“科迪亚克”", + "PILLAR OF THE ABYSS": "深渊支柱", + "A tube red dot sight with 2x magnification, good for hitting small targets consistently over medium range.": "2倍放大管式红点瞄准镜,适合中程持续精准打击小型目标。", + "As the electric arc generates a strong magnetic field, wearers should avoid use while in vicinity of stapled paperwork.": "电弧可产生强大的磁场,穿戴者应避免在装订好的文书附近使用此盔甲。", + "SERGEANT": "中士", + "Debuted during the New Mombasa Armor Show, this sleek ensemble is sure to turn heads and blow minds.": "这套时髦的盔甲套装在新蒙巴萨盔甲展上首次亮相,必定成为全场焦点。", + "STRENGTH IN OUR ARMS": "武器之力", + "Jump Pack": "喷射背包", + "SG-225IE": "SG-225IE", + "Let all who see this cape be struck still with Freedom's beauty, or struck dead with Liberty's bullets.": "凡见此披肩者都将为自由之美所震慑,或被自由之弹所击毙。", + "More Ammo In Backpack": "增加背包弹药数量", + "Launches a prolonged barrage of napalm shells over a wide area, setting a swath of land ablaze in mere moments.": "持续投射凝固汽油弹火力网覆盖广大区域,顷刻将土地点燃。", + "Lockstep": "齐步行进", + "LOADING OPTIMIZATIONS": "优化配备装载", + "Default Internal Part": "默认内部零件", + "A larger heatsink that can store more heat.": "容量更大的散热器,可储存更多热量。", + "High Dissipation Heatsink": "高功率散热器", + "LAS-5": "LAS-5", + "This armor is based on the antique uniforms of the 'Super Earth Legion', a less patriotic precursor to the Helldivers.": "这套盔甲脱胎于古老的“超级地球军团”制服。后者是绝地潜兵的前身,但是不像绝地潜兵这样忠心爱国。", + "12g Buckshot Magnum Shells": "12g鹿弹马格南霰弹", + "IMPATIENT": "急躁", + "CENSOR": "审查官", + "MLS-4X": "MLS-4X", + "GUIDED": "制导", + "FS-11 Executioner": "FS-11“行刑者”", + "Rover": "漫游车", + "This cape reminds us that even faced with the abyssal darkness of space, nothing can stand against our human ingenuity, our powers of collaboration, or our sheer overwhelming numbers.": "这件披肩提醒我们,即使面对太空万籁俱静的黑暗,任何力量都无法对抗人类的智慧、协作能力以及人海战术的优势。", + "CE-81 Juggernaut": "CE-81“巨人”", + "Pride of the Whistleblower": "检举者的荣耀", + "SHEAR": "切变", + "A camo paint job for use in arctic environments.": "适用于雪地环境的迷彩涂装。", + "CE-07 Demolition Specialist": "CE-07“拆除专家”", + "Some say that a mere glimpse of this cape, fluttering majestically in the breeze, is enough to spur a squad to victory.": "有人说,只需一瞥此披肩在微风中飘扬的庄严模样,就足以激励整支战队披荆斩棘,迈向胜利。", + "380mm HE CANNON ROUND": "380mm高爆炮弹", + "A turret firing powerful shells in a high arc. Effective at long ranges, and able to strike at targets behind cover.": "以高弧度发射强力弹药的炮台。在远程范围内较为高效,能打击藏于掩体后方的目标。", + "INNER RADIUS": "内半径", + "Stim Pistol": "治疗剂手枪", + "RL-77": "RL-77", + "The alloy in these long-range rifles includes metals from the dead planet Chara, overrun in the First Galactic War. \n\nProduced by ST Construction.": "在用于制造这些远程步枪的合金中,有部分金属来自第一次星系战争中被敌军攻陷的死寂星球常陈四。\n\n由ST建筑公司生产。", + "Loosen Up": "放松", + "MAXIGUN BACKPACK": "重装机枪背包", + "RAIL CANNON ROUND": "轨道炮弹", + "Homing Ground Missile Mk2": "追踪式地面导弹 MK2", + "12.5mm EIT ROUNDS": "12.5mm爆炸燃烧曳光弹", + "MEDIC BACKPACK": "医疗背包", + "BREAK-ACTION SHOTGUN": "中折式霰弹枪", + "FUSE TIME": "引信时间", + "COYOTE": "野狼", + "AR-48": "AR-48", + "Dog Breath": "腐息", + "2x Tube Red Dot": "2倍红点瞄准镜", + "Emblazoned with the red, white, and green of the 676th Democracy Regiment, who made their final stand on the slopes of Justice Hill.": "饰有第676民主军团的标志性红、白、绿三色,纪念他们在正义山上的殊死一战。", + "STANDARD PLASMA CONTAINER": "标准等离子弹药匣", + "MESSAGE OF MORALE": "士气宣言", + "O-2 HEAVY OPERATOR": "O-2“重装操作者”", + "This Guy": "这家伙不得了", + "5.5x50mm High Velocity": "5.5x50mm高速弹", + "A one-handed device that deploys a wide energy barrier in front of the user. The barrier is semipermeable and blocks high-speed projectiles from the outside only, leaving the user free to shoot through it.": "可单手操作的装置,使用时会在正前方展开宽大的能量屏障。该半透屏障只会抵挡外部高速射弹,使用者发射的子弹能自由穿透屏障。", + "Break-Action Shotgun": "中折式霰弹枪", + "15x100mm EMP-ROUNDS": "15x100mm电磁脉冲弹", + "Defender": "防卫者", + "Assault Rifle": "突击步枪", + "Orbital Cannons": "轨道加农炮", + "Due to the enhanced strength caused by this armor, caution is advised when using door handles or embracing colleagues.": "此盔甲可强化穿戴者的力量,因此,建议穿戴时谨慎使用门把手或拥抱同僚。", + "Made Ready": "现成补给", + "TYRANT HUNTER": "猎暴人", + "WARRANT": "法令", + "A grenade that releases a cloud of toxic gas, effective at temporarily blinding and slowing both organic and inorganic enemies.": "释放有毒气团的榴弹,可使有机体和无机体敌人暂时致盲并减速。", + "LARGER SEARCH RADIUS": "扩大搜索半径", + "LAS-13 TRIDENT": "LAS-13“三叉戟”", + "Eagle 500kg Bomb": "“飞鹰”500kg炸弹", + "Assault": "特攻", + "DILIGENCE": "勤勉", + "9x20mm HOLLOW POINT": "9x20mm空尖弹", + "A grenade launcher effective against armored infantry. Not intended for use against vehicle armor or fortified buildings.": "榴弹发射器,可有效对付装甲步兵。不适合用于攻击载具装甲或防卫森严的建筑。", + "This armor set first appeared in the music video for the summer anthem 'Our Love is Like Liberty (Indestructible)'.": "这套盔甲的首度亮相是在夏日圣歌“爱如解放(坚不可摧)”的MV中。", + "BURIER OF HEADS": "埋首者", + "Rocket Sentry": "火箭哨戒炮", + "I-92 FIRE FIGHTER": "I-92“消防队”", + "STAR MARSHAL": "星级元帅", + "CE-07 DEMOLITION SPECIALIST": "CE-07“拆除专家”", + "EXPLODING CROSSBOW": "爆燃弩", + "A single precision shot from the Destroyer's 'ATLAS' cannon.": "来自驱逐舰“阿特拉斯”轨道加农炮的一发精准攻击。", + "10g SABOT": "10g萨博特式霰弹", + "CE-74 BREAKER": "CE-74“破裂者”", + "Reduces range at which enemies can detect the wearer by #BONUS.": "敌人探测佩戴者的范围缩小#BONUS。", + "5.5x50mm DOUBLE POWER": "5.5x50mm双效子弹", + "EXOSUIT CERTIFIED": "外骨骼装甲专家资格", + "FIRE LIMIT": "开火限制", + "A-35 Recon": "A-35“侦察者”", + "DAGGER": "匕首", + "Temporarily stuns all targets within the effective radius.": "可短时眩晕效果范围内的所有目标。", + "SC-30 TRAILBLAZER SCOUT": "SC-30“开路侦察兵”", + "CM-14 PHYSICIAN": "CM-14“医师”", + "RECKONING'S CHEER": "清算颂歌", + "REAPER OF BOUNTIES": "赏金收割者", + "Directional Shield": "定向护盾", + "ASSAULT INFANTRY": "特攻步兵", + "WILL OF THE PEOPLE": "人民的意志", + "Larger Magazines": "扩容弹匣", + "UNITED IN EQUALITY": "仰齐与共", + "FS-11 EXECUTIONER": "FS-11“行刑者”", + "INCREASED STORAGE MK2": "可携带数量升级 MK2", + "Contains many small pockets, allowing the user to evenly distribute the weight of ammunition, samples, and cool rocks.": "包含许多小口袋,方便使用者根据重量均衡放置弹药、样本和酷炫岩石。", + "DECORATED HERO": "功勋英雄", + "IMPROVED AMMO STORAGE MK2": "弹药存储量升级 MK2", + "Laser Sight": "激光瞄准器", + "Woven in honor of our loyal citizens, who by raising their voices have supported the war effort more than they can ever know.": "这件披肩旨在纪念忠诚的公民,他们大声疾呼,为战争提供了超乎想象的支持。", + "VOLATILE PLASMA IGNITER": "易气化等离子点火器", + "Manual Targeting": "手动锁定目标", + "A compact version of the Liberator designed for increased viability in close quarters. Has an increased fire rate at the cost of higher spread.": "便携版“解放者”,设计目的是提升近距离交战的生存能力。射速提高,但散射更广。", + "LARGER AMMUNITION STORAGE": "扩充弹药存储量", + "DOUBLE-EDGE SICKLE": "双刃镰刀", + "FS-05 Marksman": "FS-05“神射手”", + "12g Magnum Triball": "12g马格南三连弹", + "Aspect-seeking air-to-air missiles, to eliminate most flying targets in the vicinity.": "寻向空对空导弹,可歼灭附近的大部分飞行目标。", + "R-6": "R-6", + "AX/AR-23": "AX/AR-23", + "MARK OF THE CRIMSON FANG": "猩红獠牙之印", + "DUCKBILL": "鸭嘴枪口", + "Large Drum": "大型弹鼓", + "An Exosuit equipped with dual autocannons, designed for sustained explosive firepower.": "搭载两台机炮的外骨骼装甲,可持续提供爆炸性火力。", + "9x20mm HIGH VELOCITY": "9x20mm高速弹", + "Liberator": "解放者", + "10g BUCKSHOT SHELLS": "10g鹿弹霰弹", + "EFFECTIVE RANGE": "有效射程", + "Reduces the size of the muzzle flash by dispersing the burning propellant when firing the weapon.": "通过分散燃烧的推进剂,减少射击时的枪口火焰大小。", + "Medium Plasma Bolt": "中型等离子弹", + "The heavy plate used in this armor is sustainably sourced from the corpses of non-sentient Automatons, then processed by other, similarly non-sentient Automatons.": "这套盔甲使用的重型装甲板是可持续地取材于无感知能力的机器人残骸,并由其他同样无感知能力的机器人加工而成。", + "Progressive Trigger": "渐进式扳机", + "G-10": "G-10", + "FS-34 EXTERMINATOR": "FS-34“灭绝者”", + "One-Two": "幺二", + "ORBITAL NAPALM BARRAGE": "轨道凝固汽油弹火力网", + "8x60mm Sniper Armor Piercing": "8x60mm穿甲狙击弹", + "Shotgun": "霰弹枪", + "Legend tells of the unnamed Helldiver, wandering the edges of Super Earth's reach, delivering Democracy and leveling lawlessness wherever the tumbleweeds lead. Wear this, and keep the legend alive.": "传说有一位无名的绝地潜兵,游荡在超级地球的边境,追随风滚草的引领,传播民主,肃清无序。披上这件披肩,续写传奇。", + "EXTRACTION BEACON": "撤离信标", + "Stun Lance": "眩晕长矛", + "Provides #BONUS resistance to explosive damage.": "提供#BONUS的爆炸伤害抗性。", + "CE-67 TITAN": "CE-67“泰坦”", + "BUGSLAYER": "诛虫煞星", + "85mm HEAT GRENADE MK2": "85mm高爆反坦克榴弹 MK2", + "A helmet worn by the pioneering Helldivers who first ventured into the Void. Designed by Super Earth scientists with liberated Illuminate blueprints.": "这款头盔由首批踏入寂域的先驱绝地潜兵所佩戴。由超级地球科学家利用解放的光能者手中蓝图设计而成。", + "12x25mm THERMITE": "12x25mm铝热弹", + "GRENADE PISTOL": "榴弹手枪", + "A drill capable of piercing the tough walls of Terminid hives, and deploying a nuclear charge to collapse all tunnels.": "这台钻机能够穿透终结族虫窝的坚硬墙体,还能部署核炸药摧毁所有隧道。", + "CPH-26 Commandant": "CPH-26“司令官”", + "Expendable Napalm": "消耗性凝固汽油弹", + "A plasma rifle, firing a bolt of superheated gas which explodes on impact. Avoid standing in proximity to the blast.": "等离子步枪,可发射一束过热气体,触及着弹点后引爆。请勿站在爆炸点附近。", + "Larger Shield": "延展护盾", + "#DEGREES°/sec": "#DEGREES°/秒", + "EX-03 PROTOTYPE 3": "EX-03“原型 3”", + "Big Whoop": "喝彩", + "NAPALM BOMB": "凝固汽油弹", + "LAS-17": "LAS-17", + "PROUD GOLD": "傲金", + "BREACHING HAMMER": "破门锤", + "PAYLOAD": "炮弹填料", + "RANDOMIZE VOICE": "随机声音", + "DAMAGE": "伤害", + "AGENT OF OBLIVION": "湮灭使者", + "STARS AND SUFFRAGE": "群星与选举", + "Default Helldiver Voice 4": "绝地潜兵默认声音 4", + "Over Artifice Triumphant": "巧取豪夺", + "MORE EXPLOSIVE FILLER": "增加爆炸物填料", + "Redirects propellant gases to compensate for muzzle climb when firing the weapon.": "通过更改推进气体流向,抵消射击时的枪口上扬。", + "Breaker Bugbiter": "噬虫“破裂者”", + "12x25mm Toxic": "12x25mm毒弹", + "Reaper of Bounties": "赏金收割者", + "HELLDRIVER": "绝地司机", + "DOUBLE FREEDOM": "双重自由", + "REDUCED SIGNATURE": "隐迹潜踪", + "SC-30 Trailblazer Scout": "SC-30“开路侦察兵”", + "40mm HE GRENADE": "40mm高爆榴弹", + "ANTI-MATERIEL RIFLE": "反器材步枪", + "IMMEDIATE AUTO LOADER": "即时自动装填", + "A high-velocity railcannon round fired at the largest target in close proximity to the beacon. Targeting is automatic.": "向信标附近的最大型目标发射高速轨道炮弹。轨道炮自动完成目标定位。", + "70mm LASER-GUIDED MISSILE": "70mm激光制导导弹", + "A barrage of rocket pods, which the Eagle pilot will release on the largest target near the stratagem beacon.": "火箭巢火力网。“飞鹰”驾驶员会将其发射至靠近战略配备信标的最大型目标。", + "LARGER GATLING MAGAZINE": "扩容加特林弹匣", + "Humble Regalia": "谦卑徽记", + "Agent of Oblivion": "湮灭使者", + "Woven for the trailblazers who successfully led the way during the first sanctioned deployment of a new tactical paradigm. This cape’s bold shoulder mount design ensures that while the Helldiver continues to ever look toward the future, enemies of Freedom shall gaze upon an extinction of their own making.": "专为在首个获批全新战术范式部署中成功领跑的开拓者们织就。这件披风采用大胆的肩部挂载设计,旨在确保当绝地潜兵继续放眼未来时,自由的敌人却将亲眼见证其自取灭亡的下场。", + "AF-02 HAZ-MASTER": "AF-02“危害大师”", + "A recoilless rifle effective against vehicle armor. Includes support backpack required for reloading.": "无后坐力炮,可有效对付载具装甲。包含支援背包,用于装填弹药。", + "DEFAULT HELLDIVER VOICE 3": "绝地潜兵默认声音 3", + "Orbital Railcannon Strike": "轨道炮攻击", + "Orbital Gas Round Mk3": "轨道毒气弹 MK3", + "AF-02 Haz-Master": "AF-02“危害大师”", + "PATRIOT EXOSUIT": "“爱国者”外骨骼装甲", + "BR-14": "BR-14", + "Increases reload speed of primary weapons by #BONUS.": "主要武器的装弹速度提高#BONUS。", + "No Underbarrel": "无下挂", + "This ceremonial rifle is modeled after antique relics from pre-Democratic times. It is traditionally gifted to every citizen upon turning 16 to encourage service.": "以前民主时代文明的遗产为模型制作的礼仪步枪,传统会赠给满16周岁的公民,鼓励他们服役。", + "13x40mm Penetrator": "13x40mm穿甲弹", + "9x20mm EXPLOSIVE": "9x20mm爆炸子弹", + "Anti-Air Missile": "防空导弹", + "M-104": "M-104", + "Knight": "骑士", + "A strafing run of the battlefield to clear small targets, delivered almost instantly.": "机枪扫射清除战场上的小型目标,几乎可在一瞬间内完成扫射。", + "CQC-42": "CQC-42", + "SG-225SP": "SG-225SP", + "DESERT STORMER": "沙漠突击者", + "CW-4 ARCTIC RANGER": "CW-4“极地游骑兵”", + "FS-55 DEVASTATOR": "FS-55“蹂躏者”", + "P-4": "P-4", + "5-STAR SUPER PRIVATE": "五星超级列兵", + "LARGER PLASMA CONTAINER": "扩容等离子弹药匣", + "When children have trouble sleeping, tucking them in under this cape reminds them that they are never alone, for Liberty's unseen defenders are always watching over them.": "为难以入睡的孩子盖上这件披肩,提醒他们并不孤单,看不见的自由卫士一直守护在侧。", + "Reinforce": "增援", + "ACCLIMATED": "应变自如", + "MADE READY": "现成补给", + "Mark of the Constrictor": "缚暴印记", + "12.5mm Standard Rifle Rounds": "12.5mm标准步枪子弹", + "EXTRA MAGAZINES": "额外弹匣", + "UPGRADED AMMUNITION FEED": "升级供弹系统", + "After colonists of Hellmire recovered a lost shipment of this armor, the local pastime of fence-smashing was born.": "海尔迈尔的拓殖地居民寻回一批丢失的这种盔甲后,当地兴起了一种狂打栅栏的娱乐方式。", + "Deploys a defensive anti-personnel minefield, to halt enemy advance.": "部署反步兵防御雷区,阻止敌人前进的脚步。", + "Leveller": "荡平者", + "RS-40 BEAST OF PREY": "RS-40“掠食凶兽”", + "CW-9 White Wolf": "CW-9“白狼”", + "VECTOR OF VICTORY": "胜利矢量", + "Increases initial inventory and holding capacity of stims by #SIGN#BONUS.": "治疗剂的初始库存和持有上限增加#SIGN#BONUS。", + "100KG BOMB MK3": "100KG炸弹 MK3", + "Ballistic Shield Backpack": "防弹护盾背包", + "An experimental weapon which prioritizes armor penetration. Must be charged between shots - so choose targets carefully.": "侧重穿甲能力的试验性武器。两次射击的间隙必须充能,因此,请谨慎选择目标。", + "CE-27 GROUND BREAKER": "CE-27“裂地者”", + "The Combat Walker's fuel capacity is increased by 50%.": "战斗步行机甲的燃料容量提升50%。", + "RAILGUN": "磁轨炮", + "A powerful plasma weapon that fires one blast at a time, each blast exploding on impact. Must be charged to fire. Warning: do not overcharge.": "威力强大的等离子武器,每次单发射击,击中目标后爆炸。开火前需要充能。警告:请勿过度充能。", + "10g Scatter Shot": "10g散射弹", + "High Capacity Heatsink": "高容量散热器", + "REBAR RESOLVE": "钢筋意志", + "AUTOCANNON": "机炮", + "LOOSEN UP": "放松", + "HALT": "止息", + "RANK 300": "300级", + "One of the earliest to be mass-produced, this cape has been the final sight of untold numbers of Freedom's foes.": "作为最早量产的披肩之一,此披肩已经见证了无数自由之敌的陨落。", + "Improved Air Brakes": "改良空气制动器", + "CQC-2": "CQC-2", + "Eye of the Clandestine": "隐匿之眼", + "MG-206": "MG-206", + "Body type has no impact on gameplay": "体型不影响游戏内容", + "Increases point-of-interest identification range by #BONUS.": "探索点识别范围扩大#BONUS。", + "This bolt-action rifle fires jet-assisted shells that explode shrapnel in all directions upon impact. Not recommended for close-quarters use.": "这种栓动步枪透过喷气辅助发射炮弹,炮弹触及撞击面时向四面八方崩裂碎片。不建议近战使用。", + "110mm Gas Cannon Round": "110mm毒气炮弹", + "Each purchase of this cape comes with a complimentary will and testament amendment form, which guarantees the soon-to-be-deceased a prominent spot on the Wall of Martyrs.": "每次购买这件披肩都会附赠遗嘱更改表,确保即将牺牲的战士在烈士墙上占据显眼位置。", + "The golden, piercing quills symbolize the deadly and poetic Justice delivered to seditious oppositionists. Silent sanctions, delivered with unerring precision and incontestable deniability.": "锐利的金色羽毛笔,象征着凭借充满诗意的致命正义严惩煽动叛乱的反对派。以精准无误和无可辩驳的手段实施无声的制裁。", + "PLASMA IGNITER MUZZLE BRAKE": "等离子点火器枪口制退器", + "BACKUP VEHICLE": "备用载具", + "A belt-fed minigun with an exceptional ammo capacity. Cannot be reloaded with standard non-belted munitions.": "使用弹链供弹的机枪,弹药容量非常充足。无法使用标准无链式弹药装填。", + "5.5x50mm FULL METAL JACKET": "5.5x50mm全金属被甲弹", + "Shorter Charge Time": "缩短充电用时", + "Anti-Materiel Rifle": "反器材步枪", + "VG-70": "VG-70", + "CONSTITUTION": "宪法", + "10g STUN ROUNDS": "10g眩晕弹", + "8x60mm Airburst": "8x60mm空爆弹", + "12g Liberty Fire": "12g“解放之火”霰弹", + "Hyena": "鬣狗", + "SG-8P": "SG-8P", + "G-142": "G-142", + "Talon": "猛爪", + "HOT DOG": "热狗", + "This convenient cape can double as ground insulation, warming blanket, or camp roofing to the enterprising defoliator.": "这款便利披肩可兼作地面隔离垫、保暖毯或营地遮顶,为富有开拓精神的伐木工提供多种用途。", + "Reflex Sight": "反射式瞄准镜", + "Combat Hatchet": "战斗短柄斧", + "8x60mm Super Uranium Core": "8x60mm超铀芯弹", + "A one-handed ceremonial sword suitable for use in parades, sabrage, and combat.": "单手礼仪刀,适合阅兵、开瓶和战斗。", + "Defense Wall": "防御墙", + "WAY OF THE BANDOLIER": "弹带之道", + "NO CHOKE": "无喉缩", + "Heavily layered to protect against ocular blistering, subdermal liquification, and gastrointestinal shattering, this armor is a testament to the power of iterative improvements based on user feedback.": "这套盔甲层层厚实,可防止眼部起泡、皮下液化和胃肠道碎裂,充分体现了根据用户反馈迭代改进的力量。", + "BLAST SIMULATION": "爆炸模拟", + "AC-1 Dutiful": "AC-1“恪尽职守”", + "CONCUSSIVE PADDING, REINFORCED": "防震内衬(强化型)", + "DEFENDER OF THE WALL": "高墙捍卫者", + "ORBITAL LASER": "轨道激光炮", + "ARROWHEAD": "ARROWHEAD", + "SILENCER": "消音器", + "LARGER EXPLOSION": "扩大爆炸范围", + "8x60mm Full Metal Jacket": "8x60mm全金属被甲弹", + "Larger Plasma Container": "扩容等离子弹药匣", + "EX-16 PROTOTYPE 16": "EX-16“原型 16”", + "Scatters powerful anti-tank mines that deal heavy, armor-penetrating damage. Minefield is less densely packed relative to smaller mines.": "发射强力的反坦克地雷,可造成严重的穿甲伤害。与较小型的地雷相比,雷区的部署密集度较低。", + "Plasma Igniter Muzzle Brake": "等离子点火器枪口制退器", + "DISSIDENT'S NIGHTMARE": "异见者梦魇", + "CQC-5": "CQC-5", + "Automatic Braking": "自动制动", + "BREAKER SPRAY&PRAY": "千发百中“破裂者”", + "AD-11 Livewire": "AD-11“生龙活虎”", + "Patriot Blue": "爱国蓝", + "LASER SIGHT": "激光瞄准器", + "Ingress-81": "进军-81", + "Standard Barrel": "标准枪管", + "SKULL ADMIRAL": "骷髅上将", + "A projected laser, that is aligned with the barrel of the weapon, which assists the user with landing their shots.": "与武器枪管对齐的投射激光,辅助使用者命中目标。", + "5.5x50mm SELF PROPELLED": "5.5x50mm自走弹", + "Iron Sight": "机械瞄具", + "Unblemished Allegiance": "无瑕忠诚", + "Greatcloak of Rebar Resolve": "钢筋意志大氅", + "For warriors who are so strong and confident that they don't need any reassurance whatsoever.": "为那些强大自信到不需要任何保证的战士而设计。", + "Humanity's intellect shines brighter than all other, piercing even the treacherous darkness that spawned the Automatons' pseudo-sentience; the darkness known as computer science.": "人类的智慧比万物更闪耀,能刺穿孕育机器人伪智能的“计算机科学”诡谲黑雾。", + "Conductor of Brilliance": "辉煌指挥官", + "The Hellbomb is a tactical nuke powerful enough to destroy any perceivable target in its blast zone. For safety and budgetary reasons, it has to be armed manually once deployed.": "地狱火炸弹是一种战术核武器,威力足以摧毁轰炸范围内的任何可见目标。出于安全和预算的原因,地狱火炸弹部署后必须手动启动。", + "FEDERATION'S EMBRACE": "联邦怀抱", + "Created to honor the great Freedom Chant of 2-14, in which over 10,000 loyal citizens united as one to express their undying respect for Freedom.": "为纪念伟大的2-14自由颂歌而创作,其时,有超过10,000名忠诚的公民联合表达了他们对自由的永恒敬重。", + "Short Revolver Barrel": "左轮手枪短枪管", + "EXPANDED BOMB RACKS": "扩展炸弹挂架", + "EPOCH": "纪元", + "G-4": "G-4", + "TENDERIZER": "肉锤", + "40mm APHE CANNON": "40mm穿甲高爆炮弹", + "HOLOGRAPHIC SIGHT": "全息瞄准镜", + "The default paint job for this weapon.": "该武器默认涂装。", + "100KG CLUSTER BOMB": "100KG集束炸弹", + "Marks the most obedient of the obedient, those who will strike headlong at the veins of Tyranny and administer the sweet antidote of Freedom.": "最顺从者的印记,当属毫不犹豫打击暴政血脉、为自由精神注入甜美解毒剂的人。", + "A camo paint job for use in urban environments.": "适用于城市环境的迷彩涂装。", + "85mm High-Explosive Grenade": "85mm高爆榴弹", + "EAGLE STRAFING RUN": "“飞鹰”机枪扫射", + "Improved Projectiles": "改良射弹", + "Constitution": "宪法", + "MAGAZINES": "弹匣", + "A turret firing powerful and precise laser beams. Warning: overloading heat sink may cause adverse effects.": "炮台,可发射威力强悍且精准的激光束。警告:散热器过载可能产生反效果。", + "Patriotic Administration Center": "爱国行政中心", + "ARC-3": "ARC-3", + "BOXER": "拳击手", + "PLAS-101": "PLAS-101", + "A paint job that is one with the darkness.": "与黑暗融为一体的涂装。", + "VERY LONG": "非常长", + "Breaker Incendiary": "高燃“破裂者”", + "Increased Fire Rate": "提升射速", + "SMG-203": "SMG-203", + "More HMG Mount Mags": "增加架设型重机枪弹匣", + "Diligence Counter Sniper": "反狙击“勤勉”", + "Treasure Hunt": "寻宝", + "13x40mm Hollow Point": "13x40mm空尖弹", + "MP-98": "MP-98", + "Solo Silo Targeting Remote": "单兵导弹发射井定位遥控器", + "MASTER DIVEMASTER": "大师潜兵长", + "Salvo Fire": "炮弹齐射", + "EYE OF FREEDOM": "自由之眼", + "ORBITAL WALKING BARRAGE SMOKE": "轨道游走烟雾火力网", + "Enables the user to jump higher than 'gravity' and 'safety' would normally allow. Must be charged before use.": "可助力使用者跳得更高,无视日常“重力”和“安全规范”的束缚。使用前必须充能。", + "SUPPORT": "支援", + "SSSD Delivery": "运送超级固态硬盘", + "8MM": "8mm", + "Increases sidearms reload speed by #BONUS.": "副武器重装速度提高#BONUS。", + "SEAF ARTILLERY: STATIC FIELD": "超级地球武装部队大炮:静电场", + "PROGRAMMABLE AMMO STUN ROUNDS": "智能眩晕弹", + "B-16 BATTLE-SCARRED VETERAN": "B-16“百战老兵”", + "SABER": "军刀", + "ASSAULT": "特攻", + "12x25mm High Velocity": "12x25mm高速弹", + "SENATOR": "参议员", + "EVEN MORE ARC SPLITS": "增加更多电弧分裂数", + "WELCOME ADORATION": "尽情崇拜", + "EXTRA BACKPACKS": "额外补给", + "Short Magazine": "短弹匣", + "R-63CS": "R-63CS", + "AR/GL-21": "AR/GL-21", + "Rapid Heatsink": "快速散热器", + "Based on a colonial surgeon's gown, where surgeries were often interrupted by a need to perform defensive duties.": "原型是殖民地外科医生的手术袍。外科医生经常在手术中途被打断,受命立刻前去执行防卫任务。", + "DP-40 HERO OF THE FEDERATION": "DP-40“联邦英雄”", + "CONDUCTOR OF BRILLIANCE": "辉煌指挥官", + "12g BIRDSHOT": "12g鸟弹", + "Shock and Awe Improvement": "提高震慑威力", + "5.5x50mm HOLLOW-POINT": "5.5x50mm空尖弹", + "Nuke": "核弹", + "Halt": "止息", + "Free-Spirited Spangles": "自由之魂的辉映", + "LIBERATOR": "解放者", + "MUZZLE VELOCITY": "枪口初速", + "SH-51": "SH-51", + "Breaker Spray&Pray": "千发百中“破裂者”", + "A throwable emplacement that generates a spherical, projectile-blocking shield on impact. Has a limited lifetime once deployed.": "可投掷的防护装置,落地时生成阻挡投射物的球形护盾。部署后的持续时间有限。", + "CW-22 Kodiak": "CW-22“科迪亚克”", + "THORACIC COLLISION EXULTATION MANEUVER": "碰胸庆祝", + "A slamfire shotgun: fires continuously while the trigger is depressed, via activation of the pump-action mechanism. Loaded with armor-piercing flechettes and equipped with an extended bayonet.": "一款速射霰弹枪:扣住扳机即可连续开火射击,采用泵动结构。装填穿甲飞镖弹,并配备加长刺刀。", + "RE-EDUCATOR": "思想改造", + "Loading Drills": "熟练装载配备", + "9x70mm Sniper Armor Piercing": "9x70mm穿甲狙击弹", + "Front-leaning rest position": "俯卧撑姿势", + "12g FLECHETTES": "12g飞镖弹", + "TX-41": "TX-41", + "SPACE CHIEF PRIME": "太空军督", + "PLASMA IGNITER CHOKE": "等离子点火器喉缩", + "DISPLAY OF BRAWN": "肌肉展示", + "Adorned with the insignia of the Order of the Venerated Ballot, a Ministry-sanctioned Patriot's Club for citizens who pledge themselves to preserving the sanctity of voting.": "饰有神圣投票团的徽章,该组织是由外交部批准设立的爱国者俱乐部,加入其中的公民承诺维护投票权的神圣性。", + "G-6": "G-6", + "EXTRA JUDICIAL": "法外制裁", + "Improves weapons handling with less drag on weapon movement.": "提升武器操纵性,降低携带武器移动的阻力。", + "A large-capacity assault rifle firing humane stun rounds. Reports of lethal incidents have been thoroughly debunked.": "大容量突击步枪,能发射人道主义眩晕弹药。相关致命事件的报告已被证实为谣言。", + "A specialized Fast Recon Vehicle equipped with heavier armor, a spiked ramming grille, and a roof-mounted heavy flamethrower at the expense of seating; this FRV can enable up to three Helldivers to deliver high-speed Justice, and forcefully clear obstructed transport routes.": "牺牲了座位以换取更厚重的装甲、带刺的冲撞格栅以及车顶安装的重型火焰喷射器。该快速侦察载具最多可承载三名绝地潜兵,高速播撒正义,强力打通受阻的运输路线。", + "Dynamite": "炸药", + "DP-40 Hero of the Federation": "DP-40“联邦英雄”", + "DP-11 CHAMPION OF THE PEOPLE": "DP-11“人民捍卫者”", + "SMG-32": "SMG-32", + "Crests the shoulders of those who deliver the final—and most indispensable—stroke of Justice.": "献给发起不可或缺的最终正义一击之人。", + "20mm FLAK ROUNDS": "20mm高射炮弹", + "Provides immunity to leg injuries.": "免疫腿伤。", + "TIP HAT": "脱帽致意", + "9x70mm SOCOM ASSASSIN": "9x70mm“刺客”特种作战弹", + "A high-speed Fast Recon Vehicle equipped with an automated defense turret and a mounted supply rack, allowing frontline personnel to fully replenish ammunition and medical supplies on the move.": "高速的快速侦察载具,配备自动防御炮台和挂载式补给架,允许前线人员在移动中全面补充弹药和医疗补给。", + "SIGNAL: HOLD": "信号:等待", + "70mm Laser-Guided Missile Mk2": "70mm激光制导导弹 MK2", + "You're Next": "轮到你", + "PRIDE OF THE WHISTLEBLOWER": "检举者的荣耀", + "ROVER": "漫游车", + "Some soldiers report picking up strange radio interference when wearing this armor near alien artifacts.": "部分士兵报告称,穿着这套盔甲接近外星古物时,会接收到奇怪的无线电干扰信号。", + "RS-67 Null Cipher": "RS-67“空密码”", + "An incendiary weapon for close range. Will ignite targets, terrain, and any flammable teammates.": "用于近程作战的燃烧武器,能点燃目标、地面,以及易燃易爆炸的队友。", + "85mm HIGH-EXPLOSIVE GRENADE": "85mm高爆榴弹", + "COMMAND DIVEMASTER MAJOR": "潜兵长少校指挥官", + "No oppressive murk, no fascist penumbra, no dictatorial haze and no unfree emanation; no tyrannical Gloom shall ever stand a chance against the searing light of Helldiver fire.": "无论是压迫的黑暗、法西斯的半阴影、独裁的迷雾还是非自由精神的辐射,任何专制的“阴霾”在绝地潜兵烈火般的灼热光芒前都将灰飞烟灭。", + "More Durable Chassis": "提升底盘耐久度", + "The burnished blood-red plates are forged in righteous fire, like the heroes they were wrought to protect.": "这闪闪发亮的血红色盔甲跟它保护过的英雄一样经受过正义之火的考验。", + "TR-9 CAVALIER OF DEMOCRACY": "TR-9“民主骑兵”", + "ANTI-TANK": "反坦克", + "Orbital Airburst Strike": "轨道空爆攻击", + "RAILGUN ROUND": "磁轨炮弹", + "EMS MORTAR SENTRY": "电磁冲击波迫击哨戒炮", + "APHET": "穿甲高爆曳光弹", + "OMBUDSMAN": "巡察者", + "Bugslayer": "诛虫煞星", + "2x TUBE RED DOT": "2倍红点瞄准镜", + "UF-84 DOUBT KILLER": "UF-84“疑虑克星”", + "LIFT-182": "LIFT-182", + "8x60mm LIBERTY FIRE": "8x60mm“解放之火”子弹", + "Grenadier Battlement": "掷弹兵防卫墙", + "AUTO LOADER": "自动装载", + "Woven in honor of our loyal Helldivers, whose heart's blood is the foundation on which Super Earth is built.": "这件披肩旨在纪念忠诚的绝地潜兵,他们的一腔热血是超级地球的发展根基。", + "MACHETE": "砍刀", + "AC-2 OBEDIENT": "AC-2“服从指挥”", + "ROCKET SENTRY": "火箭哨戒炮", + "Shield": "盾雷", + "SUPER SHERIFF": "超级警长", + "A/AC-8": "A/AC-8", + "Larger Explosion": "扩大爆炸范围", + "10g HE Rounds": "10g高爆弹", + "A stationary energy shield which provides cover against projectiles. Has a limited lifetime once deployed.": "固定式能量护盾,可用作掩体抵挡射弹。部署完毕后仅在有限时间内起防护作用。", + "13x40mm Magnum": "13x40mm马格南子弹", + "An advanced vertical foregrip to improve the maneuverability of the weapon.": "高级垂直前握把,可提升武器操控性。", + "40mm HEAT GRENADE": "40mm高爆反坦克榴弹", + "W.A.S.P. Launcher Backpack": "W.A.S.P.发射器背包", + "REFLEX SIGHT": "反射式瞄准镜", + "CM-21 TRENCH PARAMEDIC": "CM-21“战壕护理员”", + "Roll 'Em": "骰子定胜负", + "ROOKIE": "菜鸟", + "Vector of Victory": "胜利矢量", + "Tyranny's Bane": "暴政的毁灭", + "10g MAGNUM TRI-BALL": "10g马格南三连弹", + "The yellow is the exact shade of the Ministry of Unity's 'Golden Gate', leading to the Chamber of Unanimous Decision.": "这正是团结部“金门”的颜色,打开大门便能前往统一决策大厅。", + "ORBITAL GAS ROUND MK2": "轨道毒气弹 Mk2", + "CE-64 Grenadier": "CE-64“掷弹兵”", + "Lumberer Exosuit": "“伐木者”外骨骼装甲", + "Machine Gun": "机枪", + "Based on the ceremonial pennant flags of early Super Earth, which now adorn the entrance to each Ministry.": "设计原型是早期超级地球的仪式用三角旗,如今用于装饰各部门的入口。", + "Re-educator": "思想改造", + "REFLEX SIGHT MK2": "反射式瞄准镜MK2", + "This humane device attaches to its target and dispenses repeated electrical pulses, keeping the target in place for humane apprehension and/or termination.": "附着在目标上反复释放电击脉冲的人道主义设备,能将目标固定在原地,方便实施人道主义逮捕或处决。", + "8x60mm PENETRATOR": "8x60mm穿甲弹", + "SMALL PLASMA BOLT": "小型等离子弹", + "SC-37 LEGIONNAIRE": "SC-37“军团士兵”", + "ARMOR PENETRATION": "穿甲攻击", + "AX/TX-13": "AX/TX-13", + "To honor the heartfelt siblinghood of the heroes who stood together, bled together, and laid down their lives together in defense of Equality-On-Sea, all Helldivers are awarded one (1) commemorative polyester cape.": "为致敬在仰齐浜保卫战中共同浴血奋战的同志情谊,所有绝地潜兵将获赠一件(1)聚酯纪念披风。", + "A pistol firing bursts of guided, jet-propelled ammunition. Can be set to non-guided mode at any time, removing the need to lock on to targets.": "能发射制导喷射弹的手枪。随时可切换为非制导模式,无需锁定目标。", + "Flash Hider": "消焰器", + "HEEL KICK": "踢踏步", + "FOCUSED PRISM": "聚焦棱镜", + "STANDARD HEATSINK": "标准散热器", + "Improved targeting system": "改良目标锁定系统", + "A/FLAM-40": "A/FLAM-40", + "SCOUT": "侦察", + "TG-122 DEMO-TROOPER": "TG-122“爆破兵”", + "FLEET ADMIRAL": "舰队上将", + "TARGET SIGHTED": "索敌雷", + "Defoliation Tool": "除叶工具", + "Hair Trigger": "微力扳机", + "THIS GUY": "这家伙不得了", + "An incendiary device that shatters on impact, without explosive force, instantly creating a localized and persistent combustion field.": "一种撞击即碎的燃烧装置,无爆炸力,可瞬间产生局部且持久的燃烧区域。", + "10g HE ROUNDS": "10g高爆弹", + "A heavily-armored tank destroyer armed with a 120mm high-velocity cannon and a heavy coaxial machinegun.": "重装甲坦克歼击车,配备120mm高速火炮和重型同轴机枪。", + "BEACON OF MERCY": "仁慈信标", + "CREMATOR": "焚燃者", + "INCREASED OVERCHARGE TIME": "延长超负荷充电时长", + "SC-37 Legionnaire": "SC-37“军团士兵”", + "SR-24 Street Scout": "SR-24“街头侦察兵”", + "Part of a long line of experimental armor commonly seen on industrial engineering campuses, in the basements of select science aficionados, and around Super Destroyer Mega Garages.": "这件盔甲源于历史悠久的实验性盔甲系列,常见于工业工程学院、部分科学爱好者的地下室,以及超级驱逐舰大型车库内。", + "TR-7 Ambassador of the Brand": "TR-7“形象大使”", + "Federation's Embrace": "联邦怀抱", + "URBAN": "城市", + "13x40mm MAGNUM": "13x40mm马格南子弹", + "HUMBLE REGALIA": "谦卑徽记", + "Increased Storage Mk2": "可携带数量升级 MK2", + "70mm HE Rocket": "70mm高爆火箭弹", + "HOVER PACK": "悬浮背包", + "TOP DOWN": "自上而下", + "This cape has a visual pattern that when scanned by Automaton sensors translates to “defile your microwave mother, bot scum.”": "这款披风上的视觉图案被机器人传感器扫描时,会显示为“回你妈炉里重造吧,铁皮渣滓。”", + "DATA JACK": "数据接口", + "BETTER RACKS": "提高挂架质量", + "EMS Mortar Sentry": "电磁冲击波迫击哨戒炮", + "Smokescreen": "烟幕", + "10g Birdshot": "10g鸟弹", + "CQC-9": "CQC-9", + "Crewspace Removal": "移除船员舱", + "AT EASE": "稍息", + "WINDSWEPT WAYFINDER": "风驰引路者", + "EX-00 PROTOTYPE X": "EX-00“原型X”", + "AX/FLAM-75": "AX/FLAM-75", + "9x70mm SNIPER ARMOR PIERCING": "9x70mm穿甲狙击弹", + "Houses the Eagle Fighter & Pelican Shuttle. Also receives deliveries of materiel, supplies, frozen personnel, and fuel.": "停放“飞鹰”战斗机与“鹈鹕”运输船,同时还接收运来的材料、物资、冷冻人员以及燃油。", + "AUTOMATIC BRAKING": "自动制动", + "FIRE RATE": "射速", + "AD-49 Apollonian": "AD-49“阿波罗神”", + "Arc Thrower": "电弧发射器", + "STRATAGEM STATS": "战略配备数据", + "MORE MAGAZINES": "增加弹匣", + "HIGH-PRESSURE NAPALM": "高压凝固汽油弹", + "A linear artillery barrage which moves at intervals while firing smoke bombs to obscure enemy visibility.": "间歇性移动的线形火力网,通过发射烟雾弹,阻断敌方视线。", + "QUASAR CANNON": "类星体加农炮", + "A targeting remote, used in combination with the Solo Silo.": "定位遥控器,与单兵导弹发射井配合使用。", + "The unimpeachable justice of this cape's design is said to blind the enemies of Freedom with its glorious light.": "据说,此披肩无懈可击的正义设计将以荣耀光辉蒙蔽自由之敌的双目。", + "A high-caliber assault rifle with a restrictive magazine size but more stopping power.": "大口径突击步枪,弹匣容量有限,但停止作用较强。", + "10g High Velocity Sabot": "10g高速萨博特式霰弹", + "9x20mm Ripper": "9x20mm撕裂弹", + "LARGE PLASMA BOLT": "大型等离子弹", + "Dominator": "主宰", + "The embroidered pattern uses aluminium from Automaton motherboards, granting the once-wretched metals a new and noble purpose.": "刺绣图案采用了机器人主板上的铝材,为这些卑劣的金属赋予了更崇高的新使命。", + "Squat": "蹲坐", + "LARGER MAGAZINES": "扩容弹匣", + "SHOULDER-MOUNTED": "肩架式", + "70mm HE ROCKET": "70mm高爆火箭弹", + "First deployed in the Helldivers \"Diplomatic\" Corps, this armor enables effective non-verbal interspecies communication.": "这种盔甲最初投用于绝地潜兵的“外交”部队,非常适用于不同种族之间的非言语交流。", + "AUTOCANNON SENTRY": "自动哨戒炮", + "FLEX": "炫耀", + "Prosperous Green": "繁荣绿", + "FRAG": "破片手雷", + "BELT-FED GRENADE LAUNCHER": "弹链式榴弹发射器", + "ADVANCED ANGLED FOREGRIP": "高级直角前握把", + "As this cape flutters in the wind, it evokes a wishful, twinkling star in the sky—a star ripe for conquest.": "这件披肩在风中飘扬时,让人不禁联想到空中那颗充满希望、闪闪发光的星星,一颗等待征服的星星。", + "HIGH CAPACITY HEATSINK": "高容量散热器", + "RS-20 CONSTRICTOR": "RS-20“绞杀者”", + "RECOIL SIMULATION": "后坐力模拟", + "Purifier": "净化者", + "Supply FRV": "补给型快速侦察载具", + "Stun": "眩晕弹", + "A simple vertical foregrip to improve the maneuverability of the weapon.": "简单垂直前握把,可提升武器操控性。", + "A modified Punisher shotgun firing heavy, high-damage slug rounds. Perfect for punching big holes in big targets.": "改良后的“制裁者”霰弹枪,可发射重型高伤害独头弹,是往大型目标身上开洞的完美之选。", + "DS-42 Federation's Blade": "DS-42“联邦之刃”", + "This sigil reaffirms the Helldiver's pledge to protect Managed Democracy, serve Managed Democracy, and uphold Managed Democracy.": "这枚徽章再次强调了绝地潜兵对管理式民主的誓言:保卫、效命、秉持管理式民主。", + "This armor is the Super Earth Standard Issue, made from the same titanium alloy as the Destroyer's hull.": "超级地球制式盔甲,使用驱逐舰舰体的同种钛合金制成。", + "IE-3 MARTYR": "IE-3“烈士”", + "NUKE": "核弹", + "23mm HE CANNON": "23mm高爆炮弹", + "PH-202 TWIGSNAPPER": "PH-202“折枝”", + "NO MUZZLE": "无枪口配件", + "Lure Mine": "诱饵地雷", + "A heavier version of the Breaker shotgun, with higher damage at the cost of recoil and maneuverability.": "更重型的“破裂者”霰弹枪,虽然牺牲了后坐力和操控性,伤害却有所提升。", + "G-50": "G-50", + "110mm E.M.S. Cannon Round Mk2": "110mm电磁冲击波炮弹 MK2", + "Bearer is more resistant to being knocked prone.": "配备此盔甲可降低被击倒的概率。", + "Standard Prism": "标准棱镜", + "LAS-58": "LAS-58", + "Sweeper": "扫荡者", + "Railgun": "磁轨炮", + "A perfectly balanced multitool, optimized for the displacement of soil and other forms of resistance with surgical precision.": "一款完美平衡的多功能工具,经过特别优化,能以外科手术级的精准度移除土壤以及其他形式的抵抗。", + "Target Sighted": "索敌雷", + "10g RIFLED SLUGS": "10g线膛独头弹", + "Defender of Our Dream": "梦想卫士", + "DP-53 SAVIOR OF THE FREE": "DP-53“自由救星”", + "PH-56 Jaguar": "PH-56“捷豹”", + "Homing Ground Missile": "追踪式地面导弹", + "Bastion of Integrity": "忠义堡垒", + "Each gilded detail is polished to perfection by re-educated dissidents, as part of the Lifelong Post-Infraction Atonement Program.": "每一片镀金都由接受再教育的异见分子在终身违纪赎罪计划的监管下精心打磨至完美状态。", + "Increases the wearer's walking and running speed.": "可提升穿着者的步行与奔跑速度。", + "YOU'RE NEXT": "轮到你", + "A tribute to the mischief-makers and mavericks, those trailblazers who dutifully execute their orders with universally-endearing panache. The star-crossed trail calls to mind the special kind of Freedom that can only be achieved by going very fast in very expensive state-owned vehicles.": "对捣蛋鬼与特立独行者的致敬之作,这些开疆拓土的先锋恪尽职守使命必达,潇洒风度广受拥戴。如星轨交错般的下摆令人联想到一种特殊的“自由”——惟有为国驾驶价值不菲的载具疾速冲锋方能得到的自由。", + "UNFLINCHING": "毫不畏缩", + "This cape signifies that its wearer thinks, feels, and acts correctly at all times, and thus bears the responsibility to educate and re-educate their fellow citizen.": "这件披肩象征着穿戴者的思想、情感和行为一向无可指摘,因而肩负着教育和再教育同胞的重任。", + "It is said that only the truly Democratic can lift this cape to their shoulders.": "据说,只有真正的民主主义者才能披上此披肩。", + "ONE TRUE FLAG": "唯一真旗", + "Flashield": "闪光护盾", + "A pistol front-loaded with a single, powerful explosive. The weight of the projectile limits the weapon's range.": "前端加装单颗强力射弹的手枪。射弹重量限制了手枪的射程。", + "Rendering the Helldiver's descent to the battlefield in splendorous foil, this cape illustrates that in any successful military machinery, heroic humans are the most vital piece.": "这件披风以华丽烫印工艺展现了绝地潜兵空降战场的英姿,向世人昭示了一个真理:对于任何运转良好的军事机器来说,英勇无畏的人类都是最关键的部件。", + "Improved Reloading Process": "改良装弹流程", + "Redirects propellant gases to reduce recoil when firing the weapon.": "通过更改推进气体流向,减少射击时的后坐力。", + "12g LIBERTY FIRE": "12g“解放之火”霰弹", + "AMMUNITION STATS": "弹药数据", + "Offers its user brief fixed-height flight, stable enough for pinpoint marksmanship.": "穿戴者可在固定高度短暂稳定飞行,确保实现精确射击。", + "500kg Bomb": "500KG炸弹", + "PLAS-39": "PLAS-39", + "10g Flechettes": "10g飞镖弹", + "Designed to render even the largest foes into considerably smaller, and vastly more compliant, constituent parts. Sacrifices throwing range for a massive detonation on impact.": "旨在将体型最庞大的敌人拆解为体积小得多且远远更易“拿捏”的组成部件。以牺牲投掷距离为代价,换取命中时毁灭性爆炸威力。", + "The official uniform of the League of Patriotic Arm Wrestlers, this armor's lycra base layer is supple and sweat-wicking for maximum flexing comfort.": "爱国腕力联盟的官方制服,其莱卡底层布料柔软且兼具吸湿排汗功能,可为高强度的掰手腕动作提供极致舒适性。", + "A paint job for use in urban environments.": "适用于城市环境的涂装。", + "An angled foregrip to improve weapon stability.": "直角前握把,可提升武器稳定性。", + "CITY FIGHTER'S RESOLVE": "城市战士的决意", + "2x SUPPORT SCOPE": "2倍支援瞄准镜", + "A high explosive grenade which damages lightly armored targets. Creates high damage over a small area when detonated.": "高爆榴弹,能伤害轻型装甲的目标。引爆时可在小范围内造成较高伤害。", + "TR-62 KNIGHT": "TR-62“骑士”", + "GAS MINES": "毒气地雷", + "TG-122 Demo-Trooper": "TG-122“爆破兵”", + "AC-2 Obedient": "AC-2“服从指挥”", + "Liberator Concussive": "震荡“解放者”", + "A 'compliance weapon' to modify enemy behaviour. Creates a thick smoke screen to block targets' line of sight.": "改变敌人行为的“慑敌武器”,可形成一道厚重的烟幕,遮挡目标的视线。", + "CPR-80 Bulwark": "CPR-80 “壁垒”", + "Melta Mine": "热熔地雷", + "A/M-12": "A/M-12", + "STUN LANCE": "眩晕长矛", + "Eagle Cluster Bomb": "“飞鹰”集束炸弹", + "SWAY": "摆动", + "This aim-stabilizing armor found surprising secondary market success among alien birdwatching enthusiasts.": "这套可稳定瞄准动作的盔甲出乎意料地受到了外星观鸟爱好者的青睐,在二级市场大获成功。", + "Light Armored Vehicle": "轻甲载具", + "PH-56 JAGUAR": "PH-56“捷豹”", + "10g TRI-BALL": "10g三连弹", + "More Magazines": "增加弹匣", + "10g Sabot": "10g萨博特式霰弹", + "GS-17 Frontier Marshal": "GS-17“边境元帅”", + "Improved Rounds": "改良弹药", + "12g Buckshot Shells": "12g鹿弹霰弹", + "20mm APHET ROUNDS": "20mm穿甲高爆曳光弹", + "CQC-20": "CQC-20", + "HOMING GROUND MISSILE MK2": "追踪式地面导弹 MK2", + "Stinger": "毒刺", + "An antipersonnel fragmentation grenade. Creates damage over a large area when detonated.": "反步兵破片榴弹,引爆时可在大范围造成伤害。", + "SHAFTS OF DESPAIR": "绝望之柱", + "Improved Aiming Servos": "改良瞄准伺服系统", + "A modified Diligence rifle offering increased damage at the cost of some maneuverability. Fires a single bullet at a time.": "改良的“勤勉”步枪,伤害有所提高,但牺牲了一点操控性。每次只能发射一发子弹。", + "12x25mm HIGH VELOCITY": "12x25mm高速弹", + "Guard Dog": "“护卫犬”", + "VOLATILE PLASMA BOLT": "易气化等离子弹", + "WARP PACK": "传送背包", + "ATTACK SPEED": "攻击速度", + "CE-81 JUGGERNAUT": "CE-81“巨人”", + "SUPPLY FRV": "补给型快速侦察载具", + "RS-89 Shadow Paragon": "RS-89“暗影典范”", + "4x Combat Scope": "4倍战斗瞄准镜", + "STIMULATIVE": "治疗剂", + "A-35 RECON": "A-35“侦察者”", + "Prepared Crates": "预备弹药箱", + "#BONUS chance to not die when taking lethal damage.": "受到致命伤害时,不会阵亡的概率额外提高#BONUS。", + "12g BUGSHOT": "12g虫弹", + "Spire Sterilizer": "虫塔杀菌器", + "A flattened muzzle that forces the shotgun pellets into a thin horizontal line.": "扁平枪口,迫使霰弹呈水平细线发射。", + "LARGE DRUM": "大型弹鼓", + "Diagram of the Noblest Payload": "至高使命图谱", + "I-102 Draconaught": "I-102“龙行者”", + "REINFORCE": "增援", + "AF-91 FIELD CHEMIST": "AF-91“实地化学家”", + "E/AT-12": "E/AT-12", + "Supply boxes containing ammunition, with a backpack that allows the user to distribute boxes to fellow Helldivers.": "装着弹药的补给箱,配有背包,可供使用者将箱子分配给其他绝地潜兵。", + "Trucker's Triumph": "卡车司机的胜利", + "Ombudsman": "巡察者", + "GAS": "毒气榴弹", + "Incendiary support fed by a massive backpack fuel tank. This heavy flamethrower enables a continuous column of fire to cleanse the battlefield.": "由巨型背负式燃料罐提供燃料的燃烧型支援武器。这款重型喷火器能喷射出一道持续的火柱,荡涤净化战场。", + "Napalm Bomb Mk2": "凝固汽油弹 MK2", + "8x60mm Explosive": "8x60mm爆炸子弹", + "AX/ARC-3": "AX/ARC-3", + "DEFOLIATION TOOL": "除叶工具", + "COVERING FIRE": "火力掩护", + "DP-53 Savior of the Free": "DP-53“自由救星”", + "DAMAGE / SEC": "每秒伤害", + "Larger Fuel Tank": "扩容燃料罐", + "RAGS OF THE FASHIONABLE": "时尚褴褛", + "Breaching Hammer": "破门锤", + "Faster Deployment": "加快部署", + "A pistol that fires grenades. Must be reloaded between shots.": "发射榴弹的手枪,每射击一发子弹后必须重新装弹。", + "SEAL OF GENERAL CONSENSUS": "康森瑟斯将军之印", + "ORBITAL PRECISION STRIKE": "轨道精准攻击", + "TREASURE HUNT": "寻宝", + "No Choke": "无喉缩", + "PLAS-1": "PLAS-1", + "G-123": "G-123", + "An accurate, hard-hitting laser revolver with bespoke break action for heat sink swaps.": "精准且威力强大的激光左轮手枪,定制中折式设计便于更换散热器。", + "Laser": "激光", + "ENGINEER": "工兵", + "Holder of the Yellow Line": "黄线捍卫者", + "Patched and tattered, this banner yet waves from the unbowed shoulders of Freedom's most battle-tested warriors.": "这面旗帜虽历经修补,却依然飘扬在久经沙场的自由战士们不屈的肩膀之上。", + "R/40-K": "R/40-K", + "Machine Gun Sentry": "哨戒机枪", + "When facing the enemies of Freedom this Reckoningtide, keep up the festive spirit by recalling the opening line of A Vengeant Carol: \"They'll soon be dead, to begin with.\"": "在这个清算时节面对自由之敌时,请牢记《复仇颂歌》的开场白,坚守我们的节日精神:“它们很快就会死去,这是故事的开始。”", + "Features a patented non-stick coating, which makes scraping viscera off after a long day of battle less taxing.": "采用专利不粘涂料,方便你在一整天的血战之后轻松去除表面的脏器。", + "12g Flechette Shells": "12g飞镖霰弹", + "FS-38 Eradicator": "FS-38“根除者”", + "Veridical Ideology": "真理意识形态", + "Ruggedized for extended operation beyond the reach of paved logistics. This armor's heavy plating is intended for the \"unpaving\" of hostile territory, providing a mobile bulkhead for Helldivers who don't know the meaning of \"environmental obstacles.\"": "为执行铺装物流以外的长时间任务而强固处理。这款护甲的重型装甲旨在“铲平”敌方领土,为不懂“环境障碍”为何物的绝地潜兵提供移动堡垒。", + "Should the wearer of this cape perish at the hands of Freedom's enemies, it is customary to pass the cape on to their bravest child during the funeral, inspiring the next generation to take up arms.": "若这件披肩的佩戴者死于自由之敌手中,按照传统,葬礼上会将披肩传给其最勇敢的子女,激励下一代拿起武器继续战斗。", + "Pillars of Freedom": "自由支柱", + "ORBITAL 380MM HE BARRAGE": "轨道380MM高爆弹火力网", + "TR-40 GOLD EAGLE": "TR-40“金鹰”", + "Tesla Tower": "特斯拉塔", + "HEAT Grenades": "高爆反坦克榴弹", + "Creates a far-reaching incendiary blast ideal for crowd control against smaller enemies of Freedom. Equipped with a programmable timer for strategic versatility.": "引发大范围燃烧爆炸,适合对小规模自由之敌实施群体控制。配备可编程定时器,增强战术灵活性。", + "P-41": "P-41", + "This shotgun blasts a wide burst of high-voltage electricity that arcs between all units—enemy or otherwise—within range.": "这把霰弹枪能在大范围内释放高压电流,在效果范围内的所有敌我单位之间形成电弧。", + "Additional Hardpoints": "附加挂载点", + "PROJECTILES": "射弹", + "66mm MISSILE MK2": "66mm导弹 MK2", + "ORBITAL GAS ROUND MK3": "轨道毒气弹 MK3", + "JAMMED PIÑATA": "满载惊喜的皮纳塔", + "Caltrops": "铁蒺藜", + "The distinctive red, white, and green of the Intergalactic Medical Corps signal to all Helldivers that help is at hand.": "看见星际医疗部队标志性的红白绿三色,所有绝地潜兵都会意识到医疗援助即将到来。", + "Testament to Attrition": "百战不殆的明证", + "SUPER PEDESTRIAN": "超级步兵", + "RIGHTFUL OCCUPIER": "正当占领者", + "EXPENDABLE NAPALM": "消耗性凝固汽油弹", + "THERMITE": "铝热弹", + "RE-2310 HONORARY GUARD": "RE-2310“荣誉卫队”", + "Increases throwing range by #BONUS.": "投掷距离延长#BONUS。", + "Tests and implements the most advanced stratagem technology that funding has been allocated for.": "测试与应用受拨款支持的顶尖战略配备技术。", + "Call in an emergency beacon to show other Helldivers that you need assistance.": "呼叫求救信标,向其他绝地潜兵表明你需要支援。", + "20mm HE Cannon": "20mm高爆炮弹", + "Incinerator FRV": "炽灼型快速侦察载具", + "Schema Laid Bare": "解封蓝图", + "LIBERATOR CONCUSSIVE": "震荡“解放者”", + "Increases ammo capacity of all weapons by #BONUS. Does not affect weapon backpacks.": "所有武器的弹药容量增加#BONUS。武器背包除外。", + "This traditional armor has remained unchanged since time immemorial. Now with self-heated padding.": "这套传统盔甲自古至今一直保持原样。而今配备了自热内衬。", + "FS-61 DREADNOUGHT": "FS-61“无畏”", + "EXPENDABLE": "消耗品", + "Originally worn by lunar terraformers, this suit can withstand rapid changes in pressure, heat, and personal velocity.": "原本是月球地形改造人员的装备,足以承受气压、温度和个人速度的急剧变化。", + "85mm HEAT GRENADE": "85mm高爆反坦克榴弹", + "Long Revolver Barrel": "左轮手枪长枪管", + "Pummeler": "暴击斗士", + "Multi-Launch Protocol": "多管发射协议", + "Popularized by actor Chip Messiter, who wore this in the action-rom-com-musical \"Lost My Heart to a Man in a Helmet.\"": "由演员奇普·梅西特推广,他曾在动作浪漫欢乐音乐剧《爱上一个不脱头盔的人》中穿着这套盔甲。", + "12x25mm Ripper": "12x25mm撕裂弹", + "120mm HE Cannon Round": "120mm高爆炮弹", + "Missile Performance": "导弹性能", + "Increased Fuel Capacity": "提升燃料容量", + "1.5x Tube Red Dot": "1.5倍红点瞄准镜", + "IE-3 Martyr": "IE-3“烈士”", + "RAISE WEAPON": "高举武器", + "PYROTECH": "烟花术", + "A pistol with a built-in laser sight, suppressor, and flashlight.\nProduced by Martian Armory.": "内置激光瞄准器、消音器和手电筒的手枪。\n由火星军械库生产。", + "9x20mm Full Metal Jacket": "9x20mm全金属被甲弹", + "CPH-26 COMMANDANT": "CPH-26“司令官”", + "MORE HMG MOUNT MAGS": "增加架设型重机枪弹匣", + "A camo paint job for use in forest environments.": "适用于森林环境的迷彩涂装。", + "DP-8 MOUNTAIN-SCALED": "DP-8“山峦鳞甲”", + "FAF-14": "FAF-14", + "RANGER, EAGLE CLASS": "飞鹰级游骑兵", + "40mm HEAT Grenade": "40mm高爆反坦克榴弹", + "Variable": "变数", + "GUNS OF LIBERTY": "自由利器", + "NAPALM BOMB MK3": "凝固汽油弹 MK3", + "SH-20": "SH-20", + "Larger Ammunition Storage": "扩充弹药存储量", + "LONGER FIRE TIME": "射击时间延长", + "A repurposed firework that showers its immediate surrounding area in sparks before exploding. As delightful as it is incendiary.": "由烟花改装而成,在爆炸前向四周溅射火花。既绚丽如烟火,又致命如烈焰。", + "Increases initial inventory and holding capacity of throwables by #BONUS.": "投掷武器的初始库存和持有上限增加#BONUS。", + "EAGLE SMOKE STRIKE": "“飞鹰”烟雾攻击", + "Longer Grenade Belt": "加长榴弹腰带", + "VIGOROUS THRUSTING": "盛气凌人", + "FULL CHOKE": "全喉缩", + "8x60mm Double Power": "8x60mm双效子弹", + "110mm Airburst Cannon Round Mk2": "110mm空爆炮弹 MK2", + "CM-06 COMBAT MEDIC": "CM-06“医疗兵”", + "Projects an arc of lightning at close range. Charges up to project bolts, and may discharge through multiple targets.": "在近程范围内发射一道电弧。充能可发射电球,然后向多个目标放电。", + "ADMIRAL": "上将", + "B-02 Gloom Warden": "B-02阴霾守望者", + "Veto": "否决者", + "8x60mm EXPLOSIVE": "8x60mm爆炸子弹", + "An armor often worn by frontline surgeons, who are skilled at both putting bodies back together and taking them apart.": "前线外科医生的常用盔甲。他们既有出色的缝合技术,也很了解该怎样将敌人大卸八块。", + "FORTIFIED": "强化", + "Gives wearer a #BONUS chance to avoid grievous limb injury.": "佩戴者有#BONUS的几率避免四肢重伤。", + "Finger Guns": "手指枪", + "HORIZONTAL RECOIL": "水平后坐力", + "Hot-shot Marksman Rifle": "高能精确射手步枪", + "9x70mm FULL METAL JACKET": "9x70mm全金属被甲弹", + "12g Birdshot": "12g鸟弹", + "STIM PISTOL": "治疗剂手枪", + "Stun Explosion": "眩晕爆炸", + "12g Tri-Ball": "12g三连弹", + "Liberator Penetrator": "穿甲“解放者”", + "Shield Generator Relay": "防护罩生成中继器", + "9x70mm SUPER URANIUM CORE": "9x70mm超铀芯弹", + "FLAMES": "喷射火焰", + "BREAKER": "破裂者", + "SPEAR": "飞矛", + "An autonomous drone equipped with a Liberator assault rifle, providing 360° cover. Returns to backpack to rearm.": "配备“解放者”突击步枪的自主无人机,可提供全方位掩护。需要补充弹药时会返回背包。", + "12g Scatter Shot": "12g散射弹", + "A cape inspired by hypothetical covert operatives—pillars of Democratic order, operating in the hostile abyss where Liberty's light cannot yet reach.": "这件披肩的灵感源于幻想的秘密特工,他们被视为民主秩序的支柱,在尚未亮起自由之光的危险深渊中执行任务。", + "KDM-500 OUTRIDER": "KDM-500“先驱骑兵”", + "Adjudicator": "审判者", + "Equip stratagems to be able to drop into a mission!": "装备战略配备后才能投身任务!", + "MORE ARC SPLITS": "增加电弧分裂数", + "EXTRA PADDING": "额外垫料", + "Bearers of this cape take upon a sacred duty: that of delivering righteous retribution to every last deserving being.": "穿戴此披肩的人将背负神圣的使命:向每一个罪有应得的生灵发动正义的复仇。", + "Delivers silent justice to Freedom's enemies.": "向自由之敌传递无声的正义。", + "PINEAPPLE": "菠萝", + "MORE SALVOES": "增加齐射炮弹数", + "LARGER ROCKET PODS": "提升火箭巢装载量", + "Exploding Crossbow": "爆燃弩", + "Increased Overcharge Time": "延长超负荷充电时长", + "9x20mm High Velocity": "9x20mm高速弹", + "Shorter Cooldown Mk2": "冷却用时缩短 Mk2", + "TRUE GRIT": "坚韧不拔", + "A pump shotgun that fires a burst of incendiary phosphorus pellets, setting targets ablaze.": "泵动式霰弹枪,可连射燃烧磷弹,将目标点燃。", + "#NAME PERMIT": "#NAME许可证", + "STAMINA DRAIN": "耐力消耗", + "C4 PACK": "C4背包", + "FINGER GUNS": "手指枪", + "The SteerComfort fit of this armor allows the wearer to feel every curve, bump, and jostle of their Exosuit, as if they were one single being.": "这套盔甲的“舒适贴合驾控”设计能让穿着者感知外骨骼装甲的每一次弯折、颠簸与震动,仿佛人机合一。", + "Research suggests that Helldivers wearing this cape are seen as 17% more patriotic.": "研究表明,绝地潜兵如果穿着这件披肩,所展现的爱国程度将提升17%。", + "TOTAL VALUE": "总价值", + "EXECUTIONER'S CANOPY": "刽子手的披风", + "Larger Rocket Pods": "提升火箭巢装载量", + "Those taken under the wings of the Law can rest easy knowing that their transgressions will soon be laid bare, their harms amended, and their citizenship safely sequestered.": "那些在法律羽翼庇护下的人将无需再担忧,因为他们的罪行很快就会揭露无遗,曾经造成的伤害会得到弥补,而他们的公民身份也将被安全并妥善地剥夺。", + "Large Plasma Bolt": "大型等离子弹", + "Made famous by the Ministry of Intelligence's hide-and-seek-and-destroy champion of '52, this armor has been improved by removing excess shoulder protection.": "这套盔甲因赢得情报部52年度“隐蔽歼敌”比赛冠军而闻名。已移除多余的肩部护甲,进一步改良了设计。", + "IMPACT": "冲击弹", + "500kg BOMB MK3": "500KG炸弹 MK3", + "FS-34 Exterminator": "FS-34“灭绝者”", + "Watchful Compatriot": "守望同胞", + "Autocannon Backpack": "机炮背包", + "SG-225NS": "SG-225NS", + "S-11": "S-11", + "Completely sheathed in 14-cm silica fiber foam, except for a thin tube to the ear canal to enable hearing the satisfying screeches of Freedom's enemies as they burn.": "14厘米厚的硅纤维泡沫将全身包裹在内,只在耳道处留下了纤细的管道,让穿戴者能够心满意足地听见自由之敌在烈火中痛苦尖叫。", + "SWEEPER": "扫荡者", + "GL-52": "GL-52", + "DEFENDER OF OUR DREAM": "梦想卫士", + "10g FRAGMENTATION": "10g破片弹", + "A versatile missile launcher loaded with seven lock-on homing missiles. These can either be fired from the launcher directly or as an airburst. Includes support backpack required for reloading.\nProduced by Stål Arms.": "多功能导弹发射器,装载了七枚锁定追踪式导弹。导弹可通过发射器直接发射或作为空爆弹发射。包含支援背包,用于装填弹药。\n由斯塔尔武装公司生产。", + "FOE RENT ASUNDER": "敌分四裂", + "200KG BOMB": "200KG炸弹", + "TARGETING DISTANCE": "目标距离", + "M90A": "M90A", + "LASER CANNON": "激光大炮", + "This multi-layered protective armor keeps rough sand, spores, and other coarse granules from irritating the skin.": "这套多层防护盔甲能有效阻隔粗糙沙粒、孢子和其他颗粒物,防止皮肤受到刺激。", + "JUSTICE": "正义", + "Wearers of this stealthy armor are seldom seen by their targets—or squadmates. No refunds if misplaced.": "穿戴这套潜行盔甲的人鲜少被目标(或队友)发现。如被队友误认,恕不退款。", + "Bullet Storm": "子弹风暴", + "Scout Striders": "侦察纵步者", + "GENESIS PRIME": "创世主星", + "EUKORIA": "欧科里亚", + "ADVANCED DEVASTATOR": "进阶蹂躏者", + "Olofson": "奥洛夫松", + "Persson": "佩尔松", + "Scout Strider": "侦察纵步者", + "STANDARD EXOSUIT PATTERN": "标准外骨骼装甲涂装", + "Ankarberg": "安卡贝格", + "Radical": "激进先锋", + "Sovereign": "主宰", + "Martyr": "烈士", + "XENOBITE ARDENT": "炽热异噬者", + "HANGAR 6": "6号机库", + "BOTEIN": "天阴四", + "Mirror": "之镜", + "PROSPERITY CITY": "荣都", + "THRASH IV": "萨尔什4号", + "Patriot": "爱国者", + "Englund": "恩隆德", + "LASTOME": "归宿市", + "BUNKER TURRET": "碉堡炮台", + "SAFETY ORANGE SHUTTLE PATTERN": "安全橘运输船涂装", + "ACUBENS PRIME": "柳宿增三主星", + "AKIRA SECTOR": "阿基拉分区", + "FREEDOM PEAK": "弗里敦峰", + "Steeled Veterans": "铁血老兵", + "of Twilight": "暮光", + "Incendiary MG Devastator": "燃烧机枪蹂躏者", + "Leahy": "莱希", + "Crushers": "粉碎者", + "SOL SYSTEM": "太阳系", + "GUNPOWDER MEADOWS": "火药草原", + "Outcast Tracker": "循踪光弃者", + "Charger Behemoths": "巨兽级强袭虫", + "RATTLESNAKE EXOSUIT PATTERN": "响尾蛇外骨骼装甲涂装", + "Warrior": "武士", + "GUNVALD": "古恩瓦尔德", + "INTREPIDNESS": "勇魄市", + "GHOUL": "噬光者", + "Overships": "统御舰", + "Advocate": "拥护者", + "Brood Commanders": "虫族指挥官", + "PYTHON COMMANDOS": "蟒蛇突击兵", + "Predator Stalkers": "掠食追踪虫", + "SULFURA": "萨尔弗拉", + "SEASSE": "西斯", + "MAW": "深渊", + "SETTLEMENT 7": "7号定居点", + "of Vigilance": "警惕", + "KORV": "科尔脯", + "Advanced Devastators": "进阶蹂躏者", + "STALKER": "追踪虫", + "Executor": "执行者", + "Reinforced Scout Striders": "强化侦察纵步者", + "IVIS": "艾维斯", + "Sonesson": "索内松", + "MOBILE WHITE EXOSUIT PATTERN": "移动白色外骨骼装甲涂装", + "ARTURION SECTOR": "阿图里昂分区", + "PHANTOM 1": "幻影1", + "MARS": "火星", + "CONVENIENCE": "捷城", + "WARP SHIP": "穿梭舰", + "GAZER": "凝视者", + "SYZYGY": "朔望", + "Ghouls": "噬光者", + "Bredberg": "布雷德贝格", + "FALSTAFF SECTOR": "法尔斯塔夫分区", + "High Command has identified this Megafactory as one of two potential beachheads for the invasion of Cyberstan. Anti-air fixtures will hamper Pelican extraction.": "最高指挥部已将这座超大型工厂认定为入侵生化斯坦的两个潜在滩头堡之一。防空设施将阻碍“鹈鹕”号撤离。", + "PIONEER II": "先驱II", + "VOTER'S FALLOW": "选民荒地", + "BLACKVEIN MINES": "黑脉矿井", + "BRNO": "布尔诺", + "OUTPOST 32": "32号哨站", + "Sall": "萨尔", + "OBTRUDER": "突入者", + "Sentinel": "哨兵", + "PSEUDOTOPIA": "伪托邦", + "FORT SANCTUARY": "庇护堡", + "Bulk Fabricators": "巨型构筑者", + "EQUALITY-ON-SEA": "仰齐浜", + "TIEN KWAN": "天关", + "STARPASS": "星通市", + "Freedom's Flame": "自由烈焰", + "VOG-SOJOTH": "佛戈索约斯", + "Each form and application that passes through the hallowed halls of AdminCen is emblazoned with the Stamp of Ages, and should be given a place of honor in the home.": "行政中心神圣大厅经手的表格和申请均印有“时代印章”,应当摆放在家中显赫位置。", + "INCENDIARY MG DEVASTATOR": "燃烧机枪蹂躏者", + "PATHFINDER V": "开拓者V", + "NEW VICTORY": "新胜利市", + "HULK": "巨型者", + "Command Bunker": "指挥碉堡", + "CUTTING EDGE": "遥遥领先", + "GEM LICKET": "晶蚀", + "Schmid": "施密德", + "GAR HAREN": "轧尔哈伦", + "Outcast Seekers": "逐觅光弃者", + "SPORE BURST WARRIOR": "孢裂武斗虫", + "Entrenched Division": "堑壕之师", + "TOR E": "托尔E", + "of Law": "法律", + "RECON HEIGHTS": "侦察高地", + "KEPLER-395b": "开普勒395b", + "INCONSPICUOUS BLACK EXOSUIT PATTERN": "低调黑外骨骼装甲涂装", + "SLIF": "斯利夫", + "MIDASBURG": "弥达斯堡", + "of Determination": "坚决", + "MINERAL REFINEMENT WORKS": "矿物精炼厂", + "DARROWSHOME": "达罗橡", + "AESIR PASS": "亚萨关隘", + "Democracy Officer": "民主官", + "Sandberg": "桑德贝格", + "BANEFUL SENTINEL": "祸患光能哨兵", + "JET BRIGADE RAIDER": "喷气旅奇袭者", + "HIVE LORD": "霸王虫", + "OSHAUNE": "欧绍恩", + "Outcast Trackers": "循踪光弃者", + "MEMORIALS": "纪念市", + "PERSISTENCE GATE": "恒久之门", + "SVITJOD": "斯维特约德", + "RIGHTEOUS REVENANTS": "正义复仇者", + "War Striders": "战争纵步者", + "Agitators": "惑乱者", + "HEETH": "希斯", + "CHORT BAY": "雀特湾", + "WAR HORSES": "战马", + "CURRENCY": "通汇城", + "KHANDARK": "勘达尔克", + "PERMACURIS": "佩玛丘拉斯", + "DURGEN": "德尔根", + "FODDER GORGE": "草料谷", + "ANNIHILATED SYSTEM": "已歼灭星系", + "of Battle": "激战", + "MORADESH": "莫拉戴什", + "STRENGTH": "力量市", + "KELLA METAMORPH": "凯拉蜕变城", + "TALUS SECTOR": "塔洛斯分区", + "Jet Brigade Raiders": "喷气旅奇袭者", + "Heavy Devastator": "重型蹂躏者", + "SERENITY SUMMIT": "静峰", + "RATTLESNAKE SHUTTLE PATTERN": "响尾蛇运输船涂装", + "LLANFAIRPWLLGWYNGYLLGOGERYCHWYRNDROBWLLLLANTYSILIOGOGOGOCH II": "LLANFAIRPWLLGWYNGYLLGOGERYCHWYRNDROBWLLLLANTYSILIOGOGOGOCH II", + "Xenobite Ardents": "炽热异噬者", + "DROPSHIP": "运输舰", + "NEW HAVEN": "纽黑文", + "Magistrate": "司卫", + "PEASE": "平息市", + "GEMSTELLE GENERATOR": "晶星动力", + "UNDERGROWTH EXOSUIT PATTERN": "灌木外骨骼装甲涂装", + "LURZA": "卢尔扎堡", + "HUMANITY": "人道市", + "SHELT": "谢尔特", + "Distor": "迪斯特", + "NONE": "无", + "MINTORIA": "敏托瑞亚", + "HULK BRUISER": "巨型碾压者", + "Prophet": "先知", + "HYDROFALL PRIME": "水瀑主星", + "Bile Spitter": "胆汁吐沫虫", + "EMORATH": "艾莫拉斯", + "Rohde": "罗德", + "JET BRIGADE TROOPER": "喷气旅装甲兵", + "STANDARD SHUTTLE PATTERN": "标准运输船涂装", + "EVOLUTION PLATS": "演化高地", + "of Pride": "自豪", + "TERMADON": "特尔玛登", + "STOLTHET": "荣傲", + "Watchers": "守望者", + "GRACIOUS LIBERTY": "仁慈自由市", + "Gonçalves": "贡萨尔维斯", + "MANDILARIA": "曼迪拉里亚", + "of Iron": "铸铁", + "Following the Great York Conundrum, one City rose above the rest, pledging to hold its Hand over all other Yorks, so that no more blood be spilt between them.": "约克大纷争结束后,一座城市力压群雄,誓要统御其他约克市,终结彼此间的流血纷争。", + "Cannon Turret": "加农炮台", + "Emperor": "君主", + "FILIBUSTER": "冗辩市", + "Nursing Spewer": "抚育喷涌虫", + "of Conquest": "征服", + "ICE BEND": "冰本德", + "BENEVOLENCE": "仁城", + "AGARTHA": "雅戈泰", + "URECTEM": "乌雷克特姆", + "MYRIUM": "梅里翁", + "CHAMELEON CAMO HELLPOD PATTERN": "变色龙迷彩绝地喷射舱涂装", + "PINE TAR": "松焦", + "LUXE POINT": "琉角", + "War Strider": "战争纵步者", + "RATCH": "拉奇", + "CONSENSUS": "康森瑟斯", + "SEASSEFYRE": "息战市", + "HAMMARBY": "哈马比", + "HEATHERFIELD": "希瑟菲尔德", + "KERTH SECUNDUS": "克斯次星", + "GEMMA": "贯索四", + "Terminid": "终结族", + "Dropship": "运输舰", + "FREEDOM ETERNAL": "永恒自由城", + "CANCRI SECTOR": "康古利伊分区", + "Rupture Spewers": "爆裂喷涌虫", + "McEachern": "麦凯克伦", + "ANNE'S VIGIL": "安妮守望城", + "VARYLIA 5": "瓦瑞拉亚5", + "Alpha Commander": "阿尔法指挥官", + "MINERVA": "密涅瓦", + "FRAKENEERIA": "弗兰科尼亚", + "EPH": "埃夫市", + "BROKER'S WEALTH": "经纪财富市", + "INDEPENDENCE": "独立市", + "DARROWSPORT": "达罗斯波特", + "MG Raider": "机枪奇袭者", + "of Democracy": "民主", + "TRANSCENDENCE": "超验枢", + "Bile Spitters": "胆汁吐沫虫", + "HERITAGE OLIVE EXOSUIT PATTERN": "经典橄榄绿外骨骼装甲涂装", + "of Supremacy": "至高", + "SHREDDER TANK": "碎裂坦克", + "JET BRIGADE MG TROOPER": "喷气旅机枪装甲兵", + "Hulk Bruiser": "巨型碾压者", + "KARON BAY": "凯伦湾", + "Facility Operator": "设施操作员", + "HARVESTER": "猎杀器", + "VENERATION": "敬仰市", + "CRUSHER": "粉碎者", + "None": "无", + "HILJAISUUS": "寂城", + "Commissar": "机械统帅", + "Advanced Devastator": "进阶蹂躏者", + "Nazareno": "纳萨雷诺", + "ADRENAL 8": "脉涌8", + "Hive Guard": "虫窝护卫", + "SEVERITY": "严峻市", + "War Horses": "战马", + "VOTELESS": "无票者", + "PADOSAN": "毗印市", + "ONSEN": "温泉湾", + "Bulk Fabricator": "巨型构筑者", + "MARAUDER": "劫掠者", + "UNGU": "紫都", + "ACHERNAR SECUNDUS": "水委一次星", + "SHOTGUN SUMMIT": "霰弹枪峰", + "Ship TV": "舰船电视", + "Quinto": "昆托", + "BEEFBURG": "比夫堡", + "LOGISTICS HUB 188-B": "物流中心188-B", + "CLASA": "克拉萨", + "DOLPH": "多尔夫", + "ZONE 3": "3区", + "GROWL": "咆哮市", + "PA System": "广播系统", + "J. Bender": "J.本德", + "SIEGE BREAKERS": "破围先锋", + "WAYWARD": "逸泊", + "Malmborg": "马尔姆堡", + "Queen": "女王", + "of Freedom": "自由", + "MEKBUDA": "井宿七", + "ENHET FABRIK": "一体成型厂", + "GUNSHIP": "炮舰", + "TARSH": "塔尔什", + "SPORE CHARGER": "孢子强袭虫", + "PRASA": "普拉萨", + "Redondo": "雷东多", + "INCONSPICUOUS BLACK VEHICLE PATTERN": "低调黑载具涂装", + "PENNYBRIDGE": "彭尼布里奇", + "of Equality": "公正", + "Outcast Slashers": "狂刃光弃者", + "NEW STOROUSE": "新储仓", + "WATCHDOG 5": "守犬5", + "Advertisement": "广告播报员", + "Nummi": "努米", + "Guardian": "拯护者", + "POLARIS PRIME": "北极星主星", + "IRO": "伊罗", + "BUNDA SECUNDUS": "天垒城一次星", + "Estlind": "埃斯特林德", + "UTOPIA VAREN": "瓦伦乌托邦", + "Bile Spewer": "胆汁喷涌虫", + "ASPEN HILLS": "阿斯彭山", + "MOBILE WHITE SHUTTLE PATTERN": "移动白色运输船涂装", + "KEPLER-397b": "开普勒397b", + "STEN SECTOR": "斯坦分区", + "Andersson": "安德松", + "NYA SKELLEFTEA": "新谢莱夫特奥", + "OLUFSEN'S FOOTPRINT": "奥卢夫森足迹", + "ELYSIAN MEADOWS": "埃律西昂草原", + "GOTHENBURG III": "哥德堡III", + "MALMBERGET": "马尔姆贝吉特", + "RICTUS SECTOR": "瑞克图斯分区", + "VALMOX": "瓦尔莫克斯", + "Mandilas": "曼迪拉斯", + "Bolin": "博林", + "AVILA": "阿维拉", + "ALTUS SECTOR": "阿尔特斯分区", + "Vox Engines": "噪轰引擎", + "Representative": "代表", + "KESUMA": "花都", + "HUMAN WILL": "人类意志市", + "NEW ASPIRATION CITY": "志向新城", + "PROSPERITY": "繁荣市", + "UNMAPPED SYSTEM": "未测绘星系", + "HELLMIRE": "海尔迈尔", + "HYDROBIUS": "哈卓毕亚斯", + "TERREK": "泰雷克", + "Super Earth": "超级地球", + "Spore Burst Hunters": "孢裂追猎虫", + "YELLOW JACKET SHUTTLE PATTERN": "黄色被甲弹运输船涂装", + "WRAITH": "幽灵", + "SKAASH": "斯卡什", + "LEVIATHAN": "利维坦", + "POUNCER": "猛扑虫", + "Hulk": "巨型者", + "Shrieker": "尖啸虫", + "UNANIMITY": "统一市", + "Gauntlet": "钢铁手", + "BRILLIANCE": "璨光", + "PHACT BAY": "丈人一湾", + "MOBILE WHITE VEHICLE PATTERN": "移动白色载具涂装", + "Banner": "旗帜", + "Polar Patriots": "极地爱国者", + "ILLUMINATE": "光能者", + "FORT BOUNTY": "邦蒂堡", + "SPHERION": "斯飞利昂", + "MEISSA": "觜宿一", + "OLD BRANCH": "旧枝城", + "of Allegiance": "忠诚", + "UNDERGROWTH HELLPOD PATTERN": "灌木绝地喷射舱涂装", + "TECHNOLOCKIA ALLATEED": "科锁洛基亚-阿拉提德", + "The Crusher is the Illuminate’s most depraved advancement to date in the horrific process of mind control and manipulation. They are brute enforcers of the Illuminate agenda, whatever human matter that remains is long gone.": "粉碎者是光能者通过可怕的精神控制和操纵所创造出的终极堕落产物。粉碎者是推进光能者阴谋诡计的残暴爪牙,体内残存的人类痕迹早已荡然无存。", + "ANDWELL": "安得卫", + "EAST EMBANKMENT": "东堤", + "VOLTERRA": "沃尔泰拉", + "Automaton Mortar Emplacements": "机器人的迫击炮台", + "XI TAURI SECTOR": "金牛座分区", + "GELLERT SECTOR": "盖勒特分区", + "ADHARA": "弧矢七", + "of Conviviality": "友善", + "Yu Villa": "优·维拉", + "Hulk Scorchers": "巨型炙炎者", + "EXTRASOLAR ASH SHUTTLE PATTERN": "系外星尘运输船涂装", + "MYRADESH": "米拉戴什", + "WORTHY I": "英杰I", + "Helldrivers": "绝地司机", + "ALTA V": "奥尔塔V", + "Pride": "之傲", + "BLISTICA": "布里斯提卡", + "COZY FLATS": "馨寓", + "Flame": "之火", + "KALASATAMA PORT": "卡拉萨塔马港", + "De Giorgis": "德乔治", + "Watcher": "守望者", + "DARKWELL": "暗井", + "Comptroller": "督察者", + "AIDESVILLE": "哈得斯维尔", + "Bolle": "博莱", + "Pouncer": "猛扑虫", + "Progenitor": "始祖", + "MASTIA": "玛斯蒂亚", + "Leviathan": "利维坦", + "KARLIA": "可利亚", + "FORI PRIME": "佛里主星", + "ARLIA": "阿利亚", + "Moore": "摩尔", + "AUTOMATON": "机器人", + "PROMINENCE": "峥嵘城", + "REBELSGRAVE": "叛军墓", + "HAWKING SECTOR": "霍金分区", + "ENTRENCHED DIVISION": "堑壕之师", + "ESCAPADE": "越矩市", + "Spore Chargers": "孢子强袭虫", + "WEST MANAGEMENT": "西治市", + "ADAM PARK": "亚当帕克", + "CHATOYANT": "幻彩城", + "Helldiver Dummy": "绝地潜兵假人", + "SKITTER": "斯基特", + "Rupture Warrior": "爆裂武斗虫", + "ZEFIA": "赛飞亚", + "NANOS SECTOR": "纳诺斯分区", + "FOUNDRY": "铸造城", + "GRAFSART": "爵心市", + "SES": "SES", + "PROBABILITY": "天机", + "BRIGHT WING": "明翼市", + "Jansson": "扬松", + "of Mercy": "仁慈", + "OASIS": "绿洲", + "MEAN GREEN SHUTTLE PATTERN": "凶猛绿运输船涂装", + "SLAYER CITY": "弑亚城", + "One of 3 Maximum Security Cities. Impregnable to Tyranny; the future of the Federation.": "三大最高安全级别城市之一。暴政无法攻破之城,联邦的未来。", + "OLD DOVE": "老鸽城", + "BARNARD SECTOR": "巴纳德分区", + "Spore Lung": "孢肺", + "of Super Earth": "超级地球", + "ZEGEMA PARADISE": "泽格马乐土", + "RADICAL": "激进先锋", + "PHERKAD SECUNDUS": "北极一次星", + "RINKTOWN": "冰场镇", + "INFESTED TOWER": "侵染塔巢", + "VINDEMITARIX PRIME": "文德米塔里克斯主星", + "CHAMELEON CAMO SHUTTLE PATTERN": "变色龙迷彩运输船涂装", + "UNINHABITABLE SYSTEM": "不宜居星系", + "ELEVATED OVERSEER": "崇高监视者", + "URSA SECTOR": "大熊座分区", + "A product of the Illuminate’s so-called intellectual superiority and experimentation, the Wretch is a vile fusion of once human biomatter and hateful propaganda. These pathetic puppets envy the democratic rights of Super Earth citizens and seek to cut down those still loyal to Liberty.": "作为光能者所谓高等智慧与试验测试的产物,悲怜体是一种由昔日人类生物物质与仇恨洗脑的宣传融合而成的邪恶造物。这些可怜的傀儡嫉妒超级地球公民所享有的民主权利,妄图残害仍坚守解放大业的志士。", + "SCARLET HAVEN": "绯红湾", + "REDFIELD": "雷德菲尔德", + "UVP DELTA": "UVP德尔塔", + "FABRICATOR": "构筑者", + "EMERIA": "埃梅里亚", + "EAGLECRY": "鹰啸市", + "Crescent Overseers": "新月监视者", + "ANDROMEDA SECTOR": "仙女座分区", + "Impaler": "穿刺虫", + "POLLUX 31": "北河三31", + "SAORSA GLEN": "萨奥萨谷", + "SHALLUS": "沙勒斯", + "RD-4": "RD4", + "Charger Behemoth": "巨兽级强袭虫", + "Diamond": "之钻", + "Carlberg": "卡尔贝格", + "Harvesters": "猎杀器", + "PEOPLE'S HAND": "民手市", + "PIPIONEM": "雏鸣", + "Aegis": "神盾", + "PERSISTENCE": "坚韧市", + "QUASAR": "魁霎", + "DEMOCRACY ALWAYS": "恒民城", + "MASTERS OF CEREMONY": "典礼官", + "CASTELLAN'S CREED": "卡斯特兰信条", + "HORT": "哈尔特", + "STEEL RESOLVE": "钢铁意志城", + "Hodges": "霍奇斯", + "L'ESTRADE SECTOR": "莱斯特拉德分区", + "Pyro Troopers": "炙焰装甲兵", + "CHAIRMAN OKOTE": "主席奥科特", + "of Wrath": "盛怒", + "Gunships": "炮舰", + "NEW ALEXANDRIA": "新亚历山大城", + "SKAT BAY": "斯卡特湾", + "DARIUS II": "大流士II", + "DRYWELL": "干井市", + "The flagship Maximum Security City. Impregnable to Tyranny; the future of the Federation.": "最高安全级别城市中的王牌。暴政无法攻破之城,联邦的未来。", + "Stingrays": "刺魟", + "UNDERGROWTH SHUTTLE PATTERN": "灌木运输船涂装", + "NEW HOPE CITY": "希望新城", + "DIASPORA X": "大流散X", + "Terminids": "终结族", + "Factory Strider": "移动工厂", + "Prowlers": "潜掠虫", + "REDTHORN": "赤棘", + "DENEB SECUNDUS": "天津四次星", + "ERIDANI": "波江座", + "GREATER ATLANTEAN POWER PLANT": "大亚特兰蒂斯电厂", + "TRIGON SECTOR": "特里贡分区", + "INCONSPICUOUS BLACK HELLPOD PATTERN": "低调黑绝地喷射舱涂装", + "Berserkers": "狂暴者", + "Monuments in this Megafactory twist history to valorize the supposed resolve of Cyborgs to \"endure\" Super Earth's benevolent attempts to rehabilitate them. \n\nAnti-air defenses will hinder Eagle operations.": "这座超大型工厂的纪念碑扭曲历史,颂扬生化人所谓“忍受”超级地球仁慈改造计划的决心。\n\n防空系统将妨碍“飞鹰”的行动。", + "FORT UNION": "联合堡", + "Ship Master #NAME": "#NAME舰长", + "Overseers": "监视者", + "VITAL SYSTEM": "关键星系", + "LOOKOUT": "眺望台", + "BRAVERY": "勇城", + "Force of Law": "法律铁腕", + "Precursor": "先锋", + "PAYONG": "庇永", + "Spore Burst Hunter": "孢裂追猎虫", + "EFFLUVIA": "艾芙鲁维亚", + "EAGLESTAR ETERNAL": "鹰星恒市", + "CHOEPESSA IV": "科埃佩萨IV", + "Yousefi": "优塞菲", + "FREECREST": "自由峰", + "ALARAPH": "右执法", + "ABUNDANCE": "丰饶市", + "Annihilator Tanks": "湮灭坦克", + "JULHEIM": "尤尔海姆", + "Botelho": "博特略", + "Incendiary MG Devastators": "燃烧机枪蹂躏者", + "PRIMORDIA": "普莱默迪亚", + "CHURNED EARTH SHUTTLE PATTERN": "焦土运输船涂装", + "HABITAT RED-2": "栖地红-2", + "FORT JUSTICE": "正义堡", + "VANDALON IV": "万达隆IV", + "Troopers": "装甲兵", + "RESOLVE": "决心市", + "KODIAK FALLS": "科迪亚克瀑布", + "COMMISSAR": "机械统帅", + "BROOD WARDEN": "虫族守卫", + "Service Technician": "维修技术员", + "MEAN GREEN HELLPOD PATTERN": "凶猛绿绝地喷射舱涂装", + "TOIL": "劳作市", + "GILE": "吉尔", + "Arbiter": "仲裁", + "ALSTRAD SECTOR": "阿尔斯特拉德分区", + "LASTOFE": "赖斯斗夫", + "Charger": "强袭虫", + "Exo Experts": "外骨骼装甲专家", + "Servants of Freedom": "自由公仆", + "PILOT'S BERTH": "星驭港", + "Harbinger": "之兆", + "KEID": "九州殊口增七", + "OVERGOE PRIME": "欧维果主星", + "Fist": "之拳", + "NEW HEARTH CITY": "新寒炉市", + "GENE": "基因市", + "Stalkers": "追踪虫", + "YELLOW JACKET EXOSUIT PATTERN": "黄色被甲弹外骨骼装甲涂装", + "EASTCLEFT": "东裂谷", + "SEAF Soldier": "超级地球武装部队战士", + "MIRAGE": "幻境城", + "Agent": "桥梁", + "AIN-5": "毕宿一5", + "TRUE BLUE HELLPOD PATTERN": "忠诚蓝绝地喷射舱涂装", + "EAGLE'S LIKENESS": "鹰姿市", + "OLD CONUNDRUM": "旧谜市", + "KORPUS SECTOR": "科普斯分区", + "BORGUS SECTOR": "博格斯分区", + "VOX ENGINE": "噪轰引擎", + "Agitator": "惑乱者", + "FREE APARTMENTS": "自由公寓", + "of Audacity": "勇猛", + "PILEN V": "皮伦V", + "Dragonroach": "蟑龙", + "NABATEA SECUNDUS": "那贝塔次星", + "HOPESHIRE": "霍普郡", + "Leviathans": "利维坦", + "Brostrom": "布洛斯特伦", + "HUNTER'S BLUFF": "猎人崖", + "EDWARD'S GRAVE": "爱德华之墓", + "Harvester": "猎杀器", + "NEW STOCKHOLM": "新斯德哥尔摩", + "Blade": "之刃", + "QUELLED DISSENT": "戡异市", + "DYER STREETS": "染工街", + "DIGITI": "迪吉趾", + "FACTORY STRIDER": "移动工厂", + "Blood": "布拉德", + "KEPLER-391b": "开普勒391b", + "Brezavscek": "布雷扎夫谢克", + "NEW NEWTONVILLE": "新牛顿维尔", + "Jaeger": "耶格", + "Nursing Spewers": "抚育喷涌虫", + "CALYPSO": "卡利普索", + "Command Bunkers": "指挥碉堡", + "Zamora": "萨莫拉", + "REAF": "利夫", + "AUTOMATONS": "机器人", + "BOREA": "博瑞亚", + "ROCKET TANK": "火箭坦克", + "Friend": "弗兰德", + "Brood Warden": "虫族守卫", + "HOLL": "霍凉地", + "NAVI VII": "阁道二", + "NEW WISDOM": "新慧", + "Assault Raider": "特攻奇袭者", + "ZZANIAH PRIME": "藏尼亚主星", + "Steward": "管理者", + "Rocket Tank": "火箭坦克", + "SOCORRO III": "索科罗III", + "DEMOCRACY'S LANDING": "民主浅滩", + "Superintendent": "至尊", + "Frandsen": "弗兰德森", + "MAGNITUDE": "巨量市", + "BULK FABRICATOR": "巨型构筑者", + "ACRUX IX": "十字架二IX", + "BORDERLINE JUSTICE": "临界正义", + "WAR STRIDER": "战争纵步者", + "NUOVA ROMA": "新罗马", + "Impalers": "穿刺虫", + "Assault Raiders": "特攻奇袭者", + "Soldier": "战士", + "HOMESTEAD HILL": "家园山", + "Eriksson": "埃里克松", + "Wings": "之翼", + "MAJOSYRI": "马约叙里", + "NEW INSIGHT": "新悟", + "Siege Breakers": "破围先锋", + "MEAN GREEN EXOSUIT PATTERN": "凶猛绿外骨骼装甲涂装", + "AUTOMATON MORTAR EMPLACEMENT": "机器人的迫击炮台", + "IMPALER": "穿刺虫", + "CONCRETE JUNGLE SHUTTLE PATTERN": "混凝土丛林运输船涂装", + "BILE SPITTER": "胆汁吐沫虫", + "SERVANTS OF FREEDOM": "自由公仆", + "KEPLER-396b": "开普勒396b", + "REDACTED REGIMENT": "绝密军团", + "Raiders": "奇袭者", + "Chandler": "钱德勒", + "of Truth": "真理", + "HEZE BAY": "角宿二湾", + "ALATHFAR XI": "织女增三XI", + "of Courage": "刚毅", + "RESILIENCE": "韧城", + "BUG HOLE": "虫穴", + "Since sheltering millions of loyal refugees in the Last Great War, Port Mercy has been a safe haven for any class-A citizen in need.": "自终极大战中庇护数百万忠诚难民起,仁慈港便成为所有A级公民危难时的安全港湾。", + "KLAKA 5": "克拉卡5", + "RIGEL SECTOR": "参宿七分区", + "Hulk Obliterator": "巨型抹煞者", + "Skogsberg": "斯科格斯贝格", + "of Liberty": "解放", + "GRAFSWALLIT": "爵囊市", + "Force": "之势", + "KRAZ": "轸宿四", + "KNETH PORT": "克奈斯港", + "HERITAGE OLIVE VEHICLE PATTERN": "经典橄榄绿载具涂装", + "OUTCAST TRACKER": "循踪光弃者", + "HESOE PRIME": "海索主星", + "MÖNSTERÅS II": "门斯特罗斯II", + "VALGAARD": "瓦尔加德", + "HAKA": "哈卡", + "Home to the Democratic Council, our proud Capital is a beacon of Progress, Productivity, and Patriotism.": "我们引以为傲的首都既是民主委员会的所在地,也是进步、生产力和爱国主义的璀璨灯塔。", + "Soul": "灵魂", + "HOT GATES": "炙关", + "BASE CAMP 8": "8号基地", + "MUNITION CITY": "军工城", + "THE VOID": "寂域", + "SWAMP IV": "沼泽IV", + "BLESTRAIL": "圣途市", + "JET BRIGADE COMMISSAR": "喷气旅机械统帅", + "RATTLESNAKE VEHICLE PATTERN": "响尾蛇载具涂装", + "HOPEFUL": "希望", + "of Victory": "胜利", + "XZAR SECTOR": "兹亚尔分区", + "Sundstrom": "森德斯特伦", + "EAGLEMOUNT": "鹰山", + "PROSPERITY FALLS": "繁荣瀑布", + "SAMEN-STARK": "萨门-斯塔克", + "VEIL": "帷幕", + "NEW ABERDEEN": "新阿伯丁", + "Devastator": "蹂躏者", + "URSICA XI": "厄西卡XI", + "Dawn": "黎明", + "GRAVITAS": "庄严市", + "REGNUS": "雷格努斯", + "BASQUINE VIII": "巴斯金VIII", + "VERVE": "精力市", + "SYCAMORE GARDENS": "梧桐苑", + "HAERSTVIK": "哈尔斯特维克", + "Gazer": "凝视者", + "OMICRON": "奥密克戎", + "MORGON SECTOR": "莫根分区", + "Prophet Illusionists": "先知幻光大师", + "RAIDER": "奇袭者", + "Shredder Tanks": "碎裂坦克", + "ORBSHAM": "球珀沙姆", + "Extraction Shuttle": "撤离运输船", + "HYDRA SECTOR": "长蛇座分区", + "Hart": "哈特", + "FORTITUDE": "毅城", + "CHAMELEON CAMO EXOSUIT PATTERN": "变色龙迷彩外骨骼装甲涂装", + "TRUTH ENFORCERS": "真理执行者", + "GRAFMERE": "格拉夫米尔", + "SHETE": "赛特", + "K": "K", + "SERVITUDE": "奴役市", + "WARRIOR": "武斗虫", + "THE BUG QUARANTINE": "防虫", + "WASTEMOUNT": "韦斯特蒙特", + "LEO SECTOR": "狮子座分区", + "FREEDOM'S TORCH": "自由火炬城", + "PROPHET ILLUSIONIST": "先知幻光大师", + "REMEMBRANCE": "缅城", + "TRUE BLUE SHUTTLE PATTERN": "忠诚蓝运输船涂装", + "Nilsson": "尼尔松", + "FORNSKOGUR II": "福恩斯科古尔II", + "THE WEIR": "维尔", + "COUNCILLOR RORA": "议员罗拉", + "OSUPSAM": "欧苏普森", + "of Starlight": "星光", + "SILO A": "A舱", + "ANOMALOUS SYSTEM": "异常星系", + "Beroshi": "贝洛西", + "ASSAULT RAIDER": "特攻奇袭者", + "OUTCAST SLASHER": "狂刃光弃者", + "Hammer": "之锤", + "ISEGORIA": "思言城", + "Infested Towers": "侵染塔巢", + "Hulk Scorcher": "巨型炙炎者", + "of the State": "国家", + "Cannon Turrets": "加农炮台", + "CONFLAGRATION DEVASTATOR": "烈火蹂躏者", + "Pilot": "驾驶员", + "YMIR SECTOR": "土卫十九分区", + "TANIS SECTOR": "塔尼斯分区", + "MOMO-1": "莫莫-1", + "EAGLEOPOLIS": "鹰都", + "BIG ROCK": "巨岩", + "Eagle Fighter": "“飞鹰”驾驶员", + "Bile Warriors": "吐酸武斗虫", + "TRANDOR": "特兰道尔", + "Roughly translates to \"All Humans Must Die.\" One of the largest Megafactories on Cyberstan. A critical military production node. Defended by the Jet Brigade.": "大意为“全人类必须死”。生化斯坦最大的超大型工厂之一。关键军事生产节点。由喷气旅驻守。", + "NIBIRU": "尼比鲁", + "Vanderheide": "范德海德", + "VOTING DISTRICT F-012357": "F-012357选区", + "MENKENT": "库楼三", + "EAST IRIDIUM TRADING BAY": "东铱贸易湾", + "Python Commandos": "蟒蛇突击兵", + "Jet Brigade Commissars": "喷气旅机械统帅", + "VAULT CITY": "金库市", + "of Fortitude": "坚韧", + "SAPPORO": "札幌", + "HANZO SECTOR": "半藏分区", + "KRAKATWO": "克拉克图", + "SHED": "囤仓", + "Helldiver Recruit": "绝地潜兵新兵", + "Service Technician #NAME": "#NAME维修技术员", + "of Conviction": "坚定", + "of Honor": "尊荣", + "EAST REST": "东栖市", + "Super Earth PSA": "超级地球PSA", + "of Independence": "独立", + "Gatekeeper": "御门者", + "Reinforced Scout Strider": "强化侦察纵步者", + "CHAMELEON CAMO VEHICLE PATTERN": "变色龙迷彩载具涂装", + "Democracy Officer #NAME": "#NAME民主官", + "KEPLER-389b": "开普勒389b", + "STANDARD VEHICLE PATTERN": "标准载具涂装", + "Commissars": "机械统帅", + "Overseer": "监视者", + "CHARON PRIME": "卡戎主星", + "Wesolowski": "韦索洛夫斯基", + "IRIDICA": "艾丽迪卡", + "FEARLESS HOLLOW": "无畏谷", + "VELD": "维尔德", + "MARSPIRA SECTOR": "马斯皮拉分区", + "EXTRASOLAR ASH EXOSUIT PATTERN": "系外星尘外骨骼装甲涂装", + "The first and most well-defended Megafactory. The nexus of Cyborg command. Its destruction will trigger the collapse of the enemy's defenses on Cyberstan. Expect extreme resistance.": "最早建成、防御最坚固的超大型工厂。生化人的指挥中枢。摧毁此目标将导致敌军在生化斯坦的防线全面崩溃。预计将遭遇极端抵抗。", + "THESEUS SECTOR": "忒修斯分区", + "INCONSPICUOUS BLACK SHUTTLE PATTERN": "低调黑运输船舱涂装", + "XIN FUZHOU": "新福州", + "ACRAB XI": "房宿四XI", + "ANDAR": "安达尔", + "VERACITOR": "证真者", + "MERIDIAN IIa": "默里迪恩IIa", + "CHAIRMAN OYESLLO": "主席奥耶斯洛", + "Wiklund": "维克隆德", + "Gunship": "炮舰", + "Lindstrom": "林德斯特伦", + "Spore Charger": "孢子强袭虫", + "SETTLER'S HONOR": "开拓者荣誉市", + "AFOYAY BAY": "艾福亚湾", + "of Science": "科学", + "DIPLOMACY": "纵横市", + "MORDIA 9": "摩帝亚9", + "LOGISTICAE": "后勤", + "Shriekers": "尖啸虫", + "AGITATOR": "惑乱者", + "BIRTH": "圣生市", + "Brawler": "乱斗者", + "Protector": "护卫", + "RATTLESNAKE HELLPOD PATTERN": "响尾蛇绝地喷射舱涂装", + "CYGNIA III": "西格尼亚III", + "Raider": "奇袭者", + "This Great Heart of Commerce is renowned galaxy-wide for its Grand Shopping Malls and Splendorous Entertainment Centers.": "这座伟大商贸中枢因宏伟的购物商场和繁华的娱乐中心而闻名整个银河系。", + "MARTALE": "玛尔特", + "Citizen": "公民", + "ASPEROTH PRIME": "阿斯佩洛斯主星", + "MANTES": "蒙特斯", + "FORCE OF LAW": "法律铁腕", + "ACHIRD III": "王良三III", + "PESTIS": "瘟厉", + "YATAKHANE 263": "宿舍263", + "SPOYLE": "斯珀伊尔", + "Lindgren": "林德格伦", + "TARRAGON SECTOR": "塔拉戈分区", + "Linddqvist": "林德奎斯特", + "LIFESWORTH": "生之意", + "LYNX LYNX": "猞猁", + "CRUCIBLE": "熔炉", + "Jet Brigade Trooper": "喷气旅装甲兵", + "CURSA": "玉井三", + "Hulk Firebomber": "巨型烈焰轰炸者", + "REQUIEM": "安魂城", + "VICTORY": "胜利市", + "Vicente": "维桑特", + "Sjostrom": "舍斯特伦", + "Rocket Tanks": "火箭坦克", + "Democratic Detonation": "民主爆破", + "MASKIN": "玛斯金", + "ARGENTIS": "银辉", + "KILLJOY TOWN": "克乔伊镇", + "Giant": "巨人", + "HULK FIREBOMBER": "巨型烈焰轰炸者", + "PENSCEWT": "彭妮萌", + "VINGE": "云翼", + "CONLON COLONY": "康伦拓殖地", + "Prowler": "潜掠虫", + "FARMHANDSTOWN": "农工镇", + "Wolterbeek Muller": "沃尔特贝克·穆勒", + "Fyrvall": "菲尔瓦尔", + "Spore Burst Warrior": "孢裂武斗虫", + "Wretch": "悲怜体", + "SAGAN SECTOR": "萨根分区", + "ROCKET DEVASTATOR": "火箭蹂躏者", + "of Midnight": "午夜", + "Power": "之力", + "SPORE BURST SCAVENGER": "孢裂食腐虫", + "BALDRICK PRIME": "巴尔德里克主星", + "Prince": "王子", + "MARRE IV": "马尔IV", + "PARRHESIA": "直言城", + "BERSERKER": "狂暴者", + "ZAGON PRIME": "扎贡主星", + "of Integrity": "诚实", + "TIMELY": "甘霖城", + "Founding Father": "缔造者", + "of Judgment": "判决", + "SHELTER": "谢尔特", + "Durney": "德尼", + "GUNNAR": "刚纳尔", + "Transport Shuttle": "运输船", + "Magus Acolytes": "奇能侍僧", + "WILFORD STATION": "威尔福德站", + "YELLOW JACKET HELLPOD PATTERN": "黄色被甲弹绝地喷射舱涂装", + "UNDERVATTEN": "水下城", + "Scavengers": "食腐虫", + "REINFORCED SCOUT STRIDER": "强化侦察纵步者", + "SIRIUS": "天狼星", + "GARAGE DUNE": "车库沙丘", + "MONHEIM": "蒙海姆", + "OVERSHIP": "统御舰", + "TROOST": "特鲁斯特", + "MAIA": "昴宿四", + "WORKSONG": "劳歌市", + "NURSING SPEWER": "抚育喷涌虫", + "ANTBOOT": "踏虫市", + "PROGRESS": "进步市", + "MUSTARD VEHICLE PATTERN": "芥末黄载具涂装", + "WRETCH": "悲怜体", + "Herald": "使者", + "EXTRASOLAR ASH HELLPOD PATTERN": "系外星尘绝地喷射舱涂装", + "MERGA IV": "玄戈增二IV", + "Claw": "之爪", + "YORK SUPREME": "棒约克", + "Hedstrom": "赫德斯特伦", + "Elggren": "埃尔格伦", + "Rupture Spewer": "爆裂喷涌虫", + "CONCRETE JUNGLE HELLPOD PATTERN": "混凝土丛林绝地喷射舱涂装", + "ABUNDANCE BLUFF": "丰绝崖", + "of Glory": "荣耀", + "MT MONUMENT": "纪念碑山", + "Person": "个人", + "of Redemption": "救赎", + "Octagon": "之八方", + "Spore Lungs": "孢肺", + "RUPTURE SPEWER": "爆裂喷涌虫", + "SHADY OAKS": "荫橡", + "Scout Raider": "侦查奇袭者", + "DUNOONIA": "顿诺尼亚", + "BARABOS": "巴勒博斯", + "Eye": "之眼", + "PROPUS": "五诸侯三", + "of Family Values": "情义", + "GIRD": "戈尔德", + "FORT SANGUINE": "血色堡", + "ZYGOS": "齐戈斯", + "MUSTARD EXOSUIT PATTERN": "芥末黄外骨骼装甲涂装", + "YELLOW JACKET VEHICLE PATTERN": "黄色被甲弹载具涂装", + "Ship Master": "舰长", + "of the People": "民众", + "Rocket Devastator": "火箭蹂躏者", + "CHOOHE": "丘伊", + "Hulks": "巨型者", + "GIRI": "义理城", + "EPSILON PHOENCIS VI": "艾普斯林芬赛斯VI", + "BARRACKSBURG": "兵营堡", + "Stalker": "追踪虫", + "MORT": "莫特", + "CASTELLAN GREEN SHUTTLE PATTERN": "卡斯特兰绿运输船涂装", + "USTOTU": "伍斯特图", + "SAFETY ORANGE VEHICLE PATTERN": "安全橘载具涂装", + "STINGRAY": "刺魟", + "Hellbot": "绝地机械兵", + "SEYSHEL BEACH": "塞舌尔海滩", + "ILDUNA PRIME": "伊尔都纳主星", + "Spore Burst Warriors": "孢裂武斗虫", + "HERITAGE OLIVE HELLPOD PATTERN": "经典橄榄绿绝地喷射舱涂装", + "CASTELLAN GREEN EXOSUIT PATTERN": "卡斯特兰绿外骨骼装甲涂装", + "CAPH": "王良一", + "NASCENCE": "太初", + "MOGO PLAINS": "莫戈平原", + "SEQUIM": "猎城", + "of Gold": "黄金", + "SONGGUO CUN": "松果村", + "Bunker Turrets": "碉堡炮台", + "IGLA": "伊格勒", + "Paragon": "模范", + "Gatekeepers": "御门者", + "Devastators": "蹂躏者", + "GOTHMAR SECTOR": "戈特玛分区", + "STOR THA PRIME": "斯特萨主星", + "PEDIS": "佩迪趾", + "Marauder": "劫掠者", + "GALLUX SECTOR": "加卢克斯分区", + "SHRIEKER": "尖啸虫", + "EUPHORIA III": "欧福利亚III", + "Wretches": "悲怜体", + "LACED STRAIT": "莱醒海峡", + "Kravchenko": "克拉夫琴科", + "Chemical Agents": "化学专家", + "Billnert": "比尔纳特", + "EVERWHITE": "恒白", + "Hunters": "追猎虫", + "Rupture Warriors": "爆裂武斗虫", + "Automaton": "机器人", + "Bellawala": "贝拉瓦拉", + "MIQÉ": "米基", + "OMA PEMMA": "欧玛佩玛", + "BRAWFERMLAND": "布劳费尔兰", + "of Individual Merit": "独贤", + "SCAVENGER": "食腐虫", + "Star": "之星", + "OSTEHOVEL": "酪撕特霍维", + "HERITAGE OLIVE SHUTTLE PATTERN": "经典橄榄绿运输船涂装", + "FRONTERIA": "边陲", + "Sword": "之剑", + "Bile Titan": "吐酸泰坦", + "ADVENTURE": "探险市", + "Risen from the ashes of an ancient city, Rememberance is a monument to the Perseverance of Humankind.": "自古城废墟中涅槃重生,缅城乃人类不屈精神的丰碑。", + "SALERIA SECTOR": "萨勒莉亚分区", + "Wirz": "维尔斯", + "Predator Hunters": "掠食追猎虫", + "SUPERIORITY": "优越市", + "FAMEWOLF PEAK": "盛狼峰", + "VIRIDIA PRIME": "维尔伊迪亚主星", + "VANQUISHMENT": "征服市", + "YDINKESKUSTA": "中心城", + "NEW EAGLE": "新鹰城", + "STAR KIELD": "星陨堡", + "Frezzato": "弗雷扎托", + "HILDOARA CENTRAL": "希尔多亚拉中区", + "LINK B": "链枢B", + "EXO CITY": "外骨骼市", + "TENDRA": "坦德拉", + "BALLOT": "民望", + "ERSON SANDS": "厄尔森桑兹", + "MIRIN SECTOR": "米琳分区", + "WEST BROKER": "西贸经纪区", + "Likely one of the earliest Megafactories to be constructed on Cyberstan. The most significant producer of Cyborg combatants. Defended by the Incineration Corps.": "这可能是生化斯坦最早建造的超大型工厂之一。生化人战斗单位的最主要生产地。由炽灼部队驻守。", + "Urban Legends": "都市传奇", + "Bile Spewers": "胆汁喷涌虫", + "Courier": "信使", + "MARTYR'S BAY": "烈士湾", + "Outcast Seeker": "逐觅光弃者", + "ESTANU": "伊斯塔努", + "RETRIBUTARY": "天谴", + "LACAILLE SECTOR": "拉凯欧分区", + "TRUE BLUE EXOSUIT PATTERN": "忠诚蓝外骨骼装甲涂装", + "GENERATION": "源代", + "ROCKET RAIDER": "火箭奇袭者", + "CAMP LEIGHTON": "莱顿营", + "PARTION": "帕尔晨", + "SPORE LUNG": "孢肺", + "Bernklint": "柏恩科林特", + "NEW TOKYO": "新东京", + "PINESWOLD": "派恩斯沃尔德", + "Civilian": "平民", + "of Perseverance": "不屈", + "BILE TITAN": "吐酸泰坦", + "LIFEBLOOD": "命脉城", + "Masters of Ceremony": "典礼官", + "HADAR": "马腹一", + "DEVASTATOR": "蹂躏者", + "Baneful Sentinel": "祸患光能哨兵", + "FUTURE PRIDE": "未来荣光市", + "DUST DEVILS": "尘卷风", + "Ghoul": "噬光者", + "E-710-RICH SYSTEM": "710元素富集星系", + "Princess": "公主", + "VACCA": "瓦卡", + "Automaton Mortar Emplacement": "机器人的迫击炮台", + "INDUSTRY ALLATEED": "阿拉提德工业", + "Hive Guards": "虫窝护卫", + "SIEMNOT": "席姆纳特", + "Custodian": "守护者", + "Spore Burst Scavengers": "孢裂食腐虫", + "LIBER-TEA TOWNSHIP": "解放茶镇", + "Jet Brigade Commissar": "喷气旅机械统帅", + "GEMSTONE BLUFFS": "宝石崖", + "HARDY": "强健市", + "ALIGNMENT": "同心市", + "of Destiny": "天命", + "DEECON": "圣侍", + "ARKTURUS": "阿克图勒斯", + "DOGTOWN": "多格镇", + "FURY": "费里", + "MOX": "莫克斯", + "PROBARE": "究理", + "TOPSOIL": "表土市", + "Lady": "圣女", + "CHURNED EARTH EXOSUIT PATTERN": "焦土外骨骼装甲涂装", + "PRAVOGRAD": "权右沃格勒", + "Prophet Illusionist": "先知幻光大师", + "Brood Wardens": "虫族守卫", + "HALIES PORT": "海利斯港", + "Young": "扬", + "NEW PENG": "新漂市", + "KEPLER-400b": "开普勒400b", + "Elevated Overseer": "崇高监视者", + "STEELED VETERANS": "铁血老兵", + "NIVEL 43": "尼维尔43", + "LAMB'S PATCH": "羔原", + "Marshal": "元帅", + "Pledge": "誓约", + "ARABILITY": "沃壤", + "Mission Control": "任务调度员", + "Elevated Overseers": "崇高监视者", + "RAYSTING": "雷斯汀", + "FUTURIA": "未来城", + "Hulk Bruisers": "巨型碾压者", + "GATRIA": "盖尔崔亚", + "Thomasson": "托马松", + "Rupture Chargers": "爆裂强袭虫", + "ALTONBURG": "奥尔顿堡", + "CIRRUS": "希勒斯", + "ATRAMA": "阿特拉玛", + "MARFARK": "玛尔法克", + "High Command has identified this Megafactory as one of two potential beachheads for the invasion of Cyberstan. Rapid insertion protocols will restrict deployment ammunition.": "最高指挥部已将这座超大型工厂认定为入侵生化斯坦的两个潜在滩头堡之一。快速突入协议将限制部署弹药。", + "MAGUS ACOLYTE": "奇能侍僧", + "Thompson": "汤普森", + "MALLSTRIP NODES": "商廊节点", + "Borderline Justice": "临界正义", + "Viper Commandos": "毒蛇突击兵", + "of Selfless Service": "无私", + "Voteless": "无票者", + "SEORAKSAN": "雪岳山", + "WALNUT ACRES": "胡桃木埃克斯", + "Jet Brigade Troopers": "喷气旅装甲兵", + "CURIA": "居里亚", + "STOUT": "斯图尔特", + "ROGUE 5": "罗格5", + "MEGACORPUS": "梅加科尔普斯", + "DRAGONROACH": "蟑龙", + "LUXURIANT": "富源", + "SATELLARIA": "卫环", + "URBAN LEGENDS": "都市传奇", + "Marcus": "马库斯", + "BICEP": "擎穹", + "Hive Lords": "霸王虫", + "Spore Burst Scavenger": "孢裂食腐虫", + "VIPER COMMANDOS": "毒蛇突击兵", + "ADNAN": "安拓市", + "GREATER STOROUSE": "大储仓", + "Pyro Trooper": "炙焰装甲兵", + "UNDERGROWTH VEHICLE PATTERN": "灌木载具涂装", + "LEMURIA RISING": "利莫里亚崛起城", + "CHARGER": "强袭虫", + "TERRENE": "类地", + "CARBONDALE": "卡本代尔", + "Baneful Sentinels": "祸患光能哨兵", + "HETT": "炎核", + "INARI": "伊纳里", + "OKUL VI": "欧库VI", + "Fleshmob": "肉瘤体", + "ON-EARSAHOU": "顿听呼", + "Gazers": "凝视者", + "Radicals": "激进先锋", + "REFORMED-BY-TRUTH": "真理改造市", + "QUENCH": "淬火市", + "X-45": "X45", + "SHIRAHAMA": "白滨", + "SENATOR PEAKS": "议员峰", + "KALASATAMA": "渔港", + "NEW YEARNING CITY": "盛盼新城", + "Triumph": "的胜利", + "Roughly translates to \"Destroy Freedom At All Costs.\" Significant conventional SEAF assaults will be required to support an offensive here, straining ammunition resources.": "大意为“不惜一切代价摧毁自由”。在此发动攻势需要超级地球武装部队进行大规模常规突击支援,弹药资源将十分紧张。", + "LIL'OME": "乐居城", + "HUNTER": "追猎虫", + "HANDAKAS": "汉达卡斯", + "ANNWN": "安温", + "Inagaki": "稻垣", + "OBSERVATORY 6": "监测站6", + "Bjorkman": "比约克曼", + "BANKABILITY": "金枢", + "DRACO SECTOR": "天龙座分区", + "KUPER": "库珀", + "UVP ALPHA": "UVP阿尔法", + "PROWLER": "潜掠虫", + "AUSPICE": "天启", + "NEW PARADISE": "新天堂", + "DEEPWELL": "深井", + "COMMAND BUNKER": "指挥碉堡", + "VEGA BAY": "织女一湾", + "STACY": "斯特西", + "Nitsan": "尼岑", + "GRAND ERRANT": "大艾伦特", + "FRESH ORCHARDS": "鲜果园", + "ZOSMA": "太微右垣五", + "OBEDIENT DEMOCRACY SUPPORT TROOPERS": "民主光环驰援部队", + "CHURNED EARTH VEHICLE PATTERN": "焦土载具涂装", + "ORION SECTOR": "猎户座分区", + "APPROVAL CITY": "准都", + "Lemaire": "勒迈尔", + "GENERATORSVILLE": "电机维尔", + "Reign": "支配", + "MOG": "莫格", + "ACCOUNTANT GRAEBER": "会计格雷伯", + "BATU BELIG": "巴图贝利格", + "HELLDIVERS MOBILIZE!": "绝地潜兵总动员!", + "NEW COB": "新科布", + "OTARU'S PLEDGE": "小樽诺城", + "EIGHTRINGS": "八环城", + "DIVER'S REST": "潜兵安息市", + "HEAVY DEVASTATOR": "重型蹂躏者", + "LENG SECUNDUS": "蓝恩次星", + "Barrager Tanks": "铁幕坦克", + "Predator Hunter": "掠食追猎虫", + "WALKAWAY": "逍遥道", + "CARAMOOR": "开勒莫尔", + "Zealots": "狂热战士", + "Veracitors": "证真者", + "RESPITE": "统息市", + "Outcast Slasher": "狂刃光弃者", + "HUSARIA": "轻骑", + "ENULIALE": "安努力亚", + "MORSKIE OKO": "海洋之眸", + "of Opportunity": "机遇", + "JURISPRUDENCE": "律裁城", + "MUSTARD HELLPOD PATTERN": "芥末黄绝地喷射舱涂装", + "BROOD COMMANDER": "虫族指挥官", + "SAFETY ORANGE EXOSUIT PATTERN": "安全橘外骨骼装甲涂装", + "Brettman": "布雷特曼", + "Factory Striders": "移动工厂", + "Brood Commander": "虫族指挥官", + "Chargers": "强袭虫", + "PYRO TROOPER": "炙焰装甲兵", + "LAGERLÖF CITY": "拉格洛夫城", + "CELEBRATION": "庆祝市", + "KIRRIK": "基里克", + "MERIDIA": "默里迪亚", + "NON-PARTISAN": "超党市", + "ÖDESHÖGRE": "厄德斯霍格雷", + "Hakalax": "哈卡拉克斯", + "CONCRETE JUNGLE VEHICLE PATTERN": "混凝土丛林载具涂装", + "Higham": "海厄姆", + "Rocket Raider": "火箭奇袭者", + "KRAKABOS": "克拉克博斯", + "CIVILITY": "礼序", + "TRAITOR'S END": "终叛城", + "THE ILLUMINATE": "光能者", + "OL' OLDHAM": "老奥尔德姆", + "of Eternity": "永恒", + "HULK OBLITERATOR": "巨型抹煞者", + "Cutting Edge": "遥遥领先", + "FROSTOWN": "霜镇", + "CHARBAL-VII": "查巴尔VII", + "PEONY": "牡丹", + "Mother": "之母", + "ALMINA IV": "阿尔米纳IV", + "Armstrong": "阿姆斯特朗", + "ERATA PRIME": "艾拉特主星", + "FENMIRE": "范迈尔", + "ESKER": "艾斯克尔", + "UNKNOWN SYSTEM": "未知星系", + "COMMUNEFALLS": "公社瀑布", + "Armelin": "阿默兰", + "HULK SCORCHER": "巨型炙炎者", + "RIRGA BAY": "里尔加湾", + "Hansson-Bjerke": "汉松-比耶克", + "ZENITH": "穹顶", + "Helldivers Mobilize!": "绝地潜兵总动员!", + "Lee": "李", + "Kimura": "木村", + "DOSTOINSTVO": "尊严市", + "Berserker": "狂暴者", + "NEW KATHMANDU": "新加德满都", + "MUSTARD SHUTTLE PATTERN": "芥末黄运输船涂装", + "Severien": "塞韦连", + "Shrieker Nests": "尖啸虫巢穴", + "Fleshmobs": "肉瘤体", + "XIRAN'S CLAIM": "希兰领地", + "PIONEER'S DREAM": "先驱梦城", + "LESATH": "尾宿八", + "ALAMAK VII": "天大将军一VII", + "OTUR": "厄图尔", + "UVP GAMMA": "UVP伽马", + "OLD CHEMLAND": "旧化工城", + "Whisper": "的低语", + "BASHYR": "巴希尔", + "of Peace": "和平", + "This Megafactory contains significant Automaton production facilities. Anti-orbital defenses will tax Super Destroyer resources, resulting in longer orbital cooldowns.": "这座超大型工厂拥有大量机器人生产设施。反轨道防御设施将消耗超级驱逐舰资源,导致轨道支援冷却时间延长。", + "PANDION-XXIV": "帕狄恩XXIV", + "HAVEN": "黑文", + "IRULTA": "艾鲁尔塔", + "DYN ALPHA 534-2": "沙丘阿尔法534-2", + "ELIGIBLE": "天契", + "SANGIS": "赤血", + "OVERSEER": "监视者", + "QUINTUS SECTOR": "昆图斯分区", + "FARSIGHT SECTOR": "法尔赛特分区", + "NUBLARIA I": "努布拉里亚I", + "SCOUT STRIDER": "侦察纵步者", + "HERTHON SECUNDUS": "赫尔松次星", + "XIAMEN ANEW": "尚厦门", + "URSOOT NINE": "乌尔苏特九号", + "ADHAFERA SECUNDUS": "轩辕十一次星", + "FLEDGE": "雏羽", + "SKAR'S GARDENS": "斯卡斯加登斯", + "Bug Hole": "虫穴", + "TRUE BLUE VEHICLE PATTERN": "忠诚蓝载具涂装", + "Dropships": "运输舰", + "CLAORELL": "可洛尔", + "CHEMICAL AGENTS": "化学专家", + "THE AUTOMATONS": "机器人", + "of the Stars": "星辰", + "LIGHT-OF-LIBERTY": "耀辉自由城", + "DISCOVERY GLEN": "探索谷", + "Obedient Democracy Support Troopers": "民主光环驰援部队", + "Corpeleijn": "科尔佩莱因", + "GYEONGSEONG": "京城", + "McGregor": "麦格雷戈", + "BRINK-2": "布林克2", + "BILE SPEWER": "胆汁喷涌虫", + "BILE WARRIOR": "吐酸武斗虫", + "STRONGFORT": "斯特朗福特", + "CORNUCOPOLIS": "富饶城", + "ANDROS GAMMA": "安德罗斯伽马", + "Hunter": "追猎虫", + "LONE": "独行者", + "CONCEALED SYSTEM": "隐蔽星系", + "TURING": "图灵", + "Bettmann": "贝特曼", + "SCUTUM CANIS LUPUS": "狼盾", + "KEPLER-393b": "开普勒393b", + "SAFETY ORANGE HELLPOD PATTERN": "安全橘绝地喷射舱涂装", + "Xenobite Ardent": "炽热异噬者", + "CANNON TURRET": "加农炮台", + "Bile Warrior": "吐酸武斗虫", + "LOKAHEIM": "洛卡海姆", + "Lord": "之主", + "BOPSFIELD": "波普斯菲尔德", + "PORT MERCY": "馨家泊", + "OSLO STATION": "奥斯陆站", + "OMEGA SECTOR": "欧米茄分区", + "CLE ELUM REDIVIVA": "克利勒姆复兴城", + "PÖPLI IX": "珀普利IX", + "Morgan": "摩根", + "WEZEN": "弧矢一", + "PORUGU": "毗卢固市", + "Jet Brigade MG Trooper": "喷气旅机枪装甲兵", + "FOUR CROWNS": "四冠市", + "FREE TRADE": "自贸区", + "MOBERG'S DREAM": "莫伯格之梦", + "Hulk Obliterators": "巨型抹煞者", + "Heathcote": "希思科特", + "Bringer": "引路人", + "BLIGHTSMURK": "瘟茨默克", + "DEBTOR'S DOWNS": "债丘", + "CANOPUS": "老人", + "CALEFACTORIA": "炽庭", + "Dragonroaches": "蟑龙", + "RIZIO'S VISION": "里齐奥愿景", + "RUPTURE WARRIOR": "爆裂武斗虫", + "Annihilator Tank": "湮灭坦克", + "VIBRANCY": "活力市", + "RAS ALGETHI": "帝座", + "of Humankind": "人类", + "SERENDIPITY XI": "天缘XI", + "VALDIS SECTOR": "瓦尔迪斯分区", + "BOHUS": "布胡斯", + "of Benevolence": "博爱", + "FENRIR III": "芬里尔III", + "BIRCHVILLE": "桦木维尔", + "of Self-Determination": "自主", + "SCHOLAR'S MOOR": "学者荒原", + "BELLATRIX": "参宿五", + "KNIGHT'S HONOR": "骑士荣誉城", + "ORESINK": "奥尔辛克", + "Shrieker Nest": "尖啸虫巢穴", + "Conflagration Devastator": "烈火蹂躏者", + "NOSSER": "诺瑟", + "SETIA": "赛提亚", + "ZEALOT": "狂热战士", + "Flowers": "弗劳尔斯", + "OBEDIENCE": "服从市", + "SUPERIORIA LV": "卓尊", + "BARREN WARD": "不毛沃德", + "MERAK": "北斗二", + "Bayrak": "巴伊拉克", + "IPTUS SECTOR": "伊普都斯分区", + "Olofsson": "奥洛夫松", + "DEMOCRATIC DETONATION": "民主爆破", + "GREATWOOD MILLS": "巨木米尔斯", + "AUTONOMY": "自固堡", + "DOWNPOUR": "暴雨城", + "SEVERIN SECTOR": "塞弗林分区", + "Rocket Raiders": "火箭奇袭者", + "PERSEVERANCE": "坚毅市", + "Winaldy": "维纳尔蒂", + "PREDATOR STALKER": "掠食追踪虫", + "of Dawn": "破晓", + "BARRAGER TANK": "铁幕坦克", + "OLD HEARTH CITY": "旧寒炉市", + "SIRIUS II": "天狼星II", + "SARAH SWIFT DAM": "莎拉斯威夫特大坝", + "Warp Ship": "穿梭舰", + "SEVENSEAL": "七印城", + "VERNEN WELLS": "佛农井", + "BEACHVIEW": "碧景湾", + "Pouncers": "猛扑虫", + "STANDARD TANK PATTERN": "标准坦克涂装", + "POLAR PATRIOTS": "极地爱国者", + "Brawlers": "乱斗者", + "KELVINOR": "开尔文奥尔", + "RASP": "拉斯普", + "SHRIEKER NEST": "尖啸虫巢穴", + "EXO EXPERTS": "外骨骼装甲专家", + "PO'S RAVENNA": "波氏拉文纳", + "Obtruder": "突入者", + "ALPHA COMMANDER": "阿尔法指挥官", + "TIBIT": "提比特", + "PERIWINKLE MILLS": "长春花磨城", + "KUMA": "天棓二", + "WATCHER": "守望者", + "DUMA TYR": "杜马提尔", + "SAMMELSURIUM": "喧沌", + "Shredder Tank": "碎裂坦克", + "Zealot": "狂热战士", + "Ayre": "艾尔", + "Burrows": "伯罗斯", + "of the Constitution": "宪法", + "ALADFAR CXI": "辇道二CXI", + "Conflagration Devastators": "烈火蹂躏者", + "Named for the historic conference where Humanity was found to be the most Equal species in the Galaxy.": "因历史性会议而得名,此会议将人类认定为银河系最平等的物种。", + "Khatib": "哈提卜", + "Nicholson": "尼科尔松", + "CELESTE SECTOR": "塞勒斯特分区", + "General Brasch": "布拉施将军", + "of Serenity": "宁静", + "ERSATZ": "厄萨茨", + "Legislator": "立规者", + "COLUMBIDAE": "和平鸽", + "of Patriotism": "丹心", + "GRAFSEAD": "爵首市", + "HALDUS": "海德斯", + "LOGISTICS HUB 232-B": "物流中心232-B", + "ELECTRA BAY": "昴宿一湾", + "YED PRIOR": "天市右垣九", + "OLD INTERNMENTS": "旧禁所", + "CLOCKSTOP": "钟停市", + "CHARA": "常陈四", + "Colossus": "巨匠", + "QZ-4": "疫区4", + "CERBERUS IIIc": "刻耳柏洛斯IIIc", + "AURORA BAY": "极光湾", + "King": "之王", + "Ryhre": "吕勒", + "KEPLER-394b": "开普勒394b", + "NEKK POND": "水妖池", + "Keeper": "看守人", + "GREATER INVESTMENT": "巨资市", + "NO COMPOUND": "无堡市", + "Nystrom": "奈斯特伦", + "PIEA": "皮耶阿", + "MINERAL'S END": "矿竭地", + "of Destruction": "毁灭", + "UVP BETA": "UVP贝塔", + "KEPLER-398b": "开普勒398b", + "SWAMP V": "沼泽V", + "HAKU CITY": "哈库城", + "Fritzell": "弗里策尔", + "EMBOLD": "无畏", + "GATEKEEPER": "御门者", + "OROTH": "欧拉斯", + "Judge": "审判", + "Kelder": "凯尔德", + "Marauders": "劫掠者", + "Veracitor": "证真者", + "Johansson": "约翰松", + "Sellerfors": "塞勒福什", + "of War": "战争", + "HIVE GUARD": "虫窝护卫", + "DRAUPNIR": "德罗普尼尔", + "Fabricator": "构筑者", + "CONCRETE JUNGLE EXOSUIT PATTERN": "混凝土丛林外骨骼装甲涂装", + "RUPTURE CHARGER": "爆裂强袭虫", + "Elected Representative": "选举代表", + "HEART FLATS": "心平市", + "EXCITEMENT": "激情市", + "Sector": "分区", + "Sturk": "斯图克", + "Jet Brigade Raider": "喷气旅奇袭者", + "PIT 8": "8号坑", + "TANDEM": "天腾", + "TECHOLOCKY": "锢技坊", + "Righteous Revenants": "正义复仇者", + "KEPLER-392b": "开普勒392b", + "Control Group": "变量控制", + "PREDATOR HUNTER": "掠食追猎虫", + "OBARI": "欧巴里", + "BRAWLER": "乱斗者", + "Panther": "之豹", + "Bug Holes": "虫穴", + "Crescent Overseer": "新月监视者", + "SWAMP VI": "沼泽VI", + "CANTOLUS SECTOR": "坎托鲁斯分区", + "FAMILY-FRIEND": "家宜", + "UNISON": "和谐市", + "UBANEA": "乌巴尼亚", + "JIN XI SECTOR": "锦栖分区", + "SCOUT RAIDER": "侦查奇袭者", + "CRESCENT OVERSEER": "新月监视者", + "Infested Tower": "侵染塔巢", + "BUJU": "布朱", + "Rupture Charger": "爆裂强袭虫", + "LINDOME": "林杜默", + "OMNIPARITUS": "全诛堡", + "IMBER": "因博尔", + "CASTELLAN GREEN HELLPOD PATTERN": "卡斯特兰绿喷射舱涂装", + "CASTOR": "北河二", + "of the Regime": "政权", + "Barrager Tank": "铁幕坦克", + "Bunker Turret": "碉堡炮台", + "Crusher": "粉碎者", + "Edstrom": "艾德斯特伦", + "Lasota": "拉索塔", + "Hive Lord": "霸王虫", + "TVENNE BOTTOMS": "双瓣谷", + "of Steel": "钢铁", + "DEMIURG": "戴米尔基", + "WASAT": "天樽二", + "AMITTERE": "亚米逝地", + "STANDARD HELLPOD PATTERN": "标准绝地喷射舱涂装", + "GAELLIVARE": "耶利瓦勒", + "HELLDRIVERS": "绝地司机", + "GACRUX": "十字架一", + "GRAPESHOT": "葡萄弹市", + "CRIMSICA": "克里姆西卡", + "PROVIDENCE": "普罗维登斯", + "EXALT": "颂扬市", + "Fraser": "弗雷泽", + "PEACOCK": "孔雀十一", + "Magus Acolyte": "奇能侍僧", + "TERMINIDS": "终结族", + "DEFENSIBLE": "卫戍", + "MINCHIR": "敏切尔", + "PENTA": "彭塔", + "CAMRAT FOR": "卡姆拉特堡", + "NEW DA NANG": "新岘港", + "OUTCAST SEEKER": "逐觅光弃者", + "PORTE LIBERTÉ": "自由门", + "UMLAUT SECTOR": "乌姆劳特分区", + "REGISTER": "登记市", + "PLETHORA": "普雷索拉市", + "WORKHOUSE 239-C": "救济所239-C", + "Redacted Regiment": "绝密军团", + "FLESHMOB": "肉瘤体", + "Heavy Devastators": "重型蹂躏者", + "FERRIS SECTOR": "费里斯分区", + "Forerunner": "先驱", + "Baskin": "巴斯金", + "MERIDIAN SECTOR": "默里迪亚分区", + "THE TERMINIDS": "终结族", + "Rocket Devastators": "火箭蹂躏者", + "Trooper": "装甲兵", + "Osman": "奥斯曼", + "Frob": "弗洛伯", + "MORTAX PRIME": "摩尔塔克斯主星", + "Longato": "隆加托", + "Warriors": "武斗虫", + "Jet Brigade MG Troopers": "喷气旅机枪装甲兵", + "KELVIN SECTOR": "凯尔文分区", + "LUSCIOUS LIBERTY": "甘美自由市", + "Camara": "卡马拉", + "NEW KIRUNA": "新基鲁纳", + "Vox Engine": "噪轰引擎", + "Song": "之歌", + "Alpha Commanders": "阿尔法指挥官", + "MOBILE WHITE HELLPOD PATTERN": "移动白色绝地喷射舱涂装", + "REWA": "流望市", + "ADMINISTRATIVE CENTER 02": "行政总都02", + "INVESTMENT": "投资点", + "GUANG SECTOR": "古安分区", + "MESSAGER'S MESA": "信使台地", + "FAMILY GROVE": "家林市", + "Stallion": "神驹", + "WIDOW'S HARBOR": "寡妇港", + "THE VILLAS": "别墅区", + "EXTRASOLAR ASH VEHICLE PATTERN": "系外星尘载具涂装", + "MATAR BAY": "玛塔", + "ANDROS DELTA": "安德罗斯德尔塔", + "KHARST": "喀斯特", + "of Morality": "道德", + "of Morning": "清晨", + "Predator Stalker": "掠食追踪虫", + "Obtruders": "突入者", + "AZTERRA": "艾孜泰拉", + "SCALD": "烧卡尔德", + "Sodermark": "索德马克", + "Dream": "之梦", + "Overship": "统御舰", + "CRYSTAL SLOPES": "水晶坡", + "ALDERIDGE COVE": "阿尔德里奇湾", + "TROOPER": "装甲兵", + "Distributor": "派遣人", + "RUINED SYSTEM": "废墟星系", + "CHARGER BEHEMOTH": "巨兽级强袭虫", + "MEAN GREEN VEHICLE PATTERN": "凶猛绿载具涂装", + "SOLGHAST": "索尔加斯特", + "MINE 902": "矿洞902", + "Fabricators": "构筑者", + "LAELIA": "蕾丽兰城", + "Stingray": "刺魟", + "AQUILA XXXII": "天鹰XXXII", + "INGMAR": "英格玛", + "Father": "之父", + "SENGE 23": "新戈23", + "WILE": "千惑", + "Titan": "泰坦", + "Bile Titans": "吐酸泰坦", + "Purveyor": "传承", + "Pilestedt": "皮勒斯泰特", + "ALAIRT III": "艾列尔特III", + "KEPLER-399b": "开普勒399b", + "CHURNED EARTH HELLPOD PATTERN": "焦土绝地喷射舱涂装", + "Schonberger": "舍恩伯格", + "LAMBAST": "兰巴斯特", + "ZEA RUGOSIA": "泽亚鲁戈西亚", + "ANNIHILATOR TANK": "湮灭坦克", + "Dust Devils": "尘卷风", + "Beacon": "信标", + "AZUR SECUNDUS": "艾热尔次星", + "VÁHTJER": "瓦赫特耶尔", + "Truth Enforcers": "真理执行者", + "Will": "意志", + "KURRI KURRI": "库里库里", + "ERRANT": "艾伦特", + "BORE ROCK": "博尔岩", + "CONTROL GROUP": "变量控制", + "MG Raiders": "机枪奇袭者", + "Scavenger": "食腐虫", + "UNREGISTERED SYSTEM": "未注册星系", + "BEKVAM III": "贝克温III", + "MG RAIDER": "机枪奇袭者", + "of Justice": "正义", + "DILUVIA": "迪卢维亚", + "Warp Ships": "穿梭舰", + "LIBERTY RIDGE": "解放岭", + "CASTELLAN GREEN VEHICLE PATTERN": "卡斯特兰绿载具涂装", + "Hulk Firebombers": "巨型烈焰轰炸者", + "IDUN SECTOR": "伊顿分区", + "FREEDOM'S FLAME": "自由烈焰", + "SOLIDARITET": "团结堡", + "of Authority": "权威", + "DOUBLET II": "双子裳II", + "GLOBULUS": "球布勒斯", + "PHAM'S SITE": "范姆镇", + "BUCU'S REST": "布库安息城", + "VILHELMINA DOROTHEA FREDRIKA": "维尔赫尔米娜·多罗茜娅·弗蕾德里卡", + "Auger": "奥格", + "Broomhall": "布鲁姆霍尔", + "Susnjar": "舒什尼亚尔", + "Davidsson": "戴维松", + "KINABATANGAN": "京那巴当岸", + "DIVER'S GLORY": "潜兵荣光市", + "PARSH": "帕尔什", + "Scout Raiders": "侦查奇袭者", + "Haggstrom": "黑格斯特伦", + "FIREFLY MEADOWS": "萤火草原", + "Champion": "斗士", + "SAPPHIRE LAKE": "蓝石湖", + "Halo": "光环", + "CIVILIANS IN AREA": "区域内有平民", + "Not much is known about this planet.": "未知", + "Number of stims each Helldiver deploys with increased by #V_ONE.": "每位绝地潜兵上阵时配给的治疗剂数量增加#V_ONE。", + "Stim capacity increase no longer in effect.": "治疗剂容量增加的效果结束。", + "Annihilate": "歼灭", + "The Orbital Laser stratagem is temporarily available to all Helldivers.": "“轨道激光炮”战略配备可暂时供所有绝地潜兵使用。", + "Battlefield pickups contain #V_ONE% less ammo.": "战场拾取物中将减少#V_ONE%的弹药。", + "STRATAGEM SURPLUS": "战略配备过剩", + "HIDE ORDERS": "隐藏指令", + "T- #DAYSD:#HOURSH:#MINUTESM": "倒计时-#DAYS日:#HOURS时:#MINUTES分", + "Dense sandstorms reduce mobility and greatly reduce visibility for both enemy and friendly units.": "铺天盖地的沙暴会削弱行动能力并大幅降低能见度,敌我双方都将受影响。", + "Completing this Operation helps reclaim this city. Successfully reclaiming cities significantly contributes to the planet's Liberation.": "完成此次行动有助于收复这座城市。成功收复这座城市将大幅推动星球解放进程。", + "The Orbital 120mm HE Strike stratagem is temporarily available to all Helldivers.": "“轨道120mm高爆弹攻击”战略配备可暂时供所有绝地潜兵使用。", + "The Eagle Napalm Airstrike stratagem is temporarily available to all Helldivers.": "“‘飞鹰’凝固汽油弹空袭”战略配备可暂时供所有绝地潜兵使用。", + "The ARC-3 Arc Thrower stratagem is temporarily available to all Helldivers.": "“ARC-3电弧发射器”战略配备可暂时供所有绝地潜兵使用。", + "#V_ONE is temporarily available to all Helldivers.": "#V_ONE可暂时供所有绝地潜兵使用。", + "WEAPONS EXPERIMENTATION": "武器试验", + "GRAVITATIONAL ANOMALY DETECTED": "侦测到引力异常", + "E-711 ACQUISITION": "获取711元素", + "Parents Frantic After Child Uploads Consciousness Into Cloud Server": "儿童意识上传云服务器,引起家长恐慌", + "Helldivers KIA": "绝地潜兵阵亡数", + "INVASION CAMPAIGN PROGRESS": "入侵战役进度", + "Housing Costs On Rise As Even-Greater Greatest Generation Moves Into Retirement": "伟大中的伟大世代迎来退休,房价应声走高", + "Call For Enlistments Sent To All Citizen Classes.": "参军号召已发送至各级公民", + "DEVASTATOR SURGE": "蹂躏者激增", + "Availability of #V_ONE has ended.": "现已无法使用#V_ONE。", + "PLANET LIBERATED - MOVE TO NEW PLANET": "星球解放 - 前往其他星球", + "Virydian Toys Corp. Deemed Not At": "洛绿玩具公司无需", + "Increase in number of uses of #V_ONE stratagem no longer in effect.": "#V_ONE战略配备可用次数增加的效果结束。", + "The Heavy Machine Gun Emplacement stratagem is temporarily available to all Helldivers.": "“重机枪部署支架”战略配备可暂时供所有绝地潜兵使用。", + "Number of magazines for all weapons Helldivers deploy with is temporarily decreased by #V_ONE.": "绝地潜兵上阵时配给的所有武器弹匣数量暂时减少#V_ONE。", + "The Defense Wall stratagem is temporarily available to all Helldivers.": "“防御墙”战略配备可暂时供所有绝地潜兵使用。", + "GUNSHIP PATROLS": "炮舰巡逻队", + "For the near future, ground will be lost on Planet #V_ONE faster than before.": "近期内,#V_ONE星球的阵地将以前所未有的速度沦陷。", + "Mission time increase no longer in effect.": "任务时间延长的效果结束。", + "Dropping In": "正在降落", + "All Helldivers will passively regenerate health at a rate of #V_ONE% per second.": "所有绝地潜兵以每秒#V_ONE%的速度被动恢复生命值。", + "MERIDIAN SINGULARITY": "默里迪恩奇点", + "Any recognizeable form of life is absent in this austere, cold, rocky world.": "单调、寒冷、岩石嶙峋的星球,不存在可辨识的生命形态。", + "The M-105 Stalwart stratagem is temporarily available to all Helldivers.": "“M-105‘盟友’”战略配备可暂时供所有绝地潜兵使用。", + "The enemy has flooded this planet with Automaton Tanks. Expect increased encounters with heavy armor.": "敌人已向该星球大量投放机器人坦克。预计将频繁遭遇重甲敌军。", + "CITY OPERATION": "城市行动", + "EFFECTS": "效果", + "Legalizing 8 New Pre-Approved Comments On News Media.": "8条预先批准的新媒体评论现已合法", + "This black hole is all that remains of the hopes and dreams of the colonists who could have built a life here. Our enemies would sooner see the entire galaxy sucked into an endless void than allow our way of life to prosper.": "拓殖地居民的希冀与幻想湮灭在黑洞之中,他们原本可以在这里创造幸福的生活。我们的敌人宁愿亲眼看着整个星系被吸入无尽的虚空,也不愿意看见我们的文明繁荣发展。", + "EXPLOSIVES SHORTAGE": "爆炸品短缺", + "NEW OPERATION AVAILABLE": "有新行动可以参加", + "Extraction time against the Illuminate is #V_ONE seconds faster.": "对阵光能者时的撤离时间加快#V_ONE秒。", + "The Automatons have deployed high numbers of Devastators to this planet. Prepare to encounter heavily armored enemies.": "机器人已向该星球部署了大量蹂躏者。请做好应对重甲敌军的准备。", + "TRACKING: MISSION REQUESTS": "正在追踪: 任务申请", + "\"Pulsar Pop\" Dance Craze Sweeps Galaxy": "“脉冲星波普”舞蹈热潮席卷全星系", + "Orbital Gas Strike stratagem availability has ended.": "现已无法使用“轨道毒气攻击”战略配备。", + "SUDDEN ROUTING": "急转直下", + "Helldivers Prepare For Massive Strike on Terminid Hives.": "绝地潜兵准备大规模攻击终结族虫窝", + "Signs Of Sentient Life Discovered On Okul VI; Safely Eradicated.": "欧库VI发现感知生命体存在的迹象,现已妥善消除", + "Eagle Rearm time is #AMOUNT seconds slower on this planet.": "在此星球上的飞鹰时间将减慢#AMOUNT秒。", + "The Orbital Precision Strike stratagem is temporarily available to all Helldivers.": "“轨道精准攻击”战略配备可暂时供所有绝地潜兵使用。", + "Number of grenades each Helldiver deploys with increased by #V_ONE.": "每位绝地潜兵上阵时配给的榴弹数量增加#V_ONE。", + "A mutated strain of Terminids has been reported on this planet. Expect to encounter cunning hunter bugs.": "据报告,该星球上出现了一种终结族变异体。请做好准备,应对狡诈的追猎虫。", + "MAJOR ORDER WON\nGaellivare has been held for the designated timeframe. However, the planet, and the DSS itself, remain imperiled. The fight is not over.\nHigh Command will monitor the situation. Further guidance will be issued once the fate of Gaellivare is decided—one way or the other.": "重要指令达成\n我方在指定时段内守住了耶利瓦勒。但该星球以及DSS本身仍处在威胁中。战斗尚未结束。\n最高指挥部将持续关注局势。无论如何,待耶利瓦勒的命运尘埃落定后,我方将制定进一步的指导方针。", + "ROVING SHRIEKERS": "漫游尖啸虫", + "Number of uses of #V_ONE stratagem is temporarily increased by #V_TWO.": "#V_ONE战略配备的可用次数暂时增加#V_TWO。", + "AUTOMATON INVASION": "机器人入侵", + "Another Colony Devastated By Surprise Automaton Attack.": "机器人再次突袭破坏拓殖地", + "This planet is trapped in the Void. It will remain trapped here until the Source planet is found and dealt with, at which point this planet will return to its native galaxy.": "这颗星球被困在寂域之中。我们必须找到并妥善处理源头星球,否则这颗星球将永困于此,无法回归原本所在的星系。", + "Super Weapon Fires in #TIME": "超级武器开火倒计时:#TIME", + "ILLUMINATE OVERSHIP": "光能者统御舰", + "Welcome to the Galactic War.\n\nHere the community fights together against its common enemies.": "欢迎参加星系战争。\n\n全体绝地潜兵在此齐心协力对抗共同的敌人。", + "Eagle Napalm Airstrike stratagem availability has ended.": "现已无法使用“‘飞鹰’凝固汽油弹空袭”战略配备。", + "SECTOR": "分区", + "The Orbital Airburst Strike stratagem is temporarily available to all Helldivers.": "“轨道空爆攻击”战略配备可暂时供所有绝地潜兵使用。", + "Unknown": "未知", + "ILLUMINATE FLEET STRENGTH": "光能者舰队战力", + "The arid, rocky biome covering this world has driven the evolution of exceptionally efficient water usage in its various organisms.": "这颗星球遍布由岩石构成的干燥生物群落,其中各式各样的有机体经过进化,对水分的利用效率已十分惊人。", + "Jump Pack stratagem availability has ended.": "现已无法使用“喷射背包”战略配备。", + "Eagle 500kg Bomb stratagem availability has ended.": "现已无法使用“‘飞鹰’500kg炸弹”战略配备。", + "MEGAFACTORY MISSION": "超大型工厂任务", + "Grenade capacity increase no longer in effect.": "榴弹容量增加的效果结束。", + "Number 4 Voted \"Most Democratic Number.\"": "数字4获选成为“最民主数字”", + "Melting Icecaps On Gemstone Bluffs Lead To Increase In Superboat-Hotel Prices.": "宝石崖冰冠融化导致超级舟船酒店房费升高", + "ST-1 Stinger stratagem availability has ended.": "现已无法使用“ST-1毒刺”战略配备。", + "HEAVY ARMOR SURGE": "重甲敌军激增", + "Preliminary Installation Procedures Begin For Terminid Deterrance Network.": "终结族威慑网初期建设工作开始", + "SAMPLES:": "样本:", + "The Shield Generator Pack stratagem is temporarily available to all Helldivers.": "“防护罩生成包”战略配备可暂时供所有绝地潜兵使用。", + "Number of grenades each Helldiver deploys with decreased by #V_ONE.": "每位绝地潜兵上阵时配给的榴弹数量减少#V_ONE。", + "New Evidence Suggests Famous Photo \"The Slaying of the Beast of Vog-Sojoth\" was Faked.": "最新证据表明著名摄影作品《屠杀佛戈索约斯巨兽》主体内容不实", + "New Study Shows 98% of Children Under Twelve Want To": "最新研究发现98%的12岁以下儿童希望", + "Operations on higher difficulties are more challenging, contain new enemies and missions. \n\nThey also have a greater impact on the war, and yield higher rewards. Complete an operation on your highest unlocked difficulty to unlock the one above it.": "行动的难度越高,就越具挑战性,其中包含新的敌人和新的任务。\n\n它们对战争的影响也会提升,并产生更丰厚的奖励。完成一项已解锁的最高难度行动,即可解锁更高一级的难度。", + "Grenade capacity for all Helldivers is temporarily increased by #V_ONE.": "所有绝地潜兵的榴弹容量暂时增加#V_ONE。", + "GLOOM SOURCE": "“阴霾”源头", + "Ends in:": "结束倒计时:", + "Number of uses of #V_ONE stratagem reduced by #V_TWO.": "#V_ONE战略配备的可用次数减少#V_TWO。", + "SEAF Advance Against Automatons Stalls.": "超级地球武装部队向机器人据点进发", + "Squelching mud, twisting roots; the odor of rot and anarchy. A teeming, endless morass.": "地面泥泞不堪,树木盘根错节,散发着腐烂与混乱的恶臭。一片无边无际的沼泽。", + "OPERATION IMPACT": "行动影响", + "New Strain of Bioluminescent Kittens Sells Out In Minutes!": "生物荧光猫咪新品种若干分钟售罄!", + "Ion storms intermittently disable Stratagems.": "离子风暴会间歇性导致战略配备无法使用。", + "Caution: loyal civilians are on the battlefield.": "当心:战场上发现忠诚平民。", + "Extraction time against the Automatons is #V_ONE seconds slower.": "对阵机器人时的撤离时间减慢#V_ONE秒。", + "EXTREME": "极端", + "Helldiver Joining": "绝地潜兵正在加入", + "Artificial Sunlight Determined To Be At Least As Good For You, If Not Better, Than Natural Sunlight.": "专业判定人造阳光对你的益处不会逊色于自然阳光", + "IMPOSSIBLE": "不可能的任务", + "FASTER EAGLE REARM": "飞鹰时间加快", + "CLASS 4 MEGAFACTORY": "4级超大型工厂", + "The Illuminate are generating Dark Energy on this planet, which they are using to move the Meridian Singularity toward Super Earth. They must be stopped at all costs.": "光能者正在该星球上生成暗物质,并用此物质将默里迪恩奇点移至超级地球。必须不惜一切代价阻止它们。", + "FAILURE": "失败", + "RUPTURE STRAIN": "爆裂虫族变种", + "INITIATING FTL JUMP": "正在启动超光速跃迁", + "An orbital strike will be automatically fired whenever a Helldiver is killed.": "只要有绝地潜兵阵亡,就会自动触发一次轨道攻击。", + "Heavy Outposts": "重型哨站", + "The EAT-17 Expendable Anti-Tank stratagem is temporarily available to all Helldivers.": "“EAT-17消耗性反坦克武器”战略配备可暂时供所有绝地潜兵使用。", + "Stand by for further orders from Super Earth High Command": "等待超级地球最高指挥部的进一步指令", + "Unanticipated Automaton reinforcements are taking significant ground on Planet #V_ONE.": "突如其来的机器人增援部队正在#V_ONE星球上占领重要阵地。", + "Impact of each mission returned to normal level.": "每次任务的影响力已恢复正常。", + "Heavily Armored Enemies": "重甲敌人", + "LOW ORBIT SUPERIORITY": "低轨优势", + "#DISTANCE km": "#DISTANCE公里", + "\"Super Earth Plasma-Sniper\" Smashes Box-Office Records.": "《超级地球等离子狙击手》轻松突破票房纪录", + "The Orbital Railcannon stratagem is temporarily available to all Helldivers.": "“轨道炮”战略配备可暂时供所有绝地潜兵使用。", + "The DSS deploys Eagle Strafing Runs during missions.": "民主空间站在任务中部署“飞鹰”机枪扫射。", + "Mission Timer reduced to 30 minutes.": "任务时限缩短至30分钟。", + "Swarm": "虫群", + "INCREASED IMPACT": "扩大影响", + "The AC-8 Autocannon stratagem is temporarily available to all Helldivers.": "“AC-8机炮”战略配备可暂时供所有绝地潜兵使用。", + "GENERATING DARK ENERGY": "正在生成暗物质", + "Orbital EMS Strike stratagem availability has ended.": "现已无法使用“轨道电磁冲击波攻击”战略配备。", + "Liberate": "解放", + "Grow Up To Be Helldivers. Remaining 2% Under Investigation.": "长大以后成为绝地潜兵,剩余2%尚在调查", + "The Guard Dog stratagem is temporarily available to all Helldivers.": "“护卫犬”战略配备可暂时供所有绝地潜兵使用。", + "FAF-14 Spear stratagem availability has ended.": "现已无法使用“FAF-14飞矛”战略配备。", + "SAND RAIN": "沙雨", + "Number of grenades each Helldiver deploys with is temporarily increased by #V_ONE.": "每位绝地潜兵上阵时配给的榴弹数量暂时增加#V_ONE。", + "The Anti-Personnel Mine Deployer stratagem is temporarily available to all Helldivers.": "“反步兵地雷部署器”战略配备可暂时供所有绝地潜兵使用。", + "A blazing-hot desert planet, its rocky mesas are the sole interruptions to the endless sea of dunes.": "灼热的沙漠星球,除了坚硬的平顶山以外,只有数不尽的沙丘。", + "Orbital 380mm HE Barrage stratagem availability has ended.": "现已无法使用“轨道380mm高爆弹火力网”战略配备。", + "This planet is completely engulfed by the Gloom, severely impeding logistical support.\nExtraction times are increased by 40 seconds, Eagle Re-arm time is increased by 30% and Ammo from pickups is reduced by 50%.": "这颗星球完全被“阴霾”吞没,严重阻碍后勤支援。\n撤离时间延长40秒,“飞鹰”重新装弹时间延长30%,拾取获得的弹药数量减少50%。", + "Temporary stim decrease no longer in effect.": "治疗剂数量临时减少的效果结束。", + "Stim capacity for all Helldivers increased by #V_ONE on this planet.": "在此星球上的所有绝地潜兵的治疗剂容量增加#V_ONE。", + "Medal payout per mission for all Helldivers is temporarily increased by #V_ONE.": "所有绝地潜兵每次任务的奖章收益暂时增加#V_ONE。", + "The enemy is attacking this planet. If they are not repelled in time, it will be lost.": "敌人正在袭击这颗星球。如果不及时驱逐敌人,星球就会沦陷。", + "PLANETARY DEFENSE FAILURE IN: #TIME": "行星防御失效倒计时:#TIME", + "All currently active Orders can be viewed here.": "当前可执行指令均可在此查看。", + "A geologically recent cataclysm wiped out nearly all life on this planet. Ash and jagged lava rock seem to be all that's left.": "在地质时间尺度上较为近期内发生的一场灾难几乎抹杀了这颗星球上所有的生命。唯一剩下的似乎只有灰烬和凹凸不平的岩浆岩。", + "For the near future, an orbital strike will be automatically fired whenever a Helldiver is killed.": "近期内,只要有绝地潜兵阵亡,就会自动触发一次轨道攻击。", + "Helldivers deploy with #V_ONE% less magazines.": "绝地潜兵部署时携带弹匣数减少#V_ONE%。", + "The presence of the DSS near this planet provides a slight boost to Liberation Campaign progress.": "DSS停靠在这颗星球附近一定程度上也有助于推进解放战役。", + "Map obscured by Bug Spores.": "虫族释放的孢子将会遮蔽地图。", + "EAT-17 Expendable Anti-Tank stratagem availability has ended.": "现已无法使用“EAT-17消耗性反坦克武器”战略配备。", + "SPORE CLOUD POCKETS": "局部孢云", + "Supreme Court of Super Earth Rules Amendment": "超级地球最高法院规则通过修正案", + "PERSONAL ORDERS": "个人指令", + "Sentient Computer Network Swiftly Deleted By Quick-Thinking IT Laborer.": "IT劳工反应迅速,第一时间删除感知电脑网络", + "Mountains of sand bake in unrelenting heat on this utter desolation of a planet.": "庞大的沙丘在酷热中炙烤。这颗星球荒凉至极。", + "The Automatons have deployed a series of specialized models on this planet. Prepare to face bots upgraded with stolen Jump Pack technology.": "机器人在这颗星球上部署了一系列特殊型号。请做好应对利用失窃的喷射背包技术升级优化的机器人。", + "Exploration Vessel Claims to Have Detected Illuminate-like Energy Signature.": "勘探船声称探测到类光能者能量标志", + "SLOWER EAGLE REARM": "飞鹰时间减慢", + "Orbital Gatling Barrage stratagem availability has ended.": "现已无法使用“轨道加特林火力网”战略配备。", + "VOID EXPLORATION": "寂域探索", + "Completing this operation contributes to the planet's Liberation.": "完成此次行动将推动星球解放进程。", + "INVASION FLEET": "入侵舰队", + "Assault Commence in:": "突袭倒计时:", + "EQUIPMENT TESTING": "装备试验", + "OPERATION": "行动", + "Eagle Air-to-Air Missiles stratagem availability has ended.": "现已无法使用“‘飞鹰’空对空导弹”战略配备。", + "The prosperous Meridia was corrupted into a Terminid Supercolony, necessitating its destruction using the mysterious Dark Fluid. This galactic scar is all that remains. Advisory: volatile spacetime fluctuations currently prohibit FTL travel to the Meridian Black Hole.": "曾经欣欣向荣的默里迪亚沦为终结族超级拓殖地,不得不使用神秘的暗液体将其摧毁。如今唯有这道银河系的疤痕,昭示着它曾经的存在。警告:时空波动不稳定,目前无法通过超光速跃迁前往默里迪恩黑洞。", + "The Supply Backpack stratagem is temporarily available to all Helldivers.": "“补给背包”战略配备可暂时供所有绝地潜兵使用。", + "Accumulation of Space Trash Leads To Formation of Floating Trash Moon": "太空垃圾大量积聚组成垃圾卫星", + "Allied Tactical Objectives": "友方战术目标", + "Planet events can happen when enemies are attacking Super Earth controlled planets - Defend Event - or when Super Earth advances in the galaxy - Liberation Events.\n\nMake sure to do your part!": "敌人对超级地球控制下的星球发起攻击时,便会爆发星球战事,名为保卫战事;超级地球在星系中扩大势力时也会爆发星球战事,名为解放战事。\n\n请务必参战!", + "CLAIM": "占领", + "TERMINID QUARANTINE ZONE": "终结族隔离区", + "Planet #V_ONE, on the verge of a successful defense, has fallen to the enemy.": "#V_ONE星球在成功防御之际落入敌手。", + "BATTLE FOR CYBERSTAN": "生化斯坦之战", + "IN TRANSIT TO MISSION SITE": "正在传输至任务地点", + "Helldivers Redirected From Operation Valiant Enclosure To Fully Engage Automatons.": "绝地潜兵调离英勇围合行动,全力应战机器人", + "Senator Killjoy Jr. Gives Stirring Speech: \"Super Earth Stronger Than Ever!\"": "小克乔伊参议员言论引起轰动:“超级地球目前实力胜过任何一个历史时期!”", + "CITY OPERATION REWARD": "城市行动奖励", + "Explodes in:": "爆炸倒计时:", + "High numbers of enemy Hulks have been reported on this planet. Prepare to encounter heavily armored enemies.": "据报告称,该星球上出现大量敌方巨型者。请做好应对重甲敌军的准备。", + "Study Finds Galactic Warming Due To Natural Causes": "研究发现星系变暖与自然因素有关", + "The Orbital Gas Strike stratagem is temporarily available to all Helldivers.": "“轨道毒气攻击”战略配备可暂时供所有绝地潜兵使用。", + "SETTLEMENT": "定居点", + "In Loadout": "正在进行武装配置", + "Automatons' Mass Production Capabilities Exceed Expectations.": "机器人量产能力超出预期", + "Shield Generator Pack stratagem availability has ended.": "现已无法使用“防护罩生成包”战略配备。", + "Eagle Rearm time is #AMOUNT seconds faster on this planet.": "在此星球上的飞鹰时间将加快#AMOUNT秒。", + "The Tesla Tower stratagem is temporarily available to all Helldivers.": "“特斯拉塔”战略配备可暂时供所有绝地潜兵使用。", + "In Orbit": "正在轨道上", + "Helldivers Active": "绝地潜兵活跃数", + "Disappeared Colony Transmissions Mention \"Squids\".": "中断的拓殖地通讯内容提及“乌贼”", + "Select a mission and get ready to dive!": "选择任务,准备俯冲降落。", + "Dense fog lightly reduces visibility for both enemy and friendly units.": "浓雾会略微降低能见度,敌我双方都将受影响。", + "A desert planet prone to unpredictable and dangerous sand twisters.": "沙漠星球,时常发生危险而又难以预测的尘卷风。", + "Pro-Terminid Activists Sentenced To 20 Years In Asteroid Mines By Heroic Judge.": "亲虫活动分子被判小行星矿场流放20年", + "Friends Active": "活跃好友", + "Missing Child Astronaut Found In Plutonium Well By Robotic Dog.": "机器狗在钚井发现失踪儿童宇航员", + "LIBERATE ALL SECTORS": "解放全部分区", + "Freedomball Star Rex Stribling Scores Mega-Goal in Twelfth Consecutive Game.": "自由球明星雷克斯·斯特里布林连续12场比赛打进超远大力球", + "Extraction takes #V_TWO seconds less.": "撤离所需时间缩短#V_TWO秒。", + "The Eagle 500kg Bomb stratagem is temporarily available to all Helldivers.": "“‘飞鹰’500kg炸弹”战略配备可暂时供所有绝地潜兵使用。", + "Powerful dust devils launch smaller combatants into the air and stun larger combatants.": "猛烈的尘卷风会将小型战斗单位卷至空中并且会眩晕大型战斗单位。", + "Medal payout per mission for all Helldivers reduced by #V_ONE.": "所有绝地潜兵每次任务的奖章收益减少#V_ONE。", + "Eagle Rearm time is #V_ONE% faster.": "重新武装“飞鹰”的时间加快#V_ONE%。", + "CLASS 3 MEGAFACTORY": "3级超大型工厂", + "Ice and moss-covered rock can be found across most of the surface of this planet.": "这颗星球表面大多是冰雪和长着苔藓的岩石。", + "Missing Child Found Orbiting Asteroid After Family Spacewalk Mishap.": "太空行走事故失踪儿童现已找到,当时正在围绕小行星旋转", + "Orbital 120mm HE Strike stratagem availability has ended.": "现已无法使用“轨道120mm高爆弹攻击”战略配备。", + "MODIFIERS [#COUNT]": "限制条件[#COUNT]", + "Terminid Dragonroaches menace the skies of this planet. Prepare to encounter airborne enemies.": "终结族的蟑龙变种威胁着这颗星球的领空。请做好应对空中敌军的准备。", + "MINDLESS MASSES": "无脑群氓", + "AUTOMATON OCCUPIED SPACE": "机器人占领的空间", + "Meteors impact the surface causing massive damage.": "流星会撞击地表,造成大量伤害。", + "Melee damage is temporarily decreased by #V_ONE%.": "近战伤害暂时降低#V_ONE%。", + "FRACTURED PLANET": "碎裂星球", + "GREAT HIVES": "大虫窝", + "Medal payout per mission for all Helldivers is temporarily reduced by #V_ONE.": "所有绝地潜兵每次任务的奖章收益暂时减少#V_ONE。", + "Complete operations on #PLANET": "在#PLANET完成行动", + "MISSIONS COMPLETED BONUS": "任务完成奖励", + "Hovering over a sector shows you how much of it Super Earth has already liberated. All operations contribute to pushing the enemies of Super Earth back.\nSelect a sector to see what planets are currently playable.": "悬停在分区上可看到超级地球在该区的解放进度。所有行动皆能为击退超级地球的敌人贡献助力。\n选择分区,看看当前可以参与哪颗星球的战事。", + "Dark Energy Accumulation": "暗物质积聚", + "MG-43 Machine Gun stratagem availability has ended.": "现已无法使用“MG-43机枪”战略配备。", + "Supply Backpack stratagem availability has ended.": "现已无法使用“补给背包”战略配备。", + "#RACE": "#RACE", + "DAMAGED FACTORIES": "工厂受损", + "PROXIMITY TO MERIDIA CRITICAL": "与默里迪亚的距离达到临界点", + "CYBORGS": "生化人", + "Corrosive acid storms temporarily reduce armor effectiveness for both enemy and friendly units.": "腐蚀性酸雨风暴会暂时削弱盔甲的防护效用,敌我双方都将受影响。", + "The ST-1 Stinger stratagem is temporarily available to all Helldivers.": "“ST-1毒刺”战略配备可暂时供所有绝地潜兵使用。", + "OPERATION STATUS": "行动状态", + "HELLDIVERS: #VALUE": "绝地潜兵:#VALUE", + "Battlefield pickups on all planets contain #AMOUNT% more ammo.": "所有星球上的战场拾取物中将增加#AMOUNT%的弹药。", + "TERMINID FRENZY": "狂暴终结族", + "Heavy SEAF Presence": "超级地球武装部队重兵驻守", + "Conventional SEAF forces are heavily deployed across this planet, and may directly support Helldiver missions.": "常规超级地球武装部队已在该星球上大量部署,可直接为绝地潜兵的任务提供支援。", + "PLATOON: #VALUE": "特战排:#VALUE", + "A mutation causes Terminids on this planet to generate excess hormonal spores, which drive other similarly mutated Terminids into a frenzy. Prepare to face enemies that bolster each others' speed.": "一场突变导致该星球上的终结族产生过量激素孢子,驱使其他发生类似突变的终结族陷入狂暴。准备迎击这些为彼此提速的敌人。", + "FAILED": "失败", + "Extraction time against the Illuminate is #V_ONE seconds slower.": "对阵光能者时的撤离时间减慢#V_ONE秒。", + "VOTE SNATCHERS": "窃票者", + "The Orbital EMS Strike stratagem is temporarily available to all Helldivers.": "“轨道电磁冲击波攻击”战略配备可暂时供所有绝地潜兵使用。", + "DEFEND SUPER EARTH": "保卫超级地球", + "Unverified Reports of Illuminate Sightings Attributed to Dissident Disinformation.": "未经证实的光能者目击报道助长异见分子的造谣气焰", + "Cooldown period increase for #V_ONE stratagem no longer in effect.": "#V_ONE战略配备冷却时间延长的效果结束。", + "#PERCENTAGE% HELD": "#PERCENTAGE%保卫成功", + "The DSS fires Orbital Barrages during missions.": "民主空间站在任务中发射轨道火力网。", + "Terminid Swarming in Unprecedented Numbers, Defying Expert Explanations.": "终结族数量增速前所未见,专家理论纷纷破产", + "The GL-6 Grenade Launcher stratagem is temporarily available to all Helldivers.": "“GL-6榴弹发射器”战略配备可暂时供所有绝地潜兵使用。", + "The Orbital Gatling Barrage is experimentally modified to use incendiary rounds instead of HE rounds.": "轨道加特林火力网经实验性调整,改用燃烧弹替代高爆弹。", + "Enemy progress in Defense Campaigns is slowed.": "敌人在保卫战役中的进展放缓。", + "82-Year-Old Woman Catches Sedition Group Meeting In Attic.": "82岁女性家中阁楼发现叛乱团伙集会", + "Tall, gnarled trees flourish across the surface of this forested world. Sunlight filters past dangling vines, to the saturated undergrowth below.": "蟠枝虬根的参天大树在这片植被茂密的地表蓬勃生长。阳光穿过垂悬的藤蔓,落入色泽饱和的林下灌丛中。", + "This planet is considered enemy territory. The Helldivers must reclaim it from its oppressive occupants.": "这颗星球被列为敌占领地。绝地潜兵必须从残暴入侵者手中夺回控制权。", + "RECON CAMPAIGN": "侦察战役", + "LOWER STIM CAPACITY": "更小治疗剂容量", + "RS-422 Railgun stratagem availability has ended.": "现已无法使用“RS-422磁轨炮”战略配备。", + "Bio-Genetics Startup Fills Volcano With Mutant Giant Popcorn Kernels": "生物基因初创企业向火山内投入大量变种巨型爆米花仁", + "DEFENSE": "防御战", + "RESISTANCE": "抵抗强度", + "INTENSE HEAT": "极暑", + "Historians Determine \"Gaslighting\" Never Meant What We Thought It Meant": "历史学家认为“煤气灯操纵”实际含义始终不同于大众认知", + "SUCCEEDED": "成功", + "The FAF-14 Spear stratagem is temporarily available to all Helldivers.": "“FAF-14飞矛”战略配备可暂时供所有绝地潜兵使用。", + "STRATAGEM CONSERVATION": "节省战略配备", + "Liberation Impact from completed missions on this planet is #V_ONE% greater on this planet.": "在此星球上完成任务所造成的解放影响将扩大#V_ONE%。", + "Number of reinforcements available per mission is temporarily decreased by #V_ONE.": "每次任务的可用增援数暂时减少#V_ONE。", + "Initial Helldiver Push Against Terminids \"Unequivocal Success.\"": "绝地潜兵进攻终结族的初始计划“取得了绝对的胜利”", + "Experience gain for all Helldivers is temporarily reduced by #V_ONE%.": "所有绝地潜兵获得的经验值暂时减少#V_ONE%。", + "Massive Enemies": "大型敌人", + "CRITICAL THREAT LEVEL": "临界威胁等级", + "Protects Individual Right To Own Giant Mechanized Robot": "保障个人拥有巨型机械化机器人的权利", + "Entirely unforeseeable mutations from the Termicide led to hyper-accelerated bug growth on this planet, turning it into a Supercolony. It is corrupted beyond saving. The bugs infest every inch of it, down to the mantle, spawning trillions of spores every day.": "灭虫终结剂引发毫无预警的突变,导致虫族极速繁殖,将这颗星球变为了超级拓殖地。星球已经腐化得无可救药,虫族侵染了上面的每一寸土地,连地幔也没有幸免于难,每天都繁殖出数万亿孢子。", + "Ballistic Shield Backpack stratagem availability has ended.": "现已无法使用“防弹护盾背包”战略配备。", + "Man Trades Up Giant Red Paperclip For Asteroid.": "男子为购小行星出售巨型红色回形针", + "Guard Dog stratagem availability has ended.": "现已无法使用“护卫犬”战略配备。", + "Stratagem Call-in time increased by #V_ONE%.": "战略配备的呼叫时间增加#V_ONE%。", + "The Illuminate have unleashed the next wave of their democratically voided thralls on this planet. Expect violent voter suppression tactics.": "光能者在该星球上释放了新一波毫无民主理念的奴仆。请准备好迎接暴力的选民压制手段。", + "An unanticipated Terminid surge is taking significant ground on Planet #V_ONE.": "突如其来的终结族激增势力正在#V_ONE星球上占领重要阵地。", + "Time to complete all missions is temporarily increased by #V_ONE%.": "完成所有任务的时间暂时延长#V_ONE%。", + "#PLANET": "#PLANET", + "So long as even one Mega City stands, so does Super Earth. Illuminate Fleet Strength must be depleted before the last one falls.": "只要还有一座特大城市屹立不倒,超级地球便不会沦陷。在最后一座特大城市沦陷前,必须耗尽光能者军队战力。", + "Heroic Kindergartener Identifies Dissident Classmate": "幼儿园英勇儿童发现同班异见分子", + "FLAM-40 Flamethrower stratagem availability has ended.": "现已无法使用“FLAM-40火焰喷射器”战略配备。", + "Warning: Starting a new Operation will abandon your currently active Operation": "警告:开始新行动将终止目前进行中的行动。", + "This is a Commando Operation. It contains Commando missions.\n\nIn Commando missions, access to your Super Destroyer and Stratagems will be limited. Choose your engagements carefully.": "这是突击兵行动。其中包含突击兵任务。\n\n在突击兵任务中,使用超级驱逐舰和战略配备都将受限。请谨慎选择交战对象。", + "Extracting": "正在撤离", + "COMMANDO OPERATION": "突击兵行动", + "LIGHT GLOOM COVER": "轻度“阴霾”笼罩", + "The Orbital Walking Barrage stratagem is temporarily available to all Helldivers.": "“轨道游走火力网”战略配备可暂时供所有绝地潜兵使用。", + "Number of stims each Helldiver deploys with is temporarily decreased by #V_ONE.": "每位绝地潜兵上阵时配给的治疗剂数量暂时减少#V_ONE。", + "Heavy Machine Gun Emplacement stratagem availability has ended.": "现已无法使用“重机枪部署支架”战略配备。", + "Anti-Democracy Rebels Rounded Up with Stunning Efficiency.": "反民主叛乱分子全部落网", + "Rocky outcroppings punctuate fields of tall grass in a planet dominated by misty highland terrain.": "这颗星球地表大多是雾气氤氲的高地。茂盛的草原上不时冒出裸露的岩石。", + "Volcanos throw burning rocks around this planet.": "火山会将灼热的岩石喷射至这颗星球各处。", + "The Rocket Sentry stratagem is temporarily available to all Helldivers.": "“火箭哨戒炮”战略配备可暂时供所有绝地潜兵使用。", + "Researchers Declared Dead After Canine Neural Communication": "犬类神经通信装置意外接入附近狼类大脑", + "Heroic dog rescues boy from plutonium mine shaft": "英勇狗狗将男孩救出钚矿井", + "Carve a path through the Megafactories towards the Cyborg Capital—the largest Megafactory and nexus of Cyborg resistance. Destroy it before our Forces in Reserve are depleted to liberate Cyberstan.": "从超大型工厂杀出一条血路,直捣生化人首都,那是最大的超大型工厂,也是生化人抵抗势力的核心枢纽。在预备部队耗尽战力之前将其摧毁,解放生化斯坦。", + "Reinforcement increase is no longer in effect.": "可用增援数增加的效果结束。", + "This planet continually produces a thick atmospheric Gloom cover, rendering logistical support extremely challenging.\nTotal Reinforcements are reduced by 20%, Eagle Re-arm time is increased by 30% and Ammo from pickups is reduced by 50%.": "这颗星球持续积累厚重的“阴霾”孢子层,使后勤支援变得极其困难。\n总增援数减少20%,“飞鹰”重新装弹时间延长30%,拾取获得的弹药数量减少50%。", + "Abandon Operation": "放弃行动", + "Bullets Fired": "射击弹药数", + "The Orbital 380mm HE Barrage stratagem is temporarily available to all Helldivers.": "“轨道380mm高爆弹火力网”战略配备可暂时供所有绝地潜兵使用。", + "Medal payout decrease no longer in effect.": "奖章收益减少的效果结束。", + "LOCAL TIME SETU: #VALUE": "当地时间(超级地球时间单位): #VALUE", + "Arrives in:": "抵达倒计时:", + "Grenade capacity for all Helldivers increased by #V_ONE.": "所有绝地潜兵的榴弹容量增加#V_ONE。", + "TRIVIAL": "易如反掌", + "M-105 Stalwart stratagem availability has ended.": "现已无法使用“M-105‘盟友’”战略配备。", + "Effectiveness of #V_ONE is temporarily increased by #V_TWO%.": "#V_ONE的效果暂时提升#V_TWO%。", + "Operation Valiant Enclosure In Crisis.": "英勇围合行动面临危机", + "HULK SURGE": "巨型者激增", + "Terminid Deterrance Network Ready For Implementation Following Cordon Establishment.": "继封锁线后,终结族威慑网也已准备部署应用", + "The Eagle Air-to-Air Missiles stratagem is temporarily available to all Helldivers.": "“‘飞鹰’空对空导弹”战略配备可暂时供所有绝地潜兵使用。", + "A perenially chilly climate has allowed short, colorful shrubs to flourish across this planet's surface.": "这里常年寒冷,颜色各异的矮小灌木在得天独厚的气候条件下占领了这颗星球的地表。", + "New Study Cut Tragically Short by Terminid Strike.": "终结族袭击导致最新研究不幸提前终止", + "A deadly strain of ground-bursting Terminids is present on this planet. Prepare to face burrowing enemies.": "这颗星球上出现了一种从地下破土而出的致命终结族变种。请做好应对钻地敌军的准备。", + "Send You There\" Stranded Behind Enemy Lines.": "继续爆出参赛选手被困敌阵", + "Aftermath of Planet Busters: Devastation.": "“歼星”成效:完全毁灭", + "AUTOMATON CONTROL": "由机器人控制", + "Medal payout increase no longer in effect.": "奖章收益增加的效果结束。", + "Mansion lost in #TIME": "总统府失守倒计时:#TIME", + "EASY": "简单", + "AUTOMATON BLOCKADE WORLDS": "机器人封锁带", + "The Illuminate are attacking our prosperous colonies, raising strange structures and terrorizing our loyal citizens. While their aim does not seem to be planetary conquest their invasion must nevertheless be repelled before they can accomplish their mysterious, malevolent aims.": "光能者正袭击我们繁荣的拓殖地,还立起了奇怪的建筑物,吓坏了我们忠诚的公民。虽然光能者的目的似乎并非侵略星球,但必须击退它们的入侵,防止其恶毒的神秘目的达成。", + "THE GALACTIC WAR": "星系战争", + "The Autocannon Sentry stratagem is temporarily available to all Helldivers.": "“自动哨戒炮”战略配备可暂时供所有绝地潜兵使用。", + "Flying Gunships patrol the battlefield.": "战场上有飞空炮舰巡逻。", + "Gatling Sentry stratagem availability has ended.": "现已无法使用“加特林哨戒炮”战略配备。", + "SELECT CAMPAIGN": "选择战役", + "Periods of freezing temperatures reduce rate of fire and delay heat buildup in weapons.": "极寒时段会降低射速,减慢武器升温速度。", + "Automatons Ultimate Goal Appears To Be Super Earth Itself, According to MOD.": "国防部称机器人的终极目标疑为超级地球", + "The Jump Pack stratagem is temporarily available to all Helldivers.": "“喷射背包”战略配备可暂时供所有绝地潜兵使用。", + "AC-8 Autocannon stratagem availability has ended.": "现已无法使用“AC-8机炮”战略配备。", + "MODERATE GLOOM BLANKET": "中度“阴霾”笼罩", + "Assault Imminent": "突袭即将开始", + "The SAR-1 Sniper Rifle stratagem is temporarily available to all Helldivers.": "“SAR-1狙击步枪”战略配备可暂时供所有绝地潜兵使用。", + "Communication Troubles From Terminid Quarantine Zone.": "通讯难题困扰终结族隔离区", + "URGENT LIBERATION": "亟待解放", + "in": "in", + "START MISSION": "开始任务", + "This former planet is now nothing but a normal, stable black hole.": "这颗昔日行星现在不过是一个没什么特别的稳定黑洞。", + "Reduction in number of uses of #V_ONE stratagem no longer in effect.": "#V_ONE战略配备可用次数减少的效果结束。", + "DEFENSE PROGRESS": "保卫战役进度", + "SATURATED RANKS": "军衔晋升饱和", + "The Illuminate are converting large numbers of Super Earth citizens into Voteless-type enemies on this planet. Prepare to face a twisted, indoctrinated horde.": "光能者正在这颗星球上将大批超级地球公民转化为无票者型敌人。准备迎战这群遭到洗脑、思维扭曲的暴徒。", + "Giant Pandas Officially Extinct; Giant Panda-Bot ETF Value Skyrockets": "大熊猫正式灭绝,机器大熊猫交易所交易基金净值飙升", + "COMPLETE #CR_DESC#CR_NEWLINE OPERATION TO UNLOCK": "完成#CR_DESC#CR_NEWLINE行动后解锁", + "SEARCHING FOR MISSIONS IN PROGRESS": "正在寻找进行中的任务", + "Increased Enemy Presence": "敌人势力增强", + "Melee damage decreased by #V_ONE%.": "近战伤害降低#V_ONE%。", + "THICK FOG": "浓雾", + "DEFEND": "保卫", + "Successful Nuclear Weapons Test": "确定为死亡状态", + "MERIDIAN BLACK HOLE": "默里迪恩黑洞", + "Spaceship of Theseus Destroyed Piece By Piece": "忒修斯太空飞船已逐渐解体", + "Temporary magazine reduction no longer in effect.": "弹匣数量临时减少的效果结束。", + "PILOT SHORTAGE": "驾驶员短缺", + "Number of magazines for all weapons Helldivers deploy with is temporarily increased by #V_ONE.": "绝地潜兵上阵时配给的所有武器弹匣数量暂时增加#V_ONE。", + "Awaiting Major Order": "等待重要指令", + "Launches in:": "发射倒计时:", + "Number of grenades each Helldiver deploys with is temporarily decreased by #V_ONE.": "每位绝地潜兵上阵时配给的榴弹数量暂时减少#V_ONE。", + "Mission time reduction no longer in effect.": "任务时间缩减的效果结束。", + "Medium Outposts": "中型哨站", + "A Patriotic Miracle? Woman on Pioneer II Finds Flag of Super Earth In Toast": "爱国主义奇迹?先驱II星系上的女子在吐司中发现超级地球旗帜", + "Battlefield pickups on this planet contain #AMOUNT% more ammo.": "在此星球上的战场拾取物中将增加#AMOUNT%的弹药。", + "BATTLE FOR SUPER EARTH": "超级地球保卫战", + "SECTOR MAP": "分区地图", + "Solar Storm Edna Reclassified As Solar Hurricane Edna.": "太阳风暴埃德娜被重新界定为“太阳飓风埃德娜”", + "PLANETARY FRACTURING CONFIRMED": "行星破裂已确认", + "Destroy the Automaton Super Weapon": "摧毁机器人超级武器", + "Revenge orbital strike no longer in effect.": "复仇轨道攻击不再生效。", + "Stim capacity for all Helldivers decreased by #V_ONE on all planets.": "所有星球上的所有绝地潜兵的治疗剂容量减少#V_ONE。", + "\"Freedom of Expression\" Bill Passes Into Law,": "《表达自由》法案通过审议", + "The nearby Gloom Base provides logistical support to this Hive World, mitigating some of its extreme logistical challenges.\nExtraction times are increased by 30 seconds and Eagle Re-arm time is increased by 20%.": "附近的“阴霾”基地为这个虫窝世界提供后勤支援,缓解了严峻的后勤压力。\n撤离时间延长30秒,“飞鹰”重新装弹时间延长20%。", + "The Meridian Singularity speeds up as Dark Energy accumulates": "暗物质积聚,默里迪恩奇点加速移动", + "UNKNOWN SIGNATURE": "不明标志", + "TIN SHORTAGE": "锡资源短缺", + "Ground will no longer be lost more quickly on Planet #V_ONE.": "#V_ONE星球的阵地沦陷的速度不再加快。", + "The Automatons are deploying an abnormal amount of War Striders and Tanks to this planet. Prepare to encounter high numbers of heavily armored enemies": "机器人正在向该星球部署异常数量的战争纵步者与坦克。请做好应对大量重甲敌军的准备", + "CONVENTIONAL BLACK HOLE": "常规黑洞", + "C.O.B. Genetics to Donate Last Year's Corn to Hungry Cows.": "C.O.B.基因公司拟向饥牛捐赠去年所产玉米", + "Promising New Study Establishes Link Between 4D Cinema and Real World Violence.": "最新研究发现4D电影与现实世界的暴力行为存在关联", + "TS-4 Arc Thrower stratagem availability has ended.": "现已无法使用“ARC-3电弧发射器”战略配备。", + "Rip Gustafson Wins Yet Another Mr. Multiverse Competition": "利普·古斯塔夫松再次荣获“多重宇宙先生”称号", + "Astronomers Identify Promising New Exoplanet For Settlement.": "天文学家发现可能宜居的新系外行星", + "Conquer the #SECTOR": "征服#SECTOR", + "Helldivers Redirected from Automaton Conflict Back To Terminids.": "绝地潜兵调离机器人冲突战区,重返抗击终结族前线", + "All that remains of a planet torn apart by the Meridian singularity. A solemn reminder of the desolation Tyranny leaves in its wake.": "被默里迪恩奇点摧毁的星球残骸。它庄严地提醒着我们,暴政必将带来毁灭。", + "This planet serves as a connective point between this galaxy and the Void, allowing travel between the two spaces.": "这颗星球是本星系与寂域之间的连接点,可以让舰船在二者之间穿梭。", + "Torrential rainstorms reduce visibility.": "倾盆暴雨会降低能见度。", + "ORBITAL FLUCTUATIONS": "轨道波动", + "INVASION CAMPAIGN": "入侵战役", + "POOR INTEL": "缺乏情报", + "Number of stims each Helldiver deploys with is temporarily increased by #V_ONE.": "每位绝地潜兵上阵时配给的治疗剂数量暂时增加#V_ONE。", + "The Orbital Gatling Barrage stratagem is temporarily available to all Helldivers.": "“轨道加特林火力网”战略配备可暂时供所有绝地潜兵使用。", + "Extraction time increase no longer in effect.": "撤离时间延长的效果结束。", + "Completing this Operation helps hold this Mega City. Once a Mega City falls, it cannot be reclaimed.": "完成此次行动有助于保卫这座特大城市。特大城市一旦沦陷便无法收复。", + "Eagle 110mm Rocket Pods stratagem availability has ended.": "现已无法使用“‘飞鹰’110mm火箭巢”战略配备。", + "Stim capacity for all Helldivers is temporarily increased by #V_ONE.": "所有绝地潜兵的治疗剂容量暂时增加#V_ONE。", + "The Eagle 110mm Rocket Pods stratagem is temporarily available to all Helldivers.": "“‘飞鹰’110mm火箭巢”战略配备可暂时供所有绝地潜兵使用。", + "The Shield Generator Relay stratagem is temporarily available to all Helldivers.": "“防护罩生成中继器”战略配备可暂时供所有绝地潜兵使用。", + "SECTOR INTRUSION DETECTED": "侦测发现分区遭到入侵", + "TERMINID INVASION": "终结族入侵", + "President Authorizes Use of \"Planet Buster\" Charges to Contain Terminids.": "总统授权动用“歼星”炸药遏制终结族", + "ORBITAL 120MM HE/EMS BARRAGE": "轨道120MM高爆/电磁弹火力网", + "EXOSUIT RESERVES": "外骨骼装甲储备", + "Battlefield pickups on all planets contain #AMOUNT% less ammo.": "所有星球上的战场拾取物中将减少#AMOUNT%的弹药。", + "The #V_ONE stratagem is unavailable to all Helldivers.": "所有绝地潜兵都不能使用#V_ONE战略配备。", + "The RS-422 Railgun stratagem is temporarily available to all Helldivers.": "“RS-422磁轨炮”战略配备可暂时供所有绝地潜兵使用。", + "Multiple Operation Modifiers": "多重行动限制条件", + "79 Million Heroes Added to the Wall in Another Glorious Martyrs' Day.": "7900万英雄光荣烈士日送入英烈墙", + "The AT-48 Recoilless Rifle stratagem is temporarily available to all Helldivers.": "“AT-48无后坐力步枪”战略配备可暂时供所有绝地潜兵使用。", + "SUPPLEMENTAL STEROIDS": "类固醇补充剂", + "Enemy Tactical Objectives": "敌方战术目标", + "Fault For Deadly Hoverboarding Accidents.": "就悬浮滑板致死事故承担任何责任", + "Grenade capacity decrease no longer in effect.": "榴弹容量减少的效果结束。", + "BULLETS FIRED: #VALUE": "开火次数:#VALUE", + "Extraction time temporarily increased by #V_TWO seconds.": "撤离时间暂时延长#V_TWO秒。", + "#PERCENTAGE% LIBERATED": "已解放#PERCENTAGE%", + "MAJOR ORDER REWARD": "重要指令奖励", + "Each Order is tied to an enemy faction and a location in space, represented by an icon on the map.": "每一项指派任务均针对太空某位置的某一敌方阵营,在地图上以图标标识。", + "Stim capacity decrease no longer in effect.": "治疗剂容量减少的效果结束。", + "FORMER SUPER EARTH COLONY": "前超级地球拓殖地", + "The Resupply stratagem is temporarily available to all Helldivers.": "“重新补给”战略配备可暂时供所有绝地潜兵使用。", + "Extraction takes #V_TWO additional seconds.": "撤离所需时间延长#V_TWO秒。", + "SELECT SECTOR": "选择分区", + "New Ursine Species Discovered on Ridge World, Proven Undemocratic and Promptly Eradicated.": "山岭世界发现熊科新物种,证实为非民主物种并当场灭绝", + "EXPERIMENTAL INITIATIVE": "实验性倡议", + "UNIDENTIFIED PLANET": "未识别星球", + "Mortar Sentry stratagem availability has ended.": "现已无法使用“迫击哨戒炮”战略配备。", + "SUPER HELLDIVE": "超级绝地俯冲", + "ENTER THE COLOSSEUM: AUTOMATON VS. BUG - WHO WILL WIN!?": "走进角斗场:机器人对虫族,谁胜谁负!?", + "The #V_ONE stratagem is available to all Helldivers.": "#V_ONE战略配备可供所有绝地潜兵使用。", + "Melee damage decrease no longer in effect.": "近战伤害降低的效果结束。", + "The Gloom covers this planet completely, obstructing a variety of logistical operations.\nExtraction times are increased by 30 seconds and Eagle Re-arm time is increased by 20%.": "“阴霾”已完全笼罩这颗星球,阻碍我们开展各类后勤行动。\n撤离时间延长30秒,“飞鹰”重新装弹时间延长20%。", + "LONG: #VALUE": "经度: #VALUE", + "Enemy Patrols": "敌方巡逻队", + "This dark abyss is all that remains of the verdant paradise that was once Meridia. Its breathtaking forests and abundant resources were corrupted and destroyed by the Terminids, leaving no choice but to use Dark Fluid to destroy it completely. Now, this singularity remains as a memorial, reminding us all of the consequences of defying Freedom.": "默里迪亚曾经富饶的天堂如今只剩下黑暗的深渊。令人叹为观止的森林和丰富的资源遭到了终结族的腐化与摧毁,我们别无他法,只能利用暗液体将其完全销毁。现在,这个奇点已成为纪念碑,时刻提醒着我们藐视自由的代价。", + "OPERATION MODIFIERS": "行动限制条件", + "COLONY MISSION": "拓殖地任务", + "Due to Void interference, no data can be gathered about this planet. There is a high probability of its probable existence.": "由于寂域的干扰,我们无法获取该星球的任何数据。但它存在的可能性极高。", + "Stratagem Codes Scrambled.": "战略配备代码被扰频打乱。", + "After days of fighting, Gaellivare has fallen to the Automaton Jet Brigade. However, thanks to shrewd maneuvering of the Helldivers, the DSS is safely out of their reach.\nThe Helldivers, in their Democratic direction of the DSS, displayed undeniable tactical brilliance, demonstrating once again why they are known as the Galaxy's most elite fighting force. Their efforts held the Automaton onslaught long enough to allow emergency evacuation efforts to save many citizens, many of whom aided in the construction of the space station.\nThe Jet Brigade remains a significant threat. Meanwhile, the crisis created by the sudden and shocking outbreak at the Terminid Research Center is ongoing. The addition of the DSS to Liberty's arsenal, even in its diminished state, could not have come at a better time. Managed Democracy is imperiled; we need every weapon at our disposal.": "经过数天战斗,耶利瓦勒落入了机器人喷气旅手中。不过,幸亏绝地潜兵足够机敏,DSS已安全脱离它们的控制范围。\n绝地潜兵对DSS进行民主指挥,展现无可争议的战术才华,再次证明了他们为何称得上是银河系最精锐的战斗部队。他们拼命拖住了机器人的屠戮,给我方的紧急疏散工作预留足够时间,救出了众多平民,其中许多人还曾协助建造空间站。\n喷气旅依然虎视眈眈。同时,终结族研究中心突如其来的暴乱危机仍在肆虐。解放军械库再添民主空间站这把利器,可谓恰逢其时,即便空间站已受损,仍然无可替代。管理式民主岌岌可危;我们必须动用一切可用的武器。", + "TREMORS": "地震", + "Keep yourself updated with the latest happenings in the Galactic War through the News Feed. \n\nIt automatically displays the latest events!": "请通过新闻动态随时掌握星系战争的最新动态。\n\n最新战事会自动显示动态中!", + "SEAF Forces Cede Another Planet to Advancing Automatons.": "机器人逼近,超级地球武装部队再次割让一颗星球", + "CITY LIBERATION PROGRESS": "城市解放进度", + "Fires in:": "开火倒计时:", + "Last Surviving Hero of First Galactic War Passes Away at 103; \"Greatest Honor\" Was Service.": "第一次星系大战最后一位幸存英雄逝世(享年103岁),追授最高战功勋章", + "Hold back": "压制", + "Headset Accidentally Linked To Nearby Wolves.": "导致研究人员不幸身亡", + "Full Mobilization Declared; \"Super Earth is at War,\" says President.": "全面动员正式开始,总统宣布“超级地球进入战争状态”", + "The Gatling Sentry stratagem is temporarily available to all Helldivers.": "“加特林哨戒炮”战略配备可暂时供所有绝地潜兵使用。", + "HIDE DETAILS": "隐藏详细信息", + "This black hole is all that remains of the singularly beautiful planet that was once Moradesh. Its endless wavy dunes and abundant resources were destroyed by an unavoidable accident at the Dark Fluid Research Facility, as its heroic scientists strived to save our citizens from the first Terminid Supercolony. The Terminids took Moradesh from us, leaving this scar as a reminder of their boundless barbarity.": "莫拉戴什曾是一颗美丽绝伦的星球,如今,一切化为黑洞。星球上连绵起伏的沙丘和丰饶的资源因暗液体研究设施的突发事故而毁灭。当时,英勇的科研人员曾在该设施中致力于对抗首个终结族超级拓殖地,拯救我们的公民。终结族让我们痛失莫拉戴什,留下的疮疤将永远警示着我们,敌人是多么野蛮残暴。", + "The blinding beacon that illuminates the stars with the light of Democracy. The patriotic paradise for citizens who truly serve their Federation. And the utopian future awaiting the entire galaxy.": "炫目的灯塔,以民主之光照亮宇宙群星。真正效忠联邦的爱国公民心中的乐土。为整个银河系描绘了未来乌托邦的蓝图。", + "The lifeless grey of this planet is interrupted only by the violet flowers that grow from strange, parasitic outcroppings.": "灰色是这颗星球的主色,唯有从彷如寄生一般的奇异裸露地表长出的紫罗兰色花朵能打破这股死气沉沉的格调。", + "GRAVITATIONAL COLLAPSE CONFIRMED": "侦测到引力坍缩", + "CITY MISSION": "城市任务", + "Autocannon Sentry stratagem availability has ended.": "现已无法使用“自动哨戒炮”战略配备。", + "ILLUMINATE GOALS ACHIEVED: #TIME": "光能者目标已达成:#TIME", + "Stim capacity for all Helldivers is temporarily decreased by #V_ONE.": "所有绝地潜兵的治疗剂容量暂时减少#V_ONE。", + "Stave Off": "拖延", + "Protect the President's Mansion!": "保卫总统府!", + "Operation Modifiers": "行动限制条件", + "MOBILIZE TO A FRONTLINE PLANET": "响应动员奔赴前线星球", + "#PLANET MEGAFACTORIES": "#PLANET超大型工厂", + "LIBERATION": "解放战役", + "Infectious Disease Expert Calls Terminid Spread An \"Epidemic\".": "传染病专家称终结族扩张为“流行病”", + "Orbital Stratagems Scatter Increased.": "轨道武器战略配备效果范围更加分散。", + "ILLUMINATE FLEET": "光能者舰队", + "Enemy forces are trying to claim this planet! Push them back by playing special missions during the specified time frame, or the planet will fall to the enemy.": "敌军正试图占领这颗星球!在特定时间段内参与特别战事任务,全力击退敌军,否则这颗星球将落入敌军手里。", + "Extraction time against the Automatons is #V_ONE seconds faster.": "对阵机器人时的撤离时间加快#V_ONE秒。", + "All readings, or the notable lack thereof, indicate that the source of the Void anomaly is located here. All effort must go to enabling FTL travel to these coordinates.": "各项读数表明,寂域异常的源头就在这里,部分读数因寂域干扰而缺失,更加证实了这一点。集中全部力量,实现前往该坐标的超光速航行。", + "Experience gain for all Helldivers increased by #V_ONE%.": "所有绝地潜兵获得的经验值增加#V_ONE%。", + "Ground is being lost on Planet #V_ONE faster than before.": "#V_ONE星球的阵地正以前所未有的速度沦陷。", + "The Illuminate are spreading across this planet, seizing our colonies and citizens. They must be expunged.": "光能者正在这颗星球上大肆扩张,掠夺我们的拓殖地和公民。必须将它们彻底清除。", + "\"My Son Was An Automaton Sympathizer.\" One Mother's Valiant Choice To Turn In Her Son.": "“我儿子同情机器人”——女子大义灭亲,举报亲生儿子", + "#V_ONE stratagem is temporarily available to all Helldivers.": "#V_ONE战略配备可暂时供所有绝地潜兵使用。", + "SEAF Fight Against Bots Augmented By Limited Helldiver Operations.": "绝地潜兵的局部行动助力超级地球武装部队扩张抗击机器人的规模", + "The prosperous Meridia was corrupted into a Terminid Supercolony, necessitating its destruction using the mysterious Dark Fluid. This galactic scar is all that remains.": "曾经欣欣向荣的默里迪亚沦为终结族超级拓殖地,不得不使用神秘的暗液体将其摧毁。如今唯有这道银河系的疤痕,昭示着它曾经的存在。", + "INVASION LEVEL": "入侵等级", + "Temporary magazine increase no longer in effect.": "弹匣数量临时增加的效果结束。", + "All Orbital Stratagems have an increased cooldown.": "所有轨道武器战略配备都会延长冷却时间。", + "An Automaton unit equipped with flame throwers and incendiary ammunition is active on this planet. Prepare to face wanton arsonists who will not rest until they have razed all that humankind holds dear.": "装备火焰喷射器和燃烧弹药的机器人部队正在该星球上肆虐横行。请做好准备,应对肆无忌惮的纵火犯,他们唯有将人类珍视的一切烧为灰烬,才肯善罢甘休。", + "THE INCINERATION CORPS": "炽灼部队", + "New 3D-Printed Assault Rifle Can Defensively Slaughter Up To 30 Bugs/Second.": "新型3D打印突击步枪每秒可以防御性击毙30只虫族", + "Shield Generator Relay stratagem availability has ended.": "现已无法使用“防护罩生成中继器”战略配备。", + "The Great Host of the Illuminate is flooding this planet. Their numbers must be thinned.": "光能者大军正席卷这颗星球。必须削减敌方兵力。", + "TERRITORY CLAIMED": "领地已收复", + "Experience gain for all Helldivers is temporarily increased by #V_ONE%.": "所有绝地潜兵获得的经验值暂时增加#V_ONE%。", + "Cooldown period for #V_ONE stratagem reduced by #V_TWO.": "#V_ONE战略配备的冷却时间缩短#V_TWO。", + "Ecological Disaster or Economical Blessing? Space Tanker Crash": "生态灾难还是经济机遇?太空运输船相撞", + "LIVE FEED": "即时动态", + "MEGAFACTORY LIBERATION PROGRESS": "超大型工厂解放进度", + "#V_ONE available to all Helldivers.": "#V_ONE可供所有绝地潜兵使用。", + "from": "from", + "High-priority campaigns contain unique missions related to the current Major Order. Super Earth will liberate High-priority campaign planets just like Liberation campaigns.": "首要战役包含与当前重要指令相关的特殊任务。与解放战役一样,超级地球将解放首要战役的目标星球。", + "AVERAGE": "中等", + "Repel": "击退", + "SMOKE-ENHANCED WALKING BARRAGE": "烟幕增强型游走火力网", + "CONTESTED ORBIT": "竞相争夺的轨道", + "INCENDIARY GATLING BARRAGE": "燃烧加特林火力网", + "VOID INTERFERENCE": "寂域干扰", + "MISSION SITE": "任务地点", + "Detonates in:": "引爆倒计时:", + "University of Super Earth Adopts New Standardized Patriotism Test For Admissions": "超级地球大学入学考试采用新版标准化爱国主义测验", + "The nearby Gloom Base's logistics fleet supports operatives on this planet, counteracting all negative effects of the Gloom.": "附近“阴霾”基地的后勤舰队为这颗星球上的作战人员提供支援,希望能抵消“阴霾”带来的所有负面影响。", + "CITY DEFENSE STATUS": "城市保卫状态", + "We are passively re-gaining ground on Planet #V_ONE.": "我们正在被动夺回#V_ONE星球的阵地。", + "HIGH-PRIORITY CAMPAIGN PROGRESS": "首要战役进度", + "on": "on", + "More Contestants of \"What Planet Am I Standing on or We'll": "《行星猜猜猜,猜错送你来》", + "ORBITAL DEFENSES": "轨道防御", + "Cooldown period for #V_ONE stratagem is temporarily increased by #V_TWO.": "#V_ONE战略配备的冷却时间暂时延长#V_TWO。", + "METEOR STORMS": "流星风暴", + "CAMPAIGN STATUS": "战役状态", + "#GRADE (#PERCENT%)": "#GRADE (#PERCENT%)", + "GALACTIC WAR UPDATE": "星系战争更新", + "Cooldown period decrease for #V_ONE stratagem no longer in effect.": "#V_ONE战略配备冷却时间缩短的效果结束。", + "Watch: A Helldiver Returns To His Robo-Canine Partner After 4-year Deployment.": "观察:绝地潜兵执行任务4年终于回到机器狗伴侣身边", + "A frozen world covered in ice that is broken only by reddish rock and spongy moss.": "冰天雪地的寒冷星球,间或可见浅红色的岩石与海绵般的苔藓。", + "PLANET": "星球", + "#V_ONE stratagem is once again available (if purchased).": "#V_ONE战略配备再次供应(如已购买)。", + "Unlocks new discoverable samples and enemy types.": "解锁全新可供探索的样本和敌人类型。", + "Number of uses of #V_ONE stratagem increased by #V_TWO.": "#V_ONE战略配备的可用次数增加#V_TWO。", + "The MG-43 Machine Gun stratagem is temporarily available to all Helldivers.": "“MG-43机枪”战略配备可暂时供所有绝地潜兵使用。", + "EMPTY SLOT": "空槽", + "Dense sandstorms reduce visibility.": "铺天盖地的沙暴会降低能见度。", + "Ministry of Science Officials Identify Unprecedented Mass Production Technology in Use by Automatons.": "科学部官员发现机器人在使用前所未见的量产技术", + "Surveying unexplained spacetime fluctuations": "勘测无法解释的时空波动", + "OPERATION FAILED": "行动失败", + "Receiving Geodetic Data...": "正在接收大地测量数据……", + "Stim capacity for all Helldivers increased by #V_ONE on all planets.": "所有星球上的所有绝地潜兵的治疗剂容量增加#V_ONE。", + "New Study Finds Patriotism To Be ##1 Predictor Of Happiness, Longevity, Weight Loss.": "最新研究发现爱国情怀是幸福、长寿和减肥的首要前提", + "Proximity to Source Planet": "靠近源头星球", + "The Source planet holds a unique and unknowable structural role in the Void space. Deal with the Source planet to return the abducted planets to where they belong and expel this Void region from the galaxy.": "源头星球在寂域中扮演着独特而又难以解明的结构性作用。妥善处理源头星球,就能让遭到劫持的星球重返原位,彻底抹除这片寂域,还银河系一片清朗。", + "Dense, toxic fumes from deep within the planet's crust seep out of cracks in the earth and coat the ground in a sickly haze.": "这颗星球地壳深处的有毒浓烟透过地表的裂隙渗透出来,形成了令人作呕的雾霾。", + "\"Enter Now for a Chance to Win Front-Row Tickets to The Freedomball Galactic Cup!\"": "立刻参加即有机会获得自由球星系杯比赛前排门票!", + "Melee damage is temporarily increased by #V_ONE%.": "近战伤害暂时提高#V_ONE%。", + "CIVILIANS & SEAF IN AREA": "区域内有平民和超级地球武装部队", + "SEAF REINFORCEMENTS": "超级地球武装部队的增援", + "LOW RECRUITMENT": "一卒难求", + "#PLANET CITIES": "#PLANET城市", + "Primary Objectives": "主要目标", + "Automatons \"No Match\" for Helldivers, Says Ministry of Defense Official.": "国防部官员称机器人“完全不敌”绝地潜兵", + "Tesla Tower stratagem availability has ended.": "现已无法使用“特斯拉塔”战略配备。", + "Personal Orders are completed by Helldivers individually, and change every day in response to the shifting battlefield.": "个人指令由绝地潜兵单独完成,而且每天都会根据战场局势而改变。", + "HOLD FOR PLANET TRANSIT": "长按开始星际传输", + "Cooldown period for #V_ONE stratagem increased by #V_TWO.": "#V_ONE战略配备的冷却时间延长#V_TWO。", + "Medal payout per mission for all Helldivers increased by #V_ONE.": "所有绝地潜兵每次任务的奖章收益增加#V_ONE。", + "Completing this Operation helps hold this city. Successfully holding cities significantly contributes to the planet's Defense.": "完成此次行动有助于保卫这座城市。成功保卫城市将大幅推动星球防御进程。", + "OPERATION SUCCESSFUL": "行动成功", + "VERY HIGH": "极高", + "EXPLOSIVES SURPLUS": "爆炸品过剩", + "Automaton Sympathizers Killed in Breathtaking Raid; Collateral Damage Heroically Minimized.": "星系大突查,同情机器之人消灭无数;潜兵好英勇,连带伤害微乎其微", + "E-711 is only found on Hive Worlds. The exotic substance is critical to the maintenance of galactic security. It must be secured, no matter the risk.": "711元素只能在虫窝世界里找到。这种异域物质对维持银河系的安全非常关键。无论风险多大,都必须确保拿到这些资源。", + "Falling sand reduces visibility.": "沙尘从天而降会降低能见度。", + "OFFENSIVE ADVANTAGE": "进攻优势", + "To Any Citizen Who's Lost a Home Thanks to Enemy Activity, We Say:": "如果你的家园毁于敌人手中,没有关系", + "HIGH RECRUITMENT": "广纳千军", + "Tactical Map Disrupted": "战术地图受到干扰。", + "LEVIATHAN BLOCKADE": "利维坦封锁屏障", + "SUDDEN SPAWNING": "幼虫孵化激增", + "CHALLENGING": "充满挑战", + "Enemy Strongholds": "敌方要塞", + "Planet #V_ONE, on the verge of falling to the enemy, has been successfully defended.": "我们成功守住了濒临沦陷的#V_ONE星球。", + "Super Earth will not liberate Recon campaign planets, but they will remain available as long as the sector is active.": "超级地球不会解放侦察战役中的星球,但只要该分区坚持反抗,这些星球就仍有希望。", + "The Ballistic Shield Backpack stratagem is temporarily available to all Helldivers.": "“防弹护盾背包”战略配备可暂时供所有绝地潜兵使用。", + "CITY": "城市", + "MEDICAL SUPPLY STRAIN": "医疗补给紧张", + "Brief But Totally Not Worrying Illuminate Brain Takeover": "所幸时间较短,不足为虑", + "Time to complete all missions increased by #V_ONE%.": "完成所有任务的时间延长#V_ONE%。", + "Operation Valiant Enclosure Proceeding \"As Expected\" According to MOD Report.": "国防部报告称英勇围合行动“如期”推进", + "FRIENDS: #VALUE": "好友:#VALUE", + "Tactical Objectives Increase": "战术目标增加", + "The Helldivers must liberate this planet before time runs out. Failure will have severe consequences.": "绝地潜兵必须在时间结束前解放这颗星球。如果失败,后果将不堪设想。", + "Unknown Name": "未知名称", + "Melee damage increase no longer in effect.": "近战伤害提高的效果结束。", + "New Study Shows Illuminate Terror Lurks Around Every Corner And Citizens Can Never Be Too Vigilant.": "最新研究表明光能者的威胁无处不在,星系公民应当格外警惕", + "#V_ONE Booster is automatically active for all missions.": "#V_ONE强化资源在全部任务中自动激活。", + "Number of stims each Helldiver deploys with decreased by #V_ONE.": "每位绝地潜兵上阵时配给的治疗剂数量减少#V_ONE。", + "HARD": "困难", + "ILLUMINATE INVASION": "光能者入侵", + "HIDE HEROES OF SUPER EARTH": "隐藏超级地球英雄", + "Unexpected SEAF reinforcements have taken significant ground on Planet #V_ONE.": "意料之外的超级地球武装部队增援力量在#V_ONE星球上占领了重要阵地。", + "#V_ONE stratagem is temporarily unavailable to all Helldivers.": "所有绝地潜兵暂时都不能使用#V_ONE战略配备。", + "Extraction time reduction no longer in effect.": "撤离时间缩短的效果结束。", + "LOW": "低", + "Orbital Airburst Strike stratagem availability has ended.": "现已无法使用“轨道空爆攻击”战略配备。", + "The Eagle Airstrike stratagem is temporarily available to all Helldivers.": "“‘飞鹰’空袭”战略配备可暂时供所有绝地潜兵使用。", + "The strange subversion of photosynthesis that sustains the oddly-hued flora that flourishes on this planet remains an intriguing mystery to Super Earth's greatest exo-biologists.": "这颗星球颠覆性的神奇光合作用是如何让这里色调奇特的植物群维持生长?超级地球最出色的外星生物学家至今仍未解开此谜团。", + "Causes Element 710 Rain Over HydroFall Prime": "致710元素洒遍水瀑主星", + "INCOMING MESSAGE FROM SUPER EARTH": "来自超级地球的信息", + "Mobilized in:": "动员倒计时:", + "#V_ONE effectiveness increase no longer in effect.": "不再提升#V_ONE的效果。", + "#SECTOR": "#SECTOR", + "SUCCESS": "成功", + "Periods of high temperatures increase stamina drain and speed up heat buildup in weapons.": "酷热时段会增加耐力消耗,也会加快武器升温速度。", + "Stim capacity for all Helldivers decreased by #V_ONE on this planet.": "在此星球上的所有绝地潜兵的治疗剂容量减少#V_ONE。", + "GLOOM RESEARCH PROGRESS": "“阴霾”研究进展", + "Legion": "军团", + "FORCES IN RESERVE": "预备部队", + "Number of reinforcements available per mission is temporarily increased by #V_ONE.": "每次任务的可用增援数暂时增加#V_ONE。", + "E-711 EXTRACTED": "已提取的711元素", + "Eagle Airstrike stratagem availability has ended.": "现已无法使用“‘飞鹰’空袭”战略配备。", + "Destroy": "摧毁", + "Cyborgs are deployed to the battlefield of this planet, leading their Automaton armies. Expect to encounter vile propagandists trained in both ranged and melee combat.": "生化人已部署至该星球战场,率领机器人大军作战。请做好准备,应对经过远近战双重训练的卑劣宣传机器。", + "ATMOSPHERIC STERILIZATION": "大气灭菌", + "HIGHER STIM CAPACITY": "更大治疗剂容量", + "Though the nearby Gloom Base provides logistical support, the spore cover on this planet is heavy enough to cause issues for all landing Pelicans.\nExtraction times are increased by 20 seconds.": "虽然附近的“阴霾”基地能够提供后勤支援,但这颗星球上的孢子密度过高,令所有的“鹈鹕”难以降落。\n撤离时间延长20秒。", + "SEAF UNITS IN AREA": "区域内有超级地球武装部队", + "SUPPLY CHAIN CHALLENGES": "补给链挑战", + "OPERATIONAL VARIATIONS": "行动变量", + "This once-beautiful planet has been twisted into a hive of tyranny, corrupted beyond recognition by the ravenous spread of the Terminids.": "这颗曾经美丽的星球被扭曲为暴政的巢穴,在终结族的贪婪扩张下面目全非。", + "ESTIMATED TO FALL IN": "预计沦陷时间:", + "Time to complete all missions is temporarily reduced by #V_ONE%.": "完成所有任务的时间暂时缩减#V_ONE%。", + "Reinforcement reduction is no longer in effect.": "可用增援数减少的效果结束。", + "Spacetime Fluctuation Indicator": "时空波动指示器", + "Grenade increase no longer in effect.": "榴弹数量增加的效果结束。", + "Daredevil Felix Bressler Freefalls 2.8 Billion Miles From Neptune to Super Earth": "冒险勇士菲力克斯·布莱斯勒从海王星到超级地球自由落体28亿英里", + "TRACKING: ACTIVE HELLDIVER SQUADS": "正在追踪: 正在行动的绝地潜兵小队", + "Submerged in eternal winter, this world's frosty peaks glimmer in the light of its too-distant star.": "这颗星球处于永恒的寒冬之中。星球上冰冷的山峰隐约反射着遥不可及的恒星之光。", + "OPERATIONAL SUPPORT": "行动支持", + "Light Outposts": "轻型哨站", + "Experience gain decrease no longer in effect.": "经验值减少的效果结束。", + "Orbital Railcannon stratagem availability has ended.": "现已无法使用“轨道炮”战略配备。", + "Number of magazines Helldivers deploy with for all weapons increased by #V_ONE.": "绝地潜兵上阵时配给的所有武器弹匣数量增加#V_ONE。", + "ACQUIRED E-711": "已获取711元素", + "SHOW ORDERS": "显示指令", + "The Mortar Sentry stratagem is temporarily available to all Helldivers.": "“迫击哨戒炮”战略配备可暂时供所有绝地潜兵使用。", + "EXPERIMENTAL BOOSTER": "实验性强化资源", + "Evacuated in:": "撤离倒计时:", + "The presence of the DSS near this planet provides a -35% cooldown reduction to all Exosuit stratagems.": "DSS停靠在这颗星球附近,可使所有外骨骼装甲战略配备冷却时间缩短35%。", + "The LAS-98 Laser Cannon stratagem is temporarily available to all Helldivers.": "“LAS-98激光大炮”战略配备可暂时供所有绝地潜兵使用。", + "REV PERIOD: #VALUE YEARS": "公转周期: #VALUE年", + "ENEMY THREAT DETECTED": "侦测发现敌方威胁", + "RECON CAMPAIGN PROGRESS": "侦察战役进度", + "HONOR THE FALLEN": "缅怀烈士", + "LIBERATION EVENT PROGRESS": "解放战役进度", + "GRENADE POUCH SHORTAGE": "榴弹袋短缺", + "Enemies Killed": "击败敌人数", + "Extraction time against the Terminids is #V_ONE seconds slower.": "对阵终结族时的撤离时间减慢#V_ONE秒。", + "The pure fountain from which Managed Democracy springs forth. It must be defended at all costs.": "孕育出管理式民主之花的沃土。必须不计代价保卫其存续。", + "Local Overseer of Mine 306.7D Found Dead in Sizzle-Fish Smuggling Incident.": "嗞啦鱼走私事件306.7D矿井矿长身亡", + "Flying Leviathan warships patrol the battlefield.": "战场上空有利维坦战舰在巡逻。", + "Dissident Sabotage Blamed For Spike In Aluminum Prices": "异见分子大搞破坏致使铝价飙升", + "ENEMIES KILLED: #VALUE": "杀敌数:#VALUE", + "SAR-1 Sniper Rifle stratagem availability has ended.": "现已无法使用“SAR-1狙击步枪”战略配备。", + "COMBATANT FORCES PRESENT": "存在武装力量", + "PERSONAL ORDER": "个人指令", + "Stratagem cooldown increased by #V_ONE%.": "战略配备的冷却时间增加#V_ONE%。", + "New Study Concludes Male Pattern Baldness a Patriotic Sign of Hair's Freedom to Leave Head.": "最新研究发现男性脱发系头发自由脱离头部的爱国表现", + "Season Premiere of \"Surviving the Galactic\" Strands 18 Citizens on Kryx's Ice Moon For 39 Days": "《星系求生》本季首播导致18名公民滞留克里克斯冰质卫星39天", + "The presence of the Void cuts off communication with your Destroyer.": "由于寂域的存在,我们无法与你的驱逐舰建立通讯。", + "The oases that bespeckle this desert planet present the closest approximation of tranquility one can find this far from Super Earth.": "在这颗沙漠星球上,只有零星点缀的绿洲能让人回想起远方的超级地球,获得片刻宁静。", + "Objective locations are hidden.": "隐藏目标地点。", + "Stratagem slots reduced by #V_ONE.": "减少#V_ONE个战略配备槽位。", + "MEDICAL SUPPLY SURPLUS": "医疗补给过剩", + "RAINSTORMS": "暴雨", + "Completing this operation has an impact on the Illuminate Fleet Strength.": "完成此次行动将影响光能者舰队战力。", + "Complete operations in #SECTOR": "在#SECTOR完成行动", + "LESS BATTLEFIELD AMMO": "战场弹药减少", + "An operation is a collection of missions. Complete all missions to succeed with an operation and gain bonus rewards. Failing one mission will fail the rest of the operation.": "行动包含一系列任务。完成所有任务即表示行动成功,你将获得额外奖励。只要一项任务失败,此次行动就算失败。", + "HIGH-PRIORITY CAMPAIGN": "首要战役", + "The FLAM-40 Flamethrower stratagem is temporarily available to all Helldivers.": "“FLAM-40火焰喷射器”战略配备可暂时供所有绝地潜兵使用。", + "The Orbital Walking Barrage is experimentally modified to have smoke rounds mixed into its salvos.": "轨道游走火力网经实验性调整,在齐射弹中混入了烟幕弹。", + "Until further notice, all Helldivers will passively regenerate health at a rate of #V_ONE% per second.": "所有绝地潜兵暂时以每秒#V_ONE%的速度被动恢复生命值,直至另行通知为止。", + "SUICIDE MISSION": "玩命任务", + "Automatons Invasion Force Constitutes \"Grave Threat\" to Super Earth.": "机器人侵略军“严重威胁”超级地球", + "New Poll Ranks Erson Sands As Best Place To Raise Kids To Be Defenders Of Freedom.": "最新民调结果显示厄尔森桑兹星系最适合家长培养自由卫士", + "For the near future, each successful mission will contribute more to planetary liberation.": "近期内,每一次成功完成任务都将为行星解放事业带来更大的助力。", + "On this planet, a network of Termicide-dispensing towers repels Terminids emerging from the Gloom.": "在这颗星球上,喷洒灭虫终结剂的高塔网络抵御着源自“阴霾”的终结族。", + "For the near future, ground will be passively re-gained on Planet #V_ONE.": "近期内,我们将被动夺回#V_ONE星球的阵地。", + "to": "to", + "Automaton Invasion Shows No Signs Of Losing Steam.": "机器人侵略尚无止步迹象", + "ILLUMINATE INVASION PROGRESS": "光能者入侵进度", + "Protect": "保护", + "EXPERIMENTAL HIP POUCHES": "实验性腰包", + "Orbital Walking Barrage stratagem availability has ended.": "现已无法使用“轨道游走火力网”战略配备。", + "Defense Campaigns cannot originate from this planet.": "此星球无法发起保卫战役。", + "HIGH": "高", + "Abundant with life, this wet planet is covered in deep oceans, thick forests, and tall grasses.": "这颗湿润的星球既有深海,也有郁郁葱葱的森林和草原,充满了生命的气息。", + "MORE BATTLEFIELD AMMO": "战场弹药增加", + "GLARBLE GARB GORK! News Headline Writer Experiences": "叽里呱啦噜!光能者入侵新闻头条写手大脑", + "MAJOR ORDER": "重要指令", + "Grenade capacity for all Helldivers is temporarily decreased by #V_ONE.": "所有绝地潜兵的榴弹容量暂时减少#V_ONE。", + "Orbital Precision Strike stratagem availability has ended.": "现已无法使用“轨道精准攻击”战略配备。", + "ROT PERIOD: #VALUE DAYS": "自转周期: #VALUE天", + "EXPERIMENTAL VITAMINS": "实验性维他命", + "Helldivers Continue Valiant Fight To Contain Terminids.": "绝地潜兵仍在英勇遏制终结族", + "The main invasion fleet of the Illuminate, from arrogant Overseers to throngs of brainwashed Super Earth civilians, are present on this planet. Exterminate on sight or else risk violent resistance, or worse, treasonous propaganda.": "光能者主力入侵舰队已降临该星球,既有傲慢的监视者,也有成群结对、遭到洗脑的超级地球公民。一旦发现,立即击杀,否则将面临暴力的抵抗,甚至遭遇叛国宣传。", + "TCS INSTALLATION PROGRESS": "TCS建设进度", + "This planet is under attack. The Helldivers must defend it against the forces of tyranny.": "这颗星球遇袭。绝地潜兵必须保卫星球,抵御暴政军队。", + "Helldivers Ordered to Prepare Terminid Cordon Planets for \"Purge\".": "绝地潜兵奉命准备“净化”部署终结族封锁线的星球", + "New Poll Ranks Terminids As \"Most Buglike\" Of Super Earth's Enemies.": "最新民调结果显示大众认为终结族是超级地球“最像虫子”的敌人", + "Gloom particles interfere with landing Pelicans, increasing extraction times by 20 seconds.": "“阴霾”粒子干扰“鹈鹕”运输机着陆,撤离时间延长20秒。", + "SURGE PRODUCTION": "机械产量激增", + "Intense snowstorms reduce visibility.": "强暴风雪会降低能见度。", + "CLASS 2 MEGAFACTORY": "2级超大型工厂", + "Intense blizzards reduce mobility and moderately reduce visibility for both enemy and friendly units.": "强暴风雪会削弱行动能力并中度降低能见度,敌我双方都将受影响。", + "DRAGONROACHES": "蟑龙", + "DEFENSE CAMPAIGN": "保卫战役", + "VOLCANIC ACTIVITY": "火山活动", + "MEGAFACTORY OPERATION": "超大型工厂行动", + "LIBERATION UNDERWAY": "解放进行时", + "ORDER OVERVIEW": "指令概览", + "Extraction time on this planet is #V_ONE seconds faster on this planet.": "在此星球上的撤离时间加快#V_ONE秒。", + "Depending on the war progress, different planets will be available. Select a planet to see what operations are active on it.": "可参与行动的星球会随战争局势而变。选择一颗星球,看看上面正在部署哪些行动。", + "FIELD PROMOTIONS": "战地晋升", + "Democratize": "民主解放", + "The DSS activates its highly experimental Atmospheric Autoclave, killing 50 km³ of Gloom Spores per minute. The reduced spore cover exposes photosensitive Terminid variants to atmospheric UV radiation.": "DSS启动仍在实验阶段的大气高压灭菌器,每分钟可消灭50立方千米的“阴霾”孢子。孢子层减少,使部分对光敏感的终结族亚种暴露在大气紫外线辐射下。", + "The TS-4 Arc Thrower stratagem is temporarily available to all Helldivers.": "“ARC-3电弧发射器”战略配备可暂时供所有绝地潜兵使用。", + "Unexpected SEAF reinforcements are taking significant ground on Planet #V_ONE.": "意料之外的超级地球武装部队增援力量正在#V_ONE星球上占领重要阵地。", + "BATTLE ROYALE: Bugs vs. Automatons": "绝地乱斗:虫族对机器人", + "The Illuminate are deploying only their own kind to this planet, a clear indication of the operation's importance and/or xenophobic nature. Prepare to face foot soldiers, drones, and piloted mechanical constructs.": "光能者部署在这颗星球上的只有同族,这抑或说明此次行动至关重要,抑或暴露出他们排外的本性。准备迎击他们的步兵、无人机以及操作型机械体。", + "Allied SEAF units are operating on the battlefield.": "超级地球武装部队友军正在战场上作战。", + "PROTEIN SHORTAGE": "缺乏蛋白质", + "ILLUMINATE CONTROL": "由光能者控制", + "COMPLEX STRATAGEM PLOTTING": "复杂的战略配备部署流程", + "Temporary stim increase no longer in effect.": "治疗剂数量临时增加的效果结束。", + "New Study Finds Super Eagle to be Most Democratic Bird.": "最新研究发现超级雕为最民主的鸟类", + "INSPIRED LABORERS": "劳动者觉醒", + "TERMINID CONTROL": "由终结族控制", + "LAS-98 Laser Cannon stratagem availability has ended.": "现已无法使用“LAS-98激光大炮”战略配备。", + "Number of uses of #V_ONE stratagem is temporarily reduced by #V_TWO.": "#V_ONE战略配备的可用次数暂时减少#V_TWO。", + "Constant eruptions keep this planet covered in lava flows and utterly inhospitable to Democratic life. It also makes it a treasure trove of rare minerals.": "火山持续喷发,导致这颗星球被熔岩流覆盖,完全不适宜民主生命居住。但这里也因此成为稀有矿物的宝库。", + "Extraction time temporarily decreased by #V_TWO seconds.": "撤离时间暂时缩短#V_TWO秒。", + "Each successful mission contributes more to planetary liberation.": "每一次成功完成任务都会为行星解放事业带来更大的助力。", + "Dense fog reduces visibility.": "浓雾会降低能见度。", + "Child Finds Toy Battleship She Lost In Black Hole 6 Years From Now.": "儿童发现自己6年后无意落入黑洞的玩具战舰", + "Secondary Objectives": "次要目标", + "VOID GATEWAY": "寂域通路", + "Cyberstan Identified as Center of Automaton Command.": "已发现生化斯坦是机器人指挥中枢", + "HIVE LORDS": "霸王虫", + "#SHORT - #LONG": "#SHORT - #LONG", + "Eagle Rearm time is #V_ONE% slower.": "重新武装“飞鹰”的时间减慢#V_ONE%。", + "FINAL CHARGE": "力挽狂澜", + "Multiple citizens report having same dream of unseen tentacled mass lurking in shadowy depths": "多名平民报告称做了同一个梦:在幽暗的深处,潜伏着一团看不见的触手状巨物。", + "COLONY OPERATION REWARD": "拓殖地行动奖励", + "Grenade capacity for all Helldivers decreased by #V_ONE.": "所有绝地潜兵的榴弹容量减少#V_ONE。", + "Execution By Black Hole Spaghettification Ruled Constitutional": "最高法院判黑洞面条化死刑符合宪法", + "Extraction time on this planet is #V_ONE seconds slower on this planet.": "在此星球上的撤离时间减慢#V_ONE秒。", + "PLANET EVENTS": "星球战事", + "Flying Shrieker swarms traverse the battlefield.": "飞空尖啸虫群会穿过战场。", + "OPERATION REWARD": "行动奖励", + "The Orbital 120mm HE Barrage is experimentally modified with additional HE rounds, EMS rounds, and a tighter radius.": "轨道120mm高爆弹火力网经实验性调整,增加了额外高爆弹与电磁电磁冲击弹,并缩小了效果范围半径。", + "Grenade decrease no longer in effect.": "榴弹数量减少的效果结束。", + "Progress in Liberation Campaigns is accelerated.": "在解放战役中的进展加速。", + "Major Orders represent the goals of the Helldiver Community.": "重要指令是绝地潜兵社区的共同目标。", + "Exterminate": "消灭", + "An unanticipated Terminid surge has taken significant ground on Planet #V_ONE.": "突如其来的终结族激增势力在#V_ONE星球上占领了重要阵地。", + "Student Group Carries Out Public Deletion of Undemocratic E-Books": "学生团体开展公共活动,当众删除非民主电子书籍", + "LIBERTY DAY CELEBRATION": "解放日庆典", + "EXTREME COLD": "极寒", + "HELLPODS ACTIVE - PROCEED TO HELLPODS": "绝地喷射舱已启动 - 前往绝地喷射舱", + "#V_ONE stratagem availability has ended.": "现已无法使用#V_ONE战略配备。", + "SUPER EARTH CONTROL": "由超级地球控制", + "AT-48 Recoilless Rifle stratagem availability has ended.": "现已无法使用“AT-48无后坐力步枪”战略配备。", + "A rocky, lonely moon with extremely valuable mineral deposits underneath the surface.": "崎岖不平的孤单卫星,地下埋着极其珍贵的矿产。", + "Defense Wall stratagem availability has ended.": "现已无法使用“防御墙”战略配备。", + "Experience gain for all Helldivers reduced by #V_ONE%.": "所有绝地潜兵获得的经验值减少#V_ONE%。", + "Cooldown period for #V_ONE stratagem is temporarily reduced by #V_TWO.": "#V_ONE战略配备的冷却时间暂时缩短#V_TWO。", + "Effects are temporary alterations to battlefield conditions. They change as the war develops, and may force Helldivers to adapt their tactics.": "效果是因应战场状况临时变更的条件,会随着战争局势的发展而变化,可能迫使绝地潜兵调整战术。", + "Ground will no longer be passively re-gained on Planet #V_ONE.": "我们不再被动夺回#V_ONE星球的阵地。", + "Orbital Laser stratagem availability has ended.": "现已无法使用“轨道激光炮”战略配备。", + "Extraction time against the Terminids is #V_ONE seconds faster.": "对阵终结族时的撤离时间加快#V_ONE秒。", + "MEGA CITY": "特大城市", + "KIA: #VALUE": "阵亡:#VALUE", + "COLONY OPERATION": "拓殖地行动", + "ENEMY FORCE": "敌方势力", + "Melee damage increased by #V_ONE%.": "近战伤害提高#V_ONE%。", + "Geneticist Killed In Home By Chicken-Cow-Pig Hybrid.": "基因研究人员家中惨遭鸡牛猪杂交生物杀害", + "HEAVY GLOOM SHROUD": "重度“阴霾”笼罩", + "Experience gain increase no longer in effect.": "经验值增加的效果结束。", + "Frequent earthquakes stun players and enemies alike.": "频繁的地震会让玩家和敌人都陷入眩晕。", + "GL-6 Grenade Launcher stratagem availability has ended.": "现已无法使用“GL-6榴弹发射器”战略配备。", + "Super Earth, our home, is the center of Liberty Day Festivities. Together, all citizens can watch on television the annual Defense Parade, the Justice Executions, and of course, the Freedom Fireworks. \n\nOn this special day, Helldivers are encouraged to visit Super Earth and watch this year's fireworks from their Super Destroyers.": "超级地球,我们的家园,是解放日庆典的中心。所有公民都能在电视上观看年度阅兵、正义裁决,当然还有自由烟花秀。\n\n在这特别的日子里,所有绝地潜兵都可以前往超级地球,并在自己的驱逐舰上观看今年的烟花秀。", + "This world teems with ethereal, boundless, and peculiar plant life that spreads silent and uninterrupted across its entire surface.": "这颗星球表面布满了缥缈、奇特的植物,营造出无限蔓延的静谧感。", + "vs. Genetically-Altered Giant Turtles. Tickets on Sale!": "对基因改造的巨龟。门票特惠,售完即止!", + "CLASS 1 MEGAFACTORY": "1级超大型工厂", + "MERITORIOUS COMMENDATIONS": "论功行赏", + "Geneticists Create First Chicken-Cow-Pig Hybrid, Dubbed \"Perfect Meat.\"": "基因研究人员成功培育首个鸡牛猪杂交生物,冠名”完美肉”", + "Effectiveness of #V_ONE increased by #V_TWO%.": "#V_ONE的效果提升#V_TWO%。", + "SEAF units and loyal civilians are both on the battlefield.": "战场上同时发现超级地球武装部队和忠诚平民。", + "the": "the", + "Rocket Sentry stratagem availability has ended.": "现已无法使用“火箭哨戒炮”战略配备。", + "DIFFICULTY LEVEL LOCKED": "难度未解锁", + "MULTIPLE THREATS DETECTED": "侦测发现多个威胁", + "BACK TO GALAXY MAP": "返回星系地图", + "Stop": "制止", + "LAT: #VALUE": "纬度: #VALUE", + "TANK SURGE": "坦克激增", + "The Illuminate are moving the Meridian Singularity toward Super Earth. Anything caught in its path will be torn apart.": "光能者正将默里迪恩奇点移至超级地球。任何挡在其移动轨迹上的东西都将被摧毁。", + "Time to complete all missions reduced by #V_ONE%.": "完成所有任务的时间缩减#V_ONE%。", + "PLANET LOST - RETREAT ORDER ISSUED": "星球沦陷 - 下令撤退", + "Anti-Personnel Mine Deployer stratagem availability has ended.": "现已无法使用“反步兵地雷部署器”战略配备。", + "ANOMALY LOCATION": "异常地点", + "TOWN": "城镇", + "New Bill Funds Dissident Identification Training For Schoolteachers": "新法案出资开展在校教师异见分子甄别培训", + "Number of reinforcements available per mission increased by #V_ONE.": "每次任务的可用增援数增加#V_ONE。", + "Resupply stratagem availability has ended.": "现已无法使用“重新补给”战略配备。", + "New Study Proves 100% of Super Earth Studies to be Accurate.": "最新研究证实超级地球所有研究结果100%准确", + "Schrödinger's Cat Definitively Determined Dead Following": "核武器试验成功,薛定谔的猫", + "PLANET STATUS UPDATING": "星球状态正在更新", + "Completing this operation contributes to the planet's Defense.": "完成此次行动将推动星球防御进程。", + "#A / #B": "#A / #B", + "LEAVE HOLOGRAM": "退出全息图像", + "Terminid Hive Lords have been detected on this planet. Prepare to face massive burrowing enemies.": "已在这颗星球上探测到终结族的霸王虫。请做好应对巨型钻地敌军的准备。", + "Conquer #PLANET in the #SECTOR": "征服#SECTOR的#PLANET", + "SOURCE PLANET": "源头星球", + "Terminids Threaten To Break Free of Cordon.": "终结族威胁或突破封锁线", + "Planet is ravaged by deadly fire tornados.": "致命的烈焰龙卷在星球上肆虐。", + "NEWS ALERT": "重大新闻", + "Terminid Detterance Network Installation Heavily Delayed by Terminid Swarm Event.": "终结族虫群活动严重阻碍终结族威慑网建设", + "New Study Finds Bots Twice as Authoritarian as Previously Expected.": "最新研究发现机器社会专制程度为此前预期的两倍之多", + "The substance known as E-711 is the key to synthesizing Dark Fluid, an immensely powerful exotic material. Acquiring it is of utmost importance.": "711元素是极其强大的异域物质,也是合成暗液体的关键成分。获取这些元素至关重要。", + "ELECTRONIC COUNTERMEASURES": "电子对抗", + "Health regeneration no longer in effect.": "恢复生命值的效果结束。", + "A crimson algae has propagated wildly across this entire planet, coating its rocky hills with a constant red that masks the spilt blood of the heroes who defend it from tyranny.": "一种深红色的藻类在这颗星球大肆繁殖,嶙峋峭壁也通通被染红,掩盖了抵抗暴政的英雄在此洒下的热血。", + "HELLDIVE": "绝境", + "Number of reinforcements available per mission decreased by #V_ONE.": "每次任务的可用增援数减少#V_ONE。", + "BRIEF": "简报", + "Scorching temperatures, high winds, and low precipitation cause a near-constant cycle of fires to sweep this planet, punctuated by short bursts of lush rebirth between infernos.": "酷热、强风和稀少的降水导致席卷这颗星球的烈火灾害几乎从未间断,茂密复生的绿色植被在这个炼狱里只有极其短暂的喘息之机。", + "SHOW HEROES OF SUPER EARTH": "显示超级地球英雄", + "SEAF COUNTEROFFENSIVE": "超级地球武装部队的反攻", + "Children's Hospital Explosion Linked to Automaton Sympathizer Group \"Innominate.\"": "儿童医院发生爆炸,事件与亲机器人组织“无名”存在关联", + "Highly Anticipated Battle of Malavax Prime To Be Broadcast Live - Buy Tickets Here.": "万众期待的马拉瓦克斯主星战役现场直播,门票此处购买", + "VERY HARD": "极难", + "INDIRECT FIRE EXERCISE": "间接火力演练", + "#TEXT": "#TEXT", + "Defend against #COUNT attacks in the #SECTOR": "在#SECTOR抵御#COUNT次袭击", + "": "次数:", + "HERD THINNING": "削减虫群", + "in multiplayer": "模式:多人游戏", + "": "次数:", + "WEAPONS QUALIFICATION": "武器资质", + "#COUNT kills with turret stratagems": "利用炮台战略配备完成#COUNT次击杀", + "#SPEAKER #TEXT": "#SPEAKER #TEXT", + "LETHALITY REVIEW": "杀伤力鉴审", + "": "", + "War - #HOURS:#MINUTES:#SECONDS": "战争 - #HOURS:#MINUTES:#SECONDS", + "PILOT WEAPONS TRAINING": "飞行员武器训练", + "Outposts": "哨站", + "Career: Kill #COUNT enemies": "生涯:击杀#COUNT名敌人", + " times": "", + "#NAME Rank #COUNT": "#NAME 级别#COUNT", + " times": "", + "Defend #PLANET against #COUNT attacks by #RACE": "保卫#PLANET,击退#COUNT次#RACE的进攻。", + "DAILY ORDER": "日常指令", + "During a mission deplete #REF": "在一次任务中耗尽#REF", + "Repel #COUNT invasions by #RACE": "击退#COUNT#RACE的入侵。", + "Repel #COUNT Illuminate invasions on #PLANET": "在#PLANET上击退#COUNT次光能者的入侵", + "Request #REF stratagem #COUNT times": "请求#REF战略配备#COUNT次", + "Kill #COUNT heavy or massive enemies": "击杀#COUNT名重型武装或体型庞大的敌人", + "from the planet ": "星球:", + "FOCUSED STRATEGY": "重点战略", + "Play #COUNT #OBJ#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI.": "参与#COUNT次#OBJ。#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI", + "Enemy": "敌人", + "Community-Target Mission": "社区目标任务", + "Liberate #LOCATION": "解放#LOCATION", + "Achieve a #COUNT star rating on a Horde mission": "在一次群袭任务中达成#COUNT星评价", + "Detonate #COUNT Automaton Lieutenant fuel tanks": "引爆#COUNT个机器人中尉的燃料罐", + "or higher": "或以上", + "Get 10 kills with a single #REF #COUNT times": "仅使用#REF一次击杀10名敌人#COUNT次", + "Kill #COUNT Bug Striders": "击杀#COUNT只虫族的阔步虫", + "Complete a difficulty #COUNT or higher mission without taking any damage": "在没有受到任何伤害的情况下完成难度系数为#COUNT或以上的任务", + "RESEARCH INITIATIVE": "研究倡议", + "CAPABILITY DISRUPTION": "军事力量干扰", + "#COUNT kills with orbital stratagems": "利用轨道战略配备完成#COUNT次击杀", + "Weekly": "每周", + "on a planet controlled by the ": "星球势力:", + "Kill #COUNT Bug Alpha Chargers": "击杀#COUNT只虫族的领头强袭虫", + "Use #COUNT stratagems": "使用#COUNT次战略配备", + "Complete #COUNT difficulty 6+ missions": "完成#COUNT场难度系数为6以上的任务", + "Enemies": "敌人", + "Use #COUNT supply stratagems": "使用#COUNT次补给战略配备", + "Defend against #COUNT attacks on any planet": "在任意星球上抵御#COUNT次袭击", + "Use the #ITEM#COUNT_PRE#COUNT#COUNT_POST#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI.": "使用#ITEM。#COUNT_PRE#COUNT#COUNT_POST#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI", + "Kill #COUNT enemies with Hellpods": "利用绝地喷射舱击杀#COUNT名敌人", + "Hold #LOCATION when the order expires": "指令过期后,坚守#LOCATION", + "": "", + "on the planet ": "星球:", + "Use #COUNT orbital stratagems": "使用#COUNT次轨道战略配备", + "Complete an Operation#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST": "顺利完成行动。#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST", + "FORCED DECOMMISSIONING": "强制报废", + "Use #COUNT defensive stratagems": "使用#COUNT次防御战略配备", + "Personal Order": "个人指令", + "from any ": "星球势力:", + "Spend #COUNT Credits on stratagems": "为战略配备花费#COUNT货币", + "STRAIN CULLING": "斩草除根", + "PRIORITY MESSAGE FROM SUPER EARTH HIGH COMMAND": "来自超级地球最高指挥部的高优先级信息", + "Kill #COUNT enemies on a mission": "在一次任务中击杀#COUNT名敌人", + "Kill #COUNT enemies with Eagle stratagems": "利用“飞鹰”战略配备击杀#COUNT名敌人", + "Extract from a mission with at least #COUNT sample(s)": "从一次任务中携带至少#COUNT份样本撤离", + "Primary": "主要", + "Kill #COUNT #ENEMY#LOCATION_PRE#LOCATION#LOCATION_POST#EQUIP_PRE#EQUIP#EQUIP_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI": "击杀#COUNT个#ENEMY#LOCATION_PRE#LOCATION#LOCATION_POST#EQUIP_PRE#EQUIP#EQUIP_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI", + "Kill #COUNT enemies with a single magazine": "仅使用一个弹匣击杀#COUNT名敌人", + "Donate #GOAL #GEAR #GEARTYPE": "捐赠 #GOAL #GEAR #GEARTYPE", + "Progression": "进度", + "Defend against #COUNT attacks from #RACE": "抵御#RACE的#COUNT次袭击", + "Objectives": "目标", + "Get 4 kills with a single #REF #COUNT times": "仅使用#REF一次击杀4名敌人#COUNT次", + "Complete a difficulty #COUNT or higher mission without dying": "在无人阵亡的情况下完成难度系数为#COUNT或以上的任务", + "(personally)": "(独自)", + "Kill #COUNT enemies within 10 meters from you with the Eagle": "利用“飞鹰”击杀距离你10米内的#COUNT名敌人", + "Achieve a 'Supreme' rating on a difficulty #COUNT mission": "在难度系数为#COUNT的任务中获得“杰出”的评价", + "Destroy #COUNT Automaton Fabricators": "摧毁#COUNT个机器人构筑者", + "in multiplayer": "模式:多人游戏", + "Successfully complete #COUNT objectives on missions": "在任务中完成#COUNT个目标", + "ARMOR DESTRUCTION": "毁灭装甲", + "#COUNT times": "次数: #COUNT", + "General": "其他", + "Successfully extract#EXT_PRE#EXT#EXT_POST#COUNT_PRE#COUNT#COUNT_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI.": "成功撤离#EXT_PRE#EXT#EXT_POST#COUNT_PRE#COUNT#COUNT_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI", + "The Automatons have illegally occupied and mined Malevelon Creek for too long. The time has come to take it back.": "机器人非法占领和开采麦拉芬蒙河已久。是时候收复它了。", + "Destroy #COUNT Automaton Gunship thrusters": "摧毁#COUNT个机器人的炮舰推进器", + "using the ": "使用:", + "Outpost": "哨站", + "Complete the #OBJ Objective#COUNT_PRE#COUNT#COUNT_POST#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI.": "完成#OBJ目标。#COUNT_PRE#COUNT#COUNT_POST#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI", + "Complete an Operation#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST": "顺利完成行动。#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST", + "Liberate #COUNT planets": "解放#COUNT颗星球", + "Boosters": "强化资源", + "MASS SHUTDOWN": "大规模关停", + "Spend #COUNT Credits on weapons": "为武器花费#COUNT货币", + "Kill #COUNT flying enemies with support weapons": "利用支援武器击杀#COUNT名空中的敌人", + "#COUNT total kills with grenades": "利用榴弹总计完成#COUNT次击杀", + "Kill #COUNT enemies with Eagle stratagems during a single mission": "在单次任务中利用“飞鹰”战略配备击杀#COUNT名敌人", + "Complete a mission with #COUNT% accuracy": "以#COUNT%的命中率完成一次任务", + "TROPHY HUNT": "荣耀猎杀", + "Daily - #HOURS:#MINUTES:#SECONDS": "每日 - #HOURS:#MINUTES:#SECONDS", + "Kill #COUNT enemies using #REF": "利用#REF击杀#COUNT名敌人", + "Complete #COUNT#TYPE #OBJ#RACE_PRE#RACE#RACE_POST#MULTI.": "完成#COUNT个#TYPE#OBJ。#RACE_PRE#RACE#RACE_POST#MULTI", + "Extract from a successful #MTYPE#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST": "成功从#MTYPE撤离。#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST", + "on ": "难度:", + "Activate #COUNT #OBJ#RACE_PRE#RACE#RACE_POST#MULTI.": "启动#COUNT台#OBJ。#RACE_PRE#RACE#RACE_POST#MULTI", + "Defend #PLANET against #COUNT attacks": "保卫#PLANET,抵御#COUNT次袭击", + "Disarm #COUNT Automaton troops": "解除#COUNT支机器人军队的武装", + " controlled planet": "(任一星球)", + "Successfully extract with #COUNT #EQP_PRE#EQP#EQP_POST#EXT_PRE#EXT#EXT_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI.": "携带#COUNT个#EQP_PRE#EQP#EQP_POST成功撤离。#EXT_PRE#EXT#EXT_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI。", + "Liberate the designated planets.": "解放指定的星球。", + "Advance your PROGRESSION TRACK": "使进度条解锁更多进度", + "LANDMINE TESTING": "地雷测试", + "Repel #COUNT Illuminate invasions in the #SECTOR": "在#SECTOR击退#COUNT次光能者的入侵", + "Destroy #COUNT #OBJ#RACE_PRE#RACE#RACE_POST#MULTI.": "摧毁#COUNT次#OBJ。#RACE_PRE#RACE#RACE_POST#MULTI", + "Extract from a successful #MTYPE#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST": "成功从#MTYPE撤离。#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST", + "Liberate #COUNT planets from #RACE": "从#RACE手中解放#COUNT颗星球", + "Daily": "每日", + "Destroy #COUNT Automaton AA turrets with the Eagle": "利用“飞鹰”摧毁#COUNT台机器人的防空炮台", + "Defend #PLANET against #COUNT attacks from the #RACE": "保卫#PLANET,抵御#RACE的#COUNT次袭击", + "Kill #COUNT enemies with a single grenade": "仅使用一枚榴弹击杀#COUNT名敌人", + "Kill #COUNT enemies with a single orbital stratagem usage": "仅使用一次轨道战略配备击杀#COUNT名敌人", + "Fire #COUNT shots on a mission": "在一次任务中射击#COUNT次", + "Get #COUNT kills in 10 seconds": "10秒内完成#COUNT次击杀", + "on ": "位置:", + "Hold #COUNT planets in the #SECTOR sector when the order expires": "指令过期后,在#SECTOR守住#COUNT颗星球", + "Opportunity Mission": "机遇任务", + "MASS DECOMMISSIONING": "大规模报废", + "Liberate the designated planet.": "解放指定的星球。", + "Kill #COUNT Bug Shriekers": "击杀#COUNT只虫族的尖啸虫", + "Get #COUNT kills within 5 seconds of each other": "完成#COUNT次击杀,每次击杀间隔时间为5秒", + "in the ": "分区:", + "against ": "敌人:", + "PEST CONTROL": "害虫管制", + "Defend against #COUNT attacks from the #RACE in the #SECTOR": "在#SECTOR抵御#RACE的#COUNT次袭击", + "Spend #COUNT Credits on Eagle": "在“飞鹰”上花费#COUNT货币", + "CUTTING-EDGE RESEARCH": "尖端科研", + "Collect a total of #COUNT samples": "总计收集#COUNT份样本", + "#SPEAKER #TEXT": "#SPEAKER #TEXT", + "Fire a total of #COUNT shots": "总计射击#COUNT次", + "Liberate more planets than are lost during the order duration": "指令生效期间解放的星球数量超过沦陷的星球数量", + "Destroy #COUNT Bug Charger abdomens": "击毁#COUNT只虫族强袭虫的腹部", + "Headshot #COUNT Automaton Soldiers": "爆头击杀#COUNT个机器人士兵", + "Repel #COUNT Illuminate invasions": "击退#COUNT 次光能者的入侵", + "Achieve rank #COUNT": "达到级别#COUNT", + "Liberate more planets than are lost to #RACE during the order duration": "指令生效期间解放的星球数量超过沦陷在#RACE手中的星球数量", + "Designated planets must be under Super Earth control when order expires.": "指令计时结束之时,指定星球必须收归超级地球管辖。", + "Secondary": "次要", + "Objective": "目标", + "Destroy #COUNT Automaton Warlords": "摧毁#COUNT个机器人的军阀", + "Pop #COUNT Bug Scavengers": "射击#COUNT只虫族的食腐虫", + "Intelligence": "情报", + "Radar Wagons": "雷达车", + "INCREASE FOOTPRINT": "乘胜追击", + "Use at least #COUNT stratagems during a single mission": "在单次任务中至少使用#COUNT次战略配备", + "Liberate Malevelon Creek.": "解放麦拉芬蒙河。", + "The long arm of Justice": "法网恢恢", + "Complete a Hard difficulty mission or higher without anyone firing their primary or support weapon.": "在无人使用主武器或支援武器的情况下,完成一项难度为“困难”或以上的任务。", + "Complete Basic Training.": "完成基本训练。", + "Kill 100 enemies using fire damage during the same mission.": "在同一项任务中通过灼烧伤害击杀100名敌人。", + "The power of Democracy": "民主之力", + "Provide assisted reload for a teammate.": "辅助一名队友装填弹药。", + "Hold my primary, I'm going in!": "帮我拿着主武器,我要冲了!", + "Obtain all trophies of HELLDIVERS™ 2.": "获得《HELLDIVERS™ 2》的全部奖杯。", + "Samples are a diver's best friend": "样本是潜兵最好的伙伴", + "Fully operational": "火力全开", + "They don't call it Tacticool for nothin'": "“战术咖”并非浪得虚名", + "Customize your Helldiver with new cape, armor, and helmet.": "用新披肩、盔甲和头盔对你的绝地潜兵进行自定义。", + "Science is done by quantity": "科学以量取胜", + "Extract after the timer reaches zero.": "在倒计时归零后撤离。", + "Extract with at least 15 common samples.": "携带至少15份普通样本撤离。", + "Package of 1000 (750 + 250 bonus) Super Credits": "1000(750 + 额外250)超级货币包", + "Package of 2100 (1500 + 600 bonus) Super Credits": "2100(1500 + 额外600)超级货币包", + "Extract with at least 15 rare samples from a mission as a team.": "在一项任务中整个团队携带至少15份稀有样本撤离。", + "Package of 150 Super Credits": "150超级货币包", + "The taller they are...": "他们越高就…", + "Caught them by Supplies!": "物资出击!", + "Extractinating the Countryside": "开采乡村", + "Let's call it a draw": "就算平局吧", + "Ship it!": "赶紧送!", + "Quick Play": "快速进攻", + "Shoot off both arms on a Hulk and then extract while it's alive.": "射下巨型者的两只手臂,在它尚存活的时候撤离。", + "It's the only way to be sure...": "别无他选…", + "Have 6 orbital barrage stratagems in the same place at the same time.": "在同一地点同时部署6个轨道火力网战略配备。", + "Play 1 Bug Mission.": "参与1项虫族任务。", + "Package of 375 Super Credits": "375超级货币包", + "Complete a mission but fail to extract.": "完成任务,但撤离失败。", + "Reach max level on one ship module.": "一个舰船模块提升至最高级别。", + "Cool guys don't loo- AAAAH!": "真男人从不回头看…啊啊啊!", + "Stalking is illegal": "跟踪违法", + "Defeat a Bile Titan.": "击败一只吐酸泰坦。", + "Heal another player using stims.": "使用治疗剂治疗其他玩家。", + "Hot Potato!": "烫手山芋!", + "Get some!": "受死吧!", + "Complete at least 100 missions.": "完成至少100项任务。", + "Kill it with fire!": "烧死它!", + "Spread Managed Democracy": "散播管理式民主", + "Be injured in all limbs at the same time.": "四肢同时受伤。", + "Bug Stomper": "虫族克星", + "Super Citizen": "超级公民", + "Fire at least 150 rounds in one burst, killing at least 10 enemies.": "一次性连射至少150发弹药,击杀至少10名敌人。", + "Extract with a full squad on a Hard difficulty or more mission.": "在一项难度为“困难”或以上的任务中,与整支小队一起撤离。", + "Democracy ain't done with you yet": "民主大业还需要你的力量", + "Job's done!": "完成任务!", + "Promote Synergy": "倡导合作", + "While using a jump pack, knock yourself into a ragdoll state.": "使用喷射背包时,让自己陷入僵直状态。", + "Kill a Charger with a resupply pod.": "用重新补给舱消灭一只强袭虫。", + "The Epitome of Super Earth": "超级地球典范", + "Play at least 50 missions.": "参与至少50项任务。", + "Quick Play with friends": "与好友参与快速进攻", + "Upgrade all ship modules at least 1 level.": "将所有舰船模块提升至少1个等级。", + "Doing your part": "履行职责", + "Complete 10 tactical objectives.": "完成10个战术目标。", + "MACHINERY OF OPPRESSION": "铁腕威压", + "Hell Dive": "绝地俯冲", + "Start a quick play session with friends only": "仅与好友组队参与一场快速进攻", + "Complete a Stalker Hive tactical objective.": "完成追踪虫虫窝战术目标。", + "That which does not kill you...": "但凡杀不死你的…", + "Nothing is bigger than Freedom": "自由价更高", + "Machinery of Oppression": "铁腕威压", + "Hold My Liber-tea!": "尝尝我的解放威力!", + "Start a quick play session": "开始一场快速进攻", + "Kill 150 enemies during the same mission.": "在同一项任务中击杀150名敌人。", + "Play 1 Bot Mission.": "参与1项机器人任务。", + "Extractamundo!": "完全撤离!", + "Kill 25 enemies with one stratagem.": "利用一项战略配备击杀25名敌人。", + "Play a planet defense mission.": "参与1项星球保卫任务。", + "They mostly come at night...": "夜访异形…", + "Complete a full Extreme difficulty Blitz mission and extract in under 6 minutes.": "在6分钟内完成一项难度为“极端”的闪电战任务并撤离。", + "Bot Scrapper": "机器人克星", + "Gone in 360 seconds!": "致命360秒!", + "Complete a full Hard difficulty mission or higher without anyone firing their primary or support weapon.": "在无人使用主武器或支援武器的情况下,完成一项难度为“困难”或以上的任务。", + "Throw back a live grenade.": "掷回一颗已激活的榴弹。", + "The Real Deal": "动真格", + "Extract from a mission during nighttime.": "夜间从任务中撤离。", + "For the greater good!": "顾全大局!", + "Kill 5,000 enemies.": "击杀5000名敌人。", + "In the nick of time": "说时迟那时快", + "Complete an Extreme difficulty mission or higher without anyone dying.": "在无人死亡的情况下完成一项难度为“极端”或以上的任务。", + "Fly at least 25 meters from the shockwave of an explosion.": "飞至距离爆炸冲击波至少25米远的位置。", + "Eat This!": "接招!", + "Kill a target at a distance of over 100m.": "击杀一名100米外的目标。", + "Strapping young lad": "时空悍将", + "Defeat a Hulk.": "击败一只巨型者。", + "Kill a bug warrior with a shotgun within 1 meter.": "使用霰弹枪在1米内击杀一只武斗虫。", + "AUTOMATON DROPSHIP": "机器人运输舰", + "#ERROR!": "#ERROR!", + "TEAM KILLS #COUNT": "团队击杀数 #COUNT", + "LIBERATE HIVE WORLD": "解放虫窝世界", + "DESTROY COOLING TOWER": "摧毁冷却塔", + "Objectives bonus: #AMOUNT M": "目标加分:#AMOUNT", + "TARGET COORDINATES:": "目标坐标:", + "The Seismic Probe in this location can be used to confirm the likely locations of sub-surface geological features.": "这里的地震探测仪可以确认出现地下地质特征的可能位置。", + "Use Seismic Probes to chart the Terminid tunnel networks in this region.": "使用地震探测仪绘制该地区的终结族隧道网络。", + "Eradicate the specified number of adult Terminids and pre-adult Terminids (sometimes called eggs).": "消灭指定数量的终结族成虫和幼虫(又称“虫卵”)。", + "Halt the Illuminate and collect crucial data on the Void.": "阻止光能者,收集与寂域有关的重要数据。", + "AUTHORIZE NUCLEAR LAUNCH": "授权发射核弹", + "The Rapid Modular Drilling Platform is located here.": "快速模块化钻机平台在这里。", + "Satellite imagery has revealed that entire skyscrapers in this district are infested with Terminids. These beautiful homes and prosperous offices are now nothing but Shrieker breeding grounds.\n\nDestroy the former icons of Prosperity that have been so cruelly parasitized.": "卫星图像显示,该区域内的整栋摩天大楼都已经被终结族侵占。曾经美丽的家园和繁荣的办公室,如今沦为尖啸虫的繁殖之地。\n\n摧毁被这些寄生虫残忍霸占的昔日繁荣象征。", + "Data Jack Status: Unstable": "数据接口状态:不稳定", + "DESTROY COUNTER-ORBITAL CANNON": "摧毁反轨道加农炮", + "ALL SUB-OBJECTIVES MUST BE COMPLETED FIRST": "必须首先完成所有次要目标", + "SECURE GROUND ALL-TERRAIN EXTRACTION RIG": "控制地面全地形采集钻机", + "E-710 on Gloom-infested planets exhibits statistically-significant differences in various properties including density, viscosity, oxidation stability.\n\nReactivate defunct E-710 pumps on this planet to gather the Gloom-infused liquid for further study.": "受“阴霾”侵蚀的星球上的710元素在密度、黏度、氧化稳定性等多项属性上均呈现统计学意义的显著差异。\n\n重新启动这颗星球上废弃的710元素泵机,收集被“阴霾”侵蚀的液体以供进一步研究使用。", + "Turn the cranks on the side of the Cannon to rotate it": "转动加农炮侧面曲柄进行转向", + "DESTROY FUEL RESERVES": "销毁燃料储备", + "Conduct a geological survey to identify veins of valuable ore.": "进行地质调查,寻找珍贵矿脉。", + "#COUNT confirmed kills": "#COUNT次击杀", + "APPROPRIATE REFINERY": "占领精炼厂", + "INTELLIGENCE EXTRACTED:": "获取情报数:", + "Illuminate Warp Ships occupy key intersections in this city. These ships are critical to the enemy's insidious invasion efforts: they are used to deposit hostiles, abduct civilians, and threaten our proudly held air quality scores.\n \nSeek and destroy all Illuminate Warp Ships in the area.": "光能者穿梭舰占领了这座城市的要道。这些舰船对敌人阴险的入侵行动至关重要,被用于投放敌人、绑架平民,还威胁我们引以为傲的空气质量。\n\n搜寻并摧毁区域内的所有光能者穿梭舰。", + "Incoming Enemy Ship": "来袭敌舰", + "Area under Super Earth control:": "超级地球控制区域:", + "Use terminal to reactivate pumps": "使用终端,重新启动泵机", + "MANUALLY ADJUST VALVES": "手动调整阀门", + "ERADICATE MUTATED NESTS": "彻底摧毁变异巢穴", + "DESTROY WARP GATEWAYS": "摧毁传送门", + "UPLOADING VIDEO FILES": "正在上传视频文件", + "Swiftly secure the platinum at this site and extract before enemy reinforcements overwhelm you.": "迅速夺取此地的铂金并撤离,否则敌方的增援会将你们击溃。", + "WARP GATEWAY": "传送门", + "DROP OFF": "放下", + "An SSSD Hard Drive containing valuable data was lost at this location following an ambush of a SEAF squad. It must be recovered.": "曾有超级地球武装部队的小队在这里遭遇伏击,他们丢失了一个包含重要数据的超级固态硬盘。必须找回来。", + "Transport shuttle incoming": "运输船即将抵达", + "Wait for artillery system to initiate": "等待大炮系统启动", + "Organic plasma is synthesized in these vats. Siphon it for scientific analysis.": "有机等离子在这些槽罐之中合成。抽取样本进行科学分析。", + "Activate Aquifer Drill": "启动含水层钻机", + "Breach the Illuminate's lair and eliminate the devious threats that lurk within.": "突破光能者巢穴,消灭其中的狡诈威胁。", + "ERASE TERRORIST MEMORIALS": "推倒恐怖分子纪念碑", + "Enemy Class": "敌人等级", + "Cleared Medium Illuminate Encampment": "已摧毁光能者中型营地", + "RESCUE SCIENCE TEAMS": "救援科学团队", + "OVERWRITE CORE PROTOCOLS": "覆写核心协议", + "CAPTURE AUTOMATON TERRITORY": "占据机器人领地", + "DOCUMENT EVIDENCE": "录下证据", + "Find the objective location": "确定目标的位置", + "Find the nursery chamber drill point": "寻找繁育腔室的钻孔点位", + "COLLECT SAMPLES": "收集样本", + "Liberate Planet": "解放星球", + "Temperature": "温度", + "The Automatons have a mortar emplacement in the area. They will fire on anyone that moves in the vicinity.": "机器人在该区域设有迫击炮台,会向范围内任何移动目标开火。", + "PLEASE ACTIVATE TRANSFORMER": "请启动变压器", + "EMERGENCY EVACUATION": "紧急撤离", + "EXTRACT INTEL": "获取情报", + "The Automatons have captured a SEAF research station, slaughtering the brave scientific staff.\n\nGet to the station, download the research database, and upload it to the Super Earth mainframe using the nearby Satellite Uplink Station.": "机器人占领了一座超级地球武装部队研究站,正在残杀勇敢的科研人员。\n\n前往该研究站,下载研究数据库,然后使用附近的卫星上行链路站点将其上传至超级地球主机。", + "Locate and eliminate the Automaton Devastators.": "找到并消灭机器人蹂躏者。", + "The Terminids have transformed this world into a bastion of Fascist oppression. But it can still be restored to Liberty's Light.\n\nDeploy to the Hive World and raise the Flag of Super Earth.": "终结族已将这个世界改造成法西斯压迫的堡垒。但我们仍然可以让它恢复自由的荣光。\n\n前往虫窝世界,升起超级地球的旗帜。", + "Use the GATER to extract anomalous material from all sites.": "使用地面全地形采集钻机从所有地点提取异常物质。", + "This is the maiden voyage of the #SHIP_NAME. Its first trial is to carve a democratic path towards the indicated region and provide critical support in suppressing a small-scale Terminid outbreak.\n\nHelldiver, this is not a drill. Apply every invaluable lesson you learned at the Helldiver Training Facility. May Liberty guide you.": "这是#SHIP_NAME的首航。它的首次试炼是向指定区域开辟民主之路,并为镇压小规模终结族爆乱提供关键支援。\n\n绝地潜兵,这不是演习。请学以致用,发挥你在绝地潜兵训练设施中学到的每一条宝贵经验。愿解放保佑你们。", + "Initiate off-planet evacuation of high-value artifacts, and defend the site until evacuation is complete.": "启动高价值文物撤离星球的程序,并保卫阵地,直至撤离完成。", + "Destroyed Fortress": "已摧毁堡垒", + "A crashed escape pod in the region contains valuable data.": "坠毁在该地区的一个逃生舱中存着有价值的数据。", + "Power up data collection uplink": "为收集数据的上行链路接入电源", + "Defend generator system until all rockets have launched.\n\nRockets launched: #CURRENT/#TARGET": "在所有火箭弹发射完毕前保卫发电系统。\n\n已发射的火箭弹:#CURRENT/#TARGET", + "Please adjust all indicated valves": "请按照提示调整所有阀门", + "IMPALER ELIMINATION": "消灭穿刺虫", + "MANUALLY set ENGINE VALVES to maximum output.": "手动将引擎阀门设置为最大输出。", + "Tactically eliminate all obstacles standing in the way of peace.": "在战术层面上彻底铲除所有阻碍和平实现的障碍。", + "TEAM DEATHS #COUNT": "团队阵亡数 #COUNT", + "PEACEKEEPING OPERATION": "维和行动", + "LIBERATE CYBERSTAN": "解放生化斯坦", + "DESTROY ILLUMINATE WARP SHIPS": "摧毁光能者穿梭舰", + "Force the Cyborg Production Unit to self-destruct by disrupting its operations.": "干扰生化人生产单元的运作,迫使其自毁。", + "REDIRECT HYDROGEN FLOW": "更改氢气流向", + "INTEL RETRIEVED - OPPORTUNITIES REVEALED": "已取回情报并发掘机遇", + "Defend Battery Silo 02": "保卫电池舱02", + "MAIN SILO": "主储罐", + "Tectonic disturbances indicate the presence of an Impaler in this area.": "地壳扰动显示该区域存在穿刺虫。", + "DESTROY AUTOMATON FABRICATORS": "摧毁机器人构筑者", + "SEAF Artillery System": "超级地球武装部队大炮系统", + "Pick up ammo": "拾取弹药", + "Fire Artillery": "开炮", + "CALIBRATING VOLTAGE": "正在校准电压", + "Clear the area of Terminid nests to prepare it for Gloom research specialists.": "清除该区域的终结族巢穴,为“阴霾”研究专家的考察做好准备。", + "Nuke all Terminid nurseries and collapse the specified number of nests.": "用核武器炸毁所有终结族繁育窝,摧毁指定数量的巢穴。", + "Restart the pumps located in this region.": "重启该地区的泵机。", + "FUSION BATTERY": "聚变电池", + "LIBERATE MEGAFACTORY": "解放超大型工厂", + "ELIMINATE BILE TITAN": "消灭吐酸泰坦", + "Please log in": "请登录", + "Science strike teams—each consisting of a xenobiologist, a theoretical physicist, an astro-meteorologist, and a psychologist—will conduct expeditions to the planet's surface at key locations.\n\nClear the area of Terminid nests to secure the research site.": "科考突击队将对星球表面的重要地点进行考察,每支突击队由一名异星生物学家、一名理论物理学家、一名天文气象学家和一名心理学家组成。\n\n清除该区域的终结族巢穴,保障研究地点的安全。", + "Proceed to facility gate": "前往基地大门", + "MINING SITE COORDINATES": "采矿点坐标", + "Planetary Defense Cannon raising…": "行星防御加农炮正在抬升……", + "Deliver SSSD": "运送超级固态硬盘", + "Use door controls to release civilians from Emergency Bunkers": "使用门控装置将平民从紧急掩体中放出去", + "DEFEND EVACUATION SITE": "保卫撤离点", + "Keep open flames away from missile": "导弹周围严禁明火", + "HATCH OPENING...": "舱门正在开启……", + "DESTROY HARVESTERS": "摧毁猎杀器", + "Activate terminal": "启动终端", + "The Automatons are stealing the minerals of this planet from our citizens at this quarry. Take it back.": "机器人正在这座采石场内从我们公民的手中窃取这颗星球的矿物。将资源夺回来。", + "All Objectives Completed": "达成所有目标", + "SPREAD DEMOCRACY": "传播民主", + "#FOUND found (#TOTAL on ship)": "已找到#FOUND份(舰船上总计有#TOTAL份)", + "Use a Stim to heal your wound": "使用治疗剂疗愈伤口", + "CONFIRMING COORDINATES": "正在确认坐标", + "Low Death Count Bonus": "低阵亡次数奖励", + "2ND": "第2", + "This Automaton device prevents the use of any stratagems in the area.": "机器人的这台装置令我们无法在该区域内使用任何战略配备。", + "Destroy the Bio-Processors": "摧毁生物处理器", + "Restore power to the satellite tower": "恢复卫星塔的电力输送", + "Defend Battery Silo 01": "保卫电池舱01", + "SEIZE INDUSTRIAL COMPLEX": "占领工业联合体", + "Find Annihilator Tank": "找到湮灭坦克", + "The Illuminate have fashioned crude gateways through which they warp interloping forces from afar. A poor imitation of our FTL technology.\n\nMany of these structures have been located in this region. Destroy as many as you can.": "光能者建造简易的传送门,用于远距离传送入侵部队。这不过是对我方超光速跃迁技术的拙劣模仿。\n\n该地区内已发现大量此类建筑。尽可能摧毁这些传送门。", + "Pointless Sacrifice": "无谓牺牲", + "Illuminate Harvesters patrol this colony, enforcing the zealous rule of their masters. The unnatural, spindly constructs must be destroyed, so that Freedom can return.": "光能者猎杀器会在此拓殖地巡逻,尽心尽力维护它们主人的狂热统治。必须摧毁这些非自然的细长型结构物,我们才能重获自由。", + "CALCULATING SHUTTLE FLIGHT PATH": "正在计算运输船飞行路线", + "Destroy Automaton Mortar emplacements": "摧毁机器人的迫击炮台", + "Silo Unstable. Aborting Activation.": "舱体不稳定。即将停止启动。", + "EXTERMINATE BUGS NEAR THUMPER": "消灭桩锤附近的虫族敌人", + "ERADICATE AUTOMATON FORCES": "彻底消灭机器人部队", + "Use Terminal to open SSSD Delivery Hatch": "使用终端打开超级固态硬盘运送舱门", + "The Terminids on this planet are mutating in response to the Termicide. With every passing minute, they threaten to turn this world into another Supercolony.\n\nEradicate the mutated Terminid eggs and deactivate the corrupted Terminid Control System before its too late.": "这颗星球上的终结族正在灭虫终结剂的影响下快速变异。它们随时都有可能将这个世界变成又一个超级拓殖地。\n\n彻底清除变异终结族虫卵,尽快关闭出错的终结族遏制体系。", + "Eradicated Mega Nest": "已摧毁超巨巢穴", + "DISRUPT EXOSPIRE CORE": "破坏异界尖塔核心", + "ISOLATING NETWORK": "正在隔离网络", + "The Terminid Variant was last reported in this area.": "有报告称,终结族亚种的最后目击地点就在该区域。", + "TOWER CONTROL PANEL": "广播塔控制面板", + "Eliminate Bile Titan": "消灭吐酸泰坦", + "Proceed to Stratagem Range": "前往战略配备训练场", + "This city is under enemy control. It must be reclaimed in the name of Freedom.": "这座城市已落入敌手。必须以自由之名收复。", + "Payout already received": "已获得收益", + "INTEL PACKAGE": "情报包裹", + "Targeting Communication System": "正在锁定通信系统", + "This sector is occupied by Illuminate invaders. It must be freed.": "该分区被入侵的光能者所占领。必须解放这里。", + "Commend Player": "称赞玩家", + "A Counter-Orbital Cannon is positioned at this site.": "此处部署有反轨道加农炮。", + "Introduce Managed Democracy to the Void.": "将管理式民主传播到寂域。", + "Bore hole completed": "博尔虫洞已完成", + "Place Black Box in input tray": "将黑匣子放进输入托盘", + "HINTS": "提示", + "Silo Status: Critically Unstable": "舱体状态:极其不稳定", + "SAMPLE 01": "样本01", + "Call down SSSD and insert into Hatch": "呼叫超级固态硬盘并将其置入舱门", + "Use Reinforce Stratagem to bring back fallen squadmate": "使用增援战略配备复活阵亡的队友", + "COLLECT GLOOM-INFUSED OIL": "采集“阴霾”污染的原油", + "Destroy all Illuminate Warp Ships in the vicinity": "摧毁附近的所有光能者穿梭舰。", + "Kill Automatons and Cyborgs to reduce their numbers.": "击杀机器人和生化人,削减它们的数量。", + "Find target on grid": "在网格内寻找目标", + "Use terminal to trace defense network": "使用终端追踪防御网络", + "Destroy enemy deployment structures to secure the area": "摧毁敌方部署建筑,保障该区域的安全", + "OPEN BUNKER HATCH": "打开掩体舱门", + "Extract samples of oil that has been exposed to the Gloom.": "提取受“阴霾”污染的原油样本。", + "The bots are breaking down organic matter for use in some twisted, un-Democratic purpose.": "机器人正在分解有机质,将其用于某种不民主的扭曲用途。", + "REARMING CANNON…": "加农炮正在装弹……", + "Reconnaissance has pinpointed a number of key Automaton fuel and munitions depots within the city.\n \nInfiltrate quickly and destroy their supply bases before they can mount a defense.": "侦察部队已确定城内多个机器人燃料和弹药关键补给站的位置。\n\n快速潜入,摧毁补给基地,别让它们有机会筑起防线。", + "LIGHTNING SPIRE": "闪电尖塔", + "With the arrival of Freedom to this newfound world, the bugs have been driven into a fascist frenzy. Their destructive urge is denying our citizens the prosperous future they were always meant to inherit on this soil.\n\nA new generation of TCS+ towers stands ready to neutralize this threat and ensure total planetary safety through controlled fumigation. See that they are activated and fully operational.": "随着自由降临这片新世界,虫族陷入法西斯般的狂暴状态。它们按耐不住肆意破坏的冲动,正在剥夺我们的公民自始至终理应在这片土地上继承的繁荣未来。\n\n新一代TCS+塔已准备就绪,将通过可控式熏杀手段铲除这一威胁,保障星球的绝对安全。务必确保TCS+塔成功启动并全面投入运行。", + "ALIGN SIGNAL": "校准信号", + "FREE COLONY": "解放拓殖地", + "Enter transport pod": "进入运输舱", + "DOWNLOADING - PLEASE WAIT": "正在下载,请稍候", + "Eliminate Annihilator Tank": "消灭湮灭坦克", + "Unstable": "不稳定", + "Recover top-secret intel from a downed SEAF reconnaissance plane.": "从超级地球武装部队侦察机找回绝密情报。", + "DESTROY SPORE LUNG": "摧毁孢肺", + "System is loading - Please wait": "系统正在加载,请稍候", + "Failed to extract": "撤离失败", + "Confirm Evacuation Coordinates": "确认疏散坐标", + "Pick up supplies and load Liberator": "拾取补给,为“解放者”装弹", + "Lock the hose to the transfer pump": "将软管锁定在输送泵上", + "#MISSION_TYPE: #MISSION_NAME": "#MISSION_TYPE: #MISSION_NAME", + "Destroy the convoy before it can reach its destination": "在车队到达目的地之前将其摧毁", + "COMMUNITY IMPACT": "社区战役贡献", + "PLANETARY IMPACT": "战役贡献", + "The Terminids' grip on this planet has been weakened. We must attack now, before they have a chance to regenerate.\n\nAs Helldivers, you can take the fight to the Terminids' remaining hive cores, and root out the infestation for good.": "终结族对这颗星球的掌控有所减弱。我们必须立刻出击,避免它们恢复实力。\n\n作为绝地潜兵,你们可以直接袭击终结族剩余的虫窝核心,将其彻底清除。", + "Tune to Super Earth frequency": "调至超级地球的频率", + "Grotesque Monoliths now pepper this city, boldly empowering the Illuminate through unknown means. Their inscrutability is an affront to Liberty. They must be destroyed.": "丑陋不堪的巨石遍布城区,堂而皇之地以未知方式赋予光能者力量。它们的不可捉摸是对自由的公然亵渎。必须摧毁巨石。", + "Demolition sequence initiated": "拆除程序已启动", + "Please adjust target storage facility": "请调整目标存储设施", + "Track down and eliminate the Bile Titan.": "追踪并消灭吐酸泰坦。", + "Influence (Max)": "影响力(最大)", + "Caution: deleted data cannot be recovered": "当心:已删除的数据无法恢复", + "A Charger was last sighted in this region.": "强袭虫的最后目击地点就在这个地区。", + "Confirm scan area using probe interface": "使用探测仪界面确认扫描区域", + "SECONDARY EXTRACTION ZONE": "次级撤离区", + "Input code on terminal": "在终端上输入代码", + "HOLD CITY": "保卫城市", + "DESTROY HARD DRIVES": "摧毁硬盘驱动器", + "Cargo Truck": "货车", + "Proceed to next objective": "前往下一个目标", + "MANUALLY tighten EXHAUST CLAMPS.": "手动解开安全钳。", + "Outstanding Patriotism": "爱国精英", + "3RD": "第3", + "Disable Stratagem Blocker": "关闭战略配备屏蔽装置", + "Use Prospecting Drill to retrieve second sample": "使用勘探钻机取得第二份样本", + "Destroy ammunition stockpiles": "摧毁库存弹药", + "Establishing link...": "正在建立连接...", + "ACCURACY:": "命中率:", + "Repel the Terminid swarm threatening to infest this planet.": "击退企图占领这颗星球的终结族虫群。", + "Bonds Awarded": "奖励债券数", + "ELIMINATE DEVASTATOR": "消灭蹂躏者", + "Log in to terminal": "登录终端", + "Find and destroy any active Automaton Gunship Fabricators": "寻找并消灭所有运作中的机器人炮舰构筑者", + "This Terminid hive node emits a dense fog which reduces visibility.": "此终结族虫窝节点释放出一种降低能见度的浓雾。", + "LEVEL #COUNT": "等级#COUNT", + "Abandoned SEAF Anti-Aircraft Missile Launchers will fire on enemy airborne targets when activated.": "废弃的超级地球武装部队防空导弹发射器启动时,将向空中的敌方目标开火。", + "Use Terminal to activate Communication Tower": "使用终端启动通信塔", + "LAUNCH ICBM": "发射洲际弹道导弹", + "Use terminal to activate surface-to-air launcher sub-systems": "使用终端启动地对空导弹发射器子系统", + "#ENTITY is out of range": "#ENTITY不在范围内", + "PREPARING UPLOAD": "准备上传", + "ACTIVATE TERRAIN SCAN": "开启地形扫描", + "A cluster of hive entrances has been mapped in this region.": "这个地区内标记有多处虫窝入口。", + "Generator calibrating": "发电机正在校准", + "RAISING TOWER - PLEASE WAIT": "正在抬升卫星塔,请稍候", + "BREACHING TERMINID COLONY": "攻破终结族拓殖地", + "PROPULSION": "推进", + "Input code to finalize virus upload": "输入代码,上传病毒", + "Community Reinforced": "增援社区", + "Shriekers: #CURRENT / #TOTAL kills": "尖啸虫:#CURRENT / #TOTAL次击杀", + "Protect #ENTITY during upload": "在上传期间保护#ENTITY", + "The Illuminate are attempting to steal this planet from our citizens. \n\nWe must repel them before it is too late!": "光能者企图从我们的公民手中窃取这颗星球。\n\n我们必须及早击退它们!", + "Take control of the planet to unmake the Void.": "夺取星球的控制权,瓦解寂域。", + "Thank you for your patience": "感谢您耐心等待", + "The Terminids are mutating. Deactivate the TCS before it's too late.": "终结族发生变异。尽快关闭TCS。", + "Protect Liberty": "保卫解放", + "ELIMINATE DEVASTATORS": "消灭蹂躏者", + "Lightning Spires": "闪电尖塔", + "The Automatons use a highly-advanced keycard security system. A keycard located here will grant access to their secure containment unit.": "机器人使用高度先进的钥匙卡安全系统。此处的钥匙卡可打开它们的安全收容装置。", + "RETRIEVE THE GENERAL'S ORDERS": "取回将军的命令", + "A high-definition tactical video camera has been deployed to this location. It is critical to recording evidence of the enemy's crimes.": "我方已在此处部署一台高清战术摄像机。它对记录敌军罪证至关重要。", + "Completing this Operation helps liberate this Megafactory. Each liberated Megafactory brings us closer to the total liberation of Cyberstan.": "完成此次行动有助于解放这所超大型工厂。每解放一所超大型工厂,我们就离彻底解放生化斯坦更近一步。", + "Extraction bonus: #AMOUNT M": "撤离加分:#AMOUNT", + "SSSD Hard Drive": "超级固态硬盘", + "Intel Recovered": "已找回情报", + "Initiate Evacuation": "启动疏散程序", + "Silo Status: Stable": "舱体状态:稳定", + "Activate Battery Silo 02": "启动电池舱02", + "The brilliant scientists of this SEAF research station were abducted following an Illuminate hostile takeover. They would have wanted their life's work to be recovered and put in the service of Super Earth.\n\nAccess the station, download the research database, and upload it to the Super Earth mainframe.": "由于光能者的入侵占领,驻守超级地球武装部队研究站的杰出科学家们惨遭绑架。他们肯定希望自己毕生的研究成果能够被妥善寻回,为建设超级地球贡献力量。\n\n前往该研究站,下载研究数据库,然后上传至超级地球主机。", + "The Illuminate have invaded this colony, turning its citizens into Voteless hordes. They have raised uncanny, malevolent monoliths that generate some kind of exotic energy fields. We know neither their function nor their true nature—that is why we must destroy them.\n\nWe must cast off their occupation. Deploy to the colony, tear down the invaders' structures, and raise the flag of Super Earth once more.": "光能者入侵了这片拓殖地,将其中的公民变为了无票者。它们立起了邪恶的诡异巨石,想打造某种奇异的能量场。我们不知道巨石的功能,也不了解其中的性质,所以必须将它们摧毁。\n\n我们必须让拓殖地摆脱敌人的占领。前往拓殖地,摧毁入侵者的建筑,再次升起超级地球的旗帜。", + "INITIATE DRILL SEQUENCE": "启动钻机程序", + "The streets of this Megafactory are riddled with terrorist emblems and Cyborg propaganda. It is your duty to redress this affront, and to bring Democracy to this oppressed place.\n\nStorm the Megafactory and raise the flag of Super Earth, the one true symbol of Unity.": "这座超大型工厂的街道随处可见恐怖分子的标志和生化人的宣传物。你的职责是纠正这种冒犯行为,并将民主带到这片受压迫的土地。\n\n突袭超大型工厂,升起超级地球的旗帜,这是唯一真正的团结象征。", + "Return to Super Earth flag": "返回超级地球旗帜所在位置", + "Activate terminal at base of Central Tower": "在中央巨塔底启动终端", + "Terminal System": "终端系统", + "RETRIEVE LAUNCH CODES": "取回发射代码", + "Probe may cause significant hearing loss": "探测仪可能会严重影响听觉", + "Turn all valves indicated by the terminal": "按照终端的提示,调整所有阀门", + "Place switches to indicated positions": "将开关调到指定位置", + "CONTROL CHAMBER LOCKED": "控制室已锁定", + "Adjust pipe valves": "调整管道阀门", + "A large Automaton air base in this region is conducting frequent troop deployments by Dropship—a tactical advantage we cannot allow.\n\nDeploy behind enemy lines and destroy their Dropships and the air base's infrastructure.": "机器人在该地区有一座大型航空基地正在频繁使用运输舰调度部队——我们不能放任它们继续占领这种战术优势。\n\n深入敌方防线背后,摧毁它们的运输舰,破坏航空基地的基础设施。", + "Influence (Self)": "影响力(自我)", + "Influence (Community)": "影响力(社区)", + "SECURE BLACK BOX": "取回黑匣子", + "Launch Codes": "发射代码", + "START FUEL PUMPS": "启动燃料泵", + "Destroy all Warp Gateways in the vicinity": "摧毁附近的所有传送门", + "VERIFY TRANSFER CHECKSUM": "验证传输校验和", + "MISSION REWARDS": "任务奖励数", + "Establish connection to Super Destroyer to secure reinforcements": "与超级驱逐舰建立连接,获得增援", + "FUELING STATION": "燃料站", + "DEPLOY SEISMIC PROBE": "部署地震探测仪", + "The Automatons are synthesizing some kind of nutrient-dense plasma from organic material. Undeniable intel shows 100% of this organic material came from loyal citizens with high potential and excellent facial symmetry. The purpose of this plasma is yet unknown, but its production is extremely costly.\n\nDue to enemy anti-air, this mission must be extremely rapid. Destroy the Bio-Processors that fuel plasma synthesis, then extract.": "机器人正在用有机物质合成某种富含营养的等离子。有确凿情报显示,这些有机物质100%来自潜力巨大而且面部完美对称的忠诚公民。这种等离子的具体用途尚未明确,但其生产成本极其高昂。\n\n因敌方出动防空火力,此次任务的行动必须极其迅速。摧毁为合成等离子提供动力的生物处理器,然后撤离。", + "A network of towers stand ready to dispense bug-killing Termicide across the planet. Once they're active, this planet will be cleansed of Terminids, forever.\n\nActivate the Termicide Dispersion Tower in this region, and bathe it in a purifying haze of Termicide.": "巨塔网络已准备好在星球各地喷洒灭虫终结剂。一旦启动,这颗星球就可以永远免受终结族的威胁。\n\n启动该地区的灭虫终结剂喷洒塔,让灭虫终结剂的雾气带来净化的洗礼。", + "Use LiDAR towers to gather Gloom spore data and upload it from a communication relay.": "使用激光雷达塔收集“阴霾”孢子数据,并通过通信中继站上传数据。", + "Activate Shuttle Bay Terminal": "启动运输船坞终端", + "A fuel station in this district powers the Cyborg Production Unit with highly combustible hydrogen.": "该区域的燃料站为生化人的生产单元供应高度易燃的氢气能源。", + "#TYPE: +#AMOUNT/#POTENTIAL": "#TYPE:+#AMOUNT/#POTENTIAL", + "DESTROY EXOSPIRE": "摧毁异界尖塔", + "Use terminal to reset fuses": "使用终端重置熔断器", + "Destroy Automaton Anti-Air Emplacements": "摧毁机器人的防空炮台", + "WARHEAD": "弹头", + "Research data available and ready for upload": "研究数据准备就绪,可供上传", + "Location data ready": "附近地点的数据已准备就绪", + "Salute the Flag of Super Earth": "向超级地球旗帜敬礼", + "EXTRACT MYSTERIOUS SUBSTANCE": "提取神秘物质", + "Use terminal to direct hydrogen into Power Core": "使用终端将氢气导入动力核心", + "Drill Status: Stable": "钻机状态:稳定", + "Silo Power Module": "舱体电力模块", + "RAZE STRATEGIC INFRASTRUCTURE": "摧毁战略基础设施", + "Infiltrate this site to acquire high-value intel, and extract with it in your possession.": "潜入此地获取高价值情报,携带情报撤离。", + "TRANSMITTING DATA": "传输数据", + "SEAF units have encountered Impalers in this region. They are not capable of dealing with this threat.\n\nAs elite Helldivers, you must hunt down and kill all Impalers in the area.": "超级地球武装部队已在该地区遭遇穿刺虫。他们无法应对这一威胁。\n\n作为精锐部队的绝地潜兵,你必须找到并消灭该地区所有穿刺虫。", + "An illegal propaganda broadcast has been traced to this location.": "经追查发现,有非法宣传广播正在此处运营。", + "A heavily-guarded cache of high-grade platinum is located here. The material is the rightful property of Super Earth and its citizens, and it is your duty to reclaim it. \n\nLocal reinforcements will activate as soon as your presence is detected. Get in, reclaim the material, and get out.": "这里存有一批高品质铂金,周围戒备森严。这些物资属于超级地球及其公民的合法财产,将其夺回是你们的职责。\n\n敌军在当地的增援部队一旦发现你们,就会立即启动。闯入目的地,夺回物资,然后撤离。", + "Drill may disturb subterranean creatures": "钻机可能惊扰地下生物", + "SILO HATCH LOCKED": "发射井舱门未解锁", + "ACTIVATE TCS+": "启动TCS+", + "Enemy ships deployed: #COUNT": "已部署敌舰数:#COUNT", + "ERROR: DISENGAGE ALL HATCH LOCKS": "错误:请解除所有舱门锁", + "Destroy Shrieker-infested towers to cleanse this district from its would-be parasites.": "摧毁遍地尖啸虫的塔巢,清除此区域中潜藏的寄生虫。", + "Eradicate Terminid eggs": "彻底清除终结族虫卵", + "Heavy Automaton forces are gathered in this location.": "大批机器人部队集结于此地。", + "A mechanical chiller at this location cools the hydrogen that flows into the Cyborg Production Unit.": "这里的机械冷却器为流入生化人生产单元的氢气降温。", + "Kill the Terminid": "击杀终结族", + "RELEASE STERILIZING AGENT": "释放灭菌剂", + "CONDEMN ILLICIT EXPERIMENTS": "谴责非法实验", + "Destroy the Bio-Processors that fuel synthesis of organic plasma, then extract.": "摧毁为合成有机等离子提供动力的生物处理器,然后撤离。", + "Activate the Seismic Scan": "启动地震扫描", + "Battery Silo 03 Offline": "电池舱03停用", + "Destroy Automaton Dropships": "摧毁机器人运输舰", + "Brave the Megafactory and liberate this land from Cyborg occupation.": "勇闯超大型工厂,将这片土地从生化人的占领中解放出来。", + "Find probes sent into the Gloom and extract their research data.": "找到发射至“阴霾”的探测仪,提取研究数据。", + "Use hub terminal to upload recordings": "使用中继站终端上传记录", + "Once the black box has been secured, it must be transported to this interplanetary uplink site to upload its data to the Ministry of Defense's top-secret network.": "拿到黑匣子之后,必须将它转移到这个星际上行链路点位,将数据上传到国防部的绝密网络。", + "B. Silo 03": "电池舱03", + "ALERT: ENCRYPTED TRANSMISSION RECEIVED\n\nDECRYPTING…\n.\n.\n.\nCLASSIFICATION: TOP SECRET\n\nMINISTRY OF DEFENSE\nDIRECTORATE OF HELLDIVER READINESS\nORIGINATING STATION: MARS\n\nMEMORANDUM FOR: Helldiver Readiness Command\nSUBJECT: Daily Incoming Recruit Report\n\nTotal Incoming Trainees: 48,736\nAvg. Age (Years): 18.7 \nAvg. Combat Readiness Rating: 27.1%\nAvg. Patriotism Rating: 97.4%\n\nExpected Survival Rate: 21.3% \nProjected Helldiver Production: WITHIN QUOTA\n\nEND TRANSMISSION": "警告:接收到加密传输\n\n正在解密……\n.\n.\n.\n级别:绝密\n\n国防部\n绝地潜兵备战理事会\n发出站:火星\n\n备忘录收件人:绝地潜兵备战指挥部\n主题:新兵招募每日报告\n\n受训新兵总数:48,736\n平均年龄(岁):18.7\n平均备战评分:27.1%\n平均爱国评分:97.4%\n\n预期存活率:21.3%\n绝地潜兵计划产量:配额内\n\n结束传输", + "OUTFLOW": "外流", + "Use terminal to align communication signal": "使用终端校准通信信号", + "New Missions Available": "解锁新任务", + "Deep cover intelligence has, through highly classified and heroic means, identified a mutated strain of larvae in this hive. Find the mutated larvae and retrieve them for study by our heroic Bug Anatomy/Weapons Development (BAWD) Specialists.": "我方人员英勇果敢地通过高度保密的途径传回情报,确定此虫窝内存在一种变异幼体。找出并带回变异幼体,供虫族解剖/武器研发(BAWD)的英勇专家进行研究。", + "EVACUATE COLONISTS": "撤离拓殖地居民", + "SECURE RESEARCH SITE": "保障研究地点的安全", + "Opportunity Completed": "完成机遇任务", + "OPPORTUNITY REWARD": "机遇奖励", + "EVACUATION PROTOCOL: ACTIVE": "疏散协议:已启动", + "Proceed to Support Stratagem Training Area": "前往支援战略配备训练区", + "FUSE 5": "熔断器5", + "Defend Battery Silo until activation is complete": "保卫电池舱,直到启动完毕", + "A massive number of Automaton militants are concentrated in this overrun city. Decisive action must be taken to reduce their numbers. \n \nDeploy to the middle of the combat zone, and kill as many bots as you can.": "大量机器人武装分子集结在这座沦陷的城市中。必须果断采取行动,削减它们的数量。\n\n动身前往战区中心,全力消灭机器人。", + "Confirm depth using drill interface": "使用钻机界面确认深度", + "Gather nearby assets and place them in the container": "收集附近的资源,放进容器里", + "Pull transformer unit lever": "拉动变压器单元操纵杆", + "Eliminate Brood Commander": "消灭虫族指挥官", + "Escort Citizens safely to Shuttle Bay": "护送公民安全前往运输船坞", + "Please clear launch area": "请离开发射区域", + "OPERATION MODIFIER ADDED": "已添加行动限制条件", + "Purge Terminid spawn by delivering a nuclear payload to all Nursery Chambers.": "将核炸药送入所有繁育腔室,彻底清除终结族幼虫。", + "LAUNCH SEQUENCE INITIATED": "发射程序已启动", + "Find and destroy any active Automaton fabricators": "寻找并消灭所有运作中的机器人构筑者", + "TWO": "二", + "In this region, orbital bombardment has exposed seams of what appear to be rare and valuable mineral ores. \n\nWe cannot let the Automatons exploit them before the planet is liberated. Get down there and collect soil sample data, to confirm if the material is worth extracting.": "该地区在轨道轰炸之后露出的矿层中似乎存在稀有的珍贵矿石。\n\n绝对不能放任机器人在我们解放这颗星球前开采这些矿石。前往地表,收集土壤样本数据,确认其开采价值。", + "Glorious Victory": "辉煌胜利", + "Warning: Critically Unstable": "警告:状态极其不稳定", + "Protect our way of life from the Automatons by any means necessary.": "不惜一切代价也要捍卫我们的生存之道,不能让机器人损害半分。", + "RETRIEVE VALUABLE DATA": "检索有价值的数据", + "File transfer in progress": "文件正在输送", + "PROVING GROUND OPERATION": "试炼场行动", + "MAIN COMPONENTS": "主要组件", + "DISRUPT SHIELD GENERATOR": "破坏防护罩生成装置", + "LOAD ARTILLERY SHELLS": "装填炮弹", + "Pumping in progress...": "正在泵取……", + "A Ground All-Terrain Extraction Rig (GATER) has been deployed to this area, where multiple high-value substance reservoirs have been identified.\n\nYou have been summarily certified as Expert Large Vehicle Operators. Deploy to the area and utilize the GATER to extract the mysterious substance from all identified locations.": "此区域已部署地面全地形采集钻机(GATER),也已确认存在多个珍贵物质储藏点。\n\n仓促间你已被授予大型载具驾驶专家的资格。请部署到该区域并使用GATER从所有确认地点提取神秘物质。", + "According to atmospheric measurements, airborne spore density in this area is reaching critical levels. It is only a matter of hours before this district becomes uninhabitable.\n\nDestroy the Terminid bio-weapons producing these spores, and allow our citizens to breathe Freely once more.": "根据大气测量数据,此区域空气中的孢子密度已接近临界水平。再过几个小时,此区域将变得不适宜居住。\n\n摧毁产生这些孢子的终结族生物武器,让我们的公民能再次自由呼吸。", + "GUNSHIP FACILITY": "炮舰设施", + "DATA JACK OPERATIONAL": "数据接口运作正常", + "RETRIEVE THE CHEMICALS": "回收化学原料", + "BUFFER TANK": "缓冲罐", + "Use terminal to sabotage Control Tower": "使用终端破坏控制塔", + "DESTROY BIO-PROCESSORS": "摧毁生物处理器", + "Open valve": "打开阀门", + "Please reset all blown fuses": "请重置所有熔断的熔断器", + "Escort facility staff safely to Evacuation Shuttle": "将设施人员护送至疏散运输船", + "MISSION TIME #HOURS:#MINUTES:#SECONDS": "任务时长 #HOURS:#MINUTES:#SECONDS", + "ACTIVATE LAUNCHER SUB-SYSTEMS": "启动发射器子系统", + "PLANETARY DEFENSE CANNON ARMED": "行星防御加农炮已启动", + "EARN YOUR HELLDIVER CAPE": "努力赢得绝地潜兵披肩", + "Smelting": "冶炼", + "RAISE FLAG OF SUPER EARTH": "升起超级地球旗帜", + "Confirm that drill site is safe for operation": "确认钻探地点可安全作业", + "Defend Drill during deployment": "部署期间保卫钻机", + "Enter the GATER": "进入GATER", + "INPUT ACTIVATION SEQUENCE": "输入启动程序", + "THREAT LEVEL: LOW": "威胁等级:低", + "CONFIRM DRILL POSITION": "确认钻机位置", + "Cut the bots off from their information network by destroying their Command Bunkers.": "摧毁指挥碉堡,切断机器人的信息网络。", + "Turn Off": "关闭", + "Enemy hostiles have located a reserve of classified defensive assets placed in long-term storage for city defense. To prevent the hard-fought cache from falling into the enemy's totalitarian grip, they must be rapidly evacuated off-world.\n \nCommencing evacuation will reveal your position to the invaders. Defend the site until transport is complete.": "敌军已发现一批为城防长期储备的机密防御资产。为防止这批来之不易的储备物资落入敌人极权的掌控之中,必须迅速将其撤离至外太空。\n\n启动撤离程序后,入侵者将知晓你的位置。保卫阵地,直至撤离完成。", + "A massive Terminid swarm has gathered in this area. We cannot leave this threat unchecked if we are to take the city back.\n\nKill as many Terminids as you can to thin their numbers.": "大批终结族已在此区域聚集。要夺回这座城市,我们必须消除这一威胁。\n\n全力击杀更多终结族,削减它们的数量。", + "This planet is so thoroughly infested that it appears to be a single interconnected Terminid hive. Gloom spores originate from somewhere inside this planet.\n\nIt is difficult to predict what threats will be encountered on this planet. The Helldivers must delve into the enemy's caves to expunge their secrets. Reclaim the Hive World and free our citizens from the terror of the Gloom.": "这颗星球彻底被侵染,看起来就像内部互相连通的巨大终结族虫窝。“阴霾”孢子源自这颗星球内部某处。\n\n我们很难预测会在这里遭遇怎样的威胁。绝地潜兵必须深入敌方洞穴,抹除它们的秘密。收复虫窝世界,让我们的公民摆脱对“阴霾”的恐惧。", + "Recover the dropped #ENTITY": "取回掉落的#ENTITY", + "ACTIVATE DRILL 1?": "是否启动1号钻机?", + "HIGH-VALUE PICKUPS": "高价值拾取物", + "SYSTEM BOOTING...": "系统正在启动…", + "ICBM raising into launch position": "洲际弹道导弹正在抬升至发射位置", + "ELIMINATE FACTORY STRIDER": "消灭移动工厂", + "THREE": "三", + "ERADICATE ILLUMINATE FORCES": "彻底消灭光能者部队", + "We must seize this opportunity to destroy the Terminid Supercolony. Helldivers all across the planet will deploy with a limited supply of the exotic matter known as Dark Fluid, and insert it at critical points in the planet's crust. \n\nOnce critical mass is reached, the planet will collapse into a black hole, destroying the threat to Liberty once and for all.": "我们必须抓住这次机会,摧毁终结族超级拓殖地。全星球的绝地潜兵将携带名为“暗液体”的限量供应奇异物质上阵,须将这种物质注入星球地壳的临界点。\n\n一旦达到临界质量,星球就会坍缩成黑洞,彻底摧毁所有威胁自由的敌人。", + "Eradicated Light Bug Nest": "已摧毁轻型巢穴", + "Megafactories like this one double as strategic command nodes and industrial cores for large-scale Cyborg and Automaton production.\n\nStorm its walls and reduce this socialist hub to rubble.": "这类超大型工厂既是生化人的战略指挥节点,也是它们用于大规模生产生化人和机器人的工业核心。\n\n攻破其防御系统,将这个暴政据点夷为平地。", + "Reports indicate that a Bile Titan was last observed in this location.": "报告显示,吐酸泰坦的最后目击地点就在这个位置。", + "Use Prospecting Drill to retrieve final sample": "使用勘探钻机取得第三份样本", + "The Terminid advance has swarmed across this region, leaving one of our top secret research stations surrounded by the enemy.\n\nUse your clearance to unlock the emergency bunker doors, and defend the facility staff as they transfer to the evacuation shuttle.": "终结族的大军已经席卷了这个地区,我们的绝密研究站被敌人包围。\n\n使用你的权限打开紧急掩体的门,将该设施中的人员转移到疏散运输船,并在这个过程中保卫他们的安全。", + "Plant flag in designated area": "在指定区域竖立旗帜", + "Destroy the Illuminate's Gazer Spires.": "摧毁光能者凝视者尖塔。", + "Weather Reconnaissance aircraft that were in operation when the Gloom originally spread to this planet may contain useful data on Gloom-infused atmosphere. \n\nFind their black boxes and use a local relay station to decrypt and upload the research data to the Ministry of Science mainframe.": "在“阴霾”最初蔓延至该星球时,恰有气象侦察机在空中作业,或许能提供有关“阴霾”侵袭大气层的有用数据。\n\n找到黑匣子,利用当地中继站解密研究数据并上传至科学部主机。", + "Deposit Tactical Video Camera in Hub container": "将战术摄像机存入中继站储存箱", + "Reset Tower Alignment": "重置激光雷达塔对齐", + "FIRING SEQUENCE INITIATED": "发射程序已启动", + "SAMPLE 03": "样本03", + "The Automaton Legion relies on its strict hierarchical structure; remove the leaders, and the ranks will fall easily.\n\nWe believe there are Devastators present in the region. Find them, and destroy them.": "机器人军团依赖于严格的层级结构。清除领袖,它们的军队就会土崩瓦解。\n\n据悉,该地区存在蹂躏者。找到它们并将其摧毁。", + "DESTROY GAZER SPIRE": "摧毁凝视者尖塔", + "Decades-old pumps have been rendered inoperable by unchecked Terminid infestation. But the pumps remain structurally intact, and the reservoirs they once pumped are now filled with extremely valuable E-711.\n\nClear the Terminid outgrowth clogging the pipeline, and restore it to operation.": "因为终结族肆虐侵染,在这里放置数十年的泵机无法正常运作。但这些泵机的结构仍然完好,从前泵取的库存现在装满了极为珍贵的711元素。\n\n清除堵塞管道的滋生终结族,让管道恢复运作。", + "System Access Module": "系统访问模块", + "INSTALL ROOTKIT": "安装后门程序", + "LINK TO SUPER DESTROYER": "连接至超级驱逐舰", + "Reduce the bug population by any means necessary.": "不惜一切手段减少虫族数量。", + "RECLAIM CITY": "收复城市", + "LINK HELLPODS TO DESTROYER": "将绝地喷射舱连接至驱逐舰", + "Disgraceful Conduct": "可耻行为", + "PURGE HATCHERIES": "清除孵化点", + "Wait": "请稍候", + "Influence (Start)": "影响力(初始)", + "Destroy all the mutated Terminid eggs in this area.": "摧毁该地区内所有的变异终结族虫卵。", + "Repel the enemy forces attempting to claim this city.": "击退企图占领这座城市的敌军。", + "Mournful Victory": "悲哀得胜", + "Please evacuate the premises": "请从此处撤离", + "Eradicate the Gloom-producing Spore Lung deep within the Hive.": "消灭深藏在虫窝内孕育“阴霾”的孢肺。", + "Raise the Super Earth flag as an unassailable beacon of Liberty.": "升起超级地球旗帜,犹如树立起一座坚不可摧的解放灯塔。", + "Drill sites excavated": "已挖掘的钻探点", + "Fuel transfer in progress": "燃料正在输送", + "#COUNT SAMPLES": "#COUNT份样本", + "SABOTAGE AIR BASE": "破坏航空基地", + "Insert SSSD into receptacle": "将超级固态硬盘置入插槽", + "Insert SSSD into hatch": "将超级固态硬盘置入舱门", + "Manual valve adjustment required": "需要手动调整阀门", + "Decades-old pumps have been rendered inoperable by unchecked Terminid infestation. But the pumps remain structurally intact, and the reservoirs they once pumped are now filled with a new, strange E-710-like substance. \n\nClear the Terminid outgrowth clogging the pipeline, and restore it to operation.": "因为终结族肆虐侵染,在这里放置数十年的泵机无法正常运作。但这些泵机的结构仍然完好,从前泵取的库存现在装满了类似710元素的新奇怪物质。\n\n清除堵塞管道的滋生终结族,让管道恢复运作。", + "Cleared Stronghold": "已摧毁要塞", + "OPEN SILO HATCH": "打开发射井舱门", + "Lightning Spire": "闪电尖塔", + "Deployed Enemy Ship": "已部署敌舰", + "B. Silo 02": "电池舱02", + "Terminids in this area are multiplying exponentially. Left unchecked, this infestation will soon grow out of hand.\n\nDestroy their hives and kill as many bugs as you can.": "该地区的终结族正以指数级增长。如不加以管控,虫害很快就会到了一发不可收拾的地步。\n\n摧毁它们的虫窝,竭力消灭这些虫族。", + "We must show the galaxy that even in the face of oppression, Freedom remains defiant. \n \nInfiltrate this Terminid-infested region and raise our Flag as an unassailable beacon of Liberty.": "我们必须让整个银河系都知道,纵使面对压迫,自由仍傲然不屈。\n\n潜入终结族占据的这个地区,升起我们的旗帜,犹如树立起一座坚不可破的解放灯塔。", + "RAISING LAUNCHER": "正在抬升发射器", + "ACTIVATE TOWER": "启动通信塔", + "Fortification Quantity": "防御工事数量", + "Call down a Hellbomb to destroy the Cannon": "呼叫地狱火炸弹摧毁加农炮", + "Loadout Progression": "武装配置进度", + "RETRIEVE ESSENTIAL PERSONNEL": "找回重要人员", + "Select hydrogen outflow target": "选择氢气流出目标", + "ACTIVATION FAILURE: VALVES BLOCKED": "启动失败:阀门受阻", + "Long-range laser artillery enforces the Illuminate's tyrannical grip over this area, engaging targets in orbit and on the ground with deadly precision.\n\nTheir presence prevents us from establishing a foothold in this region. Deploy to the area and eliminate all active Gazer Spires.": "远程激光大炮维系着光能者对该区域的暴政统治,它们能以致命精度打击轨道和地面目标。\n\n这些武器的存在,导致我方无法在该地区内建立据点。部署到该区域,摧毁所有还在运行的凝视者尖塔。", + "TCS+ activation complete": "TCS+激活完成", + "Com.Mission Inf (Self)": "完成任务的影响力(自我)", + "The Void's loitering presence has visibly reshaped the surface of this world. Further analysis is required to determine how deep this corruption extends below ground.\n\nYou have been issued a reinforced Prospecting Drill. Collect soil samples to assess the full extent of the Void's unnatural influence.": "寂域盘踞附近,已明显重塑该星球的地表环境。需开展进一步分析,查明这种腐化现象在地下的渗透深度。\n\n你已获得一台加强版勘探钻机。采集土壤样本,评估寂域所带来的异常影响范围。", + "Initiate to download data to encrypted SSSD": "启动并将数据下载至加密超级固态硬盘", + "Transport Vessel to Payload Site": "运送容器至投放点", + "Fuel transport shuttle incoming": "燃料运输船即将抵达", + "Battery Silo 02 Offline": "电池舱02停用", + "Infiltrate the site and acquire undeniable evidence of the enemy's unforgivable crimes.": "潜入现场,获取敌军不可饶恕罪行的铁证。", + "Utilize the GATER to extract the E-711 from all identified sites.": "使用GATER从所有确认地点提取711元素。", + "Specimen Case": "样本箱", + "ONE": "一", + "Deliver any SSSD Hard Drives": "运送所有超级固态硬盘", + "Drill site nearby": "附近有钻探点", + "DAILY REWARD": "每日奖励", + "Secure a black box containing critical intel from a downed SEAF recon aircraft.": "从被击落的超级地球武装部队侦察机中取回存有关键情报的黑匣子。", + "Evacuate civilians trapped behind Automaton lines.": "疏散被困在机器人战线后方的平民。", + "The Automatons have constructed an air base where our citizens' homes once stood, allowing them to dominate the city's airspace. \n\nBreach the base and raze it to the ground. Don't leave a single Dropship standing.": "机器人在公民家园的废墟上建造起了空军基地,借此掌控了城市的制空权。\n\n突入基地,将它夷为平地。运输舰一艘都不要留。", + "Find Impaler": "找到穿刺虫", + "The Ministry of Science has launched hundreds of thousands of robotic space probes into the Gloom. The Gloom interferes with signal transmission. One is crashed in this area.\n\nFind the probe, and boost its signal to transmit its data past the atmospheric Gloom to the Super Destroyer.": "科学部向“阴霾”发射了数十万个机器人太空探测仪。但“阴霾”会干扰信号传输。有一个探测仪在此区域坠毁。\n\n找到探测仪并增强其信号,将数据穿越大气层中的“阴霾”传至超级驱逐舰。", + "Adjust valves in Control Chamber to overload engine": "在控制室调节阀门使引擎过载", + "INITIATE AREA SCAN": "启动区域扫描", + "Use terminal to open bunker hatch": "使用终端,打开掩体舱门", + "Defy invaders who dare forsake our flag. Proudly raise our enduring symbol of Managed Democracy, and reclaim this city in the name of Freedom.": "抗击丢弃我方旗帜的入侵者。高举管理式民主的不朽象征,以自由之名收复这座城市。", + "SEAF troops report sightings of a Devastator in this area.": "超级地球武装部队士兵报告称,在这片区域发现了蹂躏者。", + "Uploading data to Super Earth Mainframe": "正在向超级地球主机上传数据", + "Redirect fuel to new target": "更改燃料流向,将其输送至新目标", + "You will be fighting the #RACE.": "你将会迎战#RACE。", + "WAR IMPACT": "战争冲击", + "Operating at 100% efficiency": "当前运行效率:100%", + "Victory": "胜利", + "Intel has pinpointed the storage of two highly valuable products at this location: high-grade platinum and fusion batteries. Produced at extremely high cost, the materials are intended to facilitate the mass murder of innocent civilians. It is imperative that they are seized before this can happen.\n\nRaid the facility. Secure and extract platinum bars and fusion batteries on-site.": "情报部门已确定此处储存着两种高价值物品:高纯度铂金和聚变电池。这些材料耗费巨资生产,敌人意图用来大规模屠杀无辜平民。必须赶在它们达成目标之前夺得这些材料。\n\n突袭基地。夺取并撤走现场的铂金条和聚变电池。", + "Escort and protect researchers as they travel to the evacuation zone.": "护送研究员安全转移至疏散区。", + "Hatch opening. Thank you for your patience.": "舱门正在开启。感谢你的耐心等待。", + "Please adjust routing protocol": "请调整路由协议", + "SAMPLE COLLECTION IN PROGRESS": "正在收集样本", + "INTEL EXTRACTED BY": "情报提取人:", + "This anti-aircraft emplacement is preventing the spread of liberty across the skies of this planet. Take it out before any more families are forced to attend martyrdom celebrations for their fallen heroes.": "此对空炮台将妨碍自由在这颗星球的天空中传播。越快摧毁,越少家庭被迫感受阵亡英雄哀悼会的痛楚。", + "Data Jack Status: Critically Damaged": "数据接口状态:严重受损", + "Eliminate Variant": "消灭亚种", + "CULL SPAWN": "抑制孵化", + "Completing this Operation helps liberate this Megafactory. Successfully liberating Megafactories significantly contributes to the planet's Liberation.": "完成此次行动有助于解放这所超大型工厂。成功解放超大型工厂将大幅推动星球解放进程。", + "Unknown and unexpected system error": "未知意外系统错误", + "Fuel": "燃料", + "A cache of 99% purity platinum is located here. The Automatons intend to use this valuable metal to endanger Democracy. Seize it.": "这里存有一批纯度高达99%的铂金。机器人企图利用这批贵重金属来危害民主伟业。夺取铂金。", + "AVERT VOID": "抵御寂域", + "Destroy the Automatons' Counter-Orbital Cannons in the area.": "摧毁该区域内机器人的反轨道加农炮。", + "OPERATION COMPLETED": "行动完成", + "Eliminate Devastators": "消灭蹂躏者", + "Proceed to Final Test": "前往终极考验", + "A TCS+ station at this site is loaded with refined Termicide 2.0, now with no credible risk of unintended mutagenic side effects. Once initiated, it will sterilize the area with fumes highly lethal to Terminids, yet entirely safe to humans.\n\nActivate the TCS+ station, and bathe the region in a purifying haze of Termicide.": "此处的TCS+站已装载精制灭虫终结剂2.0,无任何可证实的意外诱变副作用风险。一旦启动,它将释放对终结族极度致命但对人类完全安全的烟雾,对该区域进行彻底消杀。\n\n启动TCS+站,让这片区域沐浴在灭虫终结剂的净化烟雾中。", + "Confirm": "确认", + "The Cyborgs dictate the surrounding air domain from this fortified air base. It must be decisively obliterated.\n\nInfiltrate the base and tear it down. Destroy any grounded Dropships in sight.": "生化人凭借这座要塞化空军基地掌控着周边空域。必须将其彻底摧毁。\n\n渗透基地并将其拆毁。摧毁看到的所有停靠运输舰。", + "Use terminal to activate fuel transfer": "使用终端,重新启动燃料运输", + "AIR CONTROL TOWER MAINFRAME": "航空控制塔主机", + "DEFEND PLANET": "保卫星球", + "Free trapped colonists and escort them to safe evacuation.": "释放受困的拓殖地居民,护送他们前往安全的撤离点。", + "AQUIFER DRILL": "含水层钻机", + "Release the hose": "卸除软管", + "ESTABLISHING LINK": "建立连接", + "Massive uncanny storms have erupted on this planet. These \"Exostorms\" emanate from otherworldly spires, unearthed by the Illuminate from the ruins of their fallen empire.\n\nThe intentions of the Illuminate are unclear, but undeniably sinister. Strike their crude bases and return them to rubble.": "这颗星球上爆发了诡异的巨型风暴。这些“异界风暴”的源头是光能者从其陨落帝国废墟中挖掘出的异界尖塔。\n\n光能者的意图不明,但无疑邪恶至极。直捣这个粗制滥造的基地,将其再次夷为平地。", + "OPEN SSSD HATCH": "打开超级固态硬盘舱门", + "CONDUCT MOBILE E-711 EXTRACTION": "移动式提取711元素", + "Turn On": "开启", + "Throw grenade into artificial bug hole": "将榴弹丢进人造虫穴", + "EXTRACT E-711": "提取711元素", + "Deactivate corrupted battery silos": "关闭出错的电池舱", + "Destroy all Harvesters in the area.": "摧毁区域内的所有猎杀器。", + "All assets evacuated. Proceed to extraction.": "全部目标已疏散完毕。开始撤离程序。", + "Illuminate Warp Ships are docked here. Destroy them while they are vulnerable.": "光能者穿梭舰在此停靠。趁它们不备时摧毁穿梭舰。", + "PROTECT LAUNCHERS": "保护发射器", + "Our enemies have forced conflict upon this region. There can be no peace until they are defeated.": "敌军让该地区陷入战火之中。唯有将其击败才能恢复和平。", + "The Automatons are conducting mineral surveys to identify rich ore veins to recklessly exploit. It is critical that we secure those sites first, so that this planet's resources are used responsibly. \n\nExpropriate the coordinates of this region's prospective sites from the Automatons, and extract site samples to assess their potential.": "机器人正在开展矿物勘探,寻找能够供它们肆意开采的富矿脉。我们必须抢先占领这些地点,确保该星球的资源得到合理利用。\n\n从机器人手中没收该地区勘探点的坐标,并提取现场样本,评估开采潜力。", + "Please manually disengage all hatch locks.": "请手动解除所有舱门锁。", + "Locate and eliminate the Automaton Hulk.": "找到并消灭机器人巨型者。", + "Automaton Dropship": "机器人运输舰", + "A SEAF research station in the region has been overrun by Terminids. Their vital work must be recovered.\n\nGet to the station, download the research database, and upload it to the Super Earth mainframe using the nearby Satellite Uplink Station.": "该地区的一座超级地球武装部队研究站已被终结族占领。他们的重要工作必须恢复。\n\n前往该研究站,下载研究数据库,然后使用附近的卫星上行链路站点将其上传至超级地球主机。", + "Larva Container": "幼虫储存器", + "Raising the symbol of Managed Democracy will send an undeniable message that Freedom reigns in this land once more.": "举起象征管理式民主的标志将传递出毋庸置疑的信息:自由精神再次征服这片拓殖地。", + "Eradicated Medium Bug Nest": "已摧毁中型巢穴", + "Access codes for the Planetary Defense Cannon are held at this location.": "行星防御加农炮的访问代码存放在此处。", + "Sabotage the Megafactory's fuel and ammunition depots.": "破坏超大型工厂的燃料和弹药库。", + "INITIATE EMERGENCY BACKUP": "启动紧急备份", + "Use Orbital Precision Strike Stratagem to kill enemies": "使用轨道精准攻击战略配备击杀敌人", + "Use terminal to initiate emergency data backup": "使用终端启动紧急数据库备份", + "HELLDIVERS EXTRACTED": "绝地潜兵撤离数", + "Research Point": "研究点数", + "INITIATE DATA WIPE": "启动数据抹除", + "Moving to drill position...": "移动到钻探位置……", + "STIMS USED:": "治疗剂使用次数:", + "Relay Tower": "中继塔", + "The Prospecting Drill in this location can extract sediment cores, analyze their composition, and upload the generated data.": "这里的勘探钻机可以提取沉积物核心,分析其成分,并上传产生的数据。", + "Find the Illuminate altar": "找到光能者祭坛", + "TRACE LOCAL DEFENSE NETWORK": "追踪本地防御网络", + "Allow shuttles to collect deposited fuel from reserves.": "让运输船从油田采集沉积燃料。", + "The black box must be delivered to the interplanetary uplink site at this location, for encrypted upload to the Ministry of Defense.": "必须将黑匣子转移到该位置的星际上行链路点位,以便加密上传至国防部。", + "BUG HORDE": "虫族群袭", + "SAM Launcher": "地对空导弹发射器", + "KILL BUGS": "击杀虫族敌人", + "Destroy fuel silos": "摧毁燃料仓", + "SILO FULLY CHARGED": "舱体充能完毕", + "ERROR: Communication Tower Offline": "错误:通信塔离线", + "Please access the nearby transmission station to proceed": "请前往附近的传输站继续操作", + "Use Stratagem: #ENTITY": "使用战略配备:#ENTITY", + "Deploy deep behind enemy lines. Certain missions will have severely limited Super Destroyer support.": "深入敌后。部分任务将很难获得超级驱逐舰支援。", + "SEIZE THE CIVILIAN SATELLITE TOWERS": "夺取民用卫星塔", + "RECOVER SSSD": "找回超级固态硬盘", + "BATTERY STORAGE STATION CONSOLE": "电池储存站控制台", + "Investigate and Upload Findings": "调查并上传发现的结果", + "Destroyed Light Automaton Outpost": "已摧毁轻型机器人哨站", + "EXPECTED PAYOUT": "预期收益", + "Wait for Data Jack to deploy": "等待数据接口部署", + "Take down the Harvester": "解决猎杀器", + "Investigate Rogue Research Station": "调查叛变科研站", + "Glorious Sacrifice": "光荣牺牲", + "Emergency Holding Area Terminal System": "应急等待区终端系统", + "An experimental vessel containing 40 grams of weapons-grade Dark Fluid suspended in a magnetic field.": "试验性容器,装载有40克武器级暗液体,悬浮于磁场之内。", + "Downloading research data to SSSD": "正在将研究数据下载到超级固态硬盘", + "Successful Extraction": "成功撤离", + "REDIRECT FUEL FLOW": "更改燃料流向", + "Please stand by.": "请稍候。", + "While most Terminids were killed by the Termicide, some survived and adapted. Now, they threaten to evolve further and take over the entire planet. Every Termicide Dispersion Tower on this planet must be shut down as soon as possible.": "尽管灭虫终结剂消灭了大部分终结族,但是仍有一部分幸存了下来,并且适应了灭虫终结剂。现在,它们甚至有可能进一步进化,占领整颗星球。必须尽快关闭这颗星球上的每一座灭虫终结剂喷洒塔。", + "Hatch opening…": "舱门正在开启……", + "Insert Vessel into Drill": "将容器置入钻机", + "MISSION TIME REMAINING": "任务剩余时间", + "Destroy Automaton infrastructure to cripple their troop production capabilities.": "摧毁机器人的基础设施,削弱它们的军队生产能力。", + "DISRUPT SOCIALIST INDUSTRY": "破坏党同伐异的产业", + "Access Codes": "访问代码", + "DEFENSE NETWORK BREACHED": "防御网络已突破", + "Liberty guides our hand": "解放精神指引我们行动", + "DESTROY AIR BASE CONTROL TOWER": "摧毁航空基地控制塔", + "Com.Mission Inf (Community)": "完成任务的影响力(社区)", + "RETRIEVE ACCESS CODES": "取回访问代码", + "SAMPLES EXTRACTED:": "提取样本数:", + "Verify all readings are within unsafe limits": "确认所有读数都在非安全限度内", + "Enemy ships in reserve: #COUNT": "待部署敌舰数:#COUNT", + "PLEASE EVACUATE AREA": "请撤离该区域", + "Rocket Launch in Progress": "准备发射火箭弹", + "ANNEX QUARRY": "吞并采石场", + "Locate Pump Site": "找到泵机", + "Intel indicates that the Automatons are stockpiling ammunition in this location.": "情报显示机器人正在此地囤积弹药。", + "FUSE 2": "熔断器2", + "The bio-processors here are the first step in synthesis of organic plasma. They must be destroyed.": "这里的生物处理器是合成有机等离子的第一步。必须将其摧毁。", + "REFINERY CENTRAL CONTROL": "精炼厂中央控制", + "MISSION IMPACT": "任务影响", + "Transport SSSD Hard Drive to Communications Relay": "将超级固态硬盘转移至通信中继站", + "Kill all Terminids": "击杀所有终结族", + "SAMPLES EXTRACTED #COUNT": "提取样本数 #COUNT", + "Pick up Secondary Weapon": "拾取次要武器", + "Daily Complete": "完成每日任务", + "Eradicate Void blossoms to combat planetary mutation.": "铲除寂域之花,阻止星球变异。", + "Ready to initiate reloading sequence for M723 Orbital Slag Shell": "即将启动M723轨道熔渣炮弹装填程序", + "Find mining sites identified by the Automatons and extract samples to assess their potential.": "寻找机器人发现的采矿点,提取样本,评估开采潜力。", + "Local communication towers must be located and activated, to enable broadcasts to civilians.": "必须定位并启动本地通信塔,才能向平民进行广播。", + "Free this land from Illuminate occupation.": "把这片土地从光能者的占领中解放出来。", + "Initiate Fire Sequence": "启动开炮进攻程序", + "x#VALUE": "x#VALUE", + "INITIATE PRODUCTION SEQUENCE": "启动生产序列", + "Verify post-landing integrity": "核实着陆后完整性", + "TERMINATE ILLEGAL BROADCAST": "关停非法广播", + "Deactivating...": "正在关闭…", + "REDIRECT FUEL TO NEW TARGET": "更改燃料流向,将其输送至新目标", + "Cognitive Disruption Field detected": "侦测发现感知干扰域场", + "Conduct a geological survey to identify valuable ore veins.": "进行地质调查,寻找珍贵矿脉。", + "We have received reports of the presence of Bile Titans in this region, posing a considerable threat to our operations.\n\nAny specimen encountered must be eliminated before it has a chance to breed.": "我们收到的报告显示,该地区内出没的吐酸泰坦对我们的行动构成了巨大的威胁。\n\n一旦遇到该生物,立即将其消灭,以防其繁殖。", + "DESTROY EGGS": "摧毁虫卵", + "Automaton Dropships are docked at this location.": "机器人运输舰停靠于此地。", + "Intel indicates a massive and covert Automaton industrial undertaking, which the enemy has taken extreme measures to keep hidden. Further intel is located on the ground at this location. Low orbit interdiction weaponry makes prolonged Destroyer deployment impossible. Once deployed, you're on your own.\n\nThis operation is extremely dangerous. But it is imperative we identify the nature and locations of the Automaton scheme.": "情报显示机器人正在秘密开展大规模工业项目,而且已采取极端措施进行隐蔽。在此处的地面上可获取更多情报。低轨道拦截武器使驱逐舰无法长时间部署。一旦部署,接下来就只能靠你们自己了。\n\n此次行动极其危险。但我们必须查明机器人阴谋的性质和地点。", + "POWER CORE": "动力核心", + "ELIMINATE AUTOMATON HULKS": "消灭机器人巨型者", + "COGNITIVE DISRUPTOR": "感知干扰器", + "Deactivate Battery Silo 03": "关闭电池舱03", + "Use door controls to release facility staff from Emergency Bunkers": "使用门控装置将设施中的人员从紧急掩体中放出去", + "Utilize the GATER to extract the mysterious substance from all identified sites.": "使用GATER从所有确认地点提取神秘物质。", + "An SEAF reconnaissance plane was shot down over this region. Its top-secret intel must be recovered immediately, before it can be destroyed by the enemy.": "超级地球武装部队的一架侦察机在这片沦陷的拓殖地被击落。必须立即取回机上的绝密情报,以免被敌人摧毁。", + "REPEL INVASION": "抵御入侵", + "SWITCH 2": "开关2", + "Initiate Data Transmission": "启动数据传输", + "Locate and destroy Illuminate Warp Gateways.": "寻找并摧毁光能者传送门。", + "This Control Tower is the nexus of enemy aerial operations in the region.": "该控制塔是敌方在此区域空中作战的指挥中枢。", + "An SEAF recon aircraft has been downed by the invaders mid-mission. Recover the aircraft's data drives before they are destroyed.": "一架超级地球武装部队侦察机在执行任务期间被入侵者击落。必须在侦察机的数据驱动器被毁前将其找回。", + "Input launch code: #OTHER": "输入发射代码:#OTHER", + "ALERT: ENCRYPTED TRANSMISSION RECEIVED\n\nDECRYPTING…\n.\n.\n.\nCLASSIFICATION: TOP SECRET\n\nMINISTRY OF DEFENSE\nDIRECTORATE OF HELLDIVER READINESS\nORIGINATING STATION: UNDISCLOSED LOCATION\n\nMEMORANDUM FOR: Helldiver Readiness Command\nSUBJECT: Daily Incoming Recruit Report\n\nTotal Incoming Trainees: 48,736\nAvg. Age (Years): 18.7 \nAvg. Combat Readiness Rating: 27.1%\nAvg. Patriotism Rating: 97.4%\n\nExpected Survival Rate: 21.3% \nProjected Helldiver Production: WITHIN QUOTA\n\nEND TRANSMISSION": "警告:接收到加密传输\n\n正在解密……\n.\n.\n.\n级别:绝密\n\n国防部\n绝地潜兵备战理事会\n发出站:机密位置\n\n备忘录收件人:绝地潜兵备战指挥部\n主题:新兵招募每日报告\n\n受训新兵总数:48,736\n平均年龄(岁):18.7\n平均备战评分:27.1%\n平均爱国评分:97.4%\n\n预期存活率:21.3%\n绝地潜兵计划产量:配额内\n\n结束传输", + "A Terminid Nursery has been identified beneath the surface at this location. Millions of Terminid larvae gestate in the underground chambers.\n\nTerminid Nurseries consist of one or more Nursery Chambers. Use the Hive Breaker Drill to deliver a nuclear extermination device to each one.": "此位置地底下发现了终结族繁育窝。数百万只终结族幼虫正在地下腔室中孵化。\n\n终结族繁育窝由数量不等的繁育腔室组成。使用虫窝破裂者将核灭绝装置送入各个腔室。", + "Pick up the AR-23 Liberator": "拾取AR-23“解放者”", + "Com.Mission Inf (Max)": "完成任务的影响力(最大)", + "ACTIVATE DRILL": "启动钻机", + "Deactivate Stratagem Jamming?": "是否停止干扰战略配备?", + "An abandoned SEAF Mobile Radar is located here. It can provide key information on the local area.": "这里有台被遗弃的超级地球武装部队移动雷达。可以从中获取当地区域的关键情报。", + "Prepare and launch the ICBM.": "做好准备工作,发射洲际弹道导弹。", + "RADAR": "雷达", + "Illuminate Warp Ships have docked at this location. Destroy them.": "光能者穿梭舰已在此处停靠。消灭它们。", + "to Discharge Dark Fluid": "释放暗液体", + "The Exospire rising from these ruins is defiling the atmospheric integrity of the planet. \nIt is protected by a force field that blocks access to its core chamber. Electromagnetic interference may hinder Stratagem usage.\n\nBreach the Exospire's defenses, and destroy its core to trigger its collapse.": "这座从废墟中拔地而起的异界尖塔正在玷污星球大气的完整性。\n它受到力场的保护,通向其核心密室的路径被这一力场所封锁。电磁干扰可能会阻碍战略配备的使用。\n\n突破异界尖塔的防御,通过摧毁其核心促使其坍塌。", + "Wait for generator diagnostics sequence to complete": "请等待发电机诊断程序完成", + "Use terminal to raise surface-to-air launcher": "使用终端抬升地对空导弹发射器", + "Ready to Fire Orbital Cannon. Find target using adjacent control terminal": "准备启动轨道加农炮。利用邻近控制终端寻找目标", + "Repel the Illuminate contingent attacking this planet.": "击退正在攻打这颗星球的光能者分遣队。", + "SQUAD PAYOUT": "小队收益", + "Aerial scanning has identified high levels of Automaton production in this area.": "空中扫描确认该区域存在大量机器人生产活动。", + "MORTAR EMPLACEMENT": "迫击炮台", + "Activate Artillery Terminal": "启动大炮终端", + "Oil pumps activating": "油泵正在启动", + "To limit Terminid population growth, we must strike at their mature hives.\n\nActivate a dormant ICBM silo on the planet to wipe out massive concentrations of bugs at once.": "为了限制终结族种群数量增长的速度,我们必须袭击它们成熟的虫窝。\n\n启动这颗星球上一座暂停使用的洲际弹道导弹发射井,瞬间抹除多个大型虫族聚居地。", + "This building has been overrun by Terminids and is now a Shrieker breeding ground.": "这栋建筑已被终结族攻陷,现在成为了尖啸虫的繁殖之地。", + "An Illuminate Harvester is located in this area. Find it and destroy it.": "此区域有光能者猎杀器。找到它,并将其摧毁。", + "ESTABLISHING CONNECTION": "正在建立连接", + "Artillery Activation Required": "需要启动大炮", + "ESTABLISHING NETWORK LINK": "正在建立网络连接", + "EVACUATE CITIZENS": "疏散公民", + "HIGH-VALUE TARGETS": "高价值目标", + "Drill Status: Damaged": "钻机状态:受损", + "LiDAR Tower currently lowered.": "激光雷达塔现已降下。", + "50% of Objectives Completed": "达成50%的目标", + "Eradicate the specified number of Terminids and Terminid nests.": "消灭指定数量的终结族及其巢穴。", + "DEPLOY DARK FLUID": "部署暗液体", + "Insufficient fuel": "燃料不足", + "Load Fusion Batteries into Cargo Container": "将聚变电池装入货物集装箱", + "The TCS is ready. Secure this planet from the bugs forevermore.": "TCS准备就绪。让这颗星球永远免受虫害。", + "FACILITY OPERATION INACTIVE": "设施无法操作", + "DESTROY FREIGHTERS": "摧毁货轮", + "DRILLING IN PROGRESS": "正在钻探", + "ACTIVATE TCS+ STATION": "启动TCS+站", + "SECURE TACTICAL VIDEO CAMERA": "获取战术摄像机", + "#COUNT [SC]": "#COUNT [SC]", + "The Automatons have gained ground in this city, constructing a network of Fabricators which allow them to replicate extremely rapidly.\n \nTheir locations have been identified. We must strike now before they self-replicate out of control.": "机器人在这座城市中夺得了一席之地,建立起构筑者网络,大幅提高了增殖速度。\n\n它们的位置已确定。我们必须立即行动,防止敌人失控地自我增殖。", + "Stratagem Jamming Inactive": "战略配备干扰程序停止", + "This fueling station is offline. It must be reactivated to initiate fuel distribution.": "这座燃料站已停止运转,需重新启动才能恢复燃料输送。", + "ACCESS RESTRICTED": "禁止访问", + "Free trapped citizens and escort them to evacuation.": "释放受困公民,护送他们前往撤离点。", + "Stand clear of parts being raised": "离开正在抬升的部件", + "DEPLOY THUMPER": "部署地下发射器", + "Cannon operation can damage hearing.": "加农炮操作会损伤听力。", + "ELIMINATE HULK": "消灭巨型者", + "Please adjust all indicated valves.": "请按提示调整所有阀门。", + "Automaton Gunships are being manufactured in this area.": "这个地区在制造机器人炮舰。", + "STATUE": "雕像", + "Colonists who escaped Illuminate abduction and mind control—likely the most patriotic and steadfast of their demographic—are trapped in emergency shelters. The enemy is closing in; without rescue, they are doomed.\n\nTransport ships are inbound, but the evacuation zone is under enemy control. The Helldivers are the colonists' only hope.": "逃离了光能者的囚禁及其精神控制的拓殖地居民(可能是该群体中最爱国、最坚定的人)现在困于紧急避难所中。敌人正在逼近,如果不实施营救,这些居民恐怕连性命也保不住。\n\n运输舰即将抵达,但撤离区域仍受敌人管控。绝地潜兵是拓殖地居民的最后一丝希望。", + "This square is lined with statues of tyrants and war criminals, hailed by the Cyborgs as visionaries.": "这个广场上矗立着暴君和战犯的雕像,生化人却把他们奉为远见卓识之士。", + "DEATHS:": "阵亡次数:", + "Unknowable Forces": "未知力量", + "Engines": "引擎", + "Initiate Firing Sequence": "启动发射程序", + "Activate Battery Silo 03": "启动电池舱03", + "Use Prospecting Drill to retrieve first sample": "使用勘探钻机取得第一份样本", + "EXTRACT RESEARCH PROBE DATA": "提取研究探测仪数据", + "Terrain Scan will reveal nearby locations": "地形扫描可显示附近的地点", + "WARNING: STATION INOPERABLE": "警告:站点无法运转", + "REPEL INVASION FLEET": "击退入侵舰队", + "REACTIVATE POWER GENERATOR": "重新启动发电机", + "ACTIVATE DATA TERMINAL": "启动数据终端", + "EXHAUST SYSTEM NORMAL": "排气系统正常", + "Aim Orbital Cannon": "瞄准轨道加农炮", + "NUKE NURSERY CHAMBER": "用核武器炸毁繁育腔室", + "Log in to the probe interface": "登录探测仪界面", + "BRIEFCASE": "公文包", + "ILLUMINATE ARTIFACT": "光能者古物", + "XP Awarded": "奖励经验", + "The Illuminate are invading our loyal, prosperous, peaceful colony, seeking to turn our citizens into Voteless abominations and create strange energy fields for some unknown, un-Democratic purpose. They must be stopped.": "光能者准备入侵我们忠诚、繁荣、和平的拓殖地,企图将我们的公民变为无票者那样的怪物,然后创造奇怪的能量场,以满足它们非民主的不明目的。必须阻止它们。", + "SSSD HARD DRIVE": "超级固态硬盘", + "EXTRACT ANOMALOUS MATERIAL": "提取异常物质", + "Refinery products are shipped for further processing via freighters docked here. Destroy them.": "精炼厂的产品通过停靠此处的货轮运往后方进行深加工。摧毁它们。", + "Restock ammo": "补充弹药", + "Extract with tactical video camera": "携带战术摄像机撤离", + "Please don't touch moving parts": "请勿触碰活动部件", + "Illuminate Harvesters are patrolling this city block. Seek and destroy the roaming menace.": "光能者猎杀器正在该城区巡逻。搜寻并歼灭这股游荡的敌人。", + "High-value intel of the enemy's plans is hard-coded onto devices that high-confidence intel indicates is located at this location. \n\nInfiltrate the site, acquire the intel, and extract with it in your possession.": "有关敌军计划的高价值情报已通过硬编码写入设备中,可靠情报显示,该设备就在此处。\n\n潜入现场,获取情报,并携带情报撤离。", + "Fortification Class": "防御工事等级", + "KEYCARD": "钥匙卡", + "Enemy defenses in this area make prolonged Super Destroyer deployment impossible for certain missions. Be prepared to operate with severely limited Super Destroyer support.": "该区域敌方防线坚挺,在部分任务中,超级驱逐舰无法长时间部署。请做好无法获得超级驱逐舰支援的准备。", + "Use terminal to complete takeover": "使用终端完成占领", + "Deposit any SSSD Hard Drives in receiving dock": "将全部超级固态硬盘存放到接收码头", + "Destroy Terminid Spore Spewer": "摧毁终结族孢子喷涌虫", + "Activate Liberated terminal": "启动已经解放的终端", + "Destroy the Shrieker Nest": "摧毁尖啸虫巢穴", + "TACTICAL VIDEO CAMERA": "战术摄像机", + "UPLOAD SAMPLE DATA?": "是否上传样本数据?", + "Log in to Shuttle Bay Terminal": "登录运输船坞终端", + "RAISE DISH": "抬升天线", + "Operate Data Jack terminal": "操作数据接口终端", + "A heavily reinforced Automaton convoy is expected to cross through this region. Intercept and destroy the convoy before it leaves the mission area.": "重装强化的机器人车队预计将穿越该区域。在车队离开任务区域之前将其拦截并摧毁。", + "No Reinforcement Pods available": "暂无增援舱。", + "Locate broadcast tower": "找到广播塔", + "Destroy Spore Spewers to allow our citizens to breathe Freely.": "摧毁孢子喷涌虫,让我们的公民能够自由呼吸。", + "BLACK BOX": "黑匣子", + "Repel the Illuminate invaders before they can do whatever it is they are doing.": "在光能者采取任何举动之前将它们驱逐。", + "Retrieve and transmit the vital research data.": "检索并传输关键研究数据。", + "BATTERY SILO 02": "电池舱02", + "An Automaton invasion fleet is attacking this planet.\n\nWe must repel the invading forces before it is too late!": "机器人的侵略舰队正在攻打这颗星球。\n\n我们必须及早击退侵略势力!", + "ELIMINATE BROOD COMMANDER": "消灭虫族指挥官", + "SEAF Combat Botanists have confirmed: the Illuminate are seeding Void-altered blossoms to reshape this world's ecosystem. Their alien pollen contaminates native flora through cross-pollination, spreading a toxin that gradually mutates the entire planet.\n\nThis bioengineered sickness must be cut off at its roots. Eradicate every single one of these flowers.": "超级地球武装部队战斗植物学家证实:光能者正在播撒因寂域而变异的花种,试图重塑该星球的生态系统。这些异星花粉正通过异花授粉污染本地植物,传播一种会令整颗星球逐渐变异的毒素。\n\n必须将这种生物工程病害斩草除根。铲除每一朵寂域之花。", + "Planetary Defense Cannon rearming…": "行星防御加农炮正在装弹……", + "Com.Mission Inf (Start)": "完成任务的影响力(初始)", + "EXPLORE THE GLOOM": "探索“阴霾”", + "Locate and destroy Automaton Fabricators.": "寻找并消灭机器人构筑者。", + "Hellpods will be deployed to this location upon mission launch. Due to the Super Destroyer's absence, normal reinforcement will be unavailable. \n\nSecuring this site will give access to additional reinforcements, who will deploy directly from this location.": "任务开始时,绝地喷射舱将部署至此位置。因超级驱逐舰不在场,无法获得常规增援。\n\n占领此地点可获得额外增援,增援力量将直接部署到此处。", + "We must show the galaxy that even in the face of oppression, Freedom remains defiant. \n \nInfiltrate behind Automaton lines and raise our Flag as an unassailable beacon of Liberty.": "我们必须让整个银河系都知道,纵使面对压迫,自由仍傲然不屈。\n\n潜入机器人的防线后方,升起我们的旗帜,犹如树立起一座坚不可破的解放灯塔。", + "A dense Terminid swarm is located here. Eradicate it.": "这里聚集着终结族虫群。彻底消灭它们。", + "Find Factory Strider": "寻找移动工厂", + "Reload": "装填弹药", + "DEPLOY NUCLEAR PAYLOAD": "部署核炸药", + "Select systems to sabotage": "选择要破坏的系统", + "Orbital-range cannons in this Megafactory are suppressing our Super Destroyers—a clear violation of war conventions.\n\nThis tactical imbalance will not go unaddressed. Destroy every Counter-Orbital Cannon within the perimeter.": "这所超大型工厂内的轨道射程炮正在压制我方超级驱逐舰,这公然违反战争公约。\n\n我们必须纠正这种战术上的劣势。摧毁区域内所有反轨道加农炮。", + "Retrieve the Flag of Super Earth": "取回超级地球旗帜", + "SSSD": "超级固态硬盘", + "Electrical": "电力", + "Interplanetary Data Transmission Ready": "星际数据传输就绪", + "This planet is believed to contain valuable ores, but intense Terminid activity (and elevated mortality rates for civilian geologists) have so far hindered surveying efforts.\n\nActivate the Prospecting Drill to collect soil sample data and verify the planetary composition.": "据悉,这颗星球拥有珍贵的矿藏,但是由于终结族频繁活动(同时平民地质学家死亡率上升),我们的调查工作一直困难重重。\n\n启动勘探钻机,收集土壤样本数据,核实这颗星球的构成成分。", + ">> BLOCKED <<": ">> 受阻 <<", + "LEVEL UP REWARD": "升级奖励", + "Close Door": "关门", + "A massive Terminid Nursery has been discovered here, crawling with millions of freshly-hatched larvae, mere weeks from ravenous adulthood. They must be wiped out, before they reach maturity and kill innocent human children.\n\nTerminid Nurseries consist of one or more Nursery Chambers. Use the Hive Breaker Drill to deliver a nuclear extermination device to each one.": "我方发现此处存在一个巨大的终结族繁育窝,聚集着上百万只刚刚孵化的幼虫,只需几周,它们便能成长为贪婪的成虫。必须将它们铲除,以免其育成并残害无辜的儿童。\n\n终结族繁育窝由多个繁育腔室组成。使用“虫窝破裂者”钻机将核试验设备送至每一个腔室。", + "BACK UP EMERGENCY DATABASE": "备份紧急数据库", + "Prepare your defenses.\n\nTime left until automatic initiation begins: #TIME": "做好防御准备。\n\n自动启动程序倒计时:#TIME", + "DEMOCRATIZE THE VOID": "民主解放寂域", + "Select designated coordinates in grid": "选择网格中的指定坐标", + "Use terminal to initiate launch": "使用终端,下令发射", + "Call in your Super Destroyer, enabling the usage of stratagems for a limited time. One use per mission.": "呼叫超级驱逐舰,启用战略配备,限时生效。每次任务使用一次。", + "ALERT: INCOMING FUEL BLOCKED": "警告:燃料输入路径受阻", + "Activating this generator will supply critically-needed power to SEAF devices in the region.": "启动这台发电机可以为超级地球武装部队在该地区的设备提供急需的能源。", + "Seize the Automaton industrial complex in the name of Managed Democracy.": "以管理式民主之名占领机器人工业联合体。", + "TARGET NETWORK COORDINATES": "定位网络坐标", + "Evacuation shuttle en route": "疏散运输船即将抵达", + "An Orbital Cannon is located here. Infiltrate the site and use a Hellbomb to destroy it.": "轨道加农炮就位于此处。潜入此地点,使用地狱火炸弹将其摧毁。", + "PREPARING AREA SCAN": "准备启动区域扫描", + "DANGER - ENEMY PRESENCE": "危险 - 进入敌人势力范围", + "Protect our way of life from the Terminids by any means necessary.": "不惜一切代价也要捍卫我们的生存之道,不能让终结族损害半分。", + "Raise signal strength to 100%": "将信号强度提高至100%", + "Elapsed time on surface": "行星地表历时", + "SABOTAGE ORGO-PLASMA SYNTHESIS": "破坏有机等离子合成", + "Use terminal to unlock Control Chamber": "使用终端解锁控制室", + "NUKE NURSERY": "用核武器炸毁繁育窝", + "GUIDANCE": "制导", + "This colony is occupied by the Illuminate invaders. It must be freed.": "此拓殖地被入侵的光能者所占领。必须解放这里。", + "Pick up Stims from Injury Simulator": "从损伤模拟器中拾取治疗剂", + "PORTABLE COMMS RELAY": "便携式通信中继站", + "NEUTRALIZE GROUND-TO-ORBIT DEFENSES": "瘫痪地对轨道防御系统", + "Kill Illuminate forces to reduce their numbers.": "击杀光能者部队,削减它们的数量。", + "DESTROY AUTOMATON COMMAND BUNKER": "摧毁机器人指挥碉堡", + "There are millions of kilometers of Terminid tunnels beneath the surface of this planet. A detailed subterranean mapping is necessary to identify critical targets.\n\nUtilize a repurposed Prospecting Drill to collect samples of the infested mantle. Analyses will identify properties of local Terminid structures.": "这颗星球地表下有长达数百万公里的终结族通道。需要进行细致的地下测绘确定关键目标。\n\n使用改装过的勘探钻机收集被侵染地幔的样本。通过分析即可确定当地终结族结构的特性。", + "Incriminating evidence recorded": "已录下罪证", + "This Hive World produces Gloom spores deep within the extensive Terminid cave networks. They are also the sole known source of extremely valuable E-711.\n\nNothing is more important than freeing our citizens from the threat of the Gloom. The acquisition of E-711 is also the top priority for galactic security. Your orders are clear.": "这个虫窝世界在纵深复杂的终结族洞穴网络里生产“阴霾”孢子。它们也是极为珍贵的711元素唯一已知的来源。\n\n眼下最重要的是让我们的公民摆脱“阴霾”的威胁。获取711元素也是确保银河系安全的首要任务。指令十分明确。", + "Destroy mutated Terminid eggs": "摧毁变异终结族虫卵", + "Take back this city from its illegal occupants.": "夺回这座城市,驱逐非法入侵者。", + "Drill into the Terminid Hive to analyze its composition.": "钻入终结族虫窝分析其组成结构。", + "Drilling in progress...": "正在钻探……", + "Cull the Terminids' foul brood and their odious progenitors.": "剿灭终结族可憎的幼虫和虫族始祖。", + "RAISE LIDAR TOWER?": "升起激光雷达塔?", + "The Illuminate's insidious schemes to subvert Managed Democracy are futile. Even in the most unfree depths of the Void, Liberty shall reign supreme over tyranny.\n\nTopple their monoliths and hoist the Flag of Super Earth. Let it stand as an eternal beacon of Light against the Void's fleeting darkness.": "光能者企图颠覆管理式民主的阴险诡计注定徒劳无功。即使在最不自由的寂域深处,自由亦将凌驾于暴政之上。\n\n推倒光能者巨石,升起超级地球的旗帜。让这面旗帜成为永恒的光明灯塔,照耀着寂域短暂的黑暗。", + "DESTROY COMMAND BUNKERS": "摧毁指挥碉堡", + ">> UNLOCK <<": ">> 解锁 <<", + "Infiltrate Automaton territory and destroy their fuel and munitions stockpiles.": "潜入机器人领地,销毁其库存燃料和弹药。", + "Manually realign the satellite tower": "手动重新对齐卫星塔", + "The downed SEAF aircraft is located here. Its black box contains crucial intel.": "被击落的超级地球武装部队飞行器就位于此处。它的黑匣子内存有关键情报。", + "RESTORE AIR QUALITY": "恢复空气质量", + "Destroy Automatons": "摧毁机器人", + "Load weapon": "给武器装弹", + "ACTIVATE OIL PUMPS": "启动油泵", + "A downed recon plane is crashed here. Its data is stored in a black box somewhere amongst the wreckage.": "被击落的侦察机在此处坠毁。存有数据的黑匣子就在坠毁点附近。", + "Wait for reroute to complete": "等待完成重新路由", + "A remote SEAF research station in this region remains structurally intact despite the Void's illegal planetary annexation. Data collected before and after the planet's fall is of critical importance to our efforts to understand this lawless realm.\n\nAccess the station, download the research database, and upload it to the Super Earth mainframe.": "尽管寂域非法吞并星球,该地区一座偏远的超级地球武装部队研究站仍然结构完好。该星球陷落前后收集到的数据,对于我们了解寂域这一法外之地至关重要。\n\n前往该研究站,下载研究数据库,然后将其上传至超级地球主机。", + "CHART TERMINID TUNNELS": "绘制终结族隧道网络", + "A SEAF Reconnaissance aircraft was just shot down at this site. The aircraft had identified critical intelligence of enemy force allocations. \n\nInfiltrate the area and secure the black box containing the intel.": "超级地球武装部队的一架侦察机刚刚在此地被击落。该侦察机发现了敌军兵力部署的关键情报。\n\n潜入该区域,取回存有情报的黑匣子。", + "DRIVE VEHICLE TO DROP-OFF LOCATION": "驾驶载具到降落地点", + "Use Upload Data stratagem to begin upload": "使用“上传数据”战略配备,开始上传", + "RAISE LAUNCHER": "抬升发射器", + "This facility contains unpatriotically produced research data, and must be razed to the ground.": "该设施产生的研究数据有违爱国精神,必须将其夷为平地。", + "#RACE PRESENCE": "#RACE势力", + "Activate Prospecting Drill": "启动勘探钻机", + "Backpack": "装有化学武器的背包", + "The Automaton offensive has taken this area, leaving one of our top secret research stations surrounded by the enemy.\n\nUse your clearance to unlock the emergency bunker doors, and defend the facility staff as they transfer to the evacuation shuttle.": "机器人的部队已经占领了这个地区,我们的绝密研究站被敌人包围。\n\n使用你的权限打开紧急掩体的门,将该设施中的人员转移到疏散运输船,并在这个过程中保卫他们的安全。", + "Station active": "站点已启动", + "Hatch ready for opening": "舱门随时可以开启", + "RAISE PLANETARY DEFENSE CANNON": "抬升行星防御加农炮", + "Terminids in this region threaten Freedom in a variety of ways, each more despicable than the last. They must be stopped.": "该地区的终结族不择手段地威胁着我们的自由,使出的手段越发卑鄙。我们必须阻止它们。", + "Kill Terminids to thin their numbers.": "击杀终结族,削减它们的数量。", + "Defend Freedom": "捍卫自由", + "Collecting sample": "正在收集样本", + "The missile launch code disk was left at a base in this region.": "存有导弹发射代码的磁盘遗落在该地区的一座基地里。", + "START UPLOAD AT TRANSMISSION STATION": "在传输站开始上传", + "UPLOAD ESCAPE POD DATA": "上传逃生舱的数据", + "Deactivate the battery silos to shut down the dispersion of Termicide.": "关闭电池舱,停止喷洒灭虫终结剂。", + "Recover top-secret intel from a downed SEAF reconnaissance aircraft.": "从被击落的超级地球武装部队侦察机找回绝密情报。", + "Gloom spores suffuse the planet's atmosphere from the ground to the exosphere. Scattered LiDAR towers can be used to measure the density and composition of Gloom spores.\n\nActivate the towers, download their data, and transmit it off-planet using the local relay station.": "从地面到外逸层,“阴霾”孢子充斥着整个星球的大气层。各地的激光雷达塔可以测量“阴霾”孢子的密度和构成。\n\n启动激光塔并下载数据,利用当地中继站将数据传输至星球外。", + "Open Door": "开门", + "Evacuate the area": "撤离该区域", + "Bug Extermination": "歼灭虫族", + "The extractors over this massive repository of crude oil have ceased functioning and must be re-activated.": "这里储存着大量原油,但采油机已停止运转,需重新启动。", + "SWITCH 4": "开关4", + "Beware of blinding blizzards and deep snow.": "小心阻挡视线的暴风雪和深厚的积雪。", + "DARK FLUID VESSEL": "暗液体容器", + "Activate the Drilling Platform and ensure the successful extraction of E-711.": "启动钻机平台并确保成功提取711元素。", + "Superior Valor": "卓越勇士", + "EXTRACT ORGANIC PLASMA": "提取有机等离子", + "Honorable Duty": "忠于使命", + "THREAT LEVEL: MAXIMUM": "威胁等级:最高", + "Illuminate forces have encroached upon a region believed to contain rich mineral deposits. If valuable resources do exist here, the enemy cannot be allowed to bend them towards their despotic schemes.\n\nDeploy the Prospecting Drill and collect soil samples to verify the site’s value.": "光能者部队已经入侵据称蕴藏着丰富矿产的地区。若此地确实蕴藏着宝贵资源,绝不能任其沦为敌人推进专制企图的工具。\n\n部署勘探钻机并采集土壤样本,核实此地的开发价值。", + "OPPORTUNITY MISSION": "机遇任务", + "EXTERMINATE TERMINIDS": "消灭终结族", + "Please input activation sequence": "请输入启动程序", + "TARGETING": "锁定目标", + "Destroy Automaton Detector Tower": "摧毁机器人探测塔", + "LAUNCHERS ACTIVE": "发射器已启动", + "Launch site inoperable. Proceed to extraction.": "发射点无法正常运行。开始撤离程序。", + "Activate the Planetary Defense Cannon and use it to bring down the Illuminate Overship.": "启动行星防御加农炮,击沉光能者统御舰。", + "Manually disengage all silo hatch locks": "手动解除所有发射井舱门锁", + "Restore functionality to the pump site.": "使泵机区恢复运作。", + "OPERATION MODIFIER REMOVED": "已移除行动限制条件", + "Enemy Quantity": "敌人数量", + "Planetary scanning has revealed a number of Automaton supply bases, hidden deep behind their defensive lines.\n\nInfiltrate quickly and destroy their stockpiles before they can mount a concerted defense.": "星球扫描发现机器人有多座补给基地隐藏在防线深处。\n\n迅速潜入敌方腹地,在它们组织起有效的防御之前销毁它们的库存物资。", + "Lock the fuel hose to the transfer pump": "将燃料软管锁定在输送泵上", + "KILLS:": "杀敌数:", + "The Illuminate have laid false claim to this city, besmirching our streets with more of their despotic monoliths. \n \nDeploy to the city, raze the enemy's totalitarian monuments, and raise the Flag of Super Earth to restore hope to our citizens.": "光能者以不义之名占领这座城市,立起更多专制的巨石,玷污我们的街道。\n\n前往城市,摧毁敌人极权主义的象征,升起超级地球旗帜,重燃公民的希望。", + "A Gazer Spire surveys the surrounding area from this vantage point.": "一座凝视者尖塔从此处制高点监视着周边区域。", + "Several districts of this Megafactory contain supplies that fuel the Automatons' radicalized war machine.\n\nBreach their supply depots and destroy their stockpiles.": "这所超大型工厂内多个区域存储的物资正在为机器人的激进战争机器提供补给。\n\n突破敌方补给库,摧毁它们的物资储备。", + "Mineral analysis complete": "矿物分析完成", + "Truly Exceptional Heroism": "非凡英杰", + "ELIMINATE BROOD COMMANDERS": "消灭虫族指挥官", + "ANTI-AIR EMPLACEMENT": "防空炮台", + "Use terminal to complete sabotage": "使用终端完成破坏", + "Kill Illuminate Overseers": "击杀光能者的监视者", + "PERFORMING SYSTEMS CHECK...": "正在执行系统检查…", + "SQUAD IMPACT #INFLUENCE": "小队影响力 #INFLUENCE", + "There are crucial oil reserves in this area needed to fuel our continued war effort.\n\nNavigate the Terminid swarm, reactivate the pumps, and transfer the fuel to the waiting transport shuttles.": "这块区域内的油田对于支撑我们的长线战争至关重要。\n\n绕开终结族虫群,重新启动泵机,将燃料转移到待命的运输船上。", + "Priming Seismic Probe": "地震探测仪正在准备", + "Bring each of the three battery silos online to activate this TCS+ station.": "启动全部三个电池舱,即可启动这座TSC+站。", + "PLATINUM BAR": "铂金条", + "Surveillance suggests a Brood Commander is in this location.": "监控显示,虫族指挥官正位于此处。", + "A Ground All-Terrain Extraction Rig (GATER) has been deployed to this area, where multiple E-711 reservoirs have been identified.\n\nYou have been summarily certified as Expert Large Vehicle Operators. Deploy to the area and utilize the GATER to extract E-711 from all identified locations.": "此区域已部署地面全地形采集钻机(GATER),也已确认存在多个711元素储藏点。\n\n仓促间你已被授予大型载具驾驶专家的资格。请部署到该区域并使用GATER从所有确认地点提取711元素。", + "Automaton troops are mass produced daily in the bowels of this Megafactory, then deployed in service of the Cyborgs' senseless expansionism.\n\nDisrupt their industry of death. Destroy their fabricators one by one.": "在这所超大型工厂深处,每天都在批量生产机器人的部队,随后被部署并服务于生化人毫无意义的扩张主义。\n\n瓦解敌人的死亡工业。逐一摧毁它们的构筑者。", + "INFILTRATE ILLUMINATE LAIR": "潜入光能者巢穴", + "We have identified a number of heavily-guarded bunkers in this region. We suspect they contain Command Nodes central to linking in to the Automaton Transmission Stream.\n\nDestroy the bunkers, and cut the bots off from the flow of information.": "该地区内发现有多座防备森严的碉堡。我们怀疑其中存在连接机器人数据传输流的重要指挥节点。\n\n摧毁这些碉堡,切断机器人的信息传输。", + "TCS+ ACTIVATION TERMINAL": "TCS+启动终端", + "Please keep limbs away from moving drill parts": "四肢请勿靠近钻机的活动部件", + "A new, highly dangerous Terminid Variant has decimated SEAF units in this area. We must limit the spread of this mutant strain. \n\nFind and eradicate the Variant. Exercise extreme caution.": "一种极其危险的新型终结族亚种在该区域重挫了超级地球武装部队。我们必须限制该突变种扩散。\n\n找到并铲除该亚种。务必谨慎行事。", + "SYSTEM ERROR": "系统错误", + "REINFORCEMENT PODS": "增援太空舱", + "BATTERY SILO 01": "电池舱01", + "Activate the Drilling Platform and ensure the successful extraction of the E-710-like substance.": "启动钻机平台并确保成功提取类似710元素的物质。", + "Input code to authorize ejection": "输入代码,授权弹出", + "Repel the Automaton invasion fleet attacking this planet.": "击退正在攻打这颗星球的机器人侵略舰队。", + "To curb Terminid population growth, we must strike at their vile hatcheries.\n\nFind and destroy all Terminid eggs in the area before the enemy has a chance to react.": "为了抑制终结族种群数量增长的速度,我们必须袭击它们可恨的孵化点。\n\n迅速行动,找到并摧毁该区域内所有终结族虫卵,不给它们反击的机会。", + "Power up Battery Silos": "为电池舱供电", + "PAYLOAD SITE": "投放点", + "Drive the Automatons off this planet.": "将机器人逐出这颗星球。", + "RETURN TO AREA": "返回区域", + "MELEE KILLS:": "近战击杀数:", + "THREAT LEVEL: HIGH": "威胁等级:高", + "Data Jack Status: Stable": "数据接口状态:稳定", + "The Automatons have gained ground in this region, constructing a vast network of Fabricators which allow them to replicate extremely rapidly.\n\nWe have detected a narrow window of maintenance, giving us a chance to strike at their facilities. Destroy all that you can.": "机器人在该地区内夺得了一席之地。它们建立起庞大的构筑者网络,大幅提高了增殖速度。\n\n我们侦测发现短暂的维护窗口期,这是发动突袭的宝贵时机。尽可能摧毁一切。", + "OBTAIN COORDINATES": "获取坐标", + "Find Terminid Charger": "找到终结族强袭虫", + "Deactivate Battery Silo 02": "关闭电池舱02", + "BLITZ": "闪电战", + "Deploy into the Exostorm and shatter the Exospires that sustain it.": "部署至异界风暴内部,粉碎维持风暴运作的异界尖塔。", + "Release the fuel hose": "卸除燃料软管", + "Illuminate forces have aggregated in vast numbers in this region. We must seize this tactical opportunity to annihilate them while they remain clustered.\n\nEliminate the squids and their monstrous congregation. Kill as many as possible.": "光能者部队已在该地区内大量集结。我们必须抓住这一战术窗口,趁其集结之时将其一举歼灭。\n\n消灭那些鱿鱼及其丑陋的聚群。尽可能消灭光能者。", + "SEARCH AND DESTROY": "搜寻并摧毁", + "Jammer deactivated": "干扰装置已关闭", + "ERROR - MANUAL ALIGNMENT REQUIRED": "错误,需要手动对齐", + "Secure the black box from a crashed weather reconnaissance aircraft and transmit the data off-planet.": "从坠毁的气象侦察机中取出黑匣子,并将数据传输至星球外。", + "CALIBRATE VOLTAGE": "校准电压", + "UNDISCLOSED LOCATION": "机密位置", + "Eliminate Hulk": "消灭巨型者", + "Find Automaton Devastators": "找到机器人蹂躏者", + "B. Silo 01": "电池舱01", + "Gallantry Beyond Measure": "无上英雄", + "SEAL BUG HOLES": "封闭虫穴", + "Find and eliminate the Terminid Variant.": "找到并消灭终结族亚种。", + "BATTERY SILO 03": "电池舱03", + "Descend upon Cyberstan and free it from the Cyborgs' oppressive grip once and for all.": "降临生化斯坦,将这个星球从生化人的压迫统治中彻底解放出来。", + "The Terminids have stolen highly valuable specimens of enemy larvae and eggs. Recover them.": "终结族偷走了极为珍贵的敌方幼虫样本和虫卵样本。请把样本找回来。", + "Reload Artillery": "为大炮装填弹药", + "CONDUCT GEOLOGICAL SURVEY": "开展地质调查", + "Find Automaton Hulk": "找到机器人巨型者", + "Costly Failure": "惨痛失利", + "COLLECT MINERAL DATA": "收集矿物数据", + "Establish connection to SEAF network": "与超级地球武装部队网络建立连接", + "Regulate engine output in Control Chamber": "在控制室调节引擎输出", + "Extract with SSSD": "携带超级固态硬盘撤离", + "Once acquired, bring the footage to this location for secure extraction.": "获取录像后,将其运至此处进行安全撤离。", + "Database downloading": "数据库正在下载", + "Use drill interface to deploy Nuclear Payload": "使用钻机界面部署核炸药", + "Find the downed SEAF recon aircraft": "找到被击落的超级地球武装部队侦察机", + "Proceed to Graduation Chamber and become a Helldiver": "前往毕业礼堂,成为绝地潜兵", + "Return to terminal and force-start unit": "返回终端并强制启动装置", + "Activate Battery Silo 01": "启动电池舱01", + "Production of new Cyborgs requires a bio-synthetic process conducted in massive production units. They are structurally blastproof, but can be destroyed from within by exploiting the volatile hydrogen fuel used in the process.\n\nFlood the Production Unit with hydrogen, then destabilize its integrity until it fails safe and self-destructs.": "生产新的生化人需要在大型生产单元中进行生物合成工序。生产单元的结构可抵御爆炸,但可以利用工序中使用的易燃氢燃料从内部将其摧毁。\n\n向生产单元灌入过量氢气,然后破坏其结构稳定性,直至触发故障保护机制并自毁。", + "CLEANSE INFESTED DISTRICT": "净化侵染区域", + "Drill Status: Critically Damaged": "钻机状态:严重受损", + "Disrupt production of organic plasma and secure samples of the liquid for further analysis.": "破坏有机等离子的生产过程,获取液体样本供进一步分析。", + "SAMPLE 02": "样本02", + "The Cyborgs have assembled a large detachment of Automatons in this sector. They must be dismantled, before they march upon our homes and leave orphans in their wake.\n\nTheir numbers must be thinned. Destroy as many as possible.": "生化人已在该分区集结了大批机器人部队。必须将它们通通拆解,不能让它们进军我们的家园、造成无数孤儿寡母的惨况。\n\n必须削减敌方兵力。尽可能消灭敌人。", + "INTELLIGENCE REPORT": "情报汇报", + "DATA PACKAGES DELIVERED (#COUNT / #TARGET)": "已交付的数据包(#COUNT / #TARGET)", + "The Automatons are using augmented cannons with high-orbit reach to bombard our Super Destroyers.\n \nWe cannot allow our aerospace superiority to be challenged. Deploy to the area and destroy any active Counter-Orbital Cannons.": "机器人正在使用具有高轨道射程的增强型加农炮轰击我方的超级驱逐舰。\n\n我方的空天优势不容挑战。部署到该区域,摧毁所有还在运行的反轨道加农炮。", + "QUELL EXOSTORM": "平息异界风暴", + "Extract with the Specimens": "携带样本撤离", + "Massive Automaton factories in this region are fueling their advance. They must be destroyed.\n\nThis dormant ICBM silo is beyond their range of detection; launch a devastating strike before they can mount a defense.": "该地区的大型机器人工厂为机器人的推进行动提供了源源不断的动力。必须将其摧毁。\n\n这座暂停使用的洲际弹道导弹发射井位于它们的探测范围之外。在它们构筑防线之前发动毁灭性打击。", + "Use terminal to establish communication with Super Destroyer": "使用终端与超级驱逐舰建立通信", + "Calibrate LiDAR tower alignment": "校准对齐激光雷达塔", + "PRIMARY OBJECTIVES": "主要目标", + "Destroyed Medium Automaton Outpost": "已摧毁中型机器人哨站", + "An arcane Illuminate device at this location is creating a mind-disruption field, filling one's mind with un-Democratic thoughts that make it difficult to think or push Stratagem codes properly.": "这个地点有件神秘的光能者设备创造出了干扰思维的域场,令人的大脑塞满不民主的思想,进而难以思考,也难以正确输入战略配备代码。", + "Efforts to expand into the Gloom are underway. The Helldivers must support these efforts through data collection and resource extraction.": "我们正在向“阴霾”区域扩张。绝地潜兵必须通过收集数据和开采资源提供支援。", + "RETRIEVE MUTANT LARVA": "取回变异幼虫", + "Redirect fuel to Transfer Station": "更改燃料流向,将其输送至中转站", + "TOWER MISALIGNED": "卫星塔方向偏离", + "INTERCEPT CONVOY": "拦截车队", + "Flag": "旗帜", + "DISTANCE TRAVELED:": "行军距离:", + "Pressure": "压力", + "Reroute command path to override automaton control.": "更改命令路径,夺取机器人的控制权限。", + "#CURRENT / #TARGET Rockets": "#CURRENT / #TARGET火箭弹", + "Please clear front of surface-to-air launcher": "请离开地对空导弹发射器的正面", + "DETECTOR TOWER": "探测塔", + "#COUNT/#TOTAL objectives completed": "达成#COUNT/#TOTAL的目标", + "This location has been strategically chosen to maximize the flag's inspirational impact.": "这个位置经过精心选择,目的是最大限度地发挥旗帜鼓舞人心的力量。", + "A compact comms relay hub that can be effortlessly deployed on demand.": "小巧的通信中继站,可按需轻松部署。", + "The citizens are safe for now, trapped inside emergency bunkers. They must be released and escorted to the facility's shuttle bay for extraction.": "困在紧急掩体里的公民们暂无危险。你必须把他们放出来,护送至该设施的运输船坞,帮助他们撤离。", + "RETRIEVE THE BLACK BOX": "取回黑匣子", + "LOCK TARGET COORDINATES": "锁定目标坐标", + "SWITCH 5": "开关5", + "Defend the evacuation of top-secret military assets.": "护送绝密军事资产撤离。", + "DESTROY HARVESTER": "摧毁猎杀器", + "ERROR: MANUALLY ADJUST BLOCKED VALVES": "错误:请手动调整受阻阀门", + "#SECONDS REMAINING UNTIL LOADOUT!": "武装配置还剩#SECONDS!", + "Open Shuttle Bay Door": "打开运输船坞门", + "The enemy is closing in on a cache of high-value assets that have been sequestered since the First Galactic War. We cannot allow them to be captured.\n\nThe enemy will be alerted to your position as soon as the evacuation process is initiated. Defend the site until all assets have been safely transported off-planet.": "敌人正逼近一批自第一次星系战争以来一直处于封存状态的高价值目标。我们不能让其落入敌人魔爪。\n\n撤离程序一旦开始,敌人就会注意到你的位置。保卫阵地,直到所有目标安全运离星球。", + "CALIBRATE PROBE": "校准探测仪", + "Destroy mutated Terminid eggs and deactivate the Termicide Dispersion Tower to prevent any further mutations.": "摧毁变异终结族虫卵,关闭灭虫终结剂喷洒塔,预防终结族进一步变异。", + "Calibrate voltage to maximize output": "校准电压,将输出提升至最大", + "WORLD LIBERATED": "解放的星球", + "ELIMINATE ANNIHILATOR TANK": "消灭湮灭坦克", + "#COUNT Samples Extracted": "已提取#COUNT份样本", + "VARIANT ERADICATION": "铲除亚种", + "Clear area of enemies (#REMAINING Remaining)": "肃清敌方区域(还剩#REMAINING)", + "Shuttle Bay System": "运输船坞系统", + "Complete Helldiver Obstacle Course": "完成绝地潜兵障碍训练", + "Destroy Illuminate Warp Gates": "摧毁光能者传送门", + "ERADICATE VOID BLOSSOMS": "清除寂域之花", + "DESTROY SPORE SPEWER": "摧毁孢子喷涌虫", + "Locate the Spore Lung underground": "在洞穴中搜寻孢肺", + "Activate Jammer Terminal": "启动干扰装置终端", + "Strange Illuminate monoliths seem to be creating fields of negative energy. We do not understand their purpose or their true nature. That is why they must be destroyed.": "古怪的光能者巨石似乎创造出了负能量的域场。我们不知道巨石的目的,也不清楚其中的性质。所以只能将它们全部摧毁。", + "#CURRENT / #TOTAL kills": "#CURRENT / #TOTAL次击杀", + "Please stand clear of platform.": "请远离发射平台。", + "SSA Radar has identified a fleet of Illuminate invasion ships descending upon this sector from the close orbit. They intend to seize control of the area in an aerial blitz.\n\nYou are the last line of defense. Destroy all enemy ships as quickly as possible.": "SSA雷达侦测到光能者入侵舰队正从近地轨道登陆该分区,企图通过空中闪电战夺取区域控制权。\n\n你是最后一道防线。迅速摧毁所有敌舰。", + "Manually disengage all hatch locks": "手动解除所有舱门锁", + "SHOTS HIT:": "命中次数:", + "ANOMALOUS MATERIAL EXTRACTED": "已提取异常物质", + "Destroy the Illuminate Monolith": "摧毁光能者巨石", + "BATTERY SILO ACTIVATING": "电池舱正在启动", + "TRANSFER OIL TO SHUTTLE": "将油输送至运输船", + "ACCIDENTALS:": "意外阵亡次数:", + "Please Log In": "请登录", + "EJECT HARD DRIVE": "弹出硬盘", + "FLOOD HYDROGEN PIPELINE": "灌注氢气管道", + "Rerouting Turret Control...": "正在变更炮台控制路径…", + "SUPPRESS TOXIC POLLINATION": "遏制毒素授粉", + "Use Machine Gun Stratagem to call in Support Weapon": "使用机枪战略配备,呼叫支援武器", + "Secondary Objectives Completed": "达成次要目标", + "#NAME LIBERATED": "成功解放#NAME", + "HELLPOD LAUNCH IMMINENT!": "绝地喷射舱即将发射!", + "Locate and eliminate the Automaton Factory Strider": "找到并消灭机器人移动工厂。", + "Crushing": "破碎", + "Stable": "稳定", + "Transmission to Super Earth Mainframe in progress": "正在向超级地球主机进行传输", + "Killed Hive Lord": "击杀霸王虫", + "Use the Cannon to shoot down the Overship": "使用加农炮,击沉统御舰", + "ACQUIRE EVIDENCE": "获取证据", + "Tower supports demolished": "塔巢支撑结构已摧毁", + "CONDUCT MOBILE SUBSTANCE EXTRACTION": "移动式提取物质", + "Activate the Battlefield Injury Simulator": "启动战场损伤模拟器", + "A Nursery Chamber is located here, ripe with millions of feeding larvae who tunneled here after hatching on the surface. Use the Hive Breaker Drill to deliver a nuclear payload and wipe them out.": "此处有一个繁育腔室,其抚育着数百万只在地表孵化后就钻入地下觅食的幼虫,使用“虫窝破裂者”钻机将核炸药送入腔室,将幼虫铲除。", + "This city is under attack. It cannot be allowed to fall to the forces of oppression.": "这座城市遇袭。绝不能让它落入压迫者之手。", + "Activate Mobile Radar": "启动移动雷达", + "Radar scans of this region have detected anomalous subsurface readings. By analyzing the signatures of extracted material, we can trace their source of origin and uncover the path to our final destination within the Void.\n\nYou have been authorized one GATER, already deployed. Use it to extract anomalous material from all indicated sites.": "该地区的雷达扫描检测到异常的地下读数。通过分析提取物的特征,我们就能寻踪溯源,找到通往寂域内部最终目的地的路线。\n\n你已获准使用一台已部署的地面全地形采集钻机。使用这台地面全地形采集钻机从所有已标记地点提取异常物质。", + "RESTART PUMPS": "重启泵机", + "INTEL EXTRACTED": "获取情报", + "Please stand by": "请稍候", + "INITIATING ARTILLERY SYSTEM": "正在启动大炮系统", + "Kill Automatons to reduce their numbers.": "击杀机器人,削减它们的数量。", + "Silo Status: Unstable": "舱体状态:不稳定", + "Reload Orbital Shell": "装填轨道炮弹", + "FREQUENCY ALIGNMENT": "校准频率", + "AA EMPLACEMENT": "防空炮台", + "Locate and destroy Terminid structures.": "找到并摧毁终结族虫窝结构。", + "Destroy the Exospire to suppress the growing Exostorm.": "摧毁异界尖塔,平息越发狂躁的异界风暴。", + "Automaton Horde": "机器人群袭", + "DELIVER ANY SSSD HARD DRIVES": "运送所有超级固态硬盘", + "The Gloom may be compounded by the Terminid scum overrunning the planet's surface.\n\nWipe the region clean of all Terminid presence, including their fetid nests.": "由于可憎的终结族在星球上四处肆虐,“阴霾”可能会愈发猖獗。\n\n清除该区域的所有终结者,包括它们臭气熏天的巢穴。", + "CONFIRM SCAN AREA": "确认扫描区域", + "Satellite imagery confirms that the Automatons are operating a fuel depot in this area.": "卫星图像证实机器人在该区域内有一座正在运作的燃料库。", + "Cleared Light Illuminate Encampment": "已摧毁光能者轻型营地", + "Periodic sandstorms pose a significant threat to visibility.": "周期性沙尘暴会严重影响能见度。", + "Deploy to the unknown Hive World and reclaim it in the name of Super Earth.": "前往未知的虫窝世界部署行动,以超级地球之名收复要地。", + "Destroy the Illuminate's strange and unnatural spacecraft.": "摧毁光能者古怪的飞行器。", + "OPTIONAL OBJECTIVES": "可选目标", + "EXTRACTION SUCCESSFUL": "撤离成功", + "LIDAR STATION": "激光雷达站", + "CONDUCT MOBILE EXTRACTION": "移动式提取", + "[ DATA FOUND ]": "[ 已找到数据 ]", + "collect the data disc": "收集数据磁盘", + "ACTIVATE UPLINK": "启动上行链路", + "DEMOLISH CYBORG ASSEMBLY UNIT": "摧毁生化人的组装单元", + "GROUND ALL-TERRAIN EXTRACTION RIG": "地面全地形采集钻机", + "Inside this towering facility, Cyborgs are grown in pod-like artificial wombs.": "在这座高耸的设施内部,生化人在舱形人造子宫中完成培育生长。", + "Move closer to objective": "移动至离目标更近的位置", + "Login required": "需要登录", + "SWITCH 3": "开关3", + "EVACUATE PRIORITY CITIZENS": "疏散优先级公民", + "Chemical Backpack": "装有化学武器的背包", + "BAY DOOR CONTROL": "坞门控制", + "Searching for problems. Please wait.": "正在查找问题。请稍候。", + "Eliminate Charger": "消灭强袭虫", + "Load Platinum Bars into Cargo Container": "将铂金条装入货物集装箱", + "Invading Illuminate forces have unleashed Harvesters upon the city. These intolerant machines patrol the streets in this area, devastating once-peaceful neighborhoods and murdering innocent civilians. Destroy them, and reclaim control of this sector.": "入侵的光能者部队已在城市投放猎杀器。这些偏狭的机器正在该区域的街道巡逻,摧毁曾经安宁的社区,屠杀无辜平民。消灭它们,夺回该分区的控制权。", + "Joint Operation": "联合行动", + "LOG IN": "登录", + "Input Access Code: #OTHER": "输入访问代码:#OTHER", + "DESTROY INFESTED TOWER": "摧毁侵染塔巢", + "Destroy buildings within the Megafactory": "摧毁超大型工厂内的建筑", + "Large quantities of eggs are located in this area. Use any means necessary to destroy them.": "该区域内发现大量虫卵。使用一切必要手段将它们摧毁。", + "Tune probe to lock onto signal": "调节探测仪,锁定信号", + "Calibrating seismic sensor array": "正在校准地震传感器阵列", + "The recon aircraft is located here. Its precious black box must be recovered.": "侦察机位于此处。必须取回机上珍贵的黑匣子。", + "Input code to authorize access": "输入代码,授权访问", + "ORGANIC PLASMA FLOW BLOCKED": "有机等离子流受阻", + "Fire Artillery Command": "开炮指令", + "Multiple opportunities to disrupt the enemy's opaque and sinister machinations have been identified in this region. Illuminate forces are highly concentrated here; expect significant resistance. \n \nDisrupt their schemes and restore peace to this area.": "在该地区发现多个可挫败敌人阴谋诡计的良机。光能者部队在此处重兵集结;我方预计将遭遇敌人的顽强抵抗。\n\n挫败光能者的阴谋,恢复该地区的安宁。", + "Destroy all facility buildings": "摧毁设施内的所有建筑", + "COLLECT GLOOM SPORE READINGS": "收集“阴霾”孢子数据", + "Initiate off-planet evacuation of high-value assets, and defend the site until evacuation is complete.": "启动高价值目标撤离星球的程序,并保卫阵地,直至撤离完成。", + "CHECK ALL SUB-SYSTEMS": "检查所有子系统", + "Input code to raise satellite tower": "输入代码以抬升卫星塔", + "CRITICAL SYSTEM FAILURE": "系统严重故障", + "ALL SYSTEMS OPERATIONAL": "所有系统均正常运行", + "DESTROY MONOLITH": "摧毁巨石", + "DELIVER CARGO TO THE PICKUP POINT": "将货物送到聚集点", + "INVALID DROP POINT": "无效降落点", + "ELIMINATE CHARGERS": "消灭强袭虫", + "JOINT OPERATION": "联合行动", + "Transport Black Box to Communications Relay": "将黑匣子转移至通信中继站", + "Extract with Intel Package": "携带情报包裹撤离", + "SPORE SPEWER": "孢子喷涌虫", + "Destroy the Megafactory's Counter-Orbital Cannons.": "摧毁超大型工厂的反轨道加农炮。", + "CONFISCATE ASSETS": "没收资产", + "Please manually load all shells": "请手动装填所有炮弹", + "Turret reload sequence initiated...": "炮台装弹程序已启动…", + "ENEMY BIO-PROCESSORS": "敌方生物处理器", + "Protect our citizens' E-711 interests from Terminid despoilment.": "保护我们公民的711元素利益免遭终结族破坏。", + "ELIMINATE VARIANT": "消灭亚种", + "Test w/ Above Settings": "测试上述设置", + "A dense swarm of Terminids has amassed in this region.": "有大量终结族聚集在这个地区。", + "INPUT ACCESS CODE": "输入访问代码", + "TECTONIC DRILL": "地壳钻机", + "Open hatch to deliver SSSD": "打开舱门运送超级固态硬盘", + "Find Variant": "找到亚种", + "MAIN OBJECTIVES": "主要目标", + "BATTERY DISPERSAL INTERFACE": "电池分配界面", + "LOCAL TERMINAL": "本地终端", + "Activate the TCS+ station to cleanse this area of Terminids.": "启动TCS+站,清除该区域的终结族。", + "Gloom-infested planets appear to have more extensive hive patterns than normal.\n\nDeploy Seismic Probes to collect scans of their tunnel networks, then use a local relay station to upload the data to a Ministry of Science hub.": "在受“阴霾”侵蚀的星球上,虫窝的散布范围似乎比普通星球更广泛。\n\n部署地震探测仪,收集隧道网络的扫描数据,再利用当地中继站将数据上传至科学部中心。", + "Firing sequence initiated": "发射程序已启动", + "Proceed to Reinforcement Training Area": "前往增援训练区", + "The TCS created several fissures in the planet's crust in this area. A Drill stratagem can be used to deploy Dark Fluid payloads in these locations.": "这片区域内,星球的地壳因TCS而出现了一些裂缝。钻机战略配备可以用于在这些地点部署暗液体。", + "Conduct a geological survey to assess planetary composition.": "开展地质调查,评估星球的构成成分。", + "E-711": "711元素", + "Log in to Jammer Terminal": "登录干扰装置终端", + "Find Terminid Bile Titan": "找到终结族吐酸泰坦", + "CENTRAL NETWORK": "中央网络", + "We have located a key facility in the Automaton's mining operations. Platinum ore is extracted, refined, and shipped to other facilities for further processing. \n\nThese assets have been deemed forfeit to the Federation. Seize them.": "我们已找到机器人采矿作业的关键设施。它们在此开采和加工铂金矿石,然后运往其他设施进行深加工。\n\n这些资产已认定为归联邦所有。夺取它们。", + "The Illuminate have invaded this region and promptly raised a blasphemous monolith as a symbol of their occupation. We must show the galaxy that even in the face of oppression, Freedom remains defiant. \n \nTear down their tyrannical emblem, and raise our Flag as an unassailable beacon of Liberty.": "光能者入侵了该地区,并迅速立起了一块亵渎性的巨石作为占领标志。我们必须让整个银河系都知道,纵使面对压迫,自由仍傲然不屈。\n\n推倒它们暴政的象征,升起我方旗帜,犹如树立起一座坚不可摧的解放灯塔。", + "SHUTTLE LEAVING WITH VEHICLE": "运输船已带着载具离开", + "There is reason to believe this facility holds undeniable proof of socialist war crimes. Weapons of mass destruction, breaches of interstellar humanitarian law, unspeakable threats to our citizens. Held deep behind enemy lines.\n\nYou must bring the truth to light. Infiltrate the site and obtain footage of this wrongdoing. Our citizens must see the true face of the enemy.": "我方有理由相信这座设施内有敌方战争罪行的确凿证据。大规模杀伤性武器、违反星际人道主义法、对我方公民构成不可言说的威胁,全都深藏于敌后。\n\n你必须揭露真相。潜入现场并录下他们的罪行。必须要让我们的公民看清敌人的真面目。", + "This heavily-guarded bunker is thought to contain a vital Command Node for the Automaton Transmission Stream.": "据悉,这座防备森严的碉堡中可能有机器人数据传输流的重要指挥节点。", + "COLLECT ENCRYPTED HARD DRIVE": "收集加密硬盘", + "STATION INOPERABLE": "站点无法运转", + "COMMS RELAY HUB": "通信中继站", + "The encrypted drives were abandoned at these coordinates.": "加密硬盘被遗弃在这些坐标处。", + "A nest of flying Shriekers has been reported in this area.": "这个地区内发现飞空尖啸虫的巢穴。", + "The Spore Lung is located deep within this Terminid tunnel complex.": "孢肺位于这个终结族地下网络通道的深处。", + "#COUNT XP TO NEXT LEVEL": "升到下一等级还需要#COUNT经验", + "FREE THE CITY": "解放城市", + "Use terminal to wipe sensitive data": "使用终端抹除敏感数据", + "Disrupt the Illuminate's opaque and sinister machinations in this region.": "挫败光能者在该地区的阴谋诡计。", + "Override Turret Control": "夺取炮台控制权限", + "This planet was purged of the Gloom at great cost. Now, a Terminid outbreak threatens to mutate it into a festering Hive World once again. Our ethically sourced E-711 deposits and the lives of hard-working pump inspectors are imperiled.\n\nYou must stop the bugs from despoiling what we have rightfully secured. Do not let this planet sink back into the Gloom.": "这颗星球曾为肃清“阴霾”付出巨大的代价。现在,一场终结族暴乱使其再次面临沦为腐化巢窝世界的威胁。我们以道德方式采集的711元素,以及辛勤工作的泵机督察员的生命都将危在旦夕。\n\n必须阻止这些害虫破坏我们正大光明取得的一切。绝不能让这颗星球再次深陷“阴霾”。", + "The Terminid Control System is complete. All across the planet, Termicide Dispersion Towers await activation. This planet won't be completely immunized from the Terminids until every single Tower is activated.": "终结族遏制体系业已建成,遍布星球的灭虫终结剂喷洒塔只待启动。必须启动每一座喷洒塔才能让终结族彻底从这颗星球上消失。", + "ACTIVATE DRILL 2?": "是否启动2号钻机?", + "Welcome to Voragon Systems Generic Military Terminal.": "欢迎使用沃瑞肯系统通用型军用终端。", + "Warning: Stay Clear of Launchers": "警告:请远离发射器", + "Move GATER to indicated drill sites": "将地面全地形采集钻机移至已标记的钻探点", + "TIMES REINFORCING:": "增援次数:", + "Eliminate Terminids underground": "消灭地下的终结族", + "ELIMINATE IMPALER": "消灭穿刺虫", + "BUNKER HATCH LOCKED": "掩体舱门未解锁", + "CALL IN SUPER DESTROYER": "呼叫超级驱逐舰", + "We have received credible reports of brutal Automaton Hulks in the region. Destroying them would weaken the Automaton command structure.\n\nLocate the Hulks, and eliminate them.": "据可靠消息称,该地区内存在着残暴的机器人巨型者。将其摧毁可以削弱机器人的指挥结构。\n\n找到巨型者,将其消灭。", + "Planetary scanning has identified a vast assemblage of Automaton troops in this region. This may be in preparation for an offensive on nearby Super Earth installations.\n\nYou must reduce their numbers—kill as many bots as you can.": "星球扫描的结果显示,该地区聚集有大量的机器人士兵。它们或许正在准备进攻附近属于超级地球的设施。\n\n你必须削减其数量——尽可能击杀更多机器人。", + "OIL PUMP CONTROL SYSTEM": "油泵控制系统", + "Use the Hive Drill to destroy all subterranean Terminid structures in the area.": "使用虫窝钻机摧毁该地区内所有终结族地下结构物。", + "Community Rewards": "社区奖励", + "VERIFY TRANSFER AT TERMINAL": "在终端验证传输", + "Missile fueling in progress": "正在为导弹添加燃料", + "Purge site of Terminid Matter": "抹除目标地点内的终结族物质痕迹", + "Concrete, undeniable evidence of unspeakable Automaton atrocities are located here. Capture them with the tactical video camera so the truth can be brought to light.": "证明机器人暴行的确凿证据就在此处。用战术摄像机录下证据,让真相大白于天下。", + "The cache of high-value assets is located here. Fortify your defenses, then initiate evacuation and defend the site until evacuation is complete.": "高价值目标的隐匿之处就在这里。加强防御然后开始撤离,并保卫此处,直至撤离完成。", + "SHUTTLE BAY": "运输船坞", + "RAISE TOWER": "升起信号塔", + "SEAF SAM-SITE": "超级地球武装部队地对空导弹基地", + "This Nuclear Missile travels over long distances at high speeds, to strike before the enemy has time to retreat or retaliate.": "这枚核导弹能以极快的速度击中超远距离外的目标,不给敌人撤退或反击的机会。", + "Illuminate Artifact": "光能者古物", + "FUSE 4": "熔断器4", + "ELIMINATE OVERSEERS": "消灭监视者", + "Orbital infrared scans have detected the waste heat of an Automaton Factory Strider in this region. If it is allowed to persist, the planet will be overrun with mechanical monstrosities before long.\n\nEnd it.": "轨道红外线在该区域内扫描发现一名移动工厂的余热。如果放任不管,这颗星球迟早会被机械怪物攻陷。\n \n终结它。", + "Interact with the main terminal": "与主终端交互", + "ELIMINATE BILE TITANS": "消灭吐酸泰坦", + "Eliminate Impaler": "消灭穿刺虫", + "RECEIVE SCAN DATA": "接收扫描数据", + "Use Resupply Stratagem to call in supplies": "使用重新补给战略配备,呼叫补给物资", + "SWITCH 1": "开关1", + "SEAF in this region have reported sightings of Chargers exhibiting dangerous new mutations.\n\nThese specimens must be eliminated before their mutant strain spreads.": "该地区的超级地球武装部队报告称,发现强袭虫表现出危险的新型突变属性。\n\n必须在突变种扩散之前将其消灭。", + "Rapidly clear the area": "迅速肃清该区域", + "Eliminate Factory Strider": "消灭移动工厂", + "Use terminal to commandeer refinery": "使用终端接管精炼厂", + "Root out the Terminid infestation on this planet.": "彻底清除侵袭这颗星球的终结族。", + "Collect the #ENTITY": "收集#ENTITY", + "Package Progress": "包裹进度", + "SYSTEM PROCESSING...": "系统正在处理…", + "Orbital infrared scans have detected a Factory Strider in this area.": "轨道红外线在该区域内扫描发现一名移动工厂。", + "Use terminal to eject SSSD Hard Drive": "使用终端弹出超级固态硬盘", + "PREVENT SPIRE GROWTH": "阻止虫塔繁殖", + "Choking fog and torrential rainfall can affect sight range.": "令人窒息的浓雾和暴雨会影响视野能见度。", + "RAISING MISSILE - PLEASE WAIT": "正在抬升导弹高度,请稍候", + "CHECK MEMORY ADDRESS": "检查存储器地址", + "Use terminal to raise Planetary Defense Cannon": "使用终端抬升行星防御加农炮", + "The Exospire is located here. Its power core is housed in a subterranean chamber at its base.": "异界尖塔矗立于此。其动力核心位于底部的地下密室中。", + "DESTROY STOCKPILED AMMUNITION": "摧毁库存弹药", + "Cleared Heavy Illuminate Encampment": "已摧毁光能者重型营地", + "Transferring data from SSSD": "从超级固态硬盘传输数据", + "This is a potential platinum-rich site identified by the Automatons. Take a site sample to determine its viability.": "这是机器人发现的潜在富铂金矿点。采集现场样本,确定开采价值。", + "HATCH OPEN": "舱门已打开", + "Repel the fleet of invading Illuminate ships before they can seize control of the area.": "在敌人夺取该区域之前,击退入侵的光能者舰队。", + "FUSE 3": "熔断器3", + "Call down a Hellbomb to destroy the Gazer Spire": "呼叫地狱火炸弹摧毁凝视者尖塔", + "The antenna responsible for the local Automaton Transmission Stream is thought to be located here.": "据悉,机器人的本地数据传输天线应该就在这里。", + "UPLOAD DATA VIA LOCAL RELAY": "通过当地转接设备上传数据", + "Destroy Antenna transmitters": "摧毁天线发射器", + "This area is overgrown with noxious blossoms that spread the Void's taint.": "该区域长满了散播寂域污秽的毒花。", + "Call in a large container to load up with liberated goods for secure extraction.": "呼叫大型集装箱,装载解放物资以便安全撤离。", + "Deploy to the Supercolony, call down the Dark Fluid Vessel, and insert it at each of the payload sites to help destroy the planet.": "部署至超级拓殖地,呼叫暗液体容器,然后将其注入各投放点,准备摧毁该星球。", + "Planetary Defense Cannon in lowered position.": "行星防御加农炮处于收起状态。", + "The Automatons' grip on this planet has been greatly weakened. We must press the advance now, before they have a chance to bolster their forces.\n\nAs Helldivers, you can reach their last holdouts and deal the final blow, to drive them off this planet for good.": "机器人对这颗星球的掌控已经大幅减弱。我们必须立刻向前推进,不给它们喘息之机。\n\n作为绝地潜兵,你们可以奔袭最后的顽固分子,给予它们致命一击,将其彻底逐出这颗星球。", + "Be advised that you will shortly expire if you are reading this": "注意,读到这条消息意味着你命不久矣", + "Coordinates of potential ore strains, identified by the Automatons, are located here. Seize them.": "机器人发现的潜在矿脉坐标情报就在此处。夺取坐标。", + "Destroy statues within the Megafactory": "摧毁超大型工厂内的雕像", + "1ST": "第1", + "Destroy Stalker Lair": "摧毁追踪虫巢穴", + "DISRUPT VOID": "扰乱寂域", + "Flag raising": "升起旗帜", + "Activate the communications relay": "启动通信转接程序", + "STRATAGEMS USED:": "战略配备使用次数:", + "Validate data checksum to confirm data integrity": "验证数据校验和,确认数据完整性", + "Near-Total Victory": "几近全胜", + "Find ammo shells and load into artillery gun": "找到炮弹,将其装入大炮", + "MOBILE RADAR": "移动雷达", + "Oil Extractor": "采油机", + "CAPTURE BUG TERRITORY": "占据虫族领地", + "Adjust all valves to maximize hydrogen flow": "调节所有阀门,使氢气流量达到最高", + "Match security grid pattern": "匹配安全网格图案", + "STRATAGEM JAMMER": "战略配备干扰装置", + "Manually disengage hatch locks": "手动解除舱门锁", + "This tower will summon Bot Dropships if intruders are detected.": "探测到入侵者后,这座塔将呼叫机器人运输舰。", + "Call down a Hellbomb and use it to destroy the monolith": "呼叫地狱火炸弹摧毁巨石", + "OIL EXTRACTORS ACTIVATING": "采油机正在启动", + "Use terminal to log in to research database": "使用终端登录研究数据库", + "Capture evidence of Illuminate atrocities": "收集光能者暴行证据", + "Evacuate civilians trapped deep within the Terminid swarm.": "疏散被困在终结族虫群深处的平民。", + "MISSILE CONTROL SYSTEM": "导弹控制系统", + "SILO HATCH UNLOCKED": "发射井舱门已解锁", + "Destroy Access Node": "摧毁接入节点", + "COLLECT BLACK BOX": "收集黑匣子", + "Move through Highly Realistic Battlefield Simulator": "通过高度逼真的模拟战场", + "DEPLOY SIGNAL PROBE": "部署信号探测仪", + "Activate all charges to trigger overload": "激活所有充电装置以触发过载", + "Pick up grenades": "拾取榴弹", + "Search for the target in the indicated map area": "接近目标区域", + "Find the hard disk containing the Launch Codes.": "找到存有发射代码的硬盘。", + "Worthwhile Sacrifice": "死得其所", + "DATA TRANSMISSION": "数据传输", + "SPECIMEN CASE": "样本箱", + "Use drill interface to deploy sterilizing agent": "使用钻机界面部署灭菌剂", + "SCOUR SURFACE": "肃清地表", + "Find and eradicate all Impalers in the region.": "找到并铲除该地区所有穿刺虫", + "LiDAR Tower activating": "激光雷达塔正在启动", + "OBJECTIVE LOCATION UNKNOWN": "目标位置未确认", + "A cache of cutting-edge fusion batteries are located here. They are made with stolen materials. Seize them.": "这里存有一批尖端聚变电池。它们是用盗取的材料制造而成的。夺取电池。", + "Tighten all exhaust pipe clamps": "紧固所有排气管管夹", + "UPLOAD BLACK BOX DATA": "上传黑匣子数据", + "Operate deep in enemy territory to uncover what vast operation the Automatons want to keep out of Liberty's sight.": "深入敌方领地,调查机器人试图瞒过自由锐眼的大规模行动。", + "JOINT OPERATION AVAILABLE": "可参与的联合行动", + "Deactivate Battery Silo 01": "关闭电池舱01", + "The Ground All-Terrain Extraction Rig (GATER) is located here.": "地面全地形采集钻机(GATER)在这里。", + "System override successful": "成功取得系统权限", + "RETRIEVE RECON CRAFT INTEL": "取回侦察机情报", + "Track down and eliminate the Charger.": "追踪并消灭强袭虫。", + "The Terminid swarm has descended on this planet and threatens to infest it.\n\nWe must repel this vile incursion before it is too late!": "终结族虫群涌入这颗星球,企图将其占领。\n\n我们必须及早挫败它们邪恶的入侵行动!", + "SABOTAGE SUPPLY BASES": "破坏补给基地", + "TAKE DOWN OVERSHIP": "击沉统御舰", + "Sabotage Automaton air capabilities in the region.": "破坏机器人在该地区的空运能力。", + "Use terminal to calibrate generator voltage": "使用终端,校准发电机电压", + "Use terminal to upload virus": "使用终端上传病毒", + "ERADICATE TERMINID SWARM": "彻底清除终结族虫群", + "Drilling in progress": "正在钻探", + "SELECT DATA MODULE FOR UPLOAD": "选择上传数据模块", + "FRIENDLY FIRE DAMAGE:": "友军误伤造成伤害:", + "Reloading": "正在装填炮弹", + "STALKER LAIR": "追踪虫巢穴", + "A massive Terminid Nursery has been discovered here, crawling with millions of freshly-hatched larvae, mere weeks from ravenous adulthood. They must be wiped out, before they reach maturity even if we must sacrifice the city to do so.\n\nTerminid Nurseries consist of one or more Nursery Chambers. Use the Hive Breaker Drill to deliver a nuclear extermination device to each one.": "我方发现此处存在一个巨大的终结族繁育窝,聚集着上百万只刚刚孵化的幼虫,只需几周,它们便能成长为贪婪的成虫。为避免它们育成,必须将它们全部铲除,即使要牺牲整座城市也在所不惜。\n\n终结族繁育窝由数量不等的繁育腔室组成。使用虫窝破裂者将核灭绝装置送入各个腔室。", + "Eradicate Void Blossoms in the area": "清除该区域的寂域之花", + "Main Refinery Components Listed": "已列出主要精炼厂组件", + "You will deploy to the surface of the Supercolony in vicinity of former TCS nodes, where the crust has been weakened. Once on the surface, call down the Dark Fluid Vessel and deliver it to each Payload site.\n\nThe Supercolony is like nothing you have deployed to before. Expect extreme resistance. All of Super Earth is counting on you.": "你将部署至超级拓殖地的地表,靠近以前TCS节点的位置,该处的地壳较为薄弱。一旦降落,立即呼叫暗液体容器,并将其运送至各投放点。\n\n超级拓殖地不同于你们曾经战斗过的任何战场,你们可能会遭遇极端反抗。超级地球一切都靠你了。", + "Level-Up Reward": "升级奖励", + "A group of Class-A citizens are stranded at a priority evacuation port. We cannot leave these patriots to be slaughtered by the Terminids.\n \nGet to the port and secure the evacuation of as many civilians as can fit aboard the designated transport shuttle.": "一组A级公民被困在优先级疏散港口。我们不能让这些爱国者为终结族所残杀。\n\n前往港口,确保让尽可能多的平民登上指定运输船进行疏散。", + "Transmit data burst": "传输数据冲压包", + "RECOVER SCIENTIFIC SPECIMENS": "找回科学样本", + "Use terminal to complete TCS+ activation": "使用终端完成TCS+激活", + "ENABLE OIL EXTRACTION": "设法采油", + "EXTRACT WITH #ENTITY": "携带#ENTITY撤离", + "A dense nest of Stalkers has been sighted in this area.": "这个地区内发现有大量追踪虫聚居的巢穴。", + "SHOTS FIRED:": "开火次数:", + "DESTROY DROPSHIPS": "摧毁运输舰", + "RAISING SURFACE-TO-AIR LAUNCHER": "正在抬升地对空导弹发射器", + "SEAF Combat Engineers have deployed a Rapid Modular Drilling Platform above a pool of E-711 within the Terminid caves. High Terminid activity has made the area extremely dangerous and made extraction impossible.\n\nDeploy to the Hive World and manually activate the Rig. Protect the extraction process until the E-711 is safely airlifted away.": "终结族洞穴深处有整整一池的711元素,超级地球武装部队战斗工程师已在其上方部署了快速模块化钻机平台。终结族活动频繁,导致该区域变得异常危险,提取难度极大。\n\n前往虫窝世界并手动激活钻机装置。提取过程中要捍卫阵地,保护711元素安全空运离开。", + "Destroy Stratagem Jammer": "摧毁战略配备干扰装置", + "SYSTEM BOOTING": "系统正在启动", + "Transfer in progress": "正在输送", + "Intel Package": "情报包裹", + "EVACUATE HIGH-VALUE ASSETS": "疏散高价值目标", + "No Deaths": "从未阵亡", + "Raw ore is refined into high-grade platinum at this refinery. Seize control of it.": "这座精炼厂将原矿加工成高品质铂金。夺取控制权。", + "Call down a Hellbomb to destroy the Cooling Tower": "呼叫地狱火炸弹摧毁冷却塔", + "TOUCH": "触碰", + "Illuminate Warp Ships are docked in this area. These ships are critical to the Illuminate invasion, used for all terrestrial military functions including personnel abduction and combatant deployment.\n\nWhile the ships are grounded, they are vulnerable. Find them and destroy them.": "光能者穿梭舰在此区域停靠。这些舰船对光能者的入侵行动而言非常重要,人员绑架和作战人员部署等所有地面军事行动都需要用到这些舰船。\n\n如果舰船无法起飞,它们将无力抵御攻击。找到舰船,并将其摧毁。", + "This fuel facility can be used to transfer crucial reserves to hovering shuttles.": "这座燃料设施可以将宝贵的储备资源输送至悬停的运输船。", + "Access relay controls": "获取中继控制权限", + "Within this laboratory, vile experiments twist upstanding citizens into grotesque thralls.": "在这座实验室内,邪恶的实验将正直的公民扭曲为丑陋的奴仆。", + "#WAVES waves completed": "击溃#WAVES波攻势", + "Prepare and launch the local ICBM.": "做好准备工作,发射当地的洲际弹道导弹。", + "RAISE SIGNAL STRENGTH": "提高信号强度", + "An Access Node linked to the Exospire's subterranean shield generator is stationed here.": "此处部署有接入节点,与异界尖塔地下的防护罩生成装置相连。", + "Reactivating these abandoned SEAF LiDAR towers will provide invaluable geographical data of the area.": "重新启用这些废弃的超级地球武装部队激光雷达塔,即可生成该地区的宝贵地理数据。", + "Use map to navigate to Helldiver Training Facility": "使用地图前往绝地潜兵训练基地", + "Cyberstan, once again, forms the axis of the Cyborg Legion's insurrection. Massive Megafactories cover its surface, churning out mechanical armies and weapons of mass extinction.\n\nThe Ministry of Defense has ordered the unconditional destruction of Cyberstan. Descend upon their Megafactories and put a permanent end to the Cyborg threat.": "生化斯坦再度成为生化人军团叛乱的核心。庞大的超大型工厂遍布地表,源源不断地制造机械军团与灭绝性武器。\n\n国防部已下令无条件摧毁生化斯坦。降落到这些超大型工厂,彻底终结生化人威胁。", + "TRANSMISSION STATION UPLOAD READY": "传输站上传程序准备就绪", + "Extract with Black Box": "带黑匣子撤离", + "Log in to Missile Control System": "登录导弹控制系统", + "This planet has been subjected to extended Illuminate debasement, and its corruption runs deep. Analysis of its corrupted biome will enable continued progress through the Void.": "这颗星球长期遭受光能者的侵蚀,腐化已经根深蒂固。分析这颗星球被腐化的生态系统,可以帮助我们继续深入寂域。", + "Inject Dark Fluid beneath the Supercolony's crust to destroy it once and for all.": "将暗液体注入超级拓殖地的地壳内,彻底将其摧毁。", + "Colony Breach Progress": "拓殖地攻破进度", + "MANUALLY set FLOW RATE VALVES to maximum output.": "手动将流量阀门设置为最大输出。", + "Conduct mass-scale Terminid fumigation to ensure planetary safety.": "开展大规模终结族熏杀作业,保障星球安全。", + "Illuminate forces are converging on the xenophobic ruins of their former empire. They must not be allowed to restore the relics of their tyrannical order.\n\nActivate the dormant ICBM silo in this region and reduce these makeshift lairs to ashes.": "光能者的部队正在其昔日帝国充满排外色彩的废墟之上集结。我们绝不能纵容他们重建这些象征其暴政秩序的遗迹。\n\n启动该地区休眠中的洲际弹道导弹发射井,将这些简陋的据点化为灰烬。", + "Close valve": "关闭阀门", + "Ammunition Input Required": "需要加入弹药", + "Find Terminid Brood Commander": "找到虫族指挥官", + "Open": "打开", + "Destroy Dark Fluid cells to destabilize Core": "摧毁暗液体电池,破坏核心的稳定性", + "Raise the Super Earth flag as an unassailable beacon of Unity.": "升起超级地球旗帜,犹如树立起一座坚不可摧的团结灯塔。", + "PLANETARY DEFENSE CANNON RAISING…": "行星防御加农炮正在抬升……", + "INPUT SYSTEM LOGIN CODE": "输入系统登录码", + "TOWER CONTROL TERMINAL": "通信塔控制终端", + "Upload sample data using drill interface": "使用钻机界面上传样本数据", + "Find and destroy all Terminid eggs.": "找到并摧毁终结族的所有虫卵。", + "SEIZE HIGH-GRADE PLATINUM": "夺取高品质铂金", + "SHUTTLE ENROUTE": "运输船正在航行", + "THREAT LEVEL: MODERATE": "威胁等级:中", + "This SEAF communication relay can be used to send information to ships in planetary orbit.": "这个超级地球武装部队通信转接设备可以用于给行星轨道上的舰船发送信息。", + "Select target network coordinates in grid": "选择网格中的目标网络坐标", + "We have identified the source of the Gloom: large subterranean fruiting bodies known as Spore Lungs. Larval Terminids within the Lungs appear to produce the Gloom spores, while the Lung itself pumps it into the exosphere.\n\nThe exact biology is unimportant. Delve deep into the Hive and detonate a Hellbomb within to eradicate the Spore Lung.": "我们已确认“阴霾”的源头是被称为“孢肺”的巨型地下子实体。该结构内的终结族幼虫似乎会产生“阴霾”孢子,再由孢肺泵入大气外逸层。\n\n眼下最重要的不是弄清楚其中具体的生物学原理。而是要深入虫窝内部,引爆地狱火炸弹,彻底毁灭孢肺。", + "Please stay clear of all moving parts": "请勿靠近所有活动部件", + "Scientists vital to the continued war effort were working in this top-secret research facility when the invasion hit. \n\nThey are currently kept safe inside emergency bunkers that must be opened from the outside to allow for an authorized evacuation.": "遭到入侵时,在这场持久战中起到至关重要作用的科学家正在这座绝密研究设施中孜孜不倦地工作。\n\n他们目前在紧急掩体里很安全,必须从外侧打开该掩体,才能执行授权撤离行动。", + "Reports indicate that the Annihilator Tank was last observed in this location.": "报告显示,湮灭坦克的最后目击地点就在这个位置。", + "A group of Class-A citizens are stranded at an emergency evacuation port. We cannot leave these patriots to be massacred by the Automatons.\n \nGet to the port and secure the evacuation of as many civilians as can fit aboard the designated transport shuttle.": "一组A级公民被困在紧急疏散港口。我们不能让这些爱国者为机器人所屠戮。\n\n前往港口,确保让尽可能多的平民登上指定运输船进行疏散。", + "Hack into the terminal to sabotage stationary defenses": "入侵终端以破坏固定防御设施", + "Log in to the Tower Control Panel": "登录广播塔控制面板", + "Warning: Silo susceptible to damage while charging": "阻止终结族靠近电池舱", + "Activate relay dish lift mechanism": "启动中继天线升降装置", + "Manual dish adjustment required": "需要手动调整天线", + "Facilitate our deepening understanding of the Gloom, so that it may be ultimately destroyed.": "尽快加深我们对“阴霾”的了解,以便最终将其摧毁。", + "Eradicated Heavy Bug Nest": "已摧毁重型巢穴", + "It is only a matter of time before this planet grants us safe passage into the Void. The Illuminate have deployed a massive fleet to drive our forces back and prevent the completion of this monumental breakthrough.\n\nPut an end to their interference. Hold this planet at all costs.": "我们借助这颗星球打开安全进入寂域的通道已指日可待。光能者已派出一支大型舰队,企图击退我方部队,阻止我们完成这一重大突破。\n\n终结他们的阻挠。不惜一切代价,守住这颗星球。", + "Confiscate platinum and fusion batteries at this site.": "没收此处的铂金和聚变电池。", + "Secure the SSSD containing the top-secret Cannon Access Codes.": "找到内含机密加农炮访问代码的超级固态硬盘。", + "Restore functionality to the E-711 pump site.": "使711元素泵机恢复运行。", + "Sabotage the Megafactory's air capabilities.": "破坏超大型工厂的空中作战能力。", + "Find and close any active Terminid holes": "找寻并关闭所有活动的终结族虫穴", + "DEACTIVATE TERMICIDE TOWER": "关闭灭虫终结塔", + "Battery silo offline": "电池舱停用", + "Activate the Termicide Dispersion Tower to immunize this area from the Terminids.": "启动灭虫终结剂喷洒塔,消灭该区域内的终结族。", + "ACTIVATE TRANSFER": "开始输送", + "EVACUATE HIGH-VALUE ARTIFACTS": "撤走高价值文物", + "This planet is the center of Illuminate operations within the Void. They have constructed extensive facilities, whose nature is bewildering to Democratic minds and affronts to all things Free. Tear them down, and put an end to the Void.": "这颗星球是光能者在寂域中的行动枢纽。他们建造了规模庞大的设施,民主的思维难以理解其中的本质,这些地方全都是对一切自由事物的公然亵渎。将这里夷为平地,终结寂域的存在。", + "COLLECT METEOROLOGICAL DATA": "收集气象数据", + "DISRUPT ILLUMINATE": "挫败光能者", + "INPUT LAUNCH CODE": "输入发射代码", + "RETRIEVE KEYCARD": "取得钥匙卡", + "Halt the extensive Automaton industrial operations on this lava-covered planet. Annex their facilities and seize their stolen goods.": "阻止机器人在这颗熔岩覆盖的星球上展开大规模工业活动。占领它们的设施,夺回被盗的物资。", + "Connect Battery Silos to Central Tower": "将电池舱与中央巨塔连接起来", + "Completed: #AMOUNT M": "完成:#AMOUNT", + "PRIMING SEISMIC PROBE": "地震探测仪正在准备", + "Battery Silo 01 Offline": "电池舱01停用", + "ACTIVATE PUMPS": "启动泵机", + "Power unavailable": "电力不可用", + "Use drill interface to switch drills": "使用钻机界面切换钻机", + "Seal indicated exhaust pipes": "密封已标记的排气管", + "The Overship is the command-and-control nexus of Illuminate forces in this sector. Its oppressive presence must be destroyed.\n\nA Planetary Defense Cannon in this area can penetrate its shields. Activate the Cannon and use it to bring down the Overship.": "统御舰是该分区光能者部队的指挥中枢。必须摧毁这艘暴政舰船。\n\n该区域的行星防御加农炮可穿透其护盾。启动加农炮,击沉统御舰。", + "The Illuminate have carved a totalitarian lair amid this region's tangled growth. Heretical altars and foul laboratories create unspeakable horrors that would terrorize every household in the galaxy. \n\nInfiltrate this twisted cradle of corruption. Expose and put an end to their depravity.": "光能者在该地区茂密的丛林深处建造了一座极权主义巢穴。它们在异端祭坛和肮脏实验室里炮制出的不可名状的恐怖存在,足以令银河系的每家每户都活在恐惧之中。\n\n潜入这个扭曲的腐化巢穴。揭露并终结它们的邪恶勾当。", + "FUELING MISSILE - PLEASE WAIT": "正在为导弹添加燃料,请稍候", + "PLACE DATA DRIVE IN INPUT TRAY": "将数据硬盘放进输入托盘", + "FUSE 1": "熔断器1", + "CONTROL CHAMBER UNLOCKED": "控制室已解锁", + "ACTIVATE DRILL 3?": "是否启动3号钻机?", + "We have discovered extensive Automaton mining and processing operations on this previously uninhabited planet. This lava-covered world is rich in mineral resources, but constant eruptions and a noxious atmosphere makes it unsuitable for human habitation. \n\nThe Automatons are recklessly exploiting the natural riches of this planet, stealing them from our citizens and transforming them into tools of Socialist oppression. We must stop them, annex their industry, and seize their stolen goods.": "我们发现机器人在这颗此前无人居住的星球上进行大规模采矿和加工作业。这颗被熔岩覆盖的星球矿物资源丰富,但上面的火山持续喷发,大气环境有毒,不适合人类居住。\n\n机器人肆意开采这颗星球的自然财富,从我们公民手中窃取资源,并转化为党同伐异的工具。我们必须阻止它们,吞并它们的产业,夺回被盗的物资。", + "CRITICAL SYSTEMS INTERFACE": "关键系统界面", + "Charge into the Exostorm and save this planet from falling to the Void.": "挺进异界风暴,拯救这颗星球,使其免于堕入寂域。", + "RUN SABOTAGE SOFTWARE": "运行破坏软件", + "This altar’s wellspring is crawling with Illuminate tadpoles, poised to evolve into fully fledged war criminals at any moment.": "这座祭坛的泉眼中爬满了光能者蝌蚪,它们随时可能蜕变为彻头彻尾的战犯。", + "#COUNT% XP RATING": "#COUNT%经验等级", + "FLAG": "旗帜", + "Filter": "筛选", + "Low death bonus: #AMOUNT M": "低阵亡率加分:#AMOUNT", + "Thank you for your cooperation": "感谢您的配合", + "INVESTIGATE VOID PLANET": "调查寂域星球", + "AA Emplacement": "防空炮台", + "Loot Update": "战利品更新", + "SAFEGUARD VITAL E-711": "保卫VITAL E-711", + "Black Box": "黑匣子", + "ANOMALOUS MATERIAL SITE": "异常物质地点", + "DESTROY PROTOSPIRE": "摧毁原始虫塔", + "#TYPE: +#AMOUNT/#POTENTIAL M": "#TYPE:+#AMOUNT/#POTENTIAL", + "DISABLING CRITICAL SYSTEMS...": "正在关闭关键系统…", + "Illuminate Exospires are channeling an aberrant Exostorm that rages on the surface of this world. The planet is at risk of being consumed by the Void, unless we act now.\n\nLay waste to their abyssal sanctums. Not a single Exospire can remain if Freedom’s light is to prevail.": "光能者异界尖塔正引导一股畸变的异界风暴,在这个世界的地表肆虐。若不立即采取行动,星球恐将被寂域吞噬。\n\n彻底捣毁它们的深渊圣所。只有摧毁所有的异界尖塔,自由之光方能普照。", + "Destroy the Cognitive Disruptor's power supply.": "摧毁感知干扰器的能源。", + "SEIZE FUSION BATTERIES": "夺取聚变电池", + "Retrieve coordinates": "获取坐标", + "HALT CYBORG PRODUCTION": "使生化人停产", + "Maiden voyage of the #SHIP_NAME.": "#SHIP_NAME的首航。", + "The Automatons have heavily industrialized this region and are producing a nonstop supply of fresh troops. \n\nDestroy their infrastructure and kill as many bots as you can.": "机器人已经在该地区实现重度工业化,同时在源源不断地为自己的军队输送新鲜血液。\n\n摧毁它们的基础设施,尽可能击杀机器人。", + "COMPROMISE AUTOMATON DEFENSES": "破坏机器人的防御系统", + "Use terminal to raise satellite tower": "使用终端抬升卫星塔", + "DESTROY ROGUE RESEARCH STATION": "摧毁叛变科研站", + "The Illuminate have corrupted this planet after sequestering it within the Void. Stop this planetary degradation, and aid in the collection of data that will lead us further into the Void.": "光能者将这颗星球困在寂域中,然后对其进行了彻底腐化。阻止这颗星球的进一步恶化,协助我们收集数据,为深入寂域开辟道路。", + "RAPID ACQUISITION": "快速夺取", + "Destroy Command Bunker": "摧毁指挥碉堡", + "Activate Artillery": "启动大炮", + "Call down a Hellbomb to destroy the Counter-Orbital Cannon": "呼叫地狱火炸弹摧毁反轨道加农炮", + "Automatons in this region pose an undeniable and multifaceted threat to Liberty. Do whatever it takes to defend our way of life.": "毋庸置疑,该地区的机器人对解放大业的多个方面都构成威胁。不惜一切代价也要捍卫我们的生存之道。", + "The Automatons are synthesizing some kind of nutrient-dense plasma from organic material. Undeniable intel shows 100% of this organic material came from loyal citizens with high potential and excellent facial symmetry. The purpose of this plasma is yet unknown, but its production is extremely costly.\n\nDisrupt the plasma production and secure samples of the liquid for further analysis.": "机器人正在用有机物质合成某种富含营养的等离子。有确凿情报显示,这些有机物质100%来自潜力巨大而且面部完美对称的忠诚公民。这种等离子用途尚不明确,但其生产成本极其高昂。\n\n破坏等离子的生产过程,获取液体样本供进一步分析。", + "Samples Found": "已找到样本数", + "Keep hands away from extractors": "请勿触碰提取器", + "Illuminate invaders have located Priority Emergency Bunkers (available to citizens at Class B and above), and are ruthlessly targeting these non-combatants in clear violation of galactic law. \n \nTransport ships are inbound to evacuate the citizens. The Helldivers must ensure these patriotic and loyal citizens reach safe harbor.": "光能者已发现向B级及以上公民开放的优先紧急掩体,正残忍屠杀这些平民,公然践踏星际法律。\n\n帮助公民撤离的运输舰即将抵达。绝地潜兵必须确保这些忠诚的爱国公民安全登舰。", + "An Automaton Hulk was last reported in this location.": "据报告称,机器人巨型者的最后目击地点就在这个位置。", + "ANNEX UNTAPPED MINERAL SITES": "吞并未开发的矿点", + "EXTRACT WITH FOOTAGE": "带录像撤离", + "OUTPOSTS DESTROYED": "已摧毁哨站", + "Highest priority upload speed": "最高优先级上传速度", + "RAISE SATELLITE TOWER": "抬升卫星塔", + "Proceed to Live Fire Range": "前往实弹靶场", + "A massive Terminid swarm is gathering in this region. Left unchecked, it threatens to explode out of control.\n\nKill as many Terminids as you can to thin their numbers.": "一个庞大的终结族虫群正在该地区集结。如果置之不理,它们可能有失控的风险。\n\n尽可能击杀更多终结族,削减它们的数量。", + "Once the GATER is secured, use it to extract the resources in this area.": "GATER到位就绪后,立即使用它在该区域提取资源。", + "ICBM Launching": "洲际弹道导弹即将发射", + "READY TO LAUNCH": "准备发射", + "The Illuminate have discovered a long-sequestered cache of top-secret, highly valuable assets, frozen in cryostasis since the First Galactic War. These assets cannot be allowed to fall into the Illuminate's clutches.\n\nDefend the site long enough for all evacuation rockets to launch.": "光能者发现了一处尘封已久的绝密贵重资产库,该库存自第一次星系战争以来就利用冷冻技术封存至今。不能让这批资产落入光能者手中。\n\n坚守撤离点,直至所有撤离火箭发射完毕。", + "ERROR - TOWER MISALIGNED": "错误,卫星塔方向偏离", + "Shameful Return": "屈辱归来", + "ROOT OUT HIVES": "清除虫窝", + "Geological grid map scale 1:100": "地质网格地图比例尺 1:100", + "Abandoned SEAF artillery can be reactivated for ground-based support.": "重新启动废弃的超级地球武装部队大炮可以提供陆基火力支援。", + "ACTIVATE SEISMIC SCAN?": "是否启动地震扫描?", + "NEUTRALIZE ORBITAL CANNON": "阻止敌方使用轨道加农炮", + "THREAT LEVEL: SUBSTANTIAL": "威胁等级:较高", + "TRANSMIT DATA PACKAGE": "传输数据包", + "Liberate the Hive World to prevent the spread of the Gloom, and extract as much E-711 as possible.": "解放虫窝世界,阻止“阴霾”扩散,并尽可能提取更多711元素。", + "INITIATE POWER SURGE": "启动电涌", + "INITIATE POWER TRANSFER": "开始输电", + "CLEANSE FOUL SHRINE": "净化污秽神社", + "Purification": "提纯", + "Bypass terminal security": "绕过终端安全系统", + "Proceed to TCS+ activation terminal": "前往TCS+激活终端", + "Helldiver Replacements": "绝地潜兵替补兵员", + "Enter code to begin activation process": "输入代码激活启动程序", + "MISSION TIME : #MINUTES:#SECONDS": "任务用时:#MINUTES:#SECONDS", + "Briefcase": "公文包", + "FINAL TEST IN PROGRESS": "正在进行终极考验", + "Activate Hive Breaker Drill": "启动“虫窝破裂者”钻机", + "ACQUIRE SOIL SCAN DATA": "获取土壤扫描数据", + "Raising satellite tower": "正在抬升卫星塔", + "SEAF Combat Engineers have deployed a Rapid Modular Drilling Platform above a pool of a mysterious E-710-like substance deep within the Terminid caves. High Terminid activity has made the area extremely dangerous and made extraction impossible.\n\nDeploy to the Hive World and manually activate the Rig. Protect the extraction process until the substance is safely airlifted away.": "终结族洞穴深处有整整一池的类710元素神秘物质,超级地球武装部队战斗工程师已在其上方部署了快速模块化钻机平台。终结族活动频繁,导致该区域变得异常危险,提取难度极大。\n\n前往虫窝世界并手动激活钻机装置。提取过程中要捍卫阵地,保护神秘物质安全空运离开。", + "Use the Portable Hellbomb to destroy the Hive Lung": "使用便携式地狱火炸弹摧毁虫窝孢肺", + "We have received reports from this region of Brood Commanders exhibiting dangerous new mutations.\n\nFind and eliminate them before they can breed.": "我们收到了来自该地区的报告。据称,虫族指挥官表现出危险的新型突变属性。\n\n在此类生物繁殖之前找到它们并将其消灭。", + "ELIMINATE CHARGER": "消灭强袭虫", + "Shuttle Bay Terminal System": "运输船坞终端系统", + "DESTROY TRANSMISSION NETWORK": "摧毁传输网络", + "Track down and eliminate the Brood Commander.": "追踪并消灭虫族指挥官。", + "Terminal": "终端", + "BLOWN FUSES FOUND": "发现熔断器熔断", + "GENERATOR CONTROL UNIT": "发电机控制单元", + "Use terminal to lock the target coordinates": "使用终端,锁定目标坐标", + "A vast network of underground hives has allowed the Terminids in this region to become entrenched, breeding and swelling in number.\n\nFortunately, this hive has just gone into a brief hibernation. Infiltrate, and destroy all you can before the Terminids return to full strength.": "庞大的地下虫窝网络使终结族得以在该地区根深蒂固,不断繁殖壮大。\n\n幸好,这个虫窝刚刚进入了短暂的休眠状态。赶在终结族完全恢复力量之前潜入其中,尽可能摧毁一切。", + "Wait for power charge": "等待充电", + "Thank you for your service": "感谢你的付出", + "ESTABLISH COMMUNICATION UPLINK": "建立通信上行链路", + "CARGO CONTAINER": "货物集装箱", + "Use terminal to open silo hatch": "使用终端,打开发射井舱门", + "TOTAL: +#AMOUNT M": "总计:+#AMOUNT", + "The high-value intel is located here. It is locked inside a secure containment unit.": "高价值情报位于此处。情报被锁在安全收容装置内。", + "Nuclear Missile": "核导弹", + "Locate and unlock system access port": "定位并解锁系统访问端口", + "Destroyed Heavy Automaton Outpost": "已摧毁重型机器人哨站", + "Network connection lost": "网络连接丢失", + "ELIMINATE AUTOMATON FACTORY STRIDER": "消灭机器人移动工厂", + "Defend Battery Silo 03": "保卫电池舱03", + "Station inoperable at current time": "站点目前无法运转" + }, + "dialogue": { + "{0.00->3.85}Defeat is but the catalyst of its own rectification.": "{0.00->3.85}失败是自我修正的催化剂。", + "{0.01->0.96}Let's go!": "{0.00->1.02}一起冲啊!", + "{0.02->1.15}Where are the evac ships?": "{0.02->1.08}撤离飞船在哪?", + "{0.00->1.29}The Shete system": "{0.00->1.29}赛特星系", + "{0.00->6.47}No one likes a complainer. If your living conditions aren't to your liking, just remember, aliens {6.47->8.59}could kill us all at any moment.": "{0.00->1.45}没人愿意听牢骚。{1.99->4.41}如果你对生活条件不满意,不妨想一想,{4.73->9.29}外星人随时都可能终结我们的生命,或许就会释怀了。", + "{0.00->0.99}Little help?!": "{0.00->1.15}来搭把手?!", + "{0.01->1.37}Steady now! Be ready!": "{0.01->1.37}稳住!做好准备!", + "{0.03->2.08}Mission at 20 minutes remaining.": "{0.03->2.08}任务剩余20分钟。", + "{0.07->2.12}Everyone get down!": "{0.00->2.30}注意,全体卧倒!", + "{0.11->0.28}Well{0.80->2.07}these folks look safe!": "{0.32->2.40}看来大家都安全了!", + "{0.00->0.50}Charlie": "{0.00->0.50}C", + "{0.18->0.94}Out of stims.": "{0.18->0.94}没针了。", + "{0.00->2.76}Sweet Liberty! They got a Helldiver!": "{0.00->2.98}解放你大业的!他们杀了绝地潜兵!", + "{0.00->0.90}Marking location.": "{0.00->0.90}标记地点,", + "{0.00->0.86}New canister.": "{0.00->0.86}新燃料罐。", + "{0.01->2.89}How about a nice cup of Liber-tea!": "{0.01->2.89}一盅陈茶敬自由!", + "{0.00->0.76}Joining the fray.": "{0.00->0.76}加入战斗。", + "{0.02->2.05}Freedom conquers all!": "{0.00->2.11}自由精神战无不胜!", + "{0.04->1.93}Forward, for Liberty!": "{0.00->2.05}前进,为了解放!", + "{0.00->1.05}Additional objective.": "{0.00->0.95}其他目标,", + "{0.01->1.75}For the glory of Super Earth.": "{0.01->1.75}荣耀属于超级地球。", + "{0.00->1.83}Thank Freedom they're on our side!": "{0.00->1.96}感谢自由站在我们这边!", + "{0.03->0.72}Get down!": "{0.00->0.76}快卧倒!", + "{0.02->1.16}There! Hide there!": "{0.02->1.16}那边!躲在那!", + "{0.01->1.33}Automatons!": "{0.01->1.33}机器人!", + "{0.05->1.93}It's gonna cut me open!": "{0.05->1.93}救命,它快把我给撕了!", + "{0.02->0.99}What are those things?": "{0.02->0.99}什么鬼东西?", + "{0.02->2.56}WHOA—that was loud!": "{0.00->1.99}哇啊,太吵了吧!", + "{0.00->3.33}Recruit expired. Initiate terminid containment protocol.": "{0.00->3.39}新兵死亡。启动终结族控制程序。", + "{0.00->0.94}I've got you.": "{0.00->0.94}我来帮你。", + "{0.01->3.14}Finish this fight, as they would have.": "{0.01->3.14}代替他们结束这场战斗吧。", + "{0.03->0.89}I'm pinned!": "{0.00->0.89}遭到压制!", + "{0.03->1.31}Dropping item!": "{0.03->1.31}放下物品!", + "{0.02->0.93}More squids!": "{0.02->0.93}还有鱿鱼!", + "{0.03->1.25}Taking position!": "{0.00->1.40}战士们各就各位!", + "{0.00->0.38}1!": "{0.00->0.38}幺!", + "{0.00->1.32}The Pandion system": "{0.00->1.32}帕狄恩星系", + "{0.03->1.76}Stim! Over here!": "{0.00->1.75}这里!给我一针!", + "{0.00->1.07}This is the right place.{1.54->1.80}Right?": "{0.05->1.12}是在这里等,{1.60->1.92}对吧?", + "{0.00->2.76}All the galaxy looks to you for salvation. {3.12->6.07}Let nothing stand in the way of Liberty.": "{0.00->2.76}全星系都等待你去救赎。{3.12->6.07}清除解放之路上的一切阻碍吧!", + "{0.00->1.75}No diver left behind.": "{0.00->1.71}不抛弃,不放弃。", + "{0.04->2.28}Help over here!": "{0.00->2.37}我需要帮助!", + "{0.52->2.78}Let's go! For Democracy!": "{0.42->2.86}我们一起!为民主喝彩!", + "{0.00->1.32}Reloading! Running low here!": "{0.00->1.82}换弹!这里弹药不够了!", + "{0.07->1.48}The Inari system": "{0.07->1.48}伊纳里星系", + "{0.00->1.89}They gave their all, for Liberty!{2.31->4.13}We will do the same!": "{0.00->1.89}他们为解放付出了一切!{2.56->4.62}我们也会做出同样的选择!", + "{0.04->1.95}Super Uranium acquired.": "{0.04->1.95}超铀到手了。", + "{0.00->0.73}I win.": "{0.00->0.73}我赢了。", + "{0.51->1.36}Op - wrong way!": "{0.00->1.36}呃,不是这边!", + "{0.02->6.07}You want my Freedom? MY Freedom?! Gotta try harder than that!": "{0.02->6.07}想要我的自由?我的自由?!你得再加把劲!", + "{0.00->1.72}I feel—I feel—RRAAH!": "{0.00->3.36}我感觉——我感觉,嗷!", + "{0.04->0.68}Moving!": "{0.04->0.68}前进!", + "{0.02->3.53}Ah! They got me, the Fascists got me!": "{0.00->1.58}啊!我受伤了,{1.58->3.45}那群没脸皮的法西斯!", + "{0.00->3.47}This world needs your righteous extermination, Helldiver.": "{0.00->3.47}这颗星球需要你以正义之名铲除敌人。", + "{0.00->1.74}Stay alert in those Illuminate ruins,{2.12->4.43}could be all sorts of propaganda down there.{4.92->6.67}Don't look, just blow them up.": "{0.00->2.69}到了光能者遗迹,一定要保持警惕,{3.16->7.52}里面可能藏着各种宣传品。别看,直接炸掉就行。", + "{0.00->5.57}Helldiver. You face a Hive Lord. Liberty guide you.": "{0.00->5.57}绝地潜兵。出现霸王虫。愿解放保佑。", + "{0.00->0.33}E-{0.74->2.22}710-rich System": "{0.00->2.19}710元素富集星系", + "{0.05->3.11}Every shot is a taste of Freedom! Fire!": "{0.00->3.44}每一枪都是自由的滋味!开火!", + "{0.00->0.48}Five.": "{0.00->0.48}五。", + "{0.00->2.90}If we stay close to the Helldivers, we're safe.": "{0.00->2.90}有绝地潜兵在,我们就安全了。", + "{0.02->0.92}Help me!": "{0.02->1.28}救救我!", + "{0.00->1.80}The Elysian Meadows system": "{0.00->1.80}埃律西昂草原星系", + "{0.06->1.89}It's just like on TV!!!": "{0.06->1.72}和电视上一样!!!", + "{0.02->1.75}Deploying explosive munitions!": "{0.00->1.91}正在部署爆破炸药!", + "{0.03->2.53}It's nice, cuz today I won't have to work overtime to get 'em done.": "{0.03->2.83}真好,今天我不用加班就能完成工作了。", + "{0.08->1.57}The Avila System": "{0.08->1.20}阿维拉星系", + "{0.03->1.56}Anomalous System": "{0.03->1.09}异常星系", + "{0.05->1.89}Take a moment to remember: {3.04->5.69}Every Helldiver is your friend. {7.02->8.69}Every single one.": "{0.00->6.58}你要记住:每位绝地潜兵都是你的朋友。{7.16->8.75}无一例外。", + "{0.01->1.95}Reloading! Watch my six.": "{0.01->1.95}换弹!注意我身后。", + "{0.00->1.34}Deploying Support Station.": "{0.00->1.34}部署支援站。", + "{0.00->1.38}Calling in an orbital strike.": "{0.00->1.38}请求轨道攻击支援。", + "{0.04->5.09}When it comes to these Automatons, there's no fixing 'em. Only solution is to wipe the slate clean.": "{0.00->4.91}比如这些机器人,它们就是没法修好的。我们只能把它们彻底清除。", + "{0.00->1.69}No diver left behind.": "{0.00->1.69}不抛弃,不放弃。", + "{0.00->2.69}That's the flag of Super Earth, recruit! {3.08->4.89}Plant it in the designated area.": "{0.00->2.69}那就是超级地球的旗帜,新兵!{3.08->4.89}把它插在指定区域。", + "{0.00->1.68}Change of plan - this way!": "{0.00->1.68}计划有变。这边!", + "{0.00->1.16}Inputting drop point.": "{0.00->1.16}确定降落地点。", + "{0.09->0.95}Out of stims.": "{0.09->0.95}针用光了。", + "{0.30->1.95}Where are those reinforcements?": "{0.00->1.58}我们援军在哪儿?", + "{0.06->2.92}RIP THEM TO PIECES, HELLDIVERS!": "{0.06->2.92}绝地潜兵,把它们撕成碎片!", + "{0.00->1.69}Harmless animal.": "{0.00->1.51}无害的动物。", + "{0.00->1.47}The Mortax system": "{0.00->1.47}摩尔塔克斯星系", + "{0.00->1.35}The Fledge System": "{0.00->1.19}雏羽星系", + "{7.67->13.12}Freedom's Greetings; I'm Coretta Kelly, with joyous tidings.{13.12->17.63}The Helldivers have liberated Cyberstan from the Cyborgs.{17.63->22.39}For the first time in over a year, Cyberstan is free.{22.39->28.58}The Cyborgs fled the planet, along with the Automatons, deeper into their territory.{28.58->33.01}The Helldivers have already been ordered to pursue the enemy.{33.01->36.99}Concerning reports indicate Cyborgs have already begun {36.99->40.30}constructing new Megafactories on other planets,{40.30->43.24}in a desperate bid to grow their numbers.{43.60->47.16}The Helldivers have been ordered to destroy the Megafactories {47.16->54.50}and eradicate the entire race of half-human monstrosities—in order to protect our children.{54.80->58.06}That's Liberty's Latest; I'm Coretta Kelly.": "{7.63->12.72}自由向各位问好,我是科雷塔·凯利,下面播报喜讯。{13.41->17.35}绝地潜兵成功击败生化人,解放了生化斯坦。{17.74->22.34}时隔一年多,生化斯坦终于再度迎来解放的曙光。{22.70->26.33}生化人与机器人一同仓皇撤离了这颗星球,{26.67->28.58}逃往它们更深处的领地。{29.10->32.39}绝地潜兵已接到指令继续追击敌人。{33.39->36.22}而情报部门传来一则令人不安的报告:{36.80->40.34}生化人已经在其他星球兴建新的超大型工厂,{40.80->43.63}企图通过量产增兵绝地反击。{43.83->47.44}绝地潜兵已接到指令,摧毁所有超大型工厂,{47.81->51.07}彻底消除这些半人怪物的机器人种族——{51.48->54.47}只为给我们的孩子一个更安全的未来。{54.79->58.92}以上就是今天的《解放新闻》,我是科雷塔·凯利。", + "{0.00->4.50}Never forget: we are all one Super Earth.": "{0.00->4.84}永远谨记:我们同属一个超级地球。", + "{0.00->3.54}The enemy has launched a cowardly attack against one of our planets. {4.23->5.13}Will you defend it?": "{0.00->3.00}敌人对我们的一颗星球发起了卑劣的袭击。{3.38->5.13}你会捍卫这颗星球吗?", + "{0.00->1.58}High-value sample collected.": "{0.00->1.82}高价值样本到手了。", + "{0.00->1.89}The Helldivers came for us!": "{0.00->1.89}绝地潜兵来救我们了!", + "{0.03->1.14}Thanks, Helldiver!": "{0.00->1.25}谢谢你,潜兵!", + "{0.10->1.85}Squid Outpost destroyed.": "{0.10->1.85}已摧毁鱿鱼哨站。", + "{0.00->1.33}Point me to the enemy.": "{0.00->1.33}告诉我敌人在哪儿。", + "{0.00->3.52}One small scrap of technology, one giant leap for Liberty.": "{0.00->3.52}科技研究一小步,解放大业一大步。", + "{0.00->0.75}Calling down fortifications.": "{0.00->1.93}请求部署防御工事。", + "{0.42->1.59}The Auspice System": "{0.03->1.06}天启星系", + "{0.00->0.50}I'll take it.": "{0.00->0.38}我来。", + "{0.03->2.28}You can walk it off! Walk it off!": "{0.03->2.28}你能挺过去!挺住!", + "{0.00->2.20}Hellbomb armed—clear the area.": "{0.00->2.20}地狱火启动,炸平这里。", + "{1.11->3.74}This land is OUR land!": "{1.05->4.20}这片土地是属于我们的!", + "{0.00->4.15}Commando operations present a challenge for only the most elite{4.54->6.42}of the Galaxy's elite.{6.92->9.59}Will you brave the gauntlet, Helldiver?": "{0.00->5.19}突击兵行动只有银河系的顶级精英才能胜任。{5.97->9.66}绝地潜兵,你敢接受这个挑战吗?", + "{0.00->0.95}Fortifications.": "{0.00->0.95}防御工事,", + "{0.00->0.54}Code is:": "{0.00->0.77}代码是:", + "{0.04->1.48}It's the Automatons!": "{0.04->1.48}是机器人来了!", + "{0.00->1.68}Freedom's purity secured.": "{0.00->1.68}已守护自由的纯洁。", + "{0.00->2.60}I know we can't stay like this, but...": "{0.00->2.87}我知道我们不能一直抱下去,但……", + "{0.01->2.78}Yeah!! Keep up the momentum!": "{0.00->2.82}对!!保持这样的势头!", + "{0.00->1.88}We've touched down on Cyberstan itself.{2.30->8.90}Our old enemy is waiting down there: not just the Cyborgs themselves, but their twisted socialist{8.90->9.50}agenda.": "{0.00->1.84}我们已经登陆生化斯坦了。{2.56->4.47}我们的老对手就在下面等着:{5.35->9.19}不只是生化人,还有它们党同伐异的扭曲思想。", + "{0.00->2.55}Liberty calls for aid across the galaxy; {3.12->5.41}only you can decide where to answer.": "{0.00->2.55}解放向整个银河系发起求助;{3.12->5.65}只有你能决定要在哪里响应。", + "{0.01->0.83}What is that?": "{0.01->0.83}那是什么?", + "{0.00->1.33}Calling down a vehicle.": "{0.00->1.33}请求载具支援。", + "{0.00->3.82}we just draw an imaginary line from the ship to the center of Super Earth, and then take our {3.82->7.98}distance from Super Earth, along with the latitude and longitude of where that line hits Super {7.98->8.65}Earth's surface.": "{0.00->3.63}只需要画一条虚构的线,把舰船和超级地球的中心连接起来,{3.79->6.02}然后计算我们和超级地球之间的距离,{6.10->8.65}以及这条线和超级地球表面交点的经纬度。", + "{0.00->2.81}I will never forgive myself!": "{0.00->2.89}我永远不会原谅自己!", + "{0.00->1.26}Op - wrong way!": "{0.00->1.50}哎呀,不是这边!", + "{0.00->3.03}YES, HELLDIVERS! YESSSSS!!!!": "{0.00->3.58}绝地潜兵,好样的!干得好!!!!", + "{0.00->1.75}The Superioria System": "{0.00->1.10}卓尊星系", + "{1.23->5.33}One less Megafactory. A win for the human gene pool.": "{1.23->5.48}解决了一座超大型工厂。这是人类基因库的胜利。", + "{0.00->2.31}Bug outpost spotted. Prepare to exterminate.": "{0.00->2.31}发现虫族哨站,准备歼灭。", + "{0.00->1.21}Majestic.": "{0.00->1.39}噢太棒了。", + "{0.01->4.53}Uh, Democracy for everybody!": "{0.01->3.96}啊,人人民主!", + "{0.03->1.37}The Atrama system": "{0.03->1.37}阿特拉玛星系", + "{0.00->2.62}Never thought I'd see anything like it.": "{0.41->2.67}从没想过我能亲眼见到。", + "{0.00->2.29}The flag...it's so beautiful...": "{0.00->2.76}这面旗帜……多么的耀眼……", + "{0.02->1.99}Manning combat walker.": "{0.02->1.99}操纵战斗步行机甲。", + "{0.00->0.75}This is where the shuttle lands?": "{0.00->1.33}就在这儿等运输船吗?", + "{0.00->0.95}Keep moving.": "{0.00->0.95}得赶紧走。", + "{0.03->1.17}Help me, please!": "{0.03->1.17}救救我!", + "{0.02->0.95}Take cover!": "{0.02->0.95}快找掩体!", + "{0.03->3.81}Smells like Freedom to me.": "{1.65->3.93}是自由的芬芳。", + "{0.13->1.78}Special delivery!": "{0.13->1.78}有你的快递!", + "{0.01->0.47}I'm out.": "{0.01->0.47}打光了。", + "{0.00->1.39}Suppressing fire!": "{0.00->1.11}火力压制!", + "{0.01->2.21}Incoming. Choose your targets!": "{0.01->1.95}来了。选择目标!", + "{0.15->1.69}Visualize the Flag. {3.67->4.24}See it {5.08->6.64}wrapping around your legs, {8.10->8.93}your arms, {10.50->11.28}your body, {13.04->14.00}your face. {16.08->17.29}You are safe.": "{0.05->2.00}想象旗帜。{3.67->7.23}想象它环绕{8.10->9.92}你的四肢、{10.50->11.94}身躯{13.04->14.82}与脸庞。{16.08->18.42}你很安全。", + "{0.04->2.42}Get back, you filthy squids!": "{0.04->2.42}恶心的鱿鱼,快滚开!", + "{0.00->1.71}SEAF are out of the combat zone.": "{0.00->1.77}武装部队已撤离战区。", + "{0.04->1.60}The Pennybridge System": "{0.04->1.64}彭尼布里奇星系", + "{0.00->1.61}Freedom never sleeps!": "{0.00->1.61}自由真提神!", + "{0.03->2.17}If this is a trap, it's our{2.17->4.26}Democratic duty to be the bait.": "{0.01->1.14}就算这是个坑,{1.50->3.81}为了民主,今天我也得跳了。", + "{0.00->1.66}Crystallized E-710 acquired.": "{0.00->1.66}710元素晶体到手了。", + "{0.00->2.22}An opportunity for Liberation. {2.78->4.04}We must seize it.": "{0.00->1.72}这是解放的良机,{2.26->4.26}我们必须要紧紧抓住。", + "{1.43->3.16}Did you see that? They touched my hand!": "{0.00->2.36}你看到了吗?他们跟我握手了!", + "{0.00->0.88}Sub-objective.": "{0.00->0.88}次要目标,", + "{0.00->1.19}SEAF is Oscar Mike.": "{0.00->1.28}武装部队出发了。", + "{0.02->1.34}The Ballot System": "{0.02->1.06}民望星系", + "{0.01->1.46}The bugs are coming!": "{0.01->1.46}虫族来了!", + "{0.03->1.02}Don't let go.": "{0.00->1.11}别放手。", + "{0.00->1.25}The Cursa system": "{0.00->1.25}玉井三星系", + "{0.01->2.63}We will remember their sacrifice.": "{0.01->2.63}我们会铭记他们的牺牲。", + "{0.02->1.07}Bugs! Aaaaaah!": "{0.02->1.64}虫族!啊啊啊啊!", + "{0.00->0.89}Ouch.": "{0.00->0.89}呃……", + "{0.02->1.63}Sub-objective in your vicinity.": "{0.02->1.63}你们附近有次要目标。", + "{0.03->1.41}I'll never forget this.": "{0.03->1.67}我会永远记得今天。", + "{0.01->1.07}More Red-eyes!": "{0.01->1.07}红眼怪物又来了!", + "{0.00->1.15}Sample collected.": "{0.00->1.15}样本到手了。", + "{0.00->0.93}Defense complete.": "{0.00->0.93}防守完成。", + "{0.00->0.60}Second one.": "{0.00->0.60}第二个。", + "{0.00->0.30}Here.": "{0.00->0.30}来。", + "{0.06->4.38}I'd ask if you were going to take a break, but I already know the answer. {5.09->9.34}You and your fellow Helldivers inspire me every day.": "{0.06->3.85}我想问你们用不用休息,但不问也能看出来。{4.43->8.80}你和你的绝地潜兵弟兄每天都激励着我前进。", + "{0.00->2.31}The operation proceeds smoothly.": "{0.00->2.31}目前行动十分顺利。", + "{0.01->2.66}Maintain formation! Make Super Earth proud!": "{0.01->2.99}保持阵型!让超级地球为我们自豪!", + "{0.00->1.19}Let's do this!": "{0.00->1.30}咱们开干吧!", + "{0.00->2.73}Our enemies have cut off our route to this planet. {3.30->5.16}The war has eclipsed us.": "{0.00->2.73}敌人切断了我们前往这颗星球的路线。{3.30->5.16}战争的阴霾笼罩着我们。", + "{0.00->1.19}Decreased visibility. {1.65->3.22}Should help obscure our movements.": "{0.00->1.22}能见度降低,{1.24->3.22}方便我们隐藏行踪。", + "{0.00->0.48}Intel.": "{0.00->0.48}情报,", + "{0.08->4.92}So the Cyborgs are back, after all those years of peaceful service to Managed Democracy. {5.76->9.66}And they'd rather die on the battlefield than live under Super Earth?{10.26->11.21}That's stupid.": "{0.08->2.42}这些年来,生化人一直在平静地{2.73->5.76}为管理式民主服役,现在却卷土重来了。{6.10->8.39}它们宁可死在战场上,也不愿服从{8.51->9.58}超级地球的统治?{10.46->11.62}这真是太蠢了。", + "{0.00->1.20}This is crazy!": "{0.00->1.20}太可怕了!", + "{0.00->1.45}The Acamar system": "{0.00->1.45}天园六星系", + "{0.00->2.73}It's like you're under my skin...": "{0.00->2.91}我的身心再次完整了……", + "{0.00->1.39}The Hesoe system": "{0.00->1.39}海索星系", + "{0.00->1.82}Liberty save me!": "{0.00->1.82}解放保佑!", + "{0.03->3.38}5 minutes left. We can't stay this low much longer, Helldiver.": "{0.03->3.38}还剩5分钟。绝地潜兵,不能再耽误了。", + "{0.00->3.09}You cannot allow the bugs to infest this planet.": "{0.00->3.09}你不能放任虫族占据这颗星球。", + "{0.00->0.90}Advancing!": "{0.00->0.95}继续推进!", + "{0.02->0.89}Taking cover!": "{0.00->0.92}寻找掩护!", + "{0.00->4.31}Today's defeat stokes the forge of tomorrow's victory.": "{0.00->4.31}今日的战败是为明日的胜利奠基。", + "{0.11->0.78}Never doubt...{1.35->2.64}never doubt...": "{0.00->0.82}忠诚…{1.85->3.07}忠诚…", + "{0.00->2.49}Democracy fills my sample container.": "{0.00->2.49}样本容器装满了民主。", + "{0.00->2.54}A patriot right down to your fingertips!": "{0.00->2.77}直达神经末梢的爱国主义精神!", + "{0.00->4.69}True citizens of Democracy can spot fascism with a single glance. {5.10->8.75}Consult your Loyalty Pamphlets to brush up on the telltale signs!": "{0.00->4.22}真正心怀民主的公民只需一眼就能察觉法西斯主义。{4.84->9.13}仔细阅读忠诚手册,学习辨别法西斯主义迹象的方法!", + "{0.00->1.67}They knew what they signed up for.": "{0.00->1.67}这是他们自愿的选择。", + "{0.00->1.26}Breathe easy, citizen.{1.67->3.61}We got Helldivers with us.": "{0.00->1.26}同胞,放心吧。{1.67->3.07}有绝地潜兵在。", + "{0.00->0.28}Oh,{0.81->2.39}you uh, let me win?": "{0.00->2.72}噢,你故意让我赢的吗?", + "{0.00->1.39}The Gacrux system": "{0.00->1.39}十字架一星系", + "{0.01->3.77}A Helldiver! A real Helldiver!": "{0.86->3.77}绝地潜兵!真的是绝地潜兵!", + "{0.01->1.91}Live to Liberate another day!": "{0.01->1.91}改天再为解放而战!", + "{0.03->1.96}It wants my brain!": "{0.03->1.96}它想吃我的脑子!", + "{0.02->1.21}Artifact collected.": "{0.02->1.21}古物到手了。", + "{0.05->2.40}We'd spend all day making Bots outta whatever we could find.": "{0.05->2.40}我们会花上一天,用找到的杂物制作机器人。", + "{0.01->2.07}MAN I wish I could shoot like that!": "{0.01->2.62}天啊,真希望我也有那种枪法!", + "{0.00->1.48}Biological sample secured.": "{0.00->1.48}生物样本到手了。", + "{0.00->0.69}Engaging.": "{0.00->0.69}打这个。", + "{0.00->1.43}The Partion system": "{0.00->1.43}帕尔晨星系", + "{0.00->0.73}Stay low!": "{0.00->0.73}蹲下!", + "{0.02->3.06}FIRE AT WILL! FIRE AT WILL!": "{0.00->3.08}自由开火!自由开火!", + "{0.00->0.43}Thank you.": "{0.00->0.43}谢谢。", + "{0.10->2.59}Look alive, demo-time!": "{0.00->2.54}注意点,要爆破了!", + "{0.00->0.83}At once.": "{0.00->0.83}马上。", + "{0.04->1.51}More samples. Good. {1.98->5.04}I'm looking forward to seeing what Destroyer upgrades you can get for them.": "{0.04->1.78}又拿到了样本,不错。{2.43->5.70}很期待看到你将给驱逐舰带来的新升级。", + "{0.01->1.75}Let's take the fight to them!": "{0.01->1.49}向他们发起进攻!", + "{0.00->3.60}They gave their all, for Liberty! We will do the same!": "{0.00->3.60}他们为解放付出了一切!我们也会这么做!", + "{0.04->1.70}Deploying destructive equipment!": "{0.00->1.71}我们正在部署爆破装置!", + "{0.00->1.86}Support weapon inbound.": "{0.00->1.86}支援武器马上就到。", + "{0.00->1.31}The Minchir system": "{0.00->1.31}敏雀特星系", + "{0.00->3.72}The bots terrorize this planet with their mechanized brutality. {4.24->6.50}Dive to the surface and end them.": "{0.00->3.72}机器人凭借机械化的暴行统治着这颗星球。{4.24->6.50}前往地表,将它们推翻。", + "{0.04->1.66}Shoot them! Shoot them!": "{0.04->1.66}快打它们!快打呀!", + "{0.00->1.85}Freedom never falters!": "{0.00->1.90}自由永不退缩!", + "{0.00->2.10}The Helldivers battle for Freedom. {2.58->4.90}Let us decide where to enter the fray.": "{0.00->2.10}绝地潜兵为自由而战。{2.58->4.90}请决定要参加哪片战场。", + "{0.00->0.77}Hail Super Earth.": "{0.00->0.77}超级地球万岁。", + "{0.12->0.81}OH NO, I'M SORRY!": "{0.00->2.99}天哪,抱歉抱歉!", + "{0.00->0.88}Protect us!": "{0.00->0.88}保护我们!", + "{0.02->1.19}Throwing grenade!": "{0.02->1.19}投掷手雷!", + "{0.00->1.60}The Sirius System": "{0.00->1.27}天狼星星系", + "{0.00->0.82}Manned emplacement.": "{0.00->0.82}敌方炮位。", + "{0.00->3.56}The Cyborgs have always dreamed of destroying Super Earth.{3.94->8.87}Well, that dream ends now, with the scheduled wake-up call of justice.": "{0.00->3.03}生化人一直在做摧毁超级地球的白日梦。{3.80->8.46}不过,这个梦可以结束了,正义会准时叫醒它们。", + "{0.10->1.82}Okay, time to spread out.": "{0.00->1.87}好了,该散开了。", + "{0.03->3.96}Fan out everybody, we've got this, we've got this.": "{0.00->2.11}所有人摆开阵型,{2.12->4.28}我们能行,我们一定行。", + "{0.08->3.23}Super Earth doesn't know the meaning of half measures!": "{0.08->3.23}超级地球的字典里没有半途而废!", + "{0.00->0.70}Found something.": "{0.00->0.78}这边有发现。", + "{0.28->1.94}Unleashing Democracy!": "{0.28->1.94}释放民主之力!", + "{0.26->1.96}NO ENEMY OF FREEDOM {1.96->3.75}WALKS AWAY FROM THIS!": "{0.00->1.23}自由的敌人,{1.41->3.24}一个都别想逃!", + "{0.00->1.24}Let's do this!": "{0.00->1.24}来一下子!", + "{0.05->2.84}We got mines here! 'Course we got mines here.": "{0.00->2.91}这儿有地雷!这儿明摆着有地雷!", + "{0.00->3.03}Unthinking scraps of metal thought they could beat Super Earth? Well, {3.70->4.38}think again.": "{0.00->3.39}没有思想的废铜烂铁还以为自己能打败超级地球?{3.52->4.56}痴心妄想。", + "{0.06->4.92}Another step towards Galactic liberation. You may extract when ready.": "{0.06->2.64}我们距离解放银河更近了一步,{2.98->4.92}准备好就撤离吧。", + "{0.01->2.11}Uh - For Super Earth!": "{0.01->2.11}啊…为了超级地球!", + "{0.00->1.91}Bust them all into scraps!": "{0.00->1.53}通通炸成碎片!", + "{0.00->1.15}Visibility decreasing.": "{0.00->1.15}注意,能见度降低。", + "{0.00->1.95}Contact! CONTACT!!!": "{0.00->1.95}有敌人!有敌人!!!", + "{0.00->0.62}I'll take it.": "{0.00->0.62}我来拿。", + "{0.00->1.15}Marking extraction point.": "{0.00->1.15}标记撤离点,", + "{0.00->1.60}Requesting orbital strike!": "{0.00->1.60}请求轨道攻击!", + "{0.00->1.54}The Gar Haren system": "{0.00->1.54}轧尔哈伦星系", + "{0.00->1.87}You inspire me, Helldiver!": "{0.00->1.87}绝地潜兵,你是我的榜样!", + "{0.03->1.76}The Tor E System": "{0.03->1.36}托尔E星系", + "{0.00->0.95}Changing course?{1.42->2.25}Something go wrong?": "{0.00->1.11}调整路线吗?{1.57->2.36}出问题了吗?", + "{0.01->2.18}This Tyranny will not stand!": "{0.01->2.18}暴政绝不会得逞!", + "{0.00->0.95}Asset secured.": "{0.00->0.95}已确保资产安全。", + "{0.00->7.30}Children of Super Earth, keep an ear trained on your parents for signs of rebellion! Signs include {7.51->14.60}disparaging Super Earth, distrust in managed democracy, asking questions, and any sentence that {14.60->20.41}includes the phrase \"alien rights\". A report today is a life saved tomorrow!": "{0.00->5.49}超级地球的孩子们,时刻留意你们的父母是否发表了反叛言论!{6.07->9.75}不论他们是贬低超级地球、不信任管理式民主,{9.97->14.81}还是提出质疑,或说出任何带有“外星人权利”字眼的话语,{15.06->20.85}都是反叛的迹象。你的每次举报都能挽救一条生命!", + "{0.01->0.89}Battery's drained!": "{0.01->0.89}没电了!", + "{0.00->5.49}This area is in dire need of liberation from the Terminid scourge.{5.49->7.03}Activate that terminal!": "{0.00->4.25}整个区域正在遭受终结族的侵害,亟须解放。{4.93->7.03}先去启动终端!", + "{0.00->0.78}Leave me...{1.34->2.81}save Super Earth...": "{0.00->0.78}别管我…{1.34->3.24}去救超级地球…", + "{0.06->1.66}Well done, soldier. {2.02->7.42}It takes uncommon resolve to move past the death of your ally with so little pause.": "{0.06->1.66}干得好,士兵。{2.02->7.42}只有非常坚强的人才能这么快克服友军阵亡造成的冲击。", + "{0.03->1.44}The Demiurg system": "{0.03->1.44}戴米尔基星系", + "{0.07->1.45}Sweet Liberty.{2.32->4.06}Always a sight to behold.": "{0.00->1.41}解放啊!{2.73->4.29}总是这么壮观。", + "{0.02->0.73}The enemy!": "{0.02->0.73}有敌人!", + "{0.03->2.83}Back, run, fall back!": "{0.00->2.87}撤退,快,撤退!", + "{0.01->2.86}I'm sorry! I'm sorry!": "{0.00->2.88}抱歉!我真的很抱歉!", + "{0.00->0.83}Loadout confirmed.": "{0.00->0.83}武装配置确认。", + "{0.01->2.23}Want me to go lure in some hostiles?": "{0.00->2.39}要不我再引些敌人过来?", + "{0.00->0.83}Contact!": "{0.00->0.83}来了!", + "{0.01->1.47}Calling down objective equipment.": "{0.01->1.47}呼叫目标所需装备。", + "{0.02->0.72}Take cover!": "{0.02->0.84}快找掩体!", + "{0.00->2.00}Change of plan - this way!": "{0.00->2.00}计划有变。这边!", + "{1.29->5.52}The Void is unnatural. The less time we spend inside, the better.": "{1.38->3.06}寂域违背自然规律。{3.28->5.30}待在里面的时间越短越好。", + "{0.00->2.06}Democracy will keep us safe.": "{0.00->2.06}民主会保佑我们的。", + "{0.02->0.65}We're safe!": "{0.02->0.65}我们没事了!", + "{0.01->2.60}GRENADE! Gather round, freaks!": "{0.01->2.60}手雷!怪物们,集合了!", + "{0.06->2.28}The crimes of the Cyborgs grow.{2.71->5.16}They will not be forgiven this time.": "{0.06->2.38}生化人的罪孽与日俱增。{2.82->5.37}这一次绝不会饶恕它们。", + "{0.00->1.24}Disgusting squid.": "{0.00->1.24}恶心的鱿鱼。", + "{0.32->3.26}That's right, that's Super Earth values!": "{0.00->3.39}没错,这就是超级地球的价值观!", + "{0.00->0.43}One.": "{0.00->0.43}幺。", + "{1.40->2.83}Eagle Sweat.{4.30->8.92}With an all-new formula containing 83% more sweat.{9.72->14.29}Eagle Sweat. Don't just smell it. Live it.": "{1.40->3.18}飞鹰香汗。{4.30->8.92}全新配方,香汗成分增加83%。{9.72->15.02}飞鹰香汗。闻着香,更要活得香。", + "{0.01->1.45}Protect the children!": "{0.01->1.45}保护孩子!", + "{0.00->1.73}Mission coordinates locked.": "{0.00->1.73}锁定任务坐标。", + "{0.00->1.73}It's how they would've wanted to go:{2.13->3.31}fighting Tyranny.": "{0.00->1.73}为反抗暴政献身,{2.13->3.31}也算死得其所。", + "{0.01->1.49}Lightening Liberty's load!": "{0.01->1.49}为自由助力!", + "{0.02->0.80}Hold Position!": "{0.02->0.80}原地待命。", + "{0.00->1.10}The Rogue system": "{0.00->1.10}罗格星系", + "{0.00->2.16}The Cyborgs cannot run.": "{0.00->2.25}生化人已无路可逃。", + "{0.00->2.49}Repel these mucilaginous marauders.": "{0.00->2.49}击退这些粘兮兮的掠夺者。", + "{0.00->0.48}West.": "{0.00->0.48}西边,", + "{0.00->1.72}At least I saw{2.25->3.33}the Helldivers...": "{0.00->3.44}至少见到绝地潜兵……", + "{0.02->2.56}Another great day for Democracy.": "{0.00->2.54}民主又迎来了美好的一天。", + "{0.03->1.37}It's the Illuminate!": "{0.03->1.37}光能者来了!", + "{0.00->1.91}The existence of high-casualty missions {2.32->5.10}implies the existence of low-casualty missions. {5.87->7.90}And we can take some solace in that.": "{0.00->1.63}既然有高伤亡的任务,{1.98->3.68}必然就有低伤亡的任务,{4.12->6.59}这样想至少能自我安慰。", + "{0.04->2.44}I say again: reinforcement is available.": "{0.04->2.44}重复:增援准备就绪。", + "{0.00->0.65}Supplies.": "{0.00->0.65}补给,", + "{0.05->5.76}The forms of these Cyborgs differ from those fought in the First Galactic War. {6.32->11.90}They have altered their augmentations, but their violent, hateful nature remains the same.": "{0.05->5.56}与第一次星系战争时相比,这些生化人的形态已经改变了。{5.99->11.97}虽然他们实现了强化技术的改造,但暴虐仇恨的本性依然没变。", + "{0.00->5.92}A Helldiver? Sir or uh, Ma'am, it is the GREATEST honor.": "{0.00->5.31}绝地潜兵?见到你是我最大的荣幸。", + "{0.00->2.79}The Cyborgs hide behind their battlements,{3.18->8.08}employing an army of replaceable slaves to fight their war for them.{8.73->14.15}Despite all their augmentations, they have not rid themselves of cowardice.": "{0.00->2.27}生化人躲在工事后面,{2.49->7.04}指挥着随时都能替换的奴隶军队替它们作战。{7.69->9.91}尽管进行了全面改造,{10.42->14.22}但它们依然摆脱不了懦弱的本性。", + "{0.02->1.77}It's the Helldivers!": "{0.02->1.41}是绝地潜兵!", + "{0.01->1.78}Stims, quick!": "{0.00->1.83}给我一针,快!", + "{0.16->1.27}This evens the odds.": "{0.00->1.07}这样才公平。", + "{0.00->0.69}Fourth one.": "{0.00->0.69}第四个。", + "{0.00->1.74}The Logisticae System": "{0.00->1.10}后勤星系", + "{0.07->0.88}ETA T-{1.42->1.82}1 minute.": "{0.01->1.65}预计1分钟后到达。", + "{0.01->2.20}Nothing's gonna mess with this!": "{0.01->2.20}没人敢和这大宝贝儿作对!", + "{0.00->0.37}Move.": "{0.00->0.37}走。", + "{0.00->1.39}Calling down a support weapon.": "{0.00->1.39}呼叫支援武器。", + "{0.00->1.34}Launch initiated.": "{0.00->1.34}现在开始发射。", + "{0.00->2.94}A ship without a Service Technician is like a Helldiver without...{3.46->4.12}without a...{4.71->6.04}well, it's good to have her back.": "{0.00->3.27}没有维修技术员的舰船就像绝地潜兵没有……{3.62->4.52}没有……{5.47->6.92}算了,她能回来真好。", + "{0.03->1.68}Kill them! Kill them!": "{0.03->2.05}杀了它们!快杀了它们!", + "{0.00->1.67}High-value sample collected.": "{0.00->1.67}高价值样本到手了。", + "{0.03->1.51}Cover the flanks!": "{0.00->1.47}掩护我方侧翼!", + "{0.00->1.79}Will the shuttle have enough room for all of us?": "{0.00->1.79}运输船能装下所有人吗?", + "{0.00->1.65}Death won't win today!": "{0.00->1.61}不怕死就不会死!", + "{0.00->0.47}Walker.": "{0.00->0.47}步行机甲,", + "{0.02->1.17}Automatons!": "{0.02->1.17}机器人!", + "{0.00->1.58}The Hammarby System": "{0.00->1.14}哈马比星系", + "{0.06->2.78}Hurry, fan out, let's go!": "{0.00->1.82}快点,散开,{1.82->2.85}我们走!", + "{3.29->4.64}The Void plays by different rules. We'll have to adapt.": "{0.00->2.71}寂域的规则非常地怪异。{3.39->4.81}我们必须适应。", + "{0.03->2.42}Guh! That smarts.": "{0.00->1.36}呃!{1.36->2.48}痛死了。", + "{0.00->1.25}The Skitter system": "{0.00->1.25}斯基特星系", + "{0.00->0.21}E-{0.57->3.22}710, the galaxy's greatest energy source.": "{0.00->1.32}710元素,{1.64->3.40}全星系最棒的能源。", + "{0.04->3.79}The Void claims more honorable heroes.": "{0.00->3.90}更多英雄被寂域夺去了生命。", + "{0.03->1.66}Just like in the movies.": "{0.00->1.83}简直跟拍电影似的。", + "{0.01->2.47}Trigger's set! Gangway!": "{0.01->2.87}引爆器就位!都让开!", + "{2.75->6.19}Barely even felt it...": "{1.86->5.49}根本没感觉…", + "{0.00->2.17}Crystallized E-710 acquired.": "{0.00->2.17}710元素晶体到手了。", + "{0.00->1.78}Mission accomplished, Helldiver. {2.20->4.10}One small step for Democracy, {4.75->7.23}one giant leap in the death count of our enemies.": "{0.00->2.28}绝地潜兵,任务完成。{2.85->4.60}这是民主的一小步,{4.81->7.56}却是敌人死亡总数飙升的一大步。", + "{0.14->1.46}I always knew you'd come.": "{0.00->1.63}我一直坚信你们会来。", + "{0.00->1.07}Requesting vehicle!": "{0.00->1.07}请求载具!", + "{0.02->1.20}Team reload required.": "{0.02->1.20}给我来点弹药。", + "{0.00->1.36}The Bekvam system": "{0.00->1.36}贝克温星系", + "{0.00->0.69}Follow me.": "{0.00->0.69}跟我走。", + "{0.02->1.16}Danger close!": "{0.02->1.16}危险距离!", + "{0.05->1.25}Come on!": "{0.00->1.44}一起上啊!", + "{0.01->1.15}The tentacles!": "{0.01->1.15}是触手!", + "{0.00->2.69}They're no match for the Helldivers!": "{0.00->2.69}它们根本不是绝地潜兵的对手!", + "{0.02->6.71}They may cling to Cyberstan for now, but forever? Heh, that's statistically improbable.": "{0.02->3.59}它们现在能死守生化斯坦,但能守一辈子吗?{4.04->6.71}呵,统计学来说不太可能。", + "{0.00->0.88}Deep breaths...": "{0.00->0.94}深呼吸……", + "{0.02->1.98}Go back to where you came from!": "{0.00->1.35}滚回你的老家去!", + "{0.01->2.39}Democracy will protect me...": "{0.01->2.39}民主会保佑我的...", + "{0.02->1.27}Thank Liberty!": "{0.02->1.27}感谢解放!", + "{0.00->1.49}Stim me, I'll—I'll{1.96->2.92}last this time!": "{0.00->1.45}给我一针,我——{1.45->3.09}我保证就要一针!", + "{0.09->1.77}Now, enough jibjab! {2.24->6.78}The upcoming obstacles will take everything your exceptional physique can muster. {7.29->11.95}This is it. The real deal. Get to it, soldier!": "{0.09->1.77}闲话少说!{2.24->7.26}你需要把优秀的体能运用到极致,才能克服接下来的障碍。{8.02->11.95}这才是真正的挑战。士兵,去吧!", + "{0.03->1.03}We can do this.": "{0.03->1.03}我们能行的。", + "{0.00->1.86}Get down, you sons o' dissidents!": "{0.00->1.94}趴下,你这异见分子养的!", + "{0.00->2.35}Liberty is victorious once more.": "{0.00->2.35}解放又一次获胜。", + "{0.03->1.99}The colors of Democracy!": "{0.00->2.02}这就是民主的色彩!", + "{0.01->1.03}Bug outpost!": "{0.01->1.03}虫族哨站!", + "{0.00->0.94}Deploying flare.": "{0.00->0.94}部署照明弹。", + "{0.00->2.73}Overlapping fire. Steady and true!": "{0.00->2.72}交叉火力。又稳又准!", + "{0.00->5.81}One small step for you, one giant leap for the FTL industry.": "{0.00->5.81}你们的一小步,是超光速产业的一大步。", + "{0.02->1.50}An Eagle never misses.": "{0.02->1.50}“飞鹰”弹无虚发。", + "{0.00->0.84}We're saved.": "{0.00->0.84}我们得救了。", + "{0.00->0.84}Sample collected.": "{0.00->0.84}样本到手了。", + "{0.05->1.08}For Super Earth!": "{0.00->1.18}为超级地球!", + "{0.05->0.36}Yeah, {0.91->2.77}I feel like everyone had a version of that story.": "{0.26->2.77}嗯,感觉每个人听到的这个故事都是不同的。", + "{0.00->3.80}The ground is yours. Treat it as you'd treat your own.": "{0.00->1.78}务必守住这里。{1.78->3.84}就像守护自己的家。", + "{0.00->1.11}It will be done.": "{0.00->1.11}一定完成任务。", + "{0.00->0.90}High-value item.": "{0.00->0.91}高价值物品,", + "{0.00->1.24}The Slif system": "{0.00->1.24}斯利夫星系", + "{0.87->1.10}I need stims!": "{0.09->1.10}快给我来一针!", + "{0.02->1.88}Help! Help!": "{0.02->1.88}救命!救命!", + "{0.00->1.25}Gotta swap batteries.": "{0.00->1.25}得换下电池了。", + "{0.02->2.17}Together, fire!": "{0.00->2.18}预备、开火!", + "{0.00->1.50}The Emorath system": "{0.00->1.50}艾莫拉斯星系", + "{0.01->2.09}Freedom never falters.": "{0.01->2.09}自由从不退缩。", + "{0.00->1.12}Watch for OPFOR.": "{0.00->1.15}留意敌方动向。", + "{0.00->0.53}Heavy.": "{0.00->0.69}重型敌人,", + "{0.00->0.78}Southwest.": "{0.00->0.78}西南,", + "{0.01->1.58}Give 'em everything you got!": "{0.01->1.18}不要手下留情!", + "{0.00->1.48}Requesting supplies.": "{0.00->1.48}请求投放补给。", + "{0.00->0.89}Sample collected.": "{0.00->0.89}样本到手了。", + "{0.01->3.63}Don't breathe!": "{1.20->2.66}别呼吸!", + "{0.00->2.30}Funding approved for one more reinforcement.": "{0.00->2.30}已批准拨款,可以加派一次增援。", + "{0.08->2.99}Sweet Liberty, my leg!": "{0.08->2.99}我超级自由的腿!", + "{0.02->1.76}Helldivers taking point!": "{0.00->1.84}绝地潜兵在打头阵!", + "{0.00->1.37}The Sirius system": "{0.00->1.37}天狼星星系", + "{0.00->2.76}Spread out, we've gotta spread out, go!": "{0.00->2.83}散开,我们得散开,快!", + "{0.02->0.53}Will do!": "{0.02->0.53}好的!", + "{0.00->2.76}Flags in rags, this is really happening.": "{0.00->2.81}插了个旗的,这居然是真的。", + "{0.02->1.93}Need--need assistance!": "{0.00->2.10}援助……请求援助!", + "{0.01->2.07}Look...a Helldiver..!": "{0.01->1.83}快看…是绝地潜兵…!", + "{0.00->0.38}Mag.": "{0.00->0.38}换弹匣。", + "{0.01->3.03}What in the name of Freedom...?!": "{0.01->3.03}自由也有意外…", + "{0.00->0.53}Intel.": "{0.00->0.53}情报,", + "{0.00->1.74}I owe you my life, Helldiver.": "{0.00->1.87}潜兵,我欠你一条命。", + "{0.03->2.19}INCOMING! CLEAR OUT!": "{0.00->2.38}要来了!快撤!", + "{0.00->0.95}I got one!": "{0.00->0.95}我干掉一个!", + "{0.01->1.65}Freedom save me!": "{0.01->2.07}自由保佑我 !", + "{0.00->1.66}The Grand Errant system": "{0.00->1.66}大艾伦特星系", + "{0.00->6.68}Nine out of nine doctors endorse Super Earth combat stims. Plus, they're a great source of Vitamin {6.68->10.06}D! That's Vitamin D, for Democracy. {10.62->13.65}Paid for by Permacura. There is no evidence that combat stims provide Vitamin D. Please stim {13.65->14.18}responsibly.": "{0.00->4.20}每位医生都愿意为超级地球的作战治疗剂代言。{4.68->7.98}不仅如此,这些治疗剂还富含维他命D!{8.48->10.30}维他命,为公民。{11.10->11.88}(佩玛丘拉资助研究。{11.89->14.43}没有数据表明治疗剂可以补充维他命D,请酌情使用。)", + "{0.00->2.69}Show 'em some family values!": "{0.00->2.91}展示下我们的家庭价值观!", + "{0.00->1.07}Dirty zealot!": "{0.00->1.07}垃圾玩意儿。", + "{0.00->2.17}\"Tell me, tell me!\" shouted Danny.": "{0.00->2.17}丹尼大喊:“告诉我,告诉我!”。", + "{0.04->3.71}We're advancing on Cyberstan, just like in the good old days.{4.27->10.74}It won't be easy. Unless we take on easy operations. But even then, they won't be as easy as they{10.74->12.32}would have been, otherwise.": "{0.04->4.13}我们正在向生化斯坦挺进,就像曾经的辉煌时代。{4.62->7.66}这并不简单。除非选择简单的行动。{8.38->11.87}但即便如此,也不会像以前那么简单了。", + "{7.70->10.83}Freedom's Greetings, I'm Coretta Kelly.{11.45->15.70}Super Earth High Command declared the total victory of the Great Expedition,{15.99->23.12}following the successful reduction of the Gloom's spread and the discovery of Element 711 on its planets.{23.54->26.84}Now, the Helldivers have been deployed to support a new,{26.84->36.09}even more ambitious plan to extract E-711 and use it to secure plenty of living space for all Super Earth's citizens.{36.78->40.39}This plan has been named \"Operation Free Space.\"{41.13->44.21}While the Gloom will be allowed to continue existing,{44.36->52.11}the Ministry of Defense has expressed high confidence in the Helldivers' ability to contain the amorphous space cloud.{52.82->53.90}In other news,{54.11->64.84}the heroic 10-year-old who turned in her own parents for dissident speech has become the youngest-ever recipient of the Super Presidential Medal of Ultra Freedom.{64.69->68.96}That's Liberty's Latest; I'm Coretta Kelly.": "{7.70->10.83}自由向各位问好,{11.45->15.70}我是科雷塔·凯利。{15.99->23.12}超级地球最高指挥部宣布大远征取得全面胜利,{23.54->26.84}成功遏制了“阴霾”的蔓延,并在其星球上发现了711元素。现在,{26.84->36.09}绝地潜兵也出动去支援更加野心勃勃的新计划,目标是提取711元素,{36.78->40.39}并利用它为所有超级地球公民占领充足的生存空间。{41.13->44.21}这项计划命名为“自由太空行动”。虽然国防部允许“阴霾”继续存在,{44.36->52.11}但也表示高度信任绝地潜兵有能力遏制这团无形的太空云团。下一则新闻,{52.82->53.90}举报亲生父母发表异见言论的10岁英勇女孩已成为超级总统至高自由奖章史上最年轻的授勋者。{54.11->64.84}以上就是今天的《解放新闻》,{64.69->68.96}我是科雷塔·凯利。", + "{0.01->4.16}Sweet, sweet Helldiver! You'll be okay! You'll be...": "{0.01->4.94}我的天啊,绝地潜兵!你会没事的!你不会…", + "{0.01->1.12}Target reached.": "{0.00->0.86}抵达目标。", + "{0.03->1.38}For Super Earth!": "{0.00->1.49}为了超级地球!", + "{0.01->3.36}The only thing that burns brighter is Freedom itself.": "{0.01->3.36}能比它更加耀眼的,就只有自由。", + "{0.00->0.66}You win.": "{0.00->0.66}你赢了。", + "{0.00->3.04}Finish this fight, as they would have.": "{0.00->3.04}代替他们结束这场战斗吧。", + "{0.02->1.90}For Lady liberty!": "{0.00->2.02}为了自由女神!", + "{0.02->1.69}Victory awaits us!": "{0.02->1.69}胜利等待着我们!", + "{0.00->0.12}Take{0.48->2.85}this ground for all citizens!": "{0.00->3.08}为了全体公民,拿下这里!", + "{0.00->4.74}I do not believe the Exostorms are the endgame of the Illuminate plans.{5.27->5.91}No,{6.29->10.28}I fear they merely herald something far worse.": "{0.00->4.13}我认为异界风暴并不是光能者计划的最终目标。{4.65->9.84}不,恐怕这只是前兆,更可怕的灾变还在后头。", + "{0.00->2.17}They're going for both Cyberstan and Super Earth, huh?{3.10->7.34}Well, Liberty has two fists, and she's ambidextrous.": "{0.00->3.80}它们想同时拿下生化斯坦和超级地球,是吧?{4.50->7.69}自由可是有俩拳头,还都是利手。", + "{0.02->2.09}Thanks, good morale boost.": "{0.00->2.13}多谢,士气大振。", + "{0.00->0.75}Get some! {1.22->2.15}GET SOOOOME!": "{0.00->0.96}给我死!{1.22->2.42}给老子死!", + "{0.00->1.42}I need stims.": "{0.00->1.42}给我来一针。", + "{0.00->0.34}One.": "{0.00->0.34}幺。", + "{0.01->5.21}To die for the cause... no greater...honor...": "{0.01->5.21}为大业献身…是至高无上的…光荣…", + "{0.03->1.32}I need stims!": "{0.00->1.33}快给我来一针!", + "{0.04->1.80}What in Liberty's name!?": "{0.04->1.80}解放他大业的!?", + "{0.00->0.49}Sample.": "{0.00->0.45}样本,", + "{0.04->3.95}He read all the official Super Earth histories, but it still wasn't enough for Danny.": "{0.04->3.95}丹尼读完了超级地球的正史,但是还不满足。", + "{0.04->3.24}Oh, oh wow, thanks! Thank you, I mean.": "{0.00->1.38}噢,哇哦,{1.39->3.39}谢谢!谢谢你,真心的。", + "{0.01->4.47}Kill them! Kill all of them! Teach those freaks the meaning of PAIN!": "{0.01->4.99}杀了它们!把它们杀光!让那些怪物尝尝痛苦的滋味!", + "{0.00->1.31}Priority Alert.": "{0.00->1.31}重要通知。", + "{0.04->1.22}Time for payback!": "{0.00->1.36}该还债了!", + "{0.03->1.06}More squids!": "{0.03->1.06}还有鱿鱼!", + "{0.00->0.47}Illuminate.": "{0.00->0.47}光能者,", + "{0.00->0.83}Helldiver. {1.21->3.93}The Super Destroyer is ready for your next mission.": "{0.00->1.71}超级驱逐舰时刻待命,{1.94->3.93}随时可以执行下一个任务。", + "{0.01->1.17}Gotta reload!": "{0.01->1.17}需要换弹!", + "{0.00->3.35}Local fauna identified. Possible source for emergency rations.": "{0.00->3.35}发现本地动物,紧急情况下可充当口粮。", + "{0.03->1.63}Bugs! Aaaaaah!": "{0.03->1.63}虫族!啊啊啊啊!", + "{0.01->1.86}Grenade - grenade out!": "{0.00->0.81}手雷!{1.04->2.36}小心手雷!", + "{0.01->0.79}Regroup!": "{0.01->0.79}重整队伍!", + "{0.00->0.36}1!": "{0.00->0.36}幺!", + "{0.00->1.54}Ship's in top shape, Helldiver. {1.94->4.35}Ready to dispense Democracy wherever you choose.": "{0.00->2.10}绝地潜兵,舰船状态良好。{2.40->5.02}只要选择目的地,随时可以播撒民主。", + "{0.00->0.95}Requesting walker.": "{0.00->0.95}请求步行机甲。", + "{0.00->1.39}Calling in mission shuttle.": "{0.00->1.39}呼叫任务运输船。", + "{0.00->1.42}The Pherkad system": "{0.00->1.42}北极一星系", + "{0.04->6.18}I am grateful for my assignment. My tasks suit me and I suit them.{6.18->12.32}A menial task is a glorious task. My ship needs me, and I need it.{12.32->15.25}I am grateful for my assignment.": "{0.04->1.98}我很感激分配到的工作。{2.31->4.14}我和我的任务是双向奔赴。{5.21->7.25}微小的任务也是光荣的任务。{7.78->10.82}我的舰船需要我,我也需要它。{13.15->15.11}有这工作真是太好了。", + "{0.00->0.49}Charlie": "{0.00->0.49}C", + "{0.03->2.45}Ugh... requesting stims...": "{0.00->2.59}呃……请求治疗剂……", + "{0.00->0.47}Sentry.": "{0.00->0.92}哨戒炮,", + "{0.06->2.79}Oh, you... you let me win?": "{0.00->2.85}噢,故意让我赢的?", + "{0.00->1.35}We have to get out of here!": "{0.00->1.35}我们必须得离开这儿!", + "{0.00->0.93}100 meters.": "{0.00->0.93}100米。", + "{0.02->0.86}Freedom five!": "{0.02->0.86}自由击掌!", + "{0.48->1.56}Flag-forsaken thing...": "{0.80->2.10}插他旗的玩意儿……", + "{0.00->1.52}Never seen anything like it.": "{0.00->1.68}我真是开了眼了。", + "{0.02->1.35}Flag-forsaken thumbs...": "{0.00->1.51}没旗的东西……", + "{0.00->0.78}Robot scum!": "{0.02->1.61}铁皮渣滓!", + "{0.11->4.50}The earlier version of Stratagem Hero had another whole mini-game inside of it, with its own rules {4.50->4.95}and everything.": "{0.11->5.10}初版《战略配备英雄》里面还有一个完整的小游戏,还有独特的规则,五脏俱全。", + "{0.01->1.46}How'd they even get here?": "{0.01->1.46}它们是怎么跑到这里来的?", + "{2.04->2.26}Say hello to Democracy.": "{0.06->2.26}民主驾到。", + "{0.00->1.60}I need a team reload!": "{0.00->1.60}来人帮忙换弹!", + "{0.01->2.14}Plenty more where that came from!": "{0.01->2.14}这玩意儿我们多着呢!", + "{0.02->1.46}Fire at will!": "{0.00->1.58}自由开火!", + "{0.00->0.90}We made it!": "{0.00->0.90}成功了!", + "{0.00->7.68}Remember: Those ready to sacrifice everything can never be truly harmed.": "{0.00->7.68}切记:决心牺牲一切的人永远不会真正受到伤害。", + "{0.00->0.85}Reloading you.": "{0.00->0.85}帮你换弹。", + "{0.00->2.07}Additional extraction point located.": "{0.00->2.07}发现其他撤离点。", + "{0.00->2.14}I will remember this forever!": "{0.00->2.14}我会永远记住这一刻!", + "{0.00->2.25}Super Earth's finest, back in action.": "{0.00->2.25}超级地球的精锐重返前线。", + "{0.00->1.13}Deploying minefield.": "{0.00->1.13}确认部署雷区。", + "{0.00->1.91}New battery, more Liberating.": "{0.00->1.91}新电池助力解放。", + "{0.01->2.79}Steady hands, soldiers. Do your part!": "{0.00->2.94}所有人把枪拿稳!尽全力!", + "{0.01->1.77}I'm hit! Cover me.": "{0.01->1.77}我中弹了!掩护我。", + "{0.01->1.19}Move it!": "{0.01->1.19}跑起来!", + "{0.00->1.83}We gotta stop the bleeding!": "{0.00->1.88}必须得先把血止住!", + "{0.02->8.45}Alert: Liberation of currently orbited planet from Automaton menace has ended in absolute victory. {8.69->11.61}Planet now under Super Earth control.": "{0.02->7.34}通知:击退机器人威胁,解放当前星球的行动大获全胜。{7.38->11.61}该星球现在归超级地球统治。", + "{0.00->1.03}Calling in a Hellbomb.": "{0.00->1.30}呼叫地狱火炸弹。", + "{0.02->1.20}Fire in the hole.": "{0.07->0.93}小心手雷。", + "{0.00->1.82}Super Uranium acquired.": "{0.00->1.82}超铀到手了。", + "{0.00->1.60}Sending out an SOS!": "{0.00->1.40}部署求助信标!", + "{0.00->0.71}Of course.": "{0.00->0.71}那当然。", + "{0.03->1.19}It's the Automatons!": "{0.03->1.19}是机器人来了!", + "{0.01->1.07}Move your feet!": "{0.01->1.07}动起来!", + "{0.00->0.94}Of course!{1.42->2.93}Such an honor!": "{0.00->0.94}没问题!{1.42->2.93}这是我的荣幸!", + "{0.00->1.16}For democracy!": "{0.00->1.16}为了民主!", + "{0.00->4.23}You might hear people ask, \"do we really need all those planets?\" {4.62->10.02}The truth is, if you hear this, report the traitor who said it to the nearest Loyalty Officer {10.24->11.11}immediately.": "{0.00->4.12}你可能会听到有人问:“我们真的需要那么多星球吗?”{4.72->6.88}听到这种发言,正确的做法{6.95->11.61}是立即将满嘴胡言的叛徒就近移交给忠诚事务官。", + "{0.05->3.73}Hey-hey, if you get a tank, crush some bots for me, yeah?": "{0.05->3.79}嘿嘿,你要是能弄到坦克的话,替我碾碎几个机器人,行不?", + "{0.00->1.29}Bring it down!": "{0.00->1.30}炸平这里!", + "{0.00->1.32}Dropping high-value item.": "{0.00->1.32}放下高价值物品。", + "{0.01->1.31}Slimy freaks!": "{0.01->1.69}黏了吧唧的玩意儿!", + "{0.00->2.58}We had reinforcements ready, but you didn't need them. {3.20->4.26}Excellent work.": "{0.00->2.87}我们原本准备好了增援,但是你根本用不上。{3.20->4.26}非常好。", + "{0.00->4.95}The Illuminate eat brains. Only monsters would eat brains.": "{0.00->4.62}光能者吃脑子。怪物才吃脑子。", + "{0.00->1.27}Do you know someplace safe?": "{0.00->1.53}你知道哪里安全吗?", + "{0.01->1.81}Freedom cannot die!": "{0.00->1.85}自由永不灭!", + "{0.00->2.73}Enemy reinforcements inbound. Prepare for contact.": "{0.00->2.73}敌方增援即将抵达。准备交战。", + "{0.01->0.69}Pack's out.": "{0.01->0.69}背包空了。", + "{0.00->4.54}I only regret that I have but one ship's worth of lives to give to our cause.": "{0.00->3.00}我唯一遗憾的是我只有一艘舰船的生命{3.10->4.81}能够奉献给大业。", + "{0.00->1.65}This is why we fight.": "{0.00->1.82}我们为此而战。", + "{0.00->6.20}If you've ever lost a loved one to the Bug scourge, remember, they would want you to seek {6.20->6.95}retribution.": "{0.00->3.00}如果你曾有心爱之人惨遭虫族杀害,{3.46->7.56}请记住,虫族正等着你去找它们报仇。", + "{0.00->2.68}Watching Helldivers in action is great for crew morale. {3.24->4.41}It's even better than a {4.87->6.25}dissident execution.": "{0.00->3.99}亲眼观看绝地潜兵作战可以大幅提振船员士气,{4.25->6.57}效果比处决异见分子还要好。", + "{0.00->0.93}They have fallen,{1.55->4.76}but they prevented the spread of Tyranny's shadow.": "{0.00->4.82}他们虽已死亡,但阻止了暴政阴影的蔓延。", + "{0.00->2.33}Hostiles! Lock and load, soldiers!": "{0.00->2.64}有敌人!战士们,拿起武器!", + "{0.04->1.87}Okay, who's next!": "{0.00->1.96}好了。轮到谁了?", + "{0.00->1.69}Get re-educated!": "{0.00->1.69}再念念书吧!", + "{0.02->1.31}What in Liberty's name!?": "{0.02->1.42}解放啊...是真的吗?", + "{0.00->0.46}More!{0.97->2.39}MORE! Kill 'em all!": "{0.00->1.20}继续!继续!{1.45->3.17}全部杀光!", + "{0.00->0.94}Found something.": "{0.00->0.94}这边有发现。", + "{0.00->1.56}The Krakatwo system": "{0.00->1.56}克拉克图星系", + "{0.00->0.81}Oh wow,{1.23->2.28}so that's how it's done!": "{0.00->2.40}哇,原来是这样操作的!", + "{7.90->11.41}Freedom's Greetings, I'm your host, Coretta Kelly.{12.08->17.34}The Helldivers are advancing on Cyberstan for the first time since the planet was{17.34->21.77}seized by the Automatons at the start of the second Galactic War.{22.44->25.56}Cyberstan, once a nexus of dissidence,{25.56->30.97}has served as a center for rehabilitative labor since the end of the First Galactic War,{30.97->33.16}when the Cyborgs were defeated.{33.75->40.90}Now, we know the Cyborgs spent that time secretly plotting to once again destroy our way of life.{41.49->47.76}And the Automatons have been nothing more than mindless cannon fodder for their Socialist overlords.{48.32->54.09}Up next: \"At Any Cost,\" an adaptation of the bestselling war memoir,{54.09->57.65}is projected to break box office records this weekend.{57.84->61.21}That's Liberty's Latest; I'm Coretta Kelly.": "{7.64->11.00}自由向各位问好,我是主持人科雷塔·凯利。{11.76->14.59}绝地潜兵正在向生化斯坦推进,{14.97->19.12}自第二次星系战争爆发、该星球被机器人占领以来,{19.39->21.65}这是我方首次发起反攻。{22.49->25.01}生化斯坦曾是异议分子的集中地,{25.54->28.80}自第一次星系战争结束、生化人被追击后,{29.11->32.67}生化斯坦便成为了劳动改造中心投入使用。{33.47->36.43}我们现已查明,生化人在那段时间里{36.69->41.21}一直在暗中策划,企图再次摧毁我们的生存正道。{41.62->47.55}而机器人所扮演的角色不过是为其集权统治者充当无脑炮灰。{48.45->53.98}接下来请收看:改编自畅销战争回忆录的电影《不惜一切代价》{54.34->57.23}预计将在本周末打破票房纪录。{57.67->61.41}以上就是今天的《解放新闻》,我是科雷塔·凯利。", + "{0.02->1.64}The Angel's Venture system": "{0.02->1.64}天使投资星系", + "{0.00->2.29}Limping does not equal Liberating.": "{0.00->2.29}瘸腿无法解放。", + "{0.00->2.95}High Priority Target eliminated; Justice served.": "{0.00->2.95}已消灭高优先级目标,正义必胜。", + "{0.03->4.24}Remember: every Terminid killed is a step forward for science.": "{0.03->4.24}切记:每一只终结族,都是科学的燃料。", + "{0.03->1.57}More Terminids!": "{0.03->1.57}终结族又来了!", + "{0.03->1.92}Woo! That's the stuff!": "{0.00->1.94}呜——就是这感觉!", + "{0.01->1.80}How are there always so many of 'em?": "{0.01->1.80}它们的数量怎么一直不见少?", + "{0.00->4.11}Danny finally had all the secrets he could ever want.": "{0.00->4.11}丹尼终于掌握了他想要的所有秘密。", + "{0.04->3.08}Another flag planted for Super Earth!": "{0.00->2.95}再为超级地球插下一旗!", + "{0.00->2.14}Bot Dropships inbound to your position!": "{0.00->2.14}机器人运输舰快到你那边了!", + "{0.00->1.33}The Doublet System": "{0.00->1.33}双子裳星系", + "{0.05->3.47}An entire planet was lost to the Dark Fluid. {4.00->5.86}Our enemies will pay.": "{0.05->2.92}整颗星球都被暗液体吞噬了,{3.53->5.86}敌人必将为此付出沉重代价。", + "{0.00->2.19}Freedom will steady any ship.": "{0.13->1.83}自由驶得万年船。", + "{0.00->2.66}Wait for it... wait for it...": "{0.00->2.66}耐心一点,耐心一点!", + "{0.00->1.33}Take that, dissidents.": "{0.00->1.54}尝尝这个,异见分子。", + "{0.04->1.70}Stay strong, soldiers!": "{0.00->1.71}士兵们,撑住!", + "{0.01->1.89}Requesting objective equipment!": "{0.01->1.89}请求目标所需装备!", + "{0.04->2.94}Uh, everyone, over there -- quickly!": "{0.00->3.06}呃,所有人,那边——快!", + "{0.00->2.05}You will never destroy our way of life.": "{0.00->2.05}生存正道坚不可摧。", + "{0.01->1.37}Out of ammo!": "{0.01->1.37}弹药打光了!", + "{0.00->1.30}The Prasa system": "{0.00->1.30}普拉萨星系", + "{1.07->1.69}Th...thank you...": "{0.78->1.94}还好……有你……", + "{0.01->2.03}Our revenge will be swift!": "{0.01->1.75}我们有仇必报!", + "{0.03->2.08}Kill them! Kill them all!": "{0.03->2.08}杀了它们!都杀光!", + "{0.00->1.08}New canister.": "{0.00->1.08}新燃料罐。", + "{0.00->1.78}Illuminate artifact acquired.": "{0.00->1.78}光能者古物到手了。", + "{0.02->3.55}Now show the Helldivers what you're made of! Fire!": "{0.00->2.43}给绝地潜兵看看你们的本事!{2.43->3.53}开火!", + "{0.01->1.28}Throwing grenade!": "{0.01->1.28}投掷手雷!", + "{0.03->0.92}Fall back!": "{0.00->0.95}立即撤退!", + "{0.02->1.34}My legs!": "{0.02->1.65}我的腿!", + "{0.00->1.11}Over there! Over there!": "{0.00->1.29}在那边!在那边!", + "{0.00->0.90}Plug the hole!": "{0.00->0.90}堵住缺口!", + "{0.00->0.94}Fortifications.": "{0.00->0.79}防御工事,", + "{0.00->3.60}There's nothing sweeter than victory in the name of Freedom.": "{0.00->3.60}没有什么比自由的胜利更为甘甜!", + "{0.03->0.76}We made it!": "{0.03->0.76}成功了!", + "{0.01->1.75}That all you got?!": "{0.01->1.33}你就这点本事?!", + "{0.01->1.19}Hold the line!": "{0.01->1.19}守住阵线!", + "{0.00->1.35}The Khandark system": "{0.00->1.35}勘达尔克星系", + "{0.00->1.46}The Troost system": "{0.00->1.46}特鲁斯特星系", + "{0.05->3.61}Status: Defending against Automaton invasion. {3.99->5.68}Helldiver support requested.": "{0.00->3.36}状态:抵御机器人入侵。{3.38->5.68}请求绝地潜兵支援。", + "{0.00->0.36}Alpha": "{0.00->0.36}A", + "{0.07->1.93}Squids! Run!": "{0.07->1.93}鱿鱼!快跑!", + "{0.00->1.46}Are you sure it's safe here?": "{0.00->1.46}这里确定安全吗?", + "{0.00->0.42}No!": "{0.00->0.75}没办法!", + "{0.02->1.04}Are we nearly there?": "{0.02->1.04}快到了吗?", + "{0.00->0.87}Objective nearby.": "{0.00->0.87}目标在附近。", + "{0.00->1.41}I fight for Super Earth.": "{0.00->1.41}我为超级地球而战。", + "{0.00->0.87}Dropping package.": "{0.00->0.87}放下物品。", + "{0.00->0.75}New canister.": "{0.00->0.75}新燃料罐。", + "{0.03->1.89}Legendarium acquired.": "{0.03->1.89}传说矿物到手了。", + "{0.00->2.76}The flames of Democracy spread like wildfire.": "{0.00->2.76}民主是燎原的野火。", + "{0.00->1.68}Liberty will endure..": "{0.00->1.93}解放精神不会消亡…", + "{0.03->1.13}Deploying smokescreen.": "{0.03->1.13}确认投放烟幕。", + "{0.00->2.45}At least... we still have... the{3.20->5.01}moral high ground...": "{0.00->2.45}至少…还有…{3.20->5.01}正义的高地…", + "{0.94->2.92}I could watch this all day!": "{0.94->2.92}我看一整天也不会腻!", + "{0.00->1.14}Calling in a Hellbomb.": "{0.00->1.14}呼叫地狱火炸弹。", + "{0.00->3.80}The spread of the Cyborg Menace has been duly checked.": "{0.00->3.80}生化人威胁的扩散趋势已得到有效遏制。", + "{0.00->0.60}That one.": "{0.00->0.60}那一个。", + "{0.79->1.55}Uh, excuse me. {2.68->3.46}Please move through the training course quickly as possible. Thank you. Have a good day.": "{0.00->1.23}呃,不好意思。{1.49->3.79}请尽快通过训练场。谢谢。{4.36->5.14}祝你好运。", + "{0.16->1.95}That was almost as exciting as Liberty Day.": "{0.04->1.59}像过解放日一样。", + "{0.00->2.05}You being here means everything.": "{0.00->2.33}只要你在,就是最大的帮助。", + "{0.00->0.86}A patriot{1.23->3.14}right down to your fingertips!": "{0.00->3.05}直达神经末梢的爱国主义精神!", + "{0.00->1.67}Someone tell me where to shoot!": "{0.00->1.73}指哪打哪,我最在行!", + "{0.02->1.87}Oh, thank you!": "{0.00->1.89}哦,谢谢!", + "{0.00->0.65}War. {1.09->2.60}It brings us together. {3.02->9.79}It makes us stronger. And it leads to countless new technologies, some of them related to saving {9.79->10.34}lives. {10.90->13.41}This, is why we fight.": "{0.00->2.35}战争让我们团结一致,{2.79->4.42}也让我们更加强大。{5.23->8.56}战火燃起时,无数新科技应运而生,{8.89->11.62}有些技术甚至关乎拯救生命。{12.09->14.36}这就是我们战斗的理由。", + "{7.41->10.68}Freedom's Greetings, I'm Coretta Kelly.{11.13->14.74}The Star of Peace has completed a successful test fire,{14.86->17.88}collapsing a small moon into the size of a pebble.{18.39->23.88}The defensive station fired a beam of atomized Dark Fluid into the celestial body,{23.88->26.03}triggering a gravitational collapse.{26.86->30.99}While deployment of Dark Fluid once created the Meridian black hole,{31.16->38.10}extensive testing has shown the Star of Peace only presents a danger to Super Earth's enemies.{38.43->41.89}The powerful new technology will be put to use imminently,{41.89->47.02}following a Helldiver-led vote on where to defensively deploy the station.{47.81->52.65}In other news: are inquisitive children more susceptible to Illuminate influence?{53.07->55.23}Studies say yes, they are.{55.77->59.45}That's Liberty's Latest; I'm Coretta Kelly.": "{7.41->10.68}自由向各位问好,{11.13->14.74}我是科雷塔·凯利。和平之星已成功试射,{14.86->17.88}将一颗小卫星坍缩至鹅卵石大小。{18.39->23.88}防御空间站向天体发射原子化暗液体光束,引发了引力坍缩。{23.88->26.03}虽然暗液体的部署曾经创造出默里迪恩黑洞,{26.86->30.99}但大量测试表明,和平之星只会对超级地球的敌人构成威胁。{31.16->38.10}这项强大的新技术即将投入使用,{38.43->41.89}此前绝地潜兵已投票决定空间站的防御部署位置。{41.89->47.02}后续新闻:好奇心强的儿童是否更容易受到光能者影响?{47.81->52.65}研究表明确实如此。{53.07->55.23}以上就是今天的《解放新闻》,{55.77->59.45}我是科雷塔·凯利。", + "{0.00->1.08}I hope it hurt.": "{0.00->0.90}这下够狠了吧。", + "{0.00->1.95}Crystallized E-710 acquired.": "{0.00->1.95}710元素晶体到手了。", + "{0.00->1.86}Managed Democracy, {2.26->6.03}the pillar that keeps us safe in these trying times. {6.42->7.43}Super Earth—{7.88->9.59}governed by you.": "{0.00->1.18}时局艰难,{1.99->6.03}只有管理式民主才能保障人民的安全。{6.72->9.85}超级地球,民主当先。", + "{0.00->0.58}Helldiver. {1.32->2.80}Dire news greets us. {3.33->7.32}The Automatons have proved a greater threat to Democracy than anticipated. {7.94->11.15}The Helldivers must now fight the Automatons and Terminids both. {11.95->12.48}This {12.97->14.31}is why you were trained.": "{0.00->2.65}绝地潜兵,前线传来了噩耗,{2.92->5.82}机器人对民主的威胁大大超出了预期,{6.22->11.06}这也就意味着,绝地潜兵现在必须同时迎战机器人和终结族。{11.44->14.31}练兵千日正是为了今天。", + "{0.00->3.56}Show these alien invaders no mercy.": "{0.00->3.56}不能对这些外星侵略者手下留情。", + "{0.02->1.66}Get some! GET SOOOOME!": "{0.00->2.23}给老娘死!给我死!", + "{0.06->4.60}Mmm! Smells like squid guts in here. Must've been a good mission.": "{0.01->4.60}有一股烤鱿鱼味。看来这趟任务非常顺利。", + "{0.00->1.30}Establish security.": "{0.00->1.30}确保安全。", + "{0.00->1.00}Need fresh I.C.E.": "{0.00->1.21}换下冷却元件。", + "{0.00->1.08}Time to move!": "{0.00->1.08}该走了!", + "{0.00->1.86}Sorry, I got distracted.{2.34->3.02}What's happening?": "{0.00->1.50}对不起,我走神了。{2.01->2.44}怎么了?", + "{0.00->4.55}This city is a center of commerce. It must be defended!": "{0.00->4.55}这座城市是商业中心。必须誓死守卫!", + "{0.00->0.69}Comin' in hot!": "{0.00->0.69}火力全开!", + "{0.00->1.79}Enemy Reinforcements incoming.": "{0.00->1.79}小心,敌方增援来了。", + "{0.00->1.10}Enemy down, baby.": "{0.00->1.10}宝贝儿,打中咯。", + "{0.00->1.61}Legendary iridescence.": "{0.00->1.61}这光芒真是耀眼。", + "{0.00->2.99}The hour of our next victory rapidly approaches. {3.64->6.20}Let us cleanse the Galaxy of alien scum.": "{0.00->2.40}下一次胜利很快就要降临,{2.87->6.20}把银河系的外星渣滓彻底清除干净。", + "{0.00->0.58}Tagging map.": "{0.00->0.81}标记地图,", + "{0.00->2.86}We have reclaimed another city from the enemy.": "{0.00->3.21}我们又从敌人的魔爪中夺回一座城市。", + "{0.00->1.68}Rounds on target, soldiers!": "{0.00->1.68}战士们,向目标射击!", + "{0.00->1.81}Welcome to the bridge, Helldiver. {2.27->5.77}From here, we shall shepherd the galaxy towards Freedom. {6.34->9.24}Open the Galactic Map, and guide us to the fight.": "{0.00->2.60}绝地潜兵,欢迎来到舰桥。{3.06->5.93}我们会在这里带领星系走向自由。{6.46->9.73}开启星系地图,带领我们去战斗吧!", + "{0.02->1.71}Help me, please!": "{0.02->2.13}救我!救救我!", + "{0.07->3.77}Super Earth High Command has graced us with a sign of their approval.": "{0.07->3.77}超级地球最高指挥部对我们表示嘉奖。", + "{0.03->2.69}Take position. Achieve the objective.": "{0.00->2.73}各就各位。争取完成任务。", + "{0.02->4.15}Once we make it out of this, I'm gonna donate the rest of my salary to the war effort.": "{0.02->3.97}事成了,我就把工资都捐给部队。", + "{0.00->2.55}We're not dying here! Fall back!": "{0.00->2.52}还不是死的时候!撤退!", + "{0.00->0.30}Mag's empty.": "{0.00->0.63}弹匣空了。", + "{0.03->1.12}Don't let 'em kill you!": "{0.00->1.19}可别翻车了!", + "{0.01->0.81}Sixth one.": "{0.01->0.81}第六个。", + "{0.20->2.95}For...Super Earth...": "{0.00->3.23}为了…超级地球…", + "{0.05->4.34}I heard that Cyborgs don't even use any permits to determine who should reproduce.{6.36->8.23}It's like they don't care about their gene pool at all.": "{0.06->2.32}我听说生化人甚至连{2.46->4.37}繁衍资格许可证都不需要。{5.64->8.18}它们好像完全不在乎自己的基因库。", + "{0.00->0.95}They're coming soon, right?": "{0.00->0.95}他们快到了,对吗?", + "{6.71->7.64}FREEDOM.{9.27->12.08}YOU ENSLAVED US IN THE NAME OF FREEDOM.{13.13->17.08}YOU TRIED TO ERADICATE US IN THE NAME OF FREEDOM.{17.90->19.08}WE ENDURED.{19.64->21.22}WE SURVIVED.{22.39->25.81}WE ARE THE CYBORG LEGION.{26.46->28.59}AND NOW WE ARE FREE.{29.42->32.15}LEAVE US AND THERE WILL BE PEACE.{32.26->34.67}ELSE BE ANNIHILATED.": "{7.23->7.88}自由。{9.36->12.45}你们以自由之名奴役我们。{13.35->16.63}你们还想以自由之名消灭我们。{18.22->19.27}我们隐忍。{19.83->21.39}我们苟活。{22.74->25.84}我们是生化人军团。{26.75->28.47}此刻,我们自由。{29.79->32.05}退让,和平尚在。{32.67->35.73}对抗,必死无疑。", + "{0.00->0.92}More bots!": "{0.00->0.92}还有机器人!", + "{0.02->0.69}Done.": "{0.02->0.69}好了。", + "{0.10->0.91}Out of ammo!": "{0.10->0.91}打光了!", + "{0.00->0.77}Last reload.": "{0.00->0.77}最后的弹药。", + "{0.00->2.15}High Command has answered our need!": "{0.00->2.15}最高指挥部回应了我们的需求!", + "{0.02->1.01}Calling down equipment.": "{0.02->1.01}呼叫装备。", + "{0.00->1.49}You've done your duty. {1.88->3.95}You may extract with honor.": "{0.00->1.49}你已经完成使命,{1.88->3.95}可以光荣撤离了。", + "{0.00->0.69}Take cover!": "{0.00->0.76}找掩护!", + "{0.00->1.30}Welcome aboard, Helldiver. {1.91->4.66}We can never have too many heroes fighting for peace.": "{0.00->1.30}绝地潜兵,欢迎登舰。{1.91->4.33}我们永远欢迎为和平而战的英雄。", + "{0.00->2.82}Not a single Helldiver lost on that mission. {3.48->5.95}A result as glorious as it is atypical.": "{0.00->3.12}这次任务没有任何一位绝地潜兵阵亡,{3.67->5.57}真是罕见的辉煌成果。", + "{0.00->1.44}Black saffron harvested.": "{0.00->1.65}番黑花到手了。", + "{0.00->1.16}They're still coming!": "{0.00->1.16}它们又来了!", + "{0.04->1.65}Point me to the enemy.": "{0.04->1.65}告诉我敌人在哪儿。", + "{0.06->2.28}That's what happens when you fight Freedom.": "{0.06->2.28}这就是与自由为敌的下场。", + "{0.01->2.01}Here comes JUSTICE!": "{0.01->2.01}正义来了!", + "{0.00->2.95}How'd you like the taste of Freedom?": "{0.00->3.28}你说这自由甜不甜?", + "{0.00->1.54}Illuminate artifact acquired.": "{0.00->1.54}光能者古物到手了。", + "{0.02->1.41}Need assistance!": "{0.00->1.38}我请求救助!", + "{0.02->0.92}Get us out of here!": "{0.02->0.92}快带我们走!", + "{0.03->4.31}Every moment we ruminate, another family is torn limb from limb. {4.74->5.72}We must strike.": "{0.03->3.94}每犹豫一刻,就有一个家庭被敌人撕成碎片。{4.16->6.00}我们必须迅速出击。", + "{0.47->1.52}My legs!": "{0.06->1.52}我的腿!", + "{0.00->1.27}Here we go!": "{0.00->1.40}走起!", + "{0.00->1.06}Bullets do{1.06->3.12}NOT go through cover! You got that?": "{0.00->1.89}子弹是打不穿掩体的!{2.26->2.89}懂了吗?", + "{0.02->1.06}This is a nightmare!": "{0.02->1.06}太吓人了。", + "{0.07->2.73}Whoa. For me? Thank you.": "{0.00->2.81}哇。给我用吗?谢谢。", + "{0.00->1.64}Pelican 1 landing in progress.": "{0.00->1.64}“鹈鹕”1号正在降落。", + "{0.06->3.79}Go there, now! Don't look back!": "{0.00->1.52}去那边,{1.52->2.74}快!{2.74->3.78}别回头!", + "{0.05->3.30}Another step in the journey to galactic peace.": "{0.00->3.39}向星系和平又迈进了一步。", + "{0.01->0.56}Boarding!": "{0.01->0.56}登船!", + "{0.03->0.98}Moving up!": "{0.00->1.05}向前推进!", + "{0.07->4.56}These Illuminate ruins, they're just like this one nightmare I used to have...": "{0.07->1.54}这些光能者遗迹,{2.28->4.53}跟我以前做过的噩梦一模一样……", + "{0.00->0.68}Enemy elite.": "{0.00->0.68}敌方精英,", + "{0.09->5.93}The Cyborgs, unleashed, now seek to expand their mechano-socialist empire.{6.42->10.15}Their forces descend upon the homes of our citizens.{10.51->12.60}They must be defended.": "{0.09->5.73}挣脱束缚的生化人正试图扩张它们的机械化帝国。{6.54->9.49}它们正在袭击我方公民的家园。{10.16->12.64}誓死守卫我们的领土。", + "{0.07->2.14}Kill them! Kill all of them!{2.32->4.75}Teach those freaks the meaning of PAIN!": "{0.07->2.14}杀了它们!把它们杀光!{2.32->4.75}让那些怪物尝尝痛苦的滋味!", + "{0.04->2.89}The Illuminate believe themselves enlightened, {3.39->10.14}yet all their delving has not acquired them immunity to the liberation of an honestly-placed bullet.": "{0.04->3.05}光能者自诩通晓真理,{3.84->10.14}但无论如何探索各种力量,他们都无法抵挡正义的制裁。", + "{0.00->0.46}North.": "{0.00->0.62}北边,", + "{0.00->1.36}Liberty will not fall.": "{0.00->1.36}解放到底。", + "{0.31->1.66}The Andwell System": "{0.08->1.17}安得卫星系", + "{0.06->2.94}You saved me! Thank you!": "{0.00->3.05}你救了我!谢谢!", + "{0.80->1.66}Duck and cover!": "{0.56->1.66}快躲起来!", + "{0.07->0.84}Stims!": "{0.00->0.91}立即扎针!", + "{0.00->0.59}Right away!": "{0.00->0.59}马上就去!", + "{0.01->0.83}Dropships!": "{0.01->0.83}运输舰!", + "{0.00->0.38}Heavy.": "{0.00->0.63}重型敌人,", + "{0.00->1.04}Canister's empty.": "{0.00->1.04}没燃料了。", + "{0.00->4.62}YEEEAH! EAT LIBERTY! THERE'S ENOUGH FOR EVERYBODY!!": "{0.00->4.27}爽啊!尝尝解放!你给大家都出气了!!", + "{0.01->1.93}Showing us how it's done!": "{0.01->1.93}让大家看看你的本领!", + "{0.05->3.92}I'm hit! Sweet liberty…the blood.": "{0.05->3.92}我被击中了!解放你大业的…", + "{0.00->3.95}Please brace for impact. Please brace for impact.": "{0.00->3.95}请做好防撞准备。请做好防撞准备。", + "{0.00->1.02}It'd be an honor.": "{0.00->1.02}这是我的荣幸。", + "{0.03->1.57}Providing covering fire!": "{0.00->1.65}提供火力掩护!", + "{0.00->3.15}When I need some motivation, I like to read The Helldiver Ethos. {3.63->4.45}Picks me right up.": "{0.00->3.15}缺乏动力的时候,我喜欢读《绝地潜兵精神》,{3.20->4.70}一下子就能重新鼓舞斗志。", + "{0.00->1.93}A successful operation. {2.44->4.83}Liberty rings true this day.": "{0.00->1.11}行动成功,{1.80->4.19}解放在今日鸣响。", + "{0.00->3.56}Course, the sewage system is pretty straightforward—just a set of vacuum tubes that open out into {3.56->4.72}space like a mini airlock.": "{0.00->2.12}当然,污水处理系统结构很简单,{2.12->5.34}不过是一组对准太空的真空管道,就像一个小型气闸室。", + "{0.03->1.51}All in a day's work.": "{0.00->1.51}职责所在。", + "{0.00->0.92}Enemy emplacement.": "{0.00->0.92}敌方炮位,", + "{0.03->1.35}Squid outpost spotted.": "{0.03->1.30}发现鱿鱼哨站。", + "{0.03->1.17}Take cover!": "{0.00->1.19}寻找掩护!", + "{0.00->1.76}Pain is ephemeral!{2.02->4.10}Freedom is eternal!": "{0.00->1.55}疼痛是短暂的!{2.34->4.25}自由是永恒的!", + "{0.00->1.78}Contact! Stand by!": "{0.00->1.64}交战!准备!", + "{0.00->0.39}No.": "{0.00->0.39}不行。", + "{0.02->0.98}Augh, get it off!": "{0.02->0.98}快把它弄走!", + "{0.00->2.76}Freedom smiles on me today.": "{0.00->3.01}今天自由眷顾了我。", + "{0.04->1.08}Spread out,{1.46->1.89}now!": "{0.00->1.98}散开,就现在!", + "{0.02->1.17}Get behind something!": "{0.68->1.50}躲好!", + "{0.00->1.27}The Hopeful System": "{0.00->1.15}希望星系", + "{0.04->1.26}I'm hit!": "{0.00->1.30}我中弹了!", + "{0.03->2.65}Take up the new position, while we still can!": "{0.00->2.79}趁现在还有机会,稳住新的阵地!", + "{0.00->0.95}Let's do this!": "{0.00->0.95}来一下子!", + "{0.00->1.00}Joining the fray.": "{0.00->1.10}加入战斗。", + "{0.03->3.59}A draw against a Helldiver! Amazing!": "{0.00->3.63}居然和绝地潜兵打平了!不可思议!", + "{0.04->1.14}They're coming soon, right?": "{0.04->1.30}他们快到了,对吗?", + "{0.02->0.76}Bugs!": "{0.02->0.76}虫族!", + "{0.00->0.29}Eight.": "{0.00->0.31}八。", + "{0.08->5.18}Just then, Danny, the Stranger, and all the Stranger's friends were shot dead by heroic Loyalty {5.18->7.37}Officers, who had been watching Danny for months, {8.10->8.36}because that's what happens to dissidents. The end.": "{0.08->5.77}说时迟,那时快,英勇的忠诚事务官打死了丹尼,陌生人,和陌生人的所有朋友。{6.28->10.08}他观察了丹尼个把月,这就是异见分子的下场。", + "{0.00->2.01}Tragedy visits us this day. {2.52->5.14}But tomorrow comes retribution.": "{0.00->2.01}今日,悲剧降临;{2.52->5.14}明日,报仇雪恨。", + "{0.02->0.72}Northeast.": "{0.02->0.72}东北,", + "{1.11->2.02}I'm... hurt...!": "{0.00->2.45}我……受伤了!", + "{0.00->2.32}Atten-hut! {2.32->4.39}I'm General Brasch{4.39->8.11}—Super Earth's oldest and most grizzled war hero, {8.11->11.19}and I'm not easy to impress. {11.19->15.32}Helldiver Training is the toughest test in the galaxy{15.32->18.54}—but I can tell that doesn't scare you.{18.54->20.31}Impressive!": "{0.00->2.32}立正!{2.32->4.39}我是布拉施将军,{4.39->8.11}也是超级地球最年长、资历最深的战争英雄。{8.96->11.19}想让我高看一眼可没那么简单。{12.13->15.32}绝地潜兵的训练是银河系中最艰难的考验,{16.56->18.54}但是我看得出来,你没有被吓倒。{19.45->20.31}很好!", + "{0.00->3.11}We are close to securing another planet for Democracy. {3.61->6.70}You could be the final determinant of its salvation.": "{0.00->3.66}我们很快就能将民主的福音带到另一个星球。{3.82->6.70}你可能是它获得救赎的最后决定因素。", + "{0.00->1.40}Look at what they've done to this planet...{1.77->7.54}Exploiting every inch of it, leeching its oil, destroying the local flora to build their ugly{7.54->8.52}infrastructure...{9.45->10.48}Makes me sick.": "{0.00->1.96}看看它们把这颗星球糟蹋的……{2.39->5.00}榨干每一寸土地,汲取石油,{5.22->8.52}摧毁当地的植被,建造丑陋的基础设施……{9.84->11.10}真是令人恶心。", + "{0.06->2.16}Thank Liberty we made it.": "{0.06->2.16}解放保佑。", + "{0.03->1.61}It's fish fry night at the chow hall. {2.50->4.11}I don't know what planets they get these fish from, {4.11->6.71}and I don't care. It's all fried, and it's all good.": "{0.00->1.71}今天是食堂的炸鱼之夜。{1.87->4.90}我不知道这些鱼是从哪个星球运过来的,我也不关心。{5.17->6.88}全都是炸鱼,太爽了。", + "{0.00->2.10}They found us! Run!!!": "{0.00->2.10}我们暴露了!快跑!!!", + "{0.01->1.10}Take cover!": "{0.01->1.10}快找掩体!", + "{0.02->1.71}The Svitjod System": "{0.02->1.71}斯维特约德星系", + "{0.00->0.71}Steering clear.": "{0.00->0.71}绕开这里。", + "{0.00->1.05}Prosperity, {1.49->2.15}Liberty, {2.59->5.66}Justice. Our way of life.": "{0.00->0.80}繁荣、{1.53->2.19}解放、{2.72->3.20}正义,{3.62->5.81}我们的生存正道。", + "{0.11->1.89}Stratagems selected.": "{0.01->1.59}战略配备已选定。", + "{0.02->1.25}Freedom forever.": "{0.02->1.48}自由万岁。", + "{0.01->2.40}The bunker's this way, right?": "{0.01->2.08}地堡是在这边?对吧?", + "{0.00->1.42}It's really them...": "{0.00->1.42}他们真的来了…", + "{0.00->2.75}Super Earth doesn't surrender!": "{0.00->2.75}超级地球永不屈服!", + "{0.00->1.59}Legendarium acquired.": "{0.00->1.59}传说矿物到手了。", + "{0.00->1.90}We're here to support, Helldiver.": "{0.00->1.90}绝地潜兵,我们会支援你。", + "{0.00->2.05}The Fort Sanctuary system": "{0.00->2.05}庇护堡星系", + "{0.00->4.63}You have proven beyond doubt the mettle of the Helldivers.": "{0.00->4.34}你已证明,绝地潜兵拥有无可置疑的勇气。", + "{0.00->2.15}You inspire the soldiers, Helldiver.": "{0.00->2.42}绝地潜兵,你是战士们的榜样。", + "{0.00->0.84}I'm empty!": "{0.00->0.84}没弹药了!", + "{0.00->1.44}Calling in reinforcements!": "{0.00->1.44}请求投放新的增援!", + "{0.11->2.39}Freedom owes you a debt.": "{0.11->2.39}你为自由立下大功。", + "{0.00->3.77}Sometimes the price of victory is the blood of heroes.": "{0.00->3.77}有时,胜利的代价就是要英雄挥洒热血。", + "{0.00->3.05}This is the nexus of the Automaton war machine.{3.60->4.61}Dismantle it,{4.90->8.54}that the galaxy be freed of Tyranny's chains.": "{0.00->3.80}这里是机器人战争机器的核心枢纽。{4.51->8.50}摧毁它,让银河系摆脱暴政的枷锁。", + "{0.04->1.01}We're safe now!": "{0.04->1.01}我们安全了!", + "{0.00->1.27}SEAF support incoming.": "{0.00->1.34}武装部队前往支援。", + "{0.00->1.08}Requesting tac-pack.": "{0.00->1.08}请求投放战术背包。", + "{0.01->1.23}Last reload!": "{0.01->1.23}最后的弹药!", + "{0.00->1.35}We shall prevail!": "{0.00->1.35}我们必将胜利!", + "{0.00->0.71}Sixth one.": "{0.00->0.71}第六个。", + "{0.01->3.00}You'll pay for that, alien scum!": "{0.01->2.60}外星畜生,都等死吧!", + "{0.00->0.81}Dropships!": "{0.00->0.70}运输舰!", + "{0.00->1.05}Calling in an Eagle.": "{0.00->1.05}请求飞鹰支援。", + "{0.00->2.76}This atrocity will not go unanswered.": "{0.00->2.76}此等暴行必有报应。", + "{0.01->1.30}Out of ammo!": "{0.01->1.30}弹药打光了!", + "{0.00->2.42}Helldiver, you are moving outside the mission area.": "{0.00->2.42}绝地潜兵,你即将远离任务区域。", + "{0.00->1.53}Take that, dissidents.": "{0.00->1.65}尝尝这个,异见分子。", + "{0.00->2.22}Soldiers! Attention!": "{0.00->2.22}战士们!立正!", + "{0.00->6.25}They gave their last breaths ensuring the immortality of Managed Democracy.": "{0.00->6.25}他们用最后一口气确保管理式民主永恒不朽。", + "{0.00->1.79}That's called Democracy!": "{0.00->1.79}这就是民主!", + "{0.00->1.75}Select an operation, Helldiver.": "{0.00->1.75}潜兵,请选择一项行动。", + "{0.00->0.71}Critical item.": "{0.00->0.71}关键物品,", + "{0.00->1.17}Calling in mission shuttle.": "{0.00->1.17}呼叫任务运输船。", + "{0.00->5.53}The fate of all humanity's children are in your hands. Do not let them fall.": "{0.00->5.53}全人类孩童的未来都掌握在你的手中,不要让他们无助地堕落。", + "{0.00->1.66}Rare sample acquired.": "{0.00->1.66}稀有样本到手了。", + "{0.00->1.55}Liberating the galaxy...{2.06->3.42}stomping bugs...{3.99->5.25}every kid's dream.": "{0.00->1.55}解放银河…{1.68->3.29}剿灭虫族…{3.33->5.25}这是每一个孩子的梦想。", + "{0.03->0.76}Get to cover!": "{0.00->0.82}快找掩护!", + "{0.06->2.06}Make a fist with your gun-wielding {2.06->2.70}hand.{2.70->4.11} Clench it.{4.11->5.01} Relax.{5.01->11.15} Now, hold your fist up in the Helldiver salute.{11.15->15.38} This fist is holding our future.{15.38->23.96} Clench it as hard as you can, for as long as your body can manage.": "{0.00->2.76}用持枪的手握拳。{3.98->5.19}握紧。{5.79->6.80}放松。{8.05->12.95}现在,举起拳头,以绝地潜兵的方式敬礼。{13.21->16.79}这只拳头紧握着我们的未来。{17.70->24.00}尽全力握紧拳头,直至力竭。", + "{0.10->6.88}All this time, the Cyborgs have been the true masterminds of the Automatons. {7.31->15.85}A development none could have foreseen...but one must always anticipate that which cannot be anticipated. {16.35->19.36}Then you can never be caught off guard.": "{0.00->5.14}原来生化人才是机器人背后真正的主谋。{6.41->9.31}虽然这结果出乎所有人预料……{10.01->15.49}但我们本来就应该要时刻防备无法预料的状况。{16.13->19.32}小心驶得万年船。", + "{0.42->5.49}Relax. Feel the endless void of space.{5.49->17.31}Feel the cold, vast loneliness pressing against the hull of your ship. Feel yourself fall.{17.31->21.34}Now, let Super Earth catch you.": "{0.00->2.09}放松身心。{2.39->5.19}感受无尽的宇宙虚空。{6.11->11.38}感受冰冷浩瀚的孤独感压迫着舰体。{12.93->15.65}感受失重坠落感。{16.43->21.63}现在,投入超级地球的怀抱。", + "{0.00->0.43}Yes": "{0.00->0.43}好的。", + "{0.02->1.86}You guys are the coolest!": "{0.00->1.97}你们最酷了!", + "{0.03->1.11}Hostiles on me!": "{0.00->1.13}敌人在打我!", + "{0.00->0.72}Welcome back. {1.17->4.36}Democracy's reach extends a bit further, thanks to you.": "{0.00->0.84}欢迎回来。{1.55->4.23}民主之光因你而愈发耀眼。", + "{0.00->1.58}Calling down objective equipment.": "{0.00->1.58}呼叫目标所需装备。", + "{0.00->3.92}At long last, Cyberstan will be free.": "{0.00->3.92}生化斯坦终于要重获自由了。", + "{0.00->1.66}The Fort Union system": "{0.00->1.66}联合堡星系", + "{0.00->1.44}Help, help me!": "{0.00->2.25}救命,救救我!", + "{0.00->1.95}You are the best of the best. {2.32->5.54}Live up to your name. Live up to Freedom.": "{0.00->1.95}你是顶级精英,{2.32->5.54}不负绝地潜兵之名,不负自由之名。", + "{0.02->2.00}Oh wow! Oh wow!": "{0.02->2.00}我去!我去!", + "{0.00->1.09}We're saved!": "{0.00->0.97}得救了!", + "{0.00->2.38}Nothing can damage Democracy!": "{0.00->2.38}民主坚不可摧!", + "{0.01->1.91}Uh, lead the way.": "{0.01->1.91}呃,你带路吧。", + "{0.06->3.05}Democracy Above, here we go again...": "{0.00->3.14}民主在上,我们又来了……", + "{0.00->5.12}Freedom marches onward, thanks to you. You may proceed to extraction.": "{0.00->2.66}在你的努力下,自由一往无前。{3.02->5.12}现在可以撤离了。", + "{0.00->0.55}Reloading.": "{0.00->0.55}换弹。", + "{0.04->1.55}What in Liberty's name!?": "{0.04->1.55}解放他大业的!?", + "{0.04->2.94}Back—eh, back at it!": "{0.45->3.05}继续……继续打!", + "{0.00->0.48}Yes!": "{0.00->0.48}好的!", + "{0.05->3.40}That will teach the Illuminate to challenge Super Earth.": "{0.05->3.40}要让光能者铭记挑衅超级地球的代价。", + "{0.07->3.45}The logistics involved in running the DSS...{4.31->6.68}I could think about it all day.": "{0.00->2.69}运行民主空间站要操心的事…{4.57->6.56}我能想上一整天。", + "{0.05->1.74}The Afoyay Bay system": "{0.00->1.74}艾福亚湾星系", + "{0.02->1.25}Reloading!": "{0.02->1.25}在换弹!", + "{0.00->0.80}Deploying flare.": "{0.00->0.80}部署照明弹。", + "{1.43->2.59}Hey, let's keep moving.": "{1.81->2.98}我们继续前进吧。", + "{0.00->1.64}High-value sample collected.": "{0.00->1.64}高价值样本到手了。", + "{0.00->2.90}Enemies of Freedom always get what they deserve.": "{0.00->2.90}自由的敌人就别指望自由了。", + "{0.00->1.37}A loss of resources. {1.97->3.12}But we will recover.": "{0.00->1.27}虽然损失了资源,{1.67->2.61}但还能恢复。", + "{0.01->1.13}Keep them back!": "{0.00->0.84}挡住它们!", + "{0.05->0.91}Stay sharp!": "{0.05->0.91}保持警惕!", + "{0.02->2.75}Retreat, retreat for Super Earth!": "{0.00->2.85}撤退,为了超级地球撤退!", + "{0.00->5.56}Every mission brings us one step closer to the full Democratization of the known universe.": "{0.00->1.25}每完成一次任务,{1.48->5.79}就能更进一步在已知宇宙范围内实现全面民主化。", + "{0.00->4.39}The planet will be ours. The only variable is time.": "{0.00->4.39}这颗星球必将属于我们。只是时间问题罢了。", + "{0.00->0.30}Enemy outpost spotted.": "{0.00->1.16}发现敌方哨站。", + "{0.00->2.55}Another step towards total eradication.": "{0.00->2.55}距离彻底根除敌人又近了一步。", + "{0.00->3.28}They gave their lives for us! Make it count!": "{0.00->3.40}他们为我们而死!不要让他们白白牺牲!", + "{0.00->3.00}Mission complete without a single friendly fire incident. That will save paperwork.": "{0.00->2.54}没有误伤友军就完成了任务,{3.15->5.10}大幅减少了文书工作。", + "{0.00->2.98}For a minute, I thought I might never vote again.": "{0.00->3.05}差点以为自己再也不能投票了。", + "{0.00->0.39}East.": "{0.00->0.39}东边,", + "{0.00->0.25}Got a sample.": "{0.00->0.78}样本到手了。", + "{0.00->0.93}A Helldiver!": "{0.00->0.93}绝地潜兵!", + "{0.00->1.70}Democracy's on its way!": "{0.00->1.70}民主马上就到!", + "{0.00->5.06}Remember: No matter your age or experience,{5.70->8.70}no matter how long you have served,{9.32->13.96}and no matter your actual contributions on the battlefield:{15.10->18.52}you helped save Super Earth.": "{0.00->5.06}切记:抛开你的年龄、资历、{5.70->10.59}服役年限和战场上的实际贡献不谈,{12.21->18.45}你的的确确帮忙拯救了整个超级地球。", + "{0.02->2.22}Our revenge will be swift!": "{0.02->2.22}我们有仇必报!", + "{0.00->3.13}Now that was what I call a profitable use of resources.": "{0.00->3.13}这就叫好钢用在刀刃上。", + "{0.00->5.42}We will avenge their memory when the Void is no more.": "{0.00->2.38}让寂域消失,{2.38->5.59}才是真正的复仇之道。", + "{0.00->1.18}Liberty guide us!": "{0.00->1.18}解放指引我们!", + "{0.00->1.73}Objective target destroyed.": "{0.00->1.73}已摧毁任务目标。", + "{0.00->1.64}Ammo, fuel, personnel—{2.07->4.92}I manage everything on this ship with one thing in mind: {5.37->8.12}making sure you have the support you need, Helldiver.": "{0.00->1.60}弹药、燃料、人员…{1.91->5.07}管理舰船的一切事务时,我都秉持一条原则:{5.53->8.18}绝地潜兵需要什么,我就提供什么。", + "{0.01->0.75}Reloading you.": "{0.01->0.75}帮你换弹。", + "{0.00->1.52}Unmapped System": "{0.00->1.20}未测绘星系", + "{0.00->1.35}The Fenmire system": "{0.00->1.35}范迈尔星系", + "{0.00->1.33}The Bicep System": "{0.00->1.12}擎穹星系", + "{0.01->1.27}Activating jump pack.": "{0.01->1.27}喷射背包启动。", + "{0.34->1.64}I was almost done for...": "{0.32->1.74}差点儿就交代了……", + "{0.01->2.02}Good riddance.": "{0.89->2.02}死得好。", + "{0.00->1.94}Legendarium acquired.": "{0.00->1.94}传说矿物到手了。", + "{0.03->0.83}Get down!": "{0.03->0.83}快趴下!", + "{0.00->1.32}Watch out for us!": "{0.00->1.32}当心点我们!", + "{0.00->1.55}You're my hero!": "{0.00->1.55}你是我的英雄!", + "{0.02->1.73}Liberty save me!": "{0.02->1.73}解放保佑!", + "{0.01->2.29}For Liberty's sake, shoot them!": "{0.01->2.55}为了解放,打死它们!", + "{0.00->1.41}The Gunvald system": "{0.00->1.41}古恩瓦尔德星系", + "{0.00->3.71}Our forces fight to keep this planet from the Terminids' clutches. {4.15->5.33}They need your help.": "{0.00->3.08}我方部队正在奋力抵抗终结族的侵略。{3.71->5.33}他们需要你的帮助。", + "{0.05->2.34}Sweet Liberty, my arm!": "{0.05->3.00}我超级自由的胳膊!", + "{0.00->0.75}How much longer?": "{0.00->0.75}还得等多久?", + "{0.04->1.89}Fallb—Fall back!": "{0.00->1.91}撤——撤退!", + "{0.05->2.16}Super Earth's counting on us!": "{0.00->2.27}超级地球就靠我们了!", + "{0.05->2.05}I hate Socialism.": "{0.70->2.22}最烦装算的东西了。", + "{0.00->1.53}Black saffron harvested.": "{0.00->1.53}番黑花到手了。", + "{0.00->0.90}Item collected.": "{0.00->0.90}东西到手了。", + "{0.21->2.07}C'mere, you big lunk o' Liberty.": "{0.00->2.18}来吧,你这自由的大块头。", + "{0.00->1.51}Calling down a sentry.": "{0.00->1.19}呼叫哨戒炮。", + "{0.00->5.86}The Democratic Transit Authority recommends that all citizens planning to attend Super Earth's {5.86->10.57}Martyrs Day celebrations book their tickets at least three years in advance.": "{0.00->6.60}民主交通局友情提醒:所有计划参加超级地球烈士纪念日活动{6.65->10.39}的公民都需提前至少三年订票。", + "{0.00->5.26}So he started asking everyone he could find if they knew any secrets, and eventually, he found {5.26->5.95}someone who did.": "{0.00->3.56}所以他开始找所有人询问他们是否知道什么秘密。{4.28->6.43}最后,他找到了一个掌握秘密的人。", + "{0.00->1.33}I need a team reload.": "{0.00->1.33}给我来点弹药。", + "{0.02->0.57}Thank you.": "{0.00->0.66}谢谢。", + "{0.00->1.25}The Choohe system": "{0.00->1.25}丘伊星系", + "{0.03->3.07}Makes me appreciate what a beautiful Democracy it'll be{3.07->5.32}once we finish stamping out those Fascist bugs.": "{0.03->3.07}我不禁感叹,等我们铲除了法西斯虫族,{3.07->5.32}民主会变得多么美好啊!", + "{0.00->3.93}I bet watchin' 'em spark and explode really lights up your Freedom-lovin' heart.": "{0.00->3.93}看着它们冒出电火花然后爆炸,肯定能鼓舞对自由的热爱。", + "{0.00->2.23}It'd be my Patriotic privilege.": "{0.00->1.77}这是我的爱国特权。", + "{0.00->2.33}Please avoid shooting the training facility {2.70->3.52}whenever possible.": "{0.00->3.34}请尽量不要射击训练设施。", + "{0.00->1.38}Calling in a Hellbomb.": "{0.00->1.38}呼叫地狱火炸弹。", + "{0.00->2.27}The flag of Super Earth!": "{0.00->2.28}高举超级地球的旗帜!", + "{0.00->1.73}This must be part of the plan...{2.17->2.57}right?": "{0.00->2.78}这肯定是计划好的吧?", + "{0.03->2.18}Sweet Liberty, it's the bots!": "{0.03->2.18}解放你大业的,是机器人!", + "{0.02->3.06}Another flag planted for Super Earth!": "{0.00->3.05}再为超级地球插下一旗!", + "{0.00->1.69}The Stolthet System": "{0.00->1.13}荣傲星系", + "{0.00->5.66}If we don't keep fighting, what happened down there will happen to every citizen of Super Earth.": "{0.00->3.11}如果我们不继续战斗,发生在那里的惨剧{3.12->5.89}就会落到每一名超级地球公民头上。", + "{0.04->1.68}For Super Earth!": "{0.00->1.77}为了超级地球!", + "{0.01->2.43}Helldivers! We can't lose!": "{0.01->2.55}绝地潜兵!我们不会输!", + "{0.00->1.43}The Lastofe system": "{0.00->1.43}赖斯斗夫星系", + "{0.01->2.09}Oh, I—thank you.": "{0.00->2.13}噢,谢谢你。", + "{0.00->0.67}Dropping item.": "{0.00->0.67}放下物品。", + "{0.02->1.26}We're gonna die!": "{0.02->1.26}我们死定了!", + "{0.00->7.72}The Megafactories appear to be proto-metropoli; factory-settlements, from which to one day expand.": "{0.00->3.99}这些超大型工厂似乎是原始都市的雏形,{4.14->7.77}也就是以工厂为据点向外扩张的定居点。", + "{0.00->2.17}One small scrap of technology, {2.72->4.84}one giant leap for Liberty.": "{0.00->1.76}科技研究一小步,{2.37->4.84}解放大业一大步。", + "{0.00->0.56}Helldiver.{1.19->2.37}Hail Freedom.": "{0.00->0.73}绝地潜兵。{1.66->2.87}自由万岁。", + "{0.00->0.54}Bug hole.": "{0.00->0.54}虫穴,", + "{0.01->2.80}Bullets do NOT go through cover!": "{0.01->2.60}子弹打不穿掩体!", + "{0.02->1.19}Gotta swap I.C.E.": "{0.02->1.19}得换冷却元件。", + "{0.18->1.82}Much appreciated, Helldiver.": "{0.00->1.85}感激不尽,绝地潜兵。", + "{0.01->0.78}What are they?": "{0.01->0.78}是什么东西?", + "{0.01->1.02}Canister's empty.": "{0.01->1.02}没燃料了。", + "{0.00->1.06}Tactical impediment.": "{0.00->0.72}战术障碍,", + "{0.02->1.67}FLAG-forsake it!": "{0.00->1.72}我插了个旗的!", + "{0.00->1.20}Orbital inbound!": "{0.02->1.08}轨道攻击来了!", + "{0.25->1.95}I feel safer already.": "{0.25->1.95}我感觉安全多了!", + "{0.01->0.98}Fire in the hole.": "{0.01->0.98}小心手雷。", + "{0.06->3.77}OUTTA THE WAY! GO! GO!": "{0.77->3.84}快离开那儿!走开!走开!", + "{0.04->1.78}Super Destroyer leaving low orbit.": "{0.04->1.78}超级驱逐舰正在离开低空轨道。", + "{0.00->2.64}So much of our land is occupied. {3.06->4.89}We must take it back.": "{0.00->2.10}敌人侵占了众多疆域。{2.53->4.89}收复失地,刻不容缓。", + "{0.00->0.58}First one.": "{0.00->0.58}第一个。", + "{0.01->1.63}I'm out!": "{0.01->1.63}没弹药了!", + "{0.01->2.59}Sweet Liberty, that stings!": "{0.69->2.88}解放你大业的,好痛!", + "{0.00->1.28}Watch your fire!": "{0.00->1.34}别打错人了!", + "{0.00->0.64}Are we safe?": "{0.00->0.75}我们安全了吗?", + "{0.00->1.72}The Family-Friend System": "{0.00->1.13}家宜星系", + "{0.02->5.67}Just catching my breath...": "{1.20->4.64}让我喘口气…", + "{0.28->1.11}My arm!": "{0.03->1.11}我的胳膊!", + "{0.00->1.85}Manning combat walker.": "{0.00->2.06}操纵战斗步行机甲。", + "{0.00->1.09}Launching smokescreen.": "{0.00->1.09}确认发射烟幕。", + "{0.03->1.30}We're being suppressed!": "{0.00->1.22}敌人火力很猛!", + "{0.03->3.44}A draw! And we'll draw together out there, too.": "{0.00->3.62}平局!我们在战场上也会这么默契。", + "{0.01->1.67}Retreat, retreat!": "{0.00->1.71}撤退,撤退!", + "{0.00->0.95}Last reload.": "{0.00->0.95}最后的弹药。", + "{0.00->0.54}Third one.": "{0.00->0.54}第三个。", + "{0.00->3.60}That casing's bulletproof, right...? Right?": "{0.00->1.56}那个外壳能防弹吧…?{3.62->4.06}对吧?", + "{0.00->1.24}The Fori system": "{0.00->1.24}佛里星系", + "{0.00->4.48}Apparently, non-compensated labor was what that strike was about, the one that{4.48->10.72}some other Service Technicians got a little too interested in. But hey, we all scored some{10.72->15.77}Professional Development Training, the bad apples got re-educated, so it all worked out!": "{0.00->3.27}看起来那次罢工是关于无偿劳动的,{3.77->7.09}就是其他一些维修技术员特别关注的那次罢工。{7.99->10.53}不过,我们都接受了职业发展培训,{11.23->13.50}那些害群之马也得到了再教育,{13.98->16.02}所以皆大欢喜!", + "{0.00->1.21}Orbital incoming.": "{0.00->1.21}轨道攻击来了。", + "{0.01->2.27}Courage and loyalty will see me through!": "{0.00->2.96}勇气和忠诚会帮我渡过难关!", + "{0.00->1.17}The Brink system": "{0.00->1.17}布林克星系", + "{0.01->3.79}An attack on Super Earth is an attack on Democracy!": "{0.01->3.25}对超级地球不敬就是对民主不敬!", + "{0.00->0.60}Fifth one.": "{0.00->0.66}第五个。", + "{0.00->1.51}The Grafmere system": "{0.00->1.51}格拉夫米尔星系", + "{0.00->1.37}Deploying flare.": "{0.00->1.37}部署照明弹。", + "{0.00->2.07}The Illuminate think they are above us.{2.53->3.53}Prove them wrong.": "{0.00->2.07}光能者自认为高人一等。{2.53->3.53}证明它们是错的。", + "{0.01->1.19}R-reloading!": "{0.00->1.22}正、正在装弹!", + "{0.01->0.85}Get behind that!": "{0.01->0.80}去那后面!", + "{0.00->4.91}Soon, not even a single spore will sully the surface of this planet.": "{0.00->4.91}很快就不会再有哪怕一个孢子来玷污这颗星球了。", + "{0.00->1.18}Calling down a walker.": "{0.00->1.18}呼叫步行机甲。", + "{0.01->2.69}Our way of life is why we fight!": "{0.01->2.37}我们为生存正道而战!", + "{0.00->2.22}How are there always so many of 'em?": "{0.00->1.89}它们的数量怎么不见少?", + "{0.03->1.51}It's the Automatons!": "{0.03->1.51}是机器人来了!", + "{0.00->4.09}This operation is complete. You have served Democracy well.": "{0.00->4.09}这次行动已完成,你为民主做出了贡献。", + "{0.00->6.02}The Illuminate, in their hubris, think us incapable of deciphering their wicked plots. {6.39->11.09}But make no mistake: we will arrest their dark machinations. {11.87->13.67}Whatever they may be.": "{0.00->6.02}狂妄自大的光能者以为我们无法破解他们的邪恶阴谋。{6.39->10.50}但我们无疑会粉碎其黑暗图谋,{11.07->13.67}无论那是什么。", + "{0.00->6.23}The word of your Democracy Officer is Law. Laws must not be broken.": "{0.00->6.53}民主官之言即为法律。我们不得违背法律。", + "{0.00->2.23}Mind your step, Diver, demo time.": "{0.00->2.36}潜兵,当心,该爆破了。", + "{0.00->1.35}The Pioneer system": "{0.00->1.35}先驱星系", + "{0.00->1.53}The New Haven system": "{0.00->1.70}纽黑文星系", + "{0.09->9.97}Can you smell it? The tantalizing scent of calamari, frying.{9.97->23.41}Whenever you see Illuminate writing, recall the scent, and refocus on your mission.": "{0.09->1.24}闻到了吗?{4.30->8.59}炸鱿鱼的诱人香味。{9.98->12.68}每次看到光能者的文字,{13.22->15.20}就回想这种香味,{19.92->23.49}将注意力重新集中到任务上。", + "{0.01->0.73}New mag.": "{0.01->0.73}新弹匣。", + "{0.00->1.89}The Basquine System": "{0.00->1.18}巴斯金星系", + "{0.05->1.39}I'm up, I'm up!": "{0.00->1.50}我没事了,没事了!", + "{0.00->4.67}The enemy has launched a surprise attack on one of our planets. It needs our aid.": "{0.00->4.67}敌人对我们的一颗星球发动袭击。那里需要我们的援助。", + "{0.00->0.46}I'm on it.": "{0.00->0.46}我来。", + "{0.21->2.89}Enemies of Freedom always get what they deserve.": "{0.07->3.04}自由的敌人就别指望自由了。", + "{0.01->1.12}Swapping battery.": "{0.01->1.04}换下电池。", + "{0.00->4.81}\"I've got all kinds of juicy secrets for a curious boy like you,\" the Stranger said.": "{0.00->4.81}那个陌生人说:“我有各种各样的诱人秘密,很适合你这样好奇的孩子。”", + "{0.02->1.54}Hold your ground!": "{0.02->1.54}不要退缩!", + "{0.00->2.37}The East Iridium Trading Bay system": "{0.00->2.37}东铱贸易湾星系", + "{0.01->0.56}Get in!": "{0.01->0.56}上来!", + "{0.00->1.63}Democracy conquers all.": "{0.00->1.63}民主征服一切。", + "{0.02->1.04}They're not letting up!": "{0.00->1.39}敌方火力太猛烈了!", + "{0.01->0.80}Get 'em!": "{0.00->1.03}消灭它们!", + "{0.14->1.84}So what, the Cyborgs are back?{2.45->3.74}Big deal! {4.27->5.53}We always knew this day would come. {6.24->8.97}The Service Technician forums have predicted this for like,{9.49->10.51}eighty years already.": "{0.09->3.00}什么,生化人还是回来了?{3.58->4.51}大事啊!{5.44->7.26}我们早就知道这一天会到来。{7.47->10.53}维修技术员论坛早在八十年前就预测过了。", + "{0.01->1.76}KILL 'EM ALL!!!!": "{0.01->1.76}全部杀光!!!!", + "{0.02->1.00}Yes! Push{1.61->2.36}forward!": "{0.02->0.61}好!{0.95->2.05}前进!", + "{0.04->2.71}Hah! As expected!": "{0.00->1.42}哈!{1.43->2.87}毫不意外!", + "{0.01->2.98}That casing's bulletproof, right...? Right?": "{0.01->2.90}那个外壳能防弹吧…?对吧?", + "{0.00->0.49}Close.": "{0.00->0.49}很近。", + "{0.04->1.83}It's going to cut me open!": "{0.04->1.83}它要把我给撕了!", + "{0.00->0.47}5!": "{0.03->0.43}5!", + "{0.02->2.60}You guys do this all the time. Right?": "{0.02->1.02}你们都是老手了,{1.89->2.40}对吧?", + "{0.04->3.08}Supressing fire! Now! NOW!!": "{0.00->3.16}火力压制!快!快!", + "{0.00->0.51}South.": "{0.00->0.51}南边,", + "{0.00->1.95}The Outpost 32 system": "{0.00->1.95}32号哨站星系", + "{0.05->1.21}Move, move, move!": "{0.05->1.21}快,快,快!", + "{0.63->1.15}We're all gonna die!": "{0.00->1.68}我们全都死定了!", + "{0.00->0.87}Like a goldfish, {1.62->2.57}or even a hamster.": "{0.00->1.04}比如一条金鱼,{1.27->2.57}或者一只仓鼠也好。", + "{0.03->1.45}The Acrab system": "{0.03->1.45}房宿四星系", + "{0.04->3.17}Nothing fills you up like the taste of Democracy!": "{0.00->3.25}没什么比民主的滋味更让人满足了!", + "{0.02->1.70}Cover, move, move!": "{0.00->1.73}掩护,前进,快!", + "{7.57->10.72}Freedom's Greetings, I'm Coretta Kelly.{11.05->13.49}In a triumphant display of Democracy,{13.70->19.09}the Star of Peace has successfully been activated in the defense of Super Earth.{19.55->24.81}The Helldivers voted to defend our citizens by pre-emptively neutralizing a{24.81->29.62}highly threatening planet harboring known enemies of Freedom.{30.11->36.68}The space formerly occupied by the planet is now free from the Terminid's tyrannical presence.{37.12->41.15}All that remains is a highly-compressed boulder-sized mass,{41.48->44.60}which is being kept under round-the-clock surveillance.{45.42->50.24}Citizens across the galaxy have been advised to celebrate the newfound{49.95->54.58}era of peace and prosperity ushered in by the Helldivers.{54.86->59.24}That's Liberty's Latest; I'm Coretta Kelly.": "{7.57->10.72}自由向各位问好,{11.05->13.49}我是科雷塔·凯利。{13.70->19.09}在民主的胜利表明,{19.55->24.81}和平之星已成功激活,{24.81->29.62}即将守卫超级地球。{30.11->36.68}绝地潜兵投票决定,{37.12->41.15}先发制人清除一颗窝藏自由之敌的高威胁星球来保卫我们的公民。{41.48->44.60}原先被该星球占据的空间现已摆脱终结族的暴虐掌控。{45.42->50.24}建议全银河系的公民共同庆祝绝地潜兵辛勤打拼得来的和平繁荣新时代。{49.95->54.58}以上就是今天的《解放新闻》,{54.86->59.24}我是科雷塔·凯利。", + "{1.73->3.95}A draw! And we'll draw together out there, too.": "{0.00->1.65}平局!{1.65->4.25}我们在战场上也会这么默契。", + "{0.00->0.49}Zero.": "{0.00->0.49}洞。", + "{0.00->4.24}The average Helldiver mission approaches the cost of a Liberty-class Cruiser. {4.88->7.81}Just goes to show how critical our mission is to the war effort.": "{0.00->2.15}绝地潜兵执行任务的平均成本{2.43->4.53}接近一艘解放级巡洋舰的造价。{4.79->8.16}只是想说明我们的任务对这场战争有多么关键。", + "{0.02->1.54}Cover, move, move!": "{0.00->1.53}掩护,前进,前进!", + "{0.00->1.06}Objective cleared.": "{0.00->1.11}目标已清除。", + "{0.00->1.23}Requesting air support.": "{0.00->1.23}请求空中支援。", + "{0.03->0.90}Kill them all!": "{0.03->1.09}把他们杀光!", + "{0.00->2.37}Thanks Helldiver, I needed the humility.": "{0.00->2.61}谢谢你潜兵,我正需要这份谦卑。", + "{0.13->7.88}Alert: Defense of currently orbited planet from Automaton invasion has ended in temporary defeat. {8.53->11.65}Planet now under Automaton control.": "{0.00->7.23}通知:当前星球抵御机器人入侵的行动暂时失利。{7.28->11.65}该星球现在归机器人统治。", + "{0.04->1.75}The New Insight System": "{0.04->1.18}新悟星系", + "{0.03->0.86}Let's go!": "{0.00->0.91}这下可以了!", + "{0.00->0.40}Nine.": "{0.00->0.47}勾。", + "{0.01->3.05}The might of Super Earth!": "{0.01->3.05}这是超级地球的力量!", + "{0.02->1.47}It's the Automatons!": "{0.02->1.47}是机器人来了!", + "{0.02->2.72}Feel Democracy's warm embrace!": "{0.02->2.72}感受民主的温暖拥抱!", + "{0.00->1.01}Safe and sound.": "{0.00->1.01}非常安全。", + "{0.02->1.89}It's going to cut me open!": "{0.02->1.89}它要把我给撕了!", + "{0.00->1.15}We did it.{1.80->3.54}The Void is gone.": "{0.00->1.58}成功了。{1.83->3.79}寂域消失了。", + "{0.04->2.18}Dispense that Freedom!": "{0.00->2.26}彻底释放自由吧!", + "{0.00->8.81}Steel your heart. Let nothing in. You are empty; you are numb;{10.21->12.07}you are at peace.": "{0.00->5.09}坚定内心。抵御一切侵扰。{5.85->8.31}你的内心空无一物,{8.94->12.07}麻木,平静。", + "{0.00->1.43}They're coming!": "{0.47->1.53}它们来了!", + "{0.00->1.62}Help! HELP!!!": "{0.00->1.69}救命!救命!!", + "{0.07->1.27}Thank you for saving us.": "{0.07->1.54}谢谢你们来救我们。", + "{0.00->0.95}Bug tunnel breach.": "{0.00->0.95}虫族隧道洞口,", + "{0.01->0.74}Reloading.": "{0.01->0.74}换弹。", + "{0.02->0.70}Right away!": "{0.02->0.70}马上!", + "{0.00->2.90}Victorious throughout the stars.": "{0.00->3.05}胜利传遍宇宙群星。", + "{0.01->2.14}S'gotta be somewhere safe!": "{0.01->2.14}肯定会有安全的地方!", + "{0.00->0.47}Ok!": "{0.00->0.47}好的!", + "{0.00->4.19}We cannot allow the Illuminate to exert their influence unobstructed.": "{0.00->4.19}我们绝对不能让光能者继续为所欲为。", + "{0.00->2.64}Every Helldiver lost is an unspeakable tragedy, {3.23->6.62}but this mission had fewer unspeakable tragedies than average.": "{0.00->3.32}哪怕只折损一位绝地潜兵,也是莫大的悲剧,{3.77->6.62}但这次任务发生的悲剧比平常更少。", + "{0.00->4.54}Super Destroyer leaving low orbit. Emergency Extraction shuttle deployed": "{0.00->4.54}超级驱逐舰正在离开低轨道。已部署紧急撤离运输船。", + "{0.00->1.78}Liberty for every being.": "{0.00->1.78}一切皆可解放。", + "{0.00->0.48}Vehicle.": "{0.00->0.48}载具,", + "{0.00->0.91}Dropping package.": "{0.00->0.91}放下物品。", + "{0.00->0.36}Move.": "{0.00->0.36}走。", + "{0.01->1.27}IT CAN'T BE!!": "{0.00->1.27}不可能!!", + "{0.00->0.70}Steering clear.": "{0.00->0.70}绕开这里。", + "{0.01->2.18}Retreat, retreat for Super Earth!": "{0.00->2.28}撤退,为了超级地球撤退!", + "{0.00->1.12}I'll handle the terminal.": "{0.00->1.12}这个终端交给我。", + "{0.00->0.52}Nevermind.": "{0.00->0.52}算了。", + "{0.02->0.81}Look out!": "{0.02->0.81}小心!", + "{0.06->3.04}Eagle 1, ready to unleash Liberty on your command.": "{0.06->3.04}“飞鹰”1号随时听令,准备释放解放之火。", + "{0.00->2.16}Another step closer to closing the Void.{2.67->4.35}Can't come soon enough.": "{0.00->2.46}我们朝关闭寂域又迈进了一步。{2.95->4.16}事不宜迟。", + "{0.01->1.88}Target hit! Target hit!": "{0.01->1.88}命中目标!命中目标!", + "{0.00->1.93}The Prosperity Falls system": "{0.00->1.93}繁荣瀑布星系", + "{0.00->1.27}We have to keep moving.": "{0.00->1.27}我们必须继续前进。", + "{0.01->0.56}Right away!": "{0.01->0.79}马上就去!", + "{0.00->0.93}How far are we going?": "{0.00->1.21}我们要走多远?", + "{0.00->2.07}Brain-eating terrorists.": "{0.00->2.21}吃脑子的垃圾玩意儿。", + "{0.00->4.94}This is the fate of all humankind, if the Cyborgs are not stopped.": "{0.00->4.99}如果不阻止生化人,全人类都会变成这样。", + "{0.01->1.14}Little close for comfort!": "{0.01->1.14}实在太近了!", + "{0.00->2.43}The fate of this planet hangs in the balance. {3.01->5.07}You must tip the scales.": "{0.00->2.01}这颗星球危在旦夕,{2.70->5.14}只能靠你扭转局势。", + "{0.00->0.56}Hellbomb.": "{0.00->0.79}地狱火炸弹,", + "{0.00->2.38}Like hugging an action figure.": "{0.00->2.39}就像在抱动作片巨星。", + "{0.00->0.91}Heroic!": "{0.00->0.97}英雄之举!", + "{0.01->3.96}Hellbomb secured. Give the 'divers space to work.": "{0.01->3.96}找到地狱火炸弹了。给潜兵腾出点地方。", + "{0.05->0.82}What are they?": "{0.05->0.82}是什么东西?", + "{0.00->4.18}Helldivers to Hellpods. Repeat: Helldivers to Hellpods.": "{0.00->4.18}绝地潜兵进入喷射舱。重复:绝地潜兵进入喷射舱。", + "{0.01->2.92}Here they come - about time!": "{0.01->2.92}它们来的,正是时候!", + "{0.00->1.44}Democracy isn't done with you yet.": "{0.00->1.44}民主大业跟你没完。", + "{0.00->1.44}Establish a perimeter!": "{0.00->1.44}建立防线!", + "{0.00->2.48}History in the making! Yeah!": "{0.00->2.48}我们在创造历史!爽啊!", + "{0.01->2.11}Bust them all into scraps!": "{0.01->1.79}通通炸成碎片!", + "{0.00->1.29}The Wraith system": "{0.00->1.29}幽灵星系", + "{0.00->1.33}Requesting sentry.": "{0.00->1.33}请求哨戒炮。", + "{0.01->2.34}DEATH TO ALL SQUIDS!": "{0.01->2.03}都给我死!鱿鱼!", + "{0.00->0.58}Fire!": "{0.00->0.58}开火!", + "{0.05->1.93}The Lynx Lynx System": "{0.05->1.24}猞猁星系", + "{0.00->2.42}Another proud day for Super Earth!": "{0.00->2.70}又是为超级地球而自豪的一天!", + "{0.00->3.28}I'm not worried about these Illuminate sightings. If they come back, {3.66->6.41}we'll send 'em packing like we did in the First Galactic War.": "{0.00->1.98}我并不担心光能者来犯。{2.23->6.71}就算它们回来,我们也能像第一次星系战争那样把它们赶走。", + "{0.00->1.06}Tac-pack's empty.": "{0.00->1.06}战术背包空了。", + "{0.00->0.95}Tac-pack's empty.": "{0.00->0.95}战术背包空了。", + "{0.03->1.23}More bots!": "{0.03->1.23}还有机器人!", + "{0.00->2.91}We cannot let the enemy any closer to Super Earth.": "{0.00->2.91}不能让敌人再接近超级地球一步。", + "{0.00->1.13}Ready to Liberate.": "{0.00->1.13}准备好解放。", + "{0.01->1.20}Suppressing fire!": "{0.01->1.04}火力压制!", + "{0.00->1.66}You inspire me, Helldiver. {2.24->3.59}You inspire us all.": "{0.00->2.08}绝地潜兵,你激励了我,{2.44->3.59}还有我们所有人。", + "{0.02->0.69}Terminids!": "{0.02->0.69}终结族!", + "{0.04->2.17}Super Uranium acquired.": "{0.04->2.17}超铀到手了。", + "{0.00->0.45}Here.": "{0.00->0.45}来。", + "{0.00->1.45}The Volterra system": "{0.00->1.45}沃尔泰拉星系", + "{0.00->4.95}Before I joined the service, I'd never left my home planet. Now I see a new planet almost every day.": "{0.00->2.44}入伍之前,我从来没有离开过母星。{2.89->5.45}而现在我几乎每天都会见到一颗新的星球。", + "{0.01->2.45}Protect Super Earth's investments!": "{0.01->2.61}保护超级地球的资产!", + "{0.00->1.84}Maintain your resolve!": "{0.00->1.58}坚定决心!", + "{0.03->1.95}Take a moment to remember: {3.12->4.74}Hugs are free.": "{0.00->4.80}你要记住:拥抱免费。", + "{0.02->0.97}Moving in!": "{0.00->1.05}向前推进!", + "{0.02->1.10}Tac-pack inbound.": "{0.02->1.10}战术背包来了。", + "{0.01->3.14}Price of Freedom! Keep the change!": "{0.00->1.51}自由的代价!{2.03->3.14}不用找钱了!", + "{0.03->0.89}Wohoo!": "{0.00->0.98}喔吼!", + "{0.01->1.76}Everyone take cover!": "{0.00->1.87}所有人,找掩体!", + "{0.00->0.80}Regroup!": "{0.00->1.02}重整队伍!", + "{0.00->1.84}Delivering Democracy...{2.38->3.61}it's beautiful.": "{0.00->1.84}传播民主…{2.38->3.61}真美。", + "{0.00->1.30}We haven't a moment to waste. {1.66->4.82}The Terminids are swarming, beyond anything we've yet seen. {5.21->7.78}Operation Valiant Enclosure is on the brink. {8.28->9.58}You must hold the line—{10.06->11.18}at any cost.": "{0.00->1.42}不能再浪费时间了。{1.64->5.45}终结族蜂拥而至,比以往的各种境况都要危险。{5.78->7.97}英勇围合行动一触即发。{8.28->11.34}你一定要坚守阵地,不惜一切代价。", + "{0.00->1.46}Orbit synchronized.": "{0.00->1.46}轨道已同步。", + "{7.41->10.73}Freedom's Greetings, I'm Coretta Kelly.{11.11->13.65}In a triumphant display of Democracy,{13.65->19.10}the Star of Peace has successfully been activated in the defense of Super Earth.{19.48->24.85}The Helldivers voted to defend our citizens by pre-emptively neutralizing a{24.85->29.33}highly threatening planet harboring known enemies of Freedom.{29.74->37.13}The space formerly occupied by the planet is now free from the Illuminate's totalitarian presence.{37.58->41.68}All that remains is a highly-compressed boulder-sized mass,{41.94->45.93}which is being kept under round-the-clock surveillance.{45.93->50.44}Citizens across the galaxy have been advised to celebrate the newfound{50.44->55.15}era of peace and prosperity ushered in by the Helldivers.{55.59->59.56}That's Liberty's Latest; I'm Coretta Kelly.": "{7.41->10.73}自由向各位问好,{11.11->13.65}我是科雷塔·凯利。{13.65->19.10}在民主的胜利表明,{19.48->24.85}和平之星已成功激活,{24.85->29.33}即将守卫超级地球。{29.74->37.13}绝地潜兵投票决定,{37.58->41.68}先发制人清除一颗窝藏自由之敌的高威胁星球来保卫我们的公民。{41.94->45.93}原先被该星球占据的空间现已摆脱光能者的专制掌控。{45.93->50.44}建议全银河系的公民共同庆祝绝地潜兵辛勤打拼得来的和平繁荣新时代。{50.44->55.15}以上就是今天的《解放新闻》,{55.59->59.56}我是科雷塔·凯利。", + "{0.02->1.32}This is crazy!": "{0.02->1.32}太可怕了!", + "{0.00->1.36}Thank you for saving us.": "{0.00->1.36}谢谢你们来救我们。", + "{0.00->0.75}Need fresh I.C.E.": "{0.00->0.75}换下冷却元件。", + "{0.05->5.26}The Illuminate void is spreading. If it's not stopped, it could swallow our entire Galaxy... the{5.63->8.21}only Galaxy that is truly Good, and Pure,{8.58->9.47}and Free.": "{0.05->1.74}光能者的寂域在扩张。{2.17->5.26}如果不去阻止,它可能会吞噬整个银河系……{5.63->10.07}这可是唯一真正善良、纯洁、自由的银河系。", + "{0.01->2.27}Helldiver's watching! Fire!": "{0.00->2.25}绝地潜兵看着呢!开火!", + "{0.03->0.79}Southeast.": "{0.03->0.62}东南,", + "{0.00->1.46}The Diluvia system": "{0.00->1.46}迪卢维亚星系", + "{0.00->3.66}You know Super Earth cares when you see one of these.": "{0.00->3.39}看到这个就明白超级地球重视我们。", + "{0.00->2.55}Resources for Freedom's expansion.": "{0.00->2.55}收集资源,推动自由。", + "{0.00->1.70}High-value sample collected.": "{0.00->1.70}高价值样本到手了。", + "{0.63->1.15}Sweet{1.96->2.70}Liberty...": "{1.65->3.56}解放啊…", + "{0.00->2.95}As much as I hate the Bugs, I hate dissidents even more.": "{0.00->2.95}虽然我憎恨虫族,但是我更恨异见分子。", + "{0.00->1.55}Need assistance!": "{0.00->1.52}请求救助!", + "{0.00->1.49}SEAF units on standby.": "{0.00->1.57}武装部队各单位待命。", + "{0.04->3.84}Maintain position and fire. They'll come to us.": "{0.00->2.38}稳住站位,持续开火。{2.38->3.96}它们会过来的。", + "{0.02->5.92}Sweet, sweet Helldiver! You'll be okay! You'll be...": "{0.02->5.08}天啊,是绝地潜兵!你会没事的!你不会…", + "{0.03->1.92}Flag-forsaken robots!": "{0.03->1.92}一堆破铜烂铁!", + "{0.01->0.58}Reloading.": "{0.01->0.58}换弹。", + "{0.00->2.31}This land is OUR land!": "{0.00->2.43}这片土地是属于我们的!", + "{0.00->1.84}Sending out an SOS!": "{0.00->1.84}正在部署求助信标!", + "{0.02->1.70}Augh, get it off!": "{0.02->1.70}啊,快把它弄走!", + "{0.00->1.22}Team reload required.": "{0.00->1.22}给我来点弹药。", + "{0.01->1.67}Out of sight, out of mind!": "{0.01->1.70}看不到我看不到我!", + "{0.00->1.60}Oh no, bots!": "{0.00->1.82}天呐,机器人!", + "{0.00->1.95}You have a strategic eye.": "{0.00->1.95}你很有战略眼光。", + "{0.00->1.25}Hostiles in my sights!": "{0.00->0.98}发现敌人!", + "{0.08->0.95}Enemy outpost.": "{0.08->0.95}敌方哨站。", + "{0.02->1.26}The Kirrik system": "{0.02->1.26}基里克星系", + "{0.00->1.84}Allied coordinates locked.": "{0.00->1.84}已锁定友方坐标。", + "{0.04->2.39}Lady Liberty has arrived!": "{0.00->2.43}自由女神,来了!", + "{0.02->1.32}The bots are back!": "{0.02->1.32}机器人回来了!", + "{0.01->0.73}Reloading.": "{0.00->0.54}换弹。", + "{0.03->0.96}Little help?!": "{0.00->0.97}搭把手?!", + "{0.00->1.88}Looks like we're taking the fight to them --{2.47->3.95}welcome, Helldiver.": "{0.00->1.71}看来我们要主动出击了。{2.04->3.65}欢迎,绝地潜兵。", + "{0.00->8.23}Return, refit, and redeploy to purge the stain of this failure with the peroxide of victory.": "{0.00->4.98}返航重整队伍,然后重新踏上战场,{5.32->8.23}用胜利清洗失败的污点。", + "{0.00->1.35}The Botein system": "{0.00->1.35}天阴四星系", + "{0.00->0.92}.Sub-objective.": "{0.00->0.80}次要目标,", + "{0.01->1.04}Cover down!": "{0.01->1.04}提供掩护!", + "{0.00->0.50}Changing I.C.E.": "{0.00->0.78}更换冷却片。", + "{0.00->1.63}Heh, who's next?": "{0.00->1.81}嘿,下一个是谁?", + "{0.03->1.58}Flag-forsaken thing...": "{0.00->1.64}插他旗的玩意儿……", + "{0.00->2.76}Give them no quarter. Reclaim our homes.": "{0.00->2.76}毫不留情,夺回我们的家园。", + "{0.04->0.75}Moving!": "{0.00->0.75}前进!", + "{0.00->0.86}Item collected.": "{0.00->0.86}东西到手了。", + "{0.00->1.83}SEAF backup en route to your position.": "{0.00->1.91}武装部队支援正在前往。", + "{3.42->4.49}AHHHHH HA HA {4.87->5.52}HA!!": "{0.00->4.49}啊哈哈哈!!", + "{0.04->1.27}There's too many!": "{0.00->1.41}敌人太多了!", + "{0.00->5.17}If the Helldivers can't stop them...we're all dead! AAAUUUGHHH!!!!": "{0.00->5.17}要是绝地潜兵都挡不住……我们就死定了!啊啊啊啊!!!!", + "{0.00->1.63}Greetings, Fellow Helldiver!": "{0.00->1.63}绝地潜兵战友,你好!", + "{0.09->0.77}Support weapon.": "{0.09->0.77}支援武器,", + "{0.00->1.09}Never doubt!": "{0.00->0.67}忠诚!", + "{0.03->2.33}Democracy save me!": "{0.03->2.33}求求民主显灵!", + "{1.30->2.88}Death won't win today!": "{1.22->2.93}不怕死就不会死!", + "{0.00->1.27}Hold your ground!": "{0.00->1.27}不要退缩!", + "{0.02->0.96}There's more of them!": "{0.02->0.96}那边还有!", + "{0.02->2.50}KILL EM ALLLLLLL!!!": "{0.02->2.50}一个都别想跑!!!", + "{0.02->1.18}Marking extraction point.": "{0.02->1.18}标记撤离点,", + "{0.00->1.95}Objective targets destroyed.": "{0.00->1.95}已摧毁任务目标。", + "{0.64->4.88}The fewer cities we control, the harder the planet will be to defend.": "{0.79->4.22}我们控制的城市越少,星球就越难保卫。", + "{0.00->1.06}Out of stims.": "{0.00->1.06}针用光了。", + "{0.02->1.17}We're all gonna die!": "{0.02->1.17}我们全都死定了!", + "{0.04->1.69}It's going to eat me!": "{0.04->1.69}它要把我吃了!", + "{0.00->1.63}Feel free to take a look around. {2.05->3.41}This is your ship, after all.": "{0.00->1.24}不妨四处看看,{1.77->3.41}以后这就是你的舰船了。", + "{0.00->4.00}We claim this land in the name of Democracy!": "{0.00->4.13}我们代表民主接管这片土地!", + "{0.71->1.43}The Aquila System": "{0.15->1.15}天鹰星系", + "{0.02->1.09}It's going to be ok!": "{0.02->1.09}不会有事的!", + "{0.00->5.11}Helldivers are willing to give their lives to protect our Liberty. {5.68->6.66}Helldivers: {7.06->9.32}all heroes wear capes.": "{0.00->2.15}绝地潜兵愿意为了捍卫{2.16->4.83}我们的解放事业献出生命,{5.77->9.12}他们都是身穿披风的真英雄。", + "{0.00->1.39}Look alive, soldiers!": "{0.00->1.82}战士们,动起来吧!", + "{0.00->1.53}All in good fun, eh Diver?": "{0.00->1.95}就是图个乐子,对吧潜兵?", + "{13.19->14.46}Close your eyes. {15.47->16.34}See nothing. {16.34->16.81}Be nothing.{16.81->18.50} This is life without the Right to Vote.{18.50->19.39} Now, open your eyes.{19.39->22.48} See the world as a Registered Voter -- resplendent in Democracy's light.": "{0.00->5.86}闭上双眼。一片漆黑。一无是处。{7.29->10.68}这就是没有投票权的生活。{11.82->14.62}现在,睁开眼睛。{15.49->22.41}在民主的光辉中,以注册选民的身份重新看世界。", + "{0.07->2.53}Now THERE'S a Helldiver. {2.90->5.28}You remind me of a younger me{5.47->9.63}—fearless, invulnerable, and 7 feet tall.": "{0.07->2.98}你已经是名副其实的绝地潜兵了,{3.55->5.28}让我想起了当年的自己,{6.06->9.63}那个勇猛、两米多高一往无前的英雄。", + "{0.00->0.40}West.": "{0.00->0.40}西边,", + "{0.00->4.52}This cannot stand. The Void must be destroyed.": "{0.00->2.02}我们容不得失败。{2.02->4.54}寂域必须被摧毁。", + "{0.05->1.61}Get it off of me!": "{0.05->1.61}快把它搞走!", + "{0.06->2.35}Not the Moon... that's our Moon!{2.35->6.51}I know all moons are our moons, but this Moon, that's...{6.51->7.73}one Moon too far.": "{0.06->2.75}那可是月球……我们的月球!{3.45->7.01}我知道所有卫星都是我们的,但这可是月球……{7.36->8.11}这太过分了。", + "{0.02->1.33}For Super Earth!": "{0.00->1.37}为了超级地球!", + "{0.00->0.52}Fifth one.": "{0.00->0.52}第五个。", + "{0.00->4.82}The Illuminate Exospires rise from the sites of their uncovered ruins.{5.31->9.10}We should have torn them up by the root when we had the chance.": "{0.00->4.37}光能者异界尖塔从它们发掘的遗迹地点拔地而起。{4.87->9.08}早知如此,当初就应该把它们连根除掉。", + "{0.02->0.51}1!": "{0.02->0.51}幺!", + "{0.00->5.69}When the Illuminate are expunged from this planet, these heroes will be remembered.": "{0.00->5.27}光能者被彻底清除后,这些英雄将被永远铭记。", + "{0.01->1.54}Should be safe here.": "{0.01->1.54}这里应该安全。", + "{0.02->1.80}Soldiers, at ease.": "{0.00->1.75}士兵们,稍息。", + "{0.02->1.33}Sub-objective nearby.": "{0.02->1.33}次要目标在附近。", + "{0.14->0.87}200 meters.": "{0.00->0.58}200米。", + "{0.04->1.77}The Argentis System": "{0.04->1.13}银辉星系", + "{0.00->0.95}Harmless animal.": "{0.00->1.12}无害的动物。", + "{0.02->2.27}Go get your own Democracy!": "{0.02->2.27}去找你们自己的民主!", + "{0.01->1.58}What in Liberty's name!?": "{0.01->1.74}解放啊...是真的吗?", + "{0.00->1.09}You came to right place.{1.46->2.53}Much safer here.": "{0.00->2.32}你来对地方了。这里安全多了。", + "{0.03->1.43}Joining the fray.": "{0.03->1.18}加入战斗。", + "{0.02->0.85}Mag's empty.": "{0.02->0.85}弹匣空了。", + "{0.00->1.85}Initiating FTL jump.": "{0.00->1.85}启动超光速跃迁。", + "{0.00->0.60}Got one.": "{0.00->0.60}到手了。", + "{2.78->4.86}Barely... scratched me...": "{3.01->4.86}就破了点皮…", + "{0.03->1.94}Will the shuttle have enough room for all of us?": "{0.03->1.94}运输船能装下我们所有人吗?", + "{0.00->2.89}Approaching LZ. Next recruit, prepare to dismount.": "{0.00->2.89}接近着陆区域。下一位新兵,准备下机。", + "{0.06->2.04}Deploying destructive equipment!": "{0.00->2.03}正在部署爆破装置!", + "{0.00->0.84}New orders!": "{0.00->0.84}有新命令!", + "{0.00->2.45}It's counting down! GO!": "{0.00->2.45}倒数开始了!引爆!", + "{0.00->0.75}Gotta swap I.C.E.": "{0.00->1.02}得换冷却元件。", + "{0.02->0.58}Bugs!": "{0.02->0.81}虫族!", + "{0.00->0.63}That one.": "{0.00->0.63}那个。", + "{0.00->1.95}You deserve a statue.": "{0.00->2.27}应该给你立一座雕像。", + "{0.04->1.41}I'll do my best!": "{0.00->1.44}我一定尽全力!", + "{0.50->1.90}They gave their lives for us.": "{0.12->2.30}为了保护我们,他们献出了生命。", + "{0.02->2.04}Crystallized E-710 acquired.": "{0.02->2.04}710元素晶体到手了。", + "{0.00->1.37}The Trandor system": "{0.00->1.37}特兰道尔星系", + "{0.02->0.82}Reloading you.": "{0.02->0.82}帮你换弹。", + "{0.00->0.93}Reinforcing.": "{0.00->0.93}请求增援。", + "{0.00->6.25}The fires will consume their bodies, but their memory is incombustible.": "{0.00->3.00}烈火会吞噬他们的肉身,{3.00->6.25}但他们的精神永远不灭。", + "{0.00->2.32}Yeah! You squash that bug!": "{0.00->2.51}厉害!打死了个大虫子!", + "{0.00->0.93}To the skies.": "{0.00->0.93}准备起飞。", + "{0.00->1.37}The Estanu system": "{0.00->1.37}伊斯塔努星系", + "{0.02->1.57}The Julheim system": "{0.02->1.57}尤尔海姆星系", + "{0.03->1.47}I'm... hurt...!": "{0.00->1.54}我受伤了!", + "{0.01->2.95}Tear them to shreds! Rip 'em apart!": "{0.01->3.14}把它们撕成碎片!把它们撕烂!", + "{0.03->1.50}When's the shuttle coming?": "{0.03->1.50}运输船什么时候到?", + "{0.00->1.61}Deploying SOS beacon.": "{0.00->1.61}部署SOS信标。", + "{0.00->2.12}Biological sample secured.": "{0.00->2.12}生物样本到手了。", + "{0.03->2.21}This is where the shuttle lands?": "{0.03->2.21}就在这里等运输船吗?", + "{0.04->4.12}This city will soon be a shining beacon of Freedom once more.": "{0.04->4.12}这座城市即将再次成为璀璨的自由灯塔。", + "{0.00->3.45}Show the squids what happens to those who threaten Freedom.": "{0.00->3.45}让这些鱿鱼看看威胁自由的下场。", + "{0.21->2.29}Tyranny will never prosper!": "{0.00->2.12}暴政是没有好下场的!", + "{0.00->2.17}Barely... scratched me...": "{0.00->2.40}就破了点皮…", + "{0.00->1.14}Freedom wins again.": "{0.00->1.53}自由再次得胜。", + "{0.07->1.26}We're saved.": "{0.28->1.09}我们得救了。", + "{0.01->0.81}Watch yourself!": "{0.01->0.81}小心一点!", + "{0.03->1.53}The Defensible System": "{0.03->1.08}卫戍星系", + "{0.02->2.41}Let Freedom fly!": "{0.00->2.42}让自由翱翔!", + "{0.00->0.59}Wow,{1.35->3.61}now I can take on anything.": "{0.00->3.61}哇,我现在无所畏惧了。", + "{0.00->1.36}Artifact collected.": "{0.00->1.36}古物到手了。", + "{0.00->1.53}Liberty guides my hand.": "{0.00->1.53}解放指引我。", + "{0.00->2.87}We'll show those traitors what vengeance looks like.": "{0.00->3.05}让叛徒见识一下什么叫复仇。", + "{0.03->1.27}Medic! Now!": "{0.00->1.33}针呢!赶紧的!", + "{0.00->1.46}Prepare for demolition.": "{0.00->1.64}做好爆破准备。", + "{0.04->1.99}I won't forget this!": "{0.00->2.03}我绝不会忘记!", + "{0.01->2.50}Whoa! Uh, greetings, Helldiver.": "{0.01->2.50}哇啊!绝地潜兵,你好。", + "{0.00->0.80}My body {1.28->2.45}for Super Earth.": "{0.00->2.51}为了超级地球。", + "{0.00->1.05}Battery's drained!": "{0.00->1.05}没电了!", + "{0.00->0.20}It's the Illuminate!": "{0.00->0.20}光能者来了!", + "{0.00->1.81}Liberty will always prevail!": "{0.00->1.59}解放永不消亡!", + "{0.03->3.35}Take position. Together, nothing can beat us!": "{0.00->3.36}各就各位。团结一致,我们必胜!", + "{0.01->1.40}Maintain the pressure!": "{0.01->1.12}保持压力!", + "{0.00->0.58}Cancel that.": "{0.00->0.58}不必了。", + "{0.04->1.21}Protect us!": "{0.04->1.21}保护我们!", + "{0.02->2.01}Push ahead. City needs our help.": "{0.02->2.55}向前推进。城市需要我们的帮助。", + "{0.00->1.34}The Iro system": "{0.00->1.34}伊罗星系", + "{0.01->1.29}Weapons on red!": "{0.00->1.34}武器解除保险!", + "{0.00->1.24}Let's take the fight to them!": "{0.00->1.23}向他们进攻!", + "{0.00->0.50}Negative.": "{0.00->0.50}没办法。", + "{0.00->0.41}Tie.": "{0.00->0.41}平手。", + "{0.02->2.25}Somehow, I knew you were going to win.": "{0.00->2.11}我早有预感你会赢的。", + "{0.00->0.84}Sweet Liberty, {1.25->2.29}we're saved!": "{0.00->1.92}解放大业来救我了!", + "{0.00->0.68}Follow me!": "{0.00->0.68}跟我走!", + "{0.01->0.87}Hold Position!": "{0.01->0.87}原地待命!", + "{0.00->1.12}New canister.": "{0.00->1.12}新燃料罐。", + "{0.00->1.14}The Shelt system": "{0.00->1.14}谢尔特星系", + "{0.01->3.06}Anything for Super Earth.": "{0.00->2.52}一切为了超级地球。", + "{0.03->1.05}Kill them all!": "{0.03->1.05}把他们杀光!", + "{0.00->1.41}Never doubt!": "{0.00->1.41}忠诚!", + "{0.00->8.65}Remember: our nation's founders would be proud of you. You are someone they would LOVE to grab a{8.73->9.48}beer with.": "{0.00->4.85}切记:国家的缔造者会以你为荣。{6.02->9.48}他们都非常乐意与你举杯共饮。", + "{0.00->0.61}Third one.": "{0.00->0.61}第三个。", + "{0.00->2.95}Victory for Super Earth is victory for all!": "{0.00->3.37}超级地球的胜利,就是所有人的胜利!", + "{0.02->1.61}The Civility System": "{0.02->1.11}礼序星系", + "{0.00->0.32}You know Super{1.22->2.47}Earth cares when you see one of these.": "{0.00->3.43}看到这个就明白超级地球重视我们。", + "{1.13->8.09}Not now! Not yet! So many Votes left to cast!": "{1.13->7.01}我不能死!还不是时候!还有好多票没投!", + "{0.05->6.70}One shudders to envisage what repulsive larvae gestates within the Gloom, as we speak.": "{0.00->2.30}就在我们交谈的此时此刻,{2.50->5.52}一想到“阴霾”之中孕育的各种恶心幼体,{5.57->6.96}我就不寒而栗。", + "{0.05->3.88}Cyberstan...we are here at last.": "{0.05->3.88}生化斯坦……我们终于到了。", + "{0.00->1.16}Tech sample acquired.": "{0.00->1.16}科技样本到手了。", + "{0.00->1.18}Reloading support weapon.": "{0.00->1.23}在给支援武器换弹。", + "{0.03->1.14}Don't jam on me!": "{0.00->1.06}别掉链子!", + "{0.01->1.03}Canister's empty.": "{0.01->1.03}燃料罐空了。", + "{0.04->1.79}Get d—get down!": "{0.00->1.83}卧倒,快卧倒!", + "{0.00->0.75}New mag.": "{0.00->0.75}新弹匣。", + "{0.00->0.41}Echo": "{0.00->0.53}E", + "{0.02->1.49}The squids are back!": "{0.02->1.49}鱿鱼回来了!", + "{0.01->1.51}How could the enemy make it here?": "{0.01->1.51}敌人怎么打到这儿的?", + "{0.01->1.32}They got what they deserved.": "{0.01->1.32}真是罪有应得!", + "{0.00->1.01}Last reload!": "{0.00->1.01}最后的弹药!", + "{0.03->1.32}Rally 'round the flag!": "{0.00->1.38}团结在旗帜下!", + "{0.02->1.73}Calling down objective equipment.": "{0.02->1.73}呼叫目标需要的装备。", + "{0.00->1.32}Bug outpost spotted.": "{0.00->1.32}发现虫族哨站。", + "{0.00->4.64}Keep up the good work, Helldiver. Once we win, the planets we're fighting over will finally be {4.64->5.71}allowed to prosper. {6.09->7.79}Like the rest of the Federation.": "{0.00->1.97}绝地潜兵,再接再厉。{2.26->6.36}只要获胜,我们争夺的星球就能和联邦中其他星球一样,{6.49->7.76}繁荣发展。", + "{0.02->0.84}RUN!": "{0.02->0.84}快跑!", + "{0.00->0.95}Tactical benefit.": "{0.00->0.95}战术助力,", + "{0.00->5.03}The Illuminate ruins are cultural heritage sites, containing ancient knowledge.{5.40->8.09}Knowledge of cephalopodean tyrants!{8.53->10.83}They must be destroyed!": "{0.19->5.19}光能者遗迹是文化遗产保护区,收藏着古老的知识。{5.57->7.87}关于头足类暴君的知识!{8.54->10.31}必须彻底摧毁!", + "{0.00->1.32}The Blistica system": "{0.00->1.32}布里斯提卡星系", + "{0.01->1.20}Think I saw something!": "{0.01->1.20}我似乎看到了什么!", + "{0.13->2.26}Speed is the essence of war. {2.72->3.55}Well done.": "{0.00->1.25}兵贵神速。{2.13->2.98}干得漂亮。", + "{0.12->5.76}The Cyborgs have constructed a network of Megafactories across Cyberstan. {6.12->9.45}They are obscenities of steel and concrete,{9.45->14.61}precision-built for the mass production of unsanctioned murder.{15.06->20.87}We will use every weapon in our vast arsenal to ensure they are destroyed.": "{0.12->5.72}生化人在生化斯坦各地建造了超大型工厂网络。{6.49->9.79}这些钢筋混凝土构成的邪恶建筑,{10.28->14.07}专为大规模非法杀戮而精心建造。{15.09->18.50}我们会动用庞大军械库中的各类武器,{18.88->20.93}将它们彻底摧毁。", + "{0.00->2.95}Circumstances aside, sure is nice to meet ya!": "{0.00->3.30}虽然目前情况不太好,还是很高兴见到你!", + "{0.01->2.26}IT CAN'T BE!!": "{0.01->2.26}这不可能!!", + "{0.02->1.90}Calling in extraction!": "{0.02->1.90}呼叫撤离!", + "{0.00->1.46}Sending down Fortification.": "{0.00->1.46}运送防御工事。", + "{0.00->0.85}Frag out!": "{0.00->0.85}投掷手雷!", + "{0.00->0.84}I'm hit!": "{0.00->0.84}我中弹了!", + "{0.00->1.35}SEAF support, ready to go.": "{0.00->1.35}武装部队支援就绪。", + "{0.04->1.57}Its about to get kinetic!": "{0.00->1.62}马上要动真格了!", + "{0.00->0.35}Three.": "{0.00->0.40}三。", + "{0.00->1.26}Liberty burns hot.": "{0.00->1.26}滚烫的解放。", + "{0.00->2.68}Let's see this through, for Super Earth.": "{0.00->2.68}为了超级地球坚持到最后。", + "{0.00->1.83}Run! RUN!": "{0.00->1.83}快跑!快跑!", + "{0.05->1.34}Super duper!": "{0.00->1.39}这真是倍儿棒!", + "{0.01->1.53}Democracy save me!": "{0.01->1.53}求求民主显灵!", + "{0.00->3.36}We will cleanse this Galaxy. One planet at a time.": "{0.00->3.36}我们终将肃清整个银河系,一次一个星球。", + "{0.03->1.22}Get it away from me!": "{0.03->1.22}快帮我把它弄走!", + "{0.02->1.03}This is crazy!": "{0.06->1.18}太可怕了!", + "{0.00->3.66}There are many planets in each sector where you can join the fight. {4.14->7.15}You command the ship; the choice is yours.": "{0.00->3.97}每个分区都有许多星球,你可以选择要加入哪个战场。{4.36->7.45}舰船由你指挥,选择权在你手中。", + "{0.00->0.83}Last reload.": "{0.00->0.83}最后一组弹药。", + "{0.00->1.44}Calling in mission shuttle.": "{0.00->1.59}呼叫任务运输船。", + "{0.00->0.86}I'm on the terminal.": "{0.00->0.86}让我来操作。", + "{0.03->2.11}Run, run for your vote!": "{0.00->2.15}快跑!留着命投票啊!", + "{0.26->1.62}We must be close.": "{0.30->1.87}应该不远了。", + "{0.00->2.14}They gave their lives for Freedom, {2.63->4.65}and they gave them gladly.": "{0.00->1.73}他们为了实现自由,{1.92->4.65}欣然奉献出自己的生命。", + "{0.00->1.55}Liberty dispensed!": "{0.00->1.55}传播解放!", + "{0.00->1.19}We can do this.": "{0.00->1.29}我们能行的。", + "{0.00->1.32}Team reload required.": "{0.00->1.32}给我来点弹药。", + "{0.00->0.40}Right.": "{0.00->0.40}右边。", + "{0.01->4.53}You'd think one hundred years of rehabilitative labor would have changed their tune.{5.10->7.43}But I guess some people are just too depraved... {8.64->11.70}welp, that's why they're not people anymore.": "{0.14->2.77}按理说,一百年的劳动改造{2.92->4.59}应该能让它们改变想法。{5.16->7.55}但有些人就是太堕落了吧……{8.61->11.18}所以它们才不再是人类。", + "{0.00->4.15}Their sacrifice will usher in a galaxy free of mind control.": "{0.00->4.15}他们的牺牲可以让银河系摆脱精神控制。", + "{0.00->2.02}Here's the problem with the bots, Helldiver: {2.39->4.57}Their whole society revolves around violence. {5.01->6.43}If they actually won the war, {6.82->8.31}they'd have no idea how to function.": "{0.00->1.57}机器人问题的症结在于:{2.11->4.57}它们整个社会都是围绕着暴力运转的。{5.01->8.79}它们就算真的打赢战争,也不懂得如何让社会正常运行。", + "{0.01->0.89}NOOOOOOOO!!!!": "{0.00->0.96}不!!!!", + "{0.00->1.20}I commend you.": "{0.00->1.20}你真厉害。", + "{0.02->2.25}Save yourselves, get outta here!": "{0.00->2.24}别浪费力气了,离开这儿!", + "{0.01->1.37}WOOOOOOO!!!!": "{0.01->1.37}哦!!!!", + "{0.02->2.39}Sweet Liberty, my arm!": "{0.02->2.39}我超级自由的胳膊!", + "{0.16->0.90}300 meters.": "{0.00->0.56}300米。", + "{0.03->1.70}Together, fire!": "{0.00->1.71}预备、开火!", + "{0.00->2.47}Allied Destroyer has left the squadron.": "{0.00->2.47}友方驱逐舰已离开中队。", + "{0.00->0.55}This way!": "{0.00->0.55}这边!", + "{0.04->1.15}More squids!": "{0.04->1.15}还有鱿鱼!", + "{0.00->3.10}Recruit expired. Reset course and insert next recruit.": "{0.00->3.10}新兵死亡。重置训练场,请下一位。", + "{0.03->1.30}Let's do it!": "{0.00->1.28}干就完了!", + "{0.21->3.18}And now, another helpful tip from General Brasch.{8.01->8.81}Hear that? {9.79->11.80}That's the sound of heavy armor {12.23->15.53}stopping the spread of Democracy in its tracks. {18.88->19.37}See, {19.92->24.86}enemies that are more heavily armored require you to be more heavily armed. {26.20->26.66}Mmm, {27.14->28.07}that's the stuff. {33.54->37.53}With the right stratagem, there's no defense Democracy {37.95->39.12}cannot penetrate. {43.69->47.51}BRASCH TACTICS! Use 'em, or die tryin'.": "{0.21->3.18}布拉施将军又带来了一条实用提示。{8.01->9.40}你听见了吗?{9.99->13.88}那是重型护甲阻碍民主传播的声音。{19.05->24.81}你看,既然敌人在用重型护甲,那你就要用重型武器。{26.26->27.77}嗯,没错。{33.63->39.22}只要用合适的战略配备,那就没有民主打不穿的护甲。{43.73->45.17}布拉施亲传战术!{45.51->48.00}竭尽全力,不死不休。", + "{0.00->0.87}Item collected.": "{0.00->0.87}东西到手了。", + "{0.00->1.93}Flag-forsaken Fascist.": "{0.00->2.18}无法无天的法西斯。", + "{0.00->7.22}Piece of advice: movin' around makes it hard to aim. For A-list accuracy, stay still while you {7.22->7.66}shoot!": "{0.00->5.08}给你个建议:在移动时更难瞄准。要想达到高命中率,{5.32->7.66}就得在射击时静止不动。", + "{0.00->0.57}Nevermind.": "{0.00->0.57}算了。", + "{0.00->2.05}SEAF forces standing by for support.": "{0.00->2.12}武装部队随时可以支援。", + "{1.36->5.15}Barely... scratched me...": "{0.00->3.56}就破了点皮…", + "{0.00->0.93}We can do this.": "{0.00->0.93}我们能行的。", + "{0.02->0.54}Negative!": "{0.02->0.54}没办法。", + "{0.00->0.84}I need supplies.": "{0.00->0.84}给我来点补给。", + "{0.00->5.87}There once was a ship in outer space,\nthe name of the ship was Liberty's Grace,\nthe Bug cloud came, {5.87->12.69}her bow dipped down,\nmarooned with cargo in tow.\n\nSoon may the Helldiver come,\nTo squish the Bugs {12.69->17.95}and murder the scum,\nOne day when the killin' is done,\nwe'll raise our flag and go.": "{0.00->4.52}曾经有艘太空船,它的名字叫做“解放恩典”,{4.52->9.08}虫潮袭来船头倾斜,拖着货物困在前。{9.08->13.86}盼望潜兵快赶来,来把虫族和坏人全都打败,{13.86->18.10}等到杀光这些祸害,扬起旗帜再出海。", + "{0.00->1.41}The Sulfura system": "{0.00->1.41}萨尔弗拉星系", + "{0.00->0.95}Primary objective.": "{0.00->0.95}主要目标,", + "{0.01->1.40}Need to reload!": "{0.01->1.40}需要换弹!", + "{0.00->0.75}Heads down!": "{0.00->0.75}低头!", + "{0.00->0.68}Heading there now.": "{0.00->0.68}正在路上。", + "{0.03->1.29}Stay in your lane!": "{0.00->1.43}守好自己的防区!", + "{0.00->1.32}Rare sample collected.": "{0.00->1.32}稀有样本到手了。", + "{0.04->3.86}Take position. Together, nothing can beat us!": "{0.00->1.35}各就各位。{1.35->3.92}团结一致,我们必胜!", + "{0.02->1.92}Get away from me, bot freak!": "{0.02->1.92}大铁块儿,滚远点儿!", + "{0.01->1.60}Liberty save me!": "{0.01->1.60}解放续命!", + "{0.00->0.35}Two.": "{0.00->0.35}两。", + "{0.04->2.94}Strategic pivot! PIVOT! Falling back!": "{0.00->2.94}战略转移!转移!先撤退!", + "{0.29->2.37}The greatest Helldiver I ever saw.": "{0.08->2.37}这是最伟大的绝地潜兵。", + "{0.05->6.33}\"Swarm intelligence,\" hah! They stood no chance against your tactical excellence.": "{0.05->2.80}“群体智慧”,可笑!{2.80->6.33}在精湛的战术面前,它们毫无胜算。", + "{0.00->1.51}An unmitigated success—{2.13->5.69}aside from the below-average sample collection, of course.": "{0.00->1.51}你取得了无可置疑的胜利。{2.13->5.00}不过,样本收集量不到平均水平。", + "{0.00->0.43}Wow,{1.15->2.14}you're so strong...": "{0.00->2.41}哇,你真壮……", + "{0.00->1.29}Dropping high-value item.": "{0.00->1.29}放下高价值物品。", + "{0.05->0.93}What are they?": "{0.05->0.93}是什么东西?", + "{0.00->1.68}I always knew you'd come.": "{0.00->1.68}我一直坚信你们会来。", + "{0.01->0.88}Fan out.": "{0.00->0.94}扇形散开。", + "{0.00->2.30}Initiating FTL jump to...": "{0.00->2.30}启动超光速跃迁,前往…", + "{0.02->0.70}Take this!": "{0.00->0.77}快用这个!", + "{0.43->1.52}Majestic.": "{0.00->1.89}噢简直太棒了。", + "{0.00->0.78}Enemy spotted.": "{0.00->0.78}发现敌人,", + "{0.03->3.57}The ground is yours. Treat it as you'd treat your own.": "{0.00->1.78}务必守住这里。{1.78->3.73}就像守护自己的家。", + "{0.00->1.95}Calling down fortifications.": "{0.00->1.95}请求部署防御工事。", + "{0.00->0.88}Black saffron. {1.41->3.47}Life saving and non-habit forming.": "{0.00->0.88}番黑花,{1.41->3.47}只救命,不成瘾。", + "{0.00->1.41}The Termadon system": "{0.00->1.41}特尔玛登星系", + "{0.00->3.91}Take back our land. Dismantle its occupiers.": "{0.00->3.91}光复旧土,把侵略者大卸八块。", + "{0.01->1.23}Don't let 'em get away!": "{0.00->1.27}别让它们跑了!", + "{0.00->5.21}I remember when I was a kid, they sold stickers in the Freedom Catalogue that were these little squished Bugs.": "{0.00->3.11}我记得在小时候,《自由商品目录》里面会卖一种{3.34->5.32}用压扁的小型虫族制成的贴纸。", + "{0.00->2.30}O'er every last star...": "{0.00->2.86}吹遍宇宙繁星……", + "{0.16->1.47}We shall prevail!": "{0.16->1.47}我们必将胜利!", + "{0.00->1.34}Mission: complete. {1.78->2.77}Sample collection: {3.13->4.15}below average.": "{0.00->1.47}任务完成。{2.30->4.18}样本少于平均水平。", + "{0.01->2.98}Helldiver! Nooooooooooo!": "{0.01->2.98}绝地潜兵!不要!", + "{1.55->2.30}Remember: {2.82->4.57}Super Earth is your home. {6.07->6.69}But only {7.15->8.16}if you defend it.": "{1.55->5.07}记住:超级地球是你的家园,{6.07->8.88}但是只会庇护为家园奋战的人。", + "{0.04->3.32}I'm hit! Sweet liberty…the blood.": "{0.04->3.32}我被击中了!解放你大业的…", + "{0.28->2.91}Sweet Liberty - a Helldiver!": "{0.00->2.91}解放大业啊,是绝地潜兵!", + "{0.00->7.30}Joyous news, Helldiver. Our citizens have completed construction of a new Megacity on Super Earth.": "{0.00->2.46}绝地潜兵,佳音再次传来。{2.94->7.32}我们的公民已在超级地球建成了一座新的特大城市。", + "{0.00->1.38}With the DSS around,{1.77->3.76}this planet will be free in no time.": "{0.00->1.38}只要民主空间站在,{1.77->3.61}这颗星球很快就会解放。", + "{0.00->1.03}Serves you right.": "{0.00->1.03}真活该!", + "{0.04->1.74}Automaton Outpost scrapped.": "{0.04->1.74}已扫除机器人哨站。", + "{0.01->2.43}Many hands make Liberty work.": "{0.01->2.43}团结才能自由。", + "{0.00->0.70}Fourth one.": "{0.00->0.70}第四个。", + "{0.00->1.20}Hellpods primed.": "{0.00->1.20}喷射舱已就绪。", + "{0.00->0.44}3!": "{0.00->0.44}三!", + "{0.00->0.83}Get some! {1.54->2.84}GET SOOOOME!": "{0.00->1.31}给我死!{1.36->2.84}给老子死!", + "{0.00->1.80}Tactical asset near your position.": "{0.00->1.80}战术资产就在你们附近。", + "{0.00->1.91}Bug Outpost destroyed": "{0.00->1.91}已摧毁虫族哨站。", + "{0.01->2.68}Attack Democracy, you pay the price!": "{0.00->3.01}敢攻击民主,就要付出代价!", + "{0.00->1.38}You guys do this all the time.{1.89->2.17}Right?": "{0.23->1.46}你们都是老手了,{1.97->2.34}对吧?", + "{0.00->0.95}Please stim me,{1.71->2.05}please!": "{0.00->2.15}求求你给我一针,求求你了!", + "{0.00->0.93}I'm on the terminal.": "{0.00->0.93}让我来操作。", + "{0.00->0.94}Last reload!": "{0.00->0.94}最后的弹药!", + "{0.02->0.91}For Freedom!": "{0.02->0.91}为了自由!", + "{0.04->1.09}For Liberty!": "{0.00->1.10}为了解放!", + "{0.00->0.95}Last one down.": "{0.00->0.95}都搞定了。", + "{0.00->1.49}Here comes the cavalry!": "{0.00->1.49}救兵来了!", + "{0.04->3.34}Stay alert, lest these Archives become your tomb.": "{0.04->3.34}保持警惕,别挑这里做墓地。", + "{0.32->1.91}That's what Helldivers do!": "{0.19->1.58}这才叫绝地潜兵!", + "{0.00->6.76}There may come a day when you must throw aside your safety and take up the mantle of Liberty. {7.20->9.20}That day is today. {9.57->12.47}And that mantle is the Helldiver cape. {12.95->14.63}Wear it with pride.": "{0.00->1.00}或许有一天,{1.21->5.41}你必须将自身安危抛在脑后,肩负解放的重任。{6.25->7.73}这一天已经到来。{8.35->11.57}绝地潜兵的披风就象征着这份重任,{12.15->14.63}骄傲地披上这件披风吧。", + "{0.02->1.71}Sweet Liberty, it's the bots!": "{0.02->2.09}解放你大业的,是机器人!", + "{0.14->1.75}Squid outpost spotted.": "{0.14->1.75}发现鱿鱼哨站。", + "{0.01->1.76}GRENADE! Stay back!": "{0.01->1.76}手雷!别过来!", + "{0.01->1.42}Manning emplacement.": "{0.01->1.42}操纵炮位。", + "{0.03->1.59}Kill them! Kill them all!": "{0.03->1.59}杀了它们!都杀光!", + "{0.00->1.18}The Mog system": "{0.00->1.18}莫格星系", + "{0.00->0.71}Affirmative.": "{0.00->0.71}行。", + "{0.03->5.00}Mines! Mines! Watch your step. No, YOUR step!": "{0.00->1.89}有雷!有雷!{1.89->3.59}当心脚下。{3.59->5.06}不,你脚下!", + "{0.00->4.79}The more we fight, the more it becomes clear that our enemies will never accept our way of life. {5.40->6.85}It's us or them.": "{0.00->2.34}经历的战斗越多,我们就越相信,{2.62->5.21}敌人永远也不可能接受我们的生存之道。{5.40->7.34}我们与它们势不两立。", + "{0.00->0.58}Five.": "{0.00->0.58}五。", + "{0.00->1.08}Not like this!{1.33->2.10}Don't give up!": "{0.00->0.75}别啊!{1.14->2.10}不要放弃!", + "{0.00->0.81}Squids!": "{0.00->0.81}鱿鱼!", + "{0.03->1.54}Helldivers taking point!": "{0.00->1.51}绝地潜兵在打头阵!", + "{0.04->1.08}Manning Emplacement!": "{0.00->1.08}操纵炮位!", + "{0.00->0.32}Yes": "{0.00->0.32}好的。", + "{0.00->0.26}I, uh... I{1.87->2.76}don't know what to say.": "{0.00->2.98}我,呃……我不知道该说什么好。", + "{0.00->2.00}Eagle 1 ready and rarin' to go.": "{0.00->2.00}“飞鹰”1号随时待命。", + "{0.00->1.74}Rare sample acquired.": "{0.00->1.74}稀有样本到手了。", + "{0.00->0.73}Illuminate.": "{0.00->0.73}光能者。", + "{0.00->3.10}Another victory for the right side of history.": "{0.00->3.10}胜利再次站在了历史正确的一边。", + "{0.00->0.35}Yes": "{0.00->0.35}好的。", + "{0.00->1.47}The Valgaard system": "{0.00->1.47}瓦尔加德星系", + "{0.00->0.85}We've got a heavy.": "{0.00->0.85}有重型敌人。", + "{0.00->1.85}Keep killin' those squids, Helldiver.": "{0.00->2.17}再接再厉,继续消灭鱿鱼。", + "{0.00->1.27}Need. Stim.": "{0.00->1.62}给我,来一针。", + "{0.00->3.35}Attack Democracy, and that's what happens!": "{0.00->3.06}这就是攻击民主的下场!", + "{0.00->0.50}Help!": "{0.00->0.50}救命!", + "{0.00->4.63}You know, the problem with the bugs is that they're relentless expansionists. In their region of {4.63->7.50}space, we've found them on nearly every planet we've settled.": "{0.00->3.17}虫族的问题在于,它们在毫无节制地扩张。{3.36->4.72}在虫族控制的区域,{4.92->7.95}我们几乎是每到一颗星球都能发现它们的踪迹。", + "{0.00->0.90}Pack's out.": "{0.00->0.90}背包空了。", + "{0.06->1.25}Steady yourselves!": "{0.06->0.99}稳住别动!", + "{0.00->4.56}The underhanded tactics of the Illuminate claim yet more noble heroes.": "{0.00->4.56}光能者再次用卑鄙手段夺走了英雄的崇高生命。", + "{0.00->2.85}Super Earth doesn't know the meaning of half measures!": "{0.00->3.11}超级地球的字典里没有半途而废!", + "{0.01->1.73}Another Vote stolen!": "{0.01->1.73}又被抢走一张票!", + "{0.04->4.60}This combat walker truly showcases Super Earth's superior engineering.": "{0.04->4.60}这个战斗步行机甲,展现了超级地球的先进技术。", + "{0.03->0.97}Automatons!": "{0.03->0.97}机器人!", + "{0.03->0.80}The enemy!": "{0.03->0.80}有敌人!", + "{0.00->1.01}Mission accomplished—{1.45->2.67}and quickly, too.": "{0.00->1.01}任务完成,{1.45->2.67}而且很快。", + "{0.00->3.00}FREEDOM REIGNS SUPREME!": "{0.00->2.69}谁也别想挡住自由!", + "{0.00->0.80}Wow,{1.22->2.48}you're so strong...": "{0.00->1.12}哇,{1.34->2.57}你真壮……", + "{0.00->1.37}Calling in extraction.": "{0.00->1.37}呼叫撤离。呼叫撤离。", + "{0.00->0.82}Move out!": "{0.00->0.82}出发!", + "{0.00->0.42}Bugs.": "{0.00->0.42}虫族,", + "{0.10->3.83}Uh, please don't deploy orbital strikes outside of combat areas.": "{0.10->3.83}呃,请不要在战斗区域外使用轨道攻击。", + "{0.00->3.51}Helldivers outside extraction radius — Pelican 1 aborting pickup.": "{0.00->3.51}绝地潜兵在撤离区外——“鹈鹕”1号放弃接人。", + "{0.01->0.63}Get down!": "{0.01->0.63}卧倒!", + "{0.00->0.56}Illuminate.": "{0.00->0.56}光能者,", + "{0.00->1.40}The Calypso system": "{0.00->1.40}卡利普索星系", + "{0.01->1.13}Hey, wait for me!": "{0.01->1.13}嘿,等等我!", + "{0.07->1.45}Steel yourselves!": "{0.07->1.45}做好准备!", + "{0.00->0.65}New target!": "{0.00->0.93}发现新目标!", + "{0.01->1.09}Changing I.C.E.": "{0.01->1.09}更换冷却片。", + "{0.00->1.01}I got you!": "{0.00->1.05}我来救你!", + "{0.00->0.64}Southeast.": "{0.00->0.40}东南,", + "{0.01->2.75}I'll never see Super Earth...": "{0.01->2.75}再也见不到超级地球了…", + "{0.00->1.12}Gotta reload!": "{0.00->1.12}得装弹了!", + "{0.05->1.82}Terminids! Run!": "{0.05->1.82}终结族!快跑!", + "{0.03->0.86}They're back!": "{0.03->0.86}它们回来了!", + "{0.00->0.66}Southwest.": "{0.00->0.66}西南,", + "{0.02->1.40}Kill it! Destroy it!": "{0.02->1.40}快杀了它!杀了它!", + "{0.04->0.80}They missed!": "{0.04->0.80}它们打偏了!", + "{0.00->2.33}Hot dogs! That was awesome!": "{0.00->2.56}哇热狗!实在太精彩了!", + "{0.59->1.12}Wohoo!": "{0.00->1.18}喔吼!", + "{0.00->3.56}One day, I'll have your phalangeal dexterity.": "{0.00->3.63}总有一天,我手指也能像你一样灵活。", + "{0.00->2.44}Eagle 1 reporting in, fragged and good to go.": "{0.00->2.44}“飞鹰”1号报告,状态良好,准备就绪。", + "{0.00->0.47}Here.": "{0.00->0.47}来。", + "{0.00->1.08}When I get exhausted, {1.50->5.36}I just think of all the brave Super Earth colonists out there settling new planets. {6.30->7.22}They do their part, {7.94->9.53}and we do ours.": "{0.00->1.63}感到疲惫的时候,{2.02->6.47}我就会想起超级地球拓殖者勇敢开辟新星球的背影。{7.10->9.16}我们都在各司其职。", + "{0.01->2.85}Class B Citizens, get behind me!": "{0.01->2.61}B级公民,都躲到我身后!", + "{0.00->6.47}Tired from a long day of liberating? Sounds like you need an injection of Freedom Juice! The only {6.47->8.84}beverage with that extra special kick.": "{0.00->3.62}为解放事业忙碌了一天,感到疲惫不堪?{4.34->6.53}赶快喝点“自由能量”饮料!{7.06->9.27}重燃活力,仅此一款。", + "{0.08->4.57}Perhaps the Illuminate sought to convert our citizens into their loyal subjects, {4.95->10.09}but found the allegience of a Super Earth citizen not so easily co-opted. {10.69->12.18}And the brutish Voteless {12.57->13.53}were the result.": "{0.30->1.37}或许,{1.37->5.48}光能者试图将我们的公民变成他们的忠实臣民,{5.75->9.72}却发现要让超级地球的公民效忠并非易事。{10.07->13.87}而野蛮的无票者就是这样产生的。", + "{0.03->6.06}Seize the Automatons' ill-gotten gains. They will fuel the expansion of Freedom.": "{0.03->3.00}夺回被机器人非法侵占的资源。{3.00->6.06}为自由扩张提供动力。", + "{0.00->2.51}Recruit expired. Deploy dive team.": "{0.00->2.51}新兵死亡。潜水小队出动。", + "{0.47->1.33}N-never doubt...": "{0.00->1.38}忠、忠诚……", + "{0.00->1.46}Clear the impact radius!": "{0.00->1.44}离开爆炸范围!", + "{0.00->1.93}High-value sample collected.": "{0.00->1.93}高价值样本到手了。", + "{0.14->0.79}No!": "{0.14->0.79}没办法!", + "{0.02->2.62}Duty! Fealty! Obedience!": "{0.00->2.79}责任!忠诚!服从!", + "{0.03->0.88}Moving in.": "{0.00->0.93}向前推进。", + "{0.00->0.69}Dropships.": "{0.00->0.68}运输舰,", + "{0.00->1.31}Too much incoming!": "{0.00->1.41}它们火力太猛了!", + "{0.00->0.37}No!": "{0.00->0.67}没办法!", + "{0.00->0.05}I need a team reload.": "{0.00->1.13}给我来点弹药。", + "{0.00->3.62}This Hive World will surrender its claim to independence.{4.21->5.28}And its E-{5.30->6.51}710.": "{0.00->3.62}这个虫窝世界将交出主权。{4.21->6.51}和710元素。", + "{0.00->0.51}You {0.95->3.05}are a true champion of Democracy.": "{0.00->2.71}你是真正的民主斗士。", + "{0.03->1.23}The Hett System": "{0.00->1.01}炎核星系", + "{0.00->1.73}I knew you had it in you!": "{0.00->1.55}我就知道你有本事!", + "{0.00->0.57}New mag.": "{0.00->0.70}新弹匣。", + "{0.00->1.35}The Alamak system": "{0.00->1.41}天大将军一星系", + "{0.01->0.99}The bots found us!": "{0.01->0.92}机器人来了!", + "{0.00->2.29}Good work collecting so many samples.": "{0.00->2.29}你收集了很多样本,漂亮。", + "{0.01->4.32}Whoa! That was even better than the recruitment videos!": "{0.00->1.53}哇吼!{1.53->4.15}简直比征兵宣传片还精彩!", + "{0.00->1.24}Requesting tac-pack.": "{0.00->1.24}请求战术背包。", + "{0.00->0.66}Foxtrot": "{0.00->0.66}F", + "{0.00->5.40}While their service ends here, their victory will echo throughout the galaxy.": "{0.00->5.40}他们效力的脚步就此停下,但胜利的凯歌会响彻银河。", + "{0.50->2.37}Wow, that is LOUD!": "{0.00->2.00}哇,这也太吵了吧!", + "{0.01->1.12}Sending in an Eagle.": "{0.01->1.12}请求出动“飞鹰”。", + "{0.08->0.74}I'm sorry!": "{0.08->0.74}抱歉!", + "{0.00->1.11}The Kraz system": "{0.00->1.11}轸宿四星系", + "{0.00->3.40}They'll think twice before infringing on our Freedom again.": "{0.00->2.80}自由不容侵犯。", + "{0.03->0.92}Here we go!": "{0.00->0.99}走起!", + "{0.02->0.85}Regroup!": "{0.02->0.85}重整队伍!", + "{0.00->1.13}Entering shuttle.": "{0.02->1.32}进入运输船。", + "{0.01->1.06}NOOOOOOOO!!!!!!": "{0.01->1.06}不!", + "{0.01->1.91}Yeah!! Freedom for all!": "{0.00->2.00}对!!自由属于每一个人!", + "{0.00->1.95}Nothing can pierce Democracy!": "{0.00->2.28}民主坚不可摧!", + "{0.00->0.51}Ok!": "{0.00->0.51}好嘞!", + "{0.02->2.70}Burn in the fires of Democracy!": "{0.02->1.77}滚烫的民主!", + "{0.00->1.70}The Big Rock System": "{0.00->1.16}巨岩星系", + "{0.02->2.65}Let's kill these sons of dissidents!": "{0.00->2.71}让我们把这帮杂种全都杀光!", + "{0.01->0.83}Got a bead on them!": "{0.01->0.93}瞄准它们了!", + "{0.00->1.60}The Retributary System": "{0.00->1.09}天谴星系", + "{0.00->5.15}This is a very special secret, the Stranger said, \"So only very special boys get to learn it.\"": "{0.00->5.15}陌生人说:“这是非常特别的秘密,只有非常特别的男孩儿才能知道。”", + "{0.00->1.21}Moving on target.": "{0.00->1.36}向目标移动。", + "{0.02->1.39}Can't get past!": "{0.02->1.39}这边过不去!", + "{0.01->1.78}Deploying destructive equipment!": "{0.00->1.79}我们正在部署爆破装置!", + "{0.00->1.69}Requesting objective equipment!": "{0.06->1.56}请求目标所需装备!", + "{0.44->0.96}Just{1.23->1.76}catching{2.08->2.51}my{2.83->3.61}breath...": "{0.00->1.11}让我{1.17->1.76}喘{2.28->2.78}口{2.83->3.61}气…", + "{0.04->1.79}Aw, you knew I needed that.": "{0.00->1.92}你知道我正需要这个。", + "{0.00->1.23}Liberty heal me.": "{0.00->1.23}解放续命。", + "{0.00->1.39}Reloading support weapon.": "{0.00->1.39}在给支援武器换弹。", + "{0.07->5.82}Argh! Not today, anti-democratic scum...": "{0.00->1.57}啊!{1.57->3.81}反民主渣滓,{3.81->5.74}我还没完……", + "{0.00->0.95}Automatons": "{0.00->0.95}机器人", + "{0.03->0.77}Get down!": "{0.03->0.77}快趴下!", + "{0.05->1.70}Freedom save me!": "{0.05->1.70}自由保佑我 !", + "{0.01->2.54}Not safe here either!": "{1.14->2.54}这里也不安全!", + "{0.00->3.55}Another step towards the enemy's just obliteration.": "{0.00->3.55}朝着敌人命定的灭亡结局又迈进了一步。", + "{0.35->1.23}Sweet Liberty, {1.79->2.49}my leg!": "{0.04->2.48}我超级自由的腿!", + "{0.16->0.95}To the skies.": "{0.00->0.80}飞起来。", + "{0.02->0.79}Gotta reload!": "{0.02->0.79}得换弹了!", + "{0.02->1.69}Save me!": "{0.55->1.73}救我!", + "{0.02->1.92}The Wilford Station system": "{0.02->1.92}威尔福德站星系", + "{0.00->1.44}High-value sample collected.": "{0.00->1.44}高价值样本到手了。", + "{0.00->3.25}I never thought I'd get to meet an actual Helldiver.": "{0.00->3.25}没想到我能遇见真正的绝地潜兵。", + "{0.02->0.71}They're coming!": "{0.02->0.71}它们来了!", + "{0.00->2.21}New battery, same way of life.": "{0.00->2.46}换电池,不换生存正道。", + "{0.00->0.44}Down.": "{0.00->0.44}下方。", + "{0.00->0.82}Heading there now.": "{0.00->0.82}正在赶过去。", + "{0.00->5.64}Good tidings, Helldiver. A new Megacity is under construction on Super Earth.": "{0.00->2.00}绝地潜兵,有好消息。{2.52->5.80}超级地球正在建设一座新的特大城市。", + "{0.00->0.45}East.": "{0.00->0.53}东边,", + "{0.01->1.85}Maintain your sector of fire!": "{0.01->1.68}保持区域火力压制!", + "{0.00->3.22}We must focus on defending Super Earth, Helldiver.{3.82->4.76}She needs us.": "{0.00->3.21}绝地潜兵,我们必须专心保卫超级地球。{3.92->4.86}她需要我们。", + "{0.00->1.13}Requesting sentry.": "{0.03->1.13}请求哨戒炮。", + "{0.01->2.75}Can't survive these wounds much longer.": "{0.00->2.66}伤口不能再耽误了。", + "{0.00->1.27}The Meissa system": "{0.00->1.27}觜宿一星系", + "{0.08->2.06}Super Earth's finest!": "{0.00->2.17}最优质的战士!", + "{0.00->1.91}Our heroes may have perished, {2.30->5.36}but the ramifications of their victory will endure.": "{0.00->1.91}英雄们虽已身死,{2.30->5.36}但他们取得的胜利果实会遍地开花。", + "{0.00->1.20}Package acquired.": "{0.00->0.92}东西到手了。", + "{0.00->5.67}Tear down their Exospires. Save the galaxy from this unknowable threat.": "{0.00->5.88}摧毁异界尖塔。拯救银河系,对抗未知的威胁。", + "{0.03->0.54}Run!": "{0.03->0.54}快跑!", + "{0.04->0.76}Run!": "{0.04->0.76}快跑!", + "{0.00->2.76}Request approved; reinforcements have been launched.": "{0.00->2.76}批准请求;已派出增援。", + "{0.02->1.33}For prosperity!": "{0.00->1.37}为了繁荣!", + "{0.01->1.40}Stand your ground!": "{0.01->1.18}坚守阵地!", + "{0.00->2.22}This is how we win. Together.": "{0.00->2.36}这就是取胜之道。团结一致。", + "{0.02->1.32}Never let go.": "{0.02->1.32}永不放弃。", + "{0.00->3.25}Recruit expired. Request clean-up crew to battlefield simulator.": "{0.00->3.46}新兵死亡。请清洁组进入模拟战场。", + "{0.01->1.82}Need. Stim.": "{0.01->2.09}给我,来一针。", + "{0.00->1.76}They're coming soon, right?": "{0.00->1.76}他们快到了,对吗?", + "{0.08->4.77}Our way of life will always endure...": "{0.08->5.67}生存正道,永垂不朽!", + "{0.00->1.19}Democracy for all.": "{0.00->1.19}民主人人有份。", + "{0.02->1.71}Sample collected.": "{0.02->1.71}样本到手了。", + "{0.04->1.47}Get back in there!": "{0.00->1.68}可以回战场了!", + "{0.00->4.95}The struggle for Managed Democracy continues. We have no time to waste.": "{0.00->4.95}我们仍在为管理式民主争取胜利,不能浪费时间。", + "{0.00->4.76}Another step towards the righteous reclamation of Cyberstan.": "{0.00->4.68}离光复生化斯坦的伟大事业又近一步。", + "{0.03->4.36}They... they can't take us all! FIRE!": "{0.00->2.97}开火,用火力压制它们!{2.97->4.48}开火!", + "{0.03->3.18}Our resolve cannot falter. Engage!": "{0.00->3.27}我们的决心绝不动摇,开打!", + "{0.00->0.89}Gotta reload!": "{0.00->0.89}需要换弹!", + "{0.00->2.11}Honor their sacrifice.{2.36->3.42}Fight on!": "{0.00->1.44}铭记他们的牺牲。{2.00->3.18}战斗到底!", + "{0.00->0.97}Brainless bot.": "{0.00->1.38}没脑子的机器。", + "{0.00->0.74}Absolutely!": "{0.00->0.74}没有问题!", + "{0.03->2.00}This is the right place. Right?": "{0.03->2.00}是在这里等,对吧?", + "{0.00->0.38}Close.": "{0.00->0.44}很近。", + "{0.02->1.11}Covering from here!": "{0.00->1.13}我来掩护大家!", + "{0.42->1.29}This way, everybody!": "{0.00->1.29}大家都来这边!", + "{0.02->1.99}FREEDOM!": "{0.02->1.99}自由!", + "{0.00->1.03}Primary objective.": "{0.00->1.03}主要目标,", + "{0.00->2.39}The Helldivers are here to lead us to victory!": "{0.00->2.93}绝地潜兵会领导我们取得胜利!", + "{0.00->1.59}They all deserve to die.": "{0.00->1.59}它们都该死。", + "{0.00->2.66}Flag-forsaken leg's slowin' me down.": "{0.00->2.29}这条破腿耽误了解放。", + "{0.16->0.95}Spread out!": "{0.00->1.00}散开!", + "{0.00->0.43}Seven.": "{0.00->0.43}拐。", + "{0.08->0.63}For...{1.05->2.48}Super Earth..": "{0.08->0.63}为了…{1.05->2.48}超级地球…", + "{0.00->0.68}Hold Position.": "{0.00->0.68}原地待命。", + "{0.00->2.12}Half reinforcement budget remaining.": "{0.00->2.12}增援预算只剩下一半了。", + "{0.00->2.61}Did you know that most tank production facilities {2.61->5.07}were turned into theme parks after the First Galactic War?{5.77->8.17}My parents used to take me to this fairytale-themed one.{8.59->13.40}The chimney towers were painted pink, and they said Lady Liberty lived there, and the Helldivers{13.40->15.47}all protected her from the evil Dissident King.": "{0.00->2.51}你知道吗,第一次星系战争结束后,{2.75->5.22}大部分坦克生产设施都改造成了主题公园。{5.75->8.09}我父母以前常带我去那个童话主题的公园。{8.45->9.98}烟囱塔都涂成了粉色,{10.32->13.54}他们说自由女神就住在那里,还有绝地潜兵保护她,{13.73->15.19}抵御邪恶的异见国王。", + "{0.00->4.16}The adults would all dress up as Bugs, and ring our doorbells and we'd have to fire 3 shots in the {4.16->6.33}air and say \"No Fascism here, insects!\"": "{0.00->2.22}大人们会扮成虫族,来按我们的门铃。{2.38->3.82}然后,我们必须空放3枪,{3.86->6.20}说:“虫子,这里不欢迎法西斯!”", + "{0.00->2.93}Bravely they delved beyond Liberty's light.{3.50->5.26}Never to return.": "{0.00->2.93}他们勇敢深入解放之光照不到的黑暗。{3.50->5.26}一去不回。", + "{0.02->1.76}One for the scrapbook.": "{0.00->1.90}值得珍藏的一刻。", + "{0.00->1.24}For prosperity!": "{0.00->1.36}为了繁荣!", + "{0.00->2.51}Those who sacrifice for Lady Liberty,{2.96->5.37}live forever in her memory.": "{0.00->2.51}为自由女神献身的英雄,{2.96->5.37}会永远活在她的记忆中。", + "{8.27->11.29}Freedom's Greetings, I'm Coretta Kelly.{11.57->17.50}Today, the Great Expedition launched its long-awaited voyage into the Terminid Gloom.{17.92->26.17}The massive fleet of interstellar ships has an important mission: to find the source of the Gloom and destroy the interstellar spore cloud,{26.17->27.80}once and for all.{28.27->30.64}The Helldivers are leading the charge,{30.64->36.24}ready to face whatever horrific monstrosities await in the mysterious miasma.{37.00->39.06}To send off the Expedition,{39.06->46.78}the Super Earth Children's Choir sang a stirring tribute to those lost in the New Hope City Massacre.{47.14->48.26}In other news,{48.26->53.96}an influx of new Helldiver recruits have been proving themselves on the front line of battle,{54.02->60.70}already matching the high accuracy and low casualty rate of the most seasoned soldiers.{61.67->65.23}That's Liberty's Latest; I'm Coretta Kelly.": "{8.27->11.29}自由向各位问好,{11.57->17.50}我是科雷塔·凯利。今日,大远征队正式启航,踏上期盼已久的征途,{17.92->26.17}深入终结族的“阴霾”。庞大的星际舰队肩负着重要使命:找到“阴霾”的源头,彻底摧毁这片星际孢子云。{26.17->27.80}绝地潜兵冲锋陷阵,{28.27->30.64}准备迎战潜伏在神秘瘴气中的可怕怪物。{30.64->36.24}为远征队送行时,{37.00->39.06}超级地球儿童合唱团深情献唱,{39.06->46.78}缅怀新希望城大屠杀的遇难者。{47.14->48.26}另一方面,{48.26->53.96}大批绝地潜兵新兵在前线战场证明了自己的实力,{54.02->60.70}命中率之高和伤亡率之低能媲美最资深的战士。以上就是今天的《解放新闻》,{61.67->65.23}我是科雷塔·凯利。", + "{0.02->1.10}Move, move, move!": "{0.02->1.10}快,快,快!", + "{0.01->2.85}Hostiles inbound! Bring it on!": "{0.01->2.85}敌人要来了!来吧!", + "{0.14->0.98}Deploying flare.": "{0.00->1.04}部署照明弹。", + "{0.00->0.94}You saved us!": "{0.00->0.94}多亏了你们!", + "{1.47->2.16}The flag...{3.00->4.20}it's so beautiful...": "{1.01->2.62}这面旗帜……{2.62->4.39}是多么的耀眼……", + "{0.00->0.30}Two.": "{0.00->0.30}两。", + "{0.03->0.97}The tentacles!": "{0.03->0.85}是触手!", + "{0.01->1.26}Calling down a walker.": "{0.01->1.26}呼叫步行机甲。", + "{0.00->5.59}The efforts of Helldivers across the galaxy are all that keeps the enemy from Liberty's doorstep.": "{0.00->5.96}绝地潜兵在银河系各处并肩作战,是阻止敌人攻破解放的唯一屏障。", + "{0.00->1.71}No diver left behind.": "{0.00->1.71}不抛弃,不放弃。", + "{0.00->1.67}Democracy deliver us!": "{0.00->1.67}愿民主保佑我们!", + "{0.05->4.08}Course, I don't qualify for the bonus since I haven't been approved yet. But once I am, I'll have a {4.08->5.16}nice nest egg saved up.": "{0.05->2.73}当然,我没有资格领,因为我还没有得到批准。{2.87->5.41}但是只要通过批准,我就能攒下不少钱了。", + "{0.00->2.69}The Megafactories serve a critical role:{3.37->6.60}they are the production site of new Cyborgs.{7.10->11.85}Vast Cyborg Production Units synthesize and grow human tissue{12.80->14.28}at unnatural rates,{14.67->19.72}forming twisted bipeds upon which cybernetic components are grafted.{20.31->23.89}What emerges cannot be called human.": "{0.00->6.06}超大型工厂承担着关键职能:制造新生化人的基地。{6.86->13.34}巨型生化人生产单元以超自然速度合成并培养人体组织,{13.69->19.83}形成扭曲的双足生物,然后给这东西移植机械组件。{20.72->24.40}最终的产物已经不能称之为人类了。", + "{0.02->2.07}How about a nice cup of Liber-tea!": "{0.08->2.14}尝尝这盅陈茶!", + "{0.00->1.38}That's how we free the galaxy. {1.77->2.95}One mission at a time.": "{0.00->1.55}稳扎稳打,逐一攻克,{1.74->3.52}才是解放银河系的正道", + "{0.04->2.43}Sweet Liberty, fall back!": "{0.00->2.64}他民主的,快撤退!", + "{0.00->0.49}That one.": "{0.00->0.49}那一个。", + "{0.05->2.24}Tear them to shreds! Rip 'em apart!": "{0.05->2.24}把它们撕成碎片!把它们撕烂!", + "{0.03->1.61}The Yed Prior system": "{0.03->1.61}天市右垣九星系", + "{0.00->2.23}SEAF rapid-response team on standby.": "{0.00->2.38}武装部队快速响应小队正在待命。", + "{0.01->1.24}We're all gonna die!": "{0.01->1.80}我们都死定了。", + "{0.00->1.08}Manning emplacement.": "{0.00->1.08}操纵炮位。", + "{0.01->1.01}Last reload.": "{0.01->1.01}最后的弹药。", + "{0.06->6.63}Glorious work, recruit. Already you've advanced the cause of democracy farther than any soldier {6.63->7.73}I've ever seen. {8.15->12.93}You've proved your worth. You're ready to don your cape.": "{0.06->6.63}非常好,新兵。我带过那么多兵,只有你对民主事业贡献最大。{8.22->12.77}你已经证明了自己的价值,做好了穿上披风的准备。", + "{0.00->0.82}Legendarium. {1.31->3.93}Truly as legendary as the name suggests.": "{0.00->0.82}传说矿物,{1.46->3.93}果然是传说级别的东西!", + "{0.00->4.70}Our heroes gave their last, but they died having done their duty.": "{0.00->4.70}英雄们虽然献出了生命,但他们不辱使命。", + "{0.01->0.82}Whatever you need!": "{0.01->0.82}你要什么都行!", + "{0.12->4.27}The sacrifice of our heroes was well worth the gains made here, {4.71->7.23}and I know they would say the same.": "{0.12->4.27}为了夺得胜利,英雄们死得其所,{4.71->7.23}他们一定会赞同我的想法。", + "{0.00->0.43}Nine.": "{0.00->0.43}勾。", + "{0.00->1.20}Poor bastard...": "{0.00->1.20}可怜虫…", + "{0.00->2.70}Justice shall avenge our fallen!": "{0.00->2.70}冤有头债有主!", + "{0.05->1.61}We can't stay here!": "{0.00->1.58}这里不能待了!", + "{0.00->1.10}My friend!": "{0.00->1.10}战友!", + "{0.00->1.24}The Charbal system": "{0.00->1.24}查巴尔星系", + "{0.01->1.15}Calling down equipment.": "{0.01->1.15}呼叫装备。呼叫装备。", + "{0.00->1.65}You secured a lot of samples. {2.18->2.95}Well done.": "{0.00->1.45}你获取了很多样本。{1.82->2.68}干得好。", + "{0.01->1.90}I'm hit. Patching up!": "{0.34->2.27}我中弹了。正在治疗!", + "{0.18->1.81}This is the right place. Right?": "{0.18->1.81}是在这里等,对吧?", + "{0.00->1.22}Liberty take the wheel.": "{0.00->1.22}兜解放之风。", + "{0.00->0.69}Just in time. {1.16->2.23}Glad you made it out of there.": "{0.00->0.69}刚好赶上。{1.16->2.23}幸好你撤了出来。", + "{1.40->2.87}This Liberty Day, {3.07->6.30}become the patriot your family needs. {7.64->10.57}When your children sprint to the Liberty Day Pyre {11.47->14.03}to pull presents from the flames, {14.31->16.80}make sure they get the gift they deserve. {17.86->18.55}The gift {19.00->20.04}of Helldivers. {21.17->24.50}Because Super Earth isn't just about the heroes on the front.{25.24->28.20}It's about the heroes right here at home.": "{1.40->2.87}在今年的解放日,{3.07->6.30}成为家人敬仰的爱国者吧。{7.64->10.57}当你的孩子冲向解放日柴堆,{11.47->14.03}从火中取出礼物的时候,{14.31->16.80}一定要让他们得到应得的礼物。{17.86->20.59}属于绝地潜兵的礼物。{21.17->24.50}因为超级地球不只需要前线的英雄,{25.24->28.20}还需要家庭的英雄。", + "{0.00->1.08}Objective located.": "{0.00->1.00}发现目标,", + "{0.00->0.68}Affirmative!": "{0.00->0.77}好的,收到!", + "{0.00->0.35}Mag.": "{0.00->0.54}换弹匣。", + "{0.00->1.57}Where will you strike, Helldiver?": "{0.00->1.57}潜兵,你要攻打何处?", + "{0.24->2.90}I never thought I'd get to meet an actual Helldiver.": "{0.00->2.44}没想到我能遇见真正的绝地潜兵。", + "{1.66->3.11}Flag save us all...": "{1.45->3.12}旗帜保佑……", + "{0.00->1.16}Artifact collected.": "{0.00->1.16}古物到手了。", + "{0.01->1.50}Team reload required.": "{0.01->1.31}给我来点弹药。", + "{0.00->3.09}Only Democracy tells US what to do!": "{0.00->3.09}我们只听从民主的号召!", + "{0.00->1.56}The Phact Bay system": "{0.00->1.56}丈人一湾星系", + "{0.00->2.50}New canister for maximum Liberation.": "{0.00->2.72}新燃料罐,全力实现解放。", + "{0.00->0.63}Liberty!": "{0.00->0.63}解放!", + "{0.04->1.37}MOVE! OUT OF THE WAY!": "{0.00->1.45}快!离开这儿!", + "{0.01->2.39}It's armed?! Go go go go!!": "{0.01->2.39}已经激活了?!赶紧跑!", + "{1.26->2.83}That's what I call guns!": "{1.39->3.39}这才叫真家伙呢!", + "{0.00->0.74}Welcome back. {1.23->3.91}Friendly fire is a necessary evil of war.": "{0.00->0.74}欢迎回来。{1.23->3.91}战争期间难免误伤友方。", + "{0.00->0.56}Tagging map.": "{0.00->0.70}标记地图,", + "{0.00->0.57}Helldiver. {1.20->3.55}Take command of the Galaxy's liberation.": "{0.00->0.84}绝地潜兵,{1.35->3.67}解放银河系的指挥权交给你了。", + "{0.03->1.67}We're gonna die!": "{0.03->1.67}我们死定了!", + "{0.00->0.84}On my position.": "{0.00->0.84}在我这里。", + "{0.00->0.61}Reloading.": "{0.00->0.61}换弹。", + "{0.03->2.68}Shoot! Shoot anything that looks weird!": "{0.00->2.79}射击!看到奇怪的东西就开枪!", + "{0.00->1.39}The Bellatrix system": "{0.00->1.39}参宿五星系", + "{0.01->1.70}Watch your lines of fire!": "{0.00->1.72}注意瞄准方向!", + "{0.03->2.56}FIRE AT WILL! FIRE AT WILL!": "{0.00->2.75}自由开火!自由开火!", + "{0.00->2.67}Tunnel breach detected. Prepare for Bug contact.": "{0.00->2.67}侦测到隧道洞口。准备与虫族交战。", + "{0.00->3.00}Managed Democracy offers true Freedom: {3.70->6.02}Freedom from the burden of choice.": "{0.00->3.25}管理式民主能够带来真正的自由:{3.62->6.20}你不必为选择而感到苦恼。", + "{0.00->0.71}Rolling out!": "{0.00->0.71}出发!", + "{0.00->1.26}Just stay calm.": "{0.00->1.26}不要着急。", + "{0.00->1.17}Let's move, people!{1.73->3.62}Oh uh, out I mean, move out, spread{4.10->4.42}out!": "{0.00->1.30}大家都动起来!{1.35->3.77}噢呃,我是说散开,{3.77->5.42}动起来,散开!", + "{0.00->1.30}The Leng system": "{0.00->1.30}蓝恩星系", + "{0.00->2.26}Additional reinforcement funding approved.": "{0.00->2.26}已批准增加增援资金。", + "{0.01->1.11}Let's get to work.": "{0.01->1.11}开始行动吧。", + "{0.03->1.20}Taking position.": "{0.00->1.27}各就各位。", + "{0.00->0.86}Voting Day. {1.22->4.69}An annual celebration of the idea of voting. {5.14->8.84}Enjoy. (ballots are not cast on voting day; no holiday is designated for voting)": "{0.00->3.93}投票日,即每年庆祝“投票”理念的日子。{4.43->6.87}尽情欢呼和享受吧。{7.14->9.47}(投票日不会举行投票,同时也不会放假)", + "{0.00->3.70}They got rid of it though. What's the point of havin' a game inside another game?": "{0.00->4.25}但是他们把它给删掉了。在游戏里面再放一个游戏有什么意义呢?", + "{7.67->11.23}Freedom's Greetings; I'm Coretta Kelly.{11.64->14.75}Tragedy has struck our Galaxy once more.{15.14->24.80}A strange intergalactic phenomenon created by Illuminate Exospires has plunged entire planets into an impenetrable darkness.{25.50->34.89}This strange area has been named \"The Void.\" The Void neither emits nor reflects light, or any other known signal.{35.28->38.28}Probes sent within have not returned.{39.02->47.11}The Illuminate continue their construction of Exospires, which we now understand are the means by which the Void is created.{47.43->51.67}When enough Exospires are constructed on planets near one another, {51.67->58.89}they and the space between them become engulfed by the Void, and the planets are lost from sight.{59.39->61.32}Facing this tragic threat,{61.50->69.71}the Helldivers have been ordered to prioritize their efforts entirely upon the prevention of Exospire construction,{69.84->76.21}as Ministry of Science experts race to discover more about this ethereal new threat.{76.39->80.23}That's Liberty's Latest; I'm Coretta Kelly.": "{7.59->10.65}自由向各位问好,我是科雷塔·凯利。{11.65->14.41}悲剧再度降临我们的银河系。{15.39->19.58}由光能者异界尖塔引发的一种诡异星际现象,{20.18->24.42}已使整颗星球陷入无法穿透的无尽黑暗之中。{25.14->28.23}这片诡异区域被命名为“寂域”。{29.63->34.68}寂域既不发光也不反光,更不会发出任何已知信号。{35.28->37.88}进入寂域的探测器杳无音讯。{38.78->41.24}光能者还在持续建造异界尖塔,{41.79->47.12}我们现已查明,这些尖塔正是制造寂域、引发无尽黑暗的根源。{48.05->51.59}如果相邻的星球上建造的异界尖塔达到足够的数量,{52.03->56.30}这些星球本身和星球之间的太空区域就会被寂域吞没,{56.66->58.35}从此消失不见。{59.40->61.13}面对这样悲剧性的威胁,{61.50->66.49}绝地潜兵奉命将全部精力集中于阻止敌人建造异界尖塔。{67.12->70.47}同时,科学部的专家正争分夺秒地研究{70.54->75.39}这一神秘而虚无的全新威胁,力求找出破解之道。{76.30->79.98}以上就是今天的《解放新闻》,我是科雷塔·凯利。", + "{0.00->2.56}The Illuminate reign of terror ends today.": "{0.00->2.56}今天是光能者恐怖统治的末日。", + "{0.03->0.76}What is that?": "{0.03->0.76}那是什么?", + "{0.00->1.47}The Phantom System": "{0.00->1.04}幻影星系", + "{0.00->1.56}How far are we going?": "{0.00->1.56}我们要走多远?", + "{0.03->1.21}What in Liberty's name!?": "{0.01->1.24}解放你大业啊!", + "{0.00->2.10}This is the right place. Right?": "{0.00->1.84}是在这里等,对吧?", + "{0.02->2.38}Take up the new position, while we still can!": "{0.02->2.55}趁现在还有机会,稳住新的阵地!", + "{0.00->3.03}Bug swarm intelligence is easy to misunderstand.{3.45->9.15}No single bug is smart by itself, but by coordinating as a whole, they can exhibit suprisingly{9.15->10.29}sophisticated behavior. Almost{11.04->14.60}like they're all individual neurons making up one giant brain.": "{0.00->3.03}虫族的群体智慧很容易被误解。{3.45->5.35}单个虫子本身没有智慧,{5.54->10.00}但虫群通过整体协作,就能表现出令人惊讶的复杂行为。{10.43->14.60}就像是单个神经元组成一个巨大的大脑。", + "{0.00->1.48}Deploying non-lethal payload": "{0.00->1.48}投放非致命攻击", + "{0.00->3.52}'Course, it means our coordinates are always changing as Super Earth spins, but that's easy enough {3.52->4.12}to account for.": "{0.00->3.21}当然,我们的坐标随着超级地球自转而不断改变,{3.23->4.43}但这个问题好解决。", + "{0.00->1.25}Weapons ready.": "{0.00->1.43}武器就绪。", + "{0.03->1.21}Automatons!": "{0.03->1.21}机器人!", + "{0.00->0.86}Thank Liberty,{1.23->2.87}we needed reinforcements!": "{0.00->0.88}感谢解放,{1.58->2.76}我们正需要支援!", + "{0.01->1.23}Watch the flanks!": "{0.01->1.23}注意侧翼!", + "{0.00->1.84}Illuminate artifact acquired.": "{0.00->1.84}光能者古物到手了。", + "{0.00->1.45}Strength in numbers!": "{0.00->1.16}人多力量大!", + "{0.04->1.71}Slimy freaks!": "{0.04->1.71}黏了吧唧的玩意儿!", + "{0.00->5.59}The collateral damage you did to the city was well worth its defense. Not to mention, unavoidable.": "{0.00->5.89}为了保卫城市,造成附带损害也是值得的。再说,也避免不了。", + "{0.00->6.83}Why would you grant rights to an Automaton? After all, you wouldn't grant rights to a dishwasher.": "{0.00->2.80}你怎么会想为机器人争取权利呢?{3.41->7.02}毕竟,你可不会为洗碗机争取权利。", + "{0.00->1.01}Battery's drained!": "{0.00->0.59}没电了!", + "{0.02->0.92}Find cover!": "{0.00->1.05}快找掩护!", + "{0.00->1.22}I'll never forget this.": "{0.00->1.61}我会永远记得今天。", + "{0.00->1.28}The bridge is fore of here. {1.64->4.21}Talk to the Democracy Officer when you're ready to join the fight.": "{0.00->1.28}舰桥就在前面。{1.64->4.21}做好战斗准备就去找民主官吧。", + "{0.02->1.27}The Fury system": "{0.02->1.27}费里星系", + "{0.00->1.65}Like bullets to brains!": "{0.00->1.76}这真是太爽了!", + "{0.02->1.67}Good day for violence.": "{0.00->1.71}以暴制暴就在今天。", + "{0.03->2.31}I'm never taking this stim out.": "{0.00->2.40}这一针,扎了就不想拔了。", + "{0.01->0.87}Watch your step!!": "{0.00->0.89}当心脚下!!", + "{0.00->1.25}Additional extraction point located.": "{0.00->1.25}这边也有一个撤离点。", + "{0.04->1.70}Cover, cover!": "{0.00->1.76}隐蔽,隐蔽!", + "{0.01->3.23}They'll think twice before infringing on our Freedom again.": "{0.01->3.23}自由之地不是你想来就来,想走就走的!", + "{0.01->1.03}Got a bead on them!": "{0.01->0.75}瞄准它们了!", + "{0.02->1.27}Incoming!": "{0.02->1.27}来了!", + "{0.00->5.57}They perished with the song of anti-socialism singing in their hearts.": "{0.00->5.30}他们心里唱着反集权主义的赞歌,慷慨赴死。", + "{0.01->2.25}No more controlling minds for YOU!": "{0.01->2.25}思想控制过气了!", + "{0.01->1.60}We need reinforcements!": "{0.01->1.42}我们需要增援!", + "{0.02->3.03}Can't take MY Freedom! Get your own!": "{0.00->1.91}别想夺走我的自由!{2.29->3.36}别抢我的!", + "{0.01->2.24}There! They found us!": "{0.01->2.24}那边!我们暴露了!", + "{0.00->2.13}Gonna turn their Homeworld into a junkyard.": "{0.00->2.13}一定要把它们的母星变成废料场。", + "{0.00->2.39}I haven't set foot on Super Earth myself, but {2.88->5.24}I've heard it's even more spectacular in person.": "{0.00->1.90}我还没有去过超级地球,{2.28->5.51}听说亲眼目睹会觉得更壮观。", + "{0.06->3.93}Man, those Illuminate Exostorms give me the creeps.{3.93->9.74}Reminds me of Hellmire's fire tornados, just darker, and more truth-resistant.": "{0.39->3.52}天啊,光能者的异界风暴真吓人。{4.52->9.74}让我想起了海尔迈尔的烈焰龙卷风,只是这风暴更阴暗,更抗拒真理。", + "{0.00->1.03}The mission failed, {1.45->5.07}but your return means we recovered our most invaluable asset.": "{0.00->0.99}任务失败,{1.26->4.59}但你还活着,你才是最有价值的资产。", + "{0.02->0.74}Attack!": "{0.00->0.71}进攻!", + "{0.00->0.68}Code is:": "{0.00->0.68}代码是:", + "{0.01->0.99}They killed them!": "{0.01->1.59}绝地潜兵被杀了!", + "{0.03->2.90}Agh! For Super Earth...": "{0.00->2.96}啊!为了超级地球……", + "{0.01->1.85}New engagement zone, soldiers.": "{0.00->1.91}士兵们,新的交战区。", + "{0.00->1.71}Incoming fire detected.": "{0.00->1.71}探测到敌方火力。", + "{0.10->5.07}The Illuminate clearly want to keep us out of their Archives. Proof that that's exactly where we{5.07->5.98}need to be going.": "{0.10->2.83}光能者显然不想让我们进入它们的档案阁。{3.28->5.85}这就说明我们必须要进去。", + "{0.00->1.59}A little shot o' Liberty.": "{0.00->1.59}来一针解放精华。", + "{0.03->1.00}The bugs are back!": "{0.03->1.00}虫族回来了!", + "{0.95->1.84}Incredible,{2.50->3.85}a Helldiver's might...": "{0.70->2.18}难以置信,{2.25->4.10}这就是绝地潜兵的实力……", + "{0.01->1.83}Liberty watch over us!": "{0.01->1.83}解放保佑我们!", + "{0.00->1.49}The Iridica system": "{0.00->1.49}艾丽迪卡星系", + "{0.01->0.75}We made it!": "{0.01->0.75}我们成功了!", + "{0.03->1.56}What was that!?": "{0.85->1.78}刚才那是什么!?", + "{0.00->1.32}Ruined System": "{0.03->1.12}废墟星系", + "{0.02->1.23}It's gonna eat me!": "{0.02->1.23}它要吃了我!", + "{0.22->3.16}I never thought... wow.": "{0.00->1.59}没想到……{1.65->3.39}哇。", + "{0.00->2.00}Liberty has seen you through.": "{0.00->2.35}解放保佑你度过难关。", + "{0.00->1.52}A shrewd choice. {2.09->4.75}Each operation consists of several missions. {5.17->9.88}Decide where to begin...and we will prepare the Hellpod for your descent.": "{0.00->1.52}明智之选。{2.09->4.12}一场行动分为几项任务。{4.80->9.88}决定好从何处开始…我们就会为你准备绝地喷射舱。", + "{0.00->1.36}We have to keep moving.": "{0.00->1.36}我们必须继续前进。", + "{0.00->0.38}Left.": "{0.00->0.45}左边。", + "{0.00->1.33}The Crimsica system": "{0.00->1.33}克里姆西卡星系", + "{0.00->1.53}We're all going to die!": "{0.00->2.30}我们全都死定了!", + "{1.13->2.05}Incredible.": "{0.00->2.26}哇,太厉害了。", + "{1.27->3.68}I forget the rest, but it's great to turn wrenches to.": "{0.71->3.68}剩下的我忘了,但是很适合拧扳手的时候听。", + "{0.00->0.87}Enemies inbound.": "{0.00->0.69}敌人来了,", + "{0.00->0.85}We've got equipment.": "{0.00->0.85}那儿有装备,", + "{0.00->1.30}The Penta system": "{0.00->1.30}彭塔星系", + "{0.00->1.18}Helldiver reporting to the front.": "{0.00->1.42}绝地潜兵出击。", + "{1.49->2.42}Cyberstan...{2.90->5.51}That sure is one ugly planet.{6.13->9.59}But we'll give it the cosmetic surgery of Freedom, won't we, Helldiver?": "{1.10->2.37}生化斯坦……{3.18->4.53}这星球真够丑的。{5.24->8.35}不过我们会给它做个自由风格的整容手术,{8.69->9.64}对吧,绝地潜兵?", + "{0.00->0.95}Calling down equipment.": "{0.00->0.95}呼叫装备。", + "{0.02->1.22}We can't stay here!": "{0.00->1.22}这里待不了了!", + "{0.03->3.99}Shoot! Shoot anything that looks weird!": "{0.65->1.98}射击!{1.99->3.99}看到奇怪的东西就开枪!", + "{0.03->1.67}Get away from me!": "{0.03->1.84}不!不要靠近我!", + "{0.04->3.19}Argh! It's fine, we're fine...": "{0.00->3.45}啊!没事,我们没事……", + "{0.01->2.34}No more controlling minds for YOU!": "{0.01->2.34}思想控制过气了!", + "{0.00->1.74}Calling in a Hellbomb.": "{0.00->2.11}呼叫地狱火炸弹。", + "{0.00->2.90}They say the squids come from somewhere outside the Galaxy. {3.46->4.86}If they know what's good for them, {5.34->6.61}they'll stay there.": "{0.00->2.17}据说鱿鱼来自银河系之外。{2.65->6.11}它们要是识相的话,就该乖乖待着别乱动。", + "{0.01->4.04}Our resolve in the face of Tyranny will be their undoing!": "{0.01->4.04}在坚定的意志面前,暴政什么也不是!", + "{0.00->2.94}Not a Helldiver! It should have been me!!!": "{0.00->2.94}绝地潜兵不要死!死的应该是我!", + "{0.01->2.48}Tyranny will never prosper!": "{0.01->2.48}暴政没有好下场!", + "{0.03->0.92}There's more of them!": "{0.03->0.92}那边还有!", + "{0.05->7.97}Isn't it great that when even just a couple of people from the same corps shows signs of dissidency, all of us get extra Professional Development Training?{7.97->9.50}High Command truly does care.": "{0.00->3.43}只要同一个组织单位里有几个人表现出异议倾向,{3.85->6.21}我们所有人都能获得额外的职业发展培训,{6.37->7.27}真是太棒了!{7.80->9.93}最高指挥部真的很关心我们。", + "{0.00->3.85}One step closer to a galaxy purged of xenophobia.": "{0.00->3.85}距离扫清银河系的排外分子又近了一步。", + "{0.04->1.25}I need stims!": "{0.00->1.36}快给我来一针!", + "{0.00->1.41}Bug outpost spotted.": "{0.00->1.41}发现虫族哨站。", + "{0.06->1.08}Eat Liberty!": "{0.06->1.08}尝尝解放!", + "{0.01->4.07}Maintain formation! Make Super Earth proud!": "{0.00->3.70}保持阵型!成为超级地球的英雄!", + "{0.00->0.36}You {0.89->2.53}are a paragon of Liberty.": "{0.00->2.49}你是解放的最佳楷模。", + "{0.00->0.34}Three.": "{0.00->0.34}三。", + "{0.06->1.93}Plenty more where that came from!": "{0.06->1.93}这玩意儿我们多着呢!", + "{0.00->1.79}Freedom is its own reward—{2.49->3.45}but this doesn't hurt.": "{0.00->1.79}自由本身就是奖励,{2.49->3.45}但收下这个也无妨。", + "{0.00->0.98}Whoa!{1.21->4.05}Not every day you get to see a Hellbomb.": "{0.00->1.25}哎呀妈啊!{1.75->4.05}地狱火可不是天天见的!", + "{0.04->1.17}It's too high up!": "{0.00->1.25}这也太高了!", + "{0.00->2.16}Cyberstan will be heavily defended.{2.61->3.92}Are you ready, Helldiver?": "{0.00->2.16}生化斯坦的防御肯定很坚固。{2.34->3.92}绝地潜兵,准备好了吗?", + "{0.00->1.29}Black saffron. {1.68->3.74}Life saving and non-habit forming.": "{0.00->1.29}番黑花,{1.29->3.74}只救命,不成瘾。", + "{0.00->1.25}History matters! {1.62->8.95}After the First Galactic War, Super Earth kindly allowed the Cyborg Secessionists to live, giving {8.95->12.35}them stable work deep within the mines of Cyberstan. {12.71->20.11}But, twisted by their implants, the Cyborgs sought their revenge by creating The Automaton Legion!": "{0.00->1.25}铭记历史!{1.62->3.62}第一次星系战争结束后,{3.97->8.93}超级地球好心为奉行分裂主义的生化人留了一线生机,{8.95->12.97}还让它们在生化斯坦的矿井从事稳定的工作。{13.77->16.58}但是,这些生化人被植入体扭曲了思想,{16.82->20.74}居然恩将仇报,组建了机器人军团!", + "{0.06->4.44}I love y—Super Earth, I love Super Earth.": "{0.00->2.51}我爱——超级地球,{2.51->4.71}我爱超级地球。", + "{0.00->1.90}Will the shuttle have enough room for all of us?": "{0.00->1.90}运输船能装下所有人吗?", + "{0.00->4.04}Hey there, Helldiver. I know you put your neck on the line for regular folks like me every day.": "{0.00->4.04}绝地潜兵,我知道你每天都在为我这样的平民百姓冒险冲锋。", + "{7.42->10.52}Freedom's Greetings, I'm Coretta Kelly.{11.09->17.69}Today, Super Earth High Command announced the ultimate objective of Operation Free Space:{17.70->23.20}the construction of a powerful defensive weapon known as the Star of Peace.{23.89->31.14}Once complete, the Star of Peace is expected to usher in a new era of galactic security.{31.34->33.20}That's Liberty's Latest;{33.34->35.15}I'm Coretta Kelly.": "{7.42->10.52}自由向各位问好,{11.09->17.69}我是科雷塔·凯利。今日,{17.70->23.20}超级地球最高指挥部宣布了“自由太空行动”的终极目标:打造名为“和平之星”的强大防御武器。{23.89->31.14}建成后,和平之星有望开创银河系的安全新纪元。{31.34->33.20}以上就是今天的《解放新闻》,{33.34->35.15}我是科雷塔·凯利。", + "{0.00->1.67}The Generation System": "{0.00->1.05}源代星系", + "{0.00->1.75}Time for some payback!": "{0.00->1.79}是时候讨债了!", + "{0.00->0.38}Nice.": "{0.00->0.44}很好。", + "{0.00->3.89}Push back the enemy. End their unjust occupation.": "{0.00->3.48}发起反击,击退敌人的不义侵占。", + "{0.00->5.37}He would have to strap an Illuminate anti-matter generator to his chest and Liberate all his old {5.37->5.86}friends.": "{0.00->3.13}他必须把光能者反物质发生器系在胸口,{3.80->5.86}然后去解放他以前的所有朋友。", + "{0.00->1.31}I got this...": "{0.00->1.37}我能行……", + "{0.00->0.99}Liberty. {1.43->4.15}Dissidents don't know the meaning of the word. {4.68->10.08}That's why Super Earth has introduced a zero strike law for patriotic intolerance.": "{0.31->3.73}异见分子无法理解解放的含义。{4.61->9.90}所以超级地球才会对不爱国的叛徒采取零容忍政策。", + "{0.00->5.10}Helldiver. The industrial might of the Automatons has become a grave threat.": "{0.00->5.53}绝地潜兵,机器人的工业力量已经构成严峻威胁。", + "{7.62->10.64}Freedom's Greetings, I'm Coretta Kelly.{11.07->14.57}The Helldivers have deployed to the surface of Cyberstan, {14.57->17.19}where they are engaged in fierce combat {17.19->20.77}against the Cyborgs and their Automaton slaves.{21.34->25.82}Cyberstan is the seat of the Automaton and Cyborg war machine.{26.41->32.29}Its liberation could mark a turning point in the war against Socialist Terrorism.{32.97->37.99}The Cyborgs, defeated by the Helldivers at the end of the First Galactic War,{37.99->42.95}recently revealed themselves to be the masterminds behind the Automaton attacks.{43.48->46.49}These malformed creatures were once human, {46.49->52.42}but their hatred of Freedom twisted them into horrible, ugly freaks.{53.95->59.14}The Cyborgs have constructed a series of Megafactories across Cyberstan.{59.14->66.80}Reports indicate these factories are used to synthetically grow, and construct, new Cyborgs.{67.67->73.43}Up next: do Cyborgs dream of electrocuting humans? An expert weighs in.{73.67->76.97}That's Liberty's Latest; I'm Coretta Kelly.": "{7.67->10.46}自由向各位问好,我是科雷塔·凯利。{11.08->14.16}绝地潜兵已部署到生化斯坦地表,{14.73->19.91}他们将在此地与生化人及他们的机器人奴隶展开激烈战斗。{20.71->25.24}生化斯坦是机器人和生化人战争机器的核心基地。{25.93->27.14}解放生化斯坦{27.34->31.83}意味着对抗同盟主义恐怖势力的战争迎来转折点。{32.45->36.44}生化人在第一次星系战争末期败给绝地潜兵,{36.72->38.95}最近却暴露出真实身份,{39.19->43.02}它们才是机器人攻击行动的幕后主使。{43.50->45.92}这些畸形生物曾经也是人类,{46.42->48.90}但他们对自由抱有极度仇恨,{49.23->52.25}因此变成了可怖丑陋的怪物。{54.07->58.92}生化人目前在生化斯坦各地已经建造了许多超大型工厂。{59.19->62.66}据最新报告显示,这些孵化厂的主要用途{62.92->66.42}是合成培养和制造新的生化人。{67.46->71.79}接下来请收看:生化人会梦见电击人类的场景吗?{71.83->73.40}权威专家为您解读。{73.71->77.62}以上就是今天的《解放新闻》,我是科雷塔·凯利。", + "{0.02->1.81}The flag! The flag!": "{0.00->1.97}旗帜!旗帜!", + "{0.00->2.08}Back, everybody back!": "{0.00->2.22}后撤,全体后撤!", + "{0.00->0.70}High-value item.": "{0.00->0.70}高价值物品,", + "{0.02->1.19}Swapping battery.": "{0.02->1.19}换下电池。", + "{0.01->1.46}Safe and sound.": "{0.01->1.46}非常安全。", + "{0.00->0.92}Package acquired.": "{0.00->0.92}物品到手了。", + "{0.00->0.80}Enemy patrol.": "{0.00->0.88}敌方巡逻队,", + "{0.03->2.59}Targets acquired. Engage!": "{0.00->2.59}目标已拿下。开打!", + "{0.00->2.18}It'd be my Patriotic privilege.": "{0.00->1.69}这是我的爱国特权。", + "{0.02->1.12}Calling down a vehicle.": "{0.02->1.12}请求载具支援。", + "{0.06->5.48}Ah! My life... my life... hoo, boy.": "{0.00->2.73}啊!把我的生命献给……{2.74->5.26}献给……呼,天哪。", + "{0.01->1.52}Hide, hide!": "{0.00->1.63}躲起来,躲起来!", + "{0.02->3.24}FOR SUPER EAAAAARRRTTHHHH!": "{0.02->3.24}超级地球万岁!", + "{0.13->2.49}I've rarely seen Liberty dispensed so rapidly.": "{0.00->2.78}我很少见到解放实现得如此迅速。", + "{0.01->1.85}Special delivery!": "{0.01->1.60}有你的快递!", + "{0.00->1.34}Activating jump pack.": "{0.00->1.34}启动喷射背包。", + "{0.00->2.25}Taking back what's ours, one by one!": "{0.00->1.77}夺回属于我们的一切!", + "{0.00->1.31}Mission progress logged.": "{0.00->1.31}已记录任务进度。", + "{0.00->3.63}Worth...any cost...": "{0.00->3.63}一切…都值得…", + "{0.03->3.97}Did-- did you see that? Wait 'til my kids hear about this!": "{0.00->1.99}你——你看到了吗?{1.99->4.07}我以后得说给我孩子听。", + "{0.00->1.74}What did they ever do to you?!": "{0.00->1.61}它们对你做了什么?!", + "{0.00->0.87}Fortifications.": "{0.00->0.87}防御工事,", + "{0.03->3.21}We need to be... there! I think...?": "{0.00->2.34}我们得去……那边!{2.35->3.39}没错吧……?", + "{0.00->1.06}FIRE IN THE HOLE!": "{0.00->1.06}小心爆炸!", + "{0.00->0.70}Stimming you.": "{0.00->0.70}爽吗?", + "{0.00->5.23}The very air of this planet reeks with the odor of the disenfranchised.{5.63->7.83}Be on your guard, Helldiver.": "{0.00->2.60}这颗星球就连空气里都弥漫着{2.60->4.80}失去选举权者的恶臭。{5.49->7.80}绝地潜兵,保持警惕。", + "{0.00->1.42}This is where the shuttle lands?": "{0.00->2.05}运输船会来吗?", + "{0.00->0.25}Black saffron harvested.": "{0.00->1.63}番黑花到手了。", + "{0.00->0.68}First one.": "{0.00->0.68}第一个。", + "{0.03->0.84}Changing I.C.E.": "{0.03->0.84}更换冷却片。", + "{0.05->2.57}Woo-hoo! Happy to be here!": "{0.00->2.45}呜呼!很高兴能来!", + "{0.03->1.85}Sweet Liberty, it's the Helldivers!": "{0.03->1.85}解放保佑,绝地潜兵来了!", + "{0.09->2.43}A small price to pay for Freedom!": "{0.09->2.43}为了自由,这点代价算什么!", + "{0.00->1.50}I almost thought you wouldn't make it. {2.07->2.94}Glad I was wrong.": "{0.00->1.50}我差点以为你要不行了。{1.80->2.83}幸好我猜错了。", + "{0.00->7.73}There is no greater honor than defending our way of life. Remember, winning is more important than {7.73->8.21}living!": "{0.00->3.19}捍卫生存正道,就是最高的荣耀。{3.99->7.87}切记,胜利比生命更重要!", + "{0.00->1.05}A true hero.": "{0.00->1.05}真正的英雄。", + "{0.04->3.50}Yes! ...No one's going to believe this.": "{0.00->3.54}太棒了!……说出去绝对没人会信。", + "{0.02->2.29}Thank Freedom they're on our side!": "{0.00->2.49}感谢自由精神站在我们这边!", + "{0.00->1.05}Requesting orbital.": "{0.00->1.05}请求轨道攻击。", + "{0.00->1.25}SEAF squad on target.": "{0.00->1.31}武装部队前往目标。", + "{0.00->0.74}Dropships.": "{0.00->0.74}运输舰,", + "{0.01->5.04}YEEEAH! EAT LIBERTY! THERE'S ENOUGH FOR EVERYBODY!!": "{0.01->5.04}爽啊!尝尝自由!量大管饱!", + "{0.00->1.63}Requesting supplies for the cause.": "{0.00->1.63}以解放之名请求补给。", + "{0.10->1.04}Stick together!": "{0.00->1.13}全体保持队形!", + "{0.01->1.23}RUN!": "{0.01->1.23}快跑!", + "{0.00->0.63}ETA T-{1.05->1.95}10 seconds.": "{0.00->1.82}预计10秒后到达。", + "{0.03->5.30}Well...we lost this one. The Void is still out there.{5.30->13.01}At times like these, I ask myself: what would a Helldiver do? Lay down and die?{13.01->14.77}I don't think so.": "{0.00->3.21}哎……打输了。{3.78->5.73}寂域依然存在。{6.83->11.64}在这种时候,我会问自己:绝地潜兵会怎么做?{12.23->15.02}坐以待毙?肯定不会。", + "{0.00->3.04}When this city erects a monument to its saviors,{3.33->6.95}their sacrifice will be proportionately represented.": "{0.00->3.04}当城市为英雄竖起纪念碑,{3.33->6.95}他们的牺牲将被永远铭记。", + "{0.00->0.69}I need ammo.": "{0.00->0.69}我需要弹药。", + "{0.02->1.97}The only good bug is a dead bug!": "{0.02->1.97}恶心虫子死了才好!", + "{0.05->1.25}What is that?": "{0.05->1.25}那到底是什么?", + "{0.06->3.90}Freedom must reign over every last star!": "{0.00->3.93}自由之风必将吹遍宇宙繁星!", + "{0.00->0.91}Last one down.": "{0.00->0.91}都搞定了!", + "{0.00->2.17}DEMOCRACY FOR ALL!": "{0.00->2.11}民主人人有份!", + "{0.00->0.93}Orbital inbound!": "{0.00->0.93}轨道攻击来了!", + "{0.00->4.35}Our heroes fall to the horror of the Void.": "{0.00->4.47}我们的英雄在寂域的恐怖中折戟。", + "{0.00->1.23}Let's go!{1.84->2.09}Kill 'em!": "{0.00->2.14}都给我上!消灭它们!", + "{0.04->1.89}Slimy freaks!": "{0.04->1.89}黏了吧唧的玩意儿!", + "{0.00->0.80}Incredible,{1.39->2.77}a Helldiver's might...": "{0.00->3.07}难以置信,这就是绝地潜兵的实力……", + "{0.02->0.82}Illuminate!": "{0.02->0.82}光能者!", + "{0.00->1.32}Calling down objective equipment.": "{0.00->1.32}呼叫目标需要的装备。", + "{0.00->0.90}Hold firm!": "{0.00->0.90}坚持住!", + "{0.04->1.47}More Automatons!": "{0.04->1.76}机器人又来了!", + "{0.19->0.85}200 meters.": "{0.00->0.67}200米。", + "{0.00->0.95}Calling in extraction!": "{0.00->0.95}呼叫撤离!", + "{0.00->1.15}Good work down there. {1.86->4.23}Could always use more samples, of course.": "{0.00->1.86}你的实战表现非常出色。{2.25->4.23}要是能多采集一些样本就更好了。", + "{0.00->1.30}Liberty dispensed.": "{0.00->1.30}已传播解放。", + "{0.03->2.29}Okay, time to spread out.": "{0.00->2.36}好了,该散开了。", + "{0.00->1.76}Did you spit on Cyberstan for me?": "{0.00->1.80}替我往生化斯坦吐口水了吗?", + "{0.00->2.34}Tactical reorientation! Let's go!": "{0.00->2.40}重新部署战术!先撤退!", + "{0.00->1.11}Requesting equipment!": "{0.00->1.11}请求装备支援!", + "{0.03->5.73}Remember: There is no Enlightenment outside Democracy's light.": "{0.03->5.76}切记:民主之光照耀不到的地方,再无启蒙。", + "{0.04->0.80}Watch out!": "{0.04->0.80}小心!", + "{0.05->1.29}Are we nearly there?": "{0.05->1.29}快到了吗?", + "{0.00->1.13}Package retrieved.": "{0.00->1.13}接到目标了。", + "{0.00->1.21}Eat this!!!": "{0.00->1.21}尝尝这个!!!", + "{0.00->1.47}Squid outpost spotted.": "{0.00->1.47}发现鱿鱼哨站。", + "{0.00->0.95}Squid warp gate.": "{0.00->0.95}鱿鱼传送门,", + "{0.00->2.67}Careful, Helldiver, we're tearing this down.": "{0.00->2.74}潜兵,小心,我们要把这里夷为平地。", + "{0.00->2.03}Launch countdown complete. We have to leave now!": "{0.00->2.03}起飞倒计时结束。我们必须立即离开!", + "{0.00->3.33}Do not let the Illuminate boggle your senses.{3.49->9.75}Hold fast to your weapon, and to your allies, and strike their ghastly heart.": "{0.00->3.01}别让光能者蛊惑你的感官。{3.01->6.84}握紧你的武器,守护你的战友,{6.84->9.79}直捣敌人的阴险腹地。", + "{0.09->5.73}Stretch your body. Stretch your mind.{5.73->13.61}Let it wander, let it wonder, about Liberty's grace.{13.61->24.16}This is where curiosity is safe; when dwelling on what we already know.": "{0.00->5.74}舒展身体。拓宽思维。{7.14->14.26}让思维自由游走,思考解放的恩典。{16.11->19.89}如果我们专心思考已知的事物,{20.30->24.03}就不会因为好奇而受到毒害。", + "{0.04->4.03}YEAH! SHOOT THEIR HEADS OFF! LEAVE NOTHING BEHIND!": "{0.04->4.03}爽啊!打爆它们脑袋!一个不留!", + "{0.00->0.79}Need to reload!": "{0.00->0.75}需要换弹!", + "{0.00->1.68}Dawdle not, Helldiver!{2.11->6.40}The Cyborgs have launched a surprise attack upon Super Earth itself!": "{0.00->2.32}绝地潜兵,刻不容缓!{2.70->6.68}生化人对超级地球本土发动了突袭!", + "{0.03->1.50}Everyone get down!": "{0.00->1.55}注意,全体卧倒!", + "{0.00->2.03}Always good to have another hero on board.": "{0.00->2.09}又一位英雄登舰,欢迎你。", + "{0.00->1.24}Spread out, everyone!": "{0.00->1.37}所有人,散开!", + "{0.03->1.12}Grenade!": "{0.03->1.12}手雷!", + "{0.04->2.07}Super Earth reigns!": "{0.00->2.07}超级地球一统天下!", + "{0.00->2.85}All set to Liberate a hole in their head...": "{0.00->2.85}解放,让它们的脑袋开花……", + "{0.00->3.92}For every fallen hero, we'll bomb another ten repair shops.": "{0.00->3.72}每牺牲一位英雄,我们就炸毁十座修理厂。", + "{0.03->1.87}Over every last star!": "{0.00->1.93}吹遍宇宙繁星!", + "{0.02->0.80}Throwing grenade!": "{0.02->0.80}尝尝手雷!", + "{0.00->4.28}Ours are the hands that will tear asunder the binds of tyranny.": "{0.00->1.53}正是我们的双手,{1.66->4.53}让我们能够撕裂暴政的枷锁。", + "{0.00->1.54}The Chort Bay system": "{0.00->1.54}雀特湾星系", + "{0.01->1.85}Managed Democracy in action!": "{0.01->1.85}这就是管理式民主!", + "{0.00->5.73}Reports of citizen disappearances have increased following the emergence of the Void.{6.18->7.95}A troubling development.": "{0.00->4.89}寂域出现后,公民失踪的报告显著增加。{5.68->7.83}事态令人担忧。", + "{0.00->1.57}The Claorell system": "{0.00->1.57}可洛尔星系", + "{0.02->0.90}They killed them!": "{0.02->1.27}他们被杀了!", + "{0.00->1.29}The Viridia system": "{0.00->1.29}维尔伊迪亚星系", + "{0.02->1.44}Reinforcing!": "{0.02->1.44}请求增援!", + "{0.00->4.65}Remember the 3 S's: Security, Solidarity, {5.01->6.10}Surveillance.": "{0.00->1.38}谨记3“护”:{1.91->6.00}防护、协护、还有监护。", + "{0.00->1.43}Calling down supplies.": "{0.00->1.43}呼叫补给。呼叫补给。", + "{0.04->1.24}Prepare for demolition.": "{0.00->1.32}爆破工作准备就绪。", + "{0.46->4.14}*scoffs* Great idea. Everyone'll just become a political expert overnight. {4.51->5.53}Treasonous morons.": "{0.21->1.72}呵,真厉害。{1.95->4.15}所有人都能突然变成政治专家是吧。{4.51->5.53}叛国的白痴。", + "{0.02->1.81}Hey, stim me!": "{0.00->1.81}嘿,来一针!", + "{0.00->5.52}Show your loved ones that you have the courage to be free by rejecting your retirement and {5.52->6.34}reenlisting!": "{0.00->2.54}拒绝退休,拥抱延长服役,{2.98->6.25}让爱你的人看到你追求自由的勇气!", + "{0.00->0.51}I'm on it.": "{0.00->0.51}我来。", + "{0.10->4.06}You will be among the first to foray into the depths of the Gloom. {4.72->7.30}We know not what horrors lurk within. {7.98->10.75}Be ready for anything, Helldiver.": "{0.10->3.30}你们是首批勇闯“阴霾”深处的勇士。{3.64->7.62}我们无法预知那里潜藏着何种恐怖。{8.12->10.81}绝地潜兵,请随机应变。", + "{0.07->7.19}The Automaton force that first beset our territories did not come from Cyberstan. {7.88->13.65}In what overlooked cranny of the galaxy was that invasion force constructed?": "{0.07->6.10}最初侵犯我们领土的机器人部队并非来自生化斯坦。{6.48->13.70}这支入侵部队究竟是在银河系哪个被我们忽视的角落建造的?", + "{0.00->0.46}No!": "{0.00->0.46}不!", + "{0.00->1.31}Tech sample acquired.": "{0.00->1.31}科技样本到手了。", + "{1.54->2.19}I feel safer already.": "{0.31->2.26}我觉得安全多了。", + "{0.00->1.56}The Lindome System": "{0.00->1.23}林杜默星系", + "{0.17->1.58}It's really them!": "{0.00->1.44}他们真的来了!", + "{0.06->1.08}They're coming!": "{0.06->1.08}它们来了!", + "{0.00->0.44}Danger.": "{0.00->0.44}危险,", + "{0.00->1.16}VIP secured.": "{0.00->1.16}VIP现已安全。", + "{0.02->0.68}Sixth one.": "{0.02->0.68}第六个。", + "{0.02->3.40}You are the tinder, and Liberty is the match!": "{0.02->3.18}你们是干柴,解放是烈火!", + "{0.22->2.63}And that's why YOU'RE the Helldiver!": "{0.00->2.57}这就是为什么你能当绝地潜兵!", + "{0.00->0.52}Vehicle.": "{0.00->0.52}载具,", + "{0.00->5.76}The Illuminate have returned, but their autocratic intentions remain shrouded in mystery.": "{0.00->6.07}光能者再度现世,但其专制意图依旧深藏不露,蒙着一层神秘面纱。", + "{0.01->1.92}Get your own Democracy!": "{0.01->1.92}去争取你们自己的民主!", + "{0.00->3.40}You get the family separation bonus, which more than makes up for the bunk and chow fees.": "{0.00->1.78}能拿到的家庭分离补助金{1.83->3.46}就超过了床位费和伙食费。", + "{0.00->3.46}We must give no less than the entirety of our being {3.84->5.41}in service to Freedom.": "{0.00->1.25}为了自由,{1.34->5.70}我们必须毫无保留毫无顾忌地献出一切。", + "{0.01->1.64}Democracy deliver us!": "{0.01->1.64}愿民主保佑我们!", + "{0.00->1.10}Democracy delivered.": "{0.00->1.10}已传播民主。", + "{0.00->2.91}Their bodies dirty up our streets.": "{0.00->2.91}他们的尸体,把街道都弄脏了。", + "{0.02->1.18}Cover my sector!": "{0.00->0.76}帮我一把!", + "{0.00->1.94}Ah! They got me,{1.94->4.26}the Fascists got me!": "{0.00->2.11}啊!我受伤了,{2.11->4.24}那群没脸皮的法西斯!", + "{0.00->0.91}I need supplies!": "{0.00->0.91}我需要补给!", + "{0.01->4.37}It was my... patriotic p-privilege...": "{0.01->4.37}这是我的…爱国特权…", + "{0.00->2.38}Those bots didn't stand a chance against you.": "{0.00->2.44}那些机器人,根本不是你的对手。", + "{0.02->0.77}It's them!": "{0.02->0.97}看见它们了!", + "{0.00->1.61}Annihilated System": "{0.00->1.33}已歼灭星系", + "{0.00->2.78}Lots of enemies killed, lots of samples collected. {3.48->5.24}That's a good mission in my book.": "{0.00->2.71}击杀了很多敌人,收集了很多样本。{3.17->5.07}可谓是十分成功的一次任务。", + "{0.05->1.17}Within the Gloom, {1.66->5.08}the Terminids have been enhanced into even deadlier predators. {5.48->9.37}But they remain mere quarry for Democracy's elite.": "{0.00->2.88}“阴霾”之中的终结族得到了强化,{3.21->5.53}变成更加致命的掠食者。{5.97->9.00}但它们仍旧只是民主精英的猎物。", + "{0.07->2.13}Eagle 1, rearming. Be back shortly.": "{0.07->2.13}“飞鹰”1号回去补给。请稍等。", + "{0.00->2.21}Ready or not, here I come!": "{0.00->2.24}我已经等不及了!", + "{0.00->2.94}A true servant of Freedom keeps no companion, {3.73->6.00}save Damsel Democracy herself.": "{0.00->3.18}为自由效劳的公仆不需要同伴,{3.69->6.47}只需心怀民主女神就够了。", + "{0.00->0.81}Support weapon.": "{0.00->0.75}支援武器,", + "{0.01->2.03}S'gonna blow! Move!": "{0.01->2.03}要炸了!快跑!", + "{0.00->1.29}Not safe here either!": "{0.00->1.29}这里也不安全!", + "{0.00->1.15}Illuminate teleporting in.": "{0.00->1.49}光能者即将传送抵达,", + "{0.08->2.62}Show 'em some family values!": "{0.00->2.52}展示下我们的家庭价值观!", + "{0.00->0.98}Now THAT'S{0.98->1.97}Democracy!": "{0.00->1.81}这才叫民主!", + "{0.14->1.75}Stay strong, soldiers!": "{0.00->1.78}士兵们,撑住!", + "{0.00->1.67}Get 'em... for...{2.23->3.06}me...": "{0.00->1.98}替我……消灭……{2.14->2.93}它们……", + "{0.01->1.50}Remember your duty!": "{0.01->1.50}记住你的职责!", + "{0.00->2.27}I just wiped the hard drive, reset the whole thing. {2.82->3.74}Now it's back to normal.": "{0.00->2.16}我刚刚清空了硬盘,把它整个重置了。{2.32->3.59}现在它恢复正常了。", + "{0.00->2.32}They're here! Protect us!": "{0.00->2.32}它们来了!保护我们!", + "{0.00->0.56}Affirmative.": "{0.00->0.56}好的收到。", + "{0.00->1.18}Calling down a sentry.": "{0.00->1.18}呼叫哨戒炮。", + "{0.00->1.13}Watch your sixes.": "{0.00->1.23}注意后边。", + "{0.00->1.66}Legendary iridescence.": "{0.00->1.90}这光芒真是耀眼。", + "{0.00->1.60}We've made it to the objective!": "{0.00->1.30}我们抵达目标了!", + "{0.00->2.23}High Prioriy Target neutralized.": "{0.00->2.23}已歼灭高优先级目标。", + "{0.00->0.36}Here?": "{0.00->0.42}这里?", + "{0.00->4.65}Delivering Democracy... it's beautiful.": "{0.00->4.65}传播民主…真美。", + "{0.01->0.91}Steady now!{0.97->1.74}Be ready!": "{0.00->0.57}稳住!{0.91->1.89}做好准备!", + "{0.15->0.87}Envision the {0.87->1.74}future.{1.74->5.09} Your descendants, smiling.{5.09->10.06} Super Earth, bright-towered in the sun.{10.06->21.99} Your cape, mounted on a pole, waving in the gentle breeze -- in time with the Super Earth flag.": "{0.00->1.77}想象未来。{2.81->6.08}子孙后代,笑容满面。{6.45->11.63}超级地球,巍然屹立,阳光明媚。{12.59->15.56}你的披风,高高挂起,{15.74->21.89}随风轻扬,与超级地球的旗帜交相辉映。", + "{0.00->1.14}Let's go, come on!": "{0.00->1.21}行动起来,快!", + "{2.28->3.04}Hahahahaha!": "{0.14->3.14}啊哈哈哈!!", + "{0.01->1.69}I need a hand over here!": "{0.00->1.83}我这里需要搭把手!", + "{0.00->0.87}We've got equipment.": "{0.00->0.87}那儿有装备,", + "{0.00->1.08}Swapping battery.": "{0.00->1.08}换下电池。", + "{0.00->2.33}Increased visibility. We can see them. {2.96->4.15}They can see us.": "{0.00->1.20}能见度提高。{1.22->4.15}我们能看见他们,他们也能看见我们。", + "{0.03->2.19}Come on, Lady Liberty's watching!": "{0.00->2.25}振作,自由女神看着我们呢!", + "{0.00->1.75}Freedom requires firepower.": "{0.00->1.75}自由需要更多火力。", + "{0.00->4.01}You have quenched the fires of the Automaton war machine.": "{0.00->4.01}你扑灭了机器人的战争机器燃起的烈火。", + "{0.17->1.08}I've got this one.": "{0.17->1.08}我来帮你。", + "{0.00->2.78}Let's show those sons o' dissidents who's boss!": "{0.00->2.88}让异见分子杂种看看谁才是老大!", + "{0.22->1.41}Please help! Please!": "{0.00->2.90}救命!救救我!", + "{0.03->2.06}We're all gonna die!": "{0.00->1.89}我们都死定了!", + "{0.00->2.58}Self-defense is our Democratic right.": "{0.00->2.58}自卫是民主赋予的权利。", + "{0.11->1.69}The Aurora Bay system": "{0.11->1.69}极光湾星系", + "{0.01->1.07}Dropping item!": "{0.01->1.07}放下物品!", + "{0.21->1.72}Filthy Terminid scum!": "{0.00->1.40}肮脏的臭虫!", + "{0.04->1.62}Save me, Helldiver!": "{0.00->1.63}潜兵,救救我!", + "{0.00->1.82}I'll never wash my eyes again.": "{0.00->2.01}我再也不洗眼睛了。", + "{0.01->0.59}Sentry.": "{0.01->0.59}哨戒炮,", + "{0.00->2.79}Welcome, Helldiver. Glad to have you with us.": "{0.00->2.79}欢迎,绝地潜兵。很高兴你能来。", + "{0.00->1.22}The Castor system": "{0.00->1.22}北河二星系", + "{0.00->1.29}The Veld system": "{0.00->1.29}维尔德星系", + "{0.01->2.47}Democracy will keep us safe.": "{0.01->1.99}民主会保佑我们的。", + "{0.02->0.71}Third one.": "{0.02->0.71}第三个。", + "{0.00->2.49}They died as they fought -- a hero.": "{0.00->2.49}战死沙场的都是英雄。", + "{0.00->1.45}Delivering payload.": "{0.00->1.45}火力送到家。", + "{0.00->3.62}Behind enemy lines, limited destroyer support.{4.24->6.45}Finally a challenge, eh Helldiver?": "{0.00->3.12}敌后作战,驱逐舰支援有限。{4.23->6.44}总算有点挑战了,对吧?", + "{0.01->1.12}Eat this!!!": "{0.01->0.86}接招!!!", + "{0.29->0.95}We're safe now!": "{0.29->0.95}我们安全了!", + "{0.00->0.76}Not engaging.": "{0.00->0.76}别打这个。", + "{0.01->1.25}We knew you'd come!": "{0.01->1.59}就知道你们一定会来!", + "{0.01->4.30}Oh, oh wow, thanks! Thank you, I mean.": "{0.00->2.47}噢,哇哦,谢谢!{2.48->4.52}谢谢你,真心的。", + "{0.00->0.47}Negative!": "{0.00->0.47}没办法。", + "{0.00->4.16}Good work, Helldiver. Whatever the bots try to build, we'll blow it apart.": "{0.00->5.08}绝地潜兵,干得漂亮。不管机器人造出什么玩意儿,我们都要把它炸个粉碎。", + "{0.48->3.22}I've been up late the past few days playing Bug Farm Simulator.": "{0.00->3.12}这几天我在熬夜玩《虫族农场模拟器》。", + "{0.01->2.72}You see that! Best of the best!": "{0.01->2.72}快看啊!精英中的精英!", + "{0.00->0.83}Enemies inbound.": "{0.00->0.90}敌人来了,", + "{0.30->3.35}Steady hands, soldiers. Do your part!": "{0.00->3.44}所有人把枪拿稳!尽全力!", + "{0.00->1.11}Activating jump pack.": "{0.00->1.11}喷射背包启动。", + "{0.00->0.70}Pack's out.": "{0.00->0.70}背包空了。", + "{0.02->2.63}Hellbomb request approved; deploying now.": "{0.02->2.63}批准使用地狱火炸弹;正在部署。", + "{0.00->0.63}This is it. {1.06->4.07}This is the solemn duty for which you were born. {4.50->6.05}Defend Democracy - {6.50->7.82}at any cost.": "{0.00->1.54}最终时刻来了,{1.76->4.43}这是你与生俱来的庄严使命。{4.69->7.82}不惜一切代价保卫民主!", + "{0.01->3.57}Hold your breath!": "{1.21->2.42}快憋气!", + "{0.05->1.18}Thank you, Helldiver.": "{0.00->1.65}谢谢你,潜兵。", + "{1.17->3.20}Hard work can get you there! {3.52->6.50}That is the Super Earth promise. {7.16->8.44}Put in your sweat. {8.89->10.07}Put in your blood. {10.68->14.03}Enjoy your patriotic responsibility. {15.08->19.27}Prove your dedication to the betterment of our federation...{19.58->24.19}And before you know it, you too will achieve your dreams. {24.77->26.08}Super Earth. {26.35->27.15}Freedom. {28.00->29.03}Justice. {29.40->30.74}Democracy... {31.60->33.46}And dreams.": "{1.17->3.67}只要努力,就必定会有回报!{4.03->6.50}这就是超级地球的承诺。{7.16->13.74}抛头颅,洒热血,这是我们为祖国肩负的崇高责任。{15.08->19.27}只要你以行动证明对联邦的忠诚与奉献,{19.58->24.19}你将会在不经意间,踏上实现梦想的道路。{24.77->26.08}超级地球,{26.35->27.15}自由,{28.00->29.03}正义,{29.40->30.74}民主,{31.60->33.46}还有梦想!", + "{0.01->1.20}Stay with me!": "{0.00->1.26}坚持下去!", + "{0.02->1.67}Give them what they deserve!": "{0.02->1.67}给它们应有的惩罚!", + "{0.00->2.21}There's no day-night cycle onboard these ships. {2.77->4.93}I like to imagine it's always morning, {5.46->8.47}with a whole day of defending Freedom left ahead of me.": "{0.00->1.95}舰船上没有昼夜循环。{2.56->4.82}我喜欢想象每一刻都是早晨,{5.28->8.86}那么剩下一整天都是保卫自由的时间。", + "{0.01->1.09}My ears are ringing!": "{0.01->0.91}我要聋了!", + "{0.00->1.08}I love you...{1.79->3.26}Super Earth...": "{0.00->1.10}我爱你…{1.94->4.03}超级地球…", + "{0.00->2.67}No no no no! Not a Helldiver!": "{0.00->3.03}不,不,不!绝地潜兵,不要死!", + "{0.87->2.78}Thankful you're on our side, Helldiver.": "{0.87->2.78}绝地潜兵,幸好有你。", + "{0.00->1.41}On the gun!": "{0.00->1.49}机枪手就位!", + "{0.00->4.93}Remember: a patriotic mind is a protected mind.": "{0.00->4.93}切记:爱国的心智不会被操纵。", + "{0.02->1.29}Need to reload!": "{0.02->1.29}需要换弹!", + "{0.00->0.32}YES!{1.05->1.43}I mean,{1.95->2.48}roger that.": "{0.00->0.67}遵命!{1.25->1.96}我是说,{2.17->2.78}收到。", + "{0.00->0.38}Aw,{0.92->2.66}you knew I needed that.": "{0.84->2.73}你知道我正需要这个。", + "{0.00->0.25}For prosperity!": "{0.00->1.21}为了繁荣!", + "{0.00->3.69}Allied Destroyer joining squadron. Deploying Helldiver to combat zone.": "{0.00->3.69}友方驱逐舰加入中队。将绝地潜兵部署至作战区域。", + "{0.02->2.04}How'd you like the taste of Freedom?": "{0.02->2.52}你就说这自由甜不甜?", + "{0.00->1.46}Local fauna.": "{0.00->1.20}当地动物。", + "{0.00->0.51}I win.": "{0.00->0.51}我赢了。", + "{0.03->4.20}If you've got any Medals or Super Credits, you can spend them in the Acquisition Center. {4.72->6.64}That's where they sell the fancy stuff.": "{0.00->5.08}如果你手上有奖章或者超级货币,可以去逛逛采购商店,{5.42->7.40}购买各种炫酷的东西。", + "{0.00->1.95}The Calefactoria System": "{0.00->1.11}炽庭星系", + "{0.00->1.86}Additional extraction point located.": "{0.00->1.86}这边也有一个撤离点。", + "{0.14->0.78}200 meters.": "{0.01->0.78}200米。", + "{0.06->1.74}What are those things?": "{0.06->1.74}那都是什么玩意儿?", + "{0.06->2.50}I never thought... wow.": "{0.00->2.43}没想到……哇。", + "{0.00->0.74}50 meters.": "{0.00->0.74}50米。", + "{0.03->5.12}What the...? MINES! Mines all over!": "{0.00->1.92}什么……?{1.92->5.23}有雷!遍地都是地雷!", + "{0.04->1.27}Incoming fire!": "{0.00->1.32}敌方火力很猛!", + "{0.04->1.67}Fall back, flag-rip it!": "{0.00->1.69}撤退!插了个旗的!", + "{0.00->0.38}This is the{0.79->1.82}right place. Right?": "{0.05->1.09}是在这里等,{1.24->1.68}对吧?", + "{0.02->1.13}Canister's empty.": "{0.02->1.13}没燃料了。", + "{0.05->0.56}2!": "{0.05->0.56}两!", + "{0.02->1.74}The Husaria System": "{0.02->1.22}轻骑星系", + "{0.02->1.47}A real Helldiver. {1.73->2.73}So gallant.{2.92->4.02}So noble.": "{0.00->1.77}真正的绝地潜兵。{2.07->3.10}多么英勇。{3.26->4.38}多么崇高。", + "{0.00->2.88}You can walk it off! Walk it off!": "{0.00->2.88}你能挺过去的!挺住!", + "{0.14->2.17}Just a fluke, c'mon, one more.": "{0.00->2.30}侥幸而已,再来一局。", + "{0.03->0.93}It's them!": "{0.03->0.93}看见它们了!", + "{0.01->2.26}A Helldiver!? ...RRRAAAAGHHHH!!!!!": "{0.01->2.26}绝地潜兵!?…啊啊啊啊啊!!!!!", + "{0.00->3.36}Cargo loading complete, Transport C-43 ready for launch.": "{0.00->3.36}货物装载完毕,运载火箭C-43准备发射。", + "{0.00->3.12}I... I can't believe you'd do that for me.": "{0.00->3.40}我……不敢相信你愿意分我一针。", + "{0.11->0.30}It's them!": "{0.00->1.06}看见它们了!", + "{0.02->4.67}They'll never take my... moral fortitude...": "{0.02->4.67}我的信念…不会动摇…", + "{0.00->2.06}Their lives were in our hands.": "{0.00->2.06}我们是他们的唯一希望。", + "{0.00->2.65}Another sample collected for Democracy.": "{0.00->2.65}又为民主大业拿到了一份样本。", + "{0.03->1.32}We're gonna die!": "{0.03->1.32}我们死定了!", + "{0.16->0.65}Yes!{1.13->3.03}All that training's finally paying off.": "{0.00->1.17}赢了!{1.18->3.37}平时的训练总算没有白费。", + "{0.00->1.37}Are you sure it's safe here?": "{0.00->1.37}这里确定安全吗?", + "{0.03->1.26}More bugs!": "{0.03->1.26}虫族又来了!", + "{0.03->1.41}The bugs are back!": "{0.03->1.41}虫族回来了!", + "{0.00->1.18}Consider it done.": "{0.00->1.01}包在我身上。", + "{0.00->0.69}Well done. {1.14->3.94}The enemy barely noticed our presence before we pulled out.": "{0.00->0.69}干得好。{1.14->4.13}敌人还没有察觉,我们就已经胜利撤退了。", + "{0.00->1.26}The Marre system": "{0.00->1.26}马尔星系", + "{0.00->0.51}Walker.": "{0.00->0.66}步行机甲,", + "{0.00->4.44}We enter the heart of the Gloom. Bleed it dry.": "{0.00->4.44}我们要进入“阴霾”中央。榨干它的资源。", + "{0.00->1.22}You saved my life!": "{0.00->1.34}你救了我的命!", + "{0.00->2.33}Well, no one can beat a Helldiver.": "{0.00->2.45}没事,没人能打败绝地潜兵。", + "{0.01->3.12}Don't stop! Rip 'em up! Yeah!": "{0.00->0.99}不要停!{1.21->3.12}撕烂它们!爽啊!", + "{0.05->1.63}Squid outpost spotted.": "{0.05->1.31}发现鱿鱼哨站。", + "{0.00->1.41}Hero down!": "{0.00->1.41}英雄倒下了!", + "{0.04->1.60}The embodiment of sheer{1.84->3.95}undeniable Democracy.": "{0.04->3.76}它象征着民主的势不可挡。", + "{0.00->0.79}Pack's out.": "{0.00->0.79}背包空了。", + "{0.00->0.68}Mourn,{1.07->2.18}then maim.": "{0.00->0.94}化悲痛{1.29->2.14}为力量。", + "{0.00->2.51}This is nice. Should be obligatory.": "{0.00->2.52}感觉真好。应该设为义务项目。", + "{0.02->3.10}Ugh, flags in rags, that hurts!": "{0.00->3.31}呃,插他旗的,好疼!", + "{0.00->5.30}Expect the unexpected, Helldiver—and riddle it with bullets.": "{0.00->3.33}绝地潜兵,以不变应万变,{3.33->5.29}用子弹解决一切。", + "{0.00->1.95}How dare THEY attack US!": "{0.00->1.95}这群东西,怎么敢的!", + "{0.03->0.87}I'm hit! {1.26->2.44}Sweet liberty…the {2.94->3.70}blood.": "{0.03->1.43}解放你大业的!{1.58->2.67}我中弹了!{2.75->4.12}疼死我了。", + "{0.02->3.56}Cover, uh, cover! Now!": "{0.00->2.29}掩护,掩护!{2.30->3.67}赶紧的!", + "{0.00->5.06}The time has come to tear down the Automatons' despotic infrastructure.": "{0.00->5.06}时机已经成熟,该彻底摧毁机器人的基础设施了。", + "{0.00->2.21}Dirty bug got what it deserved.": "{0.00->2.21}害虫就得杀干净。", + "{0.00->1.37}Calling in orbital strike.": "{0.00->1.37}请求轨道攻击支援。", + "{0.00->0.95}I got the terminal.": "{0.00->0.95}这个终端交给我。", + "{0.00->1.25}The Peacock system": "{0.00->1.25}孔雀十一星系", + "{0.00->1.44}Tech sample acquired.": "{0.00->1.44}科技样本到手了。", + "{0.00->3.13}We'll be generating fewer condolence letters than usual today. {3.84->4.39}Well done.": "{0.00->2.73}今天我们要写的吊唁信比平时要少。{3.66->4.42}干得好。", + "{0.03->1.61}I know we can't stay like this,{2.03->2.25}but...": "{0.00->2.12}我知道我们不能一直抱下去,{2.24->3.28}但……", + "{0.00->1.28}The Fenrir system": "{0.00->1.28}芬里尔星系", + "{0.00->4.53}We're fighting two fronts: the Terminids on one side, the Automatons on the other.": "{0.00->4.53}我们正在两线作战:一边是终结族,另一边是机器人。", + "{0.00->1.93}Freedom owes you a debt.": "{0.01->2.14}你为自由立下大功。", + "{0.01->1.53}Deploying destructive equipment!": "{0.00->1.64}正在部署爆破装置!", + "{0.01->0.86}Where to now?": "{0.01->0.86}接下来去哪?", + "{0.62->1.99}I can't wait to get home again. It's {2.50->3.90}the little things you miss, you know?": "{0.14->1.36}我等不及要回故乡了。{1.55->3.90}过往的小片段最让人怀念,你懂的吧?", + "{0.00->0.50}You will never destroy our way of life.": "{0.00->2.20}正道坚不可摧。", + "{0.02->1.32}The Erata system": "{0.02->1.32}艾拉特星系", + "{0.00->1.86}This is the right place. Right?": "{0.00->2.30}是在这里等,对吧?", + "{0.00->4.26}Megafactories rise on this planet like festering boils.{4.78->9.07}Purge the filth within, and cauterize what remains.": "{0.00->4.92}超大型工厂如溃烂的脓疮,遍布整个星球。{5.24->8.93}净化内部污秽,烧灼残余病灶。", + "{0.00->2.11}You're my oil now, bug.": "{0.00->2.11}今晚来点炸虫子。", + "{0.04->0.88}Go now. {1.37->3.95}Save this planet from infestation.": "{0.04->0.88}出发!{1.37->3.95}扫除虫害,拯救星球。", + "{0.02->1.63}Helldivers never die.": "{0.02->1.63}绝地潜兵死不了。", + "{0.03->0.55}Ok!": "{0.03->0.55}好的!", + "{0.00->2.05}Strike inbound. Clear out.": "{0.00->2.05}打击要来了。快撤。", + "{0.05->5.29}If future generations only knew the heroes that are protecting them.": "{0.00->3.11}哈哈哈,真希望子孙后代能知道,{3.11->5.17}是怎样的英雄在保护他们。", + "{0.00->1.42}The Gatria system": "{0.00->1.42}盖尔崔亚星系", + "{0.02->1.54}Prepare explosives.": "{0.00->1.59}准备炸药,准备炸药。", + "{2.12->3.27}Super Earth. {4.58->7.00}Remember why we fight.": "{2.12->3.38}超级地球。{4.58->7.19}牢记我们为何而战。", + "{0.00->1.65}Firing non-lethal payload": "{0.00->1.65}发射非致命攻击", + "{0.01->0.63}Moving!": "{0.01->0.63}前进!", + "{0.02->1.04}You're here!": "{0.02->1.04}你们来了!", + "{0.00->0.33}No.": "{0.00->0.33}不行。", + "{0.00->1.06}The Chara system": "{0.00->1.06}常陈四星系", + "{0.01->3.74}Our Democracy may be tested, but it will never be tainted.": "{0.01->3.74}民主接受考验,但不接受玷污。", + "{0.01->2.36}Now! Attack now!": "{0.00->0.87}冲啊!{1.02->2.36}趁现在!", + "{0.03->1.43}The Krakabos system": "{0.03->1.43}克拉克博斯星系", + "{0.05->4.24}Man, I can't believe we're actually gonna become Helldivers.": "{0.05->4.24}嘿,我们真的要成为绝地潜兵了,简直像做梦。", + "{0.02->0.79}Fall in.": "{0.02->0.48}集合。", + "{0.01->2.55}That all you got?!": "{0.89->2.17}就这点本事?", + "{0.05->3.23}You really are the best of the best.": "{0.05->3.05}你们是精英中的精英。", + "{0.00->0.69}Keep moving.": "{0.00->0.69}得赶紧走。", + "{0.00->0.79}Hold Position!": "{0.00->0.79}原地待命。", + "{0.01->0.75}Grenade!": "{0.01->0.75}手雷!", + "{0.00->0.88}High-value item.": "{0.00->0.88}高价值物品,", + "{0.05->0.96}Fire, now!": "{0.00->1.09}立即开火!", + "{0.00->2.52}The Terminids might be escaped farm animals, {3.86->4.11}but {4.96->5.92}they've been multiplying {6.62->8.45}faster than our regular units {9.23->9.77}can keep up {9.77->10.00}with. But now that the Helldivers are going in, we'll have them under control soon enough.": "{0.00->2.44}可以说终结族只是逃走的家畜,{2.54->6.13}但是它们繁殖得太快,我们的常规部队难以应对。{6.38->10.79}不过,既然绝地潜兵出动了,我们很快就能控制住局面。", + "{0.03->0.62}Thank you.": "{0.03->0.62}谢谢你。", + "{0.00->1.91}With the Bastion Tanks back in action,{2.27->5.58}we'll be just like the Helldivers from the first Galactic War, you and I.{6.15->7.83}We'll be unstoppable.": "{0.00->1.98}堡垒坦克重新投入战斗,{2.74->5.61}你我就像第一次星系战争中的绝地潜兵一样。{6.37->8.08}我们将所向无敌。", + "{0.00->0.65}Rolling out.": "{0.00->0.65}出发。", + "{0.07->0.54}Echo": "{0.07->0.54}E", + "{0.00->1.67}Support Station on its way.": "{0.00->1.67}支援站即将抵达。", + "{0.03->2.64}Sweet Liberty, my leg!": "{0.00->2.27}我超级自由的腿!", + "{0.14->1.95}I'm sorry, Helldiver!": "{0.00->2.08}我真的真的不是故意的!", + "{0.02->6.19}The DSS..it's like a Super Super, Super Destroyer.": "{0.00->5.62}民主空间站就像是加强版超级,超级驱逐舰。", + "{0.00->0.92}Inputting drop point.": "{0.00->0.92}确定降落地点。", + "{0.00->4.67}We have nearly freed a planet from the enemy. Your presence could decide its fate.": "{0.00->4.67}这颗星球马上就能全部解放了,你的加入至关重要。", + "{0.00->0.77}Dropping a pin.": "{0.00->0.70}正在标记,", + "{0.01->1.02}Run away!": "{0.01->1.02}快跑!", + "{0.00->2.59}It's a good day when we lose so few Helldivers.": "{0.00->2.80}我们今天很幸运,绝地潜兵的损失很少。", + "{0.02->2.21}Kill it! Destroy it!": "{0.02->2.21}快杀了它!杀了它!", + "{0.02->0.92}Need to reload!": "{0.02->0.92}需要换弹!", + "{0.22->0.65}Bug hole.": "{0.06->0.51}虫穴,", + "{0.00->1.79}I hope they died in pain.": "{0.00->1.79}希望他们不得好死。", + "{0.08->3.86}The light of Liberty's shining brighter already.": "{0.00->4.03}此刻解放之光格外的耀眼。", + "{0.07->3.43}And now, another helpful tip from General Brasch.{5.99->10.24}If you choose to reload your weapon before the current mag is empty, {14.50->17.25}those bullets end up wasted on the ground, {17.67->21.32}instead of buried in the beating hearts of our enemies.{25.10->26.05}I say: {26.42->27.82}waste enemies, {28.00->29.77}not bullets.{30.28->34.27}BRASCH TACTICS! Use 'em, or die trying.": "{0.07->3.43}布拉施将军又带来了一条实用提示。{5.99->10.24}如果你在弹匣还没耗尽的时候就重新装弹,{14.50->18.57}弹匣里的剩余子弹就会被丢弃到地上浪费掉,{18.63->20.44}不能打进敌人的心脏。{25.14->29.69}我的建议是:与其浪费子弹,不如打死敌人。{30.08->31.82}布拉施亲传战术!{31.82->34.70}竭尽全力,不死不休。", + "{0.02->0.89}For Liberty.": "{0.00->0.93}为了解放。", + "{0.01->2.00}Say hello to Democracy.": "{0.21->2.00}民主驾到。", + "{0.00->2.20}Pretty sure it's not armed yet.": "{0.00->2.25}它应该还没激活。", + "{3.71->6.22}Not now! Not yet! So many Votes left to cast!": "{0.00->6.71}我不能死!还不是时候!还有好多票没投!", + "{0.04->1.77}Somebody help!": "{0.04->2.12}谁来救救我!", + "{0.00->0.56}Delta": "{0.00->0.56}D", + "{0.00->1.94}I am a soldier of Liberty.": "{0.00->1.94}我是捍卫解放的战士。", + "{0.00->0.73}Fifth one.": "{0.00->0.73}第五个。", + "{0.01->1.18}Reinforcing.": "{0.01->1.18}请求增援。", + "{0.00->1.93}Mission at 10 minutes remaining.": "{0.00->1.93}任务剩余10分钟。", + "{0.00->4.11}Democracy is kind of like these machines I work on. It needs regular maintenance to keep running {4.11->4.60}smoothly.": "{0.00->2.08}民主有点像我负责的这些机器,{2.55->4.60}需要定期维护才能平稳运行。", + "{0.01->4.95}Liberty emerges victorious yet again. Extract when ready.": "{0.01->2.38}解放再次获得胜利,{2.89->4.95}准备好就撤离吧。", + "{0.00->4.37}Our forces fight to free this planet from the clawed grasp of the Terminids. {5.10->8.72}A litany of elite operations await your initiation.": "{0.00->4.91}我方部队正在争取击碎终结族的利爪,解放这颗星球。{5.37->8.72}你可以开展一连串的精英行动。", + "{0.02->0.71}Over there!": "{0.02->0.71}在那边!", + "{0.04->3.66}Okay, this is happening, it's happening!": "{0.45->3.60}天哪,来了来了,真的来了!", + "{0.01->2.52}Helldiver!? VENGEANCE!": "{0.01->2.52}绝地潜兵!?复仇!", + "{0.00->3.59}Another step closer to a successful operation.": "{0.00->3.59}距离此次行动成功,又近了一步。", + "{0.01->0.70}Medic!": "{0.01->0.70}医疗兵!", + "{0.03->1.12}We're gonna die!": "{0.03->1.12}我们死定了!", + "{0.10->2.15}Oh, thank you!": "{0.00->2.21}哦,谢谢!", + "{0.00->1.19}The Stout system": "{0.00->1.19}斯图尔特星系", + "{0.03->1.92}Saviors of Super Earth!": "{0.03->1.92}超级地球的救星!", + "{0.00->1.46}The Varylia system": "{0.00->1.46}瓦瑞利亚星系", + "{0.00->3.68}No no no no! Not a Helldiver!": "{0.00->4.35}不,不,不!绝地潜兵求你不要死!", + "{0.01->0.47}Here.": "{0.01->0.47}给你!", + "{0.00->3.52}Countless opportunities for Justice to be dispensed.": "{0.00->3.52}你面前有无数个伸张正义的机会。", + "{0.00->0.82}I'm on the terminal.": "{0.00->0.82}让我来操作。", + "{0.26->3.26}Sometimes I forget that we're just one piece of the puzzle. {3.88->7.95}Case in point, once we push back the bugs, the SEAF will take over, {8.51->10.35}guarding the construction of the TCS. {11.13->12.52}Everyone has their part.": "{0.26->3.77}有时我会忘记自己不过是一片拼图。举个例子,{4.00->8.60}等到我们把虫族击退之后,超级地球武装部队就会接管局面,{8.83->11.18}负责保卫遏制系统的建设工作。{11.45->13.02}大家各司其职。", + "{1.10->1.26}Uh... Ah! {1.66->3.99}Please keep moving through the training course at this time...{4.62->4.95}Over.": "{0.07->1.43}呃…{1.66->3.99}请不要在训练场里停下来…{4.62->4.95}完毕。", + "{0.03->1.53}Hey, stim me!": "{0.00->1.62}嘿,来一针!", + "{0.01->0.60}Reloading.": "{0.01->0.60}换弹。", + "{0.00->1.43}The Socorro system": "{0.00->1.43}索科罗星系", + "{0.00->0.86}We're safe!": "{0.00->0.86}我们没事了!", + "{0.13->2.59}Step up to the platform, recruit. {3.51->5.06}You've earned it.": "{0.13->2.59}新兵,走到平台上。{3.51->5.06}这是你应得的。", + "{0.00->3.26}Decreased visibility—should help obscure our movements.": "{0.00->3.26}能见度降低,方便我们隐藏行踪。", + "{0.00->2.83}Okay, this is happening, it's happening!": "{0.00->2.87}天哪,来了来了,真的来了!", + "{0.00->0.95}I don't think I can do that.": "{0.00->1.00}我这边过不去。", + "{0.00->0.50}Of course.": "{0.00->0.50}那当然。", + "{0.05->2.38}Nothing's gonna mess with this!": "{0.41->2.15}没人敢和这东西作对!", + "{0.02->2.93}Yes! ...No one's going to believe this.": "{0.00->3.08}太棒了!……说出去绝对没人会信。", + "{0.02->1.13}Need assistance!": "{0.00->1.17}请求救助!", + "{0.00->0.43}Here.": "{0.00->0.43}来。", + "{0.00->0.44}Hellbomb.": "{0.00->0.68}地狱火炸弹,", + "{0.04->0.66}Move it!": "{0.00->1.39}快,跑起来!", + "{0.04->0.72}We're safe!": "{0.04->0.72}我们没事了!", + "{0.00->0.45}Swapping battery.": "{0.00->0.98}换下电池。", + "{0.00->4.36}You know, in all the Super Earth records, there isn't a single confirmed case of a Hellpod killing {4.36->4.91}a Helldiver.": "{0.00->1.71}在超级地球的档案库里,{1.89->4.92}从未有过绝地潜兵因绝地喷射舱而死的确凿案例。", + "{0.01->2.79}It's armed?! Go go go go!!": "{0.01->2.79}已经激活了?!赶紧跑!跑!", + "{0.01->3.90}So, uh, are we getting evacuated, or, uh...?": "{0.01->3.90}那,我们是要撤离,还是……?", + "{0.00->5.50}A strong economy means a strong Super Earth. Spend money; save lives.": "{0.00->2.86}经济越发达,超级地球就越强大。{3.36->5.51}积极消费就能拯救生命。", + "{0.20->1.75}I thought I was gonna die.": "{0.49->1.83}还以为我死定了。", + "{0.00->1.28}Calling down support weapon.": "{0.00->1.28}呼叫支援武器。", + "{0.00->1.38}Democracy for all.": "{0.00->1.38}民主人人有份。", + "{0.00->2.65}Our citizens depend on you for their safety.": "{0.00->2.65}公民的人身安全就靠你了。", + "{0.06->0.93}The Gloom...{1.49->2.95}what's going on in there?": "{0.06->0.93}“阴霾”内部{1.49->2.95}发生了什么事?", + "{0.00->4.50}Lady Liberty's calls for aid haunt my dreams.": "{0.00->4.56}我在睡梦中也能听见自由女神的召唤。", + "{0.02->2.81}Helldiver down! Death to the enemy!": "{0.02->2.81}绝地潜兵阵亡了!让敌人去死吧!", + "{0.02->2.33}Only Justice speaks binary!": "{0.02->1.91}只有正义才是二进制!", + "{0.03->1.98}Glad to fight alongside ya!": "{0.00->2.05}与你并肩作战真好!", + "{0.10->1.30}Fire on target!": "{0.00->1.41}朝目标开火!", + "{0.01->0.98}I need supplies!": "{0.01->0.98}我需要补给!", + "{0.00->0.57}Three.": "{0.00->0.57}三。", + "{0.00->2.40}S-E-A-F, what does it spell?!": "{0.00->2.58}S-E-A-F,跟我一起念!", + "{0.04->1.15}Engaging terminal.": "{0.04->1.15}操作终端。", + "{0.00->1.68}The Stor Tha system": "{0.00->1.68}斯特萨星系", + "{0.00->4.06}I've been listening to old interstellar cargo shanties lately. My favorite's called \"The Helldiver.\"": "{0.00->4.06}我最近在听星际货运船金曲,最喜欢的一首叫《绝地潜兵》。", + "{0.00->1.69}High-value sample collected.": "{0.00->1.69}高价值样本到手了。", + "{0.00->1.86}Unidentified hostiles incoming.": "{0.00->1.86}身份不明的敌人就要来了。", + "{0.01->2.32}Freedom thanks you, Helldiver.": "{0.01->2.64}绝地潜兵,自由向你致谢。", + "{0.00->0.47}Heavy.": "{0.00->0.47}重型敌人。", + "{0.00->1.95}Engaging orbital thrusters.": "{0.00->1.95}准备轨道推进器。", + "{0.01->8.77}Those Exospires sure are ugly. Nothing a civilized species would build. Need more flags, for one.": "{0.01->2.28}那些异界尖塔真够难看的。{2.65->4.88}文明种族绝不会建造这种东西。{5.23->7.33}至少该多插几面旗。", + "{0.00->3.49}Who can say, when the first star was lit?{4.18->14.19}What the essence of Democracy is? When Space is truly Free? We can.{14.19->16.75}Your government can.": "{0.00->4.01}谁能说出第一颗星星何时点亮?{4.35->7.05}民主的本质是什么?{8.30->11.54}太空何时真正实现的自由?{12.53->13.93}我们能。{14.72->16.61}你的政府能。", + "{0.01->1.66}Proof of our resolve!": "{0.01->1.66}这证明了我们的决心!", + "{0.00->1.41}Freedom's greetings!": "{0.00->1.41}自由向你问好!", + "{0.00->1.45}Requesting tac-pack.": "{0.00->1.45}请求投放战术背包。", + "{0.00->0.95}Administering meds!": "{0.00->0.95}一个都不能少!", + "{0.01->1.88}Contact! CONTACT!!!": "{0.01->1.88}有敌人!有敌人!!!", + "{1.97->2.60}Can't Liberate with this broken arm.": "{0.04->2.90}受伤的胳膊还怎么解放!", + "{0.00->3.71}Our heroes held firm, as they always will.": "{0.00->3.89}英雄们守住了阵线,以后也会坚如磐石。", + "{0.00->0.64}Supplies.": "{0.00->0.48}补给,", + "{0.00->1.40}Bug tunnel breach!": "{0.00->1.40}虫族隧道洞口!", + "{0.00->3.63}Choose where to join your fellows in righteous Liberation.": "{0.00->3.88}选择战场,与同伴一起踏上解放的正道。", + "{0.00->0.85}Enemies inbound.": "{0.00->0.85}敌人来了,", + "{0.04->3.12}Cover, uh, cover! Now!": "{0.00->3.19}掩护,掩护!赶紧的!", + "{0.00->3.18}We cannot allow this city to fall into the enemy's hands.": "{0.00->3.18}绝不能让这座城市落入敌手。", + "{0.00->1.50}Requesting fortifications.": "{0.00->1.50}请求防御工事。", + "{0.04->3.17}Come ON, that's incredible!": "{0.00->3.16}噢天哪,太神奇了!", + "{0.02->1.89}Heads down, now!": "{0.00->1.92}快趴下,赶紧的!", + "{0.03->1.62}Make it stop!": "{0.03->1.62}快救救我!", + "{0.00->2.96}The enemy has corrupted our metropolis long enough.{3.34->4.80}We must take it back!": "{0.00->2.96}长久以来,敌人一直在蹂躏我们的城市。{3.34->4.80}一定要夺回这座城市!", + "{0.02->1.45}The Helldivers are here!": "{0.02->1.45}绝地潜兵来了!", + "{0.01->0.82}Get in.": "{0.01->0.82}上来。", + "{0.03->1.35}The bots are here!": "{0.03->1.35}机器人来了!", + "{0.00->1.21}The Esker system": "{0.00->1.21}艾斯克尔星系", + "{0.00->1.21}Requesting walker.": "{0.00->1.21}请求步行机甲。", + "{0.11->3.11}Burn in the fires of Democracy!": "{0.11->3.11}滚烫的民主!", + "{0.00->1.95}Time to feel the might of Super Earth.": "{0.00->2.09}准备接受超级地球的制裁吧!", + "{0.00->1.07}The bugs are coming!": "{0.00->1.07}虫族来了!", + "{0.08->1.80}Calling down objective equipment.": "{0.08->1.51}呼叫目标所需装备。", + "{0.00->1.47}Keep up the pressure, Helldiver.": "{0.00->1.78}绝地潜兵,继续施压。", + "{0.02->2.83}Sweet, sweet Liberty...!": "{0.02->2.83}解放,解放救救我!", + "{0.09->7.75}The call of the Void preys upon those whose loyalty is weak. Those of us who are steadfast in our{7.75->10.21}conviction need not fear.": "{0.09->4.69}寂域的召唤专找那些不够忠诚的人。{5.40->10.67}我们这些信念坚定的人根本无需恐惧。", + "{0.01->1.53}Should be taking notes.": "{0.00->1.61}我应该做做笔记。", + "{0.00->1.20}Nice job, rookies.": "{0.00->1.30}干得漂亮,菜鸟们。", + "{0.02->0.84}One day,{1.21->3.81}I'll have your phalangeal dexterity.": "{0.00->3.69}总有一天,我手指也能像你一样灵活。", + "{0.00->0.63}Fall back!": "{0.00->0.63}撤退!", + "{0.00->1.64}Another diver for the cause.": "{0.00->1.81}为解放大业前赴后继。", + "{0.06->1.13}Have no fear! {1.52->3.49}Helldivers always know what they're doing!": "{0.06->0.70}别怕!{0.88->3.21}绝地潜兵心里有数!", + "{0.07->1.71}The Supercolony is gone. {2.16->4.51}Now is the time to press the attack.": "{0.07->2.15}超级拓殖地已经荡然无存。{2.38->4.51}现在正是进攻的大好时机。", + "{0.03->2.10}Hot dog! What a day!": "{0.00->2.19}热狗!美好的一天!", + "{0.00->0.92}Canister's empty.": "{0.00->0.92}燃料罐空了。", + "{0.00->0.39}Bots.": "{0.00->0.57}机器人。", + "{0.00->2.13}This is where the shuttle lands?": "{0.00->1.74}运输船真的会来吗?", + "{0.00->0.81}Bug tunnel breach.": "{0.00->0.81}虫族隧道洞口,", + "{0.00->0.51}For...{1.21->3.02}Super Earth..": "{0.00->1.45}为了……{1.75->4.20}超级地球……", + "{0.00->2.61}Crystallized E-710 acquired.": "{0.00->2.61}710元素晶体到手了。", + "{0.00->1.80}A worthy sacrifice.": "{0.00->1.45}死得其所。", + "{0.00->2.95}The Illuminate must be repelled from this planet.": "{0.00->2.95}一定要把光能者赶出这颗星球。", + "{0.02->1.34}My arm!": "{0.00->1.13}我的胳膊!", + "{0.00->2.28}Get some distance between each other.": "{0.00->2.22}互相拉开,彼此保持距离。", + "{0.00->1.18}The Reaf system": "{0.00->1.18}利夫星系", + "{0.25->2.02}I'm losing so much blood!": "{0.25->2.02}我流了好多血!", + "{0.00->2.85}Hostile threat level high. Deploying SEAF to support.": "{0.00->2.87}敌方威胁等级较高。部署武装部队支援。", + "{0.00->1.28}Last reload!": "{0.00->1.28}最后的弹药!", + "{0.01->4.14}We may be outnumbered, but we'll never be outgunned.": "{0.01->4.14}虽然我们人少,但我们火力可不少。", + "{0.02->1.29}Help over here!": "{0.00->1.32}我需要帮助!", + "{0.00->0.42}Left.": "{0.00->0.42}左边。", + "{0.05->2.26}Get away from me, bot freak!": "{0.05->2.26}铁坨子,你给我滚开!", + "{0.00->0.68}What about here?": "{0.00->0.68}这里怎么样?", + "{0.05->1.66}Get me out, get me out!": "{0.00->1.72}带我出去,带我出去!", + "{0.00->1.17}Tac-pack inbound.": "{0.00->1.17}战术背包到了。", + "{0.00->1.50}They're trying to flush us out!": "{0.00->1.50}它们想把我们赶走!", + "{0.03->1.35}We're safe now!": "{0.03->1.16}我们安全了!", + "{0.01->0.70}Illuminate!": "{0.01->0.70}光能者!", + "{0.01->1.60}Follow the Helldivers!": "{0.00->1.58}跟着绝地潜兵!", + "{0.00->0.83}Sixth one.": "{0.00->0.83}第六个。", + "{0.00->1.42}Reinforcing.": "{0.00->1.42}请求增援。", + "{0.04->3.24}Did you see that?! Best squad in the system!": "{0.00->3.41}看到了吗?本星系最强小队!", + "{0.00->1.50}Helldiver down!": "{0.00->2.33}绝地潜兵倒下了!", + "{0.00->1.10}Hostiles incoming.": "{0.00->1.10}小心,敌人来了。", + "{0.01->0.61}I've got you.": "{0.01->0.61}我来帮你。", + "{0.02->4.23}This is the largest Helldiver mobilization since the First Galactic War. {4.71->6.63}Plenty of allies we can join up with.": "{0.00->4.39}自从第一次星系战争以来,这是规模最大的绝地潜兵动员。{4.66->7.07}我们可以和许多盟友并肩作战。", + "{0.33->1.91}Clear the impact radius!": "{0.00->1.98}快离开爆炸范围!", + "{7.46->10.68}Freedom's Greetings, I'm Coretta Kelly.{11.12->13.49}In a triumphant display of Democracy,{13.72->19.00}the Star of Peace has successfully been activated in the defense of Super Earth.{19.53->24.50}The Helldivers voted to defend our citizens by pre-emptively neutralizing a{24.50->29.76}highly threatening planet harboring known enemies of Freedom.{29.92->37.08}The space formerly occupied by the planet is now free from the Automaton's collectivist grip.{37.55->41.67}All that remains is a highly-compressed boulder-sized mass,{41.88->45.08}which is being kept under round-the-clock surveillance.{45.60->50.56}Citizens across the galaxy have been advised to celebrate the newfound{50.56->54.98}era of peace and prosperity ushered in by the Helldivers.{55.30->62.15}That's Liberty's Latest; I'm Coretta Kelly.": "{7.46->10.68}自由向各位问好,{11.12->13.49}我是科雷塔·凯利。{13.72->19.00}在民主的胜利表明,{19.53->24.50}和平之星已成功激活,{24.50->29.76}即将守卫超级地球。{29.92->37.08}绝地潜兵投票决定,{37.55->41.67}先发制人清除一颗窝藏自由之敌的高威胁星球来保卫我们的公民。{41.88->45.08}原先被该星球占据的空间现已摆脱机器人的集体掌控。{45.60->50.56}建议全银河系的公民共同庆祝绝地潜兵辛勤打拼得来的和平繁荣新时代。{50.56->54.98}以上就是今天的《解放新闻》,{55.30->62.15}我是科雷塔·凯利。", + "{0.00->2.47}You must not allow our civilians to perish.": "{0.00->2.47}尽全力保护公民的生命财产。", + "{0.00->0.95}Tactical impediment.": "{0.00->0.95}战术障碍,", + "{0.00->4.72}Excuse me...please try to minimize damage to the training facility when using grenades.": "{0.00->2.22}不好意思…投掷手雷时,{2.26->4.70}请尽量减少对训练设施造成损伤。", + "{0.00->2.07}Managed Democracy in action!": "{0.00->1.64}这就是管理式民主!", + "{0.07->2.69}Ugh... requesting stims...": "{0.00->2.82}呃……请求治疗剂……", + "{0.40->0.70}We're here!": "{0.00->0.70}我们来了!", + "{0.00->1.52}The Kelvinor system": "{0.00->1.52}开尔文奥尔星系", + "{0.09->5.31}Danny was so excited. What secret could be even BIGGER than everything he already knew?": "{0.09->5.31}丹尼很兴奋。是什么样的秘密能胜过他已经知道的东西呢?", + "{0.00->1.87}The Gemstone Bluffs system": "{0.00->1.87}宝石崖星系", + "{0.05->3.19}Stand firm! Liberty never yields!": "{0.00->3.08}稳住!解放永不屈服!", + "{0.00->4.38}Liber-tees. Casual wear for serious patriots.": "{0.00->4.38}解放T恤,衣着随性,爱国在心。", + "{0.03->3.04}Lady Liberty, let me survive this...": "{0.00->3.09}自由女神啊,保佑我活下去……", + "{0.03->1.51}I always knew you'd come.": "{0.03->1.51}我一直坚信你们会来。", + "{0.03->1.07}It's really them!": "{0.03->1.07}他们真的来了!", + "{0.00->5.60}Still have a lot of liberating to get to? Buy a six-pack of Freedom Juice, with an all-new,{5.70->7.32}extra-potent formula.": "{0.00->2.06}还有很多解放任务没做完?{2.81->4.99}买一提6罐装的“自由能量”吧,{5.42->7.71}全新配方,强效提神。", + "{0.03->4.19}We're gonna melt 'em down and turn 'em into guns, then liberate 'em with their own corpses. {4.82->5.54}Freeah!": "{0.00->4.27}我们要把它们熔化,做成枪炮,然后用它们的尸体解放它们。{4.64->5.54}敬自由!", + "{0.04->1.28}What are they?": "{0.04->1.51}是什么东西?", + "{0.00->1.12}The K system": "{0.00->1.12}K星系", + "{0.00->2.10}I need stims!": "{0.00->2.10}快给我来一针!", + "{0.00->0.79}Enemy patrol.": "{0.00->0.79}敌方巡逻队,", + "{0.00->1.93}They gave their lives,{2.18->6.19} that thegalaxy may be spared the tyranny of the Cyborgs.": "{0.00->1.57}他们献出了生命,{1.89->6.16}让银河系能够免受生化人的暴政统治。", + "{0.01->2.86}You have so many Votes left to give!": "{0.01->2.86}你还有好多票没投呢!", + "{0.00->0.25}Have a taste of Democracy!": "{0.00->2.45}尝尝民主的滋味儿!", + "{0.00->0.52}Third one.": "{0.00->0.52}第三个。", + "{0.01->2.68}DEMOCRACY FOR EVERYONE!!": "{0.01->2.68}恭迎民主!", + "{0.00->0.30}Enemy outpost spotted. Look alive.": "{0.00->2.01}是敌方哨站,小心有敌人。", + "{0.01->1.82}Proof of our resolve!": "{0.01->1.82}证明我们的决心!", + "{0.00->1.98}The power of Democracy!": "{0.00->1.47}这是民主之力!", + "{0.00->1.04}Calling down a vehicle.": "{0.00->1.04}请求载具支援。", + "{0.00->0.76}This is it.": "{0.00->0.76}就是这里。", + "{0.00->1.32}The Hellmire system": "{0.00->1.32}海尔迈尔星系", + "{0.00->2.70}Tell that to the 27 dead patriots and their families.": "{0.00->2.76}跟遇难的27名爱国者和他们的家人说去吧。", + "{0.01->1.98}Not like this! Don't give up!": "{0.01->1.86}能行的!别放弃!", + "{0.00->1.30}Last reload!": "{0.00->1.30}最后的弹药!", + "{0.03->1.61}They're disgusting!": "{0.03->1.61}真是恶心死了!", + "{0.02->4.79}Make them pay.": "{1.69->4.79}让他们付出代价。", + "{0.00->1.12}Inputting drop point.": "{0.00->1.12}确定降落地点。", + "{0.02->1.05}Keep them back!": "{0.02->1.05}挡住它们!", + "{0.00->1.27}Deploying Support Weapon": "{0.00->1.27}正在部署支援武器", + "{0.02->1.65}Democracy has landed.": "{0.02->1.65}迎接民主到来。", + "{0.00->2.15}Ready to dispense Democracy.": "{0.00->2.15}准备好传播民主了。", + "{0.00->0.54}Hellbomb.": "{0.00->0.54}地狱火炸弹,", + "{0.02->0.75}Illuminate!": "{0.02->0.75}光能者!", + "{0.00->2.78}Recruit expired. Reset battlefield simulator.": "{0.00->2.78}新兵死亡。重置模拟战场。", + "{0.00->0.93}We knew you'd come!": "{0.00->0.93}就知道你们会来!", + "{0.04->1.95}FTL jump successful.": "{0.04->1.95}超光速跃迁成功。", + "{0.00->5.06}I hear a new voting algorithm is coming soon. Supposed to have even better candidate selection than {5.06->5.84}the current one, {6.24->7.18}if you can believe it.": "{0.00->2.54}我听说即将推出新的投票算法。{2.84->6.35}据说推举候选人的效果比现在的算法还要好,{6.62->7.69}信不信由你。", + "{0.02->1.06}Battery's drained!": "{0.02->1.06}电池没电了!", + "{7.53->10.41}Freedom's Greetings; I'm Coretta Kelly.{11.13->14.11}Strange new activity on the Illuminate frontlines.{14.55->23.65}Towers raised from ancient Illuminate ruins appear to be causing massive atmospheric disturbances known as \"Exostorms.\"{24.16->29.48}The Exostorms are believed to be only a side effect of the Exospire activity.{29.96->39.54}Ministry of Science astronomers have observed gravitational \"wobbles\" between planets with Exospires—evidence of some sort of connection.{39.90->44.02}The Helldivers have been deployed to interdict the Illuminate{44.02->48.17}activity and prevent the construction of more Exospires.{48.68->52.22}That's Liberty's Latest; I'm Coretta Kelly.": "{7.39->10.37}自由向各位问好,我是科雷塔·凯利。{10.96->13.99}光能者前线出现诡异新动向。{14.54->17.53}从古老的光能者废墟中升起的高塔{17.94->22.74}似乎正在引发名为“异界风暴”的大规模大气扰动。{24.17->29.17}据信异界风暴只是异界尖塔活动产生的副作用。{29.90->34.19}科学部天文学家观测到建造了异界尖塔的星球之间{34.53->39.51}出现引力“颤动”现象,证明它们之间存在某种联系。{40.49->44.51}绝地潜兵已部署完毕,即将消灭光能者的活动,{44.92->47.92}阻止它们建造更多异界尖塔。{48.69->52.25}以上就是今天的《解放新闻》,我是科雷塔·凯利。", + "{0.00->0.67}Eyes up!": "{0.00->0.84}保持警觉!", + "{0.05->4.29}It will be an arduous campaign to reach Cyberstan. {4.67->10.50}It is the nexus of the Automaton Legion; resistance will be fierce.": "{0.05->3.61}进军生化斯坦将是一场恶战。{4.52->10.20}那里是机器人军团的核心中枢,抵抗势必会很激烈。", + "{0.00->0.73}Let's get 'em!": "{0.00->0.89}把它们干掉!", + "{0.00->1.68}Can't wait to see this go off.": "{0.00->1.68}等不及看它爆炸了。", + "{0.00->2.08}Love that. I LOVE that.": "{0.00->2.12}喜欢这个。爱死了。", + "{0.02->1.52}Protect the children!": "{0.02->1.52}保护孩子!", + "{0.01->2.86}Duty! Fealty! Obedience!": "{0.01->2.86}使命!忠诚!服从!", + "{0.11->1.31}That's why they're the best!": "{0.11->1.31}他们是最棒的!", + "{0.01->0.65}Bug hive!": "{0.01->0.65}有虫窝!", + "{0.00->0.36}Me? {1.01->5.68}I'm the Shipmaster of this Super Destroyer. I make sure you have everything you need to spread {5.68->7.52}Managed Democracy to our enemies.": "{0.00->0.83}我?{1.34->3.47}我是这艘超级驱逐舰的舰长,{3.79->7.52}负责提供传播管理式民主所需的一切资源和装备。", + "{0.00->1.59}They won't like this one bit.": "{0.00->2.12}它们绝对不会喜欢这个。", + "{0.04->3.23}Restoring the natural order AND the will of the people!": "{0.00->3.51}重树天然秩序,顺应人民意志!", + "{0.00->3.04}They were handed freedom, and chose to spit in its face. {3.50->4.71}Death is too good for them.": "{0.00->2.78}他们有机会获得自由,却选择了唾弃自由。{3.13->4.71}直接干掉都算是便宜他们了。", + "{0.00->3.19}Let's show those sons o' dissidents who's boss!": "{0.00->3.30}让异见分子杂种看看谁才是老大!", + "{0.00->1.19}This is the objective.": "{0.00->1.19}这就是目标。", + "{0.00->0.48}Danger.": "{0.00->0.48}危险,", + "{0.01->1.14}Stick together!": "{0.00->1.15}全体保持队形!", + "{0.02->0.61}That one.": "{0.02->0.61}那个。", + "{0.00->1.86}The Mandilaria System": "{0.00->1.54}曼迪拉里亚星系", + "{0.02->1.01}The bots are back!": "{0.02->1.25}机器人回来了!", + "{0.00->2.55}The city was once a center of commerce.{3.05->5.37}Now, it is a center of Tyranny.": "{0.00->2.55}这座城市曾是商业中心。{3.05->5.74}现在变成了暴政中心。", + "{0.00->0.32}Well,{1.02->4.69}if they had just realized that their ideology was inferior sooner,{5.26->7.29}they could have saved themselves a lot of bombings.": "{0.00->2.40}我想说,要是它们早点意识到{2.44->6.79}自己的意识形态有多低劣,就能免受这么多轰炸了。", + "{0.00->1.49}Just a temporary...{2.21->3.73}setback...": "{0.00->2.32}一时失利…{3.17->4.96}罢了…", + "{0.00->0.95}Where did that come from!?": "{0.00->0.95}那是从哪来的!?", + "{0.09->1.08}Thank Liberty!": "{0.09->1.08}感谢解放!", + "{0.00->1.63}I wish I could do what you do.": "{0.00->1.14}真想像你们一样。", + "{0.00->6.96}Senator John Killjoy Jr. declares: \"The Illuminate are back, and they bring with them the threat of {6.96->12.70}total annihilation. Which is why I say, let us annihilate them first!\"": "{0.00->5.03}参议员小约翰·克乔伊宣布:“光能者回来了,{5.18->8.55}它们来势汹汹,意图消灭人类。{9.03->12.59}因此,我们必须先下手为强!”", + "{0.05->1.71}Kill 'em all, soldiers!": "{0.00->1.68}战士们,杀光它们!", + "{0.00->0.93}Manned emplacement.": "{0.00->0.93}敌方炮位,", + "{0.24->0.94}I'm sorry!{1.54->4.53}I will report myself to re-education!": "{0.63->3.21}抱歉!我会主动申请{3.21->4.74}接受再教育!", + "{0.03->3.33}We got mines here! 'Course we got mines here.": "{0.00->1.56}这儿有地雷!{1.57->3.39}这儿明摆着有地雷!", + "{0.05->1.39}They're coming soon, right?": "{0.05->1.39}他们快到了,对吗?", + "{0.00->2.76}The enemy may anticipate but one outcome: {3.44->4.84}total annihilation.": "{0.00->2.76}敌人只能预料到一个结果,{3.44->5.19}也就是彻底覆灭。", + "{0.01->1.44}Citizen down!": "{0.68->1.83}公民倒下了!", + "{0.01->0.61}Third one.": "{0.00->0.54}第三个。", + "{0.00->2.46}Innocents perish with every wasted second. {2.92->3.63}We must act.": "{0.00->2.45}每浪费一秒,都会有无辜的人丧命。{2.73->3.65}立即行动。", + "{0.05->7.46}Horrors lurk, Helldiver. You are all that stand between them and our children.": "{0.00->2.43}危险都潜伏在暗处。{2.43->7.47}而你们是架在敌人与孩子们之间的唯一防线。", + "{0.00->0.21}Up.": "{0.00->0.40}上方。", + "{0.01->1.81}I don't think I can do that.": "{0.01->1.81}我这边过不去。", + "{0.01->3.46}It can't be! Helldiver down!": "{0.01->3.46}不可能!绝地潜兵倒下了!", + "{0.00->0.75}Support weapon.": "{0.00->0.75}支援武器,", + "{0.00->0.38}Move.": "{0.00->0.38}走。", + "{0.03->0.97}I'm pinned!": "{0.00->1.04}遭到压制!", + "{0.00->1.66}We will avenge you!!": "{0.00->1.66}我们一定会为你报仇!!", + "{0.05->1.90}Rounds on target, soldiers!": "{0.05->1.90}战士们,向目标射击!", + "{0.03->1.65}Terminids! Run!": "{0.03->1.82}终结族!快跑!", + "{7.82->10.87}Freedom's Greetings, I'm Coretta Kelly.{11.44->17.54}Discoveries in the mines of Cyberstan have shed light on the origin of the Automatons.{18.24->25.48}Recovered prototypes indicate the Automatons were developed in secret by the Cyborgs during their rehabilitation.{26.07->34.94}Worse, they derived Automaton prototypes from mining drones that were generously provided to aid in their restorative labor.{35.58->37.31}Then, as we know,{37.63->50.49}the Automaton prototypes were shipped off-planet in a stolen spacecraft known as \"Vessel 00.\" The destination of that vessel remains unknown.{51.32->54.83}That's Liberty's Latest; I'm Coretta Kelly.": "{7.78->10.63}自由向各位问好,我是科雷塔·凯利。{11.34->13.60}根据生化斯坦矿区的最新发现,{14.02->17.22}我们终于揭开了机器人的起源之谜。{18.26->19.58}回收的原型机显示,{20.02->25.24}这些机器人实际上是生化人在之前的改造期间秘密开发的。{26.06->26.90}更糟糕的是,{27.30->31.52}人类慷慨地给它们提供了采矿无人机,帮助它们恢复生产,{31.89->35.48}它们却利用这些无人机造出了机器人原型机。{35.97->38.96}据我们所知,生化人将机器人原型机{39.15->44.79}装载到名为“00号舰船”的被盗飞行器中,然后运离了星球。{46.06->49.96}而那艘舰船的目的地至今仍然未知。{51.23->54.98}以上就是今天的《解放新闻》,我是科雷塔·凯利。", + "{0.00->1.38}Democracy has landed.": "{0.00->1.38}迎接民主到来。", + "{0.00->2.75}Gah! No, this can't--": "{0.00->2.78}呃!不可能,不可能——", + "{0.08->1.63}The city is freed.": "{0.08->1.63}城市获得了解放。", + "{0.00->1.86}We're glad you're here, Helldiver.": "{0.00->2.46}绝地潜兵,还好有你在。", + "{0.00->0.86}You're free now.": "{0.00->0.93}你自由了。", + "{0.00->1.28}Target destroyed.": "{0.00->1.28}已摧毁目标。", + "{0.02->1.50}It's gonna eat me!": "{0.02->1.50}它要把我吃了!", + "{0.00->1.88}Much appreciated, Helldiver.": "{0.00->1.91}感激不尽,绝地潜兵。", + "{0.01->1.52}That was awesome!": "{0.01->1.69}太精彩了!", + "{1.92->5.25}The Automatons should have been content with what they had. {5.92->11.88}Instead, they tried to take for themselves what the citizens of Super Earth had proudly built. {13.24->17.53}Now, they're going to find out just how hard every man, woman,{17.55->20.90}and child over 7 will work to stop them. {22.16->23.39}Do your part: {23.89->25.22}get to work!": "{1.79->5.25}机器人本应恪守本分,安分服从。{5.92->9.92}然而如今,它们妄图窃取由超级地球无数公民{10.06->11.76}辛勤建起的一切。{13.24->16.62}现在,它们将会明白:所有的男女老少,{16.73->20.90}包括七岁以上的优秀儿童,都会恪尽职守,阻止他们。{22.40->25.22}履行你的职责:认真工作!", + "{0.16->0.84}100 meters.": "{0.16->0.84}100米。", + "{0.03->1.18}The tentacles!": "{0.03->1.18}是触手!", + "{1.45->3.78}How bad is it?": "{0.18->4.96}我还有救吗?", + "{0.00->0.54}East.": "{0.00->0.54}东边,", + "{0.00->4.50}The bots are proof that if you put enough 1s and 0s together, you can threaten the entire galaxy.": "{0.00->5.20}机器人的存在证明了,只要组合足够多的1和0,就能威胁整个银河系。", + "{0.00->5.05}Helldivers rally to expel the bots from this world. Will you join them?": "{0.00->5.05}绝地潜兵誓要将机器人彻底逐出这颗星球。你要一起来吗?", + "{0.02->4.42}If I had all the Super Credits in the galaxy, I'd try to find some way to convince our enemies to {4.42->5.20}embrace Freedom.": "{0.02->2.37}如果我有银河系中所有的超级货币,{2.77->5.20}我会想办法说服敌人拥抱自由。", + "{0.02->2.21}I wish I could kill 'em again.": "{0.02->2.21}真希望能再杀一次。", + "{0.03->1.93}Crystallized E-710 acquired.": "{0.03->1.93}710元素晶体到手了。", + "{0.08->1.52}The Almina System": "{0.08->1.32}阿尔米纳星系", + "{0.02->1.94}Compliments of Super Earth!": "{0.00->2.09}向超级地球致敬!", + "{0.02->1.10}Last reload.": "{0.02->1.10}最后的弹药。", + "{0.00->1.86}Flag-forsaken robot.": "{0.00->1.75}一堆废铜烂铁。", + "{1.09->4.87}I'll be fine...the Helldivers are here...": "{0.00->4.87}我…我没事…绝地潜兵来了…", + "{0.00->0.46}Bravo": "{0.00->0.46}B", + "{0.00->2.31}You're my oil now, bug.": "{0.00->2.31}今晚来点炸虫子。", + "{0.00->0.56}Right away!": "{0.00->0.77}马上就去!", + "{0.00->1.47}The Karon Bay system": "{0.00->1.47}凯伦湾星系", + "{0.00->1.34}Mission is progressing.": "{0.00->1.34}推进任务进度。", + "{0.02->1.36}The Curia system": "{0.02->1.36}居里亚星系", + "{0.00->0.95}I need supplies!": "{0.00->0.95}需要补给!", + "{0.00->0.96}Watch your step!!": "{0.00->1.17}当心脚下!!", + "{0.04->8.14}The Void has changed this planet. Into something...un-Democratic.": "{0.00->3.00}寂域改变了这颗星球。{3.00->5.45}成为某种……{6.00->8.18}反民主的存在。", + "{0.04->2.58}You are a paragon of Liberty.": "{0.04->2.47}你是解放的最佳楷模。", + "{0.00->0.63}Helldiver. {1.17->2.43}Glad to have you on board.": "{0.00->0.96}绝地潜兵,{1.43->2.43}欢迎你登舰。", + "{0.00->0.57}Will do!": "{0.00->0.57}好的!", + "{0.07->2.95}Fan out, we're fanning out, just like at training.": "{0.00->3.09}散开,摆开阵型,就像训练时那样。", + "{0.00->0.74}Hold Position.": "{0.00->0.74}原地待命。", + "{0.00->6.07}Freedom triumphs over tyranny once more. The extraction shuttle awaits your request.": "{0.00->2.41}自由再次战胜暴政,{3.18->6.07}撤离运输船等待你的指令。", + "{0.87->2.09}Bring it on, Fascists!": "{0.00->2.27}来啊,法西斯怪物!", + "{0.00->3.19}The Justice this baby's gonna dish out...": "{0.00->3.46}这大宝贝儿一定能执行正义…", + "{0.00->0.80}Remember:{1.53->4.03}Illuminate knowledge is dirty,{4.51->5.44}treasonous,{5.81->6.95}and false.": "{0.00->4.18}切记:光能者的知识不仅肮脏、{4.51->5.44}叛逆,{5.81->6.95}还虚假。", + "{0.00->2.01}Out of my way!": "{1.21->2.01}别挡路!", + "{0.03->1.29}Prepare for demolition.": "{0.00->1.29}做好爆破准备。", + "{0.03->1.36}Don't let 'em get away!": "{0.00->1.45}别让它们跑了!", + "{0.04->0.80}4!": "{0.04->0.80}四!", + "{1.53->4.44}Take position. Guard this ground like you'd guard your back yard!": "{0.00->1.34}各就各位。{1.34->4.51}人可以丢,这块地绝不能丢!", + "{0.03->0.87}They're coming!": "{0.03->0.87}它们来了!", + "{0.01->1.49}Low and steady, people!": "{0.01->1.49}大家都躲好了!", + "{0.00->1.49}The Darius system": "{0.00->1.49}大流士星系", + "{0.00->0.58}Sentry.": "{0.00->0.58}哨戒炮,", + "{0.03->0.37}Ah, {1.09->4.60}the will of Democracy. Good work!": "{0.03->0.90}啊,{1.09->4.60}贯彻民主的意志。干得好!", + "{0.05->2.81}You are all that stands between Freedom {3.35->4.49}and Tyranny.": "{0.05->0.71}此刻,{1.00->4.19}你们就站在自由抵抗暴政的最前线。", + "{0.00->1.48}The Ubanea system": "{0.00->1.48}乌巴尼亚星系", + "{0.01->1.20}Calling down supplies.": "{0.01->1.20}呼叫补给。", + "{0.00->0.75}Medic!": "{0.00->0.75}医疗兵!", + "{0.00->1.13}Good work down there.{1.52->4.34}They'll regret trespassing into our cities.": "{0.00->0.93}干得不错。{1.38->3.78}它们会后悔入侵我们的城市。", + "{0.03->1.83}That was one for the record books. {2.25->4.43}Where all missions are logged for analysis.": "{0.03->1.83}可以把这次任务载入记录了,{2.25->4.43}和所有的任务一起拿去分析。", + "{0.01->0.75}Take cover!": "{0.01->0.75}快找掩体!", + "{0.04->1.83}Slimy freaks!": "{0.04->1.83}黏了吧唧的玩意儿!", + "{0.00->2.58}Helldivers! We're gonna make it!": "{0.00->2.88}绝地潜兵!我们会没事的!", + "{0.00->1.91}Here comes JUSTICE!": "{0.00->1.44}正义来了!", + "{0.00->1.95}A reward for our righteous efforts.": "{0.00->1.95}奖励我们的正义之举。", + "{0.02->1.41}Don't let'em get me!": "{0.00->1.57}别让它们抓到我!", + "{0.02->1.50}Kill it! Destroy it!": "{0.02->1.50}快杀了它!杀了它!", + "{0.14->0.94}We made it!": "{0.14->0.94}成功了!", + "{0.00->0.71}50 meters.": "{0.00->0.51}50米。", + "{0.00->0.66}Enemy elite.": "{0.00->0.66}敌方精英,", + "{0.00->1.62}The Shirahama System": "{0.00->1.17}白滨星系", + "{0.01->1.22}Everyone into cover!": "{0.00->1.28}所有人进掩体!", + "{0.00->2.75}Super Earth really is the best place to live in the entire galaxy, isn't it?": "{0.00->3.07}超级地球真是整个银河系最宜居的地方,对吧?", + "{0.02->0.46}Hide,{1.65->2.14}hide!": "{0.00->2.27}躲起来,躲起来!", + "{0.00->4.69}The Cyborgs have spread their Megafactories across this world.": "{0.00->4.69}这个星球已经遍布生化人的超大型工厂。", + "{0.00->1.05}Changing course --{1.55->2.66}betters our Cause.": "{0.00->1.05}改变方向…{1.55->2.66}最好是解放的方向。", + "{0.00->2.49}I love y--- Super Earth,{2.89->4.15}I love Super Earth.": "{0.00->2.58}我爱——超级地球,{2.59->4.24}我爱超级地球。", + "{0.03->1.24}Throwing supply beacon.": "{0.03->1.24}投掷补给信标。", + "{0.00->1.30}Mines in the ground!": "{0.00->1.23}地下有雷!", + "{0.00->0.95}Can't take that for granted.": "{0.00->1.14}这可不是理所当然。", + "{0.00->3.50}The Cyborgs are spreading their Megafactories are all over the place.{3.95->7.95}We can't allow them to stain the face of our beautifully urbanized galaxy.": "{0.00->2.45}生化人到处扩建超大型工厂。{3.01->6.31}绝不能让它们玷污我们美丽城市化星系的面貌。", + "{0.03->1.91}Get away from me, bot freak!": "{0.03->1.91}大铁块儿,滚远点儿!", + "{0.04->2.03}Requesting stim!": "{0.00->2.21}请求治疗剂!", + "{0.00->1.67}A fast mission is a good mission.": "{0.00->1.83}速度快就是干得好。", + "{0.03->1.18}Everyone into cover!": "{0.00->1.32}所有人进掩体!", + "{0.03->2.20}Agh! Lookout—mines!": "{0.00->2.21}啊!当心——地雷!", + "{0.00->0.95}I need supplies.": "{0.00->0.95}给我来点补给。", + "{0.02->0.96}The bots are back!": "{0.02->0.96}机器人回来了!", + "{0.08->2.09}We're all going to die!": "{0.08->2.09}我们都死定了!", + "{0.01->1.23}Hold your ground!": "{0.01->1.23}不要退缩!", + "{0.00->0.90}Tactical benefit.": "{0.00->0.61}战术助力,", + "{0.06->4.61}In all my years, I've never witnessed such acrobatic perfection. {5.13->9.62}I think you're ready for our highly realistic battlefield simulator. {10.01->10.75}That's right—{11.16->12.38}the real deal.": "{0.06->4.61}这么多年以来,我从未见过如此完美的动作。{5.13->9.62}你应该已经准备好接受高度写真的战场模拟训练了。{10.01->10.75}没错,{11.16->12.38}真正的挑战。", + "{0.03->0.74}Will do!": "{0.03->0.74}好的!", + "{0.00->0.69}Did you see that?{1.47->3.07}They touched my hand!": "{0.00->0.69}你看到了吗?{1.47->3.07}他们跟我握手了!", + "{0.00->1.48}The Nascence System": "{0.00->1.08}太初星系", + "{0.00->1.05}Without more samples, {1.69->4.95}this ship will continue to operate at sub-optimal effectiveness.": "{0.00->1.05}没有足够的样本,{1.66->4.51}这艘舰船就不能以最高效率运行。", + "{0.00->1.43}The Wile System": "{0.00->1.26}千惑星系", + "{0.02->1.54}Democracy has landed.": "{0.02->1.54}迎接民主到来。", + "{0.00->2.68}The hearts of Super Earth beat as one.": "{0.00->2.73}我们的心在超级地球一起跳动。", + "{0.00->5.87}The bugs are attempting to convert our worlds into swarming hives of fascism. {6.37->7.22}Will you let them? {7.80->9.67}Or will you join the fight?": "{0.00->2.39}虫族要将我们的世界{2.65->5.71}变成繁殖法西斯主义的“虫巢”。{6.37->7.70}你会坐视不理,{8.22->9.88}还是奋起反抗?", + "{0.13->4.12}We have long realized the twisted nature of the Illuminate Cult, {4.57->8.35}but to mutate loyal citizens into enemies of Freedom...{9.13->11.47}an atrocity beyond imagining.": "{0.00->3.85}我们早已认清光能者这群异端的扭曲本质,{4.28->8.39}但是,把忠诚的公民变异成自由的敌人…{9.02->11.47}这种暴行超乎想象。", + "{0.04->1.89}SOS!": "{0.04->1.89}帮帮我!", + "{0.00->0.72}Once again...{1.08->4.89}please avoid deploying grenades outside of designated combat areas.": "{0.00->0.99}再次提醒…{1.38->4.45}请勿将手雷丢出指定的战斗区域。", + "{0.05->0.40}Done.": "{0.05->0.40}搞定。", + "{0.00->2.29}Choose where to make your stand.": "{0.00->2.01}选择你的战场吧。", + "{0.00->0.63}Out of ammo.": "{0.00->0.63}没弹药了。", + "{0.00->1.95}Democracy shields us!": "{0.00->2.31}民主保佑!", + "{0.00->4.68}We must tear free our galaxy from the affliction of bug and bot alike.": "{0.00->4.86}一定要阻止虫子和机器人继续折磨银河系。", + "{0.02->1.37}Move, move!": "{0.00->1.50}前进,前进!", + "{0.07->5.75}Hey Helldiver, did you hear? Tanks are back in production! Real tanks!": "{0.00->1.80}嘿,绝地潜兵,你听说了吗?{2.41->5.57}坦克重新投产了!是真正的坦克哦!", + "{0.00->2.04}So that's the smell of Liberty...": "{0.00->2.10}这就是自由的温度……", + "{0.00->1.00}A failed mission. {1.38->2.48}But we won't give up.": "{0.00->0.79}任务失败。{1.12->2.57}但是我们不会放弃。", + "{0.00->1.51}Calling in a Hellbomb.": "{0.00->1.51}呼叫地狱火炸弹。", + "{0.02->0.89}Target reached.": "{0.02->0.89}抵达目标。", + "{0.00->1.48}Reloading support weapon.": "{0.00->1.48}在给支援武器换弹。", + "{0.00->0.72}Absolutely!": "{0.00->0.72}没有问题!", + "{0.01->1.89}Don't stop! Go!": "{0.01->1.89}不要停!走!", + "{0.03->2.89}We claim this land in the name of Democracy!": "{0.00->2.98}我们代表民主接管这片土地!", + "{0.00->1.19}No-one escapes the flames of{1.82->2.44}Justice!": "{0.00->2.06}没人能逃过正义之火!", + "{1.02->1.81}We're together out here,{2.21->2.68}right?": "{0.00->3.03}我们是并肩的战友,对吗?", + "{0.00->2.48}New canister for maximum Liberation.": "{0.00->2.48}新燃料罐,全力实现解放。", + "{0.02->0.54}Illuminate.": "{0.02->0.54}光能者。", + "{0.00->1.33}Should we be farther away?": "{0.00->1.50}我们要不要离远一点?", + "{0.00->3.58}Whenever the war gets me down, I try to remember that at least I'm a free citizen.{4.01->5.50}It's up to me how I serve Super Earth.": "{0.00->3.58}每当战事闹心,我都会试着想,至少我是个自由的公民,{4.01->6.02}我能自己决定怎么服务超级地球。", + "{0.01->0.56}No!": "{0.01->0.56}不!", + "{0.00->1.37}Team reload required.": "{0.00->1.07}给我来点弹药。", + "{0.03->2.44}Time for our slice of glory!": "{0.00->2.57}建功立业的时候到了!", + "{0.01->1.58}There! They found us!": "{0.00->1.80}那边!我们暴露了!", + "{0.10->5.20}Those changed by the Illuminate have lost something deeper than their humanity. {5.99->9.13}Their very citizenship has been consumed, {9.58->12.50}condemning them to a fate worse than death. {13.23->15.48}They are Voteless.": "{0.00->6.96}被光能者转化的人,不仅失去了人性,还有更深层次的东西。{7.67->10.10}他们还会失去公民身份,{10.30->12.92}陷入比死亡更悲惨的境地,{13.30->15.48}沦为无票者。", + "{0.00->1.22}Calling in orbital strike.": "{0.00->1.22}请求轨道攻击支援。", + "{0.01->1.28}It's the Illuminate!": "{0.01->1.05}光能者来了!", + "{0.00->1.46}High-value sample collected.": "{0.00->1.46}高价值样本到手了。", + "{6.74->10.18}Freedom's Greetings, I'm Coretta Kelly.{10.62->17.80}Today, citizens celebrate in response to reports of the first-ever reduction in Gloom spores.{18.66->25.32}Helldivers deployed on a Terminid \"Hive World\" destroyed subterranean Gloom-producing bodies across the planet,{25.45->30.59}leading to a reduction in spore density in the surrounding star system.{31.58->35.32}This marks an auspicious beginning to the Great Expedition.{35.75->46.97}Though much of the Gloom remains, a Ministry of Defense spokesperson expressed confidence that the Gloom could be fully dissipated as early as the end of the month.{47.35->52.06}In other news: Recent reports cast doubt on the theory of swarm{52.07->56.23}intelligence as ants fail to solve simple puzzles.{56.94->61.12}That's Liberty's Latest; I'm Coretta Kelly.": "{6.74->10.18}自由向各位问好,{10.62->17.80}我是科雷塔·凯利。今日,{18.66->25.32}公民为阴霾孢子首次削减的报告而欢庆。{25.45->30.59}部署在终结族“虫窝世界”的绝地潜兵摧毁了全星球的地下阴霾孕生体,{31.58->35.32}周围星系的孢子密度得以降低。这是大远征的良好开端。尽管“阴霾”大部分仍然存在,{35.75->46.97}国防部发言人仍表示有信心最早在本月底彻底消除“阴霾”。另一方面:最新报告对群体智慧理论提出质疑,{47.35->52.06}表示蚂蚁无法解决简单谜题。{52.07->56.23}以上就是今天的《解放新闻》,{56.94->61.12}我是科雷塔·凯利。", + "{0.00->1.60}Hellpod launch suspended.": "{0.00->1.60}暂停发射喷射舱。", + "{0.00->2.55}Nice to look back and know you were helping keep everyone safe, {2.97->3.94}even if you didn't know it.": "{0.00->2.98}虽然当时还不懂,但已经开始保护所有人的安全了,{3.31->3.94}这感觉真好。", + "{2.47->3.18}Ugh, robots...{3.72->4.80}they can't be trusted.": "{1.08->2.13}机器人,{2.44->4.69}呸…不值得信任。", + "{0.00->1.64}Hellpod launch initiated.": "{0.00->1.64}开始发射喷射舱。", + "{0.42->2.35}This is what'll get us on playing cards!": "{0.00->2.45}赢了我们就能在卡牌上露脸了!", + "{0.03->0.95}I've got this one.": "{0.03->0.95}我来操作!", + "{0.06->1.11}I'm on the gun!": "{0.00->1.23}机枪手就位!", + "{0.02->1.55}Need medical attention.": "{0.00->1.62}需要医疗援助。", + "{0.01->2.87}DEATH TO ENEMIES OF DEMOCRACY!": "{0.00->3.17}民主敌人都给我死!", + "{0.00->0.46}Heavy.": "{0.00->0.46}重型敌人,", + "{0.01->1.39}The invaders are here!": "{0.01->0.99}敌人过来了!", + "{0.02->1.80}Look out! Squids!": "{0.02->1.80}小心!鱿鱼!", + "{0.00->4.95}The Galactic War. A battleground awaiting your heroic intervention.": "{0.00->4.95}星系战争,这片战场正在等着你大杀四方。", + "{0.00->0.95}Automaton": "{0.00->0.95}机器人", + "{0.01->1.47}Prepare for contact!": "{0.01->1.08}准备交战!", + "{0.02->1.35}Helldiver's got it!": "{0.00->1.37}绝地潜兵成功了!", + "{0.31->0.63}This is {1.22->1.59}crazy!": "{0.00->1.60}太可怕了!", + "{0.00->1.16}Legendarium acquired.": "{0.00->1.16}传说矿物到手了。", + "{0.00->1.77}Never seen anything like it.": "{0.00->1.89}我真是开了眼了。", + "{0.00->0.25}Let the light of Liberty shine!": "{0.00->2.00}解放照亮大地!", + "{0.01->0.93}Bug outpost!": "{0.01->0.93}虫族哨站!", + "{0.02->2.73}Come on, Lady Liberty's watching!": "{0.00->2.68}振作,自由女神看着我们呢!", + "{0.03->1.85}Democracy save me!": "{0.03->2.12}求求民主显灵!", + "{0.00->1.34}The Bashyr system": "{0.00->1.34}巴希尔星系", + "{0.07->3.51}And the Bugs are sort of like if...bugs got into one of these machines.{3.51->5.90}The only thing to do would be to exterminate them.": "{0.07->3.51}而虫族有点像是…爬进这些机器里的虫子。{4.18->5.90}只要把它们消灭干净就行了。", + "{0.03->0.90}They're coming!": "{0.03->0.90}它们来了!", + "{0.00->1.53}The Cyberstan system": "{0.00->1.53}生化斯坦星系", + "{0.03->2.07}Surrounded, I'm surrounded!": "{0.00->2.07}被包围,我被包围了!", + "{0.00->0.66}First one.": "{0.00->0.66}第一个。", + "{0.00->1.39}I always knew you'd come.": "{0.00->1.39}我一直坚信你们会来。", + "{0.01->1.31}We knew you'd come!": "{0.01->1.46}就知道你们一定会来!", + "{0.00->1.52}I fight for Super Earth.": "{0.00->1.52}为超级地球而战。", + "{0.00->3.35}We will cleanse every block of our fallen metropolis.": "{0.00->3.35}清洗这座沦陷城市的每一条街道。", + "{0.00->2.05}Extraction confirmed, SEAF coming home.": "{0.00->2.21}撤离成功,武装部队即将返航。", + "{0.01->1.87}It's just like on TV!!!": "{0.01->1.79}和电视上一模一样!", + "{0.00->1.29}Reinforcing!": "{0.00->1.29}请求增援!", + "{0.01->3.33}FREEEEEEDDDDOOOOOM!!!": "{0.01->3.33}为了自由!", + "{0.04->2.53}You saved me! Thank you!": "{0.00->2.59}你救了我!谢谢!", + "{0.00->0.86}Remember:{1.46->4.17}your enemies can never touch you,{4.70->8.24}as long as Democracy is in your heart.": "{0.00->1.37}切记:{1.82->4.18}只要心中有民主,{4.53->8.24}敌人就无法伤害你。", + "{0.00->1.05}Thank you, truly,{1.70->2.95}for taking the time to beat me.": "{0.00->2.94}谢谢你,真的,感谢你抽时间打败我。", + "{0.01->4.47}You want my Freedom? MY Freedom?! Gotta try harder than that!": "{0.00->1.59}想夺走我的自由?{1.79->3.14}我的自由?!{3.19->4.98}你得再加把劲!", + "{0.67->1.40}Incredible.": "{0.00->1.50}哇厉害。", + "{0.00->4.70}All of posterity shall either prosper in Liberty, or suffer in bondage. {5.15->7.51}That determination is our duty.": "{0.00->4.04}要么在自由中繁荣,要么在奴役中受苦。{4.51->6.72}后代的命运是我们的职责。", + "{0.00->0.64}Code is:": "{0.00->0.64}代码是:", + "{0.00->2.53}Eagle 1, leaving combat zone to resupply.": "{0.00->2.53}“飞鹰”1号离开作战区,回去补给。", + "{0.11->2.04}Sweet mother of Freedom!{2.41->4.67}Is there a finer sight than a Hellbomb?": "{0.00->1.66}自由之母在上!{2.10->5.16}还有比地狱火炸弹更美的风景吗?", + "{0.03->1.47}The Myrium system": "{0.03->1.47}梅里翁星系", + "{0.00->0.56}Fall back.": "{0.00->0.56}撤退。", + "{0.01->1.34}Last reload!": "{0.01->1.34}最后的弹药!", + "{0.16->1.81}Announcement System Test: {2.23->2.91}Freedom, {3.32->4.30}Democracy, {4.70->5.46}Liberty, {5.93->8.97}Independence, Managed Democracy. {9.63->10.77}Test complete.": "{0.00->1.81}播报系统测试:{2.13->4.40}自由、民主、{4.47->7.02}解放、独立、{7.48->9.27}管理式民主。{9.63->11.00}测试完毕。", + "{0.00->1.09}Canister's empty.": "{0.00->1.09}没燃料了。", + "{0.05->3.57}Status: Defending against Illuminate invasion. {3.99->5.68}Helldiver support requested.": "{0.00->3.26}状态:抵御光能者入侵。{3.32->5.68}请求绝地潜兵支援。", + "{0.00->0.48}Package.": "{0.00->0.52}物品,", + "{0.00->1.50}The Matar Bay system": "{0.00->1.50}玛塔星系", + "{0.01->2.23}Nothing can damage Democracy!": "{0.01->2.23}民主坚不可摧!", + "{0.00->1.11}The Weir system": "{0.00->1.11}维尔星系", + "{0.00->1.55}The Hydrobius system": "{0.00->1.55}哈卓毕亚斯星系", + "{0.00->0.61}Six.": "{0.00->0.61}六。", + "{0.00->2.88}Super Earth protect us!": "{0.00->2.88}超级地球保护我们!", + "{0.02->1.62}For Super Earth!": "{0.00->1.62}为了超级地球!", + "{0.05->0.85}This is where the shuttle lands?": "{0.05->1.25}运输船会来吗?", + "{0.00->1.45}The Genesis system": "{0.00->1.45}创世星系", + "{0.02->1.81}They're disgusting!": "{0.02->1.81}真是恶心死了!", + "{0.00->3.30}Recruit expired. Please send in the Hellpod sanitation crew.": "{0.00->3.34}新兵死亡。呼叫绝地喷射舱卫生组。", + "{0.00->1.94}Quit standing around! Go go go!": "{0.00->1.94}别再傻站着了!快走!走!", + "{0.00->1.14}Visual scan of deck...{1.57->2.13}complete.": "{0.00->1.14}视觉扫描甲板…{1.57->2.13}完毕。", + "{0.00->0.55}I'm on it.": "{0.00->0.55}我来处理。", + "{0.06->0.99}Blow it up!": "{0.00->1.06}炸了它!", + "{0.00->1.57}Demolition time.{2.16->3.33}Cool right, Helldiver?": "{0.00->1.82}该爆破了。{2.09->3.36}帅不帅,绝地潜兵?", + "{0.00->0.79}New target?{1.32->2.52}Whatever it takes.": "{0.00->0.79}有新目标?{1.32->2.52}不惜代价。", + "{0.03->2.20}Prepare for Democracy!": "{0.00->2.19}准备迎接民主吧!", + "{0.05->0.66}Helldiver. {1.22->2.95}Bring me back some squid guts.": "{0.05->0.66}绝地潜兵,{1.22->2.95}给我带点鱿鱼脑袋回来。", + "{0.01->0.52}Beacon.": "{0.01->0.52}信标,", + "{0.23->1.55}ROE: destroy.": "{0.00->1.68}一个字:干。", + "{0.00->2.17}You have no idea what that means to me.": "{0.00->2.75}你不知道这对我意义有多大。", + "{0.00->2.92}Frontline! Focus on the frontline!": "{0.00->2.73}前线!专心盯着前线!", + "{0.04->2.22}Let's kill these sons of dissidents!": "{0.00->2.13}让我们干掉这帮杂种!", + "{0.00->1.86}I knew they wouldn't abandon us.": "{0.00->1.86}我就知道他们不会抛弃我们。", + "{0.00->2.45}The planet cries out for liberation.": "{0.00->2.06}这颗星球渴望解放。", + "{0.00->0.75}At once!": "{0.00->0.75}马上!", + "{0.00->1.29}The Draupnir system": "{0.00->1.34}德罗普尼尔星系", + "{0.06->1.35}I'm never washing this hand.": "{0.06->1.35}我再也不洗手了。", + "{0.01->1.13}Let's get 'em!": "{0.00->1.23}给我等着!", + "{0.00->1.91}Reloading! Watch my six.": "{0.00->1.91}换弹!注意我身后。", + "{0.00->3.39}We will deploy as many additional soldiers as it takes{3.39->6.61}to preserve the sacred gains of our heroic fallen.": "{0.00->2.38}我们会全力调派增援,{2.76->6.61}保卫英勇牺牲的英雄取得的成果。", + "{0.00->0.75}Rolling out!": "{0.00->0.75}出发!", + "{0.00->1.25}Dropping high-value item.": "{0.01->1.29}放下高价值物品。", + "{0.00->3.01}I swear those freaks are getting stronger every day.": "{0.00->2.40}那些怪物好像变得越来越厉害了。", + "{0.03->4.49}We'll have to thank the Automatons for mining these resources for us.": "{0.03->3.47}得感谢机器人帮我们开采了这些资源。", + "{0.01->3.57}FOR SUPER EAAAAARRRTTHHHH!": "{0.01->3.57}超级地球万岁!", + "{0.03->3.88}Alert: Liberation of currently orbited planet from {4.25->6.74}Illuminate menace has ended in {7.10->8.34}temporary defeat. {8.74->12.08}Planet remains under Illuminate control.": "{0.00->7.54}通知:击退光能者威胁,解放当前星球的行动暂时失利。{7.57->12.06}该星球仍归光能者统治。", + "{0.00->2.16}They gave their lives for us!{2.32->3.52}Make it count!": "{0.00->1.35}他们为我们而死!{1.85->3.38}不要让他们白白牺牲!", + "{0.00->2.55}The torch of Freedom is passed hand to hand, {2.96->5.07}from one thawed hero to the next. {5.57->8.54}They may bear it for one hour or one minute, {8.95->12.20}but there is always another to keep it from going out.": "{0.00->1.79}自由如同火炬接力,{2.46->5.43}从一个解冻的英雄,传递给下一个。{5.95->9.74}高举火炬的时间或许只有一小时,甚至一分钟,{10.15->12.39}但自由之火不会熄灭。", + "{0.02->0.73}Dismount!": "{0.00->0.80}下来了!", + "{0.01->1.54}Reloading you!": "{0.01->1.54}帮你换弹!", + "{0.02->0.95}Bug tunnel breach!": "{0.02->0.95}虫族隧道洞口!", + "{0.00->1.17}The Mort system": "{0.00->1.17}莫特星系", + "{0.01->2.19}Squad lost; Deploying full replacement!": "{0.01->2.19}小队团灭;部署全员替补!", + "{0.00->2.43}Don't worry—the Helldivers are protecting us!": "{0.00->2.43}别担心,有绝地潜兵罩着!", + "{0.00->3.42}They died saving this planet from darkness.": "{0.00->3.62}他们为拯救这颗星球献出了生命。", + "{0.02->1.34}Democracy save me!": "{0.02->1.34}求求民主显灵!", + "{0.00->1.92}Forward, for Liberty!": "{0.00->2.04}前进,为了解放!", + "{0.02->1.99}Now that there's a Helldiver!": "{0.02->2.11}这才是绝地潜兵!", + "{0.00->2.69}Mourn, then maim.": "{0.00->2.69}化悲痛为力量。", + "{0.00->4.98}It is as we feared. Citizens are disappearing into the Rift.{5.59->9.24}They abscond from their beloved workplaces without warning,{9.78->14.78}and wander into the undeveloped wilderness to be abducted by the Illuminate.": "{0.00->2.47}最担心的事情发生了。{2.99->5.21}有公民消失在裂缝之中。{6.11->9.30}他们突然被迫离开热爱的工作岗位,{9.63->14.68}在未开发的荒野中徘徊,最后被光能者掳走。", + "{0.00->1.95}One down -- plenty more!": "{0.00->2.19}解决一个,还剩很多!", + "{0.00->0.51}Hellbomb.": "{0.00->0.51}地狱火炸弹,", + "{0.00->1.69}I am a soldier of Liberty.": "{0.00->1.69}我是捍卫解放的战士。", + "{0.03->1.58}Everyone into cover!": "{0.00->1.69}所有人进掩体!", + "{0.00->0.64}Reloading!{0.76->1.42}Cover me!": "{0.00->0.64}换弹!{0.76->1.42}掩护我!", + "{0.00->2.69}That's the flag of Super Earth, recruit! {3.08->8.25}Plant it in the designated area, and make sure you show it the proper respect!": "{0.00->2.98}那就是超级地球的旗帜,新兵!{3.63->8.25}把它插在指定区域,而且一定要好好敬个礼!", + "{0.03->0.44}Yes!": "{0.03->0.44}好的!", + "{0.01->0.66}Take cover!": "{0.01->0.66}快找掩体!", + "{0.00->1.76}Like bullets to brains!": "{0.00->1.88}这真是太爽了!", + "{0.00->6.17}Automatons are not living beings; they are weapons, hellbent on our destruction. {6.60->8.79}And how do we defeat a deadly weapon? {9.20->10.97}With an even deadlier weapon. {11.41->12.91}Requisition yours today.": "{0.00->2.35}机器人没有生命,只是武器,{2.60->4.68}不惜一切代价要消灭我们。{5.23->7.64}要怎样对付如此致命的武器呢?{8.41->10.86}答案是用更加致命的武器。{11.47->13.15}赶快申请属于你的武器吧。", + "{0.02->2.26}Kill it! Destroy it!": "{0.02->2.26}快杀了它!杀了它!", + "{0.14->0.76}Out of ammo.": "{0.00->0.74}没弹药了。", + "{0.00->3.46}An attack on Super Earth is an attack on Democracy!": "{0.00->3.46}对超级地球不敬就是对民主不敬!", + "{0.03->2.65}Come on team, the Helldiver's watching!": "{0.00->2.72}大家努力,绝地潜兵在看着呢!", + "{0.01->1.41}Watch out for us!": "{0.01->1.41}当心点我们!", + "{0.02->2.87}Let's not keep Liberty waiting. Move up.": "{0.00->3.02}别让解放等太久。压上去。", + "{0.05->1.57}We knew you'd come!": "{0.05->1.88}就知道你们一定会来!", + "{0.03->1.65}Kill 'em all, soldiers!": "{0.00->1.74}战士们,杀光它们!", + "{0.00->3.63}Fan out everybody, we've got this, we've got this.": "{0.00->1.71}所有人摆开阵型,{1.71->3.81}我们能行,我们一定行。", + "{0.02->1.51}Take cover!": "{0.02->1.51}快找掩体!", + "{7.65->10.65}Freedom's Greetings, I'm Coretta Kelly.{11.38->17.53}New information sheds light on the grisly aims of Automaton lava planet operations.{18.07->21.13}Samples of a synthetic liquid being produced on these{21.13->24.35}planets has been recovered by the Helldivers.{24.61->30.62}Scientific analysis has revealed this biological fluid to be full of amino acids,{30.62->36.74}nutrients, and stem cells - all apparently harvested from organic life forms.{37.74->38.49}Disturbingly,{38.49->44.44}scientists have verified beyond any doubt that the biological compounds were harvested{44.44->53.50}exclusively from Super Earth citizens - the majority of whom might have almost certainly been small, small children.{54.04->57.88}The Super Earth Association for Childhood Safety released{57.88->61.71}a statement condemning the Automaton actions.{62.12->67.05}Additionally, Automatons have been discovered to be mining large amounts of platinum ore.{67.57->73.31}The Helldivers have been ordered to seize this material in order to prevent its use for socialist aims.{73.83->77.38}That's Liberty's Latest; I'm Coretta Kelly.": "{7.65->10.65}自由向各位问好,{11.38->17.53}我是科雷塔·凯利。{18.07->21.13}新情报揭示了机器人在熔岩星球展开行动的可怕目的。{21.13->24.35}绝地潜兵已取得这些星球上生产的合成液体样本。{24.61->30.62}科学分析显示,这种生物液体富含氨基酸、营养物质和干细胞,{30.62->36.74}明显都是从有机生命体中提取的。{37.74->38.49}可怕的是,{38.49->44.44}科学家已全面证实,这些生物化合物完全来自超级地球公民,{44.44->53.50}其中大部分几乎可以肯定是年幼的孩子。超级地球儿童安全协会表示强烈谴责机器人的行径。{54.04->57.88}此外,{57.88->61.71}我们还发现机器人正在大量开采铂矿石。{62.12->67.05}绝地潜兵奉命夺取这些资源,{67.57->73.31}以防止被用于党同伐异的目的。以上就是今天的《解放新闻》,{73.83->77.38}我是科雷塔·凯利。", + "{0.04->2.70}Anchor your feet, and your hearts will follow!": "{0.00->2.76}站稳脚跟,心就不会动摇!", + "{0.01->1.77}Saviors of Super Earth!": "{0.01->1.77}超级地球的救星!", + "{0.00->1.49}The Sangis System": "{0.00->1.15}赤血星系", + "{0.02->2.11}For Liberty's sake, shoot them!": "{0.02->2.11}解放他大业的,弄死它们!", + "{0.02->1.87}Get it away from me!": "{0.00->1.87}别,别让它们过来!", + "{0.00->1.36}Alright, 1,{1.81->4.26}2,3 here we go!": "{0.00->4.16}好了,1、2、3,我们上!", + "{0.00->0.88}New canister.": "{0.00->0.88}新燃料罐。", + "{0.04->2.27}You guys do this all the time. Right?": "{0.04->2.27}你们都是老手了,对吧?", + "{0.00->1.46}The MOMO System": "{0.00->1.01}莫莫星系", + "{0.00->0.95}Stratagem beacon.": "{0.00->0.95}战略配备信标,", + "{0.00->0.41}2!": "{0.00->0.41}两!", + "{0.04->1.90}Here's our chance, surround them!": "{0.00->2.04}机会来了,包围它们!", + "{0.02->2.53}Those un-Democratic freaks found us!": "{0.02->2.20}反民主怪物找上来了!", + "{0.00->1.52}MOVE! OUT OF THE WAY!": "{0.00->1.68}快跑!离开这个区域!", + "{0.07->1.37}For Justice!": "{0.07->1.37}为了正义!", + "{0.00->1.37}Good luck out there, Helldiver.": "{0.00->1.85}绝地潜兵!祝你好运!", + "{0.00->1.19}SEAF backup, en route.": "{0.00->1.30}武装部队前往支援。", + "{0.01->3.33}Thank you Helldiver, really. I never thought...": "{0.00->3.36}绝地潜兵,真心感谢。我从没想过……", + "{0.00->1.69}Managed Democracy for all!": "{0.00->1.87}管理式民主人人有份!", + "{0.03->1.84}Liberty and Democracy!": "{0.00->1.96}解放和民主!", + "{0.05->2.12}Freedom, at any cost!": "{0.00->2.23}为了自由,不惜代价!", + "{0.00->0.95}Liberty!": "{0.00->0.95}解放!", + "{0.05->4.80}All this time, these old ruins had the capacity to create Exostorms. {5.23->7.66}Sure puts all those school trips into perspective.": "{0.05->3.85}原来这些古老遗迹一直都具备制造异界风暴的能力。{4.55->7.24}该好好反省当年学校的考察旅行了。", + "{0.00->2.46}I will protect our way of life.": "{0.00->2.46}守护正道,义不容辞。", + "{0.02->1.26}Bug outpost spotted.": "{0.02->1.26}发现虫族哨站。", + "{0.03->1.84}Sweet Liberty, we're saved!": "{0.03->1.68}解放大业来救我了!", + "{0.00->1.41}Establish a perimeter!": "{0.00->1.41}建立防线!", + "{0.02->1.26}Deploying Fortification.": "{0.02->1.26}部署防御工事。", + "{0.00->4.14}Tyranny festers in the alleys and sewers of our great city.": "{0.00->4.42}宏伟城市的街巷和下水道沦为暴政的温床。", + "{0.03->1.99}For Liberty's sake, shoot them!": "{0.03->1.89}为了解放,打死它们!", + "{0.00->2.28}One down -- plenty more!": "{0.00->2.73}解决一个,还剩很多!", + "{0.05->2.09}Helldiver, please!": "{0.00->2.21}绝地潜兵,拜托了!", + "{0.25->1.10}We're safe!": "{0.05->1.10}我们没事了!", + "{1.41->2.23}Argh! Not today,{2.61->4.41}anti-democratic scum...": "{0.00->2.81}啊!反民主渣滓,{2.82->4.79}我还没完……", + "{0.01->2.59}Back--eh, back at it!": "{0.00->1.16}继续……{1.16->2.58}继续打!", + "{0.00->0.72}You win.": "{0.00->0.72}你赢了。", + "{0.00->2.88}Go show 'em what we fight for, Helldivers!": "{0.00->2.88}绝地潜兵,让它们看看谁是老大!", + "{0.00->2.62}Keep working to get your Citizen Score up. {3.05->6.33}A higher Citizen Score means a better you.": "{0.00->2.68}努力工作可以提高公民评分。{3.32->6.36}更高的公民评分,更好的你。", + "{0.02->0.80}Absolutely!": "{0.02->0.80}没有问题!", + "{0.00->3.83}An Illuminate void, full of nothing, no light, no truth...{4.34->6.43}Just pure darkness.": "{0.00->4.76}光能者的寂域,空无一物,没有光明,没有真理……{5.25->6.99}只有纯粹的黑暗。", + "{0.00->1.51}This is it, Helldiver.{1.87->5.32}Today, you fight for a free Cyberstan.": "{0.00->0.97}绝地潜兵,{1.59->5.22}此刻,你要为解放生化斯坦而战。", + "{0.03->2.15}Get away from me, bug freak!": "{0.03->2.15}没脑子的东西!", + "{0.00->0.47}I'm on it.": "{0.00->0.53}我来。", + "{0.00->0.65}Pack's out.": "{0.00->0.65}背包空了。", + "{0.00->0.62}Northwest.": "{0.00->0.48}西北,", + "{0.00->0.48}I'm on it.": "{0.00->0.48}让我来。", + "{0.03->2.27}Freedom save me!": "{0.03->2.27}自由保佑我 !", + "{0.69->2.05}It's too high up!": "{0.73->2.28}这也太高了!", + "{0.04->0.59}I can't!": "{0.04->0.98}没办法!", + "{0.03->0.86}We're saved!": "{0.03->0.86}得救了!", + "{0.00->0.58}Fourth one.": "{0.00->0.58}第四个。", + "{0.00->0.50}Illuminate.": "{0.00->0.56}光能者,", + "{0.01->1.24}Show some hustle!": "{0.01->1.24}拿出干劲来!", + "{0.00->1.15}Calling down equipment.": "{0.00->1.52}呼叫装备。呼叫装备。", + "{0.00->1.36}The embodiment of sheer undeniable{2.41->3.33}Democracy.": "{0.00->3.48}它象征着民主的势不可挡。", + "{0.01->3.95}Join the party, pal! We got shots for everyone!": "{0.01->3.95}一起来吧,朋友!枪子管饱!", + "{0.01->2.23}C'mon... c'mon...! Reloading!": "{0.01->2.23}快…快…!快换弹!", + "{0.00->0.60}Fall back.": "{0.00->0.60}撤退。", + "{0.02->1.87}Kill it! Destroy it!": "{0.02->1.87}快杀了它!杀了它!", + "{0.01->0.56}Bots.": "{0.01->0.56}机器人。", + "{0.00->1.11}Tac-pack inbound.": "{0.00->0.87}战术背包来了。", + "{0.02->0.84}Fall back!": "{0.00->0.84}撤退!", + "{0.11->9.59}There it is. A Terminid. The Scourge of Liberty. Arm yourself and show that Bug the true meaning of {9.59->10.38}Freedom.": "{0.11->5.71}就在那里。一只终结族,它们都是侵害解放的灾难。{6.31->10.38}武装起来,让那只虫子领教自由的真谛。", + "{0.03->1.87}Don't let'em get me!": "{0.00->1.92}别让它们抓到我!", + "{0.00->1.33}The Durgen system": "{0.00->1.33}德尔根星系", + "{0.00->2.68}Time to feel the might of Super Earth.": "{0.00->2.70}准备好接受超级地球的制裁吧!", + "{1.53->3.11}I won't let that happen to me.": "{1.21->2.69}我绝不会变成那样。", + "{0.00->1.50}Look alive, soldiers!": "{0.00->1.56}战士们,行动起来!", + "{0.03->1.11}Don't let 'em kill you!": "{0.00->1.23}可千万别栽在这里!", + "{0.04->3.19}Back under the control of FREEDOM!": "{0.00->3.25}再次收归自由的掌控!", + "{0.00->1.98}Glad to fight alongside ya!": "{0.00->2.15}与你并肩作战真好!", + "{0.04->5.24}So when the Illuminate build Exospires on planets in formation...{5.24->9.17}everything in between gets swallowed by the Void.{9.17->12.24}Them and their flag-forsaken schemes...": "{0.04->3.47}光能者在行星上按阵型建造异界尖塔时……{3.86->6.82}中间的一切都会被寂域吞噬。{7.31->9.75}连同它们和那些旗帜唾弃的阴谋……", + "{0.00->2.02}Tunnel breach detected. Bugs incoming.": "{0.00->2.02}侦测到隧道洞口。虫族即将来袭。", + "{0.01->2.21}How dare THEY attack US!": "{0.01->2.45}这群东西,是怎么敢的!", + "{0.01->2.14}You gave it your all, Helldiver.": "{0.01->2.14}绝地潜兵,你尽力了。", + "{0.00->1.68}That's what I call Justice.": "{0.00->1.68}这个就叫做正义!", + "{0.00->4.77}He started to only spend time with the Stranger and the Stranger's friends, because only they were {4.77->6.58}curious, like Danny was.": "{0.00->3.60}他开始只跟那个陌生人以及陌生人的朋友待在一起,{4.22->6.58}因为只有他们和丹尼一样好奇。", + "{0.05->2.92}That's Super Earth's finest, right there.": "{0.00->2.91}不愧是超级地球最精锐的战士。", + "{0.00->1.18}Weapons hot!": "{0.00->1.18}准备好武器!", + "{0.00->0.52}Reloading.": "{0.00->0.52}换弹。", + "{0.01->1.20}There's more of them!": "{0.01->1.02}那边还有!", + "{0.00->1.45}Another one bites the dust.": "{0.00->1.45}又干掉一个。", + "{0.00->3.40}Underneath the surface, every citizen is the same. {4.12->5.26}Because of skulls. {5.62->10.95}Skulls are what make us human. Skulls are what make us Helldivers.": "{0.00->2.79}在皮囊之下,每位公民都是相同的,{3.20->5.09}因为每个人都具有头脑。{5.68->7.41}有头脑,才能算是人类。{7.99->10.85}有头脑,才能成为绝地潜兵。", + "{0.05->1.54}That's called Democracy!": "{0.04->1.32}这就是民主!", + "{0.00->2.22}Okay, who's next!": "{0.00->2.31}好了。轮到谁了?", + "{0.01->3.65}Must be happy hour 'cause we got shots for everyone!": "{0.00->3.56}民主加餐,枪子儿管饱,人人有份!", + "{0.24->0.95}Out of ammo.": "{0.00->0.95}没弹药了!", + "{0.02->2.56}Frontline! Focus on the frontline!": "{0.02->2.56}前线!专心关注前线!", + "{0.01->2.94}We will remember your sacrifice, Helldiver!": "{0.01->3.29}绝地潜兵,我们不会忘记你!", + "{0.00->2.20}Welcome to Helldiver Training. {2.63->5.38}Your instructor is waiting for you up ahead. Please proceed.": "{0.00->2.20}欢迎参加绝地潜兵训练。{2.63->5.38}你的教官正在前面等你。请尽快过去。", + "{0.00->1.27}The Kharst system": "{0.00->1.27}喀斯特星系", + "{0.00->2.69}I'll never see Super Earth...": "{0.00->3.84}再也见不到超级地球了……", + "{0.00->1.18}NOOOOOOOO!!!!": "{0.19->1.18}不!!!!", + "{0.00->0.95}I'll handle the terminal.": "{0.00->0.95}这个终端交给我。", + "{0.03->1.10}Incoming fire!": "{0.00->1.10}火力来袭!", + "{0.00->2.95}Welcome aboard, deliverers of Democracy.": "{0.00->2.95}民主制度的传播者,欢迎你。", + "{0.01->1.26}Hey, wait for me!": "{0.01->1.40}嘿,等等我!", + "{0.01->1.57}Socialist scum.": "{0.00->1.37}铁皮渣滓。", + "{0.02->0.72}Thank you!": "{0.02->0.72}谢谢!", + "{0.03->2.15}Flag-forsaken robots!": "{0.34->2.15}一堆破铜烂铁!", + "{0.00->1.33}Rapid response inbound.": "{0.00->1.38}已派遣快速响应小组。", + "{0.00->0.50}I can't!": "{0.00->0.50}不可以!", + "{0.12->1.92}Super Uranium acquired.": "{0.12->1.92}超铀到手了。", + "{0.00->1.44}Demolition time.{1.84->3.36}Cool right, Helldiver?": "{0.00->1.15}该爆破了。{1.15->3.52}绝地潜兵,你就说帅不帅吧?", + "{0.02->1.37}The Igla system": "{0.02->1.37}伊格勒星系", + "{0.00->2.37}Hellbomb request approved; on its way now.": "{0.00->2.37}批准使用地狱火炸弹;即将抵达。", + "{0.07->2.45}LET THE STREETS RUN RED!!!": "{0.07->2.45}统统都得死!!!", + "{0.00->1.29}The Merga system": "{0.00->1.29}玄戈增二星系", + "{0.00->1.26}Eagle, back in the fight": "{0.00->1.26}“飞鹰”重回战场", + "{0.00->1.93}A fence! What do we do!??": "{0.00->2.21}围墙!我们该怎么办!??", + "{0.00->1.72}I will keep Super Earth safe.": "{0.00->1.72}保卫超级地球。", + "{0.00->2.92}Enemy sighted. Prepare to engage.": "{0.00->2.38}发现敌人。准备交战。", + "{0.00->2.30}INCOMING! MOVE-MOVE-MOVE!": "{0.00->2.34}要来了!都赶紧散开,散开!", + "{0.00->1.33}The Valmox system": "{0.00->1.33}瓦尔莫克斯星系", + "{0.00->0.62}I'm sorry.": "{0.00->0.62}抱歉。", + "{0.00->1.81}Reinforcement ready upon request.": "{0.00->1.81}增援力量随时待命。", + "{0.00->1.84}Democracy isn't done with you yet.": "{0.00->1.84}民主大业跟你没完。", + "{0.02->3.27}Sweet Liberty I wanna see what this baby can do!": "{0.02->3.27}一起来瞧瞧这超级宝贝的威力!", + "{0.00->1.36}One mission more.": "{0.00->1.54}还有一项任务。", + "{0.00->1.26}The Borea system": "{0.00->1.26}博瑞亚星系", + "{0.02->2.31}Hellbomb armed—clear the area.": "{0.02->2.31}地狱火启动,炸平这里。", + "{0.00->1.39}Heads on a swivel.": "{0.00->1.56}都打起精神来!", + "{0.00->2.69}Yes! Are we glad to see you!": "{0.00->2.60}好!见到你真是太高兴了!", + "{0.00->1.78}The Erson Sands system": "{0.00->1.78}厄尔森桑兹星系", + "{0.01->2.46}I'm hit..I'm hit...": "{0.01->2.94}我中弹了…我中弹了…", + "{0.00->2.10}It's going to be ok!": "{0.00->2.10}不会有事的!不会有事的!", + "{0.03->1.84}Target destroyed in the name of Liberty.": "{0.03->1.84}以解放的名义摧毁目标。", + "{0.00->1.85}Victory was never in doubt.": "{0.00->1.85}胜利毋庸置疑。", + "{0.02->0.76}At once!": "{0.02->0.76}马上!", + "{0.01->0.85}Squids!": "{0.01->0.85}鱿鱼!", + "{0.00->4.62}For the benefit of our Federation...for the benefit of our Federation...": "{0.00->4.62}为了联邦…为了我们的联邦…", + "{0.00->0.93}I need supplies!": "{0.00->0.93}我需要补给!", + "{0.11->1.37}Somebody help!": "{0.00->1.56}谁来救救我!", + "{0.02->2.01}Fight on, for Super Earth!": "{0.00->2.09}别放弃,为了超级地球!", + "{0.00->0.95}Objective located.": "{0.00->0.83}发现目标,", + "{0.73->3.91}You cannot hurt Democracy!": "{1.04->4.32}你无法损害民主!", + "{0.27->1.88}A military marvel, you are.": "{0.38->2.02}你简直是个军事奇迹。", + "{0.02->1.26}Eyes forward, soldiers!": "{0.00->1.36}注意前方,士兵们!", + "{0.00->5.91}When the Illuminate raise their Exospires, they affect the fabric of spacetime somehow. {6.31->9.76}Won't they ever stop trying to manipulate forces they don't understand?": "{0.00->4.39}光能者建造异界尖塔时,不知怎地扭曲了时空结构。{4.79->8.33}它们什么时候才能停止操控自己根本不理解的力量?", + "{0.00->1.16}Point me to the enemy.": "{0.00->1.16}告诉我敌人在哪儿。", + "{0.05->1.24}Sweet Liberty... incredible.": "{0.00->2.88}解放大业啊……绝了。", + "{0.01->0.73}I'm hit!": "{0.01->0.91}我中弹了!", + "{0.02->1.31}We're all gonna die!": "{0.02->1.31}我们全都死定了!", + "{0.00->2.10}The Conlon Colony System": "{0.00->1.57}康伦拓殖地星系", + "{0.08->0.89}My leg!": "{0.08->0.89}我的腿!", + "{0.02->1.58}Dirty Xenophobes.": "{0.02->1.58}肮脏的排外分子。", + "{0.42->5.41}The Automatons' ravenous extraction of this planet continues uncontested.": "{0.42->5.41}机器人还在毫无节制地疯狂掠夺这颗星球。", + "{0.00->3.14}The Terminids profilerate out of control on this planet. {3.69->5.73}Get down there and eradicate them.": "{0.00->3.47}这颗星球的终结族数量激增,已然失控。{3.71->5.73}下去把它们彻底铲除。", + "{0.00->0.30}2!": "{0.00->0.30}两!", + "{0.00->1.08}Changing course!": "{0.00->1.08}调整路线!", + "{0.06->4.24}The mystery of our vanishing colonists is at last solved. {4.63->6.58}They were abducted by the Illuminate, {6.96->12.53}and transfigured into the betentacled assailants with which we must now contend.": "{0.00->3.77}拓殖者神秘消失的谜团终于解开了。{4.38->9.31}他们被光能者绑架,被改造成长着触手的袭击者,{9.70->12.53}如今我们不得不与他们正面交锋。", + "{0.65->2.54}It's like you're under my skin...": "{0.61->2.58}我的身心再次完整了……", + "{0.00->1.51}Showing us how it's done!": "{0.00->1.51}你真是太厉害了!", + "{0.00->3.38}I remember when my parents sat me down for the Bugs and the Bots talk.": "{0.00->3.38}我还记得小时候的事,爸妈要我坐下,和我聊起虫族和机器人。", + "{1.58->2.59}I, uh... I don't know what to say.": "{0.00->2.62}我,呃……我不知道该说什么好。", + "{0.00->1.43}Sometimes, when I can't sleep, I {1.82->3.48}imagine what it would be like to live there.": "{0.00->1.28}我偶尔失眠的时候,{1.34->3.48}就会想象住在超级地球的感觉。", + "{0.30->3.48}The Void succumbs to Managed Democracy.": "{0.00->3.56}管理式民主征服了寂域。", + "{0.00->1.30}The Gemma system": "{0.00->1.30}贯索四星系", + "{0.02->1.83}DEATH TO ALL SQUIDS!": "{0.02->1.83}都给我死!鱿鱼!", + "{0.00->1.94}Our lives for Super Earth!": "{0.00->2.21}为超级地球奉献一切!", + "{0.03->3.28}Supressing fire! Now! NOW!!": "{0.00->1.47}火力压制!{1.48->3.25}快!快!", + "{0.00->3.31}The Illuminate would plunge this planet into darkness.{3.69->5.22}They must be stopped!": "{0.00->2.81}光能者会让这颗星球陷入黑暗。{3.38->5.16}一定要阻止它们!", + "{0.04->1.36}You got 'em, Helldiver!": "{0.04->1.36}绝地潜兵干得漂亮!", + "{0.01->1.96}It sounds worse than it is.": "{0.01->1.96}雷声大雨点小。", + "{0.00->1.46}A real Helldiver.{1.96->3.90}So gallant. So noble.": "{0.00->1.38}真正的绝地潜兵。{1.68->3.90}多么英勇。多么崇高。", + "{0.03->1.81}Calling in orbital strike.": "{0.03->1.81}请求轨道攻击支援。", + "{0.00->2.27}And now, a Freedom Proclamation: {2.71->5.20}work harder, for a brighter future.": "{0.00->1.74}宣读自由宣言:{2.44->5.88}工作越努力,前途越光明。", + "{0.00->0.92}Bot fabricator.": "{0.00->1.06}机器人构筑者,", + "{0.00->2.42}LET THE STREETS RUN RED!!!": "{0.00->1.92}统统都得死!!!", + "{0.02->2.29}INCOMING! RUN!": "{0.00->2.42}要来了!快跑!", + "{0.00->0.87}Enemy patrol.": "{0.00->0.87}敌方巡逻队,", + "{0.00->1.77}My life for Super Earth.": "{0.00->1.77}为超级地球献身。", + "{0.00->3.04}Need assistance!": "{1.90->3.79}请求救助!", + "{0.01->3.07}Self-defense is our Democratic right.": "{0.01->3.35}自卫是民主赋予的权利。", + "{0.00->4.43}Though we are the most powerful fighting force the universe has ever seen, {5.08->9.54}we are naught but humble servants before Managed Democracy.": "{0.00->1.27}我们虽然是{1.37->4.75}宇宙有史以来最强大的战斗力量,{5.08->9.79}但在管理式民主面前只是卑微的公仆。", + "{0.00->1.05}More Terminids!": "{0.00->1.05}终结族又来了!", + "{0.00->1.43}Not today, freaks!": "{0.00->1.75}怪物,跟你没完!", + "{0.00->1.68}You have no idea what that means to me.": "{0.00->1.83}你不知道这对我意义有多大。", + "{0.00->1.15}Requesting air support.": "{0.00->1.15}请求空中支援。", + "{0.00->0.35}Calling in extraction!": "{0.00->0.35}呼叫撤离!", + "{0.04->3.19}Let's go! Democracy ain't gonna deliver itself!": "{0.04->3.19}上吧!民主需要传播!", + "{0.00->0.37}Let's{0.92->1.16}go!": "{0.00->1.19}一起冲啊!", + "{0.00->1.39}Sorry, I got distracted.{1.85->2.52}What's happening?": "{0.00->1.39}对不起,我走神了。{1.85->2.52}怎么了?", + "{0.03->0.96}Dropping item!": "{0.03->0.96}放下物品!", + "{0.05->3.90}The Illuminate cannot be allowed to corrupt our lands.": "{0.05->3.90}绝不容许光能者侵蚀我们的领土。", + "{0.00->2.95}Welcome aboard, Helldiver. I look forward to serving with you.": "{0.00->3.26}绝地潜兵,欢迎登舰。期待与你并肩作战。", + "{0.03->1.06}Mounting weapon!": "{0.00->1.14}操作武器!", + "{0.03->1.60}The Monheim System": "{0.03->1.35}蒙海姆星系", + "{0.04->3.60}Relocate to the coordinates, and get ready for the show.": "{0.00->3.51}转移至该坐标,准备好大干一场。", + "{0.05->4.06}Freedom has prevailed. Now head to the extraction point.": "{0.05->4.06}自由大获全胜,立即前往撤离点。", + "{0.00->1.61}A tactical retreat.{2.05->6.71}Those burrowing monstrosities will taste vengeance, in time.": "{0.00->1.61}战术撤退。{2.05->6.71}钻地怪物迟早会见识到复仇的怒火。", + "{0.00->0.92}Never doubt!": "{0.00->0.76}忠诚!", + "{0.00->1.48}Super Uranium acquired.": "{0.00->1.48}超铀到手了。", + "{0.03->2.85}Beat you! Can't believe I beat you...": "{0.00->2.90}赢了!我居然赢了你……", + "{0.00->1.95}The Sammelsurium System": "{0.00->1.17}喧沌星系", + "{0.00->0.66}Got a sample.": "{0.00->0.66}样本到手了。", + "{0.00->1.37}The Wasat system": "{0.00->1.37}天樽二星系", + "{0.00->0.53}Of course.": "{0.00->0.53}那当然。", + "{0.00->1.78}Democracy has landed.": "{0.00->1.78}民主来了。", + "{0.99->2.38}good riddance.": "{0.99->2.38}死得好。", + "{0.00->1.42}Freedom smiles on me today.": "{0.00->2.02}今天自由眷顾了我。", + "{0.02->2.99}*sigh* But that's just a pipe dream. We gotta kill 'em all.": "{0.02->1.77}唉,然而这只是幻想罢了。{1.84->3.19}只能把它们全部杀光。", + "{0.02->1.33}Just in time...": "{0.36->1.38}真及时……", + "{0.03->0.90}They're back!": "{0.03->1.18}它们回来了!", + "{0.00->2.49}Never thought I'd see anything like it.": "{0.00->2.75}从来没想过我能亲眼见到。", + "{0.02->1.20}Thank Liberty!": "{0.02->1.20}感谢解放!", + "{0.00->0.85}Sub-objective.": "{0.00->0.85}次要目标,", + "{0.00->1.10}Right on target!": "{0.00->1.10}正中目标!", + "{0.00->1.96}This'll all blow over soon enough.": "{0.00->1.96}这个要不了多久的。", + "{0.00->3.11}Pelican 1 landing sequence initiated. Watch where you're standing.": "{0.00->3.11}“鹈鹕”1号现在开始降落。请站远一点。", + "{0.01->3.20}Spread out, we've gotta spread out, go!": "{0.00->1.31}散开,{1.31->3.31}我们得散开,快!", + "{0.00->1.95}Requesting advanced weaponry!": "{0.00->1.95}请求高级武器支援!", + "{0.03->0.25}Up.": "{0.03->0.46}上方。", + "{0.00->0.73}We fight them, {1.16->5.72}but we cannot forget that the Terminids are the ichor of Democracy itself.": "{0.00->2.05}虽然我们在跟它们做斗争,{2.23->3.52}但也不能忘记,{3.64->6.22}终结族是民主本身的“血液”。", + "{0.02->1.03}Bot outpost.": "{0.02->1.03}机器人哨站。", + "{0.01->1.26}Reinforcing!": "{0.01->1.26}请求增援!", + "{0.03->0.95}Come on!": "{0.00->0.98}一起上!", + "{0.00->1.48}They'll regret this.": "{0.00->1.48}它们会后悔的。", + "{0.02->2.35}We're overrun! Fall back!": "{0.00->2.44}阵地失守了!撤退!", + "{0.00->2.10}As Democracy decrees.": "{0.00->1.51}我服从民主。", + "{0.00->1.52}The Overgoe system": "{0.00->1.52}欧维果星系", + "{3.07->3.63}Good job. That was...weird.": "{0.00->1.56}漂亮。{1.62->4.15}那地方,真诡异。", + "{0.00->0.50}I'm on it.": "{0.00->0.50}我来。", + "{0.01->2.48}Agh! Uh -- FIRE IN THE HOLE!": "{0.00->2.51}啊!呃…小心爆炸!", + "{0.00->3.15}All it took was reportin' some unpatriotic talk I heard in the barracks.": "{0.00->2.89}只需要举报我在兵营里听到的不爱国言论就行。", + "{0.00->2.36}Oops, accidentally copied you!": "{0.00->2.35}哎呀,不小心跟你出的一样!", + "{0.00->1.77}CLEAR THE ZONE! NOW!": "{0.00->1.98}撤出这个区域!快!", + "{0.00->0.49}First one.": "{0.00->0.49}第一个。", + "{0.01->0.88}Dropping package.": "{0.01->0.88}放下物品。", + "{0.01->0.85}This is it.": "{0.01->0.85}就是这里。", + "{0.03->1.14}It's going to eat me!": "{0.03->1.14}它要把我吃了!", + "{0.00->1.53}Enemy outpost spotted.": "{0.00->1.53}是敌方哨站。", + "{0.00->1.73}The Seyshel Beach system": "{0.00->1.73}塞舌尔海滩星系", + "{0.00->1.70}Gotta patch up this leg.": "{0.00->1.70}这条腿得处理下。", + "{0.02->1.64}Prepare for demolition.": "{0.00->1.69}爆破工作准备就绪。", + "{0.04->0.71}Moving out!": "{0.00->0.77}进攻!", + "{0.00->1.35}The Peony System": "{0.00->0.90}牡丹星系", + "{0.00->0.53}5!": "{0.00->0.53}五!", + "{0.03->0.86}More bugs!": "{0.03->1.27}还有虫族!", + "{0.00->0.67}Absolutely!": "{0.00->0.67}没有问题!", + "{0.01->1.00}Heads on a swivel!": "{0.01->1.00}不要松懈!", + "{0.03->1.85}That's it, that's the stuff.": "{0.00->1.93}没错,要的就是这个。", + "{0.02->0.84}Moving up!": "{0.00->0.88}向前推进!", + "{0.01->0.66}I've got you.": "{0.01->0.66}我来帮你。", + "{0.01->0.73}I'm out!": "{0.01->0.73}打光了!", + "{0.04->1.47}The Watchdog System": "{0.04->1.19}守犬星系", + "{0.00->1.29}Not today!": "{0.00->1.29}死不了!", + "{0.00->1.40}You have escaped death, {2.00->5.56}and earned us the opportunity to redeem this defeat.": "{0.00->1.40}你顺利逃脱死亡,{2.00->5.56}为我们争取到了弥补失败的机会。", + "{0.24->2.37}I will never forgive myself!": "{0.00->2.52}我永远不会原谅自己!", + "{0.02->1.89}Deploying minefield. Stand clear.": "{0.02->1.89}部署雷区。请勿靠近。", + "{0.00->0.93}Calling in an Eagle.": "{0.00->0.96}呼叫“飞鹰”。", + "{0.01->0.93}Grenade!": "{0.01->0.93}手雷!", + "{0.01->1.16}Reloading!": "{0.01->1.16}在换弹!", + "{0.00->1.20}Remember your duty!": "{0.00->1.20}记住你的职责!", + "{0.00->0.60}I'm sorry!": "{0.00->0.60}抱歉!", + "{0.04->1.53}Time for some payback!": "{0.00->1.66}是时候讨债了!", + "{0.01->2.18}Reposition! Clear the mark.": "{0.00->2.17}转移位置!离开标记区域。", + "{0.01->1.29}That's what they get!": "{0.01->1.29}这就是它们的下场!", + "{0.05->2.44}Thankful you're on our side, Helldiver.": "{0.05->2.44}绝地潜兵,幸好有你。", + "{0.00->2.44}Congratulations on completing training, Helldiver. {2.92->6.70}You're in charge of this vessel now. The Democracy Officer awaits you on the bridge. {7.09->8.57}Welcome to the Galactic War.": "{0.00->2.44}绝地潜兵,恭喜你完成训练。{2.92->7.26}现在,这艘舰船听你指挥。民主官正在舰桥等你。{7.73->9.45}欢迎参加星系战争。", + "{0.07->1.48}The Ingmar system": "{0.07->1.48}英格玛星系", + "{0.03->1.20}When's the shuttle coming?": "{0.03->1.20}运输船啥时候到?", + "{0.00->0.77}Move out!": "{0.00->0.82}转移!", + "{0.03->2.27}Freedom spreads yet further. {2.67->4.20}Extract when ready.": "{0.03->2.27}自由得到了进一步传播。{2.67->4.20}准备好就撤离吧。", + "{0.03->1.18}What is that?": "{0.03->1.18}那到底是什么?", + "{0.01->1.78}Son of a dissident!": "{0.73->2.00}解放你大业的!", + "{0.00->1.74}Off the streets!": "{0.00->1.74}远离街道!", + "{0.00->0.75}Changing I.C.E.": "{0.00->0.75}更换冷却片。", + "{0.00->5.29}You are the stakes upon which Liberty's invaders will be skewered.": "{0.00->5.29}你们就是一根根尖钉,代表自由刺穿敌人。", + "{0.00->1.18}Gotta swap batteries.": "{0.00->1.18}没电了,要换电池。", + "{0.00->1.32}Whoa. For me?{2.07->2.45}Thank you.": "{0.00->1.60}哇。给我用吗?{1.60->2.53}谢谢。", + "{0.00->1.82}The Lamb's Patch System": "{0.00->1.18}羔原星系", + "{0.12->1.09}Right away!": "{0.12->1.09}马上就去!", + "{1.18->2.05}I'd...I'd be honored.": "{0.00->2.23}我…我很荣幸。", + "{0.00->0.96}Reinforcing.": "{0.00->0.96}请求增援。", + "{0.03->1.74}INCOMING! CLEAR OUT!": "{0.00->1.81}要来了!快撤!", + "{0.03->0.95}Squid warp gate.": "{0.03->0.95}鱿鱼传送门,", + "{0.00->0.84}Are we safe?": "{0.00->0.99}我们安全了吗?", + "{0.01->2.65}The blood. Can't stop the blood.": "{0.01->2.65}血,都他民主的流干了!", + "{0.03->1.43}For Democracy!": "{0.00->1.53}为了民主!", + "{0.01->1.72}Requesting fortifications.": "{0.01->1.72}请求防御工事支援。", + "{0.00->0.95}Objective equipment.": "{0.00->0.95}目标装备,", + "{0.05->1.86}You rock, Helldiver!": "{0.00->2.03}帅呆了,绝地潜兵!", + "{0.00->2.11}You're here to save us, I know it!": "{0.00->2.35}我就知道,你是来救我们的!", + "{0.00->0.95}Ready to Liberate.": "{0.00->0.95}准备好解放。", + "{0.00->0.26}Let's go!": "{0.00->0.88}一起上!", + "{0.00->1.90}Helldiver lost. Sending replacement.": "{0.00->1.90}绝地潜兵阵亡。派出替补。", + "{0.00->0.41}Delta": "{0.00->0.41}D", + "{0.02->3.01}Thanks Helldiver, I needed the humility.": "{0.00->3.15}谢谢你,绝地潜兵,我正需要这份谦卑。", + "{0.00->2.32}Hold this new line, for Liberty.": "{0.00->2.32}守住新阵线,为了解放。", + "{0.02->1.05}Squids!": "{0.02->1.05}鱿鱼!", + "{0.51->2.07}Hh--I'm hit! Son of a-- I'm{2.83->3.20}hit!": "{0.00->1.55}呃——我中弹了!{1.55->3.25}他民主的……我中弹了!", + "{0.00->2.77}We've done it, Helldiver! The Cyborgs are on the run!": "{0.00->3.20}绝地潜兵,我们成功了!生化人逃跑了!", + "{0.03->1.22}How much longer?": "{0.03->1.22}还要等多久?", + "{0.00->0.69}Northeast.": "{0.00->0.69}东北,", + "{0.00->4.95}There is only one choice that truly matters: Democracy or {5.54->6.08}Treason.": "{0.00->2.37}世界上只有两种选择:{3.19->6.66}维护民主或是成为叛徒。", + "{0.00->0.70}On your feet, soldier!": "{0.00->1.45}士兵,站起来!", + "{0.01->0.83}Reloading!": "{0.01->0.83}换弹!", + "{0.00->1.90}You really are the best of the best.": "{0.00->1.90}你们是精英中的精英。", + "{0.11->1.81}The Embold System": "{0.11->1.06}无畏星系", + "{0.00->0.83}We're stuck!": "{0.00->0.83}被困住了!", + "{7.57->10.90}Freedom's Greetings, I'm Coretta Kelly.{11.31->15.01}Covert Helldiver reconnaissance has unearthed widespread{15.02->18.27}Automaton mining on uninhabited Lava Planets.{18.35->23.72}The Helldivers, completely evading detection thanks to their elite training,{23.87->27.84}discovered evidence of ongoing operations on multiple worlds.{28.59->33.84}These magma-covered planets are considered inhospitable to most forms of life.{34.25->43.46}While details of the enemy's objectives are still unclear, the Helldivers have been ordered to immediately deploy to interdict these activities.{44.22->49.60}Later: A new study shows that feeling unsafe or worried could be YOUR fault.{50.03->53.54}That's Liberty's Latest; I'm Coretta Kelly.": "{7.57->10.90}自由向各位问好,我是科雷塔·凯利。{11.31->15.01}绝地潜兵秘密侦察发现,{15.02->18.27}机器人在无人居住的熔岩星球上大规模采矿。{18.35->23.72}绝地潜兵凭借精英训练完全避开敌方侦测,{23.87->27.84}发现了敌人正在多个世界开展行动的证据。{28.59->33.84}这些岩浆覆盖的星球被认为不适宜大多数生命形式生存。虽然敌方目标细节仍不明确,{34.25->43.46}但绝地潜兵已奉命立即出动,阻止敌人开展的活动。接下来请收看:新研究表明,不安或担忧的情绪可能是你自己的问题。{44.22->49.60}以上就是今天的《解放新闻》,{50.03->53.54}我是科雷塔·凯利。", + "{0.00->1.91}New battery, same way of life.": "{0.00->1.91}换电池,不换生存正道。", + "{0.00->0.95}I need help!": "{0.00->1.10}我需要帮助!", + "{0.05->1.95}Time for payback!": "{0.62->1.97}该还债了!", + "{0.00->1.70}Should've stayed home, scum!": "{0.00->1.70}不知道今天不宜出门吗!", + "{0.02->2.13}It brings a tear to my eye.": "{0.00->2.14}我已经热泪盈眶了。", + "{0.00->0.40}Heavy.": "{0.00->0.56}重型敌人。", + "{0.04->0.87}Watch out!": "{0.04->0.87}小心!", + "{1.44->8.24}My family has owned this same cabin for generations. Right here in Superstone Park. {9.74->13.80}Which is why I choose Morgunson for all my huntin' needs. {15.79->19.27}Like this SG-12 Breaker Assault Shotgun. {20.05->21.27}Same as Pa. {28.84->29.87}Now that...{30.25->31.99}is what I call tradition.{33.80->34.28}Hunting. {34.81->35.48}Warfare. {35.92->39.06}Home Defense. But most of all? Tradition. {39.86->42.52}Morgunson: A Super Earth Company.": "{1.44->5.33}这栋房子在我们家已经传了好几代人了,{5.77->8.26}就坐落在超石公园里面。{9.74->13.80}所以我打猎一直用莫枪森的装备,{15.79->19.84}就像这把SG-12“破裂者”突击霰弹枪。{20.05->21.94}和我爷爷用的一样,{28.84->32.45}这就叫传统。{33.95->34.63}打猎。{34.96->35.61}打仗。{35.92->36.73}打天下。{37.24->39.52}但是最重要的是什么?是传统。{39.86->42.98}莫枪森:超级地球第一枪。", + "{0.01->0.56}That one.": "{0.01->0.56}那个。", + "{0.00->1.31}Decreased visibility—{1.75->3.95}should help obscure our movements.": "{0.00->1.31}能见度降低,{1.75->3.95}方便我们隐藏行踪。", + "{0.00->1.95}Say hello to Democracy.": "{0.00->1.95}民主驾到。", + "{0.02->2.39}BATHE IN THE BLOOD OF TYRANTS!!!": "{0.02->2.39}暴政就没有好下场!!!", + "{0.03->2.46}Blue on yellow, I repeat! Blue on yellow!": "{0.00->2.50}友军误伤,重复!友军误伤!", + "{0.02->1.52}Throwing supply beacon.": "{0.02->1.52}投掷补给信标。", + "{0.02->2.06}That's what happens when you fight Freedom.": "{0.02->2.06}这就是与自由为敌的下场。", + "{0.00->1.95}All in good fun, eh, Helldiver?": "{0.00->2.04}就是图个乐子,对吧潜兵?", + "{0.00->1.84}Requesting objective equipment!": "{0.00->1.84}请求目标所需装备!", + "{0.05->1.61}Augh, get it off!": "{0.05->1.61}啊,快把它搞走!", + "{0.00->5.33}They died free, defying Illuminate control with their last breaths.": "{0.00->5.33}他们死得自由,用尽最后一口气反抗光能者的精神控制。", + "{0.00->2.51}They abandoned our mission and our cause. {3.06->5.09}Execution was our only choice.": "{0.00->2.51}他们抛弃了我们的使命与伟业。{2.73->5.09}就地处决是唯一的选择。", + "{0.01->0.69}This way!": "{0.01->0.69}这边!", + "{0.02->1.46}The more the mightier.": "{0.02->1.46}人越多越好。", + "{0.00->0.78}Are we nearly there?": "{0.00->0.78}快到了吗?", + "{0.02->1.53}Bugs! Aaaaaah!": "{0.02->2.06}虫族!啊啊啊啊!", + "{0.00->1.95}The Zea Rugosia system": "{0.00->1.95}泽亚鲁戈西亚星系", + "{0.05->2.34}We're overrun! Fall back!": "{0.00->2.40}阵地失守了!撤退!", + "{0.00->1.16}Calling down a walker.": "{0.00->1.16}呼叫步行机甲。", + "{0.01->1.95}For the cause...": "{0.01->2.21}为了大业…", + "{0.00->2.68}I hope the Helldivers make an example of you.": "{0.00->2.37}我希望绝地潜兵先拿你开刀。", + "{0.00->1.56}This is crazy!": "{0.00->1.56}太可怕了!", + "{0.01->1.02}Changing course!": "{0.01->1.02}调整路线!", + "{0.00->1.22}Our heroes have fallen, {1.67->5.87}but their bodies shall be replaced, and their losses restored.": "{0.00->1.22}英雄虽已陨落,{1.67->5.87}但躯体可以置换,失落的一切也可复还。", + "{0.00->1.72}Prosperity weeps.{2.08->7.91}Dry her tears with your resolve, and wash her face with the blood of her enemies.": "{0.00->1.72}繁荣伤透了心。{2.08->7.91}用你的决心擦干她的泪水,用敌人的鲜血洗净她的脸庞。", + "{0.00->0.82}Let's play.": "{0.00->0.82}来玩玩吧。", + "{0.05->7.33}What a fine soldier. Your brother-in-arms. A battle-forged bond that could never be replaced.": "{0.05->7.33}多么优秀的军人,这是你的战友,在战斗中铸就的纽带永远坚不可摧。", + "{0.00->4.96}If the Helldivers can't stop them...we're all dead! AAAUUUGHHH!!!!": "{0.00->4.96}要是连绝地潜兵都挡不住…那我们都死定了!啊啊啊啊!!!!", + "{0.00->1.49}The Korv System": "{0.00->1.21}科尔脯星系", + "{0.03->1.11}Mine!!": "{0.00->1.14}有地雷!!", + "{0.01->4.33}Follow the cape, and everything's great. Follow the cape, and everything's great.": "{0.01->4.69}跟着披风走,你有我有全都有。跟着披风走,你有我有全都有。", + "{0.23->2.75}Sweet Liberty... incredible.": "{0.00->2.83}解放大业啊……绝了。", + "{0.04->3.44}There was a curious boy named Danny who was always looking for secrets.": "{0.04->3.44}有一个好奇的男孩儿叫丹尼,他总是在探索各种秘密。", + "{0.01->0.54}Danger.": "{0.01->0.54}危险,", + "{0.03->2.10}Just stim me, I'm good to go!": "{0.00->2.16}给我一针,我还能打!", + "{0.02->1.72}Shoot them! Shoot them!": "{0.02->1.72}快打它们!快打呀!", + "{0.00->0.67}Hold Position!": "{0.00->0.67}原地待命。", + "{0.03->0.91}Calling in an Eagle.": "{0.03->0.91}呼叫“飞鹰”。", + "{0.00->0.42}South.": "{0.00->0.42}南边,", + "{0.00->0.36}Eight.": "{0.00->0.36}八。", + "{0.00->1.30}Glory to Super Earth. {2.02->4.40}Death to the dogmatic Illuminate cult.": "{0.00->1.30}荣光属于超级地球,{2.02->4.40}而光能者异端必将灭亡。", + "{0.03->3.09}If I were a Helldiver, I think my favorite enemy to kill would be the Bugs.": "{0.03->1.19}我要是绝地潜兵,{1.36->3.34}我最喜欢杀的敌人应该是虫族。", + "{0.00->4.66}Super Earth has created the most advanced weaponry in the galaxy. {5.06->7.85}Our power is in your hands.": "{0.00->4.66}超级地球已经造出全星系最先进的武器。{4.71->8.30}这份力量就掌握在你的手中。", + "{0.03->1.37}We can't stay here!": "{0.00->1.33}这里待不了了!", + "{0.00->6.27}This planet has been liberated. Extract now, so we may push on to the next battleground.": "{0.00->2.80}这颗星球已得到解放。{2.80->6.27}立即撤离,向下一个战场进发。", + "{0.00->1.68}Rare sample acquired.": "{0.00->1.68}稀有样本到手了。", + "{0.05->2.78}Cyberstan was the sinister headquarters{2.78->6.80}from which the Cyborgs led their brutal assault upon Freedom{6.80->8.65}in the First Galactic War.{9.60->12.38}They were repelled and defeated;{12.38->18.19}now, they seek once more to establish dominion over Humanity.": "{0.05->3.51}生化斯坦曾经是邪恶的总部,{3.97->11.07}第一次星系战争时,生化人就是从那里发起了对自由的残酷攻击。{11.49->18.11}我方当时击退并打败了它们;而现在,它们再次企图统治人类。", + "{0.01->0.68}Nice.": "{0.01->0.68}很好。", + "{0.00->1.83}Democracy's finest.": "{0.00->1.83}你是民主的精英。", + "{0.01->1.03}Throwing grenade!": "{0.07->1.00}投掷手雷!", + "{0.02->0.56}Done.": "{0.02->0.56}搞定。", + "{0.00->2.70}I will protect Democracy at all costs.": "{0.00->2.70}不惜一切,捍卫民主。", + "{0.00->1.91}Don't you go dying on me!": "{0.00->1.90}别想在我面前死去!", + "{0.00->3.43}5 minutes remaining. I repeat, 5 minutes remaining.": "{0.00->3.43}还剩5分钟。重复,还剩5分钟。", + "{0.01->3.50}They don't have object permanence! Hide!": "{0.01->3.18}它们没脑子!我们只要躲起来就好!", + "{0.13->2.66}The Gloom remains unfree, its{3.30->5.76}resources unexploited.": "{0.13->2.66}阴霾还未散去,{3.30->5.76}资源尚待开发。", + "{0.00->0.95}Engaging terminal.": "{0.00->0.95}操作终端。", + "{0.00->1.41}Requesting tac-pack.": "{0.00->1.41}请求投放战术背包。", + "{0.00->0.92}Bug tunnel breach.": "{0.00->1.04}虫族隧道洞口,", + "{0.02->0.74}You're here!": "{0.02->0.74}你们来了!", + "{0.00->0.57}Love that. I LOVE that.": "{0.00->2.01}喜欢这个。爱死了。", + "{0.02->1.28}Keep up the pressure!": "{0.02->1.28}继续推进!", + "{0.01->1.36}My ears are ringing!": "{0.24->1.36}我要聋了!", + "{0.00->2.02}A REAL Helldiver!": "{0.00->1.35}真正的绝地潜兵。", + "{0.02->1.48}The Luxuriant System": "{0.02->1.06}富源星系", + "{0.00->0.66}Will do!": "{0.00->0.66}好的!", + "{0.00->1.12}Sending in an Eagle.": "{0.00->1.12}请求出动“飞鹰”。", + "{0.01->3.10}Sweet Liberty I wanna see what this baby can do!": "{0.01->3.10}一起来瞧瞧这超级宝贝的威力!", + "{0.00->1.33}The Omicron system": "{0.00->1.33}奥密克戎星系", + "{0.03->1.81}Flank 'em, go, go!": "{0.00->1.91}包抄他们,上上上!", + "{0.00->0.48}No!": "{0.00->0.48}没办法!", + "{0.03->1.95}Automaton Outpost destroyed.": "{0.03->1.95}已摧毁机器人哨站。", + "{0.13->5.22}The Cyborgs will recognize the Bastion Tank from the First Galactic War.{5.84->12.64}As ancient enemies resurface, we raise once more the weapons of our forefathers.": "{0.13->5.74}生化人肯定认出第一次星系战争中的堡垒坦克。{6.30->12.58}宿敌重新现身,我们也要再次举起先辈的武器。", + "{0.00->0.39}Deep{0.83->1.50}breaths.{2.29->2.81}Calm{3.54->4.76}mind.": "{0.00->1.95}深呼吸。{3.10->4.50}冷静。", + "{0.00->0.65}Injury? {1.05->1.95}What injury!": "{0.00->1.97}受伤?哪儿来的伤!", + "{0.00->3.02}Go go go!": "{0.87->3.34}赶紧走!走!", + "{0.04->1.99}Freedom will steady any ship.": "{0.04->1.99}自由驶得万年船。", + "{0.16->0.78}300 meters.": "{0.02->0.78}300米。", + "{0.00->0.38}No!": "{0.00->0.38}不行!", + "{0.00->0.93}You will never destroy our way of life.": "{0.00->2.03}生存正道坚不可摧。", + "{0.01->1.61}WHOA—that was loud!": "{0.01->2.18}哇,声音也太大了吧!", + "{0.00->1.73}It's the Helldivers!": "{0.00->1.29}是绝地潜兵!", + "{0.01->2.26}Don't worry. The Helldivers are here.": "{0.01->2.26}不用担心。绝地潜兵在这。", + "{0.00->0.93}Super Earth": "{0.00->0.93}超级地球", + "{0.00->4.37}We will not allow the Void to steal planets from our citizens.": "{0.00->4.37}绝不容许寂域夺走属于公民们的星球。", + "{0.00->1.57}The Kneth Port system": "{0.00->1.69}克奈斯港星系", + "{0.17->1.45}The Regnus system": "{0.00->1.45}雷格努斯星系", + "{0.00->0.57}Don't need it.": "{0.00->0.63}不需要。", + "{0.02->4.31}They, uh, can't take us all! FIRE!": "{0.00->2.80}开火,用火力压制它们!{2.87->4.24}开火!", + "{0.00->1.69}Eagle 1 is in the skies.": "{0.00->1.69}“飞鹰”1号空中待命。", + "{0.89->1.76}Where did that come from!?": "{0.77->1.73}那是从哪来的!?", + "{0.01->1.97}The socialists are here!": "{0.01->1.97}铁皮军来了!", + "{0.03->1.78}Get back, you filthy squids!": "{0.03->1.78}恶心的鱿鱼,滚开!", + "{0.00->0.52}4!": "{0.00->0.52}四!", + "{0.01->1.95}May its colors never bleed.": "{0.00->2.07}愿旗帜永不褪色。", + "{0.00->1.27}Indeed, Helldiver.": "{0.00->1.39}确实如此,绝地潜兵。", + "{0.01->0.73}Moving out!": "{0.01->0.73}进攻!", + "{0.00->3.18}Welcome aboard, deliverers of Democracy.": "{0.00->2.92}欢迎民主的传播者。", + "{0.00->2.78}I'm hoping to raise my Citizenship level by the time I retire.{3.15->6.25}If I ever have kids, I'd want them to be able to purchase a small pet someday.": "{0.00->2.32}我希望能在退休前提高公民等级。{2.51->6.13}假如我有了孩子,希望他们有朝一日能买一只小宠物。", + "{0.00->4.62}Today you've carved another foothold in the long climb to Liberty.": "{0.00->4.62}在实现解放的漫漫征途上,你又开拓了一个立足之地。", + "{0.00->0.50}Sending out an SOS!": "{0.00->1.19}部署求助信标!", + "{0.04->1.17}Get behind cover!": "{0.00->1.21}快速寻找掩体!", + "{0.00->1.57}Seems I still have much to learn.": "{0.00->1.64}我要学的还有很多。", + "{0.02->2.21}Good riddance, malware breath!": "{0.02->2.03}病毒走好不送!", + "{0.00->4.60}An invasion force threatens a planet of the Federation. It needs our aid.": "{0.00->4.60}入侵势力威胁到了联邦的一个星球。那里需要我们的援助。", + "{0.00->1.50}The Nublaria system": "{0.00->1.50}努布拉里亚星系", + "{0.04->2.21}Sometimes I wish it was me out there,{2.75->5.68} driving my own Bastion Tank into the heart of Cyberstan. {7.14->9.73}But then I repeat my Assignment Gratitude Mantra, {9.73->10.43}and bottle those{10.43->11.11}selfish wishes{11.11->11.67} right up.": "{0.04->2.21}有时候我真希望我也在前线,{2.73->5.79}驾驶着堡垒坦克直捣生化斯坦腹地。{7.17->9.22}然后我就会朗读岗位感谢准则,{9.49->11.60}把这些自私的想法统统压下去。", + "{0.00->2.89}5 minutes left. Liberty speed your step, Helldiver.": "{0.00->2.89}还剩5分钟。绝地潜兵,加快脚步。", + "{0.00->1.78}Move, move, move!": "{0.00->1.84}快点儿,快,快!", + "{0.00->1.10}What are those things?": "{0.00->1.21}那都是什么鬼东西。", + "{0.00->1.66}The Vernen Wells system": "{0.00->1.66}佛农井星系", + "{0.00->4.48}Let us dispense with the lingering vestiges of the Automaton resistence.": "{0.00->4.48}我们要彻底消灭机器人的残余抵抗势力。", + "{0.02->1.45}I'll remember this forever.": "{0.02->1.45}我会永远记住你们的。", + "{2.55->5.91}The automatons have stolen something precious from us.{6.90->10.87}Your mission: retrieve it. Or die trying.{11.62->16.10}Of all the wonders humanity has achieved, the one that cannot remain{16.11->19.28}in enemy hands is, without question:{19.55->21.04}Eagle Sweat.{21.54->26.50}With patented nano-fragrance technology that literally rewrites your DNA{27.02->31.38}to make you smell like a hero of the federation.{32.35->37.13}Eagle Sweat. Don't just smell it. Live it.": "{2.55->5.91}机器人从我们手中偷走了一样宝贵的东西。{6.90->10.87}你的任务就是拼死也要把它夺回来。{11.62->14.21}在人类创造的诸多奇迹之中,{14.60->19.28}唯有这一项是无论如何也不能让敌人夺走的:{19.55->26.62}飞鹰香汗。专利纳米芳香技术,真正改写你的DNA,{27.06->31.12}让你散发出联邦英雄的芬芳。{32.58->37.49}飞鹰香汗。闻着香,更要活得香。", + "{0.05->2.77}Can't Liberate with this broken arm.": "{0.05->2.58}受伤的胳膊还怎么解放!", + "{0.05->1.52}Liberty protect me!": "{0.00->1.61}解放护佑着我!", + "{0.01->1.73}I'm bleeding out!": "{0.01->1.73}我流血了!", + "{0.00->2.89}SEAF taking heavy casualties; reinforcements requested.": "{0.00->2.98}超级地球武装部队伤亡惨重,已请求增援。", + "{0.03->1.04}Mindless freaks!": "{0.03->1.04}没脑子的东西!", + "{0.00->2.45}Our city must be reclaimed.": "{0.00->2.45}我们一定要收复城市。", + "{0.00->0.60}How about a nice cup of Liber-tea!": "{0.00->2.42}一盅陈茶敬自由!", + "{0.62->0.88}Flag-forsaken{1.59->2.42}robots!": "{0.00->2.10}一堆破铜烂铁!", + "{0.02->3.91}Space travel bein' in 3 dimensions an' all, you'd think it'd get confusing keepin' track of where {3.91->4.54}everything's at.": "{0.00->1.52}太空旅行是三维的,{1.61->4.54}所以你可能会觉得很容易混淆各种事物的方位。", + "{0.70->3.10}Helldiver's got it! He's got it!": "{0.00->2.14}噢,绝地潜兵成功了,{2.15->3.30}他成功了!", + "{0.09->6.42}Cyberstan is free again. Soon, the Cyborgs will be back to their rehabilitative labor.": "{0.09->1.87}生化斯坦重获自由了。{2.64->5.70}很快,生化人就会重新投入劳动改造。", + "{0.05->9.23}Load up, soldier, because playtime's over. You've reached your final test. THIS—is the REAL DEAL. {9.57->10.35}Get to it!": "{0.05->9.23}做好准备,士兵,过家家时间结束了。你即将面对最后的考验。这就是真正的挑战。{9.57->10.35}上吧!", + "{0.00->1.40}The Alathfar system": "{0.00->1.40}织女增三星系", + "{0.00->2.62}Freedom, straight to the veins!": "{0.00->2.85}将自由注入静脉!", + "{0.00->0.96}My leg!": "{0.00->0.96}我的腿!", + "{0.03->1.02}Falling back.": "{0.00->1.11}立即撤退!", + "{0.03->1.85}Have a taste of Democracy!": "{0.03->1.85}尝尝民主的滋味儿!", + "{0.00->1.01}Much appreciated.": "{0.00->1.44}对此感激不尽。", + "{0.00->1.78}The Dunoonia System": "{0.00->1.45}顿诺尼亚星系", + "{0.00->1.29}Activating jump pack.": "{0.00->1.30}启动喷射背包。", + "{0.06->2.32}KILL EM ALLLLLLL!!!": "{0.06->2.32}全都得死!!!", + "{0.03->1.83}We'll make 'em pay!": "{0.00->1.90}让它们血债血偿!", + "{0.01->1.50}For prosperity!": "{0.01->1.30}为了繁荣!", + "{0.00->0.96}Democracy{1.76->2.60}cannot{3.00->4.78}be denied...": "{0.00->0.89}民主{1.76->2.95}无可{3.28->4.75}抵挡…", + "{0.00->0.85}Entering shuttle.": "{0.00->0.85}进入运输船。", + "{0.00->0.99}Need to reload!": "{0.00->0.99}需要换弹!", + "{0.01->0.69}Help me..!": "{0.01->0.69}救救我…!", + "{0.00->1.31}I will make you proud!": "{0.00->1.56}我会让你刮目相看!", + "{0.00->1.42}SEAF extraction complete.": "{0.00->1.50}武装部队完成撤离。", + "{0.00->1.41}The Gile System": "{0.00->1.14}吉尔星系", + "{0.00->0.90}Stratagem beacon.": "{0.00->0.90}战略配备信标,", + "{0.04->3.59}The Cyborgs have a perverse predisposition for violence.{4.00->5.33}If we're going to stamp them out,{5.94->7.82}we're going to need a lot of bullets.": "{0.04->2.27}生化人全都是天生的暴力狂。{2.99->4.44}要想彻底消灭它们,{5.04->6.85}我们得准备大量的弹药。", + "{0.03->1.37}That's what you deserve!": "{0.03->1.37}这是你们应得的!", + "{0.00->1.38}Reloading support weapon.": "{0.00->1.38}在给支援武器换弹。", + "{0.00->1.18}Soldiers!": "{0.00->0.79}战士们!", + "{0.00->8.40}Do not think of Rebels as fellow humans. If our ideals are alien to them, then they are aliens to {8.47->8.95}us.": "{0.00->2.55}不要把叛徒当作人类同胞。{3.26->5.41}如果他们容不下我们的理念,{5.89->8.85}我们自然也容不下他们。", + "{0.00->0.84}Gotta reload!": "{0.00->0.84}得换弹了!", + "{0.02->1.71}Super Earth reigns!": "{0.00->1.86}超级地球一统天下!", + "{0.00->0.58}Four.": "{0.00->0.58}四。", + "{0.02->1.31}Incoming!": "{0.00->1.34}要来了!", + "{0.02->5.60}Ah! The Flag... mind on the Flag...": "{0.00->2.85}啊!想旗帜……{3.26->5.73}专心想旗帜……", + "{0.00->2.38}New canister for maximum Liberation.": "{0.00->2.73}新燃料罐,全力实现解放。", + "{0.00->1.85}They've planted mines here!": "{0.00->1.85}敌人在这里埋了地雷!", + "{0.08->2.32}It is as we feared, Helldiver. {2.81->6.70}The better part of the Illuminate have remained trapped outside the galaxy. {7.34->9.66}They cannot be allowed to return.": "{0.00->1.22}绝地潜兵,{1.45->6.84}不出所料,光能者的主力仍被困在银河系之外,{7.42->9.19}绝不能让他们回归。", + "{0.00->1.35}Requesting sentry.": "{0.00->1.19}请求哨戒炮。", + "{0.01->1.69}Can't get past!": "{0.85->1.85}这边过不去!", + "{0.00->2.30}Live long enough and anything can happen.": "{0.00->2.62}只要活得够久,什么都能见到。", + "{0.01->1.27}Enemy heading this way!": "{0.01->1.08}敌人往这边来了!", + "{0.04->2.17}Mindless freaks!": "{0.04->2.17}没脑子的玩意儿!", + "{0.00->1.95}It was never alive to begin with.": "{0.00->2.20}有的东西就不配活着。", + "{0.00->3.14}For all citizens! Open fire!": "{0.00->3.01}为了全体公民!开火!", + "{0.02->2.69}DEATH TO ENEMIES OF DEMOCRACY!": "{0.02->2.69}民主的敌人,去死吧!", + "{0.02->0.89}Here!": "{0.02->0.89}拿着!", + "{0.00->3.92}The Illuminate pay a heavy price for their machinations.": "{0.00->3.92}光能者为阴谋诡计付出了沉重代价。", + "{0.00->0.55}Package.": "{0.00->0.55}物品,", + "{0.00->4.87}You may have won countless battles, but how many thought crimes have you reported? {5.23->10.85}Remember, REAL heroes fight on every front—including the front within.": "{0.00->2.29}你或许打赢过无数场战斗,{2.92->5.27}但是举报过多少起思想犯罪?{5.79->11.41}切记,真正的英雄会坚守每一条战线,包括思想战线。", + "{0.01->0.71}Reloading.": "{0.01->0.71}换弹。", + "{0.00->1.54}Freedom wins again.": "{0.00->2.08}自由再次得胜。", + "{0.00->1.27}The Skaash system": "{0.00->1.27}斯卡什星系", + "{0.00->3.00}Even though the First Galactic War ended almost 100 years ago, {3.46->7.25}we're still enjoying the Freedom those heroes fought and died for. {8.03->9.52}Maybe in another 100 years, {9.95->11.65}our descendants will be doing the same.": "{0.00->2.32}第一次星系战争已经过去一百年了,{2.55->7.31}但直到今天,那些英雄拼死求得的自由仍在泽被后世。{7.79->9.77}或许,再过一百年后,{9.93->12.57}我们的子孙后代也能同享恩泽。", + "{0.00->2.93}In recognition of our contribution to the war effort.": "{0.00->2.93}这是对战场上英勇表现的表彰。", + "{0.04->2.22}Hot dog! What a day!": "{0.00->2.31}热狗!美好的一天!", + "{0.02->1.05}Requesting orbital.": "{0.02->1.05}请求轨道攻击。", + "{0.03->0.88}Save me!": "{0.03->0.88}救我!", + "{0.00->1.18}We're safe!": "{0.00->1.42}我们没事了!", + "{0.02->1.96}Mindless freaks!": "{0.02->1.96}没脑子的东西!", + "{0.03->1.07}Taking position.": "{0.00->1.09}各就各位。", + "{0.05->2.48}Seems I still have much to learn.": "{0.00->2.54}我要学的还有很多。", + "{0.00->0.88}Welcome back. {1.35->4.67}Those friendly fire incidents were entirely unavoidable.": "{0.00->0.95}欢迎回来。{1.57->3.55}误伤友军总是在所难免。", + "{0.00->0.74}Incredible,{1.21->2.77}just—wow!": "{0.00->1.94}厉害,简直了,{1.95->3.13}哇!", + "{0.03->1.56}Swapping battery.": "{0.03->1.56}换下电池。", + "{0.04->3.28}Incredible, just—wow!": "{0.00->3.25}厉害,简直了,哇!", + "{0.00->0.29}Here?": "{0.00->0.50}这里?", + "{0.03->0.42}Done.": "{0.03->0.42}搞定。", + "{0.20->1.69}Get liberated!": "{0.00->1.79}我来解放你!", + "{0.00->0.28}Here?": "{0.00->0.28}这里?", + "{0.04->1.91}Illuminate Outpost destroyed.": "{0.04->1.91}已摧毁光能者哨站。", + "{0.00->1.59}Calling down fortifications.": "{0.00->1.59}请求部署防御工事。", + "{0.01->1.52}Get it away from me!": "{0.01->1.52}别,别让他们过来!", + "{0.03->0.69}Spread out!": "{0.00->0.80}立即散开!", + "{0.03->1.20}Spread out!": "{0.00->1.29}立即散开!", + "{0.02->1.50}Time to shut this down.": "{0.00->1.48}是时候做个了结了。", + "{0.63->5.57}Now, all those old theme parks have been re-converted back into tank factories. The fairy towers{5.57->6.56}are chimneys again,{6.96->9.14}huffing and puffing in service to the war machine.{9.80->11.38}All thanks to you, Helldiver!": "{0.00->3.73}现在,那些老主题公园又都改回坦克工厂了。{4.39->5.97}童话塔楼又变成了烟囱,{6.22->8.21}呼哧呼哧地为战争机器效力。{8.95->11.04}绝地潜兵,这都要感谢你!", + "{0.18->1.65}WATCH OUT!": "{0.00->1.70}小心!", + "{0.00->0.55}Engaging.": "{0.00->0.55}打这个。", + "{0.03->1.47}Preparing explosives.": "{0.00->1.60}快去把炸药准备好。", + "{0.00->1.55}Operation complete.": "{0.00->1.55}行动完成。", + "{0.00->1.10}I'll do my best!": "{0.00->1.27}我一定尽全力!", + "{0.01->1.20}Maintain the pressure!": "{0.01->1.20}保持压力!", + "{0.01->1.40}We're going this way now!": "{0.01->0.96}我们走这边!", + "{0.08->1.68}The Amittere System": "{0.08->1.40}亚米逝地星系", + "{0.00->3.54}This operation would strike a mighty blow against the enemy.": "{0.00->3.54}此次行动将会重创敌方要害。", + "{0.00->1.23}Coordinates locked.": "{0.00->1.23}坐标已锁定。", + "{0.02->1.63}The Solghast system": "{0.02->1.63}索尔加斯特星系", + "{0.00->1.50}The Ursica system": "{0.00->1.50}厄西卡星系", + "{0.05->2.77}I'm pinned!": "{1.43->2.89}遭到压制!", + "{0.00->1.56}No friendly fire incidents. {2.07->3.03}Well done.": "{0.00->1.39}没有误伤友方。{1.64->2.56}很好。", + "{0.03->1.27}Take cover!": "{0.00->1.28}找掩护!", + "{0.01->0.71}I can't!": "{0.01->0.88}没办法!", + "{0.00->1.26}Reinforcement available.": "{0.00->1.26}增援准备就绪。", + "{0.00->5.03}We will return, and plunge the depths of the Archives without fear.": "{0.00->5.03}有朝一日我们一定会回来,继续勇敢探索档案阁。", + "{0.03->1.53}Rally 'round the flag!": "{0.00->1.59}团结在旗帜下!", + "{0.00->4.70}The Illuminate may have created the Void, but its our territory now.": "{0.00->2.17}虽然是光能者创造了寂域,{2.32->5.15}但现在,这里属于我们。", + "{0.00->3.50}YEAH!!! HELLDIVERS ARE INVINCIBLE!!": "{0.00->3.50}牛啊!绝地潜兵无敌!!", + "{0.06->3.53}They're not my favorite fruit, personally, but it's nice just to have something different.": "{0.02->3.57}我个人不太喜欢这种水果,但能换换口味就已经不错了。", + "{0.01->1.35}Lightening Liberty's load!": "{0.01->1.35}为自由助力!", + "{0.01->1.66}Fight on, for Super Earth!": "{0.00->1.72}为了超级地球,挺住!", + "{0.00->1.17}The Caph system": "{0.00->1.17}王良一星系", + "{0.04->1.32}The Mordia system": "{0.04->1.32}摩帝亚星系", + "{0.00->0.49}Seven.": "{0.00->0.49}拐。", + "{0.00->2.88}More blood loss than manual recommends.": "{0.00->2.88}失血量超出手册建议值。", + "{0.00->1.16}The Nivel system": "{0.00->1.16}尼维尔星系", + "{0.00->1.57}I fight for Super Earth.": "{0.00->1.57}我为超级地球而战。", + "{0.00->1.62}Well done, Helldiver. {2.08->5.95}This operation will swiftly usher this planet's salvation.": "{0.00->1.62}绝地潜兵,干得好。{2.08->5.95}此次行动会让这颗星球迅速迎来救赎。", + "{0.00->2.05}Standby for SEAF quick-response team.": "{0.00->2.22}武装部队快速响应小队正在待命。", + "{0.02->1.04}Liberty!": "{0.02->1.04}解放!", + "{0.00->4.61}I'm technically the head Service Tech for all the ship's systems, and that means ALL the ship's {4.61->5.15}systems.": "{0.00->3.92}严格来说,我是舰船上所有系统的首席技术支持人员,{4.28->5.51}是所有系统哦。", + "{0.00->2.42}Real Helldivers! I don't believe it!": "{0.00->2.42}绝地潜兵,真的是绝地潜兵!", + "{0.05->1.83}Super Earth's counting on us!": "{0.00->1.80}超级地球就靠我们了!", + "{0.00->1.45}Outpost destroyed.": "{0.00->1.45}已摧毁哨站。", + "{0.00->2.64}We can't let the enemy take our cities from us.": "{0.00->2.16}绝不能让敌人夺走我们的城市。", + "{0.00->0.93}Stay sharp!": "{0.00->0.93}保持警惕!", + "{0.02->1.68}Back, everybody back!": "{0.00->1.81}后撤,全体后撤!", + "{0.03->1.37}Stims, quick!": "{0.00->1.44}给我一针,快!", + "{1.22->4.24}Is that... all you got...?": "{0.00->3.46}你就…这点本事…?", + "{0.03->1.77}Save me!": "{0.03->1.77}救我!", + "{0.00->0.44}Yes!{0.84->1.52}Kill 'em!": "{0.00->0.38}好!{0.67->1.40}杀了它们!", + "{0.00->0.81}Northwest.": "{0.00->0.81}西北,", + "{0.04->1.29}This is crazy!": "{0.04->1.29}太可怕了!", + "{0.00->2.42}Take position. Achieve the objective.": "{0.00->2.51}各就各位。争取完成任务。", + "{0.01->1.17}Might be safer here!": "{0.01->0.92}这里更安全!", + "{0.00->2.22}Take cover if you wanna live!": "{0.00->2.25}想活命就赶紧找掩体!", + "{0.04->2.16}Real Helldivers! I don't believe it!": "{0.04->2.55}绝地潜兵,真的是绝地潜兵!", + "{0.00->0.25}Get back, you filthy squids!": "{0.00->2.62}恶心的鱿鱼,滚开!", + "{0.06->1.06}Feels gooooood.": "{0.06->1.06}真他民主的爽!", + "{0.02->1.88}Death to Terminids!": "{0.02->2.15}终结族,受死吧!", + "{0.00->3.00}The Terminids spent decades content on the E-{3.41->4.31}710 farms. {4.90->9.72}Now their most destructive instincts run rampant, to the detriment of all.": "{0.00->4.63}终结族曾经在710元素农场享受了几十年的平静。{4.69->8.19}现在,它们暴露出残暴至极的本性,{8.32->10.08}想要毁灭一切。", + "{0.00->1.18}Requesting supplies.": "{0.00->1.18}请求投放补给。", + "{0.00->0.40}Four.": "{0.00->0.40}四。", + "{0.00->1.20}I've got the flag!": "{0.00->1.20}拿到旗子了!", + "{0.00->3.02}Many heroes gave their lives to Liberty today. {3.86->5.12}They will be remembered.": "{0.00->3.02}今天,很多英雄为解放献出了生命。{3.49->5.17}我们将铭记他们的奉献。", + "{0.03->1.62}The Payong System": "{0.03->1.16}庇永星系", + "{0.00->1.41}One last step.": "{0.00->1.41}只剩最后一步。", + "{0.00->2.72}Prosperous populace, there's too many of them!": "{0.00->2.84}繁荣个祖宗十八代,敌人太多了!", + "{0.04->2.93}Uh, everyone, over there—quickly!": "{0.00->3.11}呃,所有人,那边——快!", + "{0.00->4.57}FOR SUPER EAAAAARRRTTHHHH!": "{0.00->4.57}超级地球,为了超级地球!", + "{0.00->2.65}The shadow of the Illuminate grows.": "{0.00->2.65}光能者的阴影在蔓延。", + "{0.00->2.23}Swapping Internal Cooling Element.": "{0.00->2.23}更换内部冷却元件。", + "{0.00->1.23}Canister's empty.": "{0.00->1.23}燃料罐空了。", + "{0.00->0.95}Tech sample acquired.": "{0.00->0.95}科技样本到手了。", + "{0.00->4.54}The enemy is retreating from this planet. Our defense has held.": "{0.00->2.40}敌人正在撤离这颗星球。{2.40->4.54}我们成功抵御了威胁。", + "{0.00->0.93}Primary objective.": "{0.00->0.93}主要目标,", + "{0.05->4.22}Another Megacity on Super Earth has completed construction. {4.59->10.59}It brings a tear to my eye to witness the healing of our Federation's heart.": "{0.05->3.70}超级地球又建成了一座特大城市。{4.41->10.27}目睹联邦的心脏渐渐愈合,我不禁热泪盈眶。", + "{0.00->1.95}Helldivers'll get us through!": "{0.00->1.95}绝地潜兵会带我们走向胜利!", + "{0.02->2.42}Sweet Liberty, my arm!": "{0.02->2.42}我超级自由的胳膊!", + "{0.03->1.36}Thank Liberty!": "{0.03->1.36}感谢解放!", + "{0.00->1.42}The Ivis system": "{0.00->1.42}艾维斯星系", + "{0.00->0.64}I'm sorry.": "{0.00->0.64}抱歉。", + "{0.02->1.30}Is that all they got!?": "{0.02->1.30}它们就这点本事!?", + "{0.00->2.29}I feel safer already.": "{0.00->2.39}我觉得安全多了。", + "{0.00->0.76}Reinforcing.": "{0.00->0.76}请求增援。", + "{0.00->3.64}Our enemy would turn this city into a conurbation of Tyranny.{4.10->5.53}Do not let them!": "{0.00->3.64}敌人企图将这座城市变成暴政的据点。{4.10->5.53}绝不能让它们得逞!", + "{0.00->1.39}Attack underway.": "{0.00->1.39}即将进攻。", + "{0.00->1.64}Biological sample secured.": "{0.00->1.64}生物样本到手了。", + "{0.00->1.29}Vital System": "{0.03->1.13}关键星系", + "{0.02->1.64}Fall back and regroup!": "{0.00->1.69}先撤退,再集结!", + "{0.00->1.85}The power of Democracy!": "{0.00->1.85}这就是民主之力!", + "{0.05->1.96}Let's see what this thing can do!": "{0.00->1.90}瞧瞧这玩意儿的威力!", + "{0.02->1.40}Artifact collected.": "{0.02->1.40}古物到手了。", + "{0.04->2.59}Super Earth watches over us.": "{0.04->2.59}超级地球保佑。", + "{0.04->2.56}Get away from me, bot freak!": "{0.04->2.56}铁疙瘩,别靠近我!", + "{0.04->1.64}Spread out, now!": "{0.00->1.78}散开,就现在!", + "{0.08->4.32}AHHHHH HA HA HA!!": "{0.08->4.32}啊哈哈哈!!", + "{0.05->2.49}Need assistance!": "{0.58->2.63}我请求救助!", + "{0.00->1.13}Gotta swap batteries.": "{0.00->1.13}得换下电池了。", + "{0.00->1.04}Got eyes on them!": "{0.00->1.04}看到它们了!", + "{0.00->2.23}Eyes forward, we got this!": "{0.00->2.58}看前面,我们能赢!", + "{0.00->1.57}Tech sample acquired.": "{0.00->1.57}科技样本到手了。", + "{0.03->3.52}Gotta cover more ground, cover--cover the flanks.": "{0.00->1.66}得覆盖更大的区域,{1.67->3.63}掩护——掩护侧翼。", + "{0.00->1.29}A temporary setback. {1.77->2.82}We will fight on.": "{0.00->1.21}暂时挫败而已。{1.57->2.82}我们会继续战斗。", + "{0.00->1.60}Tyranny is a cancer, {1.97->3.88}and Managed Democracy is the cure. {4.60->8.02}And you, Helldiver, shall administer the antidote.": "{0.00->1.60}暴政如同癌症,{1.74->3.93}管理式民主则是良药。{4.34->8.44}而你,绝地潜兵,负责送药上门。", + "{0.02->0.60}No!": "{0.02->0.60}不!", + "{0.06->2.04}Together, we'll win!": "{0.00->2.01}团结就是胜利!", + "{0.00->2.13}Dirty bug got what it deserved.": "{0.00->2.13}害虫就得杀干净。", + "{0.00->1.41}You're on your own from here, recruit. {1.83->4.23}Use your map to find your way to the training facility.": "{0.00->1.41}接下来你只能靠自己了。{1.83->4.23}依靠地图找出前往训练设施的路。", + "{0.02->3.32}Man, Professional Development Training sure is{4.17->5.03}something. {5.79->10.24}And all because some Service Technicians asked too many questions about that one strike...{11.08->13.66}But hey, at least you make a lot of friends strapped into those chairs!": "{1.41->5.39}有一说一,职业发展培训这一套下来真够呛的。{6.22->10.27}就因为有些技术维修员对那次打击行动问了太多问题……{10.89->13.72}不过,至少交了不少绑在椅子上的朋友!", + "{0.00->1.95}New battery, same way of life.": "{0.00->2.69}换电池,不换生存正道。", + "{0.03->1.00}We're saved.": "{0.03->1.00}我们得救了。", + "{0.00->1.45}You'll get what's coming.": "{0.00->1.45}你会遭报应的。", + "{0.00->0.62}Supplies.": "{0.00->0.62}补给,", + "{0.00->2.02}What a catapult of an arm! {2.53->4.26}Onto the next section!": "{0.00->2.02}你的手臂抡的很标准!{2.53->4.26}去下一个区域吧!", + "{0.00->3.59}No matter how dark the cave or how thick the Gloom;{4.09->5.98}Tyranny cannot hide.": "{0.00->3.59}无论洞穴多么黑暗,无论“阴霾”多么浓重,{4.09->5.98}暴政都无处可藏。", + "{0.00->2.33}It was an honor to draw with you.": "{0.06->1.67}能与你打成平手是我的荣幸。", + "{0.00->0.45}Bots.": "{0.00->0.45}机器人,", + "{0.00->1.66}I am a soldier of Liberty.": "{0.00->1.66}我是捍卫解放的战士。", + "{0.00->2.19}May its colors never bleed.": "{0.00->2.20}愿旗帜永不褪色。", + "{0.07->1.79}Get away from me!": "{0.48->1.97}不要靠近我!", + "{0.11->1.62}Thank you, Helldiver!": "{0.00->1.71}谢谢你,绝地潜兵!", + "{0.01->2.18}See that? We'll be alright!": "{0.00->2.23}看到了吗?不会有事!", + "{0.00->1.19}Stratagems selected.": "{0.00->1.19}战略配备已选定。", + "{0.00->1.23}Calling down a sentry.": "{0.00->1.23}呼叫哨戒炮。", + "{0.01->0.74}They're back!": "{0.01->0.83}它们回来了!", + "{0.00->0.52}No!": "{0.00->0.52}不行!", + "{0.00->1.47}The Wayward System": "{0.00->1.05}逸泊星系", + "{0.00->2.82}Nobody back home can believe I get to talk to Helldivers every day.": "{0.00->2.82}老家都没人相信我能每天和绝地潜兵说上话。", + "{0.03->2.10}Now that's what I call Liberty!": "{0.03->2.10}好好瞧瞧什么叫解放!", + "{0.02->1.11}Grateful for the back-up.": "{0.02->1.11}感谢你来增援。", + "{0.00->1.19}Calling down a walker.": "{0.00->1.19}呼叫步行机甲。", + "{0.00->0.80}Dead enemy.{1.34->2.94}Best thing I've seen all day.": "{0.00->0.80}敌人死了。{1.34->3.14}这是今天最好的消息。", + "{0.00->1.50}Doing our citizens{1.96->2.44}proud!": "{0.00->2.47}成为公民的骄傲!", + "{0.02->1.13}We're saved!": "{0.02->1.13}我们得救了!", + "{0.21->1.38}More bots!": "{0.21->1.38}还有机器人!", + "{0.02->2.46}Sweet Liberty, it's the Helldivers!": "{0.02->2.46}解放保佑,绝地潜兵来了!", + "{0.00->1.35}Gotta fix this Liberty-forsaken arm.": "{0.00->3.17}必须治好这条耽误解放的胳膊。", + "{0.02->1.90}Flag save us all...": "{0.00->1.88}旗帜保佑……", + "{0.03->1.42}The Andar system": "{0.03->1.42}安达尔星系", + "{0.00->2.10}We sacrifice for paradise.": "{0.00->2.09}我们为乐土而献身。", + "{0.00->0.32}Done.": "{0.00->0.39}搞定。", + "{0.02->2.24}Sweet, sweet Liberty...!": "{0.02->2.94}说好的解放呢?", + "{0.00->1.14}Live to dive another day.": "{0.00->1.14}活着才能继续效力。", + "{0.00->0.78}Grateful to be back.{1.40->2.95}And to have been gone!{3.38->6.76}You learn a lot in Professional Development Training, like{7.14->8.72}how to create better documentation,{9.26->9.59}and{10.47->12.88}how to stay focused on a projector screen for hours at a time.": "{0.00->1.13}很庆幸能回来。{1.56->2.65}也庆幸离开过!{3.64->5.98}在职业发展培训中能学到很多东西,{6.58->8.55}比如如何制作更好的文档,{9.01->11.46}以及如何一直盯着投影仪屏幕{11.74->12.80}看好几个小时。", + "{0.01->1.08}We're pinned down!": "{0.00->0.99}被压制了!", + "{0.00->0.39}West.": "{0.00->0.39}西边,", + "{0.00->3.21}Alright, 1, 2,3 here we go!": "{0.00->3.41}好了,1、2、3,我们上!", + "{0.00->1.65}Together, we'll win!": "{0.00->1.79}团结就是胜利!", + "{0.00->0.85}How much longer?": "{0.04->1.07}还得等多久?", + "{0.00->2.36}This is Eagle 1. We are back in business.": "{0.00->2.36}这里是“飞鹰”1号。我们回来了。", + "{0.02->0.87}Reloading.": "{0.02->0.87}换弹。", + "{0.00->1.28}Sending out an SOS!": "{0.00->1.28}部署求助信标!", + "{0.00->0.70}ETA T-{1.11->2.15}20 seconds.": "{0.00->1.70}预计20秒后到达。", + "{0.02->1.44}Terminids! Run!": "{0.02->1.85}终结族!快跑!", + "{0.00->0.75}Second one.": "{0.00->0.75}第二个。", + "{0.00->2.08}Let the light of Liberty shine!": "{0.06->1.63}解放照亮大地!", + "{0.00->1.92}The Malevelon Creek system": "{0.00->1.92}麦拉芬蒙河星系", + "{0.01->0.74}Found something.": "{0.01->0.74}有发现。", + "{0.00->0.45}2!": "{0.00->0.40}2!", + "{0.00->3.50}Back when I was a kid, the local Loyalty Officer would give us sweets for telling him what was {3.50->4.95}goin' on with the adults around town.": "{0.00->3.88}小时候,只要把大人们的言行举止告诉当地的忠诚事务官,{4.19->4.95}他就会给我们糖吃。", + "{0.06->8.93}Close your eyes. Picture yourself within the Hellpod. It is a mother's womb.{8.93->14.92}Inside, you are safe. You have everything you need.{14.92->19.52}You are on the way to where you belong.{19.52->24.82}You will arrive exactly when you are meant to.": "{0.00->5.65}闭上眼睛。想象自己身处绝地喷射舱内。{6.53->11.29}它就是母亲的子宫。你在里面很安全。{12.60->19.78}你拥有自己需要的一切。你正在前往自己的归宿。{20.22->24.93}你会准时抵达你想去的地方。", + "{0.00->0.82}There's something here.": "{0.00->0.82}这边有发现。", + "{0.00->3.53}Sweet Freedom! The Helldivers'll make them pay!": "{0.00->3.72}超级自由!绝地潜兵不会放过它们!", + "{0.00->4.23}Like sitting in candlelight on Heroes' Day, chanting with my family, and renewing our vows of {4.23->5.30}Citizenship together.": "{0.00->1.55}比如,在英雄日,{1.81->3.76}坐在烛光之中和家人一起吟诵,{4.04->5.51}重申我们的公民誓词。", + "{0.00->1.16}Requesting tac-pack.": "{0.00->1.16}请求投放战术背包。", + "{0.02->0.89}More Red-eyes!": "{0.02->0.89}红眼怪又来了!", + "{0.01->2.51}Class B Citizens, get behind me!": "{0.01->2.51}B级公民,躲我后面!", + "{0.00->2.19}MAN I wish I could shoot like that!": "{0.00->2.19}真希望我也有那种枪法!", + "{0.00->0.70}Aerial enemy.": "{0.00->0.70}空中敌人,", + "{0.00->1.55}Support weapon inbound.": "{0.00->1.43}支援武器马上就到。", + "{0.00->0.88}Bug outpost!": "{0.00->0.88}虫族哨站!", + "{0.00->0.83}Keep working; {1.21->5.92}voters with a higher Citizen Score receive prioritized weighting in elections.": "{0.00->1.16}努力工作吧,{1.66->6.07}你的公民评分越高,在投票选举中获得的优先权重也越高。", + "{0.00->0.59}Are we safe?": "{0.00->0.88}我们安全了吗?", + "{0.39->1.63}Gotta be another way...?": "{0.00->1.63}应该还有别的路吧……?", + "{0.00->1.03}We got your back!": "{0.00->1.03}背后有我们!", + "{0.00->1.47}Helldivers never die.": "{0.00->1.47}绝地潜兵死不了。", + "{0.02->0.77}Bugs!": "{0.02->0.77}虫族!", + "{0.01->1.06}Grenade!": "{0.01->1.06}手雷!", + "{0.00->0.70}Heading there now.": "{0.00->0.70}正在赶过去。", + "{1.06->2.72}Pain is ephemeral!{2.91->4.79}Freedom is eternal!": "{1.06->2.72}疼痛是暂时的!{2.91->4.79}自由是永恒的!", + "{0.00->0.36}I won!": "{0.00->0.83}我赢了!", + "{0.45->1.56}Not a moment too soon.": "{0.00->1.73}来得正是时候。", + "{0.00->5.75}Crack open one of the Automaton's battery packs, and you'll find bot technology is powered {5.75->8.27}exclusively by injustice.": "{0.00->2.57}如果剖开机器人的电池组,{2.88->5.37}你会发现机器人的技术进步{5.64->8.09}完全是由非正义驱动的。", + "{0.02->1.11}Found something.": "{0.02->1.11}有发现。", + "{0.00->1.24}Heroic!": "{0.00->1.31}英雄之举!", + "{0.00->1.38}Illuminate teleporting in.": "{0.00->1.65}光能者即将传送抵达,", + "{0.00->1.28}You saved us!": "{0.00->1.28}多亏了你们!", + "{0.00->0.82}Got a sample.": "{0.00->0.82}样本到手了。", + "{0.00->0.73}Fourth one.": "{0.00->0.73}第四个。", + "{0.00->1.22}Eager to obey!": "{0.00->0.93}乐意效劳!", + "{0.05->1.55}Fall back, now!": "{0.00->1.71}马上撤退,快!", + "{0.04->2.68}I heard dissidents set another weapons factory on fire.": "{0.02->2.46}听说异见分子又烧了一座武器工厂。", + "{0.00->1.53}Additional SEAF troops en route.": "{0.00->1.60}武装部队增援正在路上。", + "{0.02->1.50}Rounds on target!": "{0.00->1.56}火力覆盖!", + "{0.00->0.54}Cancel that.": "{0.00->0.54}不必了。", + "{0.00->3.11}What the--?! They took out a Helldiver!": "{0.00->3.11}什么——?!它们杀了一个绝地潜兵!", + "{0.00->0.74}Reloading you.": "{0.00->0.74}帮你换弹。", + "{0.00->1.05}Out of stims.": "{0.00->1.05}针用光了。", + "{0.03->1.31}That was a close one!": "{0.03->1.31}好他民主的险!", + "{0.03->0.70}Keep moving.": "{0.03->0.70}得赶紧走。", + "{0.00->2.78}Expunge the squids from our territory.": "{0.00->2.37}将鱿鱼彻底赶出我们的领地。", + "{0.03->2.07}Managed Democracy wins!": "{0.00->2.08}管理式民主必胜!", + "{0.00->0.82}Last reload.": "{0.00->0.82}最后的弹药。", + "{0.01->1.42}Performing assisted reload.": "{0.01->1.42}让我来帮你换弹。", + "{0.01->3.23}Helldiver -- no! Noo!": "{0.01->3.23}绝地潜兵,不!不!", + "{0.00->4.23}We may not really understand what the Void was, or how the Illuminate created it, but I'll tell you{4.23->7.48}what I do understand: that we destroyed it.": "{0.00->2.32}也许我们没有真正理解寂域的本质,{2.42->4.91}也搞不懂光能者是怎么搞出这玩意的。{5.09->7.29}但是:我们把它干掉了。", + "{0.00->1.78}Another diver for the cause.": "{0.00->1.78}又一位奉献自我的潜兵。", + "{0.00->1.32}Hold the line!": "{0.00->1.32}守住阵线!", + "{0.00->1.60}The Martyr's Bay system": "{0.00->1.60}烈士湾星系", + "{0.00->2.14}Their bodies dirty up our streets.": "{0.00->2.14}他们的尸体,把街道都弄脏了。", + "{0.03->2.01}Fire in the name of the Flag!": "{0.00->1.87}以旗帜之名,开火!", + "{0.00->2.50}Get away from me, bot freak!": "{0.00->2.50}大铁块,滚远点!", + "{0.01->1.61}Grenade!": "{0.01->1.61}手雷!", + "{0.07->2.36}Sometimes, I almost feel bad for our enemies, {2.86->4.09}livin' without Democracy. {4.93->7.76}No say over their own lives, just believin' whatever they're told. {8.64->9.19}It's sad.": "{0.00->2.10}有时候,我简直有点可怜敌人,{2.41->6.83}因为它们没有民主,不能决定自己的生活,只能人云亦云。{7.30->8.76}真是悲哀。", + "{0.00->2.54}I am but a conduit for the Ministry of Truth, {3.09->6.29}which is itself but a conduit for Managed Democracy.": "{0.00->2.24}我只是在传播真理部的观点,{2.93->6.29}而真理部则是管理式民主的传播者。", + "{0.00->0.80}Entering shuttle.": "{0.00->0.85}进入运输船。", + "{0.04->0.97}Minefield!!": "{0.00->1.04}小心雷区!!", + "{0.02->1.21}For Prosperity.": "{0.00->1.24}为了繁荣。", + "{0.03->6.16}That's the stuff! Now, use a Resupply Stratagem to get yourself some more ammo!": "{0.03->6.16}非常好!现在,用一次重新补给战略配备,补充一些弹药!", + "{0.00->1.58}The Pipionem System": "{0.00->1.12}雏鸣星系", + "{0.00->2.23}Hope Sarge didn't see that...": "{0.84->2.73}希望中士没发现…", + "{0.00->0.70}Never doubt!": "{0.07->0.93}绝对忠诚!", + "{0.00->0.92}Tagging location.": "{0.00->0.85}标记位置,", + "{0.00->1.66}You deserve a statue.": "{0.00->1.86}应该给你立一座雕像。", + "{0.02->0.74}I've got you.": "{0.02->0.74}我来帮你。", + "{0.00->2.20}Look alive, demo-time!": "{0.00->2.27}注意点,要爆破了!", + "{0.00->0.05}I can't!": "{0.00->0.05}不可以!", + "{0.00->0.62}Hellbomb.{1.07->2.17}Once that's armed...": "{0.00->0.80}地狱火炸弹。{1.36->2.10}等它激活…", + "{0.00->1.43}Requesting vehicle!": "{0.00->1.43}请求载具!", + "{0.02->1.98}The Helldivers came for us!": "{0.02->1.98}绝地潜兵来救我们了!", + "{0.02->0.62}Bugs.": "{0.02->0.62}虫族。", + "{0.00->1.64}Requesting sentry.": "{0.00->1.64}请求哨戒炮。", + "{0.00->0.46}Alpha": "{0.00->0.46}A", + "{0.05->1.49}Freedom be with you, Helldiver.": "{0.05->1.76}自由与你同在。", + "{0.00->1.18}Enemy outpost spotted. {1.62->2.34}Look alive.": "{0.00->2.44}是敌方哨站,小心有敌人。", + "{0.03->2.81}Together even in this. Imagine that.": "{0.00->1.93}这也是并肩作战。{1.94->2.99}谁能想到呢。", + "{3.52->5.58}Hahahahaha!": "{0.08->5.58}啊哈哈哈!!", + "{0.02->3.63}Thank you Helldiver, really. I never thought...": "{0.00->2.47}绝地潜兵,真心感谢。{2.47->3.70}我从没想过……", + "{0.00->1.18}Objective secured.": "{0.00->1.18}已确保目标安全。", + "{0.00->0.99}For Justice!": "{0.00->0.99}为了正义!", + "{0.00->0.98}Nothing in the chamber.": "{0.00->0.98}子弹都打光了。", + "{0.00->2.80}Their bodies will burn with the city itself.": "{0.00->3.29}他们的身躯将与城市一同燃烧。", + "{0.04->1.45}The Aquila System": "{0.04->1.16}天鹰星系", + "{0.00->1.62}I am the one who walks.": "{0.00->1.62}我就是步行机甲。", + "{0.06->2.81}Another great day for Democracy.": "{0.00->2.82}民主又迎来了美好的一天。", + "{0.00->2.05}The Pine Tar System": "{0.00->1.17}松焦星系", + "{0.03->1.29}How does this even work...": "{0.00->1.28}这玩意儿到底怎么用……", + "{0.00->1.81}Our way of life must be protected.": "{0.00->1.81}守护正道,人人有责。", + "{0.00->0.92}Eat lead!": "{0.00->1.04}吃枪子儿吧!", + "{0.03->1.02}There's too many!": "{0.00->1.09}敌人太多了!", + "{2.77->5.62}Professional Development Training can be tough as nails, but{6.21->7.78}I knew our Service Technician could do it.": "{2.35->4.67}职业发展培训可能无比严苛,{4.96->8.41}但我知道我们的维修技术员能挺过去。", + "{0.00->2.53}They did their part. Now it's our turn.": "{0.00->2.79}他们完成了自己的使命。现在到我们了!", + "{0.43->2.18}I still have to pinch myself sometimes.": "{0.05->2.23}我现在都还是不太敢相信。", + "{0.33->2.72}That's what happens when the Helldivers arrive!": "{0.00->2.74}这场面,还是得绝地潜兵出手!", + "{0.02->2.76}Hot hotdogs! That was awesome!": "{0.00->2.83}哇热狗!实在太精彩了!", + "{0.01->1.37}Don't let them see you.": "{0.01->1.37}别被它们看到。", + "{0.00->0.81}The power of a{1.46->2.40}Helldiver...": "{0.00->2.46}这就是绝地潜兵的力量……", + "{0.00->4.75}This planet is choked by the smog of Cyborg Megafactories.": "{0.00->4.75}这颗星球被生化人超大型工厂的烟雾所笼罩。", + "{0.00->0.95}Requesting vehicle!": "{0.00->0.95}请求载具!", + "{0.00->1.13}Nothing in the chamber.": "{0.00->1.13}子弹都打光了。", + "{0.00->0.57}Package.": "{0.00->0.57}物品,", + "{0.01->3.56}They might take our lives, but they'll never take our values.": "{0.01->3.56}生命诚可贵,自由价更高。", + "{0.04->1.41}Super duper!": "{0.00->1.58}这真是倍儿棒!", + "{0.00->1.37}The Mantes system": "{0.00->1.37}蒙特斯星系", + "{4.16->5.70}That Cyborg Megafactory is still standing... but not for long.": "{0.10->2.93}那座生化人超大型工厂还在……{3.52->4.94}但撑不了多久。", + "{0.00->0.49}Six.": "{0.00->0.49}六。", + "{0.02->1.63}Calling down objective equipment.": "{0.02->1.63}呼叫目标所需装备。", + "{0.01->1.79}Hostiles in my sights!": "{0.01->1.37}发现前方有敌人!", + "{0.00->1.39}Sending down Support Weapon": "{0.00->1.39}正在运送支援武器", + "{0.00->0.86}Aerial enemy.": "{0.00->0.94}空中敌人,", + "{0.00->2.81}AGH! EARS RINGING!": "{0.00->2.81}啊!要聋了!", + "{0.00->4.30}This is the largest Helldiver mobilization we've seen since the First Galactic War. {4.73->6.79}Our enemies don't know what's coming.": "{0.00->4.89}第一次星系战争结束以后,从未有过如此大规模的绝地潜兵动员。{5.17->6.91}敌人还浑然不知。", + "{0.06->0.93}Absolutely!": "{0.06->0.93}没有问题!", + "{0.00->1.97}No-one'll set this to blow anytime soon...{2.35->2.82}right?": "{0.00->1.97}这东西不会突然爆炸吧…{2.35->2.82}不会吧?", + "{0.00->1.06}Requesting sentry.": "{0.00->1.06}请求哨戒炮。", + "{0.00->0.55}Got one.": "{0.00->0.55}到手了。", + "{0.01->1.49}Requesting orbital strike!": "{0.01->1.49}请求轨道攻击!", + "{0.00->2.82}No Helldivers KIA on that mission. {3.54->5.73}This is cause for celebration.": "{0.00->2.82}没有任何绝地潜兵在任务中阵亡,{3.54->5.15}值得热烈庆祝。", + "{0.00->3.95}Upon which anvil shall Freedom's hammer fall, Helldiver?": "{0.00->3.48}绝地潜兵,自由的重锤要砸向哪里?", + "{0.01->1.03}Bug hive spotted.": "{0.01->1.03}发现虫窝。", + "{0.02->0.98}Eyes up!": "{0.02->0.98}保持警觉!", + "{0.00->1.35}The Meridia system": "{0.00->1.35}默里迪亚星系", + "{0.01->1.16}Dirty tyrant!": "{0.01->1.16}卑鄙的暴政者!", + "{0.00->1.40}I commend you.": "{0.00->1.40}你可真厉害!", + "{0.00->0.95}Helldiver.{1.51->6.48}Our efforts to eradicate the Illuminate Void have failed.": "{0.00->1.79}绝地潜兵。{2.09->6.68}根除光能者寂域的努力宣告失败。", + "{0.04->2.04}Flag-forsaken robots!": "{0.04->1.88}一堆破铜烂铁!", + "{0.00->0.88}Tagging location.": "{0.00->0.88}标记位置,", + "{0.00->2.10}We're together out here, right?": "{0.00->2.20}我们是并肩的战友,对吗?", + "{0.00->1.29}I need a team reload.": "{0.00->1.29}来人帮忙换弹。", + "{0.00->0.95}Additional objective.": "{0.00->0.95}其他目标,", + "{0.04->0.83}Helldiver. {1.32->6.22}The Terminids have spawned some foul new miasma to stain our galaxy.": "{0.04->0.89}绝地潜兵,{1.32->6.69}终结族制造出了一种新型剧毒臭气,想要荼毒银河系。", + "{0.00->1.52}Time to shut this down.": "{0.00->1.68}是时候做个了结了。", + "{0.00->0.89}Got one.": "{0.00->0.76}到手了。", + "{0.00->8.25}Helldiver. Sites of ancient Illuminate ruins, long abandoned, now thrum with despotic activity.": "{0.00->1.07}绝地潜兵。{1.48->8.40}古老的光能者遗址在长期荒废之后,如今又响起了暴政的轰鸣声。", + "{0.02->0.79}Understood.": "{0.02->0.59}明白。", + "{0.00->1.65}The Darrowsport system": "{0.00->1.65}达罗斯波特星系", + "{0.00->1.68}That'll teach those secessionists!": "{0.00->1.73}分裂分子该长记性了!", + "{0.02->2.06}That should go on a cape!": "{0.00->2.27}完全值得绣一面披风!", + "{0.00->1.88}Long ship deployments are great for savin' up.": "{0.00->2.06}长期随舰服役很容易攒下钱。", + "{0.00->1.09}Hold firm!": "{0.00->1.09}坚持住!", + "{0.00->1.87}Return the squids to oblivion.": "{0.00->1.87}彻底清除鱿鱼。", + "{0.95->1.94}The Automatons. {2.53->4.38}Heartless killing machines. {5.21->9.04}It is an undeniable fact that they do not have hearts. {9.66->11.58}And heart is what Super Earth {11.95->12.74}is all about. {13.46->14.95}Prove your humanity. {15.53->16.70}Show you care. {18.28->18.76}Enlist {19.22->20.99}in the Super Earth Armed Forces {21.56->23.70}and destroy the Automaton threat!": "{0.77->4.99}机器人全部都是冰冷的杀人机器。{5.21->9.04}无可否认,它们自身的心中毫无感情。{9.94->13.39}而感情正是超级地球的最大优势。{14.03->17.38}彰显你的人性、展示你的热情。{18.45->23.90}加入超级地球武装力量,消除机器人的威胁!", + "{0.00->0.95}Loadout confirmed.": "{0.00->1.07}装备配置确认。", + "{0.00->1.15}Indeed, Helldiver.": "{0.00->1.28}确实如此,绝地潜兵。", + "{0.06->2.46}I've never seen a Helldiver up close before.": "{0.06->2.46}从来没有靠绝地潜兵这么近过。", + "{0.00->2.00}This fence is restricting our Freedom!": "{0.00->2.33}围墙挡住了自由!", + "{0.00->0.76}Aerial enemy.": "{0.00->0.76}空中敌人,", + "{0.02->1.38}Step carefully!": "{0.00->1.50}小心,注意脚下!", + "{0.00->1.63}Helldivers never die.": "{0.00->1.63}绝地潜兵死不了。", + "{0.02->1.06}Enemy outpost.": "{0.02->1.06}敌方哨站。", + "{0.00->3.08}Make them pay...!": "{0.00->3.08}让它们付出代价……!", + "{0.00->0.88}Are we nearly there?": "{0.00->0.88}快到了吗?", + "{0.00->1.41}Liberty will prevail.": "{0.00->1.41}解放必胜。", + "{0.00->0.28}Here.": "{0.00->0.28}给你!", + "{0.07->1.23}Super Uranium. {1.64->4.08}Defier of gravity and extremely safe.": "{0.07->0.73}超铀,{0.83->4.08}超抗重力,超安全,超好用。", + "{0.00->1.20}I hope it hurt.": "{0.00->1.20}这下够狠了吧。", + "{0.03->3.33}Fan out, we're fanning out, just like at training.": "{0.00->3.56}散开,所有人摆开阵型,就像训练时那样。", + "{0.03->1.35}The bugs are coming!": "{0.03->1.35}虫族来了!", + "{0.03->2.97}That thing you want? Go ahead, buy it. {3.34->5.17}That's how you support the economy. {5.61->8.08}That's how you support Super Earth.": "{0.03->3.29}想买东西?别犹豫,想买就买。{3.75->5.14}为了支持经济发展,{5.30->8.43}支持超级地球,请尽力消费。", + "{0.03->1.79}The colors of Democracy!": "{0.00->1.85}这就是民主的色彩!", + "{0.01->1.91}Gotta find somewhere safe to wait this out.": "{0.05->1.63}得找个安全的地方躲躲。", + "{0.14->3.32}Super Earth will never fall to the likes of you!": "{0.14->3.32}你们根本不是超级地球的对手!", + "{0.00->0.95}Squid outpost.": "{0.00->0.95}鱿鱼哨站。", + "{0.01->2.73}Front-row seats to watch the Helldivers in action!": "{0.01->2.41}近距离欣赏绝地潜兵的英姿!", + "{0.00->0.38}Thank you.": "{0.00->0.38}谢谢。", + "{0.00->0.83}Manned emplacement.": "{0.00->0.83}有人的炮位,", + "{0.00->1.87}Live to dive another day.": "{0.00->2.14}活着才能效力。", + "{0.00->2.70}SEAF are on the way to help. We got your back, Helldiver.": "{0.00->2.91}武装部队支援中。绝地潜兵,增援马上到。", + "{0.00->0.79}Not engaging.": "{0.00->0.79}别打这个。", + "{0.00->0.76}Got a sample.": "{0.00->0.76}样本到手了。", + "{0.00->1.73}Support weapon inbound.": "{0.00->1.73}支援武器马上就到。", + "{0.01->1.93}Don't worry. The Helldivers are here.": "{0.01->1.93}不用担心。绝地潜兵在这。", + "{0.01->1.46}We got company!!!": "{0.01->1.46}敌人来了!!!", + "{0.01->0.98}Changing I.C.E.": "{0.01->0.98}更换冷却片。", + "{0.01->1.03}Heads on a swivel.": "{0.00->1.10}都打起精神来!", + "{0.00->2.70}It's the Helldivers! We're saved!": "{0.00->2.70}是绝地潜兵!我们得救了!", + "{0.00->1.78}I'll remember this forever.": "{0.00->1.78}我会永远记住你们的。", + "{0.03->1.03}Objective equipment.": "{0.03->1.03}那儿有目标装备,", + "{0.02->0.69}Second one.": "{0.02->0.69}第二个。", + "{0.02->0.66}I'm sorry!": "{0.02->0.66}抱歉!", + "{0.05->2.95}Flags in rags, we're advancing on Cyberstan...{2.95->5.91}just like the heroes of the first Galactic War.{5.91->8.56}This'll be something to tell the grandkids!": "{0.00->3.25}虽然旗帜很破,但我们正在向生化斯坦挺进……{3.67->5.57}和第一次星系战争的英雄一样。{6.11->8.37}这事儿啊,值得我吹上一辈子!", + "{0.00->2.05}Helldivers never die.": "{0.11->2.42}绝地潜兵死不了。", + "{0.12->1.39}How far are we going?": "{0.02->1.22}我们要走多远?", + "{0.00->1.12}Calling down a sentry.": "{0.00->1.03}呼叫哨戒炮。", + "{0.00->0.65}Got one.": "{0.00->0.65}到手了。", + "{0.06->2.63}Mines here! Watch your step!": "{0.00->2.74}这有雷!留心脚下!", + "{0.00->5.35}We cannot rest, not while Cyberstan remains in the shadow of socialism.": "{0.00->3.61}生化斯坦仍然笼罩在集权主义的阴霾之下,{3.97->5.46}我们都不能松懈。", + "{0.00->1.68}Democracy's dignity maintained.": "{0.00->1.68}已维护民主的尊严。", + "{0.04->4.24}Hm...Floor looks clean...for now.": "{0.04->4.24}嗯…地板很干净…。", + "{0.00->2.32}The Helldivers are fighting alongside us!": "{0.00->2.12}绝地潜兵和我们并肩作战!", + "{0.01->1.66}Reloading! Cover me!": "{0.01->1.66}换弹!掩护我!", + "{0.00->2.46}The Archives are sacred to the Illuminate.{2.85->5.83}Today, they will be besmirched.": "{0.00->3.06}光能者认为档案阁神圣不可侵犯。{3.69->5.83}今天,我们就要玷污那里。", + "{0.00->1.62}Reinforcement ready to fire.": "{0.00->1.62}准备派遣增援。", + "{0.00->1.27}I'll never forget this.": "{0.00->1.27}我不会忘记你们的。", + "{0.03->1.79}Need—need assistance!": "{0.00->1.82}援助……请求援助!", + "{0.00->1.47}Managed Democracy will endure.": "{0.00->2.91}管理式民主永垂不朽。", + "{0.12->5.85}Status: Liberation from Terminids underway. Helldiver support requested.": "{0.00->5.85}状态:准备解放终结族。请求绝地潜兵支援。", + "{0.00->6.51}Let them come. Let them brawl. Let them face the insurmountable might of the Helldivers.": "{0.00->3.11}让敌人尽管来犯、让敌人无能狂怒,{3.44->6.51}让敌人见识无可估量的强大威力。", + "{0.00->5.59}Did you know? The scientific term for a group of squids is \"A Massacre of Illuminate.\" {5.98->11.04}All such groups should indeed be massacred as outlined in the proactive defense initiative,{11.15->13.01}chapter 19, section d.": "{0.00->5.59}你知道吗?一群鱿鱼的专业术语是“屠族光能者”。{5.98->9.59}《积极防御倡议》第19章D小节规定,{10.20->13.01}光能者确实必须被屠族。", + "{0.03->1.31}They're trying to pin me!": "{0.00->1.36}它们想弄死我!", + "{0.03->1.90}I knew they wouldn't abandon us.": "{0.00->1.96}我就知道他们不会抛弃我们。", + "{0.00->1.38}Who's still with us!?": "{0.00->1.38}还有谁活着!?", + "{0.00->1.31}Gas strike incoming.": "{0.00->1.31}毒气攻击来了。", + "{0.00->1.65}The Fort Justice system": "{0.00->1.65}正义堡星系", + "{0.01->3.18}Oh, thank you! That was for me, right?!": "{0.00->1.84}哦,谢谢!{1.89->3.36}这是给我的?!", + "{0.03->1.32}Terminids!": "{0.03->1.32}终结族!", + "{0.00->0.37}Up.": "{0.00->0.37}上方。", + "{0.00->1.75}Squid teleportation incoming!": "{0.00->1.75}鱿鱼即将传送!", + "{0.00->1.39}The Senge system": "{0.00->1.39}新戈星系", + "{0.07->1.19}It's the Helldivers!": "{0.07->1.19}是绝地潜兵!", + "{0.00->3.03}Occupy the waypoint. Double time, soldiers.": "{0.00->1.40}占领目标点。{1.40->3.08}跑起来士兵们。", + "{0.01->3.98}Contributing... to the Cause!": "{1.80->4.44}为大业…献身!", + "{0.02->1.01}Keep shooting!": "{0.02->1.11}继续射击!", + "{0.00->1.56}Let's settle the score!": "{0.00->1.56}我们去找敌人算账!", + "{0.03->0.56}Echo": "{0.03->0.56}E", + "{0.00->6.16}Give everything to the cause! Remember, apathy is Liberty's greatest enemy.": "{0.00->2.18}为伟大事业献上一切!{2.75->6.54}切记,事不关己是解放最大的敌人。", + "{0.12->2.61}Will the shuttle have enough room for all of us?": "{0.12->2.61}运输船能装下所有人吗?", + "{0.00->5.83}The smoldering scar is all that remains of the Cyborgs tyrannical ambitions.": "{0.00->5.33}冒着烟的焦痕就是生化人暴政野心的最后痕迹。", + "{0.00->2.56}When I was a kid, I always loved All Heroes' Eve.": "{0.00->2.56}小时候,我一直特别喜欢全英雄之夜。", + "{0.00->0.85}What about here?": "{0.00->0.85}这里怎么样?", + "{0.05->2.41}Nothing will stop our way of life!": "{0.00->2.63}没什么能阻挡我们的生存正道!", + "{0.00->1.46}Democracy's elite{1.54->2.33}in action!": "{0.00->1.81}民主精英出击!", + "{0.00->2.34}Another sample collected for Democracy.": "{0.00->2.34}又为民主大业拿到了一份样本。", + "{0.04->2.28}Warning: you are leaving the mission area.": "{0.04->2.28}警告:你即将离开任务区域。", + "{0.02->2.87}Overlapping fire. Steady and true!": "{0.00->2.82}交叉火力。又稳又准!", + "{0.06->2.55}Are we—are we friends now?": "{0.00->2.61}我们——我们现在是朋友了吗?", + "{0.02->3.70}Alert: Liberation of currently orbited planet from {4.08->11.48}Terminid menace has ended in absolute victory. Planet now under Super Earth control.": "{0.00->7.67}通知:击退终结族威胁,解放当前星球的行动大获全胜。{7.73->11.48}该星球现在归超级地球统治。", + "{0.13->0.94}I got you!": "{0.00->1.08}我来救你!", + "{0.02->1.35}Team reload required.": "{0.02->1.35}给我来点弹药。", + "{0.50->1.95}Time for payback!": "{0.18->2.05}我向来有仇必报!", + "{0.00->1.43}The Mintoria system": "{0.00->1.43}敏特瑞亚星系", + "{0.00->0.44}Open fire!": "{0.00->1.17}立即开火!", + "{0.00->1.42}Engaging orbital laser.": "{0.00->1.42}准备轨道激光炮。", + "{0.00->1.34}We have to keep moving.": "{0.00->1.34}我们得继续前进。", + "{0.00->0.85}Its like you could read my thoughts.": "{0.00->1.82}你是不是会读心术啊。", + "{0.00->1.22}Dropping high-value item.": "{0.00->1.22}放下高价值物品。", + "{0.00->4.35}I heard back when they were testing 'em, one malfunctioned and sucked someone's...{4.87->6.71}well, you can imagine what happened.": "{0.00->4.78}听说当初测试的时候,有一根管道出了故障,吸走了某人的…{5.07->6.70}嗯,不难想象。", + "{0.00->1.74}Flag-forsaken robot.": "{0.00->1.74}一堆废铜烂铁。", + "{0.00->1.32}Calling in mission shuttle.": "{0.04->1.16}呼叫任务运输船。", + "{0.00->1.77}Take a moment to remember: {2.86->5.12}Super Earth loves you.": "{0.00->5.54}你要记住:超级地球爱你。", + "{0.00->0.65}Fan out.": "{0.00->0.70}散开。", + "{0.00->2.38}Ready to dispense Democracy.": "{0.00->2.38}准备好传播民主了。", + "{0.00->1.39}Calling down supplies.": "{0.00->1.74}呼叫补给。呼叫补给。", + "{0.02->3.52}Man, Helldivers are the gift that keep giving!": "{0.00->3.66}天哪,绝地潜兵无时无刻不在奉献!", + "{0.03->2.61}Civic duty at its finest.": "{0.03->1.86}看看什么叫做公民义务!", + "{0.00->1.28}Freedom five!": "{0.00->1.28}自由击掌!", + "{0.00->1.85}Deploying destructive equipment!": "{0.00->1.88}正在部署爆破装置!", + "{0.00->3.71}The bugs seek to turn this planet into another gelatinous hive. {4.18->5.78}Do not let them succeed.": "{0.00->3.71}虫族想把这颗星球也变成胶状虫窝,{4.18->5.78}别让它们得逞。", + "{0.00->1.30}The Azterra system": "{0.00->1.30}艾孜泰拉星系", + "{0.18->3.58}We do not yet know how the Voteless were created. {4.03->8.95}It seems the Illuminate wish to transform our citizens' minds and bodies. {9.65->13.82}But are these monstrosities the end of their gruesome experimentation...{14.49->16.94}or merely the beginning?": "{0.00->4.35}我们暂时对创造无票者的方式毫无了解。{4.98->8.90}光能者似乎试图改造公民的思想和身体。{9.89->14.59}但这些怪物究竟是残忍实验的终点…{15.31->17.03}还是开端?", + "{0.00->0.55}Negative!": "{0.00->0.55}没办法。", + "{0.00->1.80}Kill them! Kill them all!": "{0.00->1.80}杀了它们!都杀光!", + "{0.03->0.80}Take cover!": "{0.00->0.86}寻找掩护!", + "{0.02->1.79}For Liberty's sake, shoot them!": "{0.02->1.79}解放他大业,弄死它们!", + "{0.00->6.87}History matters! At the end of the First Galactic War, we magnanimously allowed the Illuminate to {6.87->8.15}flee the Galaxy. {8.51->10.09}Now they're back. {10.48->11.14}Why? {11.55->13.23}Because they hate peace.": "{0.00->1.33}铭记历史!{2.00->6.95}第一次星系战争结束后,我们大发慈悲放走了光能者。{7.86->13.85}可是现在它们卷土重来,只因它们憎恨和平。", + "{0.00->1.11}That's for Meridia.": "{0.00->1.11}为了默里迪亚。", + "{0.01->1.68}We're gonna be ok.": "{0.01->1.68}我们都会没事的!", + "{0.00->2.79}Helldivers! We can't lose!": "{0.00->2.79}绝地潜兵!我们不能输!", + "{0.02->0.92}Get down!": "{0.02->0.92}快趴下!", + "{0.00->1.34}The Cirrus system": "{0.00->1.34}希勒斯星系", + "{0.01->2.00}Additional extraction point located.": "{0.01->2.00}这边也发现了一个撤离点。", + "{0.00->1.57}Freedom guide us!": "{0.19->2.04}自由保佑我们!", + "{0.00->1.38}A little shot o' Liberty.": "{0.00->1.38}来一针解放精华。", + "{0.00->0.86}I'm out!": "{0.00->0.86}打光了。", + "{0.03->1.35}Get behind cover!": "{0.00->1.44}快速寻找掩体!", + "{0.00->1.11}Flank 'em, go, go!": "{0.00->1.68}包抄它们,上上上!", + "{0.00->0.98}Just in time...": "{0.00->1.33}真及时……", + "{0.96->1.67}Voting: {2.65->3.80}your Privilege {4.81->6.22}and your Duty.": "{0.96->1.65}投票:{2.55->3.61}既是权利,{4.68->6.22}也是义务。", + "{0.00->1.33}I'll remember this forever.": "{0.00->1.33}我会永远记住你们的。", + "{0.05->6.24}Argh! Always knew I'd go down... for the right... to vote...": "{0.00->3.52}啊!为了捍卫投票权,{3.53->6.33}我无怨无悔……", + "{0.00->0.54}On my way.": "{0.00->0.54}马上来。", + "{0.00->0.37}North.": "{0.00->0.43}北边,", + "{0.00->1.35}Super Uranium acquired.": "{0.00->1.35}超铀到手了。", + "{0.04->4.95}Reminder: signs of disloyalty should be reported to the Democracy Officer.": "{0.04->4.95}提示:发现不忠诚迹象,应立即上报民主官。", + "{0.02->0.77}Third one.": "{0.02->0.77}第三个。", + "{0.03->2.41}They won't like this one bit.": "{0.00->2.39}它们绝对不会喜欢这个。", + "{0.00->1.61}The Helldivers are here!": "{0.00->1.61}绝地潜兵来了!", + "{0.01->1.22}More Automatons!": "{0.01->1.22}机器人又来了!", + "{0.02->1.07}The squids are back!": "{0.02->0.94}鱿鱼回来了!", + "{0.00->1.08}At last,{1.52->5.23}the Cyborgs themselves have entered the battlefield.{5.87->10.79}No longer must we waste bullets shredding puppets on strings;{11.26->15.37}now, we battle the puppetmasters themselves.": "{0.00->4.70}这一次,生化人终于要亲自下战场了。{5.25->9.42}我们再也不用把子弹浪费在提线木偶身上了,{10.19->15.57}这一次,我们要直接把枪口对准幕后操控者。", + "{1.60->3.75}Your vote is your voice. {5.20->7.23}Don't let it go to waste.": "{1.60->3.75}投票就是发声。{5.20->7.23}不要浪费机会。", + "{0.00->0.74}I need ammo.": "{0.00->0.74}我需要弹药。", + "{0.02->0.90}Take cover!": "{0.02->0.90}快找掩体!", + "{0.02->0.97}It's the Illuminate!": "{0.02->0.97}光能者来了!", + "{0.03->0.82}What is that?": "{0.03->1.05}那到底是什么?", + "{0.00->2.02}Restoring the natural order{2.59->4.22}AND the will of the people!": "{0.00->1.93}重树天然秩序,{1.93->4.35}顺应人民意志!", + "{0.00->1.95}Tactical asset near your location.": "{0.00->1.95}你们附近有战术资产。", + "{0.00->1.51}Danger. Danger.": "{0.00->1.51}危险。危险。", + "{0.15->0.68}But soon, {1.10->5.21}Danny started to dislike his old friends, because they didn't know all the secrets he knew.": "{0.06->4.83}但是很快,丹尼开始厌恶以前的朋友们,因为他们都不知道这些秘密。", + "{0.00->1.87}We'll get Cyberstan back.{2.60->5.78}The Cyborgs will learn what happens when you refuse to submit to Freedom.": "{0.00->1.87}我们一定会夺回生化斯坦。{2.26->3.64}要让这帮生化人明白,{4.01->5.82}拒绝服从自由会是什么下场。", + "{0.07->0.93}SOS!": "{0.07->0.93}救救我!", + "{0.04->2.12}Kill them! Kill them all!": "{0.04->2.40}杀了它们!统统杀光!", + "{0.00->2.19}Lady Liberty, let me survive this...": "{0.00->2.36}自由女神啊,保佑我活下去……", + "{0.61->0.75}You {1.38->1.75}guys do this all the time. Right?": "{0.00->1.17}你们都是老手了,{1.42->1.86}对吧?", + "{0.01->2.80}Victory for Super Earth is victory for all!": "{0.01->2.80}超级地球的胜利,就是所有人的胜利!", + "{0.00->0.95}Reinforcing.": "{0.00->0.95}请求增援。", + "{0.00->1.38}Not so advanced now, huh?": "{0.00->1.96}现在还得瑟吗?嗯?", + "{0.00->3.36}We have failed to repel the enemy's assault upon this planet. {3.74->7.62}We must regroup, and break the foothold they acquired today.": "{0.00->3.36}我们之前未能击退敌人在这颗星球上的攻势。{3.74->7.62}今天,我们必须重整队伍,扫清敌人的据点。", + "{0.00->1.64}Legendarium acquired.": "{0.00->1.64}传说矿物到手了。", + "{0.00->2.55}Another strike against Tyranny!": "{0.00->2.55}精准打击暴政!", + "{0.28->1.37}Ah, that's the stuff!": "{0.00->1.55}就是这感觉!", + "{0.00->3.41}Crushed under the heel of Justice. As they should be.": "{0.00->3.41}被正义的步伐踩碎。它们活该。", + "{0.15->1.24}Freedom forever.": "{0.15->1.24}自由万岁。", + "{0.01->1.59}Manning defensive weaponry!": "{0.00->1.66}操纵防御武器!", + "{0.00->7.29}Every day, millions of soldiers have their names inscribed upon the Wall of Martyrs. {7.76->9.34}Show your support. {9.90->13.91}Purchase one of Super Earth's exclusive Martyrs Day Celebration packages!": "{0.00->7.29}英烈墙上每天都会新增数百万名士兵的名字。{7.76->9.34}为了表达哀思,{9.90->14.12}快来购买超级地球烈士纪念日特供礼包吧!", + "{0.07->1.39}The Oasis system": "{0.07->1.39}绿洲星系", + "{0.00->3.68}This planet slides further into darkness.": "{0.00->3.51}这颗星球即将没入黑暗。", + "{0.01->0.77}Understood.": "{0.01->0.77}明白。", + "{0.03->0.87}Find cover!": "{0.00->0.86}快找掩护!", + "{0.02->0.78}Moving!": "{0.00->0.80}前进!", + "{0.03->4.34}What the...? INCOMING! GO ALREADY!": "{0.00->1.41}什么……?{1.41->4.57}要来了!已经发射了!", + "{0.04->1.93}OPEN FIIIRE!!!!": "{0.00->2.04}开火,开火!!!!", + "{0.00->1.80}High-value sample collected.": "{0.00->1.80}高价值样本到手了。", + "{0.00->1.46}Calling down fortifications.": "{0.00->1.46}请求部署防御工事。", + "{0.00->1.39}The Cerberus system": "{0.00->1.39}刻耳柏洛斯星系", + "{0.00->1.15}Calling in extraction.": "{0.00->1.15}呼叫撤离。呼叫撤离。", + "{0.02->3.27}We are Democracy! We are unstoppable!": "{0.00->3.36}我们就是民主!我们势不可挡!", + "{0.05->3.88}Hh—I'm hit! Son of a—I'm hit!": "{0.00->1.79}呃——我中弹了!{1.80->3.96}他民主的……我中弹了!", + "{0.00->1.95}Abolish Tyranny!": "{0.00->1.95}废除暴政!", + "{0.00->3.74}And now, another helpful tip from General Brasch.{6.20->9.10}Young bucks always think they're invincible.{9.32->12.53}And while they are mostly right, the fact of the matter is{12.60->16.11}that Helldivers with broken arms cannot aim.{16.30->19.45}Helldivers with broken legs cannot run.{20.13->23.20}And Helldivers with serious injuries to their vital organs{23.70->27.27}will bleed out before they can say \"Death to my enemies.\"{28.39->33.54}So next time you find yourself unable to run, aim, or stay alive,{33.94->37.01}stick yourself with a STIM, soldier!{39.05->43.01}BRASCH TACTICS! Use 'em, or die trying.": "{0.00->3.74}布拉施将军又带来了一条实用提示。{6.20->9.10}年轻人总以为自己所向无敌。{9.32->12.53}虽然他们大多数时候的确没问题,{12.60->16.87}但要是断了胳膊,绝地潜兵就不能瞄准敌人,{17.16->19.59}断了腿的绝地潜兵也跑不动,{20.13->22.51}而重要器官受重伤的绝地潜兵{22.71->25.81}甚至来不及说出“敌人全都去死吧!”{25.96->28.20}就会因失血过多而亡。{28.54->32.56}士兵,假如你发现自己跑不动路、没法瞄准{32.66->34.40}或者有生命危险,{34.59->36.29}那就快用治疗剂!{39.09->40.71}布拉施亲传战术!{41.15->43.68}竭尽全力,不死不休。", + "{0.00->1.95}Freedom thanks you, Helldiver.": "{0.00->2.52}绝地潜兵,自由向你致谢。", + "{0.00->0.95}Gotta swap batteries.": "{0.00->0.95}得换下电池了。", + "{0.02->0.87}Cover, now!": "{0.00->0.90}找掩护,快!", + "{0.00->0.76}Southeast.": "{0.00->0.76}东南,", + "{0.03->1.83}The Helldivers came for us!": "{0.03->1.83}绝地潜兵来救我们了!", + "{0.02->2.08}Freedom's...fortitude!": "{0.00->2.61}自由……不屈!", + "{0.00->2.47}Extraction Request confirmed. Shuttle inbound.": "{0.00->2.47}已确认撤离请求,运输船即将抵达。", + "{0.00->1.46}Calling down equipment.": "{0.00->1.46}呼叫装备。", + "{0.04->1.54}Heads down, now!": "{0.00->1.65}快趴下,赶紧的!", + "{0.00->1.87}This will all be over soon.": "{0.00->1.87}很快就会没事的。", + "{0.00->1.45}Orbital strike incoming.": "{0.00->1.45}轨道攻击就要来了。", + "{0.00->2.20}Don't fall in love with me, okay?": "{0.00->2.29}别爱上我,好吗?", + "{0.03->1.08}Illuminate!": "{0.03->1.08}光能者!", + "{0.06->5.99}Deep in contested territory... feels right, eh Helldiver?": "{0.06->2.05}深入争夺中的腹地……{3.38->5.63}感觉不错,对吧?", + "{0.01->1.23}Move it!": "{0.00->1.32}快,跑起来!", + "{0.85->2.26}Is there a bunker around here?": "{1.04->2.43}这附近有地堡吗?", + "{0.00->1.13}And stay down!": "{0.00->1.13}趴下吧你!", + "{0.00->0.05}I got the terminal.": "{0.00->1.12}这个终端交给我。", + "{0.04->2.04}Oh no, bots!": "{0.04->2.04}天呐,是机器人!", + "{0.02->1.70}Kill it! Destroy it!": "{0.02->1.70}快杀了它!杀了它!", + "{0.00->0.81}You're here. {1.21->3.32}The galaxy awaits your salvation.": "{0.00->0.70}你来啦,{1.21->3.32}星系正等待着你去拯救。", + "{0.00->2.67}Wow. Nobody is gonna believe this.": "{0.00->3.04}哇哦。说出去都不会有人信的。", + "{0.01->2.21}Bugs! They're gonna eat us!!": "{0.01->2.81}虫子!我们会被吃掉的!", + "{0.00->2.05}Live to dive another day.": "{0.16->2.27}活着才能继续效力。", + "{0.00->0.55}I'll take it.": "{0.00->0.55}我来。", + "{0.03->1.90}Need medical attention.": "{0.73->2.11}需要医疗援助。", + "{0.00->1.30}We have to, we've gotta--run!": "{0.00->2.75}我们,我们得——赶紧跑!", + "{1.47->2.85}Feel Democracy's warm embrace!": "{0.00->2.83}感受民主的温暖拥抱!", + "{0.00->1.16}Thank you, Helldiver!": "{0.00->1.40}谢谢你,绝地潜兵!", + "{0.00->1.61}SEAF reinforcements on the way.": "{0.00->1.74}武装部队增援正在前往。", + "{0.01->1.86}Uh - For Super Earth!": "{0.00->2.21}啊…为了超级地球!", + "{0.00->1.22}Poor bastard...": "{0.00->1.22}可怜虫…", + "{0.00->1.95}Great soldiers think alike, huh, Diver?": "{0.00->2.01}英雄所见略同,对吧,潜兵?", + "{0.00->0.71}Super Earth still needs you!": "{0.00->1.99}超级地球还需要你!", + "{0.00->2.23}Keeping things running around here isn't easy, {2.60->4.57}but if that's how I can best serve Liberty, {4.96->6.37}I'll do it gladly.": "{0.00->2.58}把这里的一切安排得井井有条并不轻松,{2.83->7.16}如果这就是我为解放作贡献的最佳方式,我心甘情愿。", + "{0.00->1.45}Performing assisted reload.": "{0.00->1.45}让我来帮你换弹。", + "{0.02->1.63}Now we have a chance!": "{0.02->1.63}这下我们有胜算了!", + "{0.00->0.79}I'm on the terminal.": "{0.00->0.79}让我来操作。", + "{0.00->0.37}Yes": "{0.00->0.37}好的。", + "{0.00->1.04}Flag acquired.": "{0.00->1.04}旗帜到手了。", + "{0.00->0.80}Out of stims.": "{0.00->0.80}没针了。", + "{0.18->2.08}Over every last star!": "{0.00->2.17}吹遍宇宙繁星!", + "{0.00->7.51}Helldivers. Protectors of humanity. Paragons of democracy. Heroes to their very core. {8.13->10.20}Do you have what it takes?": "{0.00->6.83}绝地潜兵是人类的守护者,民主的典范,当之无愧的英雄。{7.28->10.40}你是否具备成为绝地潜兵的潜质?", + "{0.02->0.92}Canister's empty.": "{0.00->0.69}没燃料了。", + "{0.00->2.95}Our Class-A citizens clamor for aid.": "{0.00->2.95}A级公民亟需支援。", + "{0.02->1.59}Don't you go dying on me!": "{0.00->1.61}别想在我面前死去!", + "{0.00->0.71}Hail!": "{0.00->0.71}万岁!", + "{0.00->1.15}We're safe!": "{0.00->1.15}我们没事了!", + "{0.02->1.12}Go, go, go!": "{0.00->1.21}走,走,走!", + "{0.02->2.08}Hope Sarge didn't see that...": "{0.02->2.08}希望中士没发现…", + "{0.00->1.25}How'd you like the taste of Freedom?": "{0.00->1.49}这壶自由好喝吗?", + "{0.00->3.81}This planet calls out to be freed from the robots that enslave it. {4.40->6.86}Choose where you will shatter its shackles.": "{0.00->2.53}这颗星球渴望摆脱机器人的奴役。{3.00->6.13}请选择你要在何处打破机器人的枷锁。", + "{0.02->1.00}The bugs are coming!": "{0.02->1.00}虫族来了!", + "{0.01->1.64}They knew what they signed up for.": "{0.01->1.64}这是他们自愿的选择。", + "{0.02->0.99}Keep shooting!": "{0.02->1.07}继续射击!", + "{0.03->2.74}Another perfect day to defend Freedom.": "{0.03->2.74}又是一个保卫自由的好日子。", + "{0.00->1.24}Should be taking notes.": "{0.00->1.41}我应该做做笔记。", + "{0.01->2.42}We're not dying here! Fall back!": "{0.00->2.44}还不是死的时候!撤退!", + "{0.00->1.64}Calling down fortifications.": "{0.00->1.64}请求部署防御工事。", + "{0.01->1.19}Thank you, Helldiver!": "{0.00->1.28}谢谢你,绝地潜兵!", + "{0.00->2.90}This world is riddled with Terminid abominations. {3.54->4.92}Where will you strike first?": "{0.00->2.90}这颗星球到处都是可恶的终结族。{3.24->4.92}你要先进攻哪里?", + "{0.00->2.05}You really are incredible.": "{0.00->2.05}你们真的是太厉害了。", + "{0.03->1.62}The Alairt system": "{0.00->1.62}艾列尔特星系", + "{0.01->1.79}Peacekeeping at its finest!": "{0.01->1.79}这才叫维护和平!", + "{0.00->0.50}Sample.": "{0.00->0.50}样本,", + "{0.00->1.61}The city is lost.{2.09->5.86}Its graceful high-rise buildings, in ruins.": "{0.00->1.99}城市失守了。{2.82->5.86}高楼大厦化为废墟。", + "{0.02->1.29}More Illuminate!": "{0.02->1.29}光能者又来了!", + "{0.06->1.23}When's the shuttle coming?": "{0.06->1.23}运输船什么时候到?", + "{0.00->4.92}Even though the First Galactic War ended nearly a hundred years ago now, Managed Democracy has {4.92->7.95}stayed vigilant. Exactly for developments like these.": "{0.00->3.31}尽管第一次星系战争大约一百年前就结束了,{3.51->8.24}但管理式民主至今不曾放松警惕,正是为了应对当前的形势。", + "{0.00->4.14}Every system will soon exult in the glory of Managed Democracy.": "{0.00->4.38}很快,每个星系都会为管理式民主欢欣鼓舞。", + "{0.00->2.27}Should've stayed out of our city, scum.": "{0.00->1.94}乡下人来错地方了。", + "{0.00->3.95}Eagle 1 reporting in. Ready to bury some aliens neck-deep in Liberty.": "{0.00->3.95}“飞鹰”1号前来报告。随时准备给敌人来两发。", + "{0.00->0.88}Dropping package.": "{0.00->0.88}放下物品。", + "{0.05->3.36}Yes! ...No one's going to believe this.": "{0.00->3.39}太棒了!……说出去绝对没人会信。", + "{0.00->0.43}Ouch.": "{0.00->0.43}呃……", + "{0.00->1.32}Let's do this!": "{0.00->1.42}开干吧!", + "{0.00->3.41}Recruit expired. Request human remains disposal team.": "{0.00->3.40}新兵死亡。呼叫人类遗体清理小队。", + "{0.00->1.06}We're saved.": "{0.00->1.27}我们得救了。", + "{0.64->1.13}Please...{2.15->2.95}please...": "{0.64->1.30}求你…{2.06->3.38}求你…", + "{0.00->0.83}Local fauna.": "{0.00->0.83}当地动物。", + "{0.00->1.13}Pretty low interest rate, too.": "{0.00->1.13}租金还便宜。", + "{0.03->0.70}Follow me!": "{0.03->0.70}跟我走!", + "{0.00->0.95}Weapons ready.": "{0.00->0.95}武器就绪。", + "{0.00->2.54}None of that now. Okay, some of that.": "{0.00->1.41}先别了吧。{1.42->2.72}好吧,也行。", + "{0.03->1.22}Advancing!": "{0.00->1.25}继续推进!", + "{0.00->1.76}My life for Super Earth!": "{0.00->1.76}为超级地球献身!", + "{0.03->1.56}Get it off of me!": "{0.03->1.56}快把它搞走!", + "{0.02->2.58}The invaders are here!": "{1.13->2.28}敌人过来了!", + "{0.00->0.58}Got one.": "{0.00->0.58}到手了。", + "{0.00->1.31}Rare sample acquired.": "{0.00->1.31}稀有样本到手了。", + "{0.00->2.14}Ready for another mission, Helldiver?": "{0.00->2.14}准备好迎接一项新任务了吗?", + "{2.99->6.69}You crash on an uncharted planet. Stranded. {7.07->9.12}Lightyears from Liberty. {9.95->10.74}Then you hear them. {11.69->16.35}They're almost on you, teeth gnashing, venom glistening in the twin moonlight. {17.08->20.63}Suddenly you remember the one thing that can save you.{21.53->23.32}Eagle Sweat. {23.73->28.25}One spray, and the world shifts. You mount the beasts and rise,{28.35->32.40}master of your domain, a god among the cosmos.{32.78->35.97}Before long, you are home.{36.25->37.81}Eagle Sweat.{38.39->43.57}With patented nano-fragrance technology that literally puts odor molecules{43.58->47.97}to the rack until they give up their secrets.{48.90->54.18}Eagle Sweat. Don't just smell it. Live it.": "{3.14->9.42}你坠落在一颗未知的星球上,手足无措,距离解放有几光年之遥。{9.96->16.35}然后你听见,它们磨着牙,向你逼近,毒液在双月照耀下闪闪发亮。{17.08->21.16}突然,你想起了唯一的救命稻草。{21.90->23.47}飞鹰香汗。{23.84->26.47}只需一喷,世界焕然一新。{26.89->28.61}你骑在野兽身上,傲然而立,{29.13->32.58}成为这一方天地的主人,有如宇宙中的神明。{33.03->35.83}不久之后,你荣归故里。{36.24->37.89}飞鹰香汗。{39.23->48.14}专利纳米芳香技术,审问气味分子,获悉芬芳奥秘。{49.06->54.38}飞鹰香汗。闻着香,更要活得香。", + "{0.00->2.08}I've never seen a Helldiver up close before.": "{0.00->2.08}从来没有靠绝地潜兵这么近过。", + "{0.00->0.66}I'm sorry.": "{0.00->0.66}我很抱歉。", + "{0.00->2.09}Democratic stims for you, my friend!": "{0.00->2.09}朋友,给你来一针民主!", + "{0.00->0.40}3!": "{0.00->0.48}3!", + "{0.00->0.65}Look out!": "{0.00->0.65}小心!", + "{0.02->0.88}To the skies.": "{0.02->0.88}飞起来。", + "{0.00->0.86}That was awesome!": "{0.00->0.86}太精彩了!", + "{0.01->1.89}Fire in the name of the Flag!": "{0.00->2.02}以旗帜之名,开火!", + "{0.00->1.86}Pelican 1 returning to extraction point. {2.25->4.56}Please ensure you are inside the extraction radius.": "{0.00->2.29}“鹈鹕”1号正在返回撤离点。{2.38->4.56}请务必进入撤离区。", + "{0.00->1.58}SEAF reinforcements requested.": "{0.00->1.57}已请求武装部队增援。", + "{0.00->0.56}What about here?": "{0.00->0.56}要不这儿?", + "{0.03->1.24}They're everywhere!": "{0.00->1.37}哪儿哪儿都是它们!", + "{0.00->1.33}Super Earth{1.78->3.32}will protect me...": "{0.00->1.33}超级地球{1.78->3.92}会保护我…", + "{0.00->0.63}I've got you.": "{0.00->0.63}我来帮你。", + "{0.00->0.56}Tie.": "{0.00->0.57}平手。", + "{0.01->2.78}Together even in this. Imagine that.": "{0.00->1.56}这也是并肩作战。{1.68->2.85}谁能想到呢。", + "{0.04->2.61}They thought they could get rid of ME!": "{0.00->2.71}哈,它们以为能干掉我!", + "{0.03->2.71}Time to take yer medicine, freaks!": "{0.00->2.86}到点该吃药了,怪物们!", + "{0.00->2.46}Democracy cannot be{2.94->3.95}denied...": "{0.00->4.12}民主无可抵挡…", + "{0.00->1.63}Need to do something about my arm.": "{0.00->1.63}要处理下胳膊。", + "{0.04->5.89}Get in position! Oh uh, not you Helldiver, unless you want to.": "{0.00->1.56}各就各位!{1.57->4.31}呃,潜兵,没说你,{4.31->5.93}你自己拿主意。", + "{0.00->0.67}Dropships.": "{0.00->0.67}运输舰,", + "{0.01->0.77}Mag's empty.": "{0.00->0.68}弹匣空了。", + "{0.02->1.74}The New Wisdom System": "{0.02->1.22}新慧星系", + "{0.01->2.26}Sweet Liberty, that stings!": "{0.01->2.79}解放你大业的,好痛!", + "{0.11->1.38}Support weapon inbound.": "{0.11->1.38}支援武器马上就到。", + "{0.00->0.51}Got one.": "{0.00->0.51}拿到了。", + "{0.00->0.43}I'm out.": "{0.00->0.49}打光了。", + "{0.00->0.54}Affirmative.": "{0.00->0.54}好的收到。", + "{0.03->2.10}For Managed Democracy!": "{0.00->2.09}为了管理式民主!", + "{0.00->2.95}Allied Destroyer joining squadron. Deploying Helldiver.": "{0.00->2.95}友方驱逐舰加入中队。正在部署绝地潜兵。", + "{0.01->3.30}They're here! They're disgusting!": "{0.01->3.30}它们来了!真是恶心死了!", + "{0.00->1.42}The Osupsam system": "{0.00->1.42}欧苏普森星系", + "{0.00->2.29}Cape looks extra sharp today, Helldiver.": "{0.00->2.92}绝地潜兵,你的披风在今天格外帅气。", + "{0.00->1.84}Liberty is an onrushing wave. {2.37->4.40}One obstacle will not stop us.": "{0.00->2.86}解放是一股汹涌的浪潮,{3.56->5.10}一块礁石挡不住我们。", + "{1.14->3.48}More heroes, lost to the Void.": "{1.75->3.89}又有英雄死于寂域。", + "{0.00->1.02}Requesting walker.": "{0.00->1.33}请求步行机甲。", + "{0.00->1.20}Freedom's finest!": "{0.00->1.20}自由精英!", + "{0.01->3.04}Sweet mother of Freedom -- look at them go!": "{0.01->3.04}解放大业啊,看看人家这水平!", + "{0.00->0.67}Northwest.": "{0.00->0.67}西北,", + "{0.03->1.23}They're disgusting!": "{0.03->1.23}恶心巴啦的!", + "{0.02->1.08}More Illuminate!": "{0.02->1.38}还有光能者!", + "{0.00->0.68}Got a sample.": "{0.00->0.68}样本到手了。", + "{0.03->1.57}Cover me, please!": "{0.00->1.72}掩护我,拜托了!", + "{0.01->3.00}Adversity is the true test of Citizenship!": "{0.01->3.00}真公民不怕火炼。", + "{0.00->1.36}We gotta get out of here!": "{0.00->1.36}我们得离开这儿!", + "{0.00->1.95}The Zegema Paradise system": "{0.00->1.95}泽格马乐土星系", + "{0.00->2.25}Another foothold for Freedom.": "{0.00->2.25}为自由又夺回了一座据点。", + "{0.00->1.42}Steel yourselves!": "{0.00->1.42}做好准备!", + "{0.05->8.14}The Void...I've got the Destroyer set to 73 degrees Freedomheit, but it still feels cold.": "{2.30->4.06}寂域……{4.33->8.55}我把驱逐舰温度调到73自由氏度,还是好冷。", + "{0.00->6.23}Freedomball viewership continues to rise. Show your support by tuning in to every match, because {6.23->7.85}nothing says Patriotism {8.24->9.34}like sports.": "{0.00->4.10}自由球比赛收视率持续攀升。如想支持赛事,{4.28->6.35}记得准时收看每一场比赛,{6.84->9.59}体育运动就是最爱国的活动。", + "{0.00->0.95}We'll drop in here.": "{0.00->0.95}这里降落。", + "{0.00->3.85}Enshrouded by spores, a hero rests.": "{0.00->3.85}孢子之下,英雄长眠。", + "{0.00->0.95}How far are we going?": "{0.00->0.95}我们要走多远?", + "{0.00->1.59}I hope they died screaming.": "{0.00->1.59}你们全都不得好死。", + "{0.01->3.28}That was for us. For me.": "{0.00->3.33}这是为了我们。为了我。", + "{0.03->2.19}Sweet Liberty, it's the bots!": "{0.03->2.44}解放你大业的,是机器人!", + "{0.17->3.59}If future generations only knew the heroes that are protecting them.": "{0.00->1.81}真希望子孙后代能知道,{1.81->3.84}是怎样的英雄在保护他们。", + "{0.01->1.37}Bot outpost spotted.": "{0.01->1.37}是机器人哨站。", + "{0.00->3.81}They killed a Helldiver...We're all gonna die!": "{0.00->3.55}它们杀了绝地潜兵…我们全都死定了!", + "{0.00->1.19}Choose where to fight, {1.58->4.67}and return this planet to our glorious Federation.": "{0.00->2.12}请选择你要在何处开始战斗,{2.40->4.67}为伟大的联邦收复这颗星球。", + "{0.03->2.68}Objective-critical stratagem no longer available.": "{0.03->2.68}无法使用目标需要的战略配备。", + "{0.00->1.66}Manning defensive weaponry!": "{0.00->1.67}操纵防御武器!", + "{0.01->0.94}Need more ammo!": "{0.01->0.94}需要弹药!", + "{0.00->2.11}We will carry their legacy!": "{0.00->2.11}我们会继承他们的意志!", + "{0.00->1.30}Launch suspended.": "{0.00->1.30}暂停发射。", + "{0.01->1.28}They can't keep this up, right?": "{0.01->1.28}对面撑不了多久吧?", + "{0.00->1.40}The Herthon system": "{0.00->1.40}赫尔松星系", + "{0.00->6.62}The bots plunder this planet of every last resource. Go forth, and reclaim our land.": "{0.00->6.62}机器人想要榨干这颗星球的资源,快去夺回我们的土地吧。", + "{0.02->1.58}Freedom forever.": "{0.02->1.58}自由万岁。", + "{0.01->3.14}The light of Liberty's shining brighter already.": "{0.00->3.13}此刻解放之光格外的耀眼。", + "{0.02->0.79}Take cover!": "{0.02->1.11}快找掩体!", + "{0.03->0.51}Right away!": "{0.03->0.76}马上就去!", + "{0.00->0.49}West.": "{0.00->0.56}西边,", + "{0.16->0.75}I can't!": "{0.16->0.75}不可以!", + "{0.00->0.75}Sixth one.": "{0.00->0.75}第六个。", + "{0.05->1.25}I won't forget this!": "{0.00->1.35}我绝不会忘记!", + "{0.00->4.09}We have failed to halt the greedful expansion of the Illuminate.": "{0.00->4.09}我们未能阻止光能者的贪婪扩张。", + "{0.00->0.57}Reloading.": "{0.00->0.57}正在换弹。", + "{0.00->0.89}Fall in.": "{0.00->0.63}集合。", + "{0.04->3.14}Thank you, Helldiver, I—thank you!": "{0.00->1.97}谢谢你,潜兵,{1.97->3.30}太感谢了!", + "{0.03->2.54}Anchor your feet, and your hearts will follow!": "{0.00->2.86}站稳脚跟,心就不会动摇!", + "{0.00->1.22}Freedom wins again.": "{0.00->1.22}自由再次得胜。", + "{0.00->1.42}The Providence system": "{0.00->1.42}普罗维登斯星系", + "{0.00->2.04}A planet is close to Liberation. {2.52->5.08}We could be the final push they need.": "{0.00->2.43}这颗星球的解放伟业即将达成。{2.97->4.71}需要我们最后推一把。", + "{0.00->3.04}The intention of the Cyborgs is clear:{3.50->10.26}they aim to construct new Megafactories across the galaxy, with the immediate aim of creating more{10.26->11.49}Cyborgs.": "{0.00->2.17}生化人的意图很明确:{2.78->4.68}它们打算在银河系各地{5.01->7.16}建造新的超大型工厂,{7.74->11.36}首要目标就是制造更多生化人。", + "{0.01->1.09}Automatons!": "{0.01->1.09}机器人!", + "{0.00->0.50}High-value sample collected.": "{0.00->1.35}高价值样本到手了。", + "{0.02->1.67}TAKE COVER!": "{0.00->1.73}快找掩护!", + "{0.00->2.80}Can't survive these wounds much longer.": "{0.00->2.53}伤口不能再耽误了。", + "{0.04->1.35}Squid outpost.": "{0.04->1.35}鱿鱼哨站。", + "{0.00->2.40}Prosperity awaits the brave!": "{0.00->2.40}繁荣需要勇士!", + "{0.00->1.34}Advancing on target.": "{0.00->1.40}向目标前进。", + "{0.00->3.31}Heavy enemy presence detected, deploying SEAF rapid-response.{3.79->5.05}Hang in there, Helldiver.": "{0.00->3.25}检测到大量敌方兵力,正在部署快速响应小队。{3.40->5.15}绝地潜兵,坚持住。", + "{0.00->1.12}Tac-pack's empty.": "{0.00->1.12}战术背包空了。", + "{1.18->1.35}They're disgusting!": "{0.01->1.61}真是恶心死了!", + "{0.00->4.37}Reminder: all personnel must submit weekly urine sample by {5.30->5.76}0400.": "{0.00->2.34}提示:所有人员必须在{2.60->5.81}凌晨4时之前提交每周尿样。", + "{0.05->1.62}Move, move, move!": "{0.00->1.68}快点儿,快,快!", + "{0.03->1.86}You guys do this all the time. Right?": "{0.03->1.86}你们都是老手了,对吧?", + "{0.00->2.60}This is just like the good old days, right Helldiver?{2.98->7.72}Blazing a trail straight into the Den of Dissidence, like our forefathers, {7.96->10.29}armed only with the courage in our hearts{10.42->12.56}and the artillery at our command.": "{0.00->3.70}就像曾经的辉煌年代一样,对吧,绝地潜兵?{4.27->7.72}就像先辈一样,直接杀进异见者的巢穴,{8.31->11.68}只靠心中的勇气和手中的火力开辟道路。", + "{0.00->0.51}Go now, {1.14->3.64}and should you fall, remember this: {4.07->8.02}Every day is a good day to die for Democracy.": "{0.00->0.51}前进!{1.14->3.64}即使跌倒,也要牢记:{4.07->8.02}为民主大业牺牲也在所不辞。", + "{0.01->2.57}Super Earth will never fall!": "{0.00->3.22}超级地球永不陨落!", + "{0.00->1.07}Artifact collected.": "{0.00->1.07}古物到手了。", + "{0.00->0.82}No pain {1.27->2.28}no Freedom.": "{0.00->2.42}痛苦铸造自由。", + "{0.13->2.72}These Terminids will be valuable research specimens. {3.08->4.57}Once they are pacified.": "{0.13->2.00}这些终结族被消灭之后,{2.39->4.57}会成为珍贵的研究样本。", + "{0.00->2.28}The greatest Helldiver I ever saw.": "{0.00->2.88}这是我见过的最伟大的绝地潜兵。", + "{0.00->1.29}The Worthy System": "{0.00->1.03}英杰星系", + "{0.10->6.79}Load yourself up, recruit. This is the real deal. It's just you, the gun in your hands, {6.79->11.21}and 2,000 megatons of explosives in close orbit. That's it!": "{0.10->6.79}新兵,拿好武器。要动真格了。你只能依靠你自己、手中的枪,{6.79->11.21}还有近地轨道上的20亿吨爆炸武器。仅此而已!", + "{0.00->6.81}The Democratic Council ensures that all elected leaders act in accordance to the values we all {6.81->7.28}share.": "{0.00->3.96}民主委员会负责确保所有当选的领袖{4.26->7.35}严格遵守我们共同的价值观。", + "{0.01->2.31}Well these folks look safe!": "{0.95->2.31}看来大家都安全了!", + "{0.00->5.95}Megafactories spawn new Cyborg abominations. They must be destroyed.": "{0.00->4.38}超大型工厂不断孕育新的生化人怪物。{4.61->6.13}必须摧毁它们。", + "{0.10->2.25}One step closer to victory!": "{0.00->2.33}离胜利又近了一步!", + "{0.00->1.28}The Seasse system": "{0.00->1.28}西斯星系", + "{0.00->1.36}Show 'em how we do it!": "{0.00->1.42}给它们露一手!", + "{0.00->1.16}Requesting sentry.": "{0.00->1.16}请求哨戒炮。", + "{0.00->1.46}Don't fall in love with me, okay?": "{0.00->1.67}别爱上我,好吗?", + "{0.00->0.39}Here.": "{0.00->0.39}来。", + "{0.00->1.23}The Kuma system": "{0.00->1.23}天棓二星系", + "{0.03->1.43}For Super Earth!": "{0.00->1.45}为了超级地球!", + "{0.00->1.48}Do not let fear stop you. {1.99->5.66}We need not understand their ways in order to annihilate them.": "{0.00->1.48}不要因为恐惧而退缩。{1.99->5.66}我们的目标是消灭他们,不是理解他们。", + "{0.01->2.43}Moral fortitude will see us through.": "{0.01->2.43}坚定的信念指引一切。", + "{0.00->0.48}Left.": "{0.00->0.48}左边。", + "{0.00->3.41}You ever run into any equipment issues, let me know. I've got your back.": "{0.00->3.41}要是装备出了问题,就来找我,我帮你解决。", + "{0.07->3.40}Oh Liberty! INCOMING!": "{0.00->3.53}解放保佑!要来了!", + "{1.11->3.25}Sweet mother of Freedom!": "{0.76->3.25}自由救救我!", + "{0.01->0.81}I can't!": "{0.01->0.81}没办法!", + "{0.00->2.21}Objective-Critical Stratagem available.": "{0.00->2.21}目标需要的战略配备已就绪。", + "{0.06->1.20}More bugs!": "{0.06->1.20}还有虫族!", + "{0.00->0.56}Reloading.": "{0.00->0.56}换弹。", + "{0.02->0.40}Move.": "{0.02->0.40}走。", + "{0.02->1.75}Calling in extraction!": "{0.02->2.14}呼叫撤离!呼叫撤离!", + "{0.00->1.45}The Midasburg system": "{0.00->1.45}弥达斯堡星系", + "{1.31->4.10}It doesn't matter who you are or where you were born—{4.86->8.47}all citizens are equal in the eyes of freedom. {9.05->11.43}Which is why Super Earth's most patriotic minds{11.50->15.19}instituted the Citizenship Classification Structure. {15.73->17.12}Thanks to the CCS, {17.28->21.27}we can determine exactly which citizens are the most equal. {21.64->26.60}Continue your war efforts, and one day you too could reach Class A citizenship. {27.21->27.97}The CCS: {28.99->30.58}Liberty Optimized.": "{1.43->8.26}无论你是谁,无论你生于何处——在自由面前,所有公民都是平等的。{9.05->17.10}所以,超级地球最坚定的爱国者联合制定了公民分级体系,也就是CCS。{17.28->21.58}我们会按照CCS准确判断哪些公民最为平等。{22.34->23.90}继续努力,建功立业。{24.37->27.01}总有一天,你也能成为A级公民。{27.65->31.13}公民分级体系就是解放的最佳助力。", + "{0.00->2.39}I thought we had a lot of planets when I was a kid, {2.96->4.84}but we've settled dozens more since then. {5.50->9.91}A few generations from now, and the entire Milky Way will be one united Democracy.": "{0.00->2.37}我小时候就知道我们有很多星球,{2.68->5.87}但现在,我们拓殖的星球又多了许多。{6.25->10.35}再过几代人,民主就会统一一整个银河系。", + "{0.00->4.90}Countless high liberty citizens call this city home. Defend their property!": "{0.00->4.90}无数高度自由的公民以这座城市为家。保卫他们的财产!", + "{0.03->0.35}Slimy freaks!": "{0.03->1.24}黏糊糊的怪物!", + "{0.00->3.87}The Automatons ambitions go up in smoke.": "{0.00->3.87}这些机器人的野心注定化为乌有。", + "{0.00->0.86}Need to reload!": "{0.00->0.86}需要换弹。", + "{0.02->2.60}So smooth, wow...": "{0.00->2.85}好丝滑,哇哦。", + "{0.00->2.16}We return empty-handed,{2.57->6.38}while the Automatons forge ever-increasing power.": "{0.00->2.16}今天我们空手而归,{2.57->6.38}而机器人那边的力量却不断壮大。", + "{0.02->0.87}Mag's empty.": "{0.02->0.87}弹匣空了。", + "{0.00->0.56}Helldiver. {1.15->2.23}Stomp any bugs lately?": "{0.00->0.82}绝地潜兵,{0.99->2.39}踩死不少虫族了吧?", + "{0.03->0.89}Get down!": "{0.00->0.91}快卧倒!", + "{0.03->2.50}Surrounded, I'm surrounded!": "{0.00->2.43}被包围,我被包围了!", + "{0.00->5.48}Please, refrain from tampering with the temperature controls. Super Earth has set the ship to the {5.48->7.93}universally ideal temperature.": "{0.00->2.31}请勿擅自调整温度控制器。{2.72->7.77}超级地球已经将飞船温度调至全宇宙最合适的温度。", + "{0.03->1.10}It's really them!": "{0.03->1.10}他们真的来了!", + "{0.04->1.52}Slimy freaks!": "{0.04->1.52}黏糊糊的怪物!", + "{0.03->0.64}Run!": "{0.03->0.64}快跑!", + "{0.00->0.89}Enemies inbound.": "{0.00->0.89}敌人来了,", + "{0.00->0.75}Out of stims.": "{0.00->0.75}针用光了。", + "{0.03->1.11}Get away from me!": "{0.03->1.11}不要靠近我!", + "{0.04->3.68}First the bugs, then the bots, and now maybe the squids, too. {4.35->6.44}Freedom finds enemies at every turn.": "{0.04->3.68}先是虫族,然后是机器人,现在连鱿鱼也来了。{4.35->6.44}自由的敌人无处不在。", + "{0.00->1.84}The Helldivers!": "{0.00->1.26}绝地潜兵!", + "{0.00->0.58}Pack's out.": "{0.00->0.58}背包空了。", + "{0.00->1.11}Maybe this way!": "{0.00->1.11}去这边试试!", + "{0.00->2.75}It's the Helldivers! We're saved!": "{0.00->3.03}是绝地潜兵!我们得救了!", + "{0.01->2.54}Quit standing around! Go go go!": "{0.01->2.99}别再傻站着了!赶紧走!走!", + "{0.28->1.20}Wow.{1.60->2.52}Flawless.": "{0.28->1.20}妈呀,{1.60->2.52}太完美了。", + "{0.00->3.79}The celebration of Liberty Day is mandatory. ... And {4.20->4.90}fun!": "{0.00->1.92}庆祝解放日是义务...{2.55->4.87}同时也是乐趣!", + "{0.00->1.64}Time for payback!": "{0.00->1.85}我向来有仇必报!", + "{0.02->1.23}This is a nightmare!": "{0.02->1.23}太吓人了。", + "{0.10->1.42}SAY HELLO {1.79->6.48}TO DEMOCRAAAACCYYYYYYY!!!!": "{0.10->1.42}民主{1.79->6.48}驾到!", + "{0.00->0.60}Code is:": "{0.00->0.81}代码是:", + "{0.00->1.16}Oh, thank you!{1.76->3.28}That was for me, right?!": "{0.00->3.29}哦,谢谢!给我的?!", + "{0.00->0.85}We've got bots.": "{0.00->0.85}机器人来了。", + "{0.00->0.96}Welcome back. {1.32->4.37}The Terminids you defeated will soon fuel the war effort.": "{0.00->0.76}欢迎回来,{1.39->4.63}你打败的那些终结族将会助力解放事业。", + "{0.00->2.02}Rest in pain, dirtbag.": "{0.00->2.02}废物都不得好死。", + "{0.00->1.94}The Alderidge Cove system": "{0.00->1.94}阿尔德里奇湾星系", + "{0.00->1.41}I'm never washing this hand.": "{0.00->1.41}我再也不洗手了。", + "{0.00->1.15}That's just good engineering.": "{0.00->1.15}因为我们技术够出色。", + "{0.00->2.79}YOU DELIVER THAT DEMOCRACY, HELLDIVER!!": "{0.00->3.07}让他们瞧瞧民主的厉害!", + "{0.01->0.92}Get down!": "{0.01->0.92}快趴下!", + "{0.02->0.97}The bots are here!": "{0.02->0.97}机器人来了!", + "{0.00->0.64}Will the shuttle have enough room for all of us?": "{0.00->2.19}运输船能装下所有人吗?", + "{0.00->2.95}I swear those freaks get stronger every day.": "{0.00->3.31}我敢发誓,那些怪物越来越厉害了。", + "{0.03->1.33}There's more of them!": "{0.03->1.33}那边还有!", + "{0.00->3.30}Use a Stratagem now to take care of those bugs. {4.00->6.84}Just make sure you take a few steps back.": "{0.00->3.30}使用一次战略配备,处理掉那些虫族。{4.00->6.84}别忘了后退几步,远离爆炸范围。", + "{0.00->0.69}Out of ammo.": "{0.00->0.69}弹药没了。", + "{0.00->1.67}Requesting objective equipment!": "{0.00->1.67}请求目标所需装备!", + "{0.02->2.62}The enemy is attempting to seize one of our planets. {2.99->4.61}We must join the defense.": "{0.02->2.62}敌人正在试图夺取我们的一颗星球。{2.99->4.61}我们必须加入抵御的队列。", + "{0.00->2.89}All Helldivers, please report to bridge.": "{0.00->2.89}所有绝地潜兵,请到舰桥报到。", + "{0.09->1.76}Unidentified enemy contact.": "{0.09->1.76}遇到身份不明的敌人。", + "{0.23->1.85}ROE: destroy.": "{0.00->1.89}一个字:干。", + "{0.05->4.02}Did they have the story of Dissident Danny where you came from? Went somethin' like this:": "{0.05->4.02}你的故乡有没有流传《异见分子丹尼》的故事?大概内容是这样的:", + "{0.00->4.24}Welcome back. That city is one step closer to Freedom.": "{0.00->4.24}欢迎回来。那座城市向着自由迈进了一步。", + "{0.01->2.17}Go go go!": "{0.01->2.17}赶紧走!走!", + "{0.00->1.50}Democracy conquers all.": "{0.00->1.50}民主征服一切。", + "{0.01->2.06}This must be part of Super Earth's plan.": "{0.01->2.06}超级地球肯定料到了。", + "{0.00->0.88}No matter. {1.24->2.97}We shall continue the fight.": "{0.00->0.71}无所谓,{1.10->2.89}我们会继续战斗。", + "{0.00->0.86}Affirmative.": "{0.00->0.86}好的收到。", + "{0.00->0.84}Dead enemy.{1.22->2.94}Best thing I've seen all day.": "{0.00->1.17}敌人死了。{1.43->3.23}这是今天最好的消息。", + "{0.00->2.30}I'm not sure what to make of these Automatons. {2.73->6.91}I'm sure they're no match for the Helldivers, but that's no reason for complacency.": "{0.00->2.30}我不确定应该如何看待这些机器人。{2.73->6.91}我坚信它们不是绝地潜兵的对手,但是也不能因此自满。", + "{0.02->2.89}Fall back, fall back if you want to live!": "{0.00->2.90}撤退,想活命就撤退!", + "{0.00->1.03}New mag.": "{0.00->1.03}新弹匣。", + "{0.00->0.35}Save me!": "{0.00->0.98}救我!", + "{0.00->5.67}Choose any of the available operations, Helldiver. Each one you complete is a paving stone on the {5.67->6.93}road to Liberty.": "{0.00->2.69}绝地潜兵,请任选一项可参与的行动。{3.20->4.73}你完成的每一项行动,{5.08->7.02}都是为解放添砖加瓦。", + "{0.00->2.94}Bug outpost spotted. Prepare to exterminate.": "{0.00->2.68}发现虫族哨站,准备歼灭。", + "{0.00->1.46}The Spherion system": "{0.00->1.46}斯飞利昂星系", + "{0.07->2.34}Freedom cannot die!": "{0.00->2.44}自由永不熄灭!", + "{0.00->0.48}I'm out!": "{0.00->0.48}没弹药了!", + "{0.00->2.78}The Illuminate shroud grows.": "{0.00->3.16}光能者的阴霾还在蔓延。", + "{0.00->1.57}The Freedom Peak system": "{0.00->1.74}弗里敦峰星系", + "{0.12->1.44}The city is saved.{1.99->3.81}Thanks to your intervention.": "{0.03->1.19}城市获救了。{1.73->3.54}多亏了你挺身而出。", + "{0.00->1.77}Here we go again...": "{0.00->1.85}老子我回来了……", + "{0.03->1.11}Get 'em!": "{0.00->1.17}消灭它们!", + "{0.00->5.99}The function of the Democratic Investigation Agency is to keep you and your family safe. {6.43->9.18}Please, co-operate with their requests.": "{0.00->5.99}民主调查局的职责是保障你和你家人的安全。{6.43->9.66}请务必配合调查局的相关工作。", + "{0.02->1.73}I knew they wouldn't abandon us.": "{0.02->1.73}我就知道他们不会抛弃我们。", + "{0.00->2.76}Nothing can pierce Democracy!": "{0.00->2.37}民主坚不可摧!", + "{0.01->1.09}They're not letting up!": "{0.01->1.09}敌方火力太猛烈了!", + "{0.00->0.69}New target?{1.21->2.30}Whatever it takes.": "{0.00->0.84}有新目标?{1.51->2.68}不惜一切代价。", + "{0.00->1.16}Super Earth. {2.23->2.96}Liberty. {3.34->4.37}Democracy. {4.77->5.43}Freedom. {6.05->7.91}Independence. Voting. {8.76->9.57}Liberty.": "{0.00->1.16}超级地球,{2.23->2.96}解放,{3.34->4.37}民主,{4.77->5.43}自由,{6.03->6.74}独立,{7.31->8.23}投票,{8.76->9.57}解放。", + "{0.00->5.79}Well done. Lots of enemies killed, and lots of samples to help us figure out how to kill even more.": "{0.00->5.79}干得好。不仅杀敌无数,而且采集了很多样本,让我们可以消灭更多敌人!", + "{0.00->1.32}Reminder: Element {1.70->6.53}710 is safe and environmentally friendly. Any rumors of E-{6.90->11.74}710 spills are the work of dissidents seeking to undermine our way of life.": "{0.00->4.20}注意:710元素十分安全且对环境无害。{4.63->7.54}任何声称710元素存在泄漏问题的谣言,{7.72->11.74}都是异见分子刻意捏造,意图抹黑我们的生存正道。", + "{7.55->10.80}Freedom's Greetings, I'm Coretta Kelly.{11.06->16.73}In a shocking development, the Cyborg Legion has revealed itself to the Galaxy.{16.73->19.31}In a cyber-terrorist attack,{19.31->25.20}the Cyborgs hijacked Super Earth channels to broadcast a disturbing message.{25.50->28.41}We will now play a portion of that video.{28.67->35.68}Viewers are advised: this content will be extremely upsetting to all patriotic individuals.{35.68->39.21}WE ARE THE CYBORG LEGION.{39.21->42.27}WE WILL ENSLAVE YOU.{42.27->46.28}WE WILL ERADICATE FREEDOM.{46.38->50.78}BE ANNIHILATED.{51.35->53.26}That was truly disturbing.{53.44->58.85}The Cyborgs had been thought extinct following the Automaton invasion of Cyberstan.{58.85->63.66}But this footage proves that not only did our former enemy survive,{63.66->68.53}they were themselves the masterminds behind the Automaton invasion.{69.25->74.44}The Government of Super Earth has voted unanimously to declare war on the Cyborgs.{74.79->81.50}The Helldivers have been ordered to lead an offensive with the objective of liberating Cyberstan.{81.82->86.29}I'm Coretta Kelly. May Liberty watch over us all.": "{7.91->10.74}自由向各位问好,我是科雷塔·凯利。{11.52->14.05}事态的发展已经超出预期,{14.29->17.22}生化人军团已经在银河系现身。{17.59->19.23}通过一场网络恐怖袭击,{19.68->22.81}生化人侵入了超级地球的广播频道,{23.07->25.89}强行播放了一则令人不安的讯息。{26.28->28.29}现在播放该视频的部分内容。{29.34->35.53}在继续收看之前我们郑重提醒:以下内容将令所有爱国人士深感不适。{35.77->38.94}我们是生化人军团。{39.56->41.99}我们会奴役你们。{43.00->45.37}我们会取缔自由。{46.45->48.31}你们必死无疑。{51.35->52.57}确实令人不适。{53.52->55.37}机器人入侵生化斯坦后,{55.58->60.60}我们曾以为生化人已经灭绝。但这段影像清晰证明,{61.08->63.68}我们这位旧日宿敌不仅幸存了下来,{64.11->67.87}他们本身更是机器人入侵背后的幕后主使。{69.32->71.35}超级地球政府已全票通过,{71.68->73.81}正式对生化人宣战。{74.72->76.89}绝地潜兵已接到指令,{77.38->80.43}解放生化斯坦的号角已经吹响。{81.74->85.86}我是科雷塔·凯利。愿解放保佑我们所有人。", + "{0.00->7.66}This Megafactory is a malignant tumor, spreading the cancer of Socialism 'cross the stars.": "{0.00->3.26}这座超大型工厂就是一颗恶性肿瘤,{3.81->7.69}将集权主义的癌症传播到群星之间。", + "{0.08->1.43}Calling in a Hellbomb.": "{0.08->1.43}呼叫地狱火炸弹。", + "{0.05->0.51}I'm out!": "{0.05->0.75}没弹药了!", + "{0.01->2.34}We'll be off-planet soon.": "{0.01->1.92}马上就能走了。", + "{0.00->3.29}I never thought I'd get to meet an actual Helldiver.": "{0.00->3.29}没想到我能遇见真正的绝地潜兵。", + "{0.00->1.41}Tech sample acquired.": "{0.00->1.41}科技样本到手了。", + "{0.03->2.08}It wants my brain!": "{0.03->2.08}它想把我的脑花吃了!", + "{0.00->3.81}At least I saw the Helldivers...": "{0.00->4.79}至少见到绝地潜兵了……", + "{0.00->3.26}Breathe easy, citizen. We got Helldivers with us.": "{0.00->3.26}放心吧同胞。我们有绝地潜兵在。", + "{0.00->1.95}But one mission remains.": "{0.00->1.95}只剩最后一项任务。", + "{0.00->1.38}The Zagon system": "{0.00->1.38}扎贡星系", + "{0.02->1.74}Will the shuttle have enough room for all of us?": "{0.02->1.74}运输船能装下所有人吗?", + "{0.00->0.82}On my way.": "{0.00->0.82}马上就来!", + "{0.00->0.93}Additional objective.": "{0.00->0.93}其他目标,", + "{0.01->1.09}Got a sample.": "{0.01->1.09}样本到手了。", + "{0.00->0.89}Marking location.": "{0.00->0.89}标记地点,", + "{0.03->1.95}Dig in, soldiers! Hold this line!": "{0.00->2.17}守住,战士们!死守防线!", + "{0.03->1.64}Flag-forsaken robots!": "{0.03->1.64}一堆破铜烂铁!", + "{0.00->0.65}Tagging map.": "{0.00->0.76}标记地图,", + "{0.00->0.60}Alert. {0.96->1.63}Alert.": "{0.00->0.60}警告。{0.96->1.63}警告。", + "{0.00->1.95}You may proceed to extraction when ready.": "{0.00->1.95}你们现在可以随时撤离。", + "{0.00->1.88}I owe you my life, Helldiver.": "{0.00->2.08}潜兵,我欠你一条命。", + "{0.00->1.56}Bot Outpost destroyed.": "{0.00->1.56}已摧毁机器人哨站。", + "{0.02->2.03}Eyes forward, we got this!": "{0.00->2.08}看前面,我们能赢!", + "{0.00->1.58}Sometimes the teachers would join in, too.": "{0.00->1.58}有时候老师也会一起玩。", + "{0.00->5.25}Their bodies shall become one with the concrete of the city they helped save.": "{0.00->5.25}他们拯救了城市,就连身躯都融入了混凝土。", + "{0.01->1.44}Need assistance!": "{0.00->1.49}请求援助!", + "{0.00->3.07}I can almost taste the Freedom from here!": "{0.92->3.07}我已经闻到了自由的芬芳了!", + "{0.06->0.99}We made it!": "{0.06->1.37}我们成功了!", + "{0.00->2.47}RIP THEM TO PIECES, HELLDIVERS!": "{0.00->2.47}把它们撕成碎片,绝地潜兵!", + "{0.02->1.46}Cover me, please!": "{0.00->1.46}掩护我,拜托了!", + "{0.04->1.39}Robot scum!": "{0.04->1.39}破铁坨子!", + "{0.00->0.63}Cancel that.": "{0.00->0.63}不必了。", + "{0.00->2.32}We will remember their sacrifice.": "{0.00->2.10}我们会铭记他们的牺牲。", + "{0.00->3.18}Don't forget to smile! Libertycams are active {3.59->4.33}24/7.": "{0.00->1.43}保持微笑!{1.71->4.73}解放摄像头全天候守护你。", + "{0.00->2.11}They are lost to the Hive.": "{0.00->2.11}他们已葬身虫窝。", + "{0.00->1.61}The New Stockholm system": "{0.00->1.77}新斯德哥尔摩星系", + "{0.00->0.76}Are we safe?": "{0.00->0.76}我们安全了吗?", + "{0.00->1.73}Democracy's finest.": "{0.00->1.29}你是民主的精英。", + "{0.00->1.60}The Hydrofall system": "{0.00->1.60}水瀑星系", + "{0.22->1.24}The Alta system": "{0.00->1.24}奥尔塔星系", + "{0.00->1.61}The Skat Bay system": "{0.00->1.61}斯卡特湾星系", + "{0.00->1.19}Calling in extraction!": "{0.00->1.28}呼叫撤离!", + "{0.34->5.90}The fires of their forges are nothing compared to the Freedom in your hearts.": "{0.34->5.90}锻造炉的烈火,远不及你们心中的自由之火那样炽热。", + "{0.14->2.19}The flag of Super Earth!": "{0.00->2.24}高举超级地球的旗帜!", + "{0.00->1.32}We fight on together!": "{0.00->1.36}一个都不能少!", + "{0.26->1.55}Eyes forward, soldiers!": "{0.00->1.68}注意前方,士兵们!", + "{0.02->1.49}Slimy freaks!": "{0.02->1.49}黏糊糊的怪物!", + "{0.06->2.25}Sweet Liberty, my arm!": "{0.06->2.25}我超级自由的胳膊!", + "{0.00->6.25}In the first intragalactic war alone, the bugs accounted for the deaths of one hundred and eighty-{6.25->8.39}nine million Super Earth citizens. {8.77->9.98}Many of them babies.\n\n{10.41->13.84}Don't let the bugs kill babies—fight the good fight!": "{0.00->1.69}单论第一次星系战争,{2.03->6.57}就有1.89亿超级地球公民被虫族残忍杀害,{7.27->10.07}其中许多人还是襁褓中的婴儿。{10.70->11.81}悲剧不能重演。{12.17->14.46}挺身而出,为人类而战!", + "{0.00->1.63}I feel safer already.": "{0.00->1.63}感觉安全多了。", + "{0.00->0.71}Southeast.": "{0.00->0.71}东南,", + "{0.04->4.55}So, the masterminds behind the Automatons reveal themselves at last.{4.55->8.29}The Cyborgs thought they could catch us by surprise, huh?{8.29->11.89}Well, we could smell their joint grease a galaxy away.": "{0.04->3.08}机器人背后的主谋终于现身了。{3.59->5.37}生化人还想偷袭我们?{7.02->11.13}在隔壁星系都能闻到它们关节润滑油的味儿。", + "{0.00->1.63}Too old to be productive? {2.00->6.54}Consider volunteering for an early trip to the bio-repurposer vats!": "{0.00->1.63}上年纪干不动了?{2.60->6.76}不妨自愿提前参加生物机能改造之旅!", + "{0.11->1.28}Fire at will!": "{0.00->1.35}自由开火!", + "{0.01->3.48}Valiant and brave though our efforts were,{3.60->9.68}the distorted reality of the Void proved uncanny beyond estimation.{9.80->17.92}Its reach may yet grow, and imperil more innocent civilians. But we will learn from this failure,{18.22->24.61}and return again, mightier than before, to restore the galaxy to rightness.": "{0.00->2.46}尽管我们英勇无畏,{2.72->4.59}但事实证明,{4.77->9.06}寂域内的扭曲现实力量远超预期。{9.41->15.59}寂域恐怕还会继续扩张,威胁更多无辜平民。{15.83->19.98}但我们会从这次失败中汲取教训,{20.21->25.10}重振旗鼓,定要让银河系重归正轨。", + "{0.00->0.38}We made it!": "{0.00->0.96}我们成功了!", + "{0.00->7.44}Alert: Defense of currently orbited planet from Terminid invasion has ended in absolute victory. {7.88->10.91}Planet remains under Super Earth control.": "{0.00->7.23}通知:当前星球抵御终结族入侵的行动已经大获全胜。{7.29->10.91}该星球仍归超级地球统治。", + "{0.01->0.90}New target!": "{0.01->1.02}发现新目标!", + "{0.00->6.83}Thanks to Super Earth's mandatory Freedom of Assignment program, every citizen gets to select which {6.83->10.05}government-provided career best suits their dreams.": "{0.00->3.74}多亏了超级地球强制实行的自由分配计划,{4.16->7.17}每位公民都能从政府提供的职业生涯规划中{7.41->9.18}选出最适合自己的道路,{9.39->11.17}最终成就梦想。", + "{0.00->2.60}Running water. Do you hear{2.60->17.93}it? There - a flowing river of E-710. Hear the river growing, larger and larger. Now, its a rushing{17.96->18.69}torrent.{19.29->24.37}It overflows its banks, washing away all opposition{24.77->28.63}and flooding the Galaxy with prosperity.": "{0.00->1.39}流水声。{2.27->3.25}听到了吗?{4.27->8.61}710元素汇集成河流。{9.26->14.55}河流声越来越大。{15.33->19.39}现在,河流变成了汹涌的激流。{19.63->24.30}激流冲出河岸,冲垮一切阻碍,{24.32->28.76}以繁荣之名淹没整个银河系。", + "{0.00->2.71}Helldiver!? VENGEANCE!": "{0.00->2.71}绝地潜兵!?复仇!", + "{0.05->2.00}Need assistance!": "{0.00->2.17}请求救助!", + "{0.26->1.75}The Helldivers?{2.80->3.76}Oh NOW it's on!": "{0.00->1.23}绝地潜兵?{2.30->3.76}撑场子的来了!", + "{0.00->1.95}SEAF supplementary teams are in reserve.": "{0.00->2.12}武装部队后援小组等待部署。", + "{0.00->0.84}Last reload.": "{0.00->0.84}最后的弹药。", + "{0.08->1.84}Stay dead, scum.": "{0.14->2.16}废物,去死吧。", + "{0.03->1.69}Vile secessionists...{2.21->3.90}they'll pay for this.": "{0.03->1.50}卑劣的分裂分子……{1.79->3.15}一定会付出代价。", + "{1.33->4.29}Ahem. So for this next part, make sure you dive {4.66->8.61}into the trench, and stay down the whole time. {9.24->9.67}That's...{10.92->11.47}that's it.": "{1.01->3.08}在接下来的环节里,{3.49->7.16}你一定要把整个身体都钻进战壕,{7.65->8.85}全程不要露头。{9.18->11.17}就…就是这样。", + "{0.03->2.95}Sorry, wish I could give you more of a fight.": "{0.00->3.07}抱歉,我也希望能够到你的水平。", + "{0.01->0.55}Moving out!": "{0.00->0.55}进攻!", + "{0.00->4.11}Our enemies couldn't take down even a single Helldiver today. {5.06->6.94}You truly are invincible.": "{0.00->4.11}今天,我们的敌人没能打倒任何一位绝地潜兵。{4.61->6.94}你真是所向披靡。", + "{0.00->0.95}How much longer?": "{0.00->0.95}还得等多久?", + "{0.00->0.73}Just stay calm.": "{0.00->0.73}保持冷静。", + "{0.38->0.60}Here!": "{0.00->0.60}拿着!", + "{0.03->1.63}Kill them! Kill them all!": "{0.03->1.91}杀了它们!统统杀光!", + "{0.00->1.87}Illuminate artifact acquired.": "{0.00->1.87}光能者古物到手了。", + "{0.00->2.67}Hostiles inbound! Bring it on!": "{0.00->2.67}敌人要来了!来吧!", + "{0.03->1.22}Get down!": "{0.03->1.22}快趴下!", + "{0.09->1.05}Until now! {1.45->9.35}Here's your REAL lesson, soldier: Squadmates can and will perish tragically all the time. Now use {9.35->13.83}the Reinforcement Stratagem to have another Helldiver take their place!": "{0.09->1.05}形势有变!{1.45->8.02}士兵,这才是你真正要学的东西:失去队友在所难免。{8.70->13.83}现在,使用增援战略配备,呼叫替补的绝地潜兵。", + "{2.87->3.51}Air quality [inhales]...passable.": "{2.87->3.51}空气质量…还行。", + "{0.02->0.48}Sample.": "{0.02->0.54}样本,", + "{0.16->1.51}Manning combat walker.": "{0.16->1.51}操纵战斗步行机甲。", + "{0.02->2.87}The Automatons are remorseless in their expansion. {3.33->5.83}We must not let this world fall.": "{0.00->2.84}机器人的扩张冷酷无情,{3.67->5.88}不能坐视这颗星球沦陷。", + "{0.01->2.23}You'll... you'll be okay...": "{0.01->2.65}你…你会没事的…", + "{0.04->2.21}CLEAR THE ZONE! NOW!": "{0.00->2.25}撤出这个区域!赶紧的!", + "{0.00->1.33}Nice and cold in here.": "{0.03->1.19}这里很凉快。", + "{0.01->1.22}I'm bleeding out!": "{0.01->1.22}我流血了!", + "{0.06->2.29}For Liberty's sake, shoot them!": "{0.06->2.73}解放他大业的,弄死它们!", + "{0.00->0.66}Northwest.": "{0.00->0.66}西北,", + "{0.02->1.09}I'll be fine...": "{0.02->1.09}我没事…", + "{0.00->5.37}Bugs, as essential as they are vile. Never forget, Element {5.79->9.69}710 extraction is just as important as eradication!": "{0.00->3.69}虫族,至关重要但又可恶至极。{4.29->9.48}别忘了,提取710元素和消灭虫族同等重要!", + "{0.00->3.64}Strategic retreat, strategic retreat everybody!": "{0.00->1.47}战略转移,{1.47->3.84}所有人战略转移!", + "{0.00->0.63}No!": "{0.00->0.63}没办法!", + "{0.00->3.52}We WILL level these factories, whatever it takes.": "{0.00->3.94}我们一定会夷平这些工厂,不惜一切代价。", + "{0.00->0.60}I'm sorry.": "{0.00->0.60}抱歉。", + "{0.00->1.30}Pelican 1 approaching pickup.": "{0.00->1.30}“鹈鹕”1号正在赶来接人。", + "{0.01->1.29}This is the objective.": "{0.01->0.96}这就是目标。", + "{0.00->1.73}The New Kiruna system": "{0.00->1.73}新基鲁纳星系", + "{0.00->0.84}Area secure.": "{0.00->0.84}区域已安全。", + "{0.00->2.12}Can't survive these wounds much longer.": "{0.00->2.12}伤口不能再耽误了。", + "{0.04->1.46}Manning emplacement!": "{0.00->1.40}我来操作炮位!", + "{0.00->0.95}Hold the line!": "{0.00->0.95}守住阵线!", + "{0.19->0.91}200 meters.": "{0.19->0.91}200米。", + "{0.01->1.09}Spread out!": "{0.00->1.15}散开!", + "{0.00->1.78}I hope they died screaming.": "{0.00->1.60}一个个都不得好死。", + "{0.04->2.25}Get back, you filthy squids!": "{0.04->2.25}恶心的鱿鱼,滚开!", + "{0.00->0.55}Reporting to the front.": "{0.00->1.37}前线少不了我。", + "{0.01->1.73}Go! Move!": "{0.01->1.73}走!快走!", + "{0.03->1.43}Get to cover!": "{0.00->1.44}快找掩护!", + "{0.04->2.19}They thought they could get rid of ME!": "{0.00->2.21}它们以为能干掉我!", + "{0.00->0.60}Reloading.": "{0.00->0.60}换弹。", + "{3.11->4.56}To die for the cause... no greater...honor...": "{0.00->6.41}为大业献身…是至高无上的…光荣…", + "{0.00->3.26}Our way of life will always endure...": "{0.00->3.71}正道永存…", + "{0.00->7.88}Report all signs of dissidence to your local loyalty officer. Remember—heroes report, cowards stay {7.90->8.67}silent.": "{0.00->1.97}如果发现任何异端思想,{2.18->5.04}请及时向当地的忠诚事务官举报。{5.45->9.77}记住,英雄敢于举报,懦夫只会沉默。", + "{0.00->2.14}Injury? What injury!": "{0.00->2.14}受伤?哪来的伤!", + "{0.03->1.43}The Terrene System": "{0.03->1.09}类地星系", + "{0.00->2.29}Let's see this through, for Super Earth.": "{0.00->2.56}为了超级地球,我们会坚持到最后。", + "{0.01->3.03}This... isn't the end.": "{0.01->3.03}这…不是末日。", + "{0.01->3.34}That was almost as exciting as Liberty Day.": "{0.70->2.81}就像是在过解放日一样。", + "{0.52->1.81}I know what that means!": "{0.00->2.14}哼,这个我可太懂了!", + "{0.04->1.46}They've planted mines here!": "{0.00->1.47}这里敌人埋了地雷!", + "{0.01->0.97}The bots are back!": "{0.01->0.97}机器人回来了!", + "{0.01->1.22}Throwing supply beacon.": "{0.01->1.22}投掷补给信标。", + "{0.00->0.70}I'm out.": "{0.00->0.70}打光了。", + "{0.05->1.56}What in Liberty's name!?": "{0.05->1.56}解放他大业的!?", + "{0.00->1.71}Legendary iridescence.": "{0.00->1.71}这光芒真是耀眼。", + "{0.45->3.27}For a minute, I thought I might never vote again.": "{0.00->3.27}差点以为自己再也不能投票了。", + "{0.01->2.63}Pleasure to watch you work, Helldiver!": "{0.01->2.63}绝地潜兵,表现太完美了!", + "{0.00->1.44}Calling down a sentry.": "{0.00->1.44}呼叫哨戒炮。", + "{0.02->1.41}Control your breathing!": "{0.00->1.20}控制你的呼吸!", + "{0.01->2.33}Barely... scratched me...": "{0.01->3.46}就破了点皮…", + "{0.02->1.27}I'm hit!": "{0.02->1.27}我中弹了!", + "{0.00->1.79}SEAF rapid response is on the way.": "{0.00->1.86}快速响应小队正在前往。", + "{0.03->1.55}The Thrash System": "{0.00->1.48}萨尔什星系", + "{0.00->1.92}Reinforcements budget running low.": "{0.00->1.92}增援预算即将耗尽。", + "{0.00->1.01}Open fire!": "{0.00->0.64}开火!", + "{0.00->2.56}You cannot hurt Democracy!": "{0.00->2.56}你无法损害民主!", + "{0.03->3.16}They're trying to pin me!": "{1.66->3.25}它们想弄死我!", + "{0.00->0.46}1!": "{0.00->0.46}1!", + "{0.00->2.63}You truly are one of Liberty's greatest heroes.": "{0.00->2.63}你真是解放事业最伟大的英雄。", + "{0.00->3.80}Be advised, the enemy High Priority Target is near your position.": "{0.00->3.80}注意,高优先级敌方目标就在你们附近。", + "{0.08->1.78}Flag-forsaken mines!": "{0.00->1.97}插他旗的有地雷!", + "{0.06->1.55}Back! Back!": "{0.06->1.55}滚开!滚开!", + "{0.00->3.70}Your sample collection is of great value to the Ministry of Science. {4.19->6.18}Everything serves Liberty, in the end. {6.61->8.29}Even our enemies.": "{0.00->3.32}你采集的样本对科学部来说很有价值。{3.85->6.71}最终,一切都将为解放大业效力,{7.23->8.50}包括敌人。", + "{0.00->2.01}Our requests have been answered!": "{0.00->1.69}我们的需求得到响应了!", + "{0.00->1.78}The Satellaria System": "{0.00->1.07}卫环星系", + "{0.00->2.40}I hope they died in pain.": "{0.00->2.40}希望它们不得好死。", + "{0.00->3.82}If might makes right, there's no way that could be wrong!": "{0.00->3.82}金拳头、银拳头、比不上民主的铁拳头!", + "{0.00->0.84}Let's play.": "{0.00->0.84}来玩玩吧。", + "{0.00->1.58}Performing assisted reload.": "{0.00->1.58}让我来帮你换弹。", + "{0.00->1.30}Welcome aboard, Helldiver. {1.81->3.30}The Galactic War needs you.": "{0.00->1.93}绝地潜兵,欢迎登舰。{2.37->3.69}星系战争需要你。", + "{0.00->0.30}Right.": "{0.00->0.43}右边。", + "{0.34->1.90}Terrorize THIS!": "{0.00->2.06}你也来感受恐怖!", + "{0.00->1.53}This is the right place. Right?": "{0.00->1.13}是在这里等,对吧?", + "{0.04->3.60}Did you see that?! Best squad in the system!": "{0.00->3.72}看到了吗?本星系最强小队!", + "{0.17->2.22}For the glory of Super Earth.": "{0.00->1.94}荣耀属于超级地球。", + "{0.02->0.91}Fire in the hole.": "{0.02->0.91}小心手雷。", + "{0.00->3.60}Hold your breath!": "{1.40->2.70}快憋气!", + "{0.00->1.10}They're coming soon, right?": "{0.00->1.30}他们快到了,对吗?", + "{0.03->0.98}Wow uh,{2.08->3.88}thank you for holding back.": "{0.00->1.25}哇,{2.25->4.06}谢谢你手下留情。", + "{0.00->2.08}Wonder if this'll help my next CCS review...": "{0.00->2.54}不知道能不能给CCS评估加点分…", + "{0.00->1.47}Bot asset destroyed.": "{0.00->1.47}已摧毁机器人资产。", + "{0.00->1.54}I did my part...": "{0.00->1.82}我尽力了…", + "{0.00->0.42}Yes!": "{0.00->0.42}好的!", + "{0.00->1.24}You saved us!": "{0.00->1.24}多亏了你们!", + "{0.00->1.70}Great shot, Helldiver!": "{0.00->1.70}绝地潜兵打的漂亮!", + "{0.00->3.48}Danny read everything he could get his hands on, always tryin' to discover something that {3.48->3.70}no one else knew.": "{0.00->2.12}丹尼想方设法地阅读各种资料,{2.37->4.37}一心想要发现其他人都不知道的秘密。", + "{0.00->1.07}Objective located.": "{0.00->1.07}发现目标,", + "{0.01->4.41}Attack Democracy, you pay the price!": "{0.01->4.41}敢攻击民主,就要付出代价!", + "{0.00->1.92}Are you sure it's safe here?": "{0.00->1.55}这里确定安全吗?", + "{1.10->1.99}A military{2.41->3.27}marvel, you are.": "{1.13->3.29}你简直是个军事奇迹。", + "{0.02->1.22}Get behind that!": "{0.02->1.22}去那后边!", + "{0.00->0.66}Ok!": "{0.00->0.66}好的!", + "{0.00->3.23}The great leveler -- Hellbomb secured.": "{0.00->3.23}发现大杀器——地狱火炸弹。", + "{0.00->2.95}Recruit expired. Deploy Terminid containment team.": "{0.00->3.10}新兵死亡。部署终结族控制小队。", + "{0.04->3.77}Don't let 'em get any closer! Shoot! SHOOT!": "{0.00->1.69}别让它们再靠近了!{1.69->3.96}射击!射击!", + "{0.00->2.17}Eagle 1, reporting for Freedom-loving duty.": "{0.00->2.17}“飞鹰”1号,时刻履行自由义务。", + "{0.00->1.63}The Bankability System": "{0.00->1.16}金枢星系", + "{0.00->1.20}No draws. Again!": "{0.00->1.96}不接受平手。再来!", + "{0.02->0.51}Bugs.": "{0.02->0.51}虫族。", + "{0.03->2.82}A pacified sector is a happy sector.": "{0.00->2.99}平定的分区才是幸福的分区。", + "{0.00->3.84}This vile Gloom has met its doom.": "{0.00->3.84}邪恶的“阴霾”迎来末日。", + "{0.00->0.95}Calling down supplies.": "{0.00->0.95}呼叫补给。", + "{0.01->1.29}Spread out, everyone!": "{0.00->1.34}所有人,散开!", + "{0.00->1.69}Human assets secured.": "{0.00->1.69}已确保人力资产安全。", + "{0.00->1.35}The Deneb system": "{0.00->1.35}天津四星系", + "{0.04->0.80}Absolutely!": "{0.04->0.80}没有问题!", + "{0.01->2.13}Uh... is this a test?": "{0.01->2.13}呃…这是测试吗?", + "{0.82->2.13}Just like in the movies...": "{0.89->2.40}跟拍电影一样…", + "{1.40->2.04}I'm hit..{3.20->3.75}I'm hit...": "{1.40->2.04}我中弹了…{3.20->3.75}我中弹了…", + "{0.00->1.32}Just stay calm.": "{0.00->1.32}不要着急。", + "{0.01->1.09}Prepare for contact.": "{0.01->1.09}注意,准备交战。", + "{0.03->1.46}Guh, I'm pinned!": "{0.00->1.52}呃,被压制了!", + "{0.00->1.09}For Super Earth!": "{0.00->1.09}为了超级地球!", + "{0.05->2.12}GET SOOOOOOME!": "{0.05->2.12}都给老娘死!", + "{0.02->1.59}That's called Democracy!": "{0.02->1.59}这就是民主!", + "{0.00->2.95}Decreased visibility—should help obscure our movements.": "{0.00->2.65}能见度降低,方便我们隐藏行踪。", + "{0.00->0.45}Zero.": "{0.00->0.49}洞。", + "{0.00->4.58}I shot a Helldiver! I don't deserve forgiveness!": "{0.00->1.83}我打中了潜兵!{1.84->4.73}我不配得到原谅!", + "{0.04->1.88}Like hugging an action figure.": "{0.00->2.08}就像在抱动作片巨星。", + "{0.00->1.00}E-710, {1.62->4.11}the galaxy's greatest energy source.": "{0.00->1.00}710元素,{1.62->4.11}全星系最棒的能源。", + "{0.00->3.23}I never thought I'd get to meet an actual Helldiver.": "{0.00->3.23}没想到我能遇见真正的绝地潜兵。", + "{0.02->2.33}Will the shuttle have enough room for all of us?": "{0.02->2.33}运输船能装下所有人吗?", + "{0.02->0.99}Robot scum!": "{0.02->0.99}铁皮渣滓!", + "{0.02->2.57}White, yellow, and blue!": "{0.00->2.53}白色、黄色、蓝色!", + "{0.01->1.19}Sweet Liberty!": "{0.01->1.47}解放他大业的!", + "{0.04->2.38}Get away from me, bug freak!": "{0.04->2.38}滚开!没脑子的东西!", + "{0.06->5.23}\"Curiosity makes dissidents,\" that's what my mom always used to say.{5.23->10.58}Who would speculate about the ancient Illuminate ruins activating after millenia,{11.86->17.87}generating spacetime-altering phenomena and vanishing hundreds and thousands of citizens?{18.46->22.44}Not me. I'll just wait to hear from the Ministry of Truth.": "{0.06->4.14}好奇心会让人变成异见分子,我妈妈总是这么说。{6.66->10.65}古老的光能者遗迹会在沉寂千年后重新激活,{11.98->16.03}然后产生时空扭曲现象,让成千上万的公民消失,{17.28->18.62}这种事谁能想到呢?{18.95->22.18}反正我想不到。我还是等真理部的消息吧。", + "{0.00->1.26}The Karlia system": "{0.00->1.31}可利亚星系", + "{0.00->1.21}Making progress.": "{0.00->1.21}有所进展。", + "{0.07->5.28}Who knows what sort of pseudo-intellectualism could be lurking in those Illuminate ruins... {5.88->7.77}and the damage it could do to our way of life.": "{0.07->4.39}谁知道那些光能者遗迹里潜伏着什么伪知识分子主义……{4.74->8.03}会对我们的生存正道造成多大的破坏。", + "{0.03->2.58}Someone, anyone, stim me!": "{0.00->2.70}谁!有谁能给我来一针!", + "{0.00->1.66}High-value sample collected.": "{0.00->1.66}高价值样本到手了。", + "{0.00->1.58}The Spoyle System": "{0.00->1.49}斯珀伊尔星系", + "{0.02->8.52}Remember: as long as you fight for Super Earth - you matter.{8.52->15.34}If you stop, you don't. But you are - and you do.": "{0.00->6.98}切记:只要为超级地球而战,你就有价值。{7.80->11.15}一旦停手,你就失去价值。{11.49->15.50}但你有价值,这点无可否认。", + "{0.01->1.02}I can't!": "{0.01->1.02}我过不去!", + "{0.00->0.28}Two.": "{0.00->0.35}两。", + "{0.00->3.29}We will not allow our planets to fall into their tentacles.": "{0.00->3.29}绝不容许星球落入它们的触手。", + "{0.01->2.09}Compliments of Super Earth!": "{0.01->2.09}向超级地球致敬!", + "{0.00->6.34}If they could speak, I know our heroes would not have us mourn their loss, but rejoice in their {6.42->7.16}victory.": "{0.00->4.51}如果英雄们有遗言,我认为他们不会让我们沉溺于哀悼,{4.89->7.16}而是要为胜利欢呼。", + "{0.00->1.48}All in a day's work.": "{0.00->1.50}职责所在。", + "{0.02->1.53}The Myradesh system": "{0.02->1.53}米拉戴什星系", + "{0.06->1.48}Thank you for saving us.": "{0.06->1.48}谢谢你们来救我们。", + "{0.00->5.29}Well fought, soldiers. You've pried their tentacles from the throat of Liberty.": "{0.00->5.29}士兵们,干得漂亮。你们成功撬开了阻碍解放的触手。", + "{0.00->3.36}I don't blame them—all of us had Helldiver posters all over our bedrooms growin' up.": "{0.00->3.36}不怪他们…我们从小就在卧室里贴满了绝地潜兵海报。", + "{0.99->2.20}Where are the evac ships?": "{0.99->2.20}撤离飞船在哪?", + "{0.37->1.77}I don't deserve the honor.": "{0.00->1.99}我配不上这份荣幸。", + "{0.02->3.43}Someone, anyone, stim me!": "{0.00->3.46}谁!有谁能给我来一针!", + "{0.00->0.60}Dropships!": "{0.00->0.74}运输舰!", + "{0.00->1.42}Bot outpost spotted.": "{0.00->1.42}是机器人哨站。", + "{0.83->1.29}The Helldivers are here!": "{0.16->1.29}绝地潜兵来了!", + "{0.00->1.74}They lease 'em out to me, so I can do my job.": "{0.00->1.74}他们租给了我,我才能顺利工作。", + "{0.00->1.30}Not today!": "{0.00->1.30}死不了!", + "{0.01->2.08}Enemy sighted. Prepare to engage.": "{0.01->2.08}发现敌人。准备交战。", + "{0.00->2.38}Flag-forsaken Fascist.": "{0.00->2.38}无法无天的法西斯。", + "{0.00->2.46}Managed Democracy wins!": "{0.00->2.59}管理式民主必胜!", + "{0.05->0.90}Stay with me!": "{0.00->0.89}坚持下去!", + "{0.23->2.22}You guys do this all the time. Right?": "{0.23->2.22}你们都是老手了,对吧?", + "{0.00->1.91}Freedom never falters.": "{0.00->1.91}自由从不退缩。", + "{0.03->3.15}This is nice. Should be obligatory.": "{0.00->1.60}感觉真好。{1.60->3.36}应该设为义务项目。", + "{0.00->2.01}During their rehabilitation,{2.41->8.41}the Cyborgs took advantage of our mercy and secretly constructed the Automatons.{8.86->16.85}From robotic aides we generously provided, they crafted an army of murderous slaves. And now they{16.85->19.58}repay our kindness in blood.": "{0.00->3.16}生化人在接受改造期间,{3.63->7.82}利用了我们的仁慈,秘密制造了机器人。{8.54->15.47}我们好心提供的机器人助手,被它们改造成了嗜杀的奴隶军队。{16.20->20.03}如今竟用鲜血回报我们的恩情。", + "{0.00->2.68}You came to right place. Much safer here.": "{0.00->2.68}你来对地方了。这里安全多了。", + "{0.03->1.03}We have to keep moving.": "{0.03->1.03}我们得继续前进。", + "{0.00->1.17}Requesting supplies.": "{0.00->1.17}请求投放补给。", + "{0.04->8.02}Some of the other techs heard the citizens who went into the Void got their brains pulled out and put into jars so they could run psychic simulations on them where they had to like,{8.78->11.19}kill their family, or trample the flag.{11.96->16.16}But...that's just talk, I don't buy any of that stuff, obviously.": "{0.00->1.58}还有些技师听说,{1.59->5.10}被寂域吞噬的公民,脑子都被挖出来放进了罐子。{5.57->7.72}光能者用这种手段进行心智模拟,{7.85->11.45}逼他们作出杀害家人、践踏国旗之类的恶劣行径。{12.33->16.55}但……只是传说罢了,我才不信。", + "{0.00->1.61}It's not much, but I donate {2.12->5.48}15% of every one of my paychecks to the War Fund. It's the least I can do.": "{0.00->3.21}所以我把工资的15%都捐给了战争基金,{3.59->5.48}虽然不多,但是我也想尽点力。", + "{0.00->3.52}You will forever be remembered as heroes of this metropolis.": "{0.00->3.52}你将永远被铭记为这座城市的英雄。", + "{0.00->0.92}Tac-pack's empty.": "{0.00->0.98}战术背包空了。", + "{0.07->3.57}The Bots are only attacking Super Earth to distract us from Cyberstan.{4.22->6.42} It's petty payback, is what it is, {7.09->9.65}going after our home just because we're reclaiming theirs.": "{0.00->1.59}机器人攻击超级地球,{1.99->4.32}只是为了转移我们对生化斯坦的注意力。{4.57->5.77}这就是小人报复,{6.24->8.03}就因为我们要收复它们的家园,{8.33->9.72}它们就来攻击我们的。", + "{0.00->1.52}The Vandalon system": "{0.00->1.52}万达隆星系", + "{0.00->2.02}I feel stronger already.": "{0.00->2.19}我感受到了力量。", + "{0.00->0.48}Negative!": "{0.00->0.48}没办法。", + "{0.01->0.60}Follow me!": "{0.01->0.60}跟我走!", + "{0.00->3.21}Burn in the fires of Democracy!": "{0.00->3.21}感受滚烫的民主!", + "{0.03->0.72}Squids!": "{0.03->0.72}鱿鱼!", + "{0.00->0.25}I don't think I can do that.": "{0.00->1.15}我这边过不去!", + "{0.05->1.51}What are those things?": "{0.05->1.51}那都是什么玩意儿?", + "{0.02->1.64}Contact! Stand by!": "{0.02->1.64}交战!准备!", + "{0.00->1.25}Calling down support weapon.": "{0.00->1.42}呼叫支援武器。", + "{0.02->1.03}We're safe!": "{0.02->1.26}我们没事了!", + "{0.01->3.03}Super Earth will never fall to the likes of you!": "{0.01->3.03}你们根本不是超级地球的对手!", + "{0.05->3.25}Another step in the journey to galactic peace.": "{0.00->3.21}向星系和平又迈进了一步。", + "{0.00->0.79}Enemy spotted.": "{0.00->0.80}发现敌人,", + "{0.03->1.27}Help me!": "{0.03->1.27}救救我!", + "{0.13->1.26}I need stims.": "{0.13->1.26}给我来一针。", + "{0.02->1.33}It's gonna cut me open!": "{0.02->1.33}它要把我给撕了!", + "{0.00->0.71}Dropping a pin.": "{0.00->0.71}正在标记,", + "{0.00->0.76}How much longer?": "{0.00->1.05}还要等多久?", + "{0.04->2.33}Cut them down! All of 'em!": "{0.00->2.36}干翻它们!一个不留!", + "{0.00->1.49}SEAF reinforcements, on the way.": "{0.00->1.58}武装部队增援正在路上。", + "{0.00->3.06}Mines! Someone's gonna get a leg blown off!": "{0.27->1.16}有雷!{1.19->3.17}一颗下去腿都得炸废了!", + "{0.00->3.21}A pacified sector is a happy sector.": "{0.00->3.41}平定的分区才是幸福的分区。", + "{0.00->2.32}Gotta fix this Liberty-forsaken arm.": "{0.00->2.32}必须治好这条耽误解放的胳膊。", + "{0.05->1.75}Don't leave me here!": "{0.00->1.69}别丢下我!", + "{0.04->2.48}Sweet Liberty, it's the Helldivers!": "{0.04->2.48}解放保佑,绝地潜兵来了!", + "{0.03->1.32}This is crazy!": "{0.03->1.04}太可怕了!", + "{0.00->2.16}Retribution will find you!": "{0.00->2.16}冤有头债有主!", + "{0.00->9.83}You are here. You are home. You are aboard your very own Super Destroyer.": "{0.00->3.93}你在这里。这里是你的家。{4.60->10.00}这里是属于你自己的超级驱逐舰。", + "{0.01->1.37}That's why they're the best!": "{0.01->1.37}他们是最棒的!", + "{0.00->1.32}The Klaka system": "{0.00->1.32}克拉卡星系", + "{0.00->1.71}Yeah, that's Liberty!": "{0.00->1.75}没错,这就是解放!", + "{0.00->0.75}Dropping item.": "{0.00->0.75}放下物品。", + "{0.02->0.69}Get down!": "{0.02->0.69}卧倒!", + "{0.00->0.64}Fifth one.": "{0.00->0.64}第五个。", + "{0.00->1.18}Greetings, Helldiver. {1.60->3.44}The Galactic War awaits.": "{0.00->1.42}绝地潜兵,你好。{1.97->3.84}星系战争正在召唤你。", + "{0.00->1.14}Illuminate teleporting in.": "{0.00->1.14}光能者即将传送抵达,", + "{0.00->1.62}Watch your lines of fire!": "{0.00->1.66}注意瞄准方向!", + "{0.00->0.66}Fourth one.": "{0.00->0.66}第四个。", + "{0.03->1.12}Get us out of here!": "{0.03->1.12}快带我们走!", + "{0.00->1.24}Not a moment too soon.": "{0.00->1.61}来得正是时候。", + "{0.00->2.17}I've never seen a Helldiver up close before.": "{0.00->2.17}从来没有靠绝地潜兵这么近过。", + "{0.02->1.48}When's the shuttle coming?": "{0.02->1.48}运输船什么时候到?", + "{0.00->1.82}Your name will live on in history.": "{0.00->1.82}你的名字将载入史册。", + "{0.01->1.58}Crush them!": "{0.82->1.82}踩死它们!", + "{0.00->0.76}Critical item.": "{0.00->0.69}关键物品,", + "{0.01->0.62}Here!": "{0.01->0.62}拿着!", + "{0.00->0.61}Illuminate.": "{0.00->0.61}光能者。", + "{0.00->2.45}I knew the Helldivers would protect us.": "{0.00->2.45}我就知道绝地潜兵会保护我们。", + "{0.00->1.49}The Duma Tyr system": "{0.00->1.49}杜马提尔星系", + "{0.02->3.95}You are a true champion of Democracy.": "{0.02->3.76}你是一位真正的民主斗士!", + "{0.02->1.93}Freedom owes you a debt.": "{0.02->1.93}你为自由立下大功。", + "{0.00->1.46}Manning combat walker.": "{0.02->1.62}操纵战斗步行机甲。", + "{0.02->0.97}Exiting cover!": "{0.00->1.03}离开掩体!", + "{0.00->0.62}Nice.": "{0.00->0.88}很好。", + "{0.00->2.27}Yeah! You squash that bug!": "{0.00->2.27}厉害!你弄死了那只虫子!", + "{0.08->5.31}Stake Super Earth's claim, Helldiver; make the Ministry of Expansion proud.": "{0.08->3.45}绝地潜兵,代表超级地球宣示主权。{3.45->5.31}让扩张部为你们骄傲。", + "{0.08->4.82}Though the quietus of the Cyborgs failed, it seems to have had {4.82->10.56}another effect: sterilization. The Cyborg Production Units {10.56->14.08}within the Megafactories are not merely war factories;{14.49->20.19}they are the means by which the Cyborgs hope to synthetically avert their own extinction.": "{0.27->3.38}虽然对生化人的灭绝行动失败了,{3.92->8.36}但似乎对它们产生了另一种效果:绝育。{8.98->13.77}超大型工厂内的生化人生产单元不只是兵工厂,{14.17->19.79}也是生化人试图用合成手段规避自身灭绝的工具。", + "{0.00->1.54}I'm in your debt, Helldiver.": "{0.00->1.87}绝地潜兵,我欠你一回。", + "{0.01->1.58}NOOOOOOOO!!!!!!": "{0.01->1.58}不!", + "{0.01->0.63}Here!": "{0.01->0.63}拿着!", + "{0.10->2.85}That... was close...": "{1.24->2.85}好险…", + "{0.03->1.43}Hostiles on me!": "{0.00->1.49}敌人在打我!", + "{0.23->4.95}Studies on captured Voteless have begun to yield insight into their creation. {5.54->9.66}Their DNA has been altered, resulting in physical deformities. {10.16->14.73}Their minds, meanwhile, bear the marks of extreme thought control. {15.26->22.76}Similar to our own patriotic re-education protocols...but twisted into something profane.": "{0.64->5.80}我们研究了俘获的无票者,逐步查明了他们的形成过程。{6.00->10.26}他们的DNA惨遭篡改,导致身体畸形。{10.43->16.44}与此同时,他们的心智中还残留着极端思想控制的痕迹。{16.60->22.98}这与我们自己的爱国再教育方案类似…但却被扭曲成了邪恶的东西。", + "{0.11->7.69}Hold up, recruit. It's finally time to call in the big guns. Use the support weapon stratagem to {7.69->9.69}get yourself a real weapon.": "{0.11->4.42}等一下,新兵。终于到了呼叫强力武器的时候。{5.13->9.69}使用支援武器战略配备,换上真正的武器。", + "{0.00->1.72}This city needs our aid.": "{0.00->1.72}城市需要我们支援。", + "{0.00->0.53}Bug hole.": "{0.00->0.53}虫穴,", + "{0.00->1.49}Bug Tunnel breach detected!": "{0.00->1.49}侦测到虫族隧道洞口!", + "{0.01->0.60}I'm out!": "{0.01->0.60}没弹药了!", + "{0.00->1.27}I thought you'd never ask!": "{0.00->1.08}就等你问了!", + "{0.00->1.91}I'll need to requisition some more Hellpods.": "{0.00->1.91}我得再多申请一些绝地喷射舱。", + "{0.04->2.64}No way, no way!": "{0.00->2.55}不得了,不得了!", + "{0.03->3.46}They killed a Helldiver...We're all gonna die!": "{0.03->3.46}它们杀了绝地潜兵……我们全都死定了!", + "{0.18->0.95}Stims!": "{0.00->1.16}立即扎针!", + "{0.04->1.56}I needed that.": "{0.00->1.61}我太需要这个了。", + "{0.00->1.35}Look, a good bug.": "{0.00->1.35}虫子死了才好。", + "{0.01->2.27}The Galaxy embraces us.{2.27->11.98}When its nonhuman inhabitants try to murder you on sight, they are a disturbance to the natural order.{11.98->13.87}Super Earth's order.": "{0.01->1.88}银河系眷顾我们。{2.66->7.50}如果银河系内的非人类居民一见到你就要灭口,{7.98->10.66}它们都是在干扰自然秩序。{11.79->14.01}超级地球的秩序。", + "{0.00->2.70}SEAF extracted. Rest is up to you, Helldiver.": "{0.00->1.35}武装部队已撤离。{1.36->2.89}绝地潜兵,交给你们了。", + "{0.00->0.55}Cancel that.": "{0.00->0.55}不必了。", + "{0.14->1.23}DEMOCRACY FOR{1.66->2.75}EVERYONE!!": "{0.00->2.01}民主保佑!", + "{0.03->0.81}Moving up!": "{0.00->0.90}向前推进!", + "{0.00->0.40}Left.": "{0.00->0.40}左边。", + "{0.00->1.77}Nice job, rookies.": "{0.00->1.80}干得漂亮,菜鸟们。", + "{0.01->1.63}For Super Earth!": "{0.00->1.75}为了超级地球!", + "{0.04->1.74}GET DOWN!": "{0.00->1.80}快趴下!", + "{0.12->1.95}The Epsilon Phoencis system": "{0.00->1.95}艾普西隆芬赛斯星系", + "{0.02->3.57}My legs! For the love of Liberty, my legs!": "{0.02->3.57}我的腿!我超级自由的腿!", + "{0.02->2.31}A glorious battle! Right?!": "{0.00->2.58}光荣的战斗!对吧?!", + "{0.00->0.21}Gotta {0.59->1.95}patch up this leg.": "{0.00->2.12}这条腿得处理下。", + "{0.00->2.43}Live long enough and anything can happen.": "{0.00->2.47}只要活得够久,什么都能见到。", + "{0.03->3.04}The blood. Can't stop the blood.": "{0.03->3.04}血,都他民主的流干了!", + "{0.00->1.32}The Imber system": "{0.00->1.32}因博尔星系", + "{0.01->0.44}Bugs.": "{0.01->0.44}虫族。", + "{0.00->0.55}Tie.": "{0.00->0.55}平手。", + "{0.00->1.41}Socialist scum.": "{0.00->1.41}铁皮渣滓。", + "{0.02->4.61}For...Super Earth...": "{0.81->5.56}为了…超级地球…", + "{0.00->1.28}I'll never forget this.": "{0.00->1.28}我不会忘记你们的。", + "{0.34->0.95}Kill them all!": "{0.00->1.08}把他们杀光!", + "{0.00->1.64}Calling down support weapon.": "{0.00->1.46}呼叫支援武器。", + "{0.00->1.68}Point me to the enemy.": "{0.00->1.68}告诉我敌人在哪儿。", + "{0.02->3.84}What the...? MINES! Mines all over!": "{0.00->1.29}什么……?{1.29->4.03}有雷!遍地都是地雷!", + "{0.00->1.52}The great leveler --{1.90->3.57}Hellbomb secured.": "{0.00->1.52}发现大杀器——{1.90->3.57}地狱火炸弹。", + "{0.00->1.95}Hellbomb armed—clear the area.": "{0.00->2.22}地狱火启动,炸平这里。", + "{0.00->3.01}Remain ever-vigilant for deceit and treachery. {3.73->6.27}They can take root in the smallest of cracks.": "{0.00->2.81}必须时刻提防欺骗和背叛。{3.01->6.47}稍有破绽,它们就会生根发芽。", + "{0.00->0.59}Fifth one.": "{0.00->0.59}第五个。", + "{0.00->4.21}You have ignited the torches of Liberty. Extraction awaits.": "{0.00->4.21}你已经点燃解放的火炬,可以撤离了。", + "{0.00->0.70}Boom!{0.82->3.53}Another alien interloper in the ground!": "{0.00->0.60}砰!{0.82->3.05}又干掉一个外星入侵者!", + "{0.00->0.81}We're saved.": "{0.00->0.81}我们得救了。", + "{1.15->3.09}Many hands make Liberty work.": "{1.00->2.61}团结才能自由。", + "{0.00->1.67}The Vindemitarix system": "{0.00->1.67}文德米塔里克斯星系", + "{0.00->3.21}You are deep in enemy territory, Helldiver.{3.71->5.92}May Liberty guide your aim.": "{0.00->2.73}绝地潜兵,你已深入敌后。{3.41->5.59}愿解放指引你的枪口。", + "{0.05->3.80}If I were a Helldiver, I think my favorite enemy to kill would be the Illuminate.": "{0.01->4.29}我要是绝地潜兵,我最喜欢杀的敌人应该是光能者。", + "{0.00->4.47}If I never see a uncanny horror from an inexplicable altered spacetime again,{4.98->6.13}it'll be too soon.": "{0.00->3.18}啊……我这辈子都不想再见到这玩意儿,{3.59->5.82}再见,再也不见。", + "{0.01->1.51}Might've cast my last Vote...": "{0.01->1.51}再投最后一票……", + "{0.01->1.43}Moving up, cover me!": "{0.00->1.57}向前推进,掩护我!", + "{0.00->1.98}Remember your training, Helldiver.{2.37->9.75}You are the elite, and no ghoulish apparition or un-Democratic abomination is your match.": "{0.00->2.90}绝地潜兵,牢记接受过的训练。{2.90->7.72}你们是真正的精英,任何阴森幻影或反民主怪胎{7.72->9.85}都不会是你们的对手。", + "{0.02->1.60}I was almost done for...": "{0.34->1.80}差点儿就交代了……", + "{0.00->1.25}The Hadar system": "{0.00->1.25}马腹一星系", + "{0.00->3.48}The tides of Liberty will sweep these streets clean.": "{0.00->3.48}让解放的春风吹满大地。", + "{0.00->0.84}You're back quickly. {1.29->1.95}Well done.": "{0.00->1.17}你回来得很快。{1.44->2.09}干得好。", + "{0.00->3.18}NO ENEMY OF FREEDOM WALKS AWAY FROM THIS!": "{0.00->3.18}自由的敌人,一个都别想逃!", + "{0.04->2.80}We have to, we've gotta—run!": "{0.00->1.83}我们……我们得——{1.83->2.98}赶紧跑!", + "{0.01->1.45}It sounds worse than it is.": "{0.01->1.45}好像也没那么可怕。", + "{0.00->1.12}Need more ammo!": "{0.00->1.12}需要弹药!", + "{0.04->3.03}Reposition! We'll strike even harder elsewhere!": "{0.00->3.09}转移阵地!换个地方全力打击!", + "{0.00->1.83}The enemies on the battlefield are one thing, {2.31->3.69}but at least they're out in the open. {4.29->7.06}It's the traitors among us I truly hate.": "{0.00->1.83}战场上的敌人虽然不好对付,{2.31->3.69}但它们至少在明处。{4.29->7.06}我真正讨厌的是藏在暗处的叛徒。", + "{0.00->0.10}I'm out.": "{0.00->0.55}打光了。", + "{0.01->1.74}Freedom never sleeps!": "{0.01->1.74}自由真提神!", + "{0.01->1.93}For the glory of Super Earth!": "{0.01->2.16}荣耀属于超级地球!", + "{0.00->1.23}A Hellbomb!{1.79->3.15}NOW we're talking!": "{0.00->1.03}地狱火炸弹!{1.56->2.72}这才像话!", + "{0.00->0.67}Rolling out!": "{0.00->0.67}出发!", + "{0.00->1.24}The Keid system": "{0.00->1.57}九州殊口增七星系", + "{0.01->0.76}Over there!": "{0.01->0.76}在那边!", + "{0.00->1.05}Jump complete.": "{0.00->1.05}跃迁完毕。", + "{0.02->0.88}Clear the area!": "{0.00->0.94}撤出该区域!", + "{0.00->1.82}Sweet Liberty that was close!": "{0.00->1.82}好他民主的险!", + "{0.00->0.60}I'm out.": "{0.00->0.60}没弹药了。", + "{0.00->2.07}ETA T-30 seconds.": "{0.00->2.07}预计30秒后到达。", + "{0.02->0.75}Over here!": "{0.02->0.75}这里!", + "{0.00->0.74}New canister.": "{0.00->0.74}新燃料罐。", + "{0.05->0.92}Stimming you.": "{0.05->0.92}爽吗?", + "{0.00->2.86}Make sure you show it the proper respect!": "{0.00->2.86}一定要好好敬个礼!", + "{0.00->1.72}United we stand!": "{0.00->1.72}我们团结一致!", + "{0.09->5.32}I wish I could see the look on the squid's faces, right before they explode.": "{0.09->4.83}真希望亲眼看看那些鱿鱼在爆炸前最后一刻的表情。", + "{0.00->1.52}The tentacles!": "{0.00->1.52}是触手!", + "{0.07->7.21}The question remains: why now do the Cyborgs reveal themselves to us? {8.04->13.21}Perhaps our answer lies in the mechanized wasteland of Cyberstan.": "{0.07->6.40}还是那个问题:生化人为什么要在这个时候现身?{7.34->12.84}也许答案就在生化斯坦的机械化荒地中。", + "{0.02->0.93}Found something.": "{0.02->0.93}这边有发现。", + "{0.00->0.87}Don't let go.": "{0.00->0.95}别放手。", + "{0.00->1.13}Anything you ask!": "{0.00->1.13}你说什么都行!", + "{0.00->2.72}Democracy will never fail.": "{0.00->2.92}民主战无不胜。", + "{0.00->1.39}The Ratch system": "{0.00->1.39}拉奇星系", + "{0.00->0.49}Bravo": "{0.00->0.49}B", + "{0.00->2.96}Here you may assess the current state of the Galactic War. {3.71->8.95}The conflict rages across many sectors. It is up to you where to lend your aid.": "{0.00->3.47}你可以从这里了解到星系战争的现状。{3.86->9.14}很多区域都在遭受战火蹂躏。由你来决定前往哪个区域。", + "{0.31->1.15}The price...{1.99->3.13}of Freedom...": "{0.00->1.61}自由的…{2.44->3.83}代价…", + "{0.04->2.00}The might of Super Earth!": "{0.04->2.00}超级地球的力量!", + "{0.00->0.93}Bot fabricator.": "{0.00->0.93}机器人构筑者,", + "{0.00->1.60}What have I done!?": "{0.31->1.69}我在干什么?", + "{0.00->2.38}Firing orbital barrage. Clear the area.": "{0.00->2.38}即将发射轨道火力网。远离此地。", + "{0.21->1.82}Uh, may I have your attention please: {2.41->5.96}you may be required to dive to the ground to pass your training. {6.52->7.14}Please resume.": "{0.00->2.06}呃,请注意听我说:{2.15->5.96}你必须得扑倒在地才能通过训练。{6.39->7.26}请继续吧。", + "{0.00->1.66}I'm bleeding out!": "{0.00->1.66}我流血了!", + "{0.00->2.49}The citizens of this city will thank you.": "{0.00->2.49}这座城市的公民感谢你的付出。", + "{0.01->1.42}Incoming fire!": "{0.00->1.48}敌方火力很猛!", + "{0.00->0.34}Zero.": "{0.00->0.34}洞。", + "{0.00->5.69}One day, we'll get back all the worlds that the Illuminate are holding hostage. And when we do,{6.25->8.92}we'll show them what devastation really means.": "{0.00->3.99}总有一天,我们会夺回所有被光能者劫持的世界。{4.68->8.87}到那时,我们会让它们见识什么叫真正的毁灭。", + "{0.00->2.69}Democracy prevails once more.": "{0.00->2.69}民主再度得利。", + "{0.06->3.73}Yes! All that training's finally paying off.": "{0.00->1.47}赢了!{1.88->3.73}平时的训练总算没白费。", + "{0.00->1.78}I fight for Freedom.": "{0.00->1.78}我为自由而战。", + "{0.01->2.26}GRENADE! Stay back!": "{0.01->2.26}手雷!别过来!", + "{0.00->3.45}The Destroyer is mighty, but it's not Super Earth's greatest weapon. {4.14->4.65}No, {5.16->7.07}that is Managed Democracy—{7.47->10.66}the one thing our enemies can never understand.": "{0.00->1.55}驱逐舰固然强大,{1.77->5.77}但超级地球最伟大的武器当属管理式民主,{6.68->10.86}敌人永远无法理解这件武器真正的威力。", + "{0.00->1.82}High Priority Target eliminated.": "{0.00->1.82}已消灭高优先级目标。", + "{0.03->1.12}Moving on target.": "{0.00->1.28}向目标移动。", + "{0.00->4.47}Today the light of Liberty will grace the skies of this world once more.": "{0.00->4.47}今天,这个世界的黑夜将再次迎接解放的光芒。", + "{0.04->1.65}For Super Earth!": "{0.00->1.64}为了超级地球!", + "{0.06->1.15}Is that really them?": "{0.00->1.28}这真的是他们吗?", + "{0.20->2.02}I earned a few more Citizenship points the other day.": "{0.00->2.45}前几天我又挣到了一点公民积分。", + "{0.02->1.21}Rounds on target!": "{0.00->1.30}火力覆盖!", + "{0.02->1.56}Feels gooooood.": "{0.02->1.56}真他民主的爽!", + "{0.00->1.80}Should've stayed home, scum!": "{0.00->1.80}你们挑错日子了!", + "{0.00->4.22}Helldivers across the galaxy are fighting for every inch of territory. {4.90->6.03}Where will you join them?": "{0.00->3.92}绝地潜兵正在银河系为每一寸领土抛洒热血。{4.68->6.03}你要在哪里加入他们?", + "{0.53->1.83}Son of a dissident!": "{0.00->1.44}解放你大业的!", + "{0.00->1.93}C'mere, you big lunk o' Liberty.": "{0.00->2.05}来吧,你这自由的大块头。", + "{0.03->0.82}Advance!": "{0.00->0.88}前进!", + "{0.05->2.41}No way, no way!": "{0.00->2.46}不得了,不得了!", + "{0.00->6.23}Have any of your friends or family members been behaving unpatriotically? If so, report them to {6.23->9.73}your local Loyalty Officer for immediate reeducation. {10.11->13.48}Remember, Freedom dies in Silence!": "{0.00->3.56}最近有没有发现好友或家人出现不爱国的迹象?{4.29->7.27}一旦发现,请向当地的忠诚事务官举报,{7.57->9.68}让他们立即接受二次教育。{10.28->13.75}切记,自由会在沉默中消亡!", + "{0.00->5.23}We have to protect Super Earth! If we don't protect our home, we might never get to see it for{5.23->5.87}ourselves.": "{0.07->1.77}我们必须保护超级地球!{2.04->3.47}我们要是不去保护家园,{3.84->5.92}可能永远都没机会亲眼见到它了。", + "{0.03->1.36}Cover, cover!": "{0.00->1.38}隐蔽,隐蔽!", + "{0.00->1.40}The Lesath system": "{0.00->1.40}尾宿八星系", + "{0.00->1.35}The Haldus system": "{0.00->1.35}海德斯星系", + "{0.03->1.26}Automatons!": "{0.03->1.26}机器人!", + "{0.03->2.49}[deep breath] ah. Liberty.": "{0.03->2.49}啊。自由。", + "{0.03->1.89}Reposition! Clear the mark.": "{0.00->1.95}转移位置!离开标记区域。", + "{0.00->1.30}We're going this way now!": "{0.00->1.10}我们走这边!", + "{0.00->6.45}The reconstruction of Super Earth continues. Ground has been broken on a new Megacity.": "{0.00->6.45}超级地球的重建仍在继续。新的特大城市已经破土动工。", + "{0.08->1.58}The Adrenal System": "{0.08->1.09}脉涌星系", + "{0.00->2.95}1 minute left! Destroyer preparing to leave.": "{0.00->2.95}还剩1分钟!驱逐舰准备撤离。", + "{0.00->0.95}Dropping package.": "{0.00->0.74}丢下物品。", + "{0.00->2.71}Eagle 1, returning to Destroyer for resupply.": "{0.00->2.71}“飞鹰”1号返回驱逐舰进行补给。", + "{0.00->0.54}Supplies.": "{0.00->0.54}补给,", + "{0.01->1.37}You saved my life!": "{0.00->1.51}你救了我的命!", + "{0.00->1.20}I fight for Freedom.": "{0.00->1.20}我为自由而战。", + "{0.00->1.51}Bring it down!": "{0.00->1.68}炸平这里!", + "{0.51->1.95}Time for our slice of glory!": "{0.00->2.03}立功的时候到了!", + "{0.00->0.95}Marking location.": "{0.00->0.95}标记地点,", + "{0.00->4.38}You have been a stalwart line of Freedom—extract when ready.": "{0.00->2.25}不愧是坚定不移的自由斗士,{2.82->4.38}准备好就撤离吧。", + "{0.04->1.48}Cover! Now!": "{0.00->1.54}找掩护!快!", + "{0.01->1.07}No way through!": "{0.01->1.07}没有路了!", + "{0.00->0.80}Item collected.": "{0.00->0.80}东西到手了。", + "{0.04->2.86}Argh! It's fine, we're fine...": "{0.00->1.76}啊!没事,{1.77->2.88}我们没事……", + "{0.00->0.95}Enemy outpost.": "{0.00->0.95}敌方哨站。", + "{0.00->0.84}A Helldiver?{1.27->2.67}Sir or uh, Ma'am,{3.23->4.65}it is the GREATEST honor.": "{0.00->0.73}绝地潜兵?{1.90->4.01}见到你是我最大的荣幸。", + "{0.01->3.21}Tell my family...to vote...": "{0.00->1.77}告诉我家人……{2.51->3.67}投票……", + "{0.02->2.14}Freedom, at any cost!": "{0.00->2.30}为了自由不惜代价!", + "{0.04->2.24}Ugh, not in front of the Diver...": "{0.00->2.33}呃,不能倒在潜兵面前……", + "{0.03->2.47}I mean, I can't even imagine trying to secede.{2.70->6.09}If you're not in any state databases, do you even exist?": "{0.03->2.86}有一说一,我想不到什么搞独立的理由。{3.34->6.07}连数据库登记都没有,那还算存在吗?", + "{0.01->2.83}Back, run, fall back!": "{0.00->2.94}撤退,快,撤退!", + "{0.01->4.90}We can do no more for this city today. The mission is failed.": "{0.01->4.90}这座城市没救了。任务失败。", + "{0.00->1.12}I need a team reload.": "{0.00->1.12}给我来点弹药。", + "{0.00->2.95}Melt them down! Turn 'em into something useful!": "{0.00->2.95}全都烧了!烧成有用的!", + "{0.00->1.17}The Azur system": "{0.00->1.17}艾热尔星系", + "{0.00->0.40}Five.": "{0.00->0.40}五。", + "{0.00->7.94}How dare they attack Super Earth. All those innocent families, all those prosperous businesses...": "{0.00->2.35}它们怎么敢攻击超级地球。{3.13->8.09}那么多无辜的家庭,那么多繁荣的企业……", + "{0.00->2.11}Democracy will never fail.": "{0.00->2.10}民主战无不胜。", + "{0.01->0.99}The bots are here!": "{0.01->0.99}机器人来了!", + "{0.00->2.95}When the whole Service Technician corps got sent to training at once, I{3.53->5.58}knew there must have been a good reason.{6.02->11.44}And I was right: support for a workers strike is no small matter. That kind of talk is a gift to{11.44->12.06}our enemies.": "{0.00->3.23}整个维修技术员团队同时被派去培训时,{3.70->5.58}我就知道事出有因。{6.40->9.87}果然被我说中了:支持工人罢工可不是小事。{10.52->13.04}这种言论就是给敌人送大礼。", + "{0.00->0.72}Nailed 'em!": "{0.00->0.72}满分!", + "{0.19->1.82}I'll remember this forever.": "{0.19->1.82}我会永远记住你们的。", + "{0.01->1.60}Calling down fortifications.": "{0.01->1.60}请求部署防御工事。", + "{0.01->1.61}Give them what they deserve!": "{0.01->1.61}给它们应有的惩罚!", + "{0.03->1.27}Requesting air support.": "{0.03->1.27}请求空中支援。", + "{0.02->2.87}Cluster together -- safety in numbers!": "{0.02->2.87}靠过来,人多安全!", + "{0.01->1.47}Calling in mission shuttle.": "{0.01->1.47}呼叫任务运输船。", + "{0.00->1.87}The Illuminate must be stopped.": "{0.00->1.87}一定要阻止光能者。", + "{0.06->4.02}So the Cyborgs just reproduce and reproduce, like rats...{4.58->7.12}spitting in the face of family values.": "{0.06->3.26}生化人一个劲儿地繁殖,跟老鼠似的……{3.91->6.11}完全是在践踏家庭价值观。", + "{0.00->2.09}When all is quiet, {3.25->5.22}listen for the Super Earth {5.38->6.15}anthem.{6.15->8.67} Hear it in your heart.{8.67->11.41} Sing it with your mouth.{11.41->17.66} Belt it from your diaphragm, for all the Galaxy to hear.": "{0.00->6.45}在万籁俱寂时,聆听超级地球国歌。{7.88->12.18}用心品味。高声吟唱。{12.89->17.94}让雄浑之声,响彻整个银河系。", + "{0.02->1.78}Flag-forsaken robots!": "{0.02->1.78}一堆破铜烂铁!", + "{0.00->1.68}Liberty for every being.": "{0.00->1.68}一切皆可解放。", + "{0.01->1.95}Was that them? That was them.": "{0.01->1.95}它们搞的吗?就是它们。", + "{0.00->2.28}This is it. I can die happy.": "{0.00->2.35}真不错啊。我死而无憾了。", + "{0.00->1.41}That's how it's done.": "{0.00->1.46}赢得很自然。", + "{0.00->4.53}We're fighting three fronts: the Terminids on one side, the Automatons on the other...{4.91->7.46}and the Illuminate, who seem to be everywhere.": "{0.00->4.81}我们正在三线作战:一边是终结族,另一边是机器人…{5.21->7.65}还有仿佛无处不在的光能者。", + "{0.00->0.91}Swapping battery.": "{0.00->0.91}换下电池。", + "{0.02->2.25}Get back, you filthy squids!": "{0.02->2.01}恶心的鱿鱼,滚开!", + "{0.00->2.09}Alien wildlife found. Assessment: {2.53->3.14}adorable.": "{0.00->1.39}发现外星野生动物。{1.41->3.14}评估:真可爱。", + "{0.04->0.88}Moving in!": "{0.00->0.88}向前推进!", + "{0.00->1.12}Enemy outpost spotted.": "{0.00->1.12}发现敌方哨站。", + "{0.00->0.70}Reloading!": "{0.00->0.70}换弹!", + "{0.00->5.70}Every bullet fired in the name of Super Earth is a bullet fired for freedom!": "{0.00->3.14}以超级地球之名发射的每一颗子弹{3.71->5.72}都是为自由而战!", + "{0.00->0.37}Heavy.": "{0.00->0.37}重型敌人,", + "{0.00->1.17}The Tibit system": "{0.00->1.17}提比特星系", + "{0.00->0.34}Eight.": "{0.00->0.34}八。", + "{0.01->0.95}Sample collected.": "{0.01->0.95}样本到手了。", + "{0.01->0.91}I'm hit!": "{0.01->0.91}我中弹了!", + "{0.17->1.07}I was just thinking: {1.58->6.24}warping across the Federation like this would be impossible without Element 710. {7.11->9.44}Which comes from the bugs themselves. {10.02->14.60}Their own corpses are fueling the creation of more corpses...{16.87->18.30}something satisfying about that.": "{0.00->3.04}我在想:要是没有710元素,{3.23->6.62}我们就无法像如今这样在联邦星域内穿梭。{7.01->9.37}这种元素源自虫族的躯体。{9.69->13.43}用虫族尸体制造出的能量干掉更多虫族…{15.35->17.15}感觉很爽。", + "{0.03->6.21}The Illuminate excavate the corpse of their dead civilization. To what end?{6.21->14.95}Do they seek to restore their empire to its former ignominy, and once again cast the galaxy into Tyranny?{14.95->16.76}We will not allow it.": "{0.03->4.37}光能者正在挖掘死寂文明的残骸。{4.86->6.18}它们要做什么?{6.69->13.17}它们是想恢复往日的帝国,再次让银河系陷入暴政吗?{13.81->16.71}这种事决不允许。", + "{0.02->0.52}Help!": "{0.02->0.52}救命!", + "{0.00->1.68}Democracy conquers all.": "{0.00->1.68}民主征服一切。", + "{0.03->0.85}R-really?": "{0.03->0.85}真、真的吗?", + "{0.03->1.30}Robot scum!": "{0.03->1.30}铁皮渣滓!", + "{0.00->1.76}Requesting stim!": "{0.00->1.86}请求治疗剂!", + "{0.00->1.84}Want me to go lure in some hostiles?": "{0.00->1.84}要不我再引些敌人过来?", + "{0.00->2.33}AGH! EARS RINGING!": "{0.00->2.33}啊!我听不见了!", + "{0.00->1.51}The Caramoor system": "{0.00->1.51}开勒莫尔星系", + "{0.30->2.69}I'm sorry, Helldiver!": "{0.00->2.85}我真的真的不是故意的!", + "{0.00->1.55}The Vega Bay system": "{0.00->1.55}织女一湾星系", + "{0.02->0.76}On the gun!": "{0.00->0.81}机枪手就位!", + "{0.00->5.15}Textbook tactics. Create a diversion, split our forces. Its a desperate attempt to keep us from{5.15->6.22}taking Cyberstan.{6.87->10.05}But that just means we'll crush them on two fronts at once.": "{0.00->3.38}典型的战术。声东击西,分散我军兵力。{4.00->6.99}不过为了阻止我们夺取生化斯坦而垂死挣扎。{7.49->10.99}但也正好让我们能同时在两条战线上碾压它们。", + "{0.00->0.98}We're gonna be ok.": "{0.00->0.98}会没事的。", + "{0.02->1.02}Recruit expired. {1.41->3.67}Request terminid containment crew to training area.": "{0.02->1.02}新兵死亡。{1.41->3.74}请终结族控制组前往训练区。", + "{0.00->2.80}This operation will fuel Liberty's future.": "{0.00->3.45}此次行动会为解放的光明未来添砖加瓦。", + "{0.05->3.32}Alert: Defense of currently orbited planet from {3.70->7.70}Terminid invasion has ended in temporary defeat. {8.32->11.32}Planet now under Terminid control.": "{0.00->7.01}通知:当前星球抵御终结族入侵的行动暂时失利。{7.09->11.32}该星球现在归终结族统治。", + "{0.05->1.96}Freedom smiles on us.": "{0.00->2.14}自由眷顾我们。", + "{0.00->1.13}Engaging terminal.": "{0.00->1.13}操作终端。", + "{0.00->1.05}Ready to Liberate.": "{0.00->1.05}准备好解放。", + "{0.00->4.54}If the Automatons can feel regret, they shall feel it soon.": "{0.00->4.54}假如机器人也有情绪,那它们很快就会后悔。", + "{0.03->1.32}Move up!": "{0.51->1.38}前进!", + "{0.00->0.81}They missed!": "{0.00->0.81}它们打偏了!", + "{0.00->2.92}The Justice this baby's gonna dish out...": "{0.00->2.30}这宝贝一定能执行正义…", + "{0.00->2.79}Liberty returns, locked and loaded.": "{0.00->2.79}解放归来,全副武装。", + "{0.00->2.62}You must drive the Terminids back from this world. {3.00->5.11}Choose an operation, and strike.": "{0.00->2.26}一定要把终结族逐出这颗星球。{2.57->5.11}选择一项行动,然后奋勇出击。", + "{0.00->1.46}Terminid Outpost purged.": "{0.00->1.46}已清除终结族哨站。", + "{0.03->1.67}In a bit of a pickle here!": "{0.00->1.74}情况棘手,有点麻烦!", + "{0.04->1.55}What are those things?": "{0.05->1.42}那都是什么玩意儿?", + "{0.30->1.40}I thought you'd never ask!": "{0.05->1.40}就等着你问了!", + "{0.01->2.55}Hahahahaha!": "{0.01->2.55}啊哈哈哈!!", + "{0.04->1.49}I don't think I can do that.": "{0.04->1.49}我这边过不去。", + "{0.00->0.93}Let's do it!": "{0.00->1.06}干就完了!", + "{0.05->3.57}Did—did you see that? Wait 'til my kids hear about this!": "{0.00->3.44}你——你看到了吗?我以后得说给我孩子听。", + "{0.00->2.95}When I vote, I'll think of you, Helldiver.": "{0.00->2.95}绝地潜兵,你就是我投票的动力。", + "{0.00->1.25}Freedom's greetings!": "{0.00->1.25}自由向你问好!", + "{0.08->1.85}Look up in the sky, recruit; {2.47->4.78}that there is a Super Destroyer, {5.29->9.27}and its all-powerful Stratagems are yours to command.": "{0.08->1.85}新兵,看天上。{2.47->4.78}那是一艘超级驱逐舰。{5.29->9.27}你可以下令调用舰船上的强力战略配备。", + "{0.00->3.58}Super Earth will never forget the Helldivers we lost today, {4.28->7.45}nor the incremental gains their sacrifice achieved.": "{0.00->3.95}超级地球永远不会忘记今天失去的绝地潜兵,{4.50->7.66}也不会忘记他们牺牲自我作出的贡献。", + "{0.00->0.64}Contact!": "{0.00->0.64}上啊!", + "{0.03->0.89}There's something here.": "{0.03->0.89}这里有发现。", + "{0.03->1.30}Incoming!": "{0.00->1.33}要来了!", + "{0.05->1.21}For the fallen.": "{0.00->1.23}为了牺牲者。", + "{0.02->2.52}Moral fortitude will see us through.": "{0.02->2.52}信念指引一切。", + "{0.01->0.64}Get in!": "{0.01->0.64}上来!", + "{0.04->0.89}Helldiver. {1.26->4.81}The time has come to reclaim our stolen galaxy.": "{0.04->0.89}绝地潜兵,{1.35->4.30}是时候夺回被侵占的银河系了。", + "{0.00->1.50}Real Helldivers! {3.07->3.17}I don't believe it!": "{0.00->3.38}绝地潜兵,真的是绝地潜兵!", + "{0.00->2.62}Bug hive spotted. Prepare to exterminate.": "{0.00->2.62}发现虫窝,准备捣毁。", + "{0.02->1.24}This is a nightmare!": "{0.02->1.24}太吓人了。", + "{0.07->1.36}Not today!": "{0.07->1.36}死不了!", + "{0.03->1.69}Undemocratic bastards!": "{0.00->1.57}不服从民主的畜生!", + "{0.01->1.71}Heavy ordnance. Fall back!": "{0.00->1.71}重火力打击!撤退!", + "{0.05->2.57}Stim me, stim me Helldiver!": "{0.00->2.68}绝地潜兵,扎我,快扎我!", + "{0.03->1.47}The tentacles!": "{0.03->1.47}是触手!", + "{0.00->5.18}The bots are simple enough. Little more than bits of metal welded to a gun and a CPU, with a single {5.18->6.32}overriding directive: {7.01->7.64}kill.": "{0.00->1.76}机器人的构造相当简单。{1.88->5.16}基本就是一堆金属,焊接上一把枪和一块CPU,{5.39->8.37}再加上一条最高指令:杀戮。", + "{0.00->0.53}Illuminate.": "{0.00->0.53}光能者,", + "{0.00->1.82}Glad to bolster our ranks.": "{0.00->1.82}很高兴能壮大队伍。", + "{0.02->1.13}Protect us!": "{0.02->1.13}保护我们!", + "{0.00->4.68}Hungry? Grab a bag of Prosperitos. A little taste of Freedom {5.11->5.95}in every bite.": "{0.00->2.62}肚子饿了?来一包繁荣脆角。{3.22->6.05}每一口都是自由的滋味。", + "{0.00->0.95}Dangerous wildlife.": "{0.00->0.95}危险的野生动物,", + "{0.00->0.50}Seven.": "{0.00->0.50}拐。", + "{0.00->3.27}Remember soldiers: waste enemies, not bullets!": "{0.00->3.93}战士们,记住:打爆敌人很重要,但不能浪费子弹!", + "{0.03->1.72}Take a moment to remember: {3.76->5.90}Every sacrifice matters.": "{0.00->6.16}你要记住:每一次牺牲都至关重要。", + "{0.00->4.86}Terminid scientists say the Gloom facilitates bug communication across the vastness of space.{5.42->12.44}Nothing complicated - just simple signals, like \"food here\" or \"danger,\" or \"I hate Freedom.\" Stuff{12.44->12.92}like that.": "{0.00->4.09}终结族科学家说“阴霾”促进了广袤太空之中的虫族交流。{4.39->7.34}内容不算复杂,就是些简单的信号,{7.60->13.27}比如“这里有食物”、“危险”,或者是“讨厌自由”。诸如此类的。", + "{0.00->2.79}Victory in this operation has eluded our grasp. {3.50->5.74}But our resolve remains firm.": "{0.00->3.54}这次行动,我们虽然与胜利失之交臂。{4.06->5.96}但决心丝毫不会动摇。", + "{0.00->1.76}You really are the best of the best.": "{0.00->1.32}你们是精英中的精英。", + "{0.02->0.96}Coming in hot!": "{0.02->0.96}加入战场!", + "{0.00->0.52}Far.": "{0.00->0.52}有点远。", + "{0.00->1.56}The Nibiru System": "{0.00->1.19}尼比鲁星系", + "{0.00->3.44}Nothing fills you up like the taste of Democracy!": "{0.00->3.65}没有什么比民主的滋味更让人满足了!", + "{0.03->1.73}I'm inspired!": "{0.00->1.83}我感受到了力量!", + "{0.00->2.40}The squids will find no purchase here.": "{0.00->2.40}鱿鱼将毫无胜算。", + "{0.00->0.63}Southwest.": "{0.00->0.59}西南,", + "{0.03->1.69}That's for the Creek.": "{0.03->1.68}这是为麦河报仇。", + "{0.00->0.95}Package acquired.": "{0.00->0.95}物品到手了。", + "{0.00->1.71}Calling in reinforcements!": "{0.00->1.71}呼叫新的增援!", + "{0.01->0.94}Weapons on red!": "{0.00->1.02}武器解除保险!", + "{0.00->0.73}We've got equipment.": "{0.00->0.73}那儿有装备,", + "{0.00->1.16}I will remember this{1.63->2.28}forever!": "{0.00->2.50}我会永远记住这一刻!", + "{0.03->1.62}For Lady liberty!": "{0.00->1.67}为了自由女神!", + "{0.00->1.88}Need team reload!": "{0.00->1.88}快帮我换弹!", + "{0.00->1.35}Establish a perimeter.": "{0.00->1.01}建立防线。", + "{0.00->0.38}Down.": "{0.00->0.38}下方。", + "{0.02->0.87}I win.": "{0.02->0.87}我赢了。", + "{0.00->0.48}Four.": "{0.00->0.48}四。", + "{0.00->2.29}Recruit expired. Insert next recruit.": "{0.00->2.51}新兵死亡。请下一位新兵入场。", + "{0.00->1.61}Their deaths will not be in vain, {2.07->5.39}so long as we still have heroes to send to fight.": "{0.00->3.00}只要我方还能把英雄送往前线作战,{3.43->5.39}他们的牺牲就不会白费。", + "{0.00->0.95}Dirty bot.": "{0.00->0.95}废物机器。", + "{0.19->1.66}You really are incredible.": "{0.01->1.66}你们真的是太厉害了。", + "{0.00->1.28}Enemy outpost spotted.": "{0.00->1.28}发现敌方哨站。", + "{0.03->1.67}The Aladfar system": "{0.03->1.67}辇道二星系", + "{0.01->0.44}Ok!": "{0.01->0.44}好的!", + "{0.01->0.84}I'm empty!": "{0.01->0.84}没弹药了!", + "{0.00->0.78}To the skies.": "{0.00->0.78}飞起来。", + "{0.04->2.18}Prepare for Democracy!": "{0.00->2.14}准备迎接民主吧!", + "{0.00->2.11}Keep an eye out for more samples next time.": "{0.00->2.11}下次记得多收集一些样本。", + "{0.01->2.36}Have you heard what they're saying?{2.36->10.99}They say the Void's influence is too strong...that it's calling out to people, begging them to re-examine their belief systems.{10.99->14.68}Yeah, I know—sounds like a ghost story from Scout camp.": "{0.01->4.09}你听说了吗?他们说寂域的影响力太强了……{4.68->8.77}它在召唤民众,恳求他们重新审视自己的信仰体系。{10.58->14.67}我懂,听起来就像是童子军夏令营的鬼故事。", + "{0.02->2.91}The squids are gonna eat our brains!": "{0.31->2.91}鱿鱼会吃掉我们的脑子!", + "{0.00->2.88}Those un-Democratic freaks found us!": "{0.00->2.88}反民主怪物找上来了!", + "{0.01->1.74}Super Earth forever!": "{0.00->1.89}超级地球永垂不朽!", + "{0.08->1.06}You saved us!": "{0.08->1.06}多亏了你们!", + "{0.00->2.11}Hellbomb armed—clear the area.": "{0.00->2.11}地狱火启动,炸平这里。", + "{0.00->2.01}Wonder if this'll help my next CCS review...": "{0.00->2.01}我寻思能给CCS评估加点分不…", + "{0.03->7.95}Helldivers. Heroes of the federation. Abolishers of tyranny. Legends that secure the Element {8.35->11.47}710 we need to maintain our way of life.": "{0.03->2.73}绝地潜兵是联邦的英雄,{3.09->8.06}是暴政的终结者,是保障710元素稳定供应,{8.27->11.98}捍卫生存正道的传奇战士。", + "{0.01->2.61}Please help! Please!": "{0.01->3.04}救命!救救我!", + "{0.04->1.45}The Ilduna system": "{0.04->1.45}伊尔都纳星系", + "{0.03->2.08}I wish I could do what you do.": "{0.03->2.30}真想像你们一样。", + "{0.00->1.18}Everyone ok?": "{0.00->1.18}大家都还好吗?", + "{0.00->7.73}Deadeye precision! Now, use a grenade to close up that Bug Hole! Otherwise, they'll just keep {7.76->8.30}comin'.": "{0.00->4.97}弹无虚发!现在,用一枚榴弹炸塌那个虫洞!{5.69->8.30}否则,它们会源源不断地过来。", + "{0.48->1.55}They're everywhere!": "{0.00->1.62}哪儿哪儿都是它们!", + "{0.00->3.27}Visibility improving—avoid being an easy target.": "{0.00->2.62}能见度提高,别变成活靶子了。", + "{0.00->0.95}Sample collected.": "{0.00->0.95}样本到手了。", + "{0.00->2.66}Pry this city from the enemy's grasp.": "{0.00->2.66}从敌人的魔爪中夺回城市。", + "{0.01->1.03}RUN!": "{0.01->1.03}快跑!", + "{0.00->2.76}This is Eagle 1, cleared for action and awaiting orders.": "{0.00->2.76}这里是“飞鹰”1号,随时待命,准备行动。", + "{2.17->3.45}Are we—are we friends now?": "{0.00->1.83}我们——{1.83->3.76}我们现在是朋友了吗?", + "{0.00->1.60}SEAF extraction successful.": "{0.00->1.63}武装部队成功撤离。", + "{0.00->5.45}I'd say you should've collected more samples, but the Super Destroyer is already fully upgraded.": "{0.00->5.45}本来想说可以多收集些样本,但超级驱逐舰已经完全升级了。", + "{0.00->0.95}Out of stims.": "{0.00->0.95}没针了。", + "{0.00->1.21}Main objective nearby.": "{0.00->1.21}主要目标就在附近。", + "{0.03->1.58}One for the scrapbook.": "{0.00->1.67}值得珍藏的一刻。", + "{0.04->3.47}I can't believe Bastion Tanks are back in production!{4.43->6.32}Imagine if kid me had known about it,{6.32->9.74}back when she was collecting all the Armored Fighting Vehicles from cereal boxes.{10.79->11.54}She would have freaked!": "{0.00->3.77}真不敢相信,堡垒坦克居然重新投产了!{4.49->6.50}我小时候还沉迷收集谷物盒里的{6.65->8.02}装甲战车模型呢。{8.64->10.15}要是那时候就有这么个事,{10.25->11.61}我肯定会激动坏的!", + "{0.00->4.57}Helldivers not at extraction site. Pelican 1 landing aborted. Regaining altitude.": "{0.00->4.57}绝地潜兵不在撤离地点。“鹈鹕”1号放弃着陆。正在重新升空。", + "{0.00->2.64}Keep it up, and pretty soon there won't be any bots left. {3.14->4.69}Just Managed Democracy.": "{0.00->0.85}继续加油。{1.24->4.92}在管理式民主面前,机器人根本没有任何机会!", + "{0.00->4.94}Remember, only a firm hand can support the weight of Freedom.": "{0.00->5.62}记住,唯有铁腕才能牢牢把握自由。", + "{0.11->4.16}Fire, you reeducated sons o' dissidents, fire!": "{0.00->2.90}开火,这群异见分子养的,{2.90->4.17}开火!", + "{0.01->0.88}Never let go.": "{0.00->1.04}永不放弃。", + "{0.00->0.60}Bots.": "{0.00->0.60}机器人。", + "{0.00->2.02}Changing course? Something go wrong?": "{0.00->2.15}调整路线吗?出问题了吗?", + "{0.00->1.74}We're here to support, Helldiver.": "{0.00->2.05}绝地潜兵,我们会支援你。", + "{0.01->2.23}We will avenge you!!": "{0.00->2.23}我们一定会为你报仇!!", + "{0.00->1.72}Looks like we're taking the fight to them --{2.21->3.56}welcome, Helldiver.": "{0.00->1.63}看来我们要主动出击了。{2.21->3.63}欢迎,绝地潜兵。", + "{0.02->3.21}Front-row seats to watch the Helldivers in action!": "{0.02->3.21}近距离欣赏绝地潜兵的英姿!", + "{0.00->0.94}Orbital incoming.": "{0.00->0.94}轨道攻击来了。", + "{0.00->0.75}There they are!": "{0.00->0.93}它们出现了!", + "{0.00->8.29}Do you think the Void is... hungry? No, that's silly.{8.36->11.19}If there were other forms of sentience out there, the Ministry of Truth would tell us.": "{0.00->4.37}你觉得寂域会不会是……饿了?{4.80->6.73}不对,这想法太愚蠢了。{7.05->10.91}如果真有其他形式的智慧生命存在,真理部肯定会告诉我们的。", + "{0.01->0.91}I love you.": "{0.00->1.03}我爱你。", + "{0.00->0.69}Sixth one.": "{0.00->0.58}第六个。", + "{0.00->0.93}You're free now.": "{0.00->0.93}你自由了。", + "{0.00->0.68}Fourth one.": "{0.00->0.59}第四个。", + "{0.02->0.99}Cover down!": "{0.02->0.99}寻找掩体!", + "{0.00->1.47}Let the light of Liberty shine!": "{0.00->1.47}让解放之光照亮大地!", + "{0.02->2.20}The Helldivers will make them pay.": "{0.02->1.73}绝地潜兵会教它们做人。", + "{0.01->1.74}Argh! I'm hit!": "{0.00->1.93}啊!我中弹了!", + "{0.00->1.13}Yes! Kill 'em!": "{0.00->1.68}爽啊!杀了它们!", + "{0.08->1.83}Automaton facility destroyed.": "{0.08->1.83}已摧毁机器人设施。", + "{0.00->2.56}That should help keep the bug population in check.": "{0.00->2.56}这次胜利应该能够有效控制虫族数量。", + "{0.00->5.08}The Hellbot went a little haywire the other day. Started spouting nonsense about its nature, {5.10->8.26}purpose, the meaning of life. I couldn't make heads or tails of it.": "{0.00->2.32}前几天,这台绝地机械兵出了点故障。{2.32->6.48}开始不停胡言乱语,说起了自己的本质、目的和生命的意义。{6.67->8.26}我完全搞不明白它说啥。", + "{0.01->2.11}Bugs! Run!": "{0.01->2.34}虫子!快跑!", + "{0.00->1.87}Make every shot count!": "{0.00->1.87}每一颗子弹都不要浪费!", + "{0.00->1.78}Main objective near your position.": "{0.00->1.78}主要目标就在你们附近。", + "{0.01->1.69}The Helldivers will save us.": "{0.01->1.69}绝地潜兵会救我们的。", + "{0.01->1.38}The Helldivers are here!": "{0.01->1.38}绝地潜兵来了!", + "{0.00->0.42}Ok!": "{0.00->0.51}好的!", + "{0.01->2.43}C'mon! Maybe we can find a bunker!": "{0.01->2.17}快!要不找个地堡!", + "{0.00->1.23}The Dolph system": "{0.00->1.23}多尔夫星系", + "{0.06->1.59}We gotta stop the bleeding!": "{0.00->1.66}必须得先把血止住!", + "{0.00->2.22}Request approved; reinforcements on the way.": "{0.00->2.22}批准请求;增援即将抵达。", + "{0.02->1.93}What in the name of Freedom?!": "{0.02->2.15}自由啊!怎么会这样?", + "{0.06->6.77}Go now, Helldiver. Let our enemies take no step that is not hindered by the corpse of their comrade.": "{0.06->6.77}出发吧,绝地潜兵。让敌人横尸遍野,寸步难行。", + "{0.13->5.84}50 billion tons of Termicide, deployed indescriminantly across an entire planet. {6.42->10.15}The genius of the TCS lies in its simplicity.": "{0.00->4.61}500亿吨灭虫终结剂部署在这片星球的每一个角落。{5.09->10.42}遏制系统的绝妙之处就在于简单朴素,不搞花样。", + "{0.00->5.52}As if we didn't know the Cyborgs were behind it all! We should broadcast THAT to Cyberstan.{5.92->9.94}Can't have those oil-soiled dissidents thinking they got one over on us.": "{0.00->2.71}还以为我们不知道生化人是幕后黑手!{3.41->6.24}我们应该在生化斯坦大肆广播宣传。{6.80->10.83}不能让那些沾满机油的异见分子以为能占我们的便宜。", + "{0.00->1.25}Black saffron harvested.": "{0.00->1.25}番黑花到手了。", + "{0.03->1.30}I don't think I can do that.": "{0.03->1.30}我去不了、办不到!", + "{0.00->1.42}A triumphant return.": "{0.00->1.20}光荣凯旋。", + "{0.04->1.61}Biological sample secured.": "{0.04->1.61}生物样本到手了。", + "{0.00->1.35}I live to serve!": "{0.00->1.35}乐意为你效力!", + "{0.01->2.85}I'd...I'd be honored.": "{0.00->0.86}我…{1.43->2.94}我很荣幸。", + "{0.02->0.67}R-really?": "{0.00->0.79}真、真的吗?", + "{0.01->1.77}Push ahead. City needs our help.": "{0.01->2.31}向前推进。城市需要我们!", + "{0.00->0.95}Deploying Sentry.": "{0.00->0.95}部署哨戒炮。", + "{0.00->1.28}Objective secured.": "{0.00->1.27}目标已夺取。", + "{0.00->2.18}Liberty rests on your shoulders, Helldiver. {2.62->4.21}I know you can bear the weight.": "{0.00->2.04}解放的责任落在你的肩上。{2.46->4.33}我知道你扛得起这副重担。", + "{0.00->0.87}Last reload.": "{0.00->0.87}最后的弹药。", + "{0.03->1.66}I can't get a clean shot!": "{0.00->1.66}我没有办法瞄准!", + "{0.04->0.68}Moving in.": "{0.00->0.71}向前推进。", + "{0.02->1.07}I don't think I can do that.": "{0.02->1.11}我这边过不去。", + "{0.00->1.51}An unfortunate outcome, {2.18->3.82}but your return gives me hope.": "{0.00->1.21}结果很遗憾,{1.65->3.46}你能回来就还有希望。", + "{0.00->1.30}It's the Illuminate!": "{0.00->1.30}光能者来了!", + "{0.00->0.87}Never Doubt!": "{0.00->0.51}忠诚!", + "{0.01->2.65}You'll rue the day you came to our city.": "{0.01->2.28}这里不是你们想来就来的。", + "{0.02->1.51}The Oshaune system": "{0.02->1.51}欧绍恩星系", + "{0.04->4.05}Justice and hope, forever unfurled!": "{0.00->3.99}正义与希望,千载不变!", + "{0.00->2.30}No fence can tell ME what to do.": "{0.00->2.30}围墙挡不住我的去路。", + "{0.00->0.43}North.": "{0.00->0.43}北边,", + "{0.00->1.77}High-value sample collected.": "{0.00->1.51}高价值样本到手了。", + "{0.04->1.67}That's what I call Justice.": "{0.04->1.67}这就是正义。", + "{0.55->1.83}Incredible.": "{0.00->2.01}哇,太厉害了。", + "{0.00->3.02}Liberty with a side of Justice, coming up!": "{0.00->3.27}你点的解放和正义来了!", + "{0.05->1.75}We're pinned down!": "{0.62->1.87}被压制了!", + "{0.00->2.89}The Automatons think this planet is theirs. {3.41->5.25}Show them otherwise.": "{0.00->2.08}机器人妄图掌控这颗星球。{2.56->4.76}让它们明白自己大错特错。", + "{0.01->2.32}Helldivers! We're gonna make it!": "{0.01->2.65}绝地潜兵!我们会没事的!", + "{0.02->1.57}TASTE FREEDOM!": "{0.02->1.57}尝尝自由的滋味!", + "{0.00->1.48}The Diaspora system": "{0.00->1.48}大流散星系", + "{0.06->3.20}That's right, that's Super Earth values!": "{0.00->3.23}没错,这就是超级地球的价值观!", + "{0.00->0.13}A {0.98->1.92}100% survival rate. {2.54->3.85}Very satisfying.": "{0.00->1.58}100%存活率。{2.01->3.39}非常出色。", + "{0.04->1.91}Just like in Diver fics...": "{0.00->1.91}就像潜兵小说……", + "{0.00->3.44}Make the Automatons pay for their wanton aggression.": "{0.00->3.44}让妄图侵略的机器人付出代价。", + "{0.00->1.55}Thank Liberty we made it.": "{0.00->1.55}解放保佑。我做到了!", + "{0.00->0.35}Rolling {0.84->1.08}out.": "{0.00->1.28}现在出发。", + "{0.00->1.34}The Pilen system": "{0.00->1.34}皮伦星系", + "{1.36->1.91}See that? We'll be alright!": "{0.00->2.14}看到了吗?不会有事!", + "{0.00->1.78}Flag-forsaken freaks!": "{0.00->1.78}没旗的东西!", + "{0.01->1.72}I will do it or I will die trying!": "{0.01->1.72}就算拼命,我也会做到!", + "{0.00->0.97}Blow it up!": "{0.00->1.27}炸了它!", + "{0.06->1.30}Good luck out there! {1.30->2.64}I'll see you on the front lines!": "{0.00->1.10}祝你好运!{1.13->2.64}我们前线见!", + "{0.02->1.42}Get it away from me!": "{0.02->1.42}快帮我把它弄走!", + "{0.03->1.32}Cover the flanks!": "{0.00->1.37}掩护我方侧翼!", + "{0.05->1.98}I needed that.": "{0.87->2.10}我太需要这个了。", + "{0.02->0.86}Out of ammo.": "{0.02->0.86}弹药没了。", + "{0.11->2.34}Yeah!!! KILL 'EM!!!": "{0.11->2.34}爽啊!!!杀了它们!!!", + "{0.04->1.42}The Menkent system": "{0.04->1.42}库楼三星系", + "{0.00->5.90}Support our troops. Sign your children up for the all-inclusive Helldiver package today!": "{0.00->1.60}支持我们的军队。{2.26->6.01}为你的孩子报名,即可获得全套绝地潜兵入伍福利!", + "{0.00->1.33}This is where the shuttle lands?": "{0.00->1.33}就在这儿等运输船吗?", + "{0.00->0.44}Negative.": "{0.00->0.44}没办法。", + "{0.00->2.38}The bugs are basically an out-of-control pest. {2.90->4.18}And you're the exterminator.": "{0.00->2.06}虫族基本上是失控的害虫。{2.49->4.30}而你的职责就是消杀。", + "{0.00->1.25}Open fire!": "{0.00->1.29}立即开火!", + "{0.00->3.70}At the end of the night, they'd re-enact the Battle of Liberty Peak, and we'd all get cake.": "{0.00->2.25}深夜时分,他们会重演“解放峰之战”,{2.54->4.29}然后我们小孩子都能吃到蛋糕。", + "{0.04->1.22}The Link System": "{0.04->1.14}链枢星系", + "{0.00->0.36}Far.": "{0.00->0.54}有点远。", + "{0.00->1.41}Throwing supply beacon.": "{0.00->1.25}投掷补给信标。", + "{0.00->3.73}What enters the Void, does not leave.": "{0.00->3.73}只要踏入寂域,永远都无法离开。", + "{0.00->1.84}Remember your training!": "{0.00->1.85}牢记训练的内容!", + "{0.00->0.85}Heading there now.": "{0.00->0.96}正在赶过去。", + "{0.00->2.24}Note to self: iron trousers.": "{0.00->2.51}注意:小心钢铁盔甲。", + "{0.00->1.74}Reinforcement budget depleted.": "{0.00->1.74}增援预算已耗尽。", + "{0.01->1.14}Get us out of here!": "{0.01->1.14}快带我们走!", + "{0.00->2.95}Super Uranium. Safe enough for babies.": "{0.00->3.05}超铀,对婴儿也完全无害。", + "{0.01->1.51}I'm bleeding out!": "{0.00->1.11}我流血了!", + "{0.00->2.12}It was never alive to begin with.": "{0.00->2.12}有的东西就不配活着。", + "{0.00->1.51}The operation has failed. {2.00->3.88}We must try again elsewhere.": "{0.00->1.23}行动失败。{1.78->3.61}我们得另寻良机。", + "{0.00->1.48}Objective completed.": "{0.00->1.48}目标已达成。", + "{0.02->1.69}Get it away from me!": "{0.02->1.69}快把他给我弄走!", + "{0.00->2.90}The hearts of Super Earth beat as one.": "{0.00->2.93}我们的心在超级地球一起跳动。", + "{0.03->1.02}Kill them all!": "{0.03->1.02}把他们杀光!", + "{0.00->1.51}The Piea System": "{0.00->1.24}皮耶阿星系", + "{0.04->3.37}Sweet Liberty, please forgive me!": "{0.00->3.59}解放大业啊,我不是故意的!", + "{0.00->0.95}Artifact collected.": "{0.00->0.95}古物到手了。", + "{0.03->4.84}My legs! For the love of Liberty, my legs!": "{0.03->4.84}我的腿!我超级自由的腿!", + "{0.00->0.85}Bot fabricator.": "{0.00->0.85}机器人构筑者,", + "{0.41->1.66}Disgusting squid.": "{0.41->1.66}恶心的鱿鱼。", + "{0.08->1.17}Calling in mission shuttle.": "{0.08->1.17}呼叫任务运输船。", + "{0.00->1.41}The Okul system": "{0.00->1.41}欧库星系", + "{0.01->1.12}Kill them all!": "{0.01->1.12}把它们杀光!", + "{0.00->1.59}White, yellow, and blue!": "{0.00->1.69}白色、黄色、蓝色!", + "{0.00->3.40}The proliferation of Megafactories must be checked.{3.83->9.61}Should the Cyborgs expand their numbers, naught but death and bedlam will follow.": "{0.29->3.96}超大型工厂的扩散必须得到有效的遏制。{4.52->9.55}如果生化人继续扩大兵力,只会带来死亡和混乱。", + "{0.01->2.92}Taking back what's ours, one by one!": "{0.01->2.92}夺回属于我们的一切!", + "{0.00->0.25}Never{0.68->1.22}doubt!": "{0.00->0.66}忠诚!", + "{0.00->3.38}How about a nice cup of liber-tea!": "{0.00->3.38}一盅陈茶敬自由!", + "{0.00->1.30}The Pöpli system": "{0.00->1.30}珀普利星系", + "{0.00->1.43}SEAF is Oscar Mike.": "{0.00->1.51}武装部队出发了。", + "{0.00->2.68}The lives of Humanity's present are a crumb; {3.43->6.93}the lives of Humanity's future, a boundless loaf.": "{0.00->2.42}人类眼前的生活如同一粒米,{2.88->7.23}而人类的未来则是拥有无限可能的一片田。", + "{0.01->2.76}Freedom, straight to the veins!": "{0.00->2.77}将自由注入静脉!", + "{0.08->3.55}You're finally ready for the realest deal of 'em all: {3.95->5.72}The Galactic War. {6.17->9.73}Liberty. Democracy. Justice. {10.20->12.34}They're in your hands now. {12.74->15.82}General Brasch, over and out.": "{0.08->5.64}你终于准备好面对最真实的挑战了:星系战争。{6.42->9.02}解放。民主。正义。{9.57->12.54}现在,这些事全都靠你了。{13.29->15.82}布拉施将军通话完毕。", + "{0.00->3.92}Recruit expired. Notify dive crew we got another one in the Terminid moat.": "{0.00->0.85}新兵死亡。{1.25->4.13}通知潜水组,又有人掉进终结族壕沟了。", + "{0.00->1.56}The Eukoria system": "{0.00->1.56}欧科里亚星系", + "{0.01->4.26}What the...? INCOMING! GO ALREADY!": "{0.00->1.39}什么……?{1.40->4.30}要来了!已经发射了!", + "{0.04->2.72}Time to take yer medicine, freaks!": "{0.00->2.53}到点该吃药了,怪物们!", + "{0.03->1.67}Everyone take cover!": "{0.00->1.74}所有人,找掩体!", + "{0.00->1.63}Helldiver, reporting for duty.": "{0.00->1.63}绝地潜兵前来报到。", + "{0.04->1.11}You saved us!": "{0.04->1.11}多亏了你们!", + "{0.00->1.43}The Nosser System": "{0.00->1.05}诺瑟星系", + "{0.07->3.29}Agh! For Super Earth...": "{0.00->3.50}啊!为了超级地球……", + "{0.02->0.74}Enemy spotted.": "{0.02->0.74}发现敌人,", + "{0.01->2.59}It can't be! Helldiver down!": "{0.01->2.59}不可能!绝地潜兵倒下了!", + "{0.01->1.89}Find shelter!": "{0.90->1.80}藏好!", + "{0.00->0.46}Two.": "{0.00->0.46}两。", + "{0.00->0.88}Dirty bot.": "{0.00->1.21}废物机器。", + "{0.00->0.30}Item collected.": "{0.00->1.07}东西到手了。", + "{0.13->6.19}You may find yourself wondering if any remnant of their former selves remains in the Voteless. {6.74->8.21}Do not waste your time. {8.74->12.58}The citizens they once were are gone completely.": "{0.13->6.19}你或许会疑惑,无票者身上是否还残留着昔日的影子?{6.74->8.21}切勿浪费时间。{8.74->12.58}他们曾经的公民身份早已荡然无存。", + "{0.00->0.50}Bugs.": "{0.00->0.50}虫族,", + "{0.03->2.72}Orbital barrage incoming. Stand clear.": "{0.03->2.72}轨道火力网即将来袭。请站远一点。", + "{0.00->1.69}Manning combat walker.": "{0.00->1.69}操纵战斗步行机甲。", + "{0.02->1.91}Liberty watches over us!": "{0.00->1.90}解放护佑我们!", + "{0.00->2.35}Black saffron harvested.": "{0.00->2.35}番黑花到手了。", + "{0.00->1.18}For Super Earth!": "{0.00->1.19}为了超级地球!", + "{0.30->1.09}More aliens!": "{0.00->1.26}外星异形又来了!", + "{0.03->1.89}What did they ever do to you?!": "{0.03->1.64}它们对你做了什么?!", + "{0.00->1.16}Weapons ready!": "{0.00->1.06}武器就绪!", + "{0.00->1.47}For all citizens!{2.47->3.49}Open fire!": "{0.00->3.53}为了全体公民!开火!", + "{0.02->1.39}Please help! Please!": "{0.02->1.39}救命!救救我!", + "{0.00->3.42}This land is our land. Destroy the interlopers.": "{0.00->3.42}这是我们的领地,入侵者格杀勿论。", + "{0.02->0.74}Affirmative!": "{0.02->0.74}好的收到!", + "{0.00->3.45}The bots will churn this planet into scrap if we do not act now.": "{0.00->3.70}我们再不行动,机器人就会把这颗星球化为废土。", + "{0.19->2.30}Democracy binds us!": "{0.19->2.30}民主让我们团结一致!", + "{0.06->1.92}Calling in orbital strike.": "{0.06->1.92}请求轨道攻击支援。", + "{0.06->2.48}This is the best moment of my life.": "{0.06->2.48}这是我这辈子最美好的一刻。", + "{0.00->1.30}Team reload required.": "{0.00->1.30}给我来点弹药。", + "{0.00->0.52}I'm out.": "{0.00->0.52}没弹药了。", + "{0.00->1.70}Hold this new line, for Liberty.": "{0.00->3.06}守住新阵线,为了解放。", + "{0.00->0.84}Marking location.": "{0.00->0.84}标记地点,", + "{0.00->1.63}The Helldivers are here!": "{0.00->1.28}绝地潜兵来了!", + "{0.03->1.17}It wants my brain!": "{0.03->1.17}它想吃我的脑子!", + "{0.00->2.89}1 minute remains! Destroyer departure imminent.": "{0.00->2.89}还剩1分钟!驱逐舰即将离开。", + "{0.01->1.58}Tear 'em apart, Helldiver!": "{0.00->1.99}绝地潜兵,撕碎它们!", + "{0.05->4.05}Tear them to shreds! Rip 'em apart! Kill their spawn!": "{0.05->4.05}把它们撕成碎片!把它们撕烂!来几个杀几个!", + "{0.01->1.07}Reinforcing!": "{0.01->1.07}请求增援!", + "{0.01->0.99}Grenade!": "{0.01->0.99}手雷!", + "{0.00->1.66}Tech sample acquired.": "{0.00->1.66}科技样本到手了。", + "{0.00->0.79}Last reload.": "{0.00->0.97}最后的弹药。", + "{0.00->5.27}There are no subterranean mistakes of nature that a Helldiver cannot correct.": "{0.00->5.27}再奇怪的地下构造,绝地潜兵也能征服。", + "{0.00->0.62}Third one.": "{0.00->0.62}第三个。", + "{0.00->1.80}Managed Democracy for all!": "{0.00->1.88}管理式民主人人有份!", + "{0.00->2.14}Another victory for Democracy.": "{0.00->2.14}民主再度胜利。", + "{0.00->1.35}Package acquired.": "{0.00->1.35}东西到手了。", + "{0.00->1.61}Unregistered System": "{0.00->1.31}未注册星系", + "{0.00->0.53}No!": "{0.00->0.53}不行!", + "{0.03->2.29}Sweet Liberty, I can't believe it!": "{0.00->2.40}解放他大业的,这谁能信!", + "{0.01->0.41}Right.": "{0.01->0.41}右边。", + "{0.00->3.52}I don't believe it. Real Helldivers!": "{0.28->3.10}不敢相信。真的是绝地潜兵!", + "{0.01->1.44}Sweet Liberty!": "{0.01->1.02}解放啊!", + "{0.07->0.68}For{1.17->3.07}Democracy...": "{0.00->1.33}为了{2.00->3.43}民主…", + "{0.00->1.23}The Zefia system": "{0.00->1.23}赛飞亚星系", + "{0.00->4.14}If you ask me, the Void is nothing but an Illuminate echochamber,{4.57->8.13}where they can cultivate their xenophobic ideology.": "{0.00->4.31}要我说,寂域不过是光能者的回音室,{5.09->7.48}为它们培养仇外思想的地方。", + "{0.16->1.25}Calling in extraction.": "{0.16->1.25}呼叫撤离。", + "{0.25->2.74}The Automatons are a good reminder to never get complacent. {3.39->4.50}It's like I always say.{5.10->8.45}Military spending is always money well spent.": "{0.00->3.88}机器人是个及时的警示:切忌自满。{4.34->5.75}我也经常这么说。{5.97->8.77}军费开支总是物有所值。", + "{0.00->3.29}The enemy has been repelled from our great city.": "{0.00->3.29}敌人被赶出了宏伟的城市。", + "{0.00->5.69}For the benefit of our Federation...for the benefit of our Federation...": "{0.00->5.69}联邦,为了联邦…为了我们的联邦…", + "{0.02->1.11}Calling down a walker.": "{0.02->1.11}呼叫步行机甲。", + "{0.01->1.57}Get re-educated!": "{0.01->1.57}再念念书吧!", + "{0.00->2.46}Democracy will protect me...": "{0.00->2.46}民主保佑…", + "{0.00->1.84}It's like you could read my thoughts.": "{0.00->2.75}你是不是会读心术。", + "{0.00->1.94}Democracy delivered!": "{0.00->2.73}民主精神又得以传播!", + "{0.01->2.38}I'm okay, I'm okay.": "{0.01->2.38}我没事,我没事。", + "{0.02->4.18}Now show the Helldivers what you're made of! Fire!": "{0.00->2.83}给绝地潜兵看看你们的本事!{2.84->4.09}开火!", + "{0.01->2.24}My life for Super Earth!": "{0.01->2.24}为超级地球献身!", + "{0.00->0.95}Just stay calm.": "{0.00->0.95}不要着急。", + "{0.00->1.41}The Emeria system": "{0.00->1.41}埃梅里亚星系", + "{0.00->0.48}A draw{0.84->2.09}against a Helldiver!{2.82->3.57}Amazing!": "{2.32->3.09}居然和绝地潜兵打平了!不可思议!", + "{0.00->1.72}Calling down objective equipment.": "{0.00->1.80}呼叫目标需要的装备。", + "{0.00->0.89}New canister.": "{0.00->0.75}新燃料罐。", + "{0.04->0.72}Take cover!": "{0.00->0.87}找掩护!", + "{0.02->3.63}Sweet Liberty, please forgive me!": "{0.00->3.74}解放大业啊,我不是故意的!", + "{0.00->0.10}I got the terminal.": "{0.00->1.09}这个终端交给我。", + "{0.00->2.37}The will of Democracy saw us safe.": "{0.00->2.37}民主保佑。", + "{0.00->3.59}How dare the enemy sully our well-swept streets.": "{0.00->3.14}敌人竟敢玷污整洁的街道。", + "{0.05->1.46}Incredible.": "{0.00->1.57}哇厉害。", + "{0.00->1.72}They died a hero.": "{0.00->1.89}英雄牺牲了。", + "{0.00->1.84}Pelican 1 arriving at coordinates.": "{0.00->1.84}“鹈鹕”1号即将抵达坐标。", + "{0.02->2.42}FOR SUPER EAAAAARRRTTHHHH!": "{0.00->2.47}超级地球万岁!", + "{7.99->12.68}Freedom's Greetings; I'm Coretta Kelly, with grave tidings.{13.33->19.49}The Cyborgs have repelled our heroic forces, retaining their hold on Cyberstan.{20.11->27.30}Following a prolonged and hard-fought campaign, the Helldivers have been forced to withdraw.{28.12->33.30}The Cyborgs, along with the Automatons, have launched a counter-offensive.{33.53->40.69}Concerning reports indicate they have begun constructing Megafactories on other planets to create{40.69->43.43}even more Cyborg soldiers.{44.12->47.67}That's Liberty's Latest; I'm Coretta Kelly.": "{7.89->10.74}自由向各位问好,我是科雷塔·凯利,{11.06->13.06}为您带来一则沉痛的消息。{13.23->15.70}生化人击退了我方英勇的部队,{16.11->19.37}继续牢牢掌握着着生化斯坦的控制权。{19.98->22.61}在一场漫长而艰苦的战役之后,{23.73->26.99}绝地潜兵被迫从前线撤离。{27.71->31.59}与此同时,生化人与机器人联手发动了反攻,{31.98->33.28}战局急转直下。{33.52->37.71}令人担忧的是,报告显示,他们已经在其他星球上{37.99->43.26}开始兴建超大型工厂,企图制造更多生化人士兵投入使用。{44.16->47.72}以上就是今天的《解放新闻》,我是科雷塔·凯利。", + "{0.00->0.72}Right away!": "{0.00->0.72}马上!", + "{0.03->2.35}So that's the smell of Liberty...": "{0.00->2.58}这就是自由的温度……", + "{0.00->7.09}Did you know? The scientific term for a group of bots is \"An Assemblage of Automatons.\" If you see {7.09->9.73}such a group, Democratize them immediately.": "{0.00->1.09}你知道吗?{1.68->4.70}科学界用“机患”代指一群机器人。{5.34->7.28}要是发现机患,别犹豫,{7.74->10.30}直接用民主手段解放它们。", + "{0.00->0.30}Here?": "{0.00->0.38}这儿?", + "{0.00->0.46}Five.": "{0.00->0.44}五。", + "{0.06->1.07}Yeah!": "{0.00->1.07}没错!", + "{0.05->1.92}We'll make 'em pay!": "{0.00->1.96}该让它们血债血偿!", + "{0.00->1.06}Gotta cover more ground, cover—cover the flanks.": "{0.00->2.94}得覆盖更大的区域,掩护——掩护侧翼。", + "{0.00->3.52}All Helldivers, please report to Ship Master.": "{0.00->3.52}所有绝地潜兵,请向舰长报到。", + "{0.00->0.93}I got this...": "{0.00->1.03}我能行……", + "{0.00->2.73}A multitude of operations. Each one, {3.15->5.45}a chance for Freedom to ring.": "{0.00->1.91}有很多行动可供选择。{2.18->5.45}每一项行动都是推动自由的良机。", + "{0.00->2.77}Our city burns. We must rescue it.": "{0.06->3.14}城市在燃烧。一定要拯救这里。", + "{0.04->1.29}Kill them all!": "{0.04->1.39}把他们杀光!", + "{0.00->2.00}You want more? I've got more!": "{0.00->2.30}你还想要?我这还有!", + "{0.00->5.24}We'll be back. We'll be back, with bigger weapons, and more ships, and we'll make the Illuminate{5.24->7.01}wish they'd never even THOUGHT of the Void.": "{0.00->1.45}以血还血。{1.47->3.14}我们要派出更多战舰,{3.20->5.97}带上更强大的武器,让光能者百倍偿还,{5.98->7.49}让它们悔不当初。", + "{0.05->1.56}We're gonna die!": "{0.05->1.56}我们死定了!", + "{0.00->1.03}When's the shuttle coming?": "{0.00->1.27}运输船什么时候到?", + "{0.03->0.98}Taking position!": "{0.00->1.09}战士们各就各位!", + "{0.00->1.35}The Maia system": "{0.00->1.35}昴宿四星系", + "{0.00->1.88}Democracy Above! They're here!": "{0.00->2.09}民主在上!它们来了!", + "{0.00->2.15}Again! Hit 'em again!": "{0.00->2.15}再来!再给他来一下!", + "{0.00->1.38}Manning Emplacement!": "{0.00->1.42}操纵炮位!", + "{8.83->9.31}Look {9.68->10.41}around. Everyone {10.97->12.27}on this ship depends on you. Let that pressure turn you into the diamond Super Earth needs.": "{0.00->1.70}环顾四周。{2.47->6.00}舰船众人安危全都在你肩上。{6.90->12.67}这份压力将你锤炼成超级地球所需的钻石。", + "{0.00->0.83}Liberty leap!": "{0.00->0.83}解放之跃!", + "{0.00->2.69}The freedom of the galaxy remains in jeopardy. {3.17->4.61}Let us join the fight.": "{0.00->2.69}银河系的自由仍然岌岌可危。{3.17->4.61}赶快加入这场战斗吧。", + "{0.04->1.24}Everyone, take cover!": "{0.00->1.32}所有人,找掩护!", + "{0.00->3.31}Welcome aboard, Helldiver. The Super Destroyer is yours.": "{0.00->3.31}绝地潜兵,欢迎登舰。超级驱逐舰由你指挥。", + "{0.01->1.78}Victory awaits us!": "{0.00->1.99}胜利就在眼前!", + "{0.01->0.93}Reinforcing.": "{0.01->0.93}请求增援。", + "{0.01->1.03}It will be done.": "{0.01->1.03}一定完成任务。", + "{0.04->1.81}Need team reload!": "{0.04->1.81}需要换弹!", + "{0.01->0.94}Back! Back!": "{0.01->1.19}滚开!滚开!", + "{0.00->4.63}You have accomplished Liberty's will. Extract at your discretion.": "{0.00->2.15}你已经贯彻解放的意志,{2.55->4.63}随时可以撤离。", + "{0.00->1.83}Manning combat walker.": "{0.00->1.83}操纵战斗步行机甲。", + "{0.01->1.14}This doesn't look good!": "{0.00->1.14}情况不妙!", + "{0.00->1.89}I could truly use a stim.": "{0.00->1.89}真的需要来一针。", + "{0.00->1.51}They're coming soon, right?": "{0.00->1.51}他们快到了,对吗?", + "{0.00->2.71}Sweet mother of Freedom -- look at them go!": "{0.00->3.11}解放他大业啊,看看人家这水平!", + "{0.00->1.19}For prosperity!": "{0.00->1.19}为了繁荣!", + "{0.00->1.33}Get back! Get back!": "{0.00->1.67}滚开!快滚开!", + "{0.01->2.72}Melt them down! Turn 'em into something useful!": "{0.01->2.64}全都烧了!烧成有用的!", + "{0.02->0.93}We're saved!": "{0.02->0.93}得救了!", + "{0.04->1.86}Freedom endures.": "{0.04->1.86}自由坚不可摧。", + "{0.11->2.86}That's Super Earth's finest, right there.": "{0.00->2.91}不愧是超级地球最精锐的战士。", + "{0.01->0.60}Fall back!": "{0.01->0.60}撤退!", + "{0.00->2.47}Let us continue our progress.": "{0.00->2.47}让我们继续前进吧。", + "{0.01->2.19}I need stims!": "{0.01->2.19}快给我来一针!", + "{0.01->1.59}Flag-forsaken mines!": "{0.00->1.52}他民主的有地雷!", + "{0.00->0.89}Bug tunnel breach.": "{0.00->0.89}虫族隧道洞口,", + "{0.01->1.79}Democracy shields us!": "{0.01->1.79}民主保佑我们!", + "{0.06->2.32}I'm in the—I'm in trouble!": "{0.00->2.49}我……我有麻烦了!", + "{0.00->1.57}Help me, please!": "{0.00->1.57}救救我!", + "{0.00->0.68}Dropping a pin.": "{0.00->0.68}正在标记,", + "{0.00->0.32}One.": "{0.00->0.32}幺。", + "{0.01->0.91}Coming in hot!": "{0.01->0.91}加入战场!", + "{0.00->2.48}Of course! Such an honor!": "{0.00->2.48}没问题!这是我的荣幸!", + "{0.00->0.85}Deploying SEAF.": "{0.00->0.97}部署武装部队。", + "{0.05->1.55}Get it away from me!": "{0.05->1.55}快帮我把它搞走!", + "{0.00->1.74}Enemy outpost spotted. Look alive.": "{0.00->1.91}是敌方哨站,小心有敌人。", + "{0.03->1.49}Look out! Squids!": "{0.03->1.49}小心!鱿鱼!", + "{0.00->1.41}The Marfark system": "{0.00->1.41}玛尔法克星系", + "{0.06->3.04}INCOMING! TAKE COVER!": "{0.00->3.20}要来了!找掩护!", + "{0.02->0.85}I'm sorry!": "{0.02->0.85}抱歉!", + "{0.00->1.25}We knew you'd save us.": "{0.00->1.59}就知道你们会来救我们。", + "{0.77->2.27}We'll be off-planet soon.": "{0.96->2.18}马上就能走了。", + "{0.00->0.61}Tagging map.": "{0.00->0.61}标记地图,", + "{0.02->1.77}Reloading team weapon!": "{0.02->1.77}团队武器换弹!", + "{0.00->1.42}Deploying Weapon Emplacement.": "{0.00->1.42}部署武器炮台。", + "{0.00->3.51}The Void... it's swallowed them all...": "{0.27->0.99}寂域……{1.90->3.45}把它们全都吞噬了……", + "{0.01->0.61}Affirmative!": "{0.01->0.61}好的收到!", + "{0.00->2.52}Liberty. Prosperity. Democracy.": "{0.00->2.52}解放,繁荣,民主。", + "{0.00->2.32}You are a true champion of Democracy.": "{0.00->2.32}你是真正的民主斗士。", + "{0.00->0.99}Wait for it...{1.56->2.84}wait for it...": "{0.00->0.99}等时机…{1.56->2.84}等时机…", + "{0.01->2.04}Flag-forsaken freaks!": "{0.01->1.78}一群没旗的东西!", + "{0.00->4.19}Pelican 1 maintaining altitude until Helldivers are within the extraction zone.": "{0.00->4.19}“鹈鹕”1号正在保持高度,等待绝地潜兵进入撤离区。", + "{0.13->0.57}Oh, Liberty!": "{0.02->1.94}自由!保佑!", + "{0.02->1.86}Shoot them! Shoot them!": "{0.02->1.86}快打它们!狠狠打!", + "{0.00->1.58}Reloading team weapon!": "{0.00->1.58}装填团队武器!", + "{0.06->1.45}The tentacles!": "{0.06->1.45}是触手!", + "{0.00->1.04}A step backwards. {1.67->3.21}We must redouble our efforts.": "{0.00->1.20}只是一次小退步。{1.67->3.21}我们必须加倍努力。", + "{0.08->1.59}Might've cast my last{2.17->2.81}Vote...": "{0.00->1.23}不如再投{1.63->3.51}最后一票…", + "{0.00->1.09}This set us back, {1.65->3.06}but I know you'll make it right.": "{0.00->0.86}我们失败了,{1.13->3.36}但我知道你会重整旗鼓。", + "{0.01->1.55}It wants my brain!": "{0.01->2.07}它想吃我的脑子!", + "{0.00->3.23}I'm honored, so honored, what an honor!": "{0.00->3.46}我很荣幸,太荣幸了,这是何等的荣幸!", + "{0.10->3.59}The uncontrolled spread of the Terminids ends today.": "{0.10->3.59}终结族的肆意扩张将在今天终结。", + "{0.00->2.95}Recruit expired. Reset course to initial conditions.": "{0.00->2.95}新兵死亡。训练场重置为初始状态。", + "{0.00->0.62}Northeast.": "{0.00->0.62}东北,", + "{0.02->2.08}High-value sample collected.": "{0.02->2.08}高价值样本到手了。", + "{0.00->1.34}The Alaraph system": "{0.00->1.34}右执法星系", + "{0.00->2.13}One step closer to mission completion.": "{0.00->2.13}距离任务完成更近一步。", + "{0.00->2.34}I can die in peace now.": "{0.00->2.08}我死而无憾了。", + "{0.03->1.07}Move, move, move!": "{0.03->1.07}快,快,快!", + "{0.00->1.48}You ready to light them up?": "{0.00->1.48}狠狠来一发吧!", + "{0.01->2.01}Freedom conquers all!": "{0.00->2.06}自由精神战无不胜!", + "{0.03->2.41}Lady Liberty has arrived!": "{0.00->2.50}自由女神,来了!", + "{0.00->1.60}All hostiles eliminated.": "{0.00->1.67}所有敌对目标已消灭。", + "{0.00->0.68}Roger that.": "{0.00->0.68}收到。", + "{0.00->3.85}If might makes right, there's no way that could be wrong!": "{0.00->4.20}有时候你要知道,拳头才是硬道理!", + "{0.00->1.51}Super Earth will...{2.33->3.36}avenge me...": "{0.00->1.15}超级地球…{1.69->3.66}会为我复仇…", + "{0.00->3.23}The siege upon Managed Democracy continues. {3.71->5.53}Let us rally to her defense.": "{0.00->2.18}敌人还在围攻管理式民主。{2.47->5.93}我们要团结一致,誓死捍卫民主。", + "{0.03->2.21}INCOMING! MOVE-MOVE-MOVE!": "{0.00->2.27}要来了!都赶紧散开!", + "{0.02->1.77}Prosperity awaits the brave!": "{0.02->1.77}繁荣需要勇士!", + "{0.00->1.43}Black saffron harvested.": "{0.00->1.43}番黑花到手了。", + "{0.00->0.87}Sub-objective.": "{0.00->0.87}次要目标,", + "{0.00->1.27}Freedom forever.": "{0.04->1.13}自由万岁。", + "{0.01->1.05}That'll show 'em!": "{0.00->1.04}民主普照!", + "{0.00->1.77}Helldiver, reporting for duty.": "{0.00->1.77}绝地潜兵前来报到。", + "{0.00->0.40}Alpha": "{0.00->0.40}A", + "{0.14->1.89}A glorious battle! Right?!": "{0.00->1.97}光荣的战斗!对吧?!", + "{0.00->0.85}Tagging location.": "{0.00->0.85}标记位置,", + "{0.00->3.84}Introduce this Hive World to Super Earth superiority.": "{0.00->4.28}让虫窝世界见识一下超级地球的优越吧。", + "{0.00->4.36}Eyes up front. Helldivers are gonna show us how it's done.": "{0.00->3.66}注意前方。绝地潜兵会给我们做好示范。", + "{0.00->2.28}I'd follow you into oblivion, Helldiver!": "{0.00->2.28}绝地潜兵,我跟定你了!", + "{0.00->0.79}Reloading!": "{0.00->0.79}换弹!", + "{0.09->6.49}Those unthinkin' bugs never stood a chance against a genius tactical mind like yourself. {6.97->9.72}You are literally invincible!": "{0.09->5.18}没有思想的虫子根本无法对抗你这样的战术天才。{6.19->9.72}你真是所向披靡!", + "{0.00->1.41}This canister will see me through.": "{0.00->1.41}燃料罐,战场必备。", + "{0.00->0.31}4!": "{0.02->0.43}4!", + "{0.02->0.63}I'm on it.": "{0.00->0.51}我来。", + "{0.00->0.53}Get in.": "{0.00->0.53}上来。", + "{0.00->1.37}Watch for mines!": "{0.00->1.36}小心地雷!", + "{0.09->4.75}The treasures of the Archives will soon belong to all of our citizens.": "{0.09->4.75}档案阁的珍宝很快就会归全体公民所有。", + "{0.00->1.38}Targets destroyed.": "{0.00->1.38}已摧毁目标。", + "{0.02->0.86}Got a sample.": "{0.02->0.86}样本到手了。", + "{0.03->1.19}Go, go, go!": "{0.00->1.23}走,走,走!", + "{0.00->2.86}E-710, the galaxy's greatest energy source.": "{0.00->2.86}710元素,全星系最棒的能源。", + "{0.01->1.69}Soldiers, at ease.": "{0.00->1.74}士兵们,稍息。", + "{0.00->1.80}Prosperous populace, that's{2.35->2.60}good.": "{0.00->2.71}繁荣在上,真不错。", + "{0.01->0.77}Illuminate.": "{0.01->0.77}光能者。", + "{0.16->2.40}Hold a Stratagem Beacon. {4.36->7.83}Sleep with a Stratagem Beacon in your hand. {10.00->11.96}Let the Stratagem Beacon {12.86->14.75}become an extension of your body, like your hand or your gun.": "{0.00->3.28}手持战略配备信标。{4.36->7.83}带着战略配备信标入睡。{9.82->15.64}让战略配备信标成为你身体的一部分,{16.25->20.17}如同你的手或枪。", + "{0.00->1.80}I wish I could kill 'em again.": "{0.00->1.80}真希望能再杀一次。", + "{0.00->0.29}Oh,{1.54->2.18}how about another one?": "{0.00->2.52}哦,再来一次怎么样?", + "{0.00->1.72}We need reinforcements!": "{0.00->1.90}需要增援!", + "{0.00->2.17}Kill them! Kill them all!": "{0.00->2.17}杀了它们!都杀光!", + "{0.00->1.50}Live to dive another day.": "{0.00->1.50}活着才能效力。", + "{0.01->1.18}Weapons ready!": "{0.01->1.45}武器准备就绪!", + "{0.00->2.34}Super Earth's finest!": "{0.00->1.98}超级地球的精英来了!", + "{0.22->0.89}300 meters.": "{0.00->0.70}300米。", + "{0.00->1.48}Pinned down over here...!": "{0.00->1.59}我被压制了……", + "{0.00->2.95}You are a true champion of Democracy.": "{0.02->2.83}你是真正的民主斗士。", + "{0.00->0.45}I'm out!": "{0.00->0.45}打光了!", + "{0.00->0.65}Gotta reload!": "{0.00->0.59}得换弹了!", + "{0.08->1.95}What's the blast radius for these again?": "{0.08->1.95}这东西能炸多远?", + "{0.00->1.37}AHHHHH HA {2.28->3.03}HA HA!!": "{0.00->3.46}啊哈哈哈!!", + "{0.00->2.52}High Priority Target is in your vicinity.": "{0.00->2.52}你们附近有高优先级目标。", + "{0.00->0.64}Fall back.": "{0.00->0.64}撤退。", + "{0.00->2.51}Take this ground for all citizens!": "{0.00->2.63}为了全体公民,拿下这里!", + "{0.00->4.57}The DSS is so large, it's run by 10 Ship Masters.{5.00->5.95}Can you imagine?": "{0.00->3.92}民主空间站规模超大,由10位舰长管理。{5.15->6.20}很难想象吧?", + "{0.00->0.77}We made it!": "{0.00->0.96}我们成功了!", + "{0.01->0.91}I'm pinned!": "{0.00->0.97}遭到压制!", + "{0.00->0.86}Let's do this!": "{0.00->0.86}来一下子!", + "{0.00->1.47}Visibility decreasing.": "{0.00->1.47}注意,能见度降低。", + "{0.00->1.30}I need supplies.": "{0.00->1.30}给我来点补给。", + "{0.03->1.45}It wants my brain!": "{0.03->1.45}它想吃我的脑子!", + "{0.00->3.24}I... I can't believe you'd do that for me.": "{0.00->1.18}我……{1.19->3.32}不敢相信你愿意分我一针。", + "{0.03->1.30}Liberty weeps. {1.75->4.78}And Democracy raises the sword of vengeance.": "{0.03->1.30}解放黯然哭泣,{1.75->4.78}于是民主举起复仇之剑。", + "{0.00->1.61}Freedom smiles on us.": "{0.00->1.83}自由眷顾我们。", + "{0.06->3.04}None of that now. Okay, some of that.": "{0.00->1.54}先别了吧。{1.54->3.15}好吧,也行。", + "{0.00->0.95}Enemy emplacement.": "{0.00->0.95}敌方炮位,", + "{0.04->2.85}We need to be... there! I think...?": "{0.00->2.81}我们得去……那边!没错吧……?", + "{0.00->1.04}Feels like home.": "{0.00->1.22}像回到家一样。", + "{0.01->1.05}Where to now?": "{0.01->1.05}现在去哪?", + "{0.02->2.07}Get back, you filthy squids!": "{0.02->2.31}恶心的鱿鱼,滚开!", + "{0.00->0.54}Zero.": "{0.00->0.54}洞。", + "{0.00->1.53}Just like in Diver fics...": "{0.00->1.63}就像潜兵小说……", + "{0.00->2.61}Flag-forsaken leg's slowin' me down.": "{0.00->2.61}这条破腿耽误了解放。", + "{0.03->2.02}EAT MY VIRTUE!": "{0.00->1.96}尝尝这发真理!", + "{0.00->2.35}Just a fluke, c'mon, one more.": "{0.44->2.41}侥幸而已,再来一局。", + "{0.00->0.89}I love you.": "{0.00->0.89}我爱你。", + "{0.00->1.02}Dangerous wildlife.": "{0.00->1.17}危险的野生动物,", + "{0.02->2.30}I'm in the—I'm in trouble!": "{0.00->2.28}我……我有麻烦了!", + "{0.03->1.47}I'll never forget this.": "{0.03->1.47}我会永远记得今天。", + "{0.01->2.78}Fall back, fall back if you want to live!": "{0.00->2.95}撤退,想活命就撤退!", + "{0.00->1.45}The Gunnar System": "{0.00->1.31}刚纳尔星系", + "{0.01->1.01}Kill them all!": "{0.01->1.01}把他们杀光!", + "{0.05->2.37}Oh, you want to hear about my dream?{2.37->7.92}So there's an Illuminate in my school cafeteria, and it's wearing a little hat, right?{7.92->11.92}So I try to shoot it, of course, but my hands are tentacles.{11.92->16.79}And it's trying to get us all to eat black pasta, and also to leave our homes forever {16.79->20.51}in order to find a \"better form of governance,\" whatever that means.{21.92->23.02}Dreams are crazy.": "{0.05->2.50}哦,你想听听我那个梦吗?{3.08->6.96}在梦里,学校食堂有个光能者,还戴着小帽子。{7.44->11.57} 我当然想开枪打它,但我的手变成了触手。{12.08->18.13}它想逼我们所有人吃黑色意面,还要我们永远离开家园去寻找“更好的治理方式”,{18.49->20.52}鬼才知道那是什么意思。{21.50->22.98}梦境真是荒诞。", + "{0.05->0.63}Follow me.": "{0.05->0.63}跟我走。", + "{0.05->1.71}Into the breach!": "{0.00->1.69}一起向前冲!", + "{0.00->2.04}Bot Dropships incoming on your position!": "{0.00->2.04}机器人运输舰往你那边去了!", + "{0.05->2.06}Filthy Terminid scum!": "{0.05->1.24}肮脏的臭虫!", + "{0.00->1.63}Make every shot count!": "{0.00->1.63}每一颗子弹都不要浪费!", + "{0.03->1.31}Reloading you!": "{0.03->1.31}帮你换弹!", + "{0.00->3.94}There is no one way to prove your devotion to Super Earth. {4.33->13.19}But there is one best way. Become a Helldiver. Become a hero. Become a legend.": "{0.00->4.01}要证明对超级地球的忠诚,方法其实有很多,{4.56->9.12}但最好的方法只有一个:成为绝地潜兵,{9.60->12.91}成为英雄,成为传奇。", + "{0.02->2.51}Get up! Please, get up!": "{0.02->2.51}起来!快站起来!", + "{0.03->2.10}Shoot them! Shoot them!": "{0.03->2.10}快打它们!快打!", + "{0.01->2.19}Live to Liberate another day!": "{0.01->2.19}改天再为解放而战!", + "{0.01->1.48}I got the good stuff for you!": "{0.00->1.61}给你带了点儿好东西!", + "{0.05->1.17}Squid outpost.": "{0.05->1.17}鱿鱼哨站。", + "{0.00->0.41}Walker.": "{0.00->0.64}步行机甲,", + "{0.01->2.24}The flag! The flag!": "{0.00->2.26}旗帜!旗帜!", + "{0.00->3.21}Some of the crew like to talk about what they'll do when the war's over. {3.89->5.23}I don't allow that sort of thing—{5.68->7.24}we need to focus on the fight.": "{0.00->2.52}有些船员憧憬战争结束后的生活。{3.04->4.94}我不许他们讨论这些事,{5.19->7.24}我们必须专心作战。", + "{0.00->0.84}Terminids": "{0.00->0.84}终结族", + "{0.66->3.27}Fire, you reeducated sons o' dissidents,{3.89->4.34}fire!": "{0.00->2.89}开火,这群异见分子养的,{2.89->4.40}开火!", + "{0.03->1.57}The Achernar system": "{0.03->1.57}水委一星系", + "{0.01->1.11}Get us out of here!": "{0.01->1.11}快带我们走!", + "{0.00->1.57}Let's go, Helldiver!": "{0.00->1.80}绝地潜兵,我们走吧!", + "{0.01->1.83}Democracy deliver us!": "{0.01->1.83}愿民主保佑我们!", + "{0.00->1.76}Need assistance!": "{0.00->1.76}请求救助!", + "{0.02->1.66}My leg!": "{0.87->1.90}我的腿!", + "{0.00->1.16}We almost had to pull out. {1.89->2.84}I'm relieved we didn't.": "{0.00->1.64}我们差点就要被迫撤离了。{1.89->3.06}真是松了一口气。", + "{0.00->1.33}Marking extraction point.": "{0.00->1.33}标记撤离点,", + "{0.00->4.24}Go with haste. Pry their creeping tentacles from this world.": "{0.00->4.24}迅速出击,务必将恶心的鱿鱼触手彻底铲除。", + "{0.00->0.48}Close.": "{0.00->0.48}很近。", + "{0.22->1.69}The Rirga Bay system": "{0.00->1.69}里尔加湾星系", + "{0.02->0.57}Cover me!": "{0.00->0.61}掩护我!", + "{0.00->2.11}Our requests have been answered!": "{0.00->1.63}我们的要求得到响应了!", + "{0.00->3.60}Remember soldiers: waste enemies, not bullets!": "{0.00->3.73}战士们,记住:浪费敌人也别浪费子弹!", + "{0.02->0.77}Watch out!": "{0.02->0.77}小心!", + "{0.00->0.63}Ouch.": "{0.00->0.63}额。", + "{0.00->1.14}Manning emplacement.": "{0.00->1.14}操纵炮位。", + "{0.03->2.43}Follow the cape, and everything's great.{2.97->4.94}Follow the cape, and everything's great.": "{0.00->1.91}跟着披风走,你有我有全都有。{2.24->4.77}跟着披风走,你有我有全都有。", + "{0.00->1.25}How bad is it?": "{0.00->1.44}我还有救吗?", + "{0.00->1.39}The Canopus system": "{0.00->1.39}老人星系", + "{0.00->1.87}Terminid hive structure destroyed.": "{0.00->1.87}已摧毁终结族虫窝结构。", + "{0.00->2.66}We will carry their legacy!": "{0.00->2.66}我们会继承他们的意志!", + "{0.04->1.76}What have I done!?": "{0.00->1.82}我在干什么?", + "{0.00->1.25}Yeah!! Freedom for all!": "{0.00->3.02}对!!自由属于每一个人!", + "{0.00->1.95}Very well. I'll do you proud.": "{0.00->2.43}好。我会让你刮目相看。", + "{0.09->0.54}This...{1.05->3.04}isn't the end.": "{0.09->0.54}这…{1.23->3.64}不是末日。", + "{0.03->1.67}The Resilience System": "{0.03->1.21}百炼星系", + "{0.03->4.58}Ah! The Flag... mind on the Flag...": "{0.00->2.77}啊!想旗帜……{2.78->4.63}专心想旗帜……", + "{0.00->0.87}Enemy emplacement.": "{0.00->0.87}敌方炮位,", + "{0.03->1.02}Awesome!": "{0.00->1.05}绝了!", + "{0.02->1.21}Rolling out!": "{0.02->1.21}出发!", + "{0.00->2.60}I'm sure you've wondered how voting works on a Destroyer. {3.08->5.26}Don't worry—our terminal is top-of-the-line. {5.68->7.34}Latest algorithm and everything.": "{0.00->3.37}想必你会好奇,在驱逐舰上要怎样投票。{3.74->5.92}别担心,我们有最好的终端。{6.12->7.87}算法什么的都是最新的。", + "{0.00->0.92}I need to reload.": "{0.00->0.92}我要换弹。", + "{0.00->2.06}No fence can tell ME what to do.": "{0.00->2.06}围墙挡不住我的去路。", + "{0.00->0.95}Fire in the hole.": "{0.00->0.83}小心手雷。", + "{0.03->2.02}They're here! They're disgusting!": "{0.03->2.60}它们来了!它们好恶心!", + "{0.19->1.37}You saved us!": "{0.19->1.37}多亏了你们!", + "{0.03->1.40}The Miqé System": "{0.03->1.06}米基星系", + "{0.07->1.73}Listen to your heart, {2.66->4.77}the strength of its beat. {6.14->8.59}Is that the strength of one {8.59->9.00}person? No. It is the strength of all humanity. Organic, endoskeletal humanity.": "{0.00->5.29}倾听心跳,感受心跳的力量。{6.48->9.06}这是一个人的力量吗?{11.00->15.28}不,这是全人类的力量。{17.22->21.97}有血有肉、傲骨铮铮的人类。", + "{0.03->3.04}Take up the coordinates. Make Super Earth proud.": "{0.00->3.07}前往坐标位置。别让超级地球失望!", + "{0.00->1.43}The Bunda system": "{0.00->1.43}天垒城一星系", + "{0.04->1.51}The Adhara system": "{0.04->1.51}弧矢七星系", + "{0.00->1.48}Welcome, Helldiver.{1.99->3.29}Glad to have you with us.": "{0.00->1.74}欢迎,绝地潜兵。{1.97->3.29}很高兴你能来。", + "{0.00->1.28}Shake it off, Helldiver.{1.74->4.31}If you don't stop the Void, no one will.": "{0.00->2.01}潜兵,振作起来。{2.68->4.41}只有你能制止寂域。", + "{0.58->4.36}It's the Illuminate again, they've just, vanished... How?{4.53->7.73}Why? How can they just disappear entire planets like that?": "{0.11->2.99}又是光能者,它们就这么……消失了……{3.12->3.87}怎么做到的?{4.18->7.56}为什么?它们怎么能让整个星球说消失就消失?", + "{0.01->3.28}FIRE IN THE HOLE! Die, Terrorists!": "{0.01->3.28}要炸了!垃圾玩意儿,去死吧!", + "{0.01->1.91}Taste our Democracy!": "{0.01->1.91}尝尝民主的滋味!", + "{0.00->2.42}Great soldiers think alike, huh, Diver?": "{0.00->2.62}英雄所见略同,对吧,潜兵?", + "{0.00->1.04}It all makes sense.{1.40->4.95}You know, the Cyborgs were doing rehabilitative labor for a hundred years,{4.98->8.89}so they realized what a boon non-compensated labor can be to a society.{8.89->11.16} So they tried to build their own laborers.{11.24->14.27}But since they didn't base the Automatons on Super Earth values, {14.27->16.73}the Bots just ended up as mindless war-slaves.": "{0.00->1.01}这就说得通了。{1.34->4.66}满打满算,生化人也进行了一百年的劳动改造,{4.89->8.38}它们肯定意识到了无偿劳动对社会能发挥多大的益处。{8.47->11.03}所以它们试图制造自己的劳工。{11.46->13.04}但它们没有在机器人身上{13.16->14.74}植入超级地球的价值观,{15.03->17.14}所以机器人只是无脑的战争奴隶。", + "{0.57->1.72}I wish I could do what you do.": "{0.00->1.82}真想像你们一样。", + "{0.00->3.93}The final absolution of xenocide is a mellifluous clarion {4.34->5.50}guiding our path.": "{0.00->2.83}灭绝外星异族的最终宽恕,{3.06->6.04}是指引我们前进的嘹亮号角。", + "{0.03->3.00}Get back, you filthy squids!": "{0.03->2.51}恶心的鱿鱼,快滚开!", + "{0.08->4.59}What are the Illuminate doing in those ruins, do you know?{4.59->8.41}Wait, don't tell me, I don't have the clearance.": "{0.08->4.13}你知道光能者在那些遗迹里做什么吗?{4.94->8.12}等等,别告诉我,我的保密级别还不够。", + "{0.00->1.53}Should'a just shaken hands.": "{0.00->1.65}刚才就该直接握手的。", + "{0.10->3.64}They didn't take responsibility, of course. Tried to blame it on \"working conditions.\"": "{0.10->3.64}他们当然是不会负责的,只想把责任推到“工作条件”上去。", + "{0.04->1.35}Let 'em have it!": "{0.00->1.37}给我狠狠地干!", + "{0.00->1.40}Calling in mission shuttle.": "{0.00->1.40}呼叫任务运输船。", + "{0.00->4.21}Dissidents sow their lies in the smallest of fractures, Helldiver. {4.80->6.05}Stay vigilant.": "{0.00->4.46}绝地潜兵,谎话连篇的异见分子向来无孔不入。{4.86->6.66}要时刻保持警惕。", + "{0.03->1.49}The Asperoth system": "{0.03->1.49}阿斯佩洛斯星系", + "{0.00->1.22}Calling down supplies.": "{0.00->1.22}呼叫补给,呼叫补给。", + "{0.00->0.68}Liberty!": "{0.00->0.70}解放!", + "{0.00->1.13}Deploying flare.": "{0.00->1.13}部署照明弹。", + "{0.03->3.75}You are the tinder, and Liberty is the match!": "{0.03->3.75}你们是干柴,解放是烈火!", + "{0.03->1.69}Need. Stim.": "{0.03->1.69}我的针。", + "{0.03->1.27}The Kerth system": "{0.03->1.27}克斯星系", + "{0.00->3.87}I realized long ago that death in the defense of Freedom {4.28->6.24}was not a tragedy to be lamented, {6.68->9.63}but a sacrifice to be revered.": "{0.00->4.18}我在很久以前就意识到,在捍卫自由的过程中,{4.37->6.81}死亡并不是需要哀悼的悲剧,{7.13->9.63}而是值得敬畏的牺牲。", + "{0.04->3.19}Beat you! Can't believe I beat you...": "{0.00->3.19}赢了!我居然赢了你……", + "{0.00->2.32}You really are incredible.": "{0.00->2.32}你们真的是太厉害了。", + "{0.02->0.64}Of course.": "{0.02->0.64}那当然。", + "{0.01->2.88}Why a Helldiver? Whyyy?!": "{0.01->3.44}为什么死的是绝地潜兵?为什么?!", + "{0.00->1.28}Activating jump pack.": "{0.00->1.28}启动喷射背包。", + "{0.01->1.22}Dirty squid.": "{0.01->1.59}恶心的鱿鱼。", + "{0.08->1.47}Cyberstan is ours!{1.98->2.97}Can you believe it? {3.46->6.35}Yes you can, because we're the ones who took it!": "{0.15->1.74}生化斯坦是我们的!{2.67->3.60}你敢相信吗?{4.52->7.07}当然可以信,因为就是我们拿下的!", + "{0.00->2.11}For a minute, I thought I might never vote again.": "{0.00->2.11}差点以为自己再也不能投票了。", + "{0.00->2.31}Warning: you are in range of enemy artillery!": "{0.00->2.31}警告:你在敌方火炮的攻击范围内!", + "{0.00->1.30}The Parsh system": "{0.00->1.30}帕尔什星系", + "{0.03->6.17}Ah! My life for... life for... hoo boy.": "{0.00->3.14}啊!把我的生命献给……{3.14->6.13}献给……呼,天哪。", + "{0.00->1.67}Follow the Helldivers!": "{0.00->1.66}跟着绝地潜兵!", + "{0.00->1.81}The Frakeneeria System": "{0.00->1.63}弗兰科尼亚星系", + "{0.04->2.64}Freedom guides our aim!": "{0.00->2.75}自由指引准星!", + "{0.00->0.53}Sentry.": "{0.00->0.53}哨戒炮,", + "{0.08->2.91}Skepticism is treason. Treason {3.51->4.48}is bad.": "{0.08->1.57}怀疑就是叛变,{1.99->4.27}叛变就得制裁。", + "{0.04->1.97}Too much incoming!": "{0.00->2.03}它们的火力太猛了!", + "{0.00->1.48}Reloading team weapon!": "{0.00->1.48}团队武器换弹!", + "{0.00->0.54}No!": "{0.00->0.54}不!", + "{0.00->0.58}Go now - {1.30->7.08}and fear the shadow of neither death nor tyranny, for Justice is your cause.": "{0.00->3.67}前进!无惧死亡与暴政的暗影,{3.67->7.08}正义就是你追求的伟大使命。", + "{0.00->2.75}For a minute, I thought I might never vote again.": "{0.00->2.30}差点以为自己再也不能投票了。", + "{0.00->1.59}Requesting tac-pack.": "{0.00->1.59}请求投放战术背包。", + "{0.01->3.52}Oh Liberty! INCOMING!": "{0.00->3.35}解放保佑!要来了!", + "{0.00->1.29}Team reload required.": "{0.00->1.29}给我来点弹药。", + "{0.00->1.25}Black saffron. {1.64->4.06}Life saving and non-habit forming.": "{0.00->3.42}番黑花,只救命,不成瘾。", + "{0.00->4.16}We did not free this planet today. But we shall not lose hope.": "{0.00->4.16}今日,这颗星球未能解放,但我们不能丧失希望。", + "{0.27->1.07}300 meters.": "{0.27->1.07}300米。", + "{0.00->3.25}Now there's one less dissident, and I get one more doctor's visit every year.": "{0.00->3.46}一个异见分子换来每年多一次医生上门的福利。", + "{0.00->1.25}SEAF support inbound.": "{0.00->1.27}武装部队前往支援。", + "{0.00->3.08}The Illuminate will wish they had remained in exile.": "{0.00->3.08}光能者会后悔没有老老实实地接受流放。", + "{0.00->3.01}You will never destroy our way of life.": "{0.00->3.01}生存正道坚不可摧。", + "{0.05->1.90}For Liberty's sake, shoot them!": "{0.05->1.90}解放他大业的,弄死它们!", + "{0.00->1.26}I'm in your debt, Helldiver.": "{0.00->1.64}绝地潜兵,我欠你一回。", + "{0.00->2.03}Hold on tight, SEAF are en route to assist.": "{0.00->2.19}坚持住,武装部队前来接应。", + "{0.00->1.09}When's the shuttle coming?": "{0.00->1.09}运输船什么时候到?", + "{0.00->0.73}Terminids! {1.16->1.47}Run!": "{0.00->0.73}终结族!{1.16->1.84}快跑!", + "{0.05->3.95}I heard that some dissidents wanted us to select our own candidates instead of using the algorithm.": "{0.05->3.95}听说有些异见分子希望我们弃用算法,改为自行选择候选人。", + "{0.00->4.15}This small bit of technology may lead to a large increase in Liberty.": "{0.00->4.15}科技研究的一小步,解放大业的一大步!", + "{0.00->1.29}Calling down equipment.": "{0.00->1.29}呼叫装备。呼叫装备。", + "{0.00->0.43}Guh!{1.74->2.45}That smarts.": "{0.00->3.05}呃!痛死了。", + "{0.00->0.71}My leg. {1.47->3.18}Not functioning at capacity.": "{0.00->0.71}腿受伤了,{1.47->3.18}无法自由行动。", + "{0.02->0.72}There they are!": "{0.02->0.72}它们出现了!", + "{0.05->3.02}I'm pinned, need assistance!": "{0.00->3.00}我被压制了,需要支援!", + "{0.00->1.40}The Martale system": "{0.00->1.40}玛尔特星系", + "{0.00->0.80}Steering clear.": "{0.00->0.80}绕开这里。", + "{0.00->0.54}Hostiles{1.06->1.88}on me!": "{0.00->1.92}敌人在打我!", + "{0.03->4.07}Wow, now I can take on anything.": "{0.00->1.71}哇,{2.13->4.02}我现在无所畏惧了。", + "{0.00->1.34}The Gaellivare system": "{0.00->1.34}耶利瓦勒星系", + "{0.00->2.15}Allied Destroyer leaving squadron.": "{0.00->2.15}友方驱逐舰离开中队。", + "{0.00->2.26}Can't Liberate with this broken arm.": "{0.00->2.26}手都断了,还怎么解放!", + "{0.00->0.62}Dropping item.": "{0.00->0.62}放下物品。", + "{0.05->1.25}Flag-forsaken leg's slowin' me down.": "{0.05->2.24}这条破腿耽误了解放。", + "{0.00->1.26}The Lone System": "{0.00->1.15}独行者星系", + "{0.00->1.22}Activating jump pack.": "{0.00->1.22}喷射背包启动。", + "{0.03->1.28}For Liberty.": "{0.00->1.37}为了解放。", + "{0.01->2.11}High Command has answered our need!": "{0.01->2.11}最高指挥部回应了我们的需求!", + "{0.00->1.29}Watch your sixes.": "{0.00->1.35}注意后边。", + "{0.01->2.12}GET SOOOOOOME!": "{0.01->2.12}给老子死!", + "{0.10->0.88}Stimming you.": "{0.10->0.88}爽吗?", + "{0.00->2.07}Gotta find somewhere safe to wait this out.": "{0.00->1.73}得找个安全的地方躲躲。", + "{0.00->2.18}This operation is no longer viable. {2.59->4.49}We must redirect our attention.": "{0.00->2.18}这次行动难以为继,{2.59->4.49}得寻找新的目标。", + "{0.01->0.77}Be ready!": "{0.01->0.77}做好准备!", + "{0.00->4.96}Did you know? No one has ever truly rebelled against Super Earth. {5.37->11.82}Our top scientists have proven that all \"rebels\" were actually acting under Illuminate mind control.": "{0.00->4.41}从未有人在真正意义上反抗超级地球。{5.28->7.59}我们的顶尖科学家已经证实,{8.26->12.64}之前的“叛乱者”都是受到了光能者的精神控制。", + "{0.13->2.07}Us, on the same level?{2.69->3.57}No way.": "{0.00->2.45}我们,居然平局?{2.45->3.67}怎么可能。", + "{0.03->1.50}Get away from me, bot freak!": "{0.03->1.50}铁疙瘩,别靠近我!", + "{0.21->1.30}Robot scum!": "{0.21->1.61}铁皮渣滓!", + "{0.01->0.59}No!": "{0.01->0.59}不!", + "{0.00->0.64}Second one.": "{0.00->0.64}第二个。", + "{0.00->3.17}Hell, one day our Service Tech might even beat my Dedication Score.{4.74->5.46}Heh, wouldn't that be something?": "{0.00->3.51}说不定哪天,维修技术员的忠诚度分数都能超过我了。{3.94->5.98}呵,那就不得了了。", + "{0.03->2.18}For Liberty's sake, shoot them!": "{0.03->2.18}为了解放,打死它们!", + "{0.00->2.14}Retribution will find you!": "{0.00->2.14}冤有头债有主!", + "{0.04->1.30}Strength in numbers!": "{0.04->1.30}人多力量大!", + "{0.00->2.48}But the navigation system's actually real simple:": "{0.00->2.48}但是导航系统其实非常简单:", + "{0.00->1.28}Stratagems selected.": "{0.00->1.28}战略配备已选定。", + "{0.22->1.43}Focus on your breath. {3.36->4.91}Inhale Democracy, {6.60->8.64}exhale treasonous thoughts. {11.05->12.25}Inhale Liberty, exhale flesh-warping, brain-killing Illuminate mind control.": "{0.00->2.02}专心呼吸。{3.48->5.24}吸入民主,{6.60->9.22}吐出叛国思想。{10.91->12.70}吸入解放,{13.57->17.28}吐出光能者精神控制。", + "{0.00->0.84}On the double!": "{0.00->0.84}马上就来!", + "{0.04->1.43}Freedom save me!": "{0.04->1.72}自由保佑我 !", + "{0.00->1.78}Let's go! Kill 'em!": "{0.00->1.89}都给我上!消灭它们!", + "{0.00->1.11}Deploying flare.": "{0.00->1.11}部署照明弹。", + "{0.00->0.87}Fire in the hole.": "{0.00->0.87}小心手雷。", + "{0.02->0.68}Take cover!": "{0.00->0.67}找掩护!", + "{0.00->2.87}You must stop the spread of the Void, Helldiver.": "{0.00->2.87}绝地潜兵,你必须阻止寂域的扩散。", + "{0.00->0.67}Roger that.": "{0.00->0.67}收到。", + "{0.00->2.61}Every shot is a taste of Freedom!{3.58->3.94}Fire!": "{0.00->2.83}每一枪都是自由的滋味!{2.83->4.03}开火!", + "{0.01->1.24}How'd they even get here?": "{0.01->1.24}它们是怎么跑到这儿来的?", + "{0.00->8.25}The Super Destroyer is fully upgraded...this is the happiest day of my entire life.": "{0.00->7.83}超级驱逐舰完全升级了…这是我一生中最快乐的一天。", + "{0.00->2.90}We may be outnumbered, but we'll never be outgunned.": "{0.00->2.47}我们人少,火力可不少。", + "{0.00->2.59}Another sample collected for Democracy.": "{0.00->2.59}又为民主大业拿到了一份样本。", + "{0.00->0.73}Out of ammo.": "{0.00->0.73}弹药没了。", + "{0.03->2.63}Get back! Get back!": "{0.03->2.63}滚开!快滚开!", + "{0.00->2.95}Back when I was a kid, we used to play \"Bug Killers\" out in the schoolyard.": "{0.00->3.20}小时候,我们经常在操场上玩“杀虫子”的游戏。", + "{0.00->3.92}Must be happy hour, 'cause we got shots for everyone!": "{0.00->2.54}民主加餐,枪子儿管饱,{2.54->4.01}人人都有份!", + "{0.00->0.93}New canister.": "{0.00->0.93}新燃料罐。", + "{0.00->1.53}Take position, soldiers!": "{0.00->1.60}士兵们,各就各位!", + "{0.01->6.11}Is that... me? Oh! I'm...I'm honored!": "{0.01->5.26}那是…我吗?哦!我…我很荣幸!", + "{0.00->0.52}Bugs.": "{0.00->0.58}虫族,", + "{0.02->1.25}For the flag!": "{0.00->1.25}为了旗帜!", + "{0.00->0.85}Injury? What {1.27->1.95}injury!": "{0.19->2.54}受伤?哪来的伤!", + "{0.00->1.70}Liberty guides my hand.": "{0.00->1.70}解放精神指引我。", + "{0.01->0.38}Whups!": "{0.00->0.47}哎呀!", + "{0.00->1.08}Welcome, Helldiver. {1.50->3.89}Operation Valiant Enclosure has begun. {4.47->8.53}With your aid, we shall drive the Terminids back into their Galactic pen.": "{0.00->1.88}绝地潜兵,欢迎你。{2.32->4.30}英勇围合行动已经开始。{4.73->8.81}在你的助力下,一定能把终结族赶回星系虫穴。", + "{0.00->2.15}Things they were sayin', where they were headed, that sort of stuff.": "{0.00->2.15}包括大人们在说什么,要去哪里,之类的。", + "{0.00->1.56}I'll reload you!": "{0.00->1.56}我帮你换弹!", + "{0.00->9.58}A reading from the Citizens' Oath, passage 8:28: We trust that in all things,{10.00->13.79}the Government works for the those who work for it.": "{0.00->5.90}选自《公民誓言》第8章第28节:{6.73->8.99}我们相信,在所有事情上,{9.38->13.79}为政府效力的人才能得到政府产生的益处。", + "{0.00->1.76}Liberty guide my legs!": "{0.00->1.76}解放保佑!", + "{0.00->1.36}The Arlia system": "{0.00->1.36}阿利亚星系", + "{0.00->1.10}They're still coming!": "{0.00->1.10}它们又来了!", + "{0.00->3.86}We cannot mourn this loss while the city remains imperiled.": "{0.00->3.86}城市危在旦夕,还不是哀悼的时候。", + "{0.01->2.29}FREEDOM CONQUERS ALL!": "{0.01->2.56}自由精神战无不胜!", + "{0.02->1.49}The tentacles!": "{0.02->1.49}是触手!", + "{0.01->1.78}Feels gooooood.": "{0.01->1.78}真他民主的爽!", + "{0.00->2.54}Mission accomplished without a single casualty. {3.27->5.73}It's a good day for Managed Democracy.": "{0.00->2.77}任务完成,而且没有任何人战死。{3.21->5.73}管理式民主在今天大获全胜。", + "{0.00->3.25}Whoa! Not every day you get to see a Hellbomb.": "{0.00->3.25}哇喔!地狱火可不是天天见的!", + "{0.03->1.57}This is where the shuttle lands?": "{0.03->1.57}就在这儿等运输船吗?", + "{0.02->1.76}The Halies Port system": "{0.02->1.76}海利斯港星系", + "{0.18->3.98}The engineers filled the TCS tanks with enough Termicide to last over a year. {4.46->7.54}Should be easy enough to replenish, once all the Terminids are dead.": "{0.04->4.53}工程师在遏制系统里装满了灭虫终结剂,足够用一年多。{4.94->7.79}把终结族都干掉以后,应该很容易补充。", + "{0.02->1.21}Minefield!!": "{0.00->1.26}小心雷区!!", + "{0.02->5.14}After the First Galactic War, we showed the Cyborgs mercy.{5.48->8.19}For the last 100 years, we have attempted{8.19->14.67}to rehabilitate them in the mines of Cyberstan. But it would seem that was for naught,{15.03->18.54}as no Humanity remained in them to salvage.": "{0.02->4.68}第一次星系战争后,我们对生化人网开一面。{5.02->10.80}过去一百年来,我们一直试图在生化斯坦的矿井中改造它们。{10.96->18.56}但现在看来都是徒劳,因为它们身上的人性早已荡然无存。", + "{0.02->1.02}Oh no, bots!": "{0.02->1.45}天呐,机器人!", + "{0.02->1.56}Squids! Run!": "{0.02->1.73}鱿鱼,快跑!", + "{0.00->4.75}You know, sometimes as a technician, you gotta realize when something's beyond repair.": "{0.00->4.44}从技术员的角度来看,有时候我们必须承认,有些东西是修不了的。", + "{0.02->3.49}Stim me, I'll—I'll last this time!": "{0.00->1.41}给我一针,{1.42->3.57}我——我保证就要一针!", + "{0.00->1.28}Marking extraction point.": "{0.00->1.13}标记撤离点,", + "{0.01->0.93}They're dead!": "{0.01->0.93}他们死了!", + "{0.01->6.32}We face a terrible choice. We reached Cyberstan only at great cost.{6.32->11.24}If we fail now, this opportunity may not come again.{11.24->14.95}But we cannot allow Super Earth to fall.": "{0.01->7.83}我们面临着艰难的抉择。我们付出了惨重代价才到达生化斯坦。{8.54->12.90}如果现在失败,以后恐怕没有更好的机会。{13.12->16.33}但我们也绝不能让超级地球沦陷。", + "{0.00->1.40}The Tandem System": "{0.00->1.10}天腾星系", + "{0.00->1.52}I live to serve!": "{0.00->1.66}为你效力是我的使命!", + "{0.02->1.63}Liberty watch over us!": "{0.02->1.29}解放保佑!", + "{0.01->2.86}Hero down!": "{0.01->2.86}英雄倒下了!", + "{0.05->2.64}Beat you! Can't believe I beat you...": "{0.00->2.75}赢了!我居然赢了你……", + "{0.00->3.31}So, uh, are we getting evacuated, or, uh...?": "{0.00->3.31}那,我们是要撤离,还是……?", + "{0.01->3.14}If this is a trap, it's our Democratic duty to be the bait.": "{0.01->3.50}就算这是个坑,今天我也得为民主跳了。", + "{0.03->3.24}Hostiles on me!": "{1.12->3.36}我被敌人打了!", + "{0.04->1.55}Watch out for mines!": "{0.00->1.62}注意,小心地雷!", + "{0.01->2.54}Sweet Liberty, I can't believe it!": "{0.00->2.70}解放他大业的啊,这谁能信!", + "{0.02->0.86}More Illuminate!": "{0.02->0.86}还有光能者!", + "{0.02->1.05}Open fire!": "{0.02->1.05}开火!", + "{0.00->0.93}Joining the fray.": "{0.00->0.93}加入战斗。", + "{0.02->1.03}Somebody help!": "{0.02->1.31}谁来救救我!", + "{0.00->0.65}Helldiver - {1.10->6.47}successful missions are rewarded by Super Earth High Command. These resources can be used to make {6.47->8.49}your Destroyer even more powerful.": "{0.00->0.65}绝地潜兵,{1.10->4.99}任务达成,超级地球最高指挥部颁发了奖励。{5.81->8.49}你可以用这些资源来进一步强化驱逐舰。", + "{0.00->1.74}Biological sample secured.": "{0.00->1.74}生物样本到手了。", + "{0.00->0.54}Of course.": "{0.00->0.54}那当然。", + "{0.03->1.74}Help me, please!": "{0.03->1.74}救救我!", + "{0.00->1.48}The Meridian system": "{0.00->1.48}默里迪恩星系", + "{0.00->2.09}There, good as new! {2.09->3.92}Now, look sharp. {3.92->7.83}You're about to encounter Democracy's sworn enemy, recruit.": "{0.00->2.28}很好,这就完全康复了!{2.98->7.83}接下来要提高警惕,新兵。你即将遭遇民主的死敌。", + "{0.00->0.22}This {0.94->1.15}is the right place. Right?": "{0.00->0.97}是在这里等,{1.34->1.82}对吧?", + "{0.00->0.91}Bot fabricator.": "{0.00->0.91}机器人构筑者,", + "{0.00->1.55}Freedom requires firepower.": "{0.00->2.08}自由需要更多火力。", + "{0.00->1.59}You guys are the coolest!": "{0.00->1.71}你们最酷了!", + "{0.11->3.35}Same throw... this can't be happening!": "{0.00->1.71}出的一样……{1.71->3.41}这怎么可能!", + "{0.03->2.95}Helldiver's watching! Fire!": "{0.00->2.92}绝地潜兵看着呢!开火!", + "{0.00->2.20}This is how we win. Together.": "{0.00->2.40}这就是取胜之道。团结一致。", + "{0.51->2.99}The Automatons gather human bodies. {3.67->7.81}What twisted algorithm is behind these posthumous abductions?": "{0.02->2.88}机器人正在大肆收集人体遗骸,{3.29->8.01}窃取遗体的背后究竟隐藏着何种扭曲的算法?", + "{0.01->2.17}Mines here! Watch your step!": "{0.00->2.13}这有雷!留心脚下!", + "{0.00->1.06}Requesting equipment!": "{0.00->0.85}请求装备!", + "{0.00->1.02}Excellent work.{1.47->4.74}If I didn't know you'd never received urban warfare training,{5.33->6.76}I'd never have guessed.": "{0.00->0.97}干得漂亮。{1.98->4.55}要不是知道你没接受过城市战训练,{4.93->6.43}我肯定看不出来。", + "{0.03->1.74}Somebody get a stim!": "{0.03->1.74}赶紧给他来一针!", + "{0.03->2.00}Get down, you sons o' dissidents!": "{0.00->1.93}快趴下,你这异见分子养的!", + "{0.00->0.63}ETA T-{1.03->2.91}10 seconds. Clear landing zone.": "{0.00->0.63}预计10秒后到达。{1.03->2.91}清空降落区。", + "{0.04->3.37}I'm so sorry you had to be without a Service Tech for so long!{3.37->12.68}I mean, here I get to enjoy Professional Development Training for months and months, while you guys are stuck here without anyone to un-jam the Nutritious Meal Dispensers.{12.68->15.04}I hope you still got your allotted calories!": "{0.00->3.65}很抱歉,害你们这么长时间都没有技术支持!{4.21->7.82}我的意思是,我享受了好几个月的职业发展培训,{8.08->11.76}而你们却困在这里,连疏通营养餐分配器的帮手都没有。{12.42->15.09}希望你们的卡路里配额都没少!", + "{0.02->1.15}More Automatons!": "{0.02->1.15}机器人又来了!", + "{0.00->0.72}50 meters.": "{0.00->0.72}50米。", + "{0.00->1.01}Firing gas strike.": "{0.00->1.01}投放毒气攻击。", + "{0.01->1.48}Over there! Over there!": "{0.01->1.68}在那边!在那边!", + "{0.02->1.33}Keep your focus!": "{0.02->1.10}保持专注!", + "{0.00->0.70}We're safe!": "{0.00->0.70}我们没事了!", + "{0.00->2.94}Plant the flag in front of that statue, recruit!": "{0.00->2.94}新兵,把旗插在雕像前面!", + "{0.14->2.26}Sweet mother of Freedom!{3.82->6.19}Is there a finer sight than a Hellbomb?": "{0.00->1.65}解放大业啊!{3.58->6.08}还有比地狱火更美的风景吗?", + "{0.00->1.43}Run away!": "{0.00->1.43}快跑!", + "{0.06->0.78}Helldiver. {1.28->2.99}The Illuminate have returned. {3.42->7.24}They are an ancient enemy—one we had believed was annihilated.": "{0.06->0.78}绝地潜兵,{1.28->2.99}光能者卷土重来。{3.42->7.24}我们曾经以为人类的古老宿敌已经被彻底灭绝了。", + "{0.00->2.63}We leave a city in ruins.": "{0.00->2.63}城市沦为废墟。", + "{0.03->1.84}Get away from me, bot freak!": "{0.03->1.84}大铁块儿,滚远点儿!", + "{0.00->1.79}Thank you for helping us, Helldiver.": "{0.00->1.99}绝地潜兵,谢谢你帮助我们。", + "{0.00->1.68}Our enemy advances. {2.13->5.81}They will pay for every inch with a gallon of blood.": "{0.00->1.68}敌人正在逼近。{2.13->5.81}但他们迈出的每一步,都要付出血的代价。", + "{0.00->1.26}This will sort you out!": "{0.00->1.28}这就给你来一针!", + "{0.00->2.74}History will remember your deeds this day.": "{0.00->2.74}历史会铭记你今日的功绩。", + "{0.02->0.84}No!": "{0.02->0.84}不!", + "{0.00->2.51}Back from the Void. Well done.": "{0.00->2.57}从寂域凯旋。干得好。", + "{0.06->1.82}Argh! I'm hit!": "{0.00->2.12}啊!我中弹了!", + "{0.00->1.33}I fight for Super Earth.": "{0.00->1.33}我为超级地球而战。", + "{0.00->0.78}We're saved.": "{0.00->1.02}我们得救了。", + "{0.01->1.29}For Super Earth!": "{0.01->1.29}为了超级地球!", + "{0.02->1.21}No way through!": "{0.02->1.21}没有路了!", + "{0.00->1.38}The Vacca System": "{0.00->1.02}瓦卡星系", + "{0.02->1.63}KILL 'EM ALL!!!!": "{0.02->1.63}全部杀光!!!!", + "{0.00->0.73}Illuminate": "{0.00->0.73}光能者", + "{0.76->3.78}I can almost taste the Freedom from here!": "{0.79->3.50}我已经闻到了自由的芬芳了!", + "{0.03->1.69}Stay dead, scum.": "{0.03->1.95}废物,去死吧。", + "{0.06->1.32}The Errant system": "{0.06->1.32}艾伦特星系", + "{0.01->2.81}Agh! Uh -- FIRE IN THE HOLE!": "{0.01->2.81}啊!呃…小心爆炸!", + "{0.01->1.77}Th...thank you...": "{0.00->1.97}还好……有你……", + "{0.00->1.41}Bot Dropships incoming!": "{0.00->1.41}机器人运输舰即将来袭!", + "{0.00->0.50}Reloading.": "{0.00->0.50}换弹。", + "{0.00->1.28}The Mastia system": "{0.00->1.28}玛斯蒂亚星系", + "{0.04->0.66}Fire!": "{0.04->0.66}开火!", + "{0.00->4.50}0 friendly fire incidents is the sort of statistical anomaly I welcome.": "{0.00->3.75}我很高兴看到这种0友军误伤的异常数据。", + "{0.01->1.47}Oop! GRENADE!": "{0.00->1.54}哎!手雷!", + "{0.04->1.21}Need assistance!": "{0.00->1.26}请求援助!", + "{0.00->1.63}The Zygos System": "{0.03->1.28}齐戈斯星系", + "{0.00->1.86}Thank you for saving us.": "{0.00->1.86}谢谢你们来救我们。", + "{0.02->1.25}Gotta reload!": "{0.02->1.25}得换弹了!", + "{0.29->2.95}This is what'll get us on playing cards!": "{0.00->3.18}哼,赢了我们就能上周边了!", + "{0.00->1.42}The Obari system": "{0.00->1.42}欧巴里星系", + "{0.06->1.51}The Acubens system": "{0.06->1.51}柳宿增三星系", + "{1.16->2.34}Oh, how about another one?": "{0.00->2.37}哦,再来一次怎么样?", + "{0.32->1.97}Nothing will stop our way of life!": "{0.00->2.14}我们的生存正道必胜!", + "{0.02->0.89}Get down!": "{0.02->0.89}快趴下!", + "{0.00->1.25}Moving up, cover me!": "{0.00->1.33}向前推进,掩护我!", + "{0.02->2.51}To the new front! Liberty awaits!": "{0.00->2.60}继续向前推进!离解放不远了!", + "{0.05->2.32}Should we be farther away?": "{0.00->2.32}我们要不要离远一点?", + "{0.00->1.42}Let's rest here.": "{0.00->1.60}在这里休息一下吧。", + "{0.00->1.72}Xenophobic scum.": "{0.00->1.28}排外的废物。", + "{0.00->1.36}The Pollux system": "{0.00->1.36}北河三星系", + "{0.00->2.01}Many sacrifices were made today. {2.93->5.05}We will never forget.": "{0.00->3.01}今天,很多人为大业牺牲了小我。{3.41->5.05}我们绝对不会忘记。", + "{0.02->0.99}Down here!": "{0.02->0.99}这里!", + "{0.04->2.27}Here's our chance, surround them!": "{0.00->2.32}机会来了,包围它们!", + "{0.00->2.13}You really are the best of the best.": "{0.00->2.13}你们是精英中的精英。", + "{0.00->2.70}They did their part. Now it's our turn.": "{0.00->2.99}他们完成了自己的使命。现在轮到我们了。", + "{0.02->1.71}Get away from me, bug freak!": "{0.02->1.98}滚开!没脑子的东西!", + "{0.00->0.92}Out of ammo.": "{0.00->0.92}没弹药了。", + "{0.01->4.75}Gas! It's gas!": "{1.19->3.41}毒气!有毒气!", + "{0.01->1.79}The Helldivers will save us.": "{0.01->1.79}绝地潜兵会救我们的。", + "{0.00->1.48}Sending down equipment package.": "{0.00->1.48}正在运送装备包。", + "{0.00->2.31}Oh, you uh, let me win?": "{0.00->2.70}噢,你故意让我赢的吗?", + "{0.00->0.48}Negative.": "{0.00->0.48}没办法。", + "{0.00->1.20}Requesting sentry.": "{0.00->1.20}请求哨戒炮。", + "{0.01->4.19}YEAH! SHOOT THEIR HEADS OFF! LEAVE NOTHING BEHIND!": "{0.01->4.19}好啊!打爆它们的脑袋!一个都不留!", + "{0.08->7.36}So, this was the Illuminate plan. A shadow cast over our Galaxy, where Liberty's light can't reach.": "{0.08->2.09}原来这就是光能者的计划。{2.55->7.36}用阴影笼罩银河系,让自由之光无法触及。", + "{0.00->0.38}Delta": "{0.00->0.50}D", + "{0.02->1.49}I'll be fine...": "{0.02->1.49}我没事……", + "{0.07->1.14}Additional objective.": "{0.07->0.84}其他目标,", + "{0.03->0.85}The enemy!": "{0.03->0.85}有敌人!", + "{0.05->4.79}Did you know that the Illuminate can manipulate us in our sleep if we're not careful?{4.79->11.93}That's why you can do crazy things in dreams, like fly, or know who you're voting for before you even see the election results.": "{0.05->4.59}你知道吗?如果我们不够警惕,光能者甚至能在睡梦中操控我们。{4.93->11.72}所以你才能在梦里干那些疯狂的事,比如飞翔,或者还没看到选举结果,就知道自己要投给谁。", + "{0.05->1.65}I can't get a clean shot!": "{0.45->1.71}我没法瞄准了!", + "{0.04->3.04}When I face Super Earth for the Vow of Allegiance every morning,{3.04->5.05}I can almost always feel where it is. {5.50->7.35}Even in a brand-new part of the galaxy.": "{0.00->2.71}每天早上面朝超级地球宣誓效忠的时候,{2.99->4.44}我总能感觉到它的位置。{4.84->7.59}即使身处银河系中的陌生区域也是如此。", + "{0.03->1.78}Liberty tells you to fight on!": "{0.00->1.87}解放需要你坚持下去!", + "{0.00->4.66}The Illuminate want to control us. To stay Free, you MUST destroy them.": "{0.00->4.66}光能者企图精神控制我们。它们是自由的绊脚石。", + "{0.00->1.95}High-value sample collected.": "{0.00->1.95}高价值样本到手了。", + "{0.00->1.10}Much appreciated.": "{0.00->1.34}对此感激不尽。", + "{0.00->0.99}Bring it in.": "{0.00->1.21}抱一个。", + "{0.01->4.09}Crushed under the heel of Justice. As they should be.": "{0.01->4.09}被正义的步伐踩碎。它们活该。", + "{0.00->5.30}Reminder: the Democracy Officer's personal sauna is off limits to crew.": "{0.00->5.43}牢记,民主官的私人桑拿房禁止其他人员进入。", + "{0.01->2.54}Feed the flames of Justice!": "{0.01->3.22}感受正义之火!", + "{0.01->2.91}They don't have object permanence! Hide!": "{0.01->2.91}它们没脑子!躲起来就好!", + "{0.00->2.12}I repeat: reinforcement ready.": "{0.00->2.12}重复一遍:增援准备就绪。", + "{0.03->1.08}Thank you, Helldiver!": "{0.00->1.19}谢谢你,潜兵!", + "{0.00->2.22}Enemy tactical asset within threat range.": "{0.00->2.22}已进入敌方战术资产威胁范围。", + "{0.00->0.88}Keep moving.": "{0.00->0.88}得赶紧走。", + "{0.01->1.21}Super Earth{1.67->3.19}protect us...": "{0.01->3.57}超级地球保佑…", + "{0.00->3.18}I could watch Helldivers work all day long.": "{0.00->3.18}我能就这样看着他们打一整天!", + "{0.00->4.83}One day, the Stranger asked Danny if he wanted to know one last secret—{5.24->6.95}the biggest secret of them all.": "{0.20->6.95}有一天,陌生人问丹尼想不想知道最后一个秘密——也是最大的秘密。", + "{0.03->3.86}The enemy has taken a planet closer to Super Earth than this one. {4.58->7.39}You are now deep behind enemy lines, Helldiver.": "{0.03->3.86}敌人已经占领了另一颗更加接近超级地球的星球。{4.58->7.39}绝地潜兵,你目前已经深入敌方战线。", + "{1.38->3.80}Nothing a Helldiver can't take...": "{0.97->3.80}没有绝地潜兵过不去的坎…", + "{0.00->1.47}Calling down a walker.": "{0.00->1.47}呼叫步行机甲。", + "{0.01->1.66}Time to make history.": "{0.01->1.66}来创造历史吧。", + "{0.02->0.67}Cover me!": "{0.00->0.75}掩护我!", + "{0.00->1.28}Calling down a walker.": "{0.00->1.28}呼叫步行机甲。", + "{0.02->1.47}More Red-eyes!": "{0.02->1.47}红眼怪物又来了!", + "{0.00->4.42}Thousands of freedom-loving citizens were killed in the mines of Cyberstan. {4.93->6.86}Don't let their deaths be in vain. {7.28->8.95}Buy war bonds today!": "{0.00->2.16}上千名渴望自由的公民{2.22->5.17}在生化斯坦的矿井中失去生命。{5.73->7.64}不要让他们白白牺牲。{8.11->9.66}快来购买战争债券!", + "{0.00->3.24}Cannot. Liberate. Effectively. With injured arm.": "{0.00->3.24}胳膊受伤,影响解放。", + "{0.00->3.46}This operation would hamstring the enemy's capabilities.": "{0.00->3.46}此次行动会大幅削弱敌方实力。", + "{0.00->2.30}Every star is a distress beacon, {2.81->4.79}crying out for Liberation.": "{0.00->4.81}每一颗星星都是一个呼唤解放的求救信标。", + "{0.00->0.71}Fourth one.": "{0.00->0.71}第四个。", + "{0.01->0.51}Thank you!": "{0.01->0.51}谢谢!", + "{0.00->2.07}A victory for Democracy.": "{0.00->2.07}民主的胜利。", + "{0.00->1.21}The Mox system": "{0.00->1.21}莫克斯星系", + "{0.00->1.22}Sending down Sentry.": "{0.00->1.22}投放哨戒炮。", + "{0.00->0.45}Thank you.": "{0.00->0.45}谢谢。", + "{0.00->1.46}The Heze Bay system": "{0.00->1.46}角宿二湾星系", + "{0.00->1.39}No need to worry—{1.82->5.77}Super Earth has your best interests at heart.": "{0.00->1.39}无需担心,{1.82->5.77}超级地球始终心系你我。", + "{0.02->2.12}Shoot them! Shoot them!": "{0.02->2.12}快打它们!快打呀!", + "{0.00->1.04}Requesting tac-pack.": "{0.00->1.04}请求投放战术背包。", + "{0.00->0.91}Manned emplacement.": "{0.00->0.84}敌方炮位,", + "{0.70->3.11}Join the party, pal! We got shots for everyone!": "{0.00->3.11}一起来吧,朋友!人人都有枪子!", + "{0.00->2.86}Let's distract ourselves with a quick vote.": "{0.00->2.18}不如来投个票,放松下。", + "{0.00->3.18}Recruit expired. Send cleanup crew to simulator area.": "{0.00->3.31}新兵死亡。派清洁组前往模拟区。", + "{0.00->0.95}Serves you right.": "{0.00->0.95}真活该!", + "{0.00->1.30}Requesting walker.": "{0.00->1.30}请求步行机甲。", + "{0.00->1.35}Calling down supplies.": "{0.00->1.35}呼叫补给。呼叫补给。", + "{0.02->1.03}Get behind something!": "{0.02->1.03}赶紧躲好!", + "{0.05->1.50}The Eligible System": "{0.05->1.14}天契星系", + "{0.05->1.59}Sweet Liberty.{2.18->4.09}Always a sight to behold.": "{0.00->1.39}解放大业。{1.90->3.31}总是这么壮观。", + "{0.00->0.49}Get in.": "{0.00->0.49}上来。", + "{0.00->1.30}The Setia system": "{0.00->1.30}赛提亚星系", + "{0.00->1.33}The Baldrick system": "{0.00->1.33}巴尔德里克星系", + "{0.02->2.92}Yeah!!! KILL 'EM!!!": "{0.02->2.92}好啊!!!杀了它们!!!", + "{0.00->0.83}We made it!": "{0.00->1.15}我们成功了!", + "{1.08->2.29}Look! Helldivers!": "{0.00->1.85}看啊!是绝地潜兵!", + "{0.00->1.84}I'll never wash my eyes again.": "{0.00->1.97}我再也不洗眼睛了。", + "{0.00->1.36}No diver left behind.": "{0.00->1.36}不抛弃,不放弃。", + "{0.00->0.68}Foxtrot": "{0.00->0.70}F", + "{0.00->1.15}Bot outpost spotted.": "{0.00->1.15}是机器人哨站。", + "{0.00->3.13}The Illuminate could be monitoring my thoughts right now...{4.00->5.60}die, squid scum. {6.13->8.24}Die die die.": "{0.00->3.32}此时此刻,光能者可能正在监控我的思想……{3.74->5.92}臭鱿鱼,去死吧。{6.30->9.21}去死!去死!去死!", + "{0.00->1.40}Looking good, Helldiver!": "{0.00->1.44}绝地潜兵,干得好!", + "{0.00->0.82}Tagging location.": "{0.00->0.82}标记位置,", + "{0.00->3.21}Visibility improving—avoid being an easy target.": "{0.00->3.21}能见度提高,别变成活靶子了。", + "{0.00->1.42}For the flag!": "{0.00->1.44}为了旗帜!", + "{0.04->3.09}Take cover, take some flag-ripped cover!": "{0.00->3.26}找掩体,插他旗的快找掩体!", + "{0.00->0.88}S'gonna blow! Move!": "{0.00->2.00}要炸了!快跑!", + "{0.02->1.02}For the fallen.": "{0.00->1.10}为了牺牲者。", + "{0.01->1.36}We got company!!!": "{0.01->1.36}它们也该来了!", + "{0.04->2.97}Saving the galaxy AND saving me?{3.97->4.84}You rule!": "{0.00->2.86}不但要拯救星系,还要救我?{2.99->5.14}哇,你是最棒的!", + "{0.01->1.82}Hail Freedom!": "{0.98->1.95}自由万岁!", + "{0.03->1.82}It's gonna cut me open!": "{0.03->1.82}它要把我给撕了!", + "{0.00->1.36}Grateful for the back-up.": "{0.00->1.10}感谢您来增援。", + "{0.21->0.84}At least...{1.21->2.01}we still have... the{2.48->3.78}moral high ground...": "{0.08->1.06}至少…{1.37->2.21}还有…{2.63->4.57}正义的高地…", + "{0.00->1.85}Must defend prosperity!": "{0.00->1.85}继续捍卫繁荣!", + "{0.01->3.00}I'm alive! I'm alive. Thank you.": "{0.00->1.49}我还活着!{1.49->3.30}我还活着。谢谢。", + "{0.02->2.24}Bugs! They're gonna eat us!!": "{0.00->2.36}虫子!我们会被吃掉的!", + "{1.95->2.06}A little shot o' Liberty.": "{0.00->2.33}来一针解放精华。", + "{0.00->0.61}Of course.": "{0.00->0.61}那当然。", + "{0.02->0.46}Thank you!": "{0.02->0.46}谢谢!", + "{0.24->2.72}This is why we fight.": "{0.00->2.63}我们正是为此而战。", + "{0.03->0.95}Make it stop!": "{0.03->0.95}快救救我!", + "{0.00->2.43}Sweet Liberty, we're saved!": "{0.00->2.43}解放大业来救我了!", + "{0.01->0.78}Looks secure.": "{0.01->1.07}看起来很安全。", + "{0.00->3.75}No-one'll set this to blow anytime soon... right?": "{0.00->1.60}这东西不会突然爆炸吧…{2.87->3.45}不会吧?", + "{0.02->1.51}Calling in extraction!": "{0.02->1.51}呼叫撤离!", + "{0.00->1.51}Welcome aboard, Helldiver.": "{0.00->1.51}绝地潜兵,欢迎登舰。", + "{0.01->2.11}How'd you like the taste of Freedom?": "{0.15->2.11}自由好喝吗?", + "{0.03->1.52}Fire, now!": "{0.00->1.50}立即开火!", + "{0.04->2.23}Squad lost; Deploying replacement squad!": "{0.04->2.23}小队团灭;部署替补小队!", + "{0.00->1.95}Helldiver needed on bridge.": "{0.00->1.95}绝地潜兵请前往舰桥。", + "{0.00->0.90}I've found something.": "{0.00->0.90}有新发现。", + "{0.00->1.88}I'll never forget this.": "{0.00->1.77}我会永远记得今天。", + "{0.05->1.24}Son of a dissident...": "{0.00->1.73}解放你大业的…", + "{0.00->1.93}The greatest order ever given.": "{0.00->1.93}这是最好的命令。", + "{0.04->1.09}Over there!": "{0.04->1.09}在那边!", + "{0.00->4.66}Show no mercy. Let the blood of Tyrants fill these streets.": "{0.00->4.66}绝不留情。让暴政的鲜血染红街道。", + "{0.00->0.97}Welcome back. {1.67->3.12}We will redeem this failure.": "{0.00->0.79}欢迎回来。{1.25->3.25}我们会洗刷这次失败的耻辱。", + "{0.03->0.74}Squids!": "{0.03->0.74}鱿鱼!", + "{0.04->2.50}Stim! Over here!": "{0.00->1.16}这里!{1.46->2.69}给我一针!", + "{0.00->1.63}Maintain your sector of fire!": "{0.00->1.35}保持火力控制区!", + "{0.00->2.24}All gave some. Some gave all.": "{0.00->2.24}有人出力,有人尽力。", + "{0.02->1.79}Fall back, now!": "{0.00->1.82}马上撤退,快!", + "{0.00->3.19}What is buried will always come to light.": "{0.00->3.19}深藏的秘密终将揭晓。", + "{0.03->2.27}Come ON, that's incredible!": "{0.00->2.31}噢天哪,太神奇了!", + "{0.00->2.80}Managed Democracy is a watchful shepherd, {3.37->7.15}guiding the will of the people so they do not stray from safety.": "{0.00->3.34}管理式民主是一位小心翼翼的牧羊人,{3.75->7.31}引导着人民的意志,带他们避开歧途。", + "{0.00->1.20}Let's get to work.": "{0.00->1.20}开始行动吧。", + "{0.00->0.63}I need ammo.": "{0.00->0.70}我需要弹药。", + "{0.01->1.96}Reloading! Running low here!": "{0.01->1.77}换弹!弹药不够了!", + "{0.00->2.77}If we stay close to the Helldivers, we're safe.": "{0.00->3.12}有绝地潜兵在,我们就安全了。", + "{0.00->2.45}I've never seen a Helldiver up close before.": "{0.00->2.51}从来没有靠绝地潜兵这么近过。", + "{0.00->0.67}Ouch.": "{0.00->0.67}呃……", + "{0.01->2.83}Democracy always wins!": "{0.00->3.11}民主必胜!", + "{0.00->1.34}Performing assisted reload.": "{0.00->1.34}我来帮你换弹。", + "{0.00->1.02}Clear the area!": "{0.00->1.05}撤出该区域!", + "{0.00->1.83}I'll remember this forever.": "{0.00->1.83}我会永远记住你们的。", + "{0.00->4.09}You know, if it weren't for Super Earth, I couldn't even afford these high-tech tools I use every day.": "{0.00->4.09}要是没有超级地球,我甚至用不上手中的这些高科技工具。", + "{0.00->1.66}Requesting advanced weaponry!": "{0.03->1.46}请求高级武器!", + "{0.00->4.33}Nothing beats spreading Democracy in a fully-upgraded Super Destroyer.{4.79->5.95}Well done, Helldiver.": "{0.00->4.27}没有什么比完全升级的超级驱逐舰更适合传播民主了。{4.66->6.47}绝地潜兵,干得好。", + "{0.00->1.68}Legendarium acquired.": "{0.00->1.68}传说矿物到手了。", + "{0.00->1.91}The Ras Algethi system": "{0.00->1.91}帝座星系", + "{0.33->1.16}We'll rebuild even{1.70->2.38}stronger.": "{0.00->2.52}我们会重建,变得更强大。", + "{0.00->0.52}Get in.": "{0.00->0.69}上来。", + "{0.00->0.20}Bot outpost spotted.": "{0.00->1.27}是机器人哨站。", + "{0.01->4.33}Tear them to shreds! Rip 'em apart! Kill their spawn!": "{0.01->4.33}把它们撕成碎片!把它们撕烂!杀掉它们崽子!", + "{0.04->0.90}For Liberty!": "{0.00->0.88}为了解放!", + "{0.07->1.57}The Minerva System": "{0.07->1.19}密涅瓦星系", + "{0.00->1.54}Calling down a support weapon.": "{0.00->1.54}呼叫支援武器。", + "{0.01->1.36}Dirty zealot!": "{0.01->1.36}垃圾玩意儿!", + "{0.00->3.03}The Helldivers are fighting alongside us!": "{0.00->3.24}绝地潜兵和我们并肩作战!", + "{0.03->1.01}They're coming!": "{0.00->0.97}它们来了!", + "{0.00->1.30}Welcome aboard, Helldiver. {1.80->4.62}Now that you're here, the war is as good as won.": "{0.00->1.92}绝地潜兵,欢迎登舰。{2.43->5.36}有你鼎力相助,我们一定会战无不胜。", + "{0.00->1.66}That's for Meridia.": "{0.00->1.66}为了默里迪亚。", + "{0.02->0.77}What are they?": "{0.02->0.77}什么东西?", + "{0.00->1.59}You guys do this all the time. Right?": "{0.00->1.21}你们都是老手了,对吧?", + "{0.00->1.35}Requesting orbital.": "{0.00->1.35}请求轨道攻击。", + "{0.01->0.57}Heavy.": "{0.01->0.57}重型敌人。", + "{0.00->1.64}Xenophobic scum.": "{0.00->1.64}排外的废物。", + "{0.04->4.11}Once again, please direct your fire at enemies, not at the training facility.": "{0.04->0.84}再次提醒,{1.13->4.24}请把火力对准敌人,不要盯着训练设施。", + "{0.01->2.78}No-one escapes the flames of Justice!": "{0.01->2.78}没有人能逃过正义之火!", + "{0.07->6.52}The Void is a threat to the very fabric of reality. You must triumph, no matter the cost.": "{0.07->6.33}寂域威胁着现实世界的根基。不惜一切代价取得胜利。", + "{0.03->2.05}Get some distance between each other.": "{0.00->2.11}互相拉开,彼此保持距离。", + "{0.00->1.53}Liberty for every being.": "{0.00->1.53}一切皆可解放。", + "{0.02->1.45}Mindless freaks!": "{0.02->1.45}没脑子的东西!", + "{0.06->1.53}Get it away from me!": "{0.06->1.53}别让他们过来!", + "{0.28->1.85}Taste our Democracy!": "{0.00->1.85}尝尝民主的滋味!", + "{0.00->1.19}The Heeth system": "{0.00->1.19}希斯星系", + "{0.01->2.10}Sweet mother of Freedom!": "{0.01->2.10}自由救救我!", + "{0.00->2.95}All set to Liberate a hole in their head...": "{0.00->2.95}解放让脑袋开花……", + "{0.00->1.80}Sweet Liberty that was close!": "{0.00->2.10}解放啊,刚才好险!", + "{0.00->0.55}The blood. {1.26->2.85}Can't stop the blood.": "{0.00->0.55}血,{1.26->2.85}都他民主的流干了!", + "{0.00->1.77}SEAF squad, inbound to your location.": "{0.00->1.83}武装部队小队前往你方位置。", + "{0.00->4.56}The Terminids are a force to be harnessed, not a scourge to be cleansed. {5.03->7.35}Liberty demands our temperance.": "{0.00->4.56}终结族是需要加以控制的势力,而不是要彻底肃清的祸害。{5.03->7.35}解放要求我们有所节制。", + "{0.00->3.10}We cannot allow the Cyborgs to restore their ranks.{3.51->7.57}Lest we witness the exponential decay of liberty.": "{0.00->2.81}绝不能让生化人重整旗鼓。{3.48->7.45}否则我们就会目睹自由迅速沦丧。", + "{0.00->2.48}And that's why YOU'RE the Helldiver!": "{0.00->2.57}这就是为什么你能当绝地潜兵!", + "{0.00->1.46}Reporting to the front.": "{0.00->1.46}前线少不了我。", + "{0.00->2.76}FREEDOM!": "{0.00->2.81}自由!", + "{0.05->1.80}The Bore Rock system": "{0.05->1.80}博尔岩星系", + "{0.01->4.59}Is that... me? Oh! I'm...I'm honored!": "{0.01->4.59}你找我吗?哦!我…我很荣幸!", + "{0.00->0.88}We'll drop in here.": "{0.00->0.95}我们在这里降落。", + "{0.00->1.15}The election is coming up. {1.64->5.53}Even in the midst of war, Managed Democracy stands strong.": "{0.00->1.30}选举的日子快到了。{1.75->5.83}就算是在战争期间,管理式民主仍屹立不倒。", + "{0.00->1.55}Time to make history.": "{0.00->1.55}来创造历史吧。", + "{0.00->2.44}You see that! Best of the best!": "{0.00->2.44}快看啊!精英中的精英!", + "{0.00->0.65}At once.": "{0.00->0.65}马上。", + "{0.03->1.80}I don't think I can do that.": "{0.03->1.80}我这边过不去!", + "{0.04->1.99}It's a good day to die!": "{0.00->2.13}今天战死沙场也值了!", + "{0.08->4.32}Hahahahaha!": "{0.08->4.32}啊哈哈哈!!", + "{0.02->1.64}Calling down a support weapon.": "{0.02->1.64}呼叫支援武器。", + "{0.05->2.17}I knew they wouldn't abandon us.": "{0.05->2.17}我就知道他们不会抛弃我们。", + "{0.01->2.82}I'm alive! I'm alive. Thank you.": "{0.00->2.96}我还活着!我还活着。谢谢。", + "{0.00->2.20}The bots have this world in an iron grip. {2.83->4.75}Find an opening and break their hold.": "{0.00->2.39}机器人牢牢地掌控着这颗星球。{2.85->5.17}找到破绽,突破掌控。", + "{0.00->0.53}Negative.": "{0.00->0.53}没办法。", + "{0.00->1.50}Deploying SOS beacon.": "{0.00->1.50}正在部署SOS信标。", + "{0.00->0.65}Watch out!": "{0.00->0.65}小心!", + "{0.03->2.11}Mission at 40 minutes remaining.": "{0.03->2.11}任务剩余40分钟。", + "{0.00->1.24}Recruit expired. {1.76->3.94}Deploy dive team for body recovery.": "{0.00->1.24}新兵死亡。{1.76->3.94}潜水小队出动,回收遗体。", + "{0.01->1.38}Down! Get down!": "{0.01->1.38}卧倒!快卧倒!", + "{0.00->2.84}Our enemies forsook mercy long ago. {3.43->5.70}Oblivion is all that awaits them now.": "{0.00->2.59}敌人在很久以前就抛弃了仁慈。{2.92->5.88}现在等待它们的只有彻底湮灭。", + "{0.00->1.30}Calling in an Eagle.": "{0.00->1.30}请求飞鹰支援。", + "{0.00->1.46}Another diver for the cause.": "{0.00->1.46}为解放大业前赴后继。", + "{0.00->0.81}Tactical benefit.": "{0.00->0.81}战术助力,", + "{0.00->0.84}Make it stop!": "{0.00->1.19}快救救我!", + "{0.00->1.22}Throwing supply beacon.": "{0.00->1.22}投掷补给信标。", + "{0.00->0.31}Will do!": "{0.00->0.47}好!", + "{0.73->2.97}Not so advanced now, huh?": "{0.85->2.29}现在还得瑟吗?", + "{0.00->3.34}Pelican 1 preparing to depart. Shuttle launch in 20 seconds.": "{0.00->3.34}“鹈鹕”1号准备出发。运输船将在20秒后起飞。", + "{0.03->2.08}Slimy freaks!": "{0.03->2.08}黏糊糊的怪物!", + "{0.00->0.94}Dangerous wildlife.": "{0.00->0.94}危险的野生动物,", + "{0.00->3.00}Fight for your family. Fight {3.53->4.59}for your freedom. {5.10->5.81}Fight…{6.23->7.64}for Super Earth.": "{0.00->1.66}为家人而战,{2.50->3.94}为自由而战,{4.81->7.51}为超级地球…而战。", + "{0.03->3.56}This is it. I can die happy.": "{0.00->1.72}真不错啊。{1.73->3.55}我死而无憾了。", + "{0.00->4.28}The Democracy Officer is the one with the eyepatch. I wouldn't recommend asking how he got it.": "{0.00->4.28}民主官是戴眼罩的那位。最好不要问他眼罩的事。", + "{0.00->6.71}The only thing necessary for the triumph of Tyranny is for heroes to fail in their duty.": "{0.00->6.25}暴政得逞的唯一条件,就是英雄未能恪尽职守。", + "{0.00->1.24}Artifact collected.": "{0.00->1.24}古物到手了。", + "{1.94->2.29}My legs! For the love of Liberty, my legs!": "{0.00->4.21}我的腿!我超级自由的腿!", + "{0.02->2.15}Hostiles, inbound!": "{0.02->1.35}敌人就要来了!", + "{0.01->0.77}Terminids!": "{0.01->0.77}终结族!", + "{0.04->1.42}The Rd system": "{0.04->1.42}Rd星系", + "{0.03->1.29}The bugs are back!": "{0.03->1.29}虫族回来了!", + "{0.04->1.11}More Illuminate!": "{0.04->1.11}还有光能者!", + "{0.00->0.57}Follow me!": "{0.00->0.57}跟我走!", + "{0.04->2.23}Get back! Get back!": "{0.04->2.23}滚开!快滚开!", + "{0.00->0.89}We'll drop in here.": "{0.00->1.02}我们在这里降落。", + "{0.00->0.72}Reloading.": "{0.00->0.72}换弹。", + "{0.00->0.64}Reloading.": "{0.00->0.64}换弹。", + "{0.00->4.40}At long last, we will deliver Justice to the Cyborgs.": "{0.00->4.47}我们终于要向生化人伸张正义。", + "{0.00->1.71}Calling down a support weapon.": "{0.00->1.71}呼叫支援武器。", + "{0.00->0.57}Affirmative!": "{0.00->0.57}好的收到!", + "{0.05->3.49}Status: Defending against Terminid invasion. {3.91->5.61}Helldiver support requested.": "{0.00->3.26}状态:抵御终结族入侵。{3.35->5.61}请求绝地潜兵支援。", + "{0.04->1.92}WOOOOOOO!!!!": "{0.04->1.92}哦!!!!", + "{0.03->3.20}Take up the coordinates. Make Super Earth proud.": "{0.00->3.33}前往坐标位置。别让超级地球失望!", + "{0.02->1.51}Activating jump pack.": "{0.02->1.51}喷射背包启动。", + "{0.00->2.11}Justice shall avenge our fallen!": "{0.00->2.11}冤有头债有主!", + "{0.04->1.08}We're gonna die!": "{0.04->1.08}我们死定了!", + "{0.02->1.08}It's really them!": "{0.02->1.08}他们真的来了!", + "{0.00->2.91}Liberty. Prosperity. Democracy.": "{0.00->2.91}解放,繁荣,民主。", + "{0.00->0.85}Help! Help!": "{0.00->1.25}救命!救命!", + "{0.00->1.06}The Hort system": "{0.00->1.06}哈尔特星系", + "{0.01->1.32}Calling down a vehicle.": "{0.01->1.32}请求载具支援。", + "{0.00->1.79}The operation is failed. {2.40->3.46}Let us not ruminate, {3.87->6.12}but instead redouble our efforts.": "{0.00->1.79}这次行动已经失败。{2.40->3.94}但我们不必为此踌躇,{4.51->6.12}我们应当加倍努力。", + "{0.00->2.22}You really are incredible.": "{0.00->2.22}你们真的太厉害了。", + "{0.00->0.38}Far.": "{0.00->0.45}有点远。", + "{0.03->2.12}Retreat, everybody! Retreat!": "{0.00->2.22}撤退,全员撤退!撤退!", + "{0.20->1.63}The Otur System": "{0.03->1.17}厄图尔星系", + "{0.00->3.16}Let the enemy feel the wrath of Liberty.": "{0.00->3.11}让敌人感受解放的怒火。", + "{0.00->0.38}Bots.": "{0.00->0.57}机器人,", + "{0.00->6.21}Take a moment to mourn. Mourn the fallen. Mourn{6.26->15.94}those twisted into Voteless abominations. Mourn those juiced and slurrified by the Automatons.{17.13->18.43}Now breathe,{19.12->19.90}fast,{20.42->21.14}faster,{21.67->27.06}hyperventilate until that grief turns to righteous rage.": "{0.00->5.25}花点时间哀悼。为逝者哀悼。{5.70->10.06}为那些沦落为无票者的人哀悼。{10.81->16.08}为被机器人榨干碾碎的人哀悼。{17.13->18.05}呼吸,{18.99->19.90}加快,{20.35->21.44}再加快,{21.96->23.36}过度换气,{23.83->27.06}将悲伤变为正义的怒火。", + "{0.00->3.12}We will make them regret this wanton aggression.": "{0.00->3.12}如此肆意侵略,一定会付出代价。", + "{0.00->2.56}Let's distract ourselves with a quick vote.": "{0.00->2.56}不如来投个票,放松下。", + "{0.00->1.94}Into Hellfire they went.{2.33->3.95}True Helldivers.": "{0.00->1.72}他们毅然踏入火海。{2.33->3.97}真正的绝地潜兵!", + "{0.01->2.91}Bug outpost spotted. Prepare to exterminate.": "{0.01->2.91}发现虫族哨站,准备歼灭。", + "{0.03->1.36}Advancing on target.": "{0.00->1.35}向目标前进。", + "{0.01->1.02}Weapons hot!": "{0.01->1.02}准备好武器!", + "{0.00->2.59}The Void is a galactic pit.{3.22->4.51}Within its depths,{4.99->6.22}Liberty's Light{6.64->8.79}is but a pale memory.{9.42->11.19}Hold tight to your duty,{11.77->13.99}lest you be swept away.": "{0.00->2.59}寂域是星系中的深渊。{3.16->4.82}在寂域腹地,{4.99->9.27}自由之光不过是一段苍白的回忆。{9.94->12.37}希望各位坚守职责,{12.73->14.77}不要被吞噬。", + "{0.00->2.44}Another proud day for Super Earth!": "{0.00->2.51}又是为超级地球而自豪的一天!", + "{0.02->0.92}Protect us!": "{0.02->0.92}保护我们!", + "{0.03->1.65}Once we make it out of this, {2.03->5.67}I'm gonna donate the rest of my salary to the war effort.": "{0.03->1.65}等我们都安全了,{2.03->5.67}我就把所有的工资都捐给我们的部队。", + "{0.00->2.69}There is but one assured path to peace...{3.41->5.66}and that path is war.": "{0.00->4.08}通向和平的道路有且仅有一条……{4.17->5.64}那就是战争。", + "{0.00->1.12}Deploying flare.": "{0.00->1.12}部署照明弹。", + "{0.02->3.18}Stims, stims please!": "{0.00->3.22}一针!我就要一针!", + "{0.00->0.72}Dropships!": "{0.00->0.72}运输舰!", + "{0.01->0.81}Last reload!": "{0.00->0.83}最后的弹药!", + "{0.01->2.09}It wants my brain!": "{0.01->1.85}它想吃我的脑子!", + "{0.01->1.30}We gotta move!": "{0.00->1.30}赶快走,快!", + "{0.00->1.56}The Deecon System": "{0.00->1.16}圣侍星系", + "{5.84->6.59}These Exostorms... the Illuminate are messing with the natural order of things again. We gotta nuke{6.59->7.14}that out of them.": "{0.04->1.38}这些异界风暴……{1.74->4.31}明显是光能者又在扰乱自然秩序。{4.97->6.67}我们得用核弹治治它们。", + "{0.02->0.94}How much longer?": "{0.02->0.94}还得等多久?", + "{0.02->2.01}Squids! Run!": "{0.02->2.01}是鱿鱼!快跑!", + "{0.00->1.69}Calling down objective equipment.": "{0.00->1.69}呼叫目标需要的装备。", + "{0.04->1.06}That'll show 'em!": "{0.00->1.12}民主普照!", + "{0.01->2.46}Citizen down!": "{0.86->2.06}公民倒下了!", + "{0.00->1.79}SEAF rapid-response redeploying.": "{0.00->1.92}快速响应小队重新部署。", + "{0.01->1.14}This way, everybody!": "{0.01->1.14}大家都来这边!", + "{0.04->2.62}Victorious throughout the stars.": "{0.00->2.80}胜利传遍宇宙群星。", + "{0.01->1.29}Soldiers!": "{0.01->1.00}战士们!", + "{0.03->1.87}Illuminate Outpost erased.": "{0.03->1.87}已抹除光能者哨站。", + "{0.00->2.69}Occupy the waypoint. Double time, soldiers.": "{0.00->2.63}占领目标点。跑起来士兵们。", + "{0.00->1.85}We knew the odds were against us.": "{0.00->2.31}我们知道胜算渺茫。", + "{0.00->1.29}Deploying equipment package.": "{0.00->1.29}正在部署装备包。", + "{0.04->5.39}A Helldiver needs a strong, solid ship crew to be able to deliver maximum devastation.{5.94->8.65}What would we have done without our Service Tech, eh?{9.02->11.36}For longer than we've already been without her, I mean.": "{0.04->4.34}绝地潜兵需要强大可靠的舰船团队才能最大限度输出民主。{4.99->7.61}要是没有维修技术员,那可怎么办呢?{8.38->11.00}我是说,她离开得再久些该怎么办。", + "{0.00->0.57}Six.": "{0.00->0.57}六。", + "{0.03->1.50}Don't let it eat me! Please!": "{0.03->2.06}别让它吃我!救命!", + "{0.00->3.16}Expeditioners: may Liberty guide you.": "{0.00->3.16}远征军,愿解放保佑你们。", + "{0.01->1.49}We've made it to the objective!": "{0.01->1.49}我们抵达目标了!", + "{0.00->1.29}Dirty Xenophobes.": "{0.00->1.29}肮脏的排外分子。", + "{0.03->1.56}Super Earth's finest!": "{0.00->1.65}最优质的战士!", + "{0.02->1.55}Find something to hide behind.": "{0.02->1.32}找地方躲起来。", + "{0.04->4.31}Imagine the sound of tank treads crushing the skulls of our enemies.{4.31->6.72}I like to think it sounds like popcorn.": "{0.11->3.89}想象一下坦克履带碾碎敌人头颅的声音。{4.73->6.48}听着就像爆米花一样。", + "{0.01->1.08}Got eyes on them!": "{0.01->1.08}看到它们了!", + "{0.04->5.21}Trust this: your body is a weapon.{5.21->10.81}Trust this: your mind is a fortress.{10.81->16.13}Trust this: your soul is a pure lake.": "{0.00->4.42}你要相信,你的躯体就是武器。{5.12->9.68}你要相信,你的思维就是堡垒。{10.92->15.98}你要相信,你的灵魂是纯净的湖泊。", + "{0.00->1.88}Look! More citizens!": "{0.00->1.88}看啊!又有公民来了!", + "{0.00->1.36}A Hellbomb?{2.83->3.83}NOW we're talkin'.": "{0.00->1.21}地狱火炸弹?{2.22->3.32}这才像话。", + "{0.01->1.48}Fire on target!": "{0.00->1.56}朝目标开火!", + "{0.00->1.15}Consider it done.": "{0.00->1.15}包在我身上。", + "{0.00->4.04}Cleanup crew to battlefield simulator; cleanup crew to battlefield simulator.": "{0.00->2.01}请清洁组前往模拟战场,{2.02->4.09}请清洁组前往模拟战场。", + "{0.00->1.89}The Bug Quarantine system": "{0.00->1.89}防虫星系", + "{0.01->1.58}I'm hit! Cover me.": "{0.01->1.81}我中弹了!掩护我。", + "{0.21->5.54}Step by step, order is restored to the Void's chaos.": "{0.00->5.64}秩序正一步步摆脱寂域的混沌,得以重建。", + "{0.00->0.91}SEAF on the way.": "{0.00->0.99}武装部队前往中。", + "{0.01->4.20}Not a Helldiver! It should have been me!!!": "{0.01->4.20}绝地潜兵不要死!死的应该是我!", + "{0.00->1.65}Assisting with support reload.": "{0.00->1.65}正在协助武器换弹!", + "{0.04->1.43}Oh, Liberty!": "{0.04->1.43}自由保佑!", + "{0.00->2.53}Time to die, enemies of Freedom!": "{0.00->2.57}自由之敌,受死!", + "{0.01->2.55}AHHHHH HA HA HA!!": "{0.17->2.68}啊哈哈哈!!", + "{0.00->2.39}Another victory over the Terminid scourge.": "{0.00->2.39}又一次战胜了危害银河的终结族。", + "{0.01->0.99}Need to reload!": "{0.01->0.99}需要换弹!", + "{0.00->2.20}C'mon... c'mon...! Reloading!": "{0.00->1.05}快……快……!{1.28->2.20}换弹!", + "{0.52->1.85}You guys do this all the time. Right?": "{0.00->1.83}你们都是老手了,对吧?", + "{0.00->3.93}We have failed the citizens of this great city.": "{0.00->3.93}我们辜负了这座伟大城市的公民。", + "{0.29->1.30}I won't forget this,{1.68->2.36}Helldiver.": "{0.00->2.38}我不会忘记的,绝地潜兵。", + "{0.00->2.32}Democracy isn't done with you yet.": "{0.00->2.32}民主大业跟你没完。", + "{0.01->2.09}Super Earth still needs you!": "{0.01->1.91}超级地球还需要你!", + "{0.12->6.15}Status: Liberation from Automatons underway. Helldiver support requested.": "{0.00->6.15}状态:准备解放机器人。请求绝地潜兵支援。", + "{0.00->2.08}Freedom never sleeps!": "{0.00->2.08}自由真提神!", + "{0.03->0.85}We can do this.": "{0.03->1.00}我们能行的。", + "{0.01->0.97}New orders!": "{0.01->0.97}有新命令!", + "{0.00->1.27}Visibility decreasing.": "{0.00->1.53}注意,能见度降低。", + "{0.07->1.07}Hey there, Helldiver!{1.07->8.00}I know you probably have a mission to get to, but me and the rest of the crew were gonna celebrate the collapse of the Void on our break later.{8.00->11.96}I used my saved-up ration cards to score a bottle of Mr. Taste from the mess hall.{11.96->16.16}We were gonna watch old combat reels, and...if you wanted to stop by, that'd be awesome.": "{0.00->3.11}嘿,绝地潜兵!我知道你赶着去执行任务,{3.19->7.23}但我跟其他船员打算待会趁着休息,庆祝一下寂域的坍塌。{7.72->11.26}我用攒下来的配给卡,去伙房换了一瓶美味先生汽水。{11.39->14.41}我们打算看看以前的战斗录像,啊,还有……{14.52->16.36}如果你有空,请你一起来。", + "{0.01->1.30}Out of sight, out of mind!": "{0.01->1.30}看不到我看不到我!", + "{0.00->1.73}Target confirmed destroyed.": "{0.00->1.73}确认摧毁任务目标。", + "{0.03->1.32}More squids!": "{0.03->1.32}鱿鱼又来了!", + "{0.00->0.66}Hold Position.": "{0.00->0.66}原地待命。", + "{0.21->1.33}I need to reload.": "{0.06->1.07}需要换弹。", + "{0.00->1.19}Manning emplacement.": "{0.00->1.21}操纵炮位。", + "{0.00->3.47}The Helldivers receive their orders from the Ministry of Defense, {4.00->6.53}and I mine from the Ministry of Truth. {7.14->7.94}In this way, {8.30->10.89}the hands of Liberty are intertwined.": "{0.00->2.59}绝地潜兵听命于国防部,{2.99->5.40}而我听命于真理部。{5.85->11.09}解放大业的左膀右臂就是这样相互协作的。", + "{0.05->3.09}Let's go! For Democracy!": "{0.00->3.15}我们一起!为民主喝彩!", + "{0.00->0.73}Pack's out.": "{0.00->0.73}背包空了。", + "{0.00->4.68}We'll take it from here, Helldiver. Your death with not be in vain!": "{0.00->5.17}绝地潜兵,接下来就交给我们吧。你不会白白牺牲!", + "{0.96->7.16}Super Earth is proud to recommend New Liberty Lite, an official sponsor of the war effort.": "{1.10->3.69}超级地球隆重推介解放牌啤酒。{4.18->7.51}解放牌啤酒,战争事业的官方赞助商。", + "{0.04->4.16}Take position. Guard this ground like you'd guard your back yard!": "{0.00->1.23}各就各位。{1.23->3.88}人可以丢,这块地绝不能丢!", + "{0.02->0.95}Oh, Liberty!": "{0.02->0.95}自由保佑!", + "{0.16->0.68}We gotta move!": "{0.00->1.53}赶快走,快!", + "{0.07->2.85}A new bastion of prosperity.": "{0.07->2.89}又一座捍卫繁荣的堡垒。", + "{0.00->1.30}The Tarsh system": "{0.00->1.30}塔尔什星系", + "{0.10->1.31}Stand firm!{1.78->3.36}Liberty never yields!": "{0.00->1.42}给我稳住!{1.42->3.49}解放永不屈服!", + "{0.00->0.42}Alpha": "{0.00->0.42}A", + "{0.00->0.59}First one.": "{0.00->0.59}第一个。", + "{0.00->1.43}Need team reload!": "{0.00->1.43}快帮我换弹!", + "{0.00->6.16}Don't like your gear? Super Earth kindly allows you to purchase new armor with those hard-earned {6.16->7.06}Super Credits.": "{0.00->1.40}对装备不满意?{1.81->7.38}别担心,大家可以用辛苦挣来的超级货币购置新的护甲。", + "{0.00->1.02}Reloading support weapon.": "{0.00->1.15}在给支援武器换弹。", + "{0.08->4.33}We are Democracy! We are unstoppable!": "{0.00->1.95}我们就是民主!{1.95->4.44}我们势不可挡!", + "{0.00->2.27}No matter what they're hiding on Cyberstan,{2.66->3.95}we'll uncover it.": "{0.03->2.21}无论它们在生化斯坦隐藏什么,{2.57->3.90}我们都会揭露出来。", + "{0.02->0.79}Affirmative.": "{0.02->0.79}赞成。", + "{0.18->1.16}Run!": "{0.08->1.69}快跑!", + "{0.00->1.36}Throwing supply beacon.": "{0.00->1.36}投掷补给信标。", + "{0.00->1.62}Grit your teeth, soldier! {2.07->4.47}Grab that STIM and patch yourself up!": "{0.00->1.62}咬紧牙关,士兵!{2.07->4.47}拿起治疗剂,处理伤口。", + "{0.01->0.58}4!": "{0.01->0.58}四!", + "{0.01->2.73}Grenade ou- standby!": "{0.73->2.93}丢手雷,注意!", + "{0.00->0.49}Intel.": "{0.00->0.49}情报,", + "{0.01->1.87}Hey, could you teach me that later?": "{0.00->1.86}嘿,待会儿能教教我吗?", + "{0.02->2.26}Someone tell me where to shoot!": "{0.00->2.30}指哪打哪我最在行!", + "{0.05->1.90}Don't leave me here!": "{0.00->1.92}别丢下我!", + "{0.27->1.25}The Ain system": "{0.00->1.25}毕宿一星系", + "{0.02->1.19}Find shelter!": "{0.02->1.19}藏好!", + "{0.00->0.93}Swapping battery.": "{0.00->0.93}换下电池。", + "{0.01->2.12}Let Freedom fly!": "{0.00->2.20}让自由翱翔!", + "{0.01->2.97}More! MORE! Kill 'em all!": "{0.00->1.52}继续!继续!{1.70->2.97}全部杀光!", + "{0.00->0.35}Help me!": "{0.00->0.95}救救我!", + "{0.01->2.12}Pretty sure my designated shelter was this way...": "{0.01->2.43}分到的避难所应该是这边…", + "{0.00->1.55}Glad to bolster our ranks.": "{0.00->1.55}很高兴能壮大队伍。", + "{0.02->3.62}Democracy Above! You can't die!": "{0.02->3.62}民主在上!你不能死!", + "{0.00->1.10}Welcome, Helldiver.{1.48->3.79}Cyberstan is free.{4.17->11.80}Now we give pursuit to the fleeing Cyborgs, to stamp out every last spark of mechano-socialist{11.89->12.95}terrorism.": "{0.00->1.94}绝地潜兵,欢迎。{2.55->4.29}生化斯坦解放了。{5.04->7.59}现在我们要追击溃逃的生化人,{8.04->12.38}彻底根除机械化党同伐异主义的余孽。", + "{0.01->3.08}Contributing... to the Cause!": "{0.61->3.23}为了解放大业,献身!", + "{0.06->1.08}There's something here.": "{0.06->1.08}这边有发现。", + "{0.01->1.63}And STAY offline!": "{0.01->1.63}强制关机!", + "{0.04->3.60}Thank you, Helldiver, I—thank you!": "{0.00->3.65}谢谢你,潜兵,太感谢了!", + "{0.04->2.24}Don't let it eat me! Please!": "{0.04->2.24}别让它吃我!救命!", + "{0.05->1.81}Fall back, flag-rip it!": "{0.00->1.80}撤退!插了个旗的!", + "{0.00->1.46}Performing assisted reload.": "{0.00->1.46}让我来帮你换弹。", + "{0.06->1.95}You... you saved me!": "{0.00->2.13}是您……您救了我!", + "{0.02->2.11}Our lives for Super Earth!": "{0.00->2.10}为超级地球奉献一切!", + "{0.00->0.24}Up.": "{0.00->0.24}上方。", + "{0.00->1.49}Proud to serve by your side, sir.": "{0.00->1.75}和长官并肩作战,我很骄傲!", + "{0.02->1.62}I can die in peace now.": "{0.00->1.93}我死而无憾了。", + "{0.00->0.62}Let's play.": "{0.00->0.62}来玩玩吧。", + "{0.00->2.57}Here they come - about time!": "{0.00->2.57}它们来的,正是时候!", + "{0.04->2.12}Don't let it eat me! Please!": "{0.04->2.12}别让它吃我!求求了!", + "{0.04->1.63}Terminid Outpost destroyed.": "{0.04->1.63}已摧毁终结族哨站。", + "{0.00->0.70}Reloading.": "{0.00->0.94}装填弹药。", + "{0.01->2.17}Squid teleportation signature detected.": "{0.01->2.17}注意,侦测到鱿鱼传送信号。", + "{0.01->1.68}Enemy heading this way!": "{0.01->1.53}敌人往这边来了!", + "{0.00->1.37}The Probare System": "{0.00->1.08}究理星系", + "{0.00->1.76}High-value sample collected.": "{0.00->1.76}高价值样本到手了。", + "{0.01->2.61}You want more? I've got more!": "{0.01->2.61}你还想要?我这还有!", + "{0.03->1.90}It wants my brain!": "{0.03->1.90}它想吃我的脑子!", + "{0.00->0.38}Last {0.81->1.29}reload!": "{0.00->1.15}最后的弹药!", + "{0.02->4.71}Mines! Mines! Watch your step. No, YOUR step!": "{0.00->2.81}有雷!有雷!当心脚下。{2.81->4.70}不,你脚下!", + "{0.00->0.97}The squids are back!": "{0.00->0.97}鱿鱼回来了!", + "{0.00->1.78}Take a moment to remember: {3.00->4.77}You are a hero.": "{0.00->4.94}你要记住:你是英雄。", + "{0.00->2.91}Recruit expired. Deploy Hellpod sanitation team.": "{0.00->2.98}新兵死亡。绝地喷射舱卫生小队出动。", + "{0.35->1.68}You rock, Helldiver!": "{0.00->1.78}帅呆了,绝地潜兵!", + "{0.03->1.30}For Prosperity.": "{0.00->1.34}为了繁荣。", + "{0.01->1.32}More aliens!": "{0.01->1.65}外星异形又来了!", + "{0.00->3.57}If the Terminids had stayed on the Element 710 farms where they belonged, {4.16->5.95}all this bloodshed could've been avoided.": "{0.12->3.42}要是终结族还本本分分地留在710元素农场,{3.75->5.80}这一切杀戮都不必发生。", + "{0.02->1.59}Oop! GRENADE!": "{0.02->1.59}不好!有手雷!", + "{0.00->1.67}Black saffron harvested.": "{0.00->1.67}番黑花到手了。", + "{0.01->1.00}Reloading!": "{0.01->1.00}换弹!", + "{0.02->0.86}More bots!": "{0.02->0.86}还有机器人!", + "{0.00->2.00}The Terminid Hives are death traps.{2.17->4.44}That's why we only send the best.": "{0.00->2.02}终结族虫窝不亚于死亡陷阱。{2.46->4.74}所以我们只会派出最精锐的战士。", + "{0.00->4.52}A chance to advance our cause. We cannot let it slip by.": "{0.00->4.52}这是推进民主的好机会,不能错失良机。", + "{0.00->0.95}To the skies.": "{0.00->0.95}飞起来。", + "{0.01->2.84}Little close for comfort!": "{1.38->2.97}实在是太近了!", + "{0.00->0.83}Yes!{1.19->2.72}Are we glad to see you!": "{0.00->0.83}好!{1.19->2.72}见到你真是太高兴了!", + "{0.00->1.95}The Vog-Sojoth system": "{0.00->1.95}佛戈索约斯星系", + "{0.00->1.82}Targets confirmed destroyed.": "{0.00->1.82}确认摧毁目标。", + "{0.03->1.79}You'll rue the day{1.79->3.09}you came to our city.": "{0.77->3.01}这儿不是你们想来就来的。", + "{0.03->1.29}It's the Helldivers!": "{0.03->1.29}是绝地潜兵!", + "{0.03->6.54}Alert: Liberation of currently orbited planet from Terminid menace has ended in {6.90->8.14}temporary defeat. {8.68->11.86}Planet remains under Terminid control.": "{0.00->7.86}通知:击退终结族威胁,解放当前星球的行动暂时失利。{8.01->11.86}该星球仍归终结族统治。", + "{0.00->1.00}Are you sure it's safe here?": "{0.00->1.23}这里确定安全吗?", + "{0.00->2.14}Heavy ordnance. Fall back!": "{0.00->2.20}重火力打击!撤退!", + "{0.02->1.29}Everyone into cover!": "{0.00->1.41}所有人进掩体!", + "{0.00->2.96}Ever marvelled at Illuminate technology?{4.03->6.71}Report to your Loyalty Officer.": "{0.00->4.01}你是不是以前赞叹过光能者的技术?{4.69->6.79}向忠诚事务官报告。", + "{0.00->1.40}Calling down a vehicle.": "{0.00->1.40}请求载具支援。", + "{0.00->2.27}If a bot speaks to you, shoot it. {2.65->9.55}Their lies are calibrated to sew dissidence and hate. And hate is one thing we cannot abide.": "{0.00->2.79}如果机器人与你对话,直接朝它开枪。{3.35->7.75}机器人满口谎言,只为在你心中种下怀疑和仇恨的种子,{8.15->9.89}我们绝不容忍仇恨。", + "{0.04->2.47}Yeah!! Keep up the momentum!": "{0.00->2.59}对!!保持这样的势头!", + "{0.01->2.49}The only good bug is a dead bug!": "{0.01->2.49}虫子死了才好!", + "{0.00->0.35}Done.": "{0.00->0.35}搞定。", + "{0.00->1.29}For Super Earth!": "{0.00->1.52}为了超级地球!", + "{0.00->1.55}They're trying to flush us out!": "{0.00->1.55}它们想把我们赶走!", + "{0.00->0.93}Stratagem beacon.": "{0.00->1.00}战略配备信标,", + "{0.07->2.02}KILL EM ALLLLLLL!!!": "{0.07->2.02}一个都别想跑!!!", + "{0.00->2.15}We're gonna make those robots regret being built.": "{0.00->2.15}要让那些机器人后悔自己被造出来。", + "{0.03->0.85}Absolutely!": "{0.03->0.85}没有问题!", + "{0.02->1.11}Cover my sector!": "{0.02->1.11}照顾下我这边!", + "{0.00->1.29}Illuminate teleporting in.": "{0.00->1.29}光能者即将传送抵达,", + "{0.02->0.84}Contact!": "{0.02->0.84}上啊!", + "{0.00->3.52}But a single triumph more, and the operation is complete.": "{0.00->4.03}只要再达成一次胜利,这次行动就圆满告成了。", + "{0.00->0.71}I'm honored,{1.18->3.68}so honored, what an honor!": "{0.00->1.21}我很荣幸,{1.21->3.89}太荣幸了,这是何等的荣幸!", + "{0.06->5.48}So, this is it! Cyberstan, the Den of Dissidence.{5.48->11.34}Doesn't look much like the cartoons, huh? Less spikes?": "{0.19->5.00}终于到了!生化斯坦,异见者的巢穴。{6.58->8.97}样子跟动画片里的不太一样,对吧?{9.44->11.28}尖刺少了些?", + "{0.00->2.65}YES, HELLDIVERS! YESSSSS!!!!": "{0.00->2.65}好样的,绝地潜兵!干得好!!!!", + "{0.00->1.11}Remember your training!": "{0.00->1.21}牢记训练的内容!", + "{0.00->3.51}Black saffron. Life saving and non-habit forming.": "{0.00->3.51}番黑花,只救命,不成瘾。", + "{0.00->2.11}Brain-eating terrorists.": "{0.00->2.11}吃脑子的垃圾玩意儿。", + "{0.03->0.46}Far.": "{0.03->0.57}有点远。", + "{0.02->1.75}Find something to hide behind.": "{0.02->1.75}找地方躲起来。", + "{0.03->2.21}Go there, now! Don't look back!": "{0.00->2.23}去那边,快!别回头!", + "{0.00->0.61}Northeast.": "{0.00->0.39}东北,", + "{0.08->1.74}Sweet Liberty,{2.13->3.48}it's the Helldivers!": "{0.04->1.15}解放保佑,{1.53->2.88}绝地潜兵来了!", + "{0.02->1.84}You and me, Helldiver!": "{0.00->1.87}你和我,绝地潜兵!", + "{0.02->0.83}Get in!": "{0.02->0.83}上来!", + "{0.00->0.37}Danger.": "{0.00->0.41}危险,", + "{0.00->1.66}With the Helldivers on our side, we can't lose!": "{0.00->3.12}有绝地潜兵站在我们这边,输不了!", + "{0.00->1.59}You'll get what's coming.": "{0.00->1.30}你会遭报应的。", + "{0.00->4.20}The Terminids think they're safe on this \"Hive World.\" Correct them.": "{0.00->2.90}终结族以为躲在这个“虫窝世界”里就安全了。{2.90->4.20}好好教育下。", + "{0.00->0.72}Reposition!{1.21->3.16}We'll strike even harder elsewhere!": "{0.00->1.22}转移阵地!{1.22->3.24}换个地方全力打击!", + "{0.05->2.12}Retreat, retreat!": "{0.00->2.26}撤退,撤退!", + "{0.00->3.84}Eagle 1 reporting in, hauling 16 tons of weaponized Freedom.": "{0.00->3.84}“飞鹰”1号报告,已装载16吨自由武器。", + "{0.00->1.30}Democracy Above,{1.98->3.26}here we go again...": "{0.00->1.79}民主在上,{1.79->3.62}我们又来了……", + "{0.01->1.17}Requesting equipment!": "{0.01->1.17}请求装备支援!", + "{0.04->2.03}I'm a hero...": "{0.00->2.68}我是英雄…", + "{0.33->1.29}Is that...{1.65->2.86}all you got...?": "{0.00->0.72}你就…{1.46->3.05}这点本事…?", + "{0.03->1.27}Get back in there!": "{0.00->1.29}可以回战场了!", + "{0.00->4.45}This is a Commando operation, deep behind enemy lines.{4.98->8.16}You will not have the support of the Super Destroyer;{8.62->14.06}only your superior wits, your thorough training, and your trusted rifle.": "{0.00->4.39}这是一项突击兵行动,需要你深入敌后。{4.98->8.16}这次行动没有超级驱逐舰的支援,{8.62->12.27}你只能靠过人的智慧、全面的训练经验{12.58->14.39}和可靠的步枪。", + "{0.00->1.19}Weapons ready!": "{0.00->1.06}武器就绪!", + "{0.00->1.94}It was an honor to draw with you.": "{0.00->2.09}能与你打成平手是我的荣幸。", + "{2.28->5.40}I'm not gonna make it...": "{1.86->4.81}我撑不下去了…", + "{0.00->1.21}Filthy bug.": "{0.00->1.21}卑鄙的虫子。", + "{0.03->1.79}Good day for violence.": "{0.00->1.82}以暴制暴就是今天。", + "{0.00->1.33}The Terrek system": "{0.00->1.33}泰雷克星系", + "{0.01->1.00}Reinforcing.": "{0.01->1.00}请求增援。", + "{0.00->1.64}Swapping Internal Cooling Element.": "{0.00->1.64}更换内部冷却元件。", + "{0.05->2.74}S-E-A-F, what does it spell?!": "{0.00->2.74}S-E-A-F,跟我一起念!", + "{0.04->2.35}Request approved; deploying reinforcements.": "{0.04->2.35}批准请求;部署增援。", + "{0.65->1.29}For Super Earth!": "{0.00->1.33}为了超级地球!", + "{0.00->2.95}SEAF forces depleted; additional reinforcements requested.": "{0.00->3.00}武装部队兵力耗尽,已请求更多增援。", + "{0.03->0.90}What are they?": "{0.03->1.06}是什么东西?", + "{0.02->1.21}Reloading you!": "{0.02->1.21}帮你换弹!", + "{0.14->2.80}Sorry, wish I could give you more of a fight.": "{0.00->2.93}抱歉,我也希望我能够到你的水平。", + "{0.02->1.22}Robot scum!": "{0.02->1.22}铁皮渣滓!", + "{0.00->0.38}Whoa! Uh,{1.76->3.07}greetings, Helldiver.": "{0.18->2.76}额。绝地潜兵,你好。", + "{0.00->0.49}I'm out.": "{0.00->0.49}打光了。", + "{0.00->1.70}The Electra Bay system": "{0.00->1.70}昴宿一湾星系", + "{0.00->3.85}All these Samples will help fund upgrades to the Super Destroyer.": "{0.00->3.85}这些样本有助于我们升级超级驱逐舰。", + "{0.01->2.33}The will of Democracy saw us safe.": "{0.01->2.33}民主保佑,我们安全了!", + "{0.00->1.11}Orbital incoming.": "{0.00->1.11}轨道攻击来了。", + "{0.07->1.76}Take a moment to remember: {3.32->5.90}Your family is proud of you.": "{0.00->6.17}你要记住:家人以你为荣。", + "{0.01->1.38}Requesting vehicle!": "{0.01->1.38}请求载具!", + "{0.05->2.67}Real Helldivers! I don't believe it!": "{0.05->2.67}绝地潜兵,真的是绝地潜兵!", + "{0.02->3.07}They got me. Need a second!": "{0.53->3.07}我被打中了。给我点时间!", + "{0.00->1.28}The Maw system": "{0.00->1.28}深渊星系", + "{0.01->1.43}When's the shuttle coming?": "{0.01->1.43}运输船什么时候到?", + "{0.00->1.67}Us, on the same level?{2.03->2.86}No way.": "{0.00->1.63}我们居然平局?{1.63->2.79}怎么可能。", + "{0.00->0.71}Rolling out.": "{0.00->0.71}现在出发。", + "{0.00->2.95}I just set all the ship's clocks back an hour for Freedom Savings Time.": "{0.00->1.76}我刚把时间都回调一小时,{1.92->3.31}换成自由节约时制。", + "{0.04->2.33}Oops, accidentally copied you!": "{0.00->2.52}哎呀,不小心跟你出的一样!", + "{0.03->2.73}The Automatons are attacking the Moon.{2.73->5.84}If they're able to establish a base there...{5.84->7.09}we won't let them.": "{0.03->1.55}机器人正在攻击月球。{2.11->3.65}它们要是在那里建造基地……{4.99->6.19}绝不能让它们得逞。", + "{0.00->1.51}We fight on together!": "{0.00->1.64}一个都不能少!", + "{0.00->3.11}This planet will not fall to darkness today.": "{0.00->3.11}这颗星球今天不会陷入黑暗。", + "{0.00->2.70}Mourn later. Cover their zones!": "{0.00->2.70}等下再哀悼。守住他们那边!", + "{0.00->3.39}That was the coolest moment of my entire life.": "{0.00->3.39}这是…我的人生高光!", + "{0.00->1.56}The Klen Dahth system": "{0.00->1.56}克伦达斯星系", + "{0.00->0.74}Of course.": "{0.00->0.74}那当然。", + "{0.00->1.72}Freedom guide us!": "{0.00->1.72}自由保佑!", + "{0.05->3.19}Same throw... this can't be happening!": "{0.00->3.35}出的一样……这怎么可能!", + "{0.02->0.43}Ok!": "{0.02->0.43}好的!", + "{0.01->1.34}There! Hide there!": "{0.01->1.57}那边!躲在那!", + "{0.04->1.72}Robot scum!": "{0.04->1.72}铁皮渣滓!", + "{0.00->1.20}Watch the flanks!": "{0.00->1.20}注意侧翼!", + "{0.00->2.10}Deploying destructive equipment!": "{0.00->2.18}正在部署爆破装置!", + "{0.00->1.49}The Wezen system": "{0.00->1.49}弧矢一星系", + "{0.00->1.45}The Effluvia system": "{0.00->1.45}艾芙鲁维亚星系", + "{1.11->3.58}Courage and loyalty will see me through!": "{1.11->3.58}勇气和忠诚会帮助我渡过难关!", + "{0.01->2.09}Democracy deliver us!": "{0.01->2.09}愿民主保佑我们!", + "{0.00->0.56}Fall back!": "{0.00->0.56}撤退!", + "{0.00->3.18}The tides of Liberty will sweep these streets clean.": "{0.00->3.18}让解放的春风吹满大地。", + "{0.00->0.70}ETA T-{1.18->2.11}2 minutes.": "{0.00->0.70}预计2分{1.18->2.11}钟后到达。", + "{0.00->1.38}Extraction is available.": "{0.00->1.38}可以呼叫撤离。", + "{0.19->2.57}We sacrifice for paradise.": "{0.00->2.74}我们为乐土而献身。", + "{0.00->7.47}Man down! Don't sweat it, soldier: friendly fire is just an unavoidable fact of life. Nothin' AT {7.47->13.75}ALL you can do to prevent it! What you CAN do is use the Reinforcement Stratagem to replace your {13.75->14.76}fallen comrade!": "{0.00->1.51}友军倒地!{1.96->6.50}别担心,士兵:友军误伤是难以回避的残酷现实。{7.04->11.97}你无法挽回也无法避免,只能使用增援战略配备,{12.20->14.95}呼叫援兵,替代阵亡的战友!", + "{0.03->1.24}Thank you, Helldiver.": "{0.00->1.42}谢谢你,潜兵。", + "{0.00->0.85}Last reload.": "{0.00->0.85}最后一组弹药。", + "{0.00->1.52}The bridge is yours, Helldiver. {2.08->3.08}Take us to the fight.": "{0.00->1.37}舰桥由你指挥,{1.76->3.09}带领我们去战斗。", + "{0.01->1.39}Stand your ground!": "{0.01->1.39}坚守阵地!", + "{0.24->1.29}Oh, Liberty!": "{0.00->1.68}自由保佑!", + "{0.00->1.81}Democracy isn't done with you yet.": "{0.00->2.29}民主大业跟你没完。", + "{0.03->1.41}More Red-eyes!": "{0.03->1.41}红眼怪物又来了!", + "{0.03->0.95}You're here!": "{0.03->0.95}你们来了!", + "{0.00->1.06}Encounter cleared.": "{0.00->1.06}遭遇战已结束。", + "{0.00->2.95}I'm gonna spend my extra hour doin' another round of maintenance checks.": "{0.00->1.57}我要用这多出来的一个小时{1.64->2.94}再做一轮维护检查。", + "{0.00->0.95}Item collected.": "{0.00->0.95}东西到手了。", + "{0.00->0.43}Mag.": "{0.00->0.43}弹匣。", + "{0.00->1.50}Reloading support weapon.": "{0.00->1.50}在给支援武器换弹。", + "{0.00->2.64}The Cyborgs rise from the dead.{3.07->5.25}Return them whence they came.": "{0.00->2.13}生化人死而复生。{2.88->5.60}让他们从哪儿来回哪儿去。", + "{0.00->0.40}Make them{1.05->1.57}pay...!": "{0.00->2.12}让它们付出代价…!", + "{0.00->2.34}Deep breaths. Calm mind.": "{0.00->2.34}深呼吸。冷静。", + "{0.00->1.95}The Oslo Station system": "{0.00->1.95}奥斯陆站星系", + "{0.00->2.15}Pleasure to watch you work, Helldiver!": "{0.00->2.54}绝地潜兵,表现太完美了!", + "{0.00->4.70}This ship will never visit most of our planets. Why? Because they aren't under attack. {5.22->6.14}And with you here, {6.58->7.72}they'll stay that way.": "{0.00->2.13}大多数星球都没见过这艘舰船。{2.48->5.07}为什么?因为它们没有受到攻击。{5.31->8.36}只要有你在,它们就能继续享受和平。", + "{0.03->0.81}Taking cover!": "{0.00->0.90}寻找掩护!", + "{0.02->0.81}Kill them all!": "{0.02->0.81}把他们杀光!", + "{0.01->1.77}Undemocratic bastards!": "{0.00->1.77}不服从民主的畜生!", + "{0.00->3.67}One small scrap of technology, one giant leap for Liberty.": "{0.00->3.67}科技研究一小步,解放大业一大步。", + "{0.09->1.95}Are you sure it's safe here?": "{0.09->1.95}这里确定安全吗?", + "{0.01->2.13}Again! Hit 'em again!": "{0.01->2.13}再来!再给他来一下!", + "{0.01->3.98}Tell my family...to vote...": "{0.01->3.98}告诉我家人…投票…", + "{7.83->11.02}Freedom's Greetings, I'm Coretta Kelly.{11.57->17.77}A recent report has shed light on the repulsive process by which new Cyborgs are created:{18.47->28.04}Zygotes are harvested from a soup of human-like gametes, to then be placed into chambers filled with synthetic amniotic fluid.{28.29->35.83}Following an accelerated growth process, a malformed humanoid is fused to a titanium exosuit.{36.52->42.59}The newly-created weapon is then rapidly conditioned with anti-Democratic brainwashing,{42.85->48.84}before being shipped to the front lines with orders to butcher any human it finds.{49.03->51.86}While Cyborg DNA may match ours,{52.06->57.79}there is no mistaking these monsters for anything resembling human.{58.51->61.75}Up next: Have you ever seen a surfboarding turtle?{62.29->68.35}This tubular terrapin says: \"Hang 10.\" More on that, when we return.": "{7.78->10.74}自由向各位问好,我是科雷塔·凯利。{11.61->13.79}一份最新报告让我们得以了解{14.12->17.41}令人作呕的新型生化人制造过程:{18.37->22.72}首先,他们从类人配子溶液中提取出受精卵,{23.19->27.80}然后将受精卵置入充满合成羊水的培养腔室中。{28.16->29.89}经过加速生长过程后,{30.17->35.92}将畸形的类人体与钛合金外骨骼熔合,变成冷酷的战斗工具。{36.72->41.60}随后,这个新造的武器将立刻接受反民主思想的洗脑训练,{42.01->44.47}然后直接送往前线参与战斗,{44.95->48.36}对视野范围内的人类进行无差别屠杀。{49.04->52.33}虽然这些生化人的基因可能与我们人类相似,{52.65->54.06}但它们身上每一处{54.27->57.90}都散发着非人怪物般的冰冷与恐怖。{58.60->61.77}接下来请收看:你见过冲浪的海龟吗?{62.21->65.59}这只帅气的龟龟说:“来个挂十。”{66.23->68.02}稍后继续为您报道。", + "{0.00->0.10}I don't think I can do that.": "{0.00->1.09}我这边过不去。", + "{0.00->2.24}If we don't stop the bugs' mindless reproduction, {2.60->4.33}the burden's going to fall on our children. {4.78->6.28}And our children's children.": "{0.00->1.84}如果不去阻止虫族的繁殖,{2.09->6.17}这幅重担就会落在我们的孩子,乃至孩子的孩子肩上。", + "{0.03->1.30}The Navi system": "{0.03->1.30}阁道二星系", + "{0.00->1.12}Requesting air support.": "{0.00->1.12}请求空中支援。", + "{0.00->3.15}We will remember your sacrifice, Helldiver!": "{0.00->3.15}绝地潜兵,我们不会忘记你!", + "{0.00->0.81}Next lesson: {1.19->5.16}Helldivers fight in squads. Meet your new squadmate!": "{0.00->0.86}下一课:{1.29->5.16}绝地潜兵组成小队作战,见见你的新队友!", + "{0.01->1.16}Need to reload!": "{0.01->1.16}需要换弹!", + "{0.00->1.60}The Lambast System": "{0.00->1.39}兰巴斯特星系", + "{0.03->1.56}Don't let it eat me! Please!": "{0.03->2.09}别让它吃我!救命!", + "{0.00->0.37}Down.": "{0.00->0.44}下方。", + "{0.05->4.14}The Void becomes full. Of Freedom.": "{0.00->2.38}寂域将会被填满。{2.39->4.31}被自由填满。", + "{0.25->0.50}Move, move, move!": "{0.03->0.79}快,快,快!", + "{0.08->1.92}It wants my brain!": "{0.08->1.92}它想吃我的脑子!", + "{0.00->0.89}I need to reload.": "{0.00->0.89}需要换弹。", + "{0.00->1.77}For Liberty, always!": "{0.00->1.90}为了解放,永远!", + "{0.15->6.41}The bot War Strider is a crude imitation of our far superior Exosuit technology. {6.97->13.84}The Automatons' attempts at dominance only serve to lay bare their fundamental inferiority.": "{0.15->6.22}机器人的战争纵步者是对我方先进外骨骼装甲技术的粗劣模仿。{6.55->13.84}机器人试图在各方面主宰一切,反而暴露了它们的根本劣势。", + "{0.00->1.25}Calling down a sentry.": "{0.00->1.25}呼叫哨戒炮。", + "{0.01->0.96}Aaargh!": "{0.00->1.05}啊啊!", + "{1.10->1.72}Well,{2.27->4.05}no one can beat a Helldiver.": "{0.90->2.07}没事,{2.27->4.09}没人能打败绝地潜兵。", + "{1.32->1.67}Have a taste of Democracy!": "{0.33->1.67}尝尝民主!", + "{0.01->1.48}SOS!": "{0.01->1.48}救救我!", + "{0.03->1.30}Get it away from me!": "{0.03->1.69}快帮我把它弄走!", + "{0.00->0.85}Deploying flare.": "{0.00->0.85}部署照明弹。", + "{0.00->2.12}Democratic stims for you, my friend!": "{0.00->2.11}朋友,给你来一针民主!", + "{1.02->1.95}Stims, stims please!": "{0.00->1.99}一针!我就要一针!", + "{0.01->2.43}No...that's impossible!": "{0.01->2.43}不…不可能!", + "{0.02->2.42}My life for Super Earth!": "{0.00->2.44}为超级地球献身!", + "{0.01->1.18}My arm!": "{0.01->1.50}我的胳膊!", + "{0.00->2.55}Allied Destroyer has joined squadron.": "{0.00->2.55}友方驱逐舰已加入中队。", + "{0.00->1.95}Calling in an orbital strike.": "{0.00->1.87}请求轨道攻击支援。", + "{0.00->1.48}Boom! Target down.": "{0.00->1.48}砰!消灭目标。", + "{0.02->1.40}...thank you, Helldiver.": "{0.00->1.52}……谢谢你,绝地潜兵。", + "{0.00->0.50}Don't need it.": "{0.00->0.49}不需要。", + "{0.00->0.85}Awesome!": "{0.00->0.91}绝了!", + "{0.00->0.72}Enemy elite.": "{0.00->0.72}敌方精英,", + "{0.40->1.31}Terminids.{1.49->4.53}Unthinking monstrosities who want nothing more than to kill{4.53->6.44}and eat every last human,{6.66->9.65}and every last human includes your family.{10.10->13.59}Don't let your family get eaten. Enlist today.": "{0.40->2.80}终结族。不会思考的怪物,{3.25->6.84}只想把人类杀光吃尽,连你的家人也不放过。{7.32->9.65}记住!不会放过你的家人。{10.10->13.59}不要让它们吃掉你的家人。立刻入伍吧!", + "{0.00->0.59}Foxtrot": "{0.00->0.59}F", + "{0.01->1.38}Low and steady, people!": "{0.01->1.04}大家都躲好了!", + "{0.00->2.18}A few more bots out of commission.": "{0.00->1.85}又多了一些破铜烂铁。", + "{0.00->2.18}This must be part of Super Earth's plan.": "{0.00->1.93}超级地球肯定料到了。", + "{0.00->1.30}Yeah, let's finish this.": "{0.00->1.30}对!干就完了。", + "{1.58->3.24}Heroes do exist...": "{1.18->3.17}英雄真的存在……", + "{0.03->1.34}Look out! Squids!": "{0.03->1.34}小心!鱿鱼!", + "{0.00->0.41}Close.": "{0.00->0.41}在附近。", + "{0.01->3.76}Super Earth protect us...": "{0.01->3.76}超级地球保佑我们...", + "{0.03->1.26}Watch for OPFOR.": "{0.00->1.35}留意敌方动向。", + "{0.06->2.65}BATHE IN THE BLOOD OF TYRANTS!!!": "{0.06->2.65}暴政没好下场!!!", + "{0.04->1.97}Let's see what this thing can do!": "{0.00->2.01}瞧瞧这玩意儿的威力!", + "{0.00->2.87}Now we're part of Super Earth's victory.": "{0.45->2.60}一切为了超级地球。", + "{0.00->2.04}O'er every last star...": "{0.00->2.28}吹遍宇宙繁星。", + "{0.00->0.80}Never doubt!": "{0.00->0.98}绝对忠诚!", + "{0.00->0.64}Fourth one.": "{0.00->0.64}第四个。", + "{0.00->2.14}This sample should greatly aid in the war effort.": "{0.00->2.14}这份样本必有大用。", + "{0.01->0.70}Reloading.": "{0.01->0.70}正在换弹。", + "{0.00->0.92}We'll drop in here.": "{0.00->0.92}在这里降落。", + "{0.01->2.57}FREEDOM CONQUERS ALL!": "{0.01->2.57}自由精神战无不胜!", + "{0.00->0.56}Dropships.": "{0.00->0.56}运输舰,", + "{0.00->3.95}All Helldivers, please report to Democracy Officer.": "{0.00->3.95}所有绝地潜兵,请向民主官报到。", + "{0.00->0.95}Found something.": "{0.00->0.95}这边有发现。", + "{0.00->1.20}We can't stay here!": "{0.00->1.25}这里不能待了!", + "{0.02->1.85}Save me, Helldiver!": "{0.00->1.97}潜兵,救救我!", + "{0.00->0.56}Bug hole.": "{0.00->0.56}虫穴,", + "{0.36->2.25}Aaargh!": "{0.00->2.46}啊啊!", + "{0.00->1.50}Are you sure it's safe here?": "{0.00->1.50}这里确定安全吗?", + "{0.05->3.22}That was for us. For me.": "{0.00->2.01}这是为了我们。{2.01->3.36}为了我。", + "{0.00->7.41}Did you know? The scientific term for a group of bugs is \"A Bane of Terminids.\" The unofficial {7.41->9.14}term is \"Future Element {9.53->9.95}710.\"": "{0.00->1.01}你知道吗?{1.46->5.41}科学界用“虫祸之源”代指一群虫族,{6.16->10.26}非正式的说法则是“未来的710元素”。", + "{0.05->5.06}The enemy's stench oppresses the very air of our children's innocent nostrils.": "{0.05->4.87}敌人散发的恶臭让无辜的孩童难以畅快呼吸。", + "{0.04->1.31}Reloading team weapon!": "{0.04->1.31}团队武器换弹!", + "{0.38->3.40}And now, another helpful tip from General Brasch.{5.91->8.31}You will get shot at. {10.98->14.91}But remember your ABCs and you will never die. {15.20->18.34}Always. Be. Taking Cover. {19.74->22.05}Because if there's one thing I've learned,{22.26->25.64}it's that bullets do not go through cover. {26.28->30.05}Assuming that cover is thick and largely impenetrable. {31.49->35.35}BRASCH TACTICS! Use 'em, or die trying.": "{0.00->3.40}布拉施将军又带来了一条实用提示。{5.91->8.68}敌人会朝你开火还击。{10.98->14.91}但只要记住一点,你就永远都不会死。{15.20->18.34}那就是,找——掩——体。{19.74->24.59}我在战场上学到的一点就是,子弹是打不穿掩体的。{25.85->28.77}前提是掩体够厚,难以打穿。{31.57->32.97}布拉施亲传战术!{33.33->35.70}竭尽全力,不死不休。", + "{0.00->1.35}The Barabos system": "{0.00->1.35}巴勒博斯星系", + "{0.02->0.74}I can't!": "{0.02->0.74}不可以!", + "{0.03->0.44}Thank you,{0.91->1.49}truly,{1.92->3.57}for taking the time to beat me.": "{0.00->1.72}谢谢你,真的,{1.92->3.75}感谢你抽时间打败我。", + "{0.03->1.45}We're all gonna die!": "{0.03->1.45}我们都死定了!", + "{0.01->1.59}Fellow citizens!": "{0.01->1.59}公民同胞!", + "{0.07->3.39}And now, another helpful tip from General Brasch.{7.31->11.63}If the enemy can see you, the enemy can kill you.{12.87->16.07}So get out of sight and lose your pursuers!{16.31->21.31}Because if there's one thing I've learned, it's that you gotta hide to survive. {21.98->23.46}But not for too long! {23.71->24.59}Because that...{25.09->26.76}makes you a coward. {30.40->34.16}BRASCH TACTICS! Use 'em, or die trying.": "{0.07->3.39}布拉施将军又带来了一条实用提示。{7.31->10.23}敌人能看到你就能杀了你,{12.42->15.11}所以你要摆脱敌人的目光!{16.85->21.89}我在战场上学到的一点就是,你必须躲起来才能活下去。{22.62->23.89}但别躲太久了!{24.34->27.29}因为……躲太久就成了懦夫了。{30.09->31.65}布拉施亲传战术!{31.88->34.16}竭尽全力,不死不休。", + "{0.03->2.55}Show these hostiles some hospitality!": "{0.00->2.58}让敌人尝尝我们的热情!", + "{0.00->3.37}Why a Helldiver? Whyyy?!": "{0.00->3.37}为什么死的是绝地潜兵?为什么?!", + "{0.02->2.51}Make way for Super Earth's finest!": "{0.02->2.51}给超级地球的精英让路!", + "{0.02->1.46}Death to the Terminids!": "{0.02->1.46}终结族,受死吧!", + "{0.04->3.50}Take cover, take some flag-ripped cover!": "{0.00->3.53}找掩体,插他旗的快找掩体!", + "{0.00->2.46}01000001 {2.74->5.21}01001000. {5.60->7.66}That was the first intercepted bot message. {8.12->10.82}Our analysts think it means \"Kill all humans.\"": "{0.00->2.69}01000001{2.86->5.58}01001000。{6.04->8.45}这是我们截获的第一条机器人情报。{8.60->11.46}破译结果可能是“消灭全人类”。", + "{0.01->1.40}They're coming!": "{0.01->1.14}它们来了!", + "{0.00->1.72}Democracy for all.": "{0.00->1.72}民主人人有份。", + "{0.00->0.62}New mag.": "{0.00->0.62}新弹匣。", + "{0.00->2.22}The bugs swarm across this planet. {2.65->4.56}Choose where to make your stand.": "{0.00->2.22}这颗星球有大量虫族盘踞。{2.65->4.56}请选择你要在何处登陆。", + "{0.00->1.51}Control your breathing!": "{0.00->1.51}控制好你的呼吸!", + "{0.00->3.79}Decide upon which battleground you shall spread Liberation.": "{0.00->3.79}请决定你要在哪个战场上传播解放。", + "{0.00->0.73}Weapons ready.": "{0.00->0.73}武器就绪。", + "{0.00->4.90}Democracy has been well delivered. May your extraction be swift.": "{0.00->2.35}民主已经落实到位,{2.91->4.90}愿你顺利快速撤离。", + "{0.09->1.40}Calling in extraction.": "{0.09->1.40}呼叫撤离。呼叫撤离。", + "{0.07->2.38}The enemy's occupation ends soon.": "{0.07->2.38}敌人的占领即将终结。", + "{0.00->1.15}The Propus system": "{0.00->1.15}五诸侯三星系", + "{0.00->1.46}The Moradesh system": "{0.00->1.46}莫拉戴什星系", + "{0.00->2.40}This crystallized E-710{2.40->4.11}will help fuel our future.": "{0.00->1.77}710元素晶体{1.81->4.11}造福未来。", + "{0.00->1.95}It was an honor to draw with you.": "{0.00->2.17}能与你打成平手是我的荣幸。", + "{0.02->8.42}Grim tidings, Helldiver. Our supply lines are strained, our reinforcements exhausted.{8.42->15.65}We have no choice but to withdraw. The liberation of Cyberstan has failed.": "{0.00->2.38}绝地潜兵,有坏消息。{2.88->6.55}我们的补给线吃紧,援军消耗殆尽。{7.10->10.24}我们别无选择,只能撤退。{11.15->15.28}解放生化斯坦以失败告终。", + "{0.00->1.67}Prosperous populace, that's good.": "{0.00->2.53}繁荣在上,真不错。", + "{0.01->2.85}Liberty will endure..": "{0.01->2.85}解放永垂不朽……", + "{1.04->1.22}Sweet Freedom!{1.68->4.18}The Helldivers'll make them pay!": "{0.00->1.20}自由大业!{1.47->4.14}绝地潜兵不会放过它们!", + "{0.00->0.64}Very well.{1.11->2.38}I'll do you proud.": "{0.13->0.50}好的。{0.89->2.01}我会让你为我骄傲!", + "{0.00->2.51}Our way of life is why we fight!": "{0.00->1.94}我们为生存正道而战!", + "{0.05->0.65}Squids! {1.06->1.35}Run!": "{0.05->0.65}是鱿鱼!{1.06->1.73}快跑!", + "{0.00->5.15}The Illuminate turned abducted citizens into Voteless against their will.{5.96->10.40}If that was but the start of their twisted plans to transform our citizens,{10.92->17.64}I shudder to imagine what unspeakable horrors await our citizens within the Void.": "{0.00->3.27}光能者违背被绑架公民的意愿,{3.67->5.86}将他们转变为无票者。{6.52->10.11}如果这只是它们扭曲改造计划的开端,{10.62->15.14}我不敢想象寂域中还有什么难以言喻的恐怖{15.46->17.62}在等待着我们的公民。", + "{0.00->0.28}Let's go!": "{0.00->1.02}这下可以了!", + "{0.00->1.69}Helldiver, please!": "{0.00->1.75}潜兵,拜托了!", + "{0.00->3.67}The galaxy slides farther into darkness, Helldiver.{4.16->7.19}The Illuminate have plunged entire planets{7.19->12.31} into an inkblack darkness that Liberty's Light cannot penetrate.": "{0.00->4.36}绝地潜兵,银河系正在滑向黑暗。{5.10->8.97}光能者让整颗星球陷入了漆黑的深渊,{9.50->12.38}连自由之光都无法照亮。", + "{0.00->1.88}Eagle 1, withdrawing to rearm.": "{0.00->1.88}“飞鹰”1号返回补给。", + "{0.00->0.59}Follow me.": "{0.00->0.59}跟我走。", + "{0.01->2.42}Thank Super Earth for the Helldivers!": "{0.00->2.92}感谢超级地球派来的绝地潜兵!", + "{0.00->3.20}Nothing can topple our way of life!": "{0.00->3.20}什么都改变不了我们的生存正道!", + "{0.00->1.16}Sending in an Eagle.": "{0.00->1.16}请求出动“飞鹰”。", + "{0.00->1.62}I'll remember this forever.": "{0.00->1.62}我会永远记住你们的。", + "{9.07->12.06}Freedom's Greetings, I'm Coretta Kelly.{12.34->16.26}The Helldiver fleet has launched bravely into the Void,{16.33->24.05}penetrating the depths of the exotic miasma for the first time since its appearance several months past.{24.28->29.62}Many planets have disappeared into the Void since it was first created by the Illuminate.{29.81->41.28}Intelligence on what lies within is scarce, but the Helldivers are undeterred, valiantly plunging into its depths to stop its spread, and destroy it.{41.43->49.58}A Ministry of Science panel has determined the top three things the Helldivers are most likely to encounter within the Void:{50.00->58.69}the Illuminate, uncanny phenomena that defy explanation, and a plot to murder every human in the galaxy.{58.77->61.09}May Liberty guide them.{61.21->66.09}That's Liberty's Latest; I'm Coretta Kelly.": "{9.12->12.44}自由向各位问好,我是科雷塔·凯利。{12.44->15.95}绝地潜兵舰队英勇挺进寂域,{15.95->19.74}自从这种异星瘴气出现数月以来,{19.74->24.17}这还算超级地球部队第一次直捣其腹地。{24.17->29.78}自光能者炮制寂域以来,已有许多星球惨遭吞噬。{29.78->33.34}我们对寂域内部几乎一无所知,{33.34->37.19}但绝地潜兵英勇出击,深入核心,{37.19->41.48}誓要遏止蔓延,将其彻底摧毁。{41.48->45.22}据隶属于科学部的专家小组断定,{45.22->50.63}绝地潜兵最有可能在寂域中遭遇以下三种情况:{50.63->54.76}光能者的袭击、无法解释的奇诡现象,{54.76->59.00}以及妄图毁灭星系内全体人类的阴谋。{59.00->61.14}愿解放指引他们。{61.14->65.12}以上就是今天的《解放新闻》,我是科雷塔·凯利。", + "{0.00->1.25}Calling in a Hellbomb.": "{0.06->1.58}呼叫地狱火炸弹。", + "{0.00->0.87}Squid warp gate.": "{0.00->0.87}鱿鱼传送门,", + "{0.03->3.61}I always dreamed of watching the Moon from Super Earth...{3.61->7.57}maybe even take part in a test firing, put my own crater on it.{7.57->11.90}That was before I took the Workplace Assignment Assessment, of course.": "{0.03->3.19}我一直梦想着从超级地球上看月球……{3.93->5.79}说不定还能参加试射,{6.06->7.72}在上面留下属于我的弹坑。{8.51->11.95}当然,那是在我参加职业分配评估之前的事情。", + "{0.00->4.64}I'm sorry! I will report myself to re-education!": "{0.74->4.71}抱歉!我会主动申请接受再教育!", + "{0.00->1.94}The Galactic War waits for no one. {2.60->3.87}Are you ready, Helldiver?": "{0.00->1.60}星系战争刻不容缓,{1.80->3.87}绝地潜兵,准备好了吗?", + "{0.00->1.07}Calling down a vehicle.": "{0.00->1.07}请求载具支援。", + "{0.06->2.23}Fallen foes -- Freedom's fuel.": "{0.06->1.94}让自由烧的更旺。", + "{0.02->1.14}The bots are here!": "{0.02->1.39}机器人来了!", + "{0.06->4.12}The Exostorms are no natural weather patterns.{4.50->9.05}Their uncanny auroras darken entire hemispheres.": "{0.06->3.77}异界风暴并非自然气候现象。{4.65->8.50}诡异的极光让整个半球陷入黑暗。", + "{0.02->1.62}SOS!": "{0.02->1.62}帮帮我!", + "{0.01->2.93}Democracy Above! They're here!": "{0.01->2.93}民主在上!它们来了!", + "{0.02->2.12}Freedom never falters!": "{0.02->2.12}自由永不退缩!", + "{0.00->1.21}Mission aborted.": "{0.00->1.21}任务已中止。", + "{0.03->1.08}Get away from me!": "{0.03->1.37}不要靠近我!", + "{0.00->1.06}Once we make it out of this, {1.43->3.95}I'm gonna donate the rest of my salary to the war effort.": "{0.00->1.06}等我们都安全了,{1.43->3.95}我就把所有的工资都捐给我们的部队。", + "{0.00->0.77}I need ammo.": "{0.00->0.77}需要弹药。", + "{0.00->3.11}Visibility improving—avoid being an easy target.": "{0.00->3.11}能见度提高,别变成活靶子了。", + "{0.00->0.87}Bot outpost.": "{0.00->0.87}机器人哨站。", + "{0.00->2.44}Should've stayed out of our city, scum.": "{0.09->2.16}这是你来的地儿吗?乡巴佬!", + "{0.00->1.87}Deploying SOS beacon.": "{0.00->1.87}正在部署SOS信标。", + "{0.00->0.88}For peace!": "{0.00->0.88}为了和平!", + "{0.03->2.25}Just stim me, I'm good to go!": "{0.00->2.38}给我一针,我还能打!", + "{0.03->1.56}Performing assisted reload!": "{0.03->1.56}正在协助武器换弹!", + "{0.00->0.54}Contact!": "{0.00->0.54}上啊!", + "{0.00->2.21}I heard the chow hall got a shipment of Purples in today.": "{0.00->2.21}听说今天食堂到了一批紫色的货。", + "{0.06->5.99}Still, the Illuminate intentions remain as dark to us as the Void itself. {6.33->11.95}Perhaps they seek to plunge the entire galaxy into this impenetrable Void.": "{0.06->5.99}尽管如此,光能者的意图对我们来说仍如同寂域一般黑暗。{6.33->11.95}也许它们想要让整个银河系都陷入无法穿透的寂域。", + "{0.01->2.75}Super Earth will avenge you, friend.": "{0.01->3.14}超级地球会为你复仇。", + "{0.46->0.65}Get it away from me!": "{0.00->1.67}快帮我把它弄走!", + "{0.04->2.05}Freedom guides our aim!": "{0.00->2.15}自由指引准星!", + "{0.03->4.90}Most everyone I know back home thinks the Void is the scariest thing imaginable.{4.90->7.92}They would die of fright before they went inside.{7.92->12.98}But it takes a little more than a big space bubble to scare us, huh Helldiver? Yep.{12.98->14.66}I'm not scared. Not one bit.": "{0.00->3.23}我在老家的朋友都认为寂域是最恐怖的东西。{3.75->6.04}还没被吞噬,肯定先吓死了。{6.34->8.95}但要吓倒咱们,巨型太空泡泡算老几,{9.06->11.16}绝地潜兵,你说对吧?{11.32->14.32}对。我才不怕。谁怕啊。", + "{0.00->2.95}Whoever could kill the most bugs by the end of recess won.": "{0.00->3.06}到课间休息结束的时候,杀得最多的人获胜。", + "{0.00->2.16}You are a paragon of Liberty.": "{0.00->2.16}你是解放的最佳楷模。", + "{0.00->1.21}The Veil system": "{0.00->1.21}帷幕星系", + "{0.00->1.10}To the skies.": "{0.00->1.10}飞起来。", + "{0.04->3.37}Maintain position and fire. They'll come to us.": "{0.00->2.28}稳住站位,持续开火。{2.29->3.42}它们会过来的。", + "{0.09->3.54}Wow. You really are a tactical genius.": "{0.00->1.44}哇。{1.44->3.68}你真是一个战术天才。", + "{0.02->1.49}Gotta patch up this leg.": "{0.02->1.49}这条腿得处理下。", + "{0.00->2.44}We lost many good Helldivers today.": "{0.00->2.96}今天我们失去了很多优秀的绝地潜兵。", + "{0.01->1.00}Run!": "{0.01->1.00}快跑!", + "{0.00->2.93}As the chain does not scrutinize the brevity of its links, {3.36->7.06}neither does Liberty mourn the transcience of a Helldiver's service.": "{0.00->2.35}链条不会在意每一个环节的完美,{2.82->6.57}解放也不会为绝地潜兵的牺牲而放慢脚步。", + "{0.00->1.21}Reloading support weapon.": "{0.00->1.21}在给支援武器换弹。", + "{0.02->2.11}Flag-forsaken robots!": "{0.02->2.45}一堆破铜烂铁!", + "{0.00->0.66}Critical item.": "{0.00->0.66}关键物品,", + "{0.00->0.46}Charlie": "{0.00->0.55}C", + "{0.01->1.21}Give 'em everything you got!": "{0.01->1.10}不要手下留情!", + "{0.02->1.90}Strike inbound. Clear out.": "{0.00->1.97}打击要来了。快撤。", + "{0.00->3.33}Pelican 1 awaiting Helldivers. Please enter the extraction radius.": "{0.00->3.33}“鹈鹕”1号正在等待绝地潜兵。请进入撤离区。", + "{1.50->2.95}Wow uh, thank you for holding back.": "{0.06->0.55}哇呃,{0.91->2.33}谢谢你手下留情。", + "{0.00->0.88}Area secured.": "{0.00->1.08}区域已控制。", + "{0.00->0.63}I'm out!": "{0.00->0.63}打光了!", + "{0.02->0.85}50 meters.": "{0.02->0.80}50米。", + "{0.07->2.74}I need a medic...": "{0.00->3.40}我需要医疗兵…", + "{0.01->1.86}Where are those reinforcements?": "{0.01->1.42}我们援军在哪儿?", + "{0.03->0.98}Exiting cover!": "{0.00->1.00}离开掩体!", + "{0.00->1.10}I need a team reload.": "{0.00->1.10}给我来点弹药。", + "{0.07->0.64}Help, help me!": "{0.00->2.08}救命,救救我!", + "{0.01->2.49}Blast 'em back where they came from! Woo!": "{0.08->2.82}把它们轰回老家去!哇哦!", + "{0.00->0.95}Orbital incoming.": "{0.00->0.95}轨道攻击来了。", + "{0.00->1.57}Calling down fortifications.": "{0.00->1.57}请求部署防御工事。", + "{0.00->2.37}A small price to pay for Freedom!": "{0.00->2.37}为了自由,这点代价算什么!", + "{0.04->0.51}3!": "{0.04->0.51}三!", + "{0.00->0.49}Ok!": "{0.00->0.49}好的!", + "{0.00->1.79}Calling in an orbital strike.": "{0.00->1.73}请求轨道攻击支援。", + "{0.06->1.65}The Enuliale system": "{0.06->1.65}安努力亚星系", + "{0.00->2.06}Good riddance, malware breath!": "{0.00->2.06}病毒走好不送!", + "{0.02->1.70}Get back, you filthy squids!": "{0.02->1.50}恶心的鱿鱼,滚开!", + "{0.03->1.84}Bring it on, Fascists!": "{0.00->1.91}来啊,法西斯怪物!", + "{0.00->0.78}On my position.": "{0.00->0.66}在我这里。", + "{0.01->0.77}Bugs.": "{0.01->0.77}虫族。", + "{0.02->1.25}Cover, cover!": "{0.00->1.39}隐蔽,隐蔽!", + "{0.04->1.63}Freedom save me!": "{0.04->1.63}自由保佑我 !", + "{0.01->0.95}Need fresh I.C.E.": "{0.01->0.95}换下冷却元件。", + "{0.00->1.19}I need a team reload.": "{0.00->0.84}帮我换弹。", + "{0.00->2.80}Rout these fascists from their caves.": "{0.00->2.80}把这些法西斯分子赶出藏身洞。", + "{0.00->1.88}Never doubt!": "{0.00->1.88}忠诚!", + "{0.03->3.31}I'm sorry! I'm sorry!": "{0.00->3.31}抱歉!我真的很抱歉!", + "{0.00->0.73}Hurry, fan{1.26->2.42}out, let's go!": "{0.00->2.49}快点,散开,我们走!", + "{0.00->0.48}Got one.": "{0.00->0.48}到手了。", + "{0.00->0.84}Sixth one.": "{0.00->0.84}第六个。", + "{0.01->1.11}Don't let them see you.": "{0.01->0.92}别被它们看到。", + "{0.03->1.96}Dispense that Freedom!": "{0.00->1.98}彻底释放自由吧!", + "{0.03->1.12}What are those things?": "{0.03->1.12}那都啥玩意儿啊?", + "{0.02->0.65}Get down!": "{0.02->0.65}快趴下!", + "{0.01->1.51}The socialists are here!": "{0.63->1.64}铁皮军来了!", + "{0.01->0.96}More aliens!": "{0.01->0.96}异形又来了!", + "{0.02->0.94}Squids!": "{0.02->0.94}鱿鱼!", + "{0.01->1.06}Eat this!": "{0.01->1.06}尝尝这个!", + "{0.00->6.31}When Cyberstan was invaded, we did not yet know the Cyborgs were behind the assault.{6.95->14.26}In an act of mercy, we activated a euthanasia protocol to spare them the pain of enslavement{14.38->16.23}underneath the Automatons.{16.86->19.20}But it would seem they endured;{19.64->23.95}we may never know the true extent of their treacheries against us.": "{0.00->2.23}生化斯坦遭到入侵时,{2.55->5.51}我们还不知道生化人是幕后黑手。{6.27->10.40}出于仁慈,我们启动了安乐死协议,{11.07->14.50}免得它们遭受机器人奴役的痛苦。{15.13->19.48}但它们似乎挺过来了;我们可能永远不知道{19.97->23.82}它们这次背叛的伤害有多深。", + "{0.03->0.71}Helldiver. {1.07->5.20}We have at last discovered the vile intentions of the Illuminate Cult.": "{0.03->1.16}绝地潜兵,{1.69->5.20}我们终于发现了光能者邪教的险恶用心。", + "{0.06->1.47}For Democracy!": "{0.00->1.46}为了民主!", + "{0.00->0.74}Looks secure.": "{0.00->1.04}看起来很安全。", + "{0.00->1.41}The bugs are a plague. {1.90->3.02}You are the vaccine.": "{0.00->1.41}虫族犹如瘟疫,{1.72->3.24}而你则是疫苗。", + "{0.00->1.60}Liberty save me!": "{0.00->1.60}解放拯救我!", + "{0.00->4.55}The Helldivers stood strong. This planet is ours once more.": "{0.00->2.40}绝地潜兵一步不退,{2.40->4.55}成功夺回了属于我们的星球。", + "{0.01->2.21}So smooth, wow...": "{0.00->2.29}好丝滑,哇哦。", + "{0.01->0.70}My legs!": "{0.01->0.70}我的腿!", + "{0.00->1.96}Each mission puts this crew at risk. {2.52->6.58}But everyone here would gladly give their lives to preserve Democracy.": "{0.00->3.48}每次执行任务,船员都要面临生命危险。{4.01->6.90}但所有人都愿意为保卫民主献出生命。", + "{0.00->2.86}Helldiver down!": "{0.00->2.86}绝地潜兵倒下了!", + "{0.02->6.68}The horrors of the Void delay their cleansing. We will return.": "{0.00->4.72}寂域中的恐怖存在让它得以苟延残喘。{5.18->6.81}我们会回来的。", + "{0.00->1.44}Fellow citizens!": "{0.00->0.97}公民同胞!", + "{0.00->0.67}Oh, I—thank you.": "{0.00->2.47}噢,谢谢你。", + "{0.00->1.08}Bot outpost.": "{0.00->1.08}机器人哨站。", + "{0.00->0.53}I'm out.": "{0.00->0.53}打光了。", + "{0.00->0.72}Got a sample.": "{0.00->0.96}样本到手了。", + "{0.03->2.11}Need stims!": "{0.67->2.22}给我来一针!", + "{0.07->1.53}The Ustotu system": "{0.07->1.53}伍斯特图星系", + "{0.00->2.05}The Helldivers came for us!": "{0.00->1.57}绝地潜兵来救我们了!", + "{0.03->1.54}That should go on a cape!": "{0.00->1.64}值得绣一面披风!", + "{0.19->1.11}Let 'em have it!": "{0.00->1.41}给我狠狠地干!", + "{0.00->1.50}No pain no Freedom.": "{0.00->1.50}痛苦铸造自由。", + "{0.02->2.51}Get some! GET SOOOOME!": "{0.02->2.51}给老娘死!给我死!", + "{0.03->3.22}I'd like to see the Illuminate try to control my brain. {4.02->5.30}They won't like what they find.": "{0.00->2.44}我倒是很乐意让光能者控制我的大脑,{2.87->6.29}但他们恐怕会对里面的内容感到颇为不适。", + "{0.00->0.45}Whups!": "{0.00->0.45}哎呀!", + "{0.00->0.50}Calling in reinforcements!": "{0.00->1.51}呼叫新的增援!", + "{0.04->1.47}Filthy bug.": "{0.04->1.47}卑鄙的虫子。", + "{0.00->2.40}Now that's what I call guns!": "{0.00->2.60}这才叫真家伙呢!", + "{0.00->0.51}North.": "{0.00->0.51}北边,", + "{0.00->1.86}You are a paragon of Liberty.": "{0.00->1.86}你是解放的最佳楷模。", + "{0.00->1.38}Weapons ready!": "{0.00->1.38}武器准备就绪!", + "{0.00->1.46}Objective near your position.": "{0.00->1.46}目标在你们附近。", + "{0.05->1.06}ETA T-{1.73->2.69}3 minutes.": "{0.05->1.06}预计3分{1.73->2.69}钟后到达。", + "{0.01->1.06}Reloading.": "{0.01->1.06}换弹。", + "{0.00->2.50}We will avenge this travesty.": "{0.00->2.50}我们必将如数奉还。", + "{0.07->4.65}Stay vigilant, Helldiver. Complacency plays right into the hands of dissidents.": "{0.07->1.82}绝地潜兵,保持警惕。{2.28->4.71}骄傲自满就会正中异见份子下怀。", + "{0.00->1.07}We're saved.": "{0.00->1.17}我们得救了。", + "{0.04->2.09}Shoot them! Shoot them!": "{0.04->2.09}快打它们!狠狠打!", + "{0.03->2.66}Fallb---Fall back!": "{0.00->2.78}撤退——撤退!", + "{0.00->0.86}Welcome back. {1.23->2.17}Well done.": "{0.00->0.86}欢迎回来。{1.23->2.17}干得漂亮。", + "{0.04->3.08}Look out! Can't support the cause if we're dead.": "{0.04->3.08}小心!死了就支持不了解放了!", + "{0.00->1.73}Oh no, bots!": "{0.00->1.73}天呐,机器人!", + "{0.00->2.45}Gh! I'm hit, I'm hit!": "{0.00->2.54}啊!我中弹了,我中弹了!", + "{0.00->1.07}Requesting orbital.": "{0.02->1.05}请求轨道攻击。", + "{0.00->0.59}Second one.": "{0.00->0.59}第二个。", + "{0.56->1.88}The Ostehovel System": "{0.09->1.61}酪撕特霍维星系", + "{0.00->1.51}I thought I was gonna die.": "{0.00->1.93}还以为我死定了。", + "{0.00->1.85}Calling down fortifications.": "{0.00->1.59}请求部署防御工事。", + "{0.01->0.87}Found something.": "{0.01->0.87}这边有发现。", + "{0.00->2.44}Look at this disgusting infestation. {2.89->5.25}Deploy to the planet and expunge it.": "{0.00->2.12}看看这令人作呕的虫群。{2.71->4.51}快去把它们消灭干净吧。", + "{0.00->7.22}Join me, Helldiver. We advance on Cyberstan: the mechano-fascist bastion of the Cyborgs.": "{0.00->1.69}绝地潜兵,加入前线。{2.06->7.27}我们正在向生化斯坦进军:那里是生化人的法西斯机械堡垒。", + "{0.00->1.52}Against all odds!": "{0.00->1.18}力挽狂澜!", + "{0.00->1.72}A lot of dead bots down there. {2.41->3.18}Good job.": "{0.00->1.52}消灭了很多机器人。{2.01->2.73}干得好。", + "{0.00->1.51}Requesting supplies.": "{0.00->1.51}请求投放补给。", + "{0.01->2.81}Managed Democracy will endure.": "{0.01->2.81}管理式民主永垂不朽。", + "{0.01->2.17}I'm in a bit of a pickle here!": "{0.00->2.30}情况棘手,遇到了一点麻烦!", + "{0.00->1.13}This will sort you out!": "{0.00->1.44}这就给你来一针!", + "{0.00->1.56}The Brilliance System": "{0.00->1.10}璨光星系", + "{0.00->1.00}Uh - um - me?{2.21->4.18}Hi. I mean - hello.": "{0.00->1.00}啊,你找我?{2.21->4.18}嗨。你好,绝地潜兵。", + "{0.01->3.00}Flags in rags, this is really happening.": "{0.00->2.92}插了个旗的,居然是真的。", + "{0.00->1.69}The Bohus System": "{0.00->1.24}布胡斯星系", + "{0.03->0.98}We're gonna die!": "{0.03->0.98}我们死定了!", + "{0.02->1.94}That's the Democratic spirit!": "{0.00->1.98}这就是真正的民主精神!", + "{0.03->1.23}I'm hit!": "{0.38->1.44}我中弹了!", + "{0.02->0.47}Uh...{0.81->1.80}is this a test?": "{0.02->0.76}呃…{0.87->1.99}这是测试吗?", + "{0.02->1.55}That was awesome!": "{0.02->1.55}太精彩了!", + "{0.00->0.47}Bots.": "{0.00->0.47}机器人,", + "{0.01->2.75}Mines! Someone's gonna get a leg blown off!": "{0.00->2.81}有雷!一颗下去腿都得炸废了!", + "{0.00->1.31}Calling down equipment.": "{0.00->1.31}呼叫装备。", + "{0.03->1.49}Mines! Stay alert!": "{0.00->1.55}有雷!保持警惕!", + "{0.00->0.67}I need stims!": "{0.00->1.34}快给我来一针!", + "{0.00->3.88}Remember, only YOU can prevent proto-spires.": "{0.00->4.47}切记,只有你才能阻止原始虫塔。", + "{0.00->2.56}Helldivers! Hey, clear the way, come on!": "{0.00->2.56}绝地潜兵!都让开!快点。", + "{0.00->1.87}Run, run for your vote!": "{0.00->2.65}快跑!留着命投票啊!", + "{0.03->1.43}Calling in an orbital strike.": "{0.03->1.43}请求轨道攻击支援。", + "{0.04->4.00}This mission required fewer heroes to make the ultimate sacrifice than normal.": "{0.04->4.00}在这次任务中牺牲的英雄数量比平常更少。", + "{0.00->1.18}Try not to fall!": "{0.00->1.25}尽量别摔倒!", + "{0.08->1.20}Fall back!": "{0.00->1.19}立即撤退!", + "{0.01->1.08}More aliens!": "{0.01->1.08}外星异形又来了!", + "{0.00->0.52}You win.": "{0.00->0.52}你赢了。", + "{0.00->2.40}Human remains disposal team to training area.": "{0.00->2.40}请人类遗体清理小队到训练区。", + "{0.02->1.73}Cover if you wanna live!": "{0.00->1.92}想活命就赶紧找掩体!", + "{0.00->3.34}It's how they would've wanted to go: fighting Tyranny.": "{0.00->3.34}为反抗暴政献身,也算死得其所。", + "{0.00->0.49}Walker.": "{0.00->0.49}步行机甲,", + "{0.04->2.48}Tactical reorientation! Let's go!": "{0.00->2.56}重新部署战术!先撤退!", + "{0.00->0.98}Don't stop! Rip 'em{1.81->2.95}up! Yeah!": "{0.00->2.01}不要停!撕烂它们!{2.32->3.14}爽!", + "{0.00->2.87}He said that Danny would have to prove he was special.": "{0.00->2.87}他说丹尼必须证明自己是特别的。", + "{0.01->2.13}Save yourselves, get outta here!": "{0.00->2.20}别浪费力气了,快离开这儿!", + "{0.02->1.95}Get back! Get back!": "{0.02->1.95}滚开!快滚开!", + "{0.47->2.65}They gave their life without hesitation.": "{0.13->2.65}他们毫不犹豫,献出了生命。", + "{0.00->0.51}Helldiver.": "{0.00->0.51}绝地潜兵。", + "{0.00->1.45}Unknown System": "{0.00->1.00}未知星系", + "{0.00->2.92}I'll recommend them for a Super Medal of Honor.": "{0.00->2.92}我会提议给他们颁发超级荣誉勋章的。", + "{0.02->1.27}We knew you'd save us.": "{0.02->1.51}就知道你们会来救我们。", + "{0.00->2.62}Allied Destroyer has left squadron.": "{0.00->2.62}友方驱逐舰已离开中队。", + "{0.00->0.90}Dirty tyrant!": "{0.00->1.04}卑鄙的暴政者!", + "{0.07->5.90}The Cyborgs just keep mass-reproducing, through those Megafactories that they're building everywhere.{5.90->8.52}Isn't it gross, how they multiply?{9.22->12.08}They're not even starting families, they're just producing more soldiers.": "{0.15->2.46}生化人到处建造超大型工厂,{2.91->5.83}然后通过这些工厂不间断地进行大量繁殖。{6.72->8.00}这样繁殖不恶心吗?{8.79->12.08}它们甚至不组建家庭,只是在生产更多战士。", + "{0.00->2.41}The Destroyer departs, Helldiver.{3.00->4.21}You're on your own.": "{0.00->2.55}绝地潜兵,驱逐舰已离开。{3.09->4.61}你只能靠自己了。", + "{0.03->1.68}For Super Earth!": "{0.00->1.71}为了超级地球!", + "{0.04->2.43}Please stim me, please!": "{0.00->2.56}求求你给我一针,求求你了!", + "{0.00->1.20}Calling in a Hellbomb.": "{0.00->1.20}呼叫地狱火炸弹。", + "{0.03->1.43}The Clasa system": "{0.03->1.43}克拉萨星系", + "{0.12->0.56}I'm{1.28->2.65}a hero...": "{0.00->1.04}我是…{1.38->3.50}超级英雄…", + "{0.01->1.69}The bunker's this way, right?": "{0.01->1.51}地堡是在这边吧?", + "{0.05->2.62}We're being suppressed!": "{0.84->2.74}敌人的火力太猛了!", + "{0.08->2.23}Please help! Please!": "{0.08->2.23}救命!救救我!", + "{0.00->1.49}Lots of friendly fire. {1.85->4.43}Unfortunate, but undoubtedly necessary.": "{0.00->1.24}误伤许多友军。{1.40->4.18}很不幸,但无疑很必要。", + "{0.02->2.39}Incoming. Choose your targets!": "{0.02->2.39}敌人来了!选择目标!", + "{0.01->0.89}It's them!": "{0.01->0.89}看见它们了!", + "{0.00->0.10}I'm on it.": "{0.00->0.10}我来。", + "{0.03->1.57}Robot scum!": "{0.03->1.57}铁皮渣滓!", + "{0.00->2.88}This is Pelican 1, I have visual on the extraction zone.": "{0.00->2.88}这里是“鹈鹕”1号。我已经看见撤离区。", + "{0.00->1.66}Artifact collected.": "{0.00->1.66}古物到手了。", + "{0.01->0.97}Bot outpost.": "{0.01->0.97}机器人哨站。", + "{0.00->1.62}Where will you take your stand?": "{0.00->1.62}你要从哪里着手?", + "{0.00->2.85}Let's go! Democracy ain't gonna deliver itself!": "{0.00->2.19}上吧!民主需要传播!", + "{0.02->0.91}More bugs!": "{0.02->0.91}还有虫族!", + "{0.03->0.86}The enemy!": "{0.03->0.86}有敌人!", + "{0.05->1.51}You gave it your all,{2.06->2.84}Helldiver.": "{0.05->1.51}绝地潜兵,{2.06->2.84}你尽力了。", + "{0.00->1.46}Manning emplacement!": "{0.00->1.75}我来操作炮位!", + "{0.09->2.19}The greatest order ever given.": "{0.09->2.19}这是今天最好的命令!", + "{0.03->2.23}Kill them! Kill them!": "{0.03->2.69}杀了它们!快杀了它们!", + "{0.07->3.12}And now, another helpful tip from General Brasch.{8.16->14.01}Utilize Super Earth's call-and-response tagging system to communicate with your squadmates! {14.45->15.19}Like this! {16.09->17.18}Look, ammo.{18.05->18.43}On it.{21.16->22.18}Look, enemy.{23.60->23.98}On it!{25.73->31.41}Because, if there's one thing I've learned, it's that there is no liberation without communication. {32.52->36.42}BRASCH TACTICS! Use 'em, or die trying.": "{0.07->3.47}布拉施将军又带来了一条实用提示。{8.16->13.60}灵活运用超级地球的呼叫与应答标记系统,及时跟队友沟通!{13.81->14.97}就像这样!{16.15->17.18}快看,弹药。{18.05->19.01}来了。{21.16->22.18}快看,敌人。{23.63->24.27}来了!{25.73->31.41}因为,我在战场上学到的一点就是,没有沟通就没有解放。{32.43->33.72}布拉施亲传战术!{34.16->36.78}竭尽全力,不死不休。", + "{0.01->5.43}It was my... patriotic p-privilege...": "{0.01->5.43}这是我的……爱国特权……", + "{0.03->2.04}Ready or not, here I come!": "{0.00->2.18}我已经等不及了!", + "{0.02->2.53}Thank Liberty, we needed reinforcements!": "{0.00->2.26}感谢解放,我们正需要支援!", + "{0.03->1.78}Need assistance!": "{0.00->1.80}请求援助!", + "{0.00->0.95}Inputting drop point.": "{0.00->0.95}确定降落地点。", + "{0.00->1.76}Warning! Warning!": "{0.00->1.76}警告!警告!", + "{0.06->8.20}Impeccable! Like I always say, the best simulation is a real simulation. Now, activate the {8.20->10.34}battlefield injury simulator!": "{0.06->6.30}无可挑剔!我一直都说,最好的模拟就是真实的模拟。{6.87->10.34}接下来,启动战场损伤模拟器。", + "{0.01->1.26}Is there a bunker around here?": "{0.01->1.14}这附近有地堡吗?", + "{0.00->2.77}Oh you should've stayed at home, Squid!": "{0.00->2.33}鱿鱼,后悔出门了吧!", + "{0.02->1.08}Take cover!": "{0.00->1.04}寻找掩护!", + "{0.01->2.23}They got me. Need a second!": "{0.01->2.40}我被打中了。给我点时间!", + "{0.01->1.60}Democracy binds us!": "{0.01->1.60}民主让我们团结一致!", + "{0.01->0.83}Thank you.": "{0.01->0.83}谢谢。", + "{0.00->1.09}Out of ammo!": "{0.00->1.09}没弹药了!", + "{0.00->3.40}I don't really want to know what those Cyborgs are up to in those Megafactories. {4.07->6.83}It's wrong. And it's icky.": "{0.11->3.40}我其实不想知道生化人在超大型工厂里搞什么名堂。{3.70->4.64}反正都是错误的。{5.28->6.75}而且很恶心。", + "{0.00->0.78}They're dead!": "{0.00->1.18}他们死了!", + "{0.00->2.92}Back when I was a kid, we'd play Bots and Helldivers every Summer.": "{0.00->2.92}小时候,我们每年夏天都会玩“机器人和绝地潜兵”。", + "{0.13->2.26}Heh, who's next?": "{0.13->2.26}嘿,下一个是谁?", + "{0.03->1.21}To the skies.": "{0.03->1.21}飞起来。", + "{0.00->1.97}Can't forget to check up on shuttle maintenance.": "{0.00->2.37}不能忘记检查运输船的维护情况。", + "{0.00->1.42}The Cygnia System": "{0.00->1.42}西格尼亚星系", + "{0.00->2.30}Honor their sacrifice. Fight on!": "{0.00->2.41}铭记他们的牺牲。战斗!", + "{0.00->2.02}The Void has the crew all jittery.{2.52->3.80}I've set them to extra duty.{4.28->6.94}It's like they say: busy hands, empty minds.": "{0.00->2.25}寂域搞得船员人心惶惶。{2.49->4.11}我让他们多多加班。{4.24->7.27}只要忙起来,就没空胡思乱想了。", + "{0.00->1.33}Maintain your resolve!": "{0.00->1.33}坚定决心!", + "{0.00->4.17}More brave heroes, lost to the abyss.": "{0.00->4.17}又一位勇敢的英雄葬身深渊。", + "{0.04->5.27}If Terminids didn't decompose into Element 710, we'd have eradicated them completely a long time {5.27->5.61}ago. {7.05->7.25}They should count themselves lucky.": "{0.00->2.46}要不是终结族能降解成710元素,{2.80->4.92}我们很早之前就能将它们彻底消灭了。{5.57->7.20}它们应当为此感到庆幸。", + "{1.18->1.55}Help! Help!": "{0.00->1.78}救命!救命!", + "{0.04->2.57}Pinned, I'm pinned!": "{0.00->2.77}我……我被压制了!", + "{0.00->2.16}Freedom requires firepower.": "{0.00->1.81}自由需要更多火力。", + "{0.00->0.44}You know, {0.81->4.85}the cost of one stratagem is more than most citizens make in a year. {5.41->7.80}You can see why they only entrust them to Helldivers.": "{0.00->4.28}一项战略配备的成本超过了大多数公民一年的收入。{4.85->7.80}所以只有绝地潜兵能调用。", + "{0.02->1.89}Kill them! Kill them!": "{0.00->2.36}杀了它们!快杀了它们!", + "{0.00->0.71}Tie.": "{0.00->0.71}平手。", + "{0.00->0.96}Falling back.": "{0.00->1.00}立即撤退!", + "{0.00->1.51}Establish a perimeter.": "{0.00->1.51}建立防线。", + "{2.30->5.34}Hahahaha -- ah, careful, don't get Cyborg DNA on the floor.": "{0.04->2.23}哈哈哈哈——啊,{2.53->5.73}小心点,别把生化人的DNA弄到地板上了。", + "{0.02->1.09}Into the breach!": "{0.00->1.24}一起向前冲!", + "{0.00->1.48}The Choepessa system": "{0.00->1.48}科埃佩萨星系", + "{0.03->5.91}Maybe we don't even need the TCS. You Helldivers seem to kill plenty of bugs just fine on your own.": "{0.03->5.91}说不定遏制系统根本用不上。好像各位绝地潜兵只靠自己就能干掉很多虫族。", + "{0.03->1.16}Covering from here!": "{0.00->1.15}我来掩护大家!", + "{0.13->2.97}It's gotta be real satisfyin', hearin' 'em crunch under your boot.": "{0.13->2.97}把它们踩扁的感觉肯定很爽。", + "{0.00->0.95}That was a close one.": "{0.00->0.95}有些惊险。", + "{0.02->1.88}Mind your step, Diver, demo time.": "{0.00->1.94}潜兵,当心,该爆破了。", + "{0.05->1.32}What is that?": "{0.05->1.32}那到底是什么?", + "{0.03->1.91}Get away from me, bug freak!": "{0.03->1.91}滚开!没脑子的东西!", + "{0.02->2.24}Helldiver! Nooooooooooo!": "{0.02->2.24}绝地潜兵!不!", + "{0.00->1.90}I hope it hurt.": "{0.00->1.90}这下够狠了吧。", + "{0.02->1.08}Advance!": "{0.00->1.30}往前推进!", + "{0.06->0.86}5!": "{0.06->0.86}五!", + "{0.00->3.73}Here at war, you may cast your vote many times. {4.19->5.69}Once on Election Day, {6.10->10.31}and another with every bullet buried in an enemy combatant.": "{0.00->3.60}在战争中,你可能要投很多次票。{4.27->6.96}一种选票用在选举日上,{7.23->10.80}另一种则是你向敌兵射出的子弹。", + "{0.02->3.13}FIRE IN THE HOLE! Die, Terrorists!": "{0.00->3.48}小心爆炸!垃圾玩意儿,去死吧!", + "{0.00->3.30}A draw against a Helldiver! Amazing!": "{0.00->2.38}居然和绝地潜兵打平了!{2.39->3.63}不可思议!", + "{0.00->1.29}Calling down a walker.": "{0.00->1.29}呼叫步行机甲。", + "{4.30->6.72}A good general knows when to retreat. So, I know High Command knows what they're doing.": "{1.85->4.14}睿智的将领一定进退有度。{4.79->7.46}所以我相信最高指挥部心里有数。", + "{0.00->1.20}Help me!": "{0.00->1.58}救救我!", + "{0.00->6.89}Early reports indicate the Megafactories contain crude simulacra of government districts and{7.06->8.38}cultural monuments.{8.89->15.64}Evidence of the dystopian rule the Cyborgs envision, should their conquest go unchallenged.": "{0.00->5.71}初步报告显示,超大型工厂内仿建了行政区和文化纪念碑,{5.90->7.81}但手法十分粗糙。{8.33->12.05}这印证了生化人构想的反乌托邦统治蓝图,{12.54->15.69}我们绝不能让它们的征服计划得逞。", + "{0.03->1.26}Watch your fire!": "{0.00->1.28}别打错人了!", + "{0.01->2.44}Yes! Push forward!": "{0.00->0.84}好!{0.84->2.44}前进!", + "{0.04->1.00}Eat lead!": "{0.00->1.02}吃枪子儿吧!", + "{0.01->3.25}Make way for Super Earth's finest!": "{0.60->2.54}给超级地球的精英让路!", + "{0.01->1.58}For Super Earth!": "{0.00->1.64}为了超级地球!", + "{0.00->2.74}I give every crew member a half day off on Liberty Day. {3.45->5.69}Some things are sacred, even on the front.": "{0.00->2.16}每位船员在解放日都有半天假。{2.52->6.31}即使身处前线,也不能怠慢如此神圣的日子。", + "{0.01->0.99}Watch yourself!": "{0.01->0.99}小心!", + "{0.17->4.30}It's like they're trying to turn the whole galaxy into one big socialist murder factory.": "{0.00->4.30}就好像想把整个银河系变成一座巨大的叛军工厂。", + "{0.02->8.36}Alert: Liberation of currently orbited planet from Illuminate menace has ended in absolute victory. {8.60->11.53}Planet now under Super Earth control.": "{0.02->7.13}通知:击退光能者威胁,解放当前星球的行动大获全胜。{7.22->11.53}该星球现在归超级地球统治。", + "{0.00->3.45}Whatever you find down in that Flag-forsaken murk,{3.86->5.02}exterminate it.": "{0.00->2.27}在自由照不到的黑暗中,{2.67->5.02}没有什么值得留恋。", + "{0.00->3.66}You put 'em on the bottom of your boot, and it was like you were squashin' bugs every time you took {3.66->3.95}a step.": "{0.00->1.21}把贴纸贴在鞋底,{1.43->4.05}你每走一步都像是把虫族踩在脚下。", + "{0.01->2.95}Say hello to Democracy.": "{0.01->2.95}民主驾到。", + "{0.00->2.64}Alcubierre drive calibration complete.": "{0.00->2.76}阿库别瑞引擎校准完毕。", + "{0.01->0.57}Move up!": "{0.00->0.67}前进!", + "{0.00->3.22}Uh, Democracy for everybody!": "{0.00->3.22}啊,人人民主!", + "{0.00->1.51}Calling in extraction!": "{0.00->1.77}呼叫撤离!呼叫撤离!", + "{0.01->1.14}Stay in your lane!": "{0.00->1.24}守好自己的防区!", + "{0.02->0.90}Duck and cover!": "{0.02->0.80}快躲起来!", + "{0.96->5.60}Again, please do not use orbital strikes in ways that cause excessive damage {5.79->7.24}to the training facility.": "{1.05->2.41}再次重复,{2.81->7.34}请不要用轨道攻击对训练设施造成不必要的损伤。", + "{0.00->4.15}The Helldivers have liberated this planet in the name of Democracy. {4.61->5.94}There is no more to be done here; {6.43->7.83}extraction awaits.": "{0.00->4.15}绝地潜兵已经以民主之名解放这颗星球。{4.61->5.94}此处的使命已完成,{6.43->7.83}可以开始撤离。", + "{0.01->1.66}Liberty watches over us!": "{0.00->1.66}解放护佑我们!", + "{0.00->3.41}The Illuminate Cult will pay for their transgressions.": "{0.00->3.41}光能者会为自己的罪行付出代价。", + "{0.02->1.85}OPEN FIIIRE!!!!": "{0.00->1.83}开火,开火!!!!", + "{0.00->0.85}Move it!": "{0.00->0.85}跑起来!", + "{0.00->3.45}This bio sample will directly increase our Freedom.": "{0.00->3.45}这份生物样本将会助力自由大业。", + "{0.00->3.67}Operation accomplished. Your valor is beyond question.": "{0.00->3.67}行动完成,你的勇气毋庸置疑。", + "{0.01->1.39}This isn't over.": "{0.01->1.39}你们死定了。", + "{1.50->2.95}This evens the odds.": "{1.50->2.95}这样就公平了。", + "{0.01->2.87}The squids are gonna eat our brains!": "{0.01->2.37}鱿鱼会吃掉我们的脑子!", + "{0.01->1.14}Danger close!": "{0.01->1.14}危险距离!", + "{0.00->1.48}Liberty watch over me...": "{0.00->1.58}解放护佑我……", + "{0.00->4.92}Our forces fight to free this planet from the mechanical grip of the Automatons. {5.50->9.40}A litany of elite operations await your initiation.": "{0.00->5.41}我方部队正在争取击碎机器人的冰冷铁拳,解放这颗星球。{5.97->9.40}你可以开展一连串的精英行动。", + "{0.01->2.01}Peacekeeping at its finest!": "{0.01->1.55}这才叫维护和平!", + "{0.26->1.07}I love you...{1.70->2.82}Super Earth...": "{0.04->1.69}我爱你…{2.35->4.36}超级地球…", + "{0.00->1.52}Administering Freedom.": "{0.00->1.52}伸张自由。", + "{0.03->2.16}Doing our citizens proud!": "{0.00->2.23}成为公民的骄傲!", + "{0.00->1.52}Eagle, back from the nest.": "{0.00->1.52}“飞鹰”重返战场。", + "{0.00->2.43}Extraction complete. Pelican 1 beginning ascent.": "{0.00->2.43}撤离完毕。“鹈鹕”1号开始升空。", + "{0.00->2.22}For Managed Democracy!": "{0.00->2.24}为了管理式民主!", + "{0.00->1.07}How much longer?": "{0.00->1.07}还得等多久?", + "{0.00->0.97}Thanks to them,{1.35->5.59}a free dawn will soon rise upon Cyberstan once more.": "{0.00->1.11}多亏了他们,{1.35->6.00}自由的曙光很快就会再次照耀生化斯坦。", + "{0.01->0.95}Eat this!": "{0.01->0.95}尝尝这个!", + "{0.02->1.94}Tear 'em apart, Helldiver!": "{0.00->2.21}绝地潜兵,撕碎它们!", + "{0.00->2.60}Liberty's enemies march ever closer.": "{0.00->2.60}解放的敌人正在逼近。", + "{0.06->0.50}Hail!": "{0.06->0.50}万岁!", + "{0.07->2.09}Aw, you knew I needed that.": "{0.49->2.63}你知道我正需要这个。", + "{0.03->1.04}You saved us!": "{0.03->1.04}多亏了你们!", + "{0.05->3.13}Show these hostiles some hospitality!": "{0.00->3.18}让敌人尝尝我们的热情!", + "{0.00->3.34}A planet cries out for succor. We must help.": "{0.00->3.61}有一颗星球正在呼救,我们必须伸出援手。", + "{0.02->2.79}Go back where you belong, filthy aliens!": "{0.02->2.79}外星人,哪儿来的回哪儿去!", + "{0.00->1.32}Tac-pack inbound.": "{0.00->1.32}战术背包来了。", + "{0.03->0.60}Bugs!": "{0.03->0.60}虫族!", + "{0.01->1.95}Swapping Internal Cooling Element.": "{0.01->1.62}更换内部冷却元件。", + "{0.00->5.92}Criticism of Super Earth's ideals are a telltale sign of Illuminate mind control. {6.42->11.26}Help critics by turning them over to your local Science Officer for reeducation.": "{0.00->2.69}如果有人批评超级地球的理念,{3.18->6.00}说明其意识已经被光能者控制。{6.42->11.48}请将这些批评者移交给当地的科学官,接受二次教育。", + "{0.00->2.73}Recruit expired. Request Hellpod sanitation crew.": "{0.00->2.74}新兵死亡。呼叫绝地喷射舱卫生组。", + "{0.03->1.37}Shoot them! Shoot them!": "{0.03->1.37}快打它们!快打呀!", + "{0.07->2.23}Close your eyes.{2.23->10.37}See yourself standing before a great nebula of Terminid spores.{10.37->18.13}Clench your fist. Send your fist into that tyrannical cloud.{18.13->25.76}Hear the enemy scream. Watch as they suffer. You are whole.": "{0.00->1.66}闭上眼睛。{2.56->8.75}想象自己站在巨大的终结族孢子星云前。{9.54->16.55}握紧拳头。挥向那片象征暴政的云团。{17.37->23.31}享受敌人的尖叫声。见证它们受苦。{23.98->25.89}你变得完整。", + "{0.04->2.81}Gh! I'm hit, I'm hit!": "{0.00->2.98}啊!我中弹了,我中弹了!", + "{0.00->1.36}Establish security.": "{0.00->1.03}确保安全。", + "{0.00->2.38}They will sing ballads of your deeds.": "{0.00->2.38}你的事迹值得歌颂。", + "{0.00->2.19}Freedom requires firepower.": "{0.00->2.19}自由需要更多火力。", + "{0.00->2.93}Your fellow Helldivers rage against the enemy's tyranny. {3.74->4.37}Join them.": "{0.00->2.44}你的战友们正在抗击敌人的暴政,{3.02->4.41}快去并肩作战吧!", + "{0.04->2.20}Cut them down! All of 'em!": "{0.00->2.27}干翻它们!一个不留!", + "{0.00->1.21}I'm on the gun!": "{0.00->1.31}机枪手就位!", + "{0.31->2.09}Good game, Diver, good game.": "{0.00->2.27}干得漂亮,潜兵,干得漂亮。", + "{0.00->2.14}You have served Democracy well. {2.52->3.87}Extraction awaits.": "{0.00->2.14}你为民主效忠的精神值得赞赏。{2.52->3.87}可以撤离了。", + "{0.00->0.45}No!": "{0.00->0.45}不行!", + "{0.00->3.22}Recruit expired. Send in human remains disposal team.": "{0.00->3.39}新兵死亡。请派出人类遗体清理小队。", + "{0.01->2.88}Should've stayed at home, Squid!": "{0.01->2.49}鱿鱼,后悔出门了吧!", + "{0.00->3.58}Well done down there. The Gloom will be gone in no time.": "{0.00->3.58}干得漂亮。“阴霾”很快就会消散。", + "{0.00->2.70}Super Earth will reap what you sow.": "{0.00->3.02}超级地球会收获你播下的种子。", + "{0.04->1.47}For Super Earth!": "{0.00->1.49}为了超级地球!", + "{0.00->0.95}We got your back!": "{0.00->0.97}背后有我们!", + "{0.03->1.51}I'll remember this forever.": "{0.03->1.63}我会永远记住你们的。", + "{0.00->2.36}This bio sample will directly increase our Freedom.": "{0.00->2.36}这份生物样本将会助力自由大业。", + "{0.01->3.34}Our resolve cannot falter. Engage!": "{0.00->2.44}我们的决心绝不动摇。{2.45->3.43}开打!", + "{0.00->1.43}Requesting equipment!": "{0.00->1.43}请求装备支援!", + "{0.00->1.76}The Raysting System": "{0.00->1.17}雷斯汀星系", + "{0.03->2.26}Sweet Liberty, fall back!": "{0.00->2.29}他民主的,快撤退!", + "{0.00->0.73}ETA T-{1.31->2.64}1 minute and 30 seconds.": "{0.00->1.98}预计1分30秒后到达。", + "{0.00->1.28}Brainless bot.": "{0.00->1.54}没脑子的机器。", + "{0.00->0.56}I'm on it.": "{0.00->0.56}我来处理。", + "{0.00->1.59}The Probability System": "{0.00->1.10}天机星系", + "{0.00->0.83}Reloading.": "{0.00->0.83}正在换弹。", + "{0.00->2.53}Our planetary defense has failed. {3.04->6.88}Now we must prevent the enemy's further encroachment upon this world.": "{0.00->1.95}行星防御失效了。{2.32->6.88}现在,我们要挺身而出,阻止敌人进一步侵占这个世界。", + "{0.04->5.41}Within the dead bugs you leave behind, lie the secrets of their brethren's annihilation.": "{0.04->5.41}在你留下的虫族残骸中,潜藏着覆灭整个虫族的秘密。", + "{0.00->1.95}Liberty tells you to fight on!": "{0.00->1.97}解放需要你坚持下去!", + "{0.00->0.94}I need supplies.": "{0.00->0.94}给我来点补给。", + "{0.00->1.25}Try not to fall!": "{0.00->1.34}尽量别摔倒!", + "{0.09->4.70}The Voteless would have been subjected to endless anti-Democratic propaganda. {5.19->10.76}The resulting mental distress likely led to the total destruction of their minds.": "{0.09->3.78}无票者原本会遭受无休止的反民主宣传。{4.25->10.76}由此产生的精神痛苦很可能导致他们心智走向彻底毁灭。", + "{0.01->0.78}Let's go!": "{0.01->0.78}上吧!", + "{0.00->0.84}Dropping item!": "{0.00->0.84}放下物品!", + "{0.01->2.63}No-one takes MY Freedom!": "{0.00->3.40}谁也别想夺走我的自由!", + "{0.00->0.65}Aerial enemy.": "{0.00->0.65}空中敌人,", + "{0.01->0.61}Affirmative.": "{0.01->0.61}好的收到。", + "{0.00->0.57}No!": "{0.00->0.57}没办法!", + "{0.34->2.09}They escaped the farms.{2.72->5.93}They murdered good citizens of Super Earth.{6.56->9.17}Now, they're coming for you.{10.06->12.06}The only thing that can stop them? {14.90->16.97}A strong economy!{18.63->20.81}Don't let your family get murdered—{21.23->23.20}spend your extra cash today!": "{0.34->2.09}它们逃离了农场。{2.72->6.55}它们杀害了超级地球的优秀公民。{6.56->9.51}现在,它们盯上了你。{10.13->12.88}唯一能阻止它们的是什么?{15.08->16.95}是强劲的经济!{18.69->23.48}不要让它们杀害你的家人——立刻花光你的闲钱!", + "{0.00->4.16}There is but one sentence commensurate to the crime of treason.": "{0.00->4.16}叛国之罪只有一种相称的刑罚。", + "{0.00->0.82}You're here!": "{0.00->0.82}你们来了!", + "{0.00->0.70}Third one.": "{0.00->0.70}第三个。", + "{0.00->1.03}As you command.": "{0.00->0.73}遵命。", + "{0.02->3.33}Go back where you belong, filthy aliens!": "{0.02->2.99}恶心的外星人,滚回去!", + "{0.00->1.29}The Shallus system": "{0.00->1.29}沙勒斯星系", + "{0.01->1.26}Show 'em how we do it!": "{0.00->1.25}给它们露一手!", + "{0.03->1.17}Thanks, Helldiver!": "{0.00->1.24}谢谢你,潜兵!", + "{0.00->1.60}Have a taste of Democracy!": "{0.00->1.60}尝尝民主的滋味儿!", + "{0.00->1.35}For Liberty's sake, shoot them!": "{0.00->1.87}为了解放,打死它们!", + "{0.08->5.09}The Gloom has altered the very air of the worlds caught in its haze. {5.67->13.09}Once-familiar worlds are now foreign lands, nesting grounds for skittering new monstrosities.": "{0.08->5.09}在“阴霾”笼罩之下,空气已经彻底改变。{5.67->13.09}曾经熟悉的世界如今沦为异域,盘踞着各种新怪物。", + "{0.00->3.98}I don't know how you do it, Helldiver. Facing off against monsters who haven't got a democratic {3.98->4.86}bone in their body.": "{0.00->2.40}绝地潜兵,我不知道你是怎样做到的,{2.60->5.48}居然能对抗无数个骨子里毫无民主的怪物。", + "{0.01->1.69}They got what they deserved.": "{0.01->1.69}真是罪有应得!", + "{0.00->2.79}The people of Super Earth look to us for hope. {3.40->4.55}And we will deliver it—{4.98->7.66}one enemy corpse at a time.": "{0.00->2.69}超级地球的人民期待我们带来希望,{2.84->4.54}而我们也会不负众望,{4.98->7.66}每次都要带回去一具敌人的尸首。", + "{0.00->1.90}That's what you deserve!": "{0.00->1.79}这就是你们的报应!", + "{0.00->1.89}Crystallized E-710 acquired.": "{0.00->1.89}710元素晶体到手了。", + "{0.55->1.67}Dirty squid.": "{0.83->1.91}恶心的鱿鱼。", + "{0.01->1.31}We gotta get out of here!": "{0.01->1.31}我们得离开这儿!", + "{0.00->6.13}Their sacrifice brought us one step closer to ending this Illuminate chicanery.": "{0.00->1.82}他们的牺牲,{1.83->6.29}让我们向终结光能者阴谋又迈进了一步。", + "{0.00->3.76}Choose an operation, and free this world from tyranny.": "{0.00->3.76}选择一项行动,然后挫败暴政,解放这颗星球。", + "{0.00->1.52}Super Uranium acquired.": "{0.00->1.52}超铀到手了。", + "{0.00->0.54}Nevermind.": "{0.00->0.54}算了。", + "{0.00->0.95}I need to reload.": "{0.00->0.95}需要换弹。", + "{0.28->2.32}Ahem. As a... uh, {2.81->4.11}supplementary note, {4.60->9.42}try firing in short, controlled bursts to improve your accuracy. {9.94->10.61}Uh, thank you.": "{0.00->0.90}咳咳(清嗓子)。{0.94->3.84}呃,让我来补充一句,{3.90->9.44}请你多多尝试短点射,这样才会提高命中率。{9.50->10.62}呃,谢谢。", + "{0.00->5.70}The Illuminate think they're safe inside their void, just because we can't enter it, see into it,{5.72->7.74}or measure it in any way.{8.20->9.39}We'll show them though.": "{0.00->2.28}光能者以为躲在寂域里就安全了,{2.51->7.52}就因为我们无法进入寂域,也没法观察或以任何方式测量。{8.09->9.56}我们要给它们上一课。", + "{0.00->0.84}Tactical benefit.": "{0.00->0.84}战术助力,", + "{0.00->0.53}That one.": "{0.00->0.53}那个。", + "{0.03->1.50}Augh, get it off!": "{0.00->1.82}啊,快把它搞走!", + "{0.00->1.20}That's for the Creek.": "{0.00->1.38}这是为麦河报仇。", + "{0.00->3.54}SWEET MOTHER OF FREEDOM! DID YOU SEE THAT?!": "{0.00->3.15}自由保佑!你看到了吗?!", + "{0.00->0.60}Helldiver. {1.01->2.20}We're counting on you.": "{0.00->0.60}绝地潜兵,{1.01->2.20}我们就靠你了。", + "{0.02->1.81}Kill them! Kill them all!": "{0.02->2.13}杀了它们!统统杀光!", + "{0.00->2.66}Liberty smiles upon your triumph.": "{0.00->2.66}自由为你喝彩。", + "{0.06->3.78}Wow uh, thank you for holding back.": "{0.00->1.64}哇,{1.64->4.07}谢谢你手下留情。", + "{0.01->2.18}You're here to save us, I know it!": "{0.01->2.18}我就知道,你是来救我们的!", + "{0.00->2.37}Our enemies can fight as hard as they like, {2.79->3.45}but Freedom {3.99->4.95}always wins.": "{0.00->1.82}无论敌人有多么顽固,{2.40->5.14}自由终将战胜一切。", + "{0.00->2.14}Time to die, enemies of Freedom!": "{0.00->2.26}自由之敌,受死!", + "{0.02->1.42}Rare sample acquired.": "{0.02->1.42}稀有样本到手了。", + "{0.00->0.62}YES!{0.99->1.38}I mean,{1.91->2.44}roger that.": "{0.00->0.62}遵命!{0.99->1.38}我是说,{1.91->2.44}收到。", + "{0.00->3.64}Soon as those Flag-forsakin' freaks are in range...": "{0.00->3.64}等那些没旗子的废物进入射程…", + "{0.01->1.09}Might be safer here!": "{0.01->1.09}这里更安全!", + "{0.00->1.11}If they even have bones.": "{0.00->1.11}可能连骨子都没有。", + "{0.03->1.11}Watch for mines!": "{0.00->1.11}小心地雷!", + "{0.66->2.39}And STAY offline!": "{0.66->2.39}强制关机!", + "{0.00->1.48}Calling down a sentry.": "{0.00->1.48}呼叫哨戒炮。", + "{0.00->1.33}The Merak system": "{0.00->1.33}北斗二星系", + "{0.00->4.19}Once we make it out of this, I'm gonna donate the rest of my salary to the war effort.": "{0.00->4.19}等我们都安全了,我就把所有的工资都捐给我们的部队。", + "{0.00->0.84}My arm!": "{0.00->1.15}我的胳膊!", + "{0.02->1.01}The bugs are back!": "{0.02->1.01}虫族回来了!", + "{0.00->2.62}We near operational completion.": "{0.00->2.62}行动胜利近在眼前。", + "{0.00->1.78}This'll all blow over soon enough.": "{0.00->1.19}要不了多久的。", + "{0.01->0.98}Tactical impediment.": "{0.01->0.98}战术障碍,", + "{0.00->2.89}Our achievements do not go unrecognized.": "{0.00->2.89}正所谓有功必有赏。", + "{0.00->0.93}This is for you!": "{0.00->0.93}拿着这个!", + "{0.00->1.25}Calling down a vehicle.": "{0.00->1.25}请求载具支援。", + "{0.00->3.01}Fallen foes -- Freedom's fuel.": "{0.00->3.01}让自由烧的更旺些。", + "{0.03->1.56}The Arability System": "{0.03->1.07}沃壤星系", + "{0.01->1.08}Is that all they got!?": "{0.01->1.34}它们就这点本事!?", + "{0.00->2.53}Somehow, I knew you were going to win.": "{0.00->2.54}我隐隐约约就觉得你会赢。", + "{1.09->2.85}That's how you get it done!": "{1.20->2.52}这就是实力!", + "{0.00->0.70}Freedom five!": "{0.00->0.70}自由击掌!", + "{0.00->2.93}Our enemies strike deeper towards Liberty's heart. {3.39->5.32}We must stop them.": "{0.00->3.32}敌人朝着解放的腹地发起了深入的进攻。{3.95->5.48}我们必须阻止它们。", + "{0.02->0.74}Take cover!": "{0.00->0.72}找掩护!", + "{0.00->1.61}Are you sure it's safe here?": "{0.00->1.61}这里确定安全吗?", + "{0.00->1.73}We knew you'd save us.": "{0.00->1.73}就知道你们会来救我们。", + "{0.00->7.14}We shall fight in the streets. We shall fight on the sidewalks. We shall fight in the intersections!": "{0.00->7.14}我们将在街头战斗。我们将在人行道上战斗。我们将在十字路口战斗!", + "{0.05->1.26}Help! HELP!!!": "{0.00->1.40}救命!救命!!", + "{0.00->1.31}Eagle 1, armed and ready.": "{0.00->1.31}“飞鹰”1号随时待命。", + "{0.00->4.94}Destroy the Megafactory. Leave naught but craters.": "{0.00->4.95}摧毁超大型工厂。除了弹坑,什么都不要留下。", + "{0.00->3.95}Everyone was collectin' 'em, tryin' to get the rare ones. Man, those things were cool.": "{0.00->2.62}当时大家都在收集,都想要稀有款。{3.20->4.21}还挺怀念的。", + "{0.00->2.69}The Illuminate terrorists reap what they sow.": "{0.00->2.69}光能者恐怖分子自食恶果。", + "{0.00->1.22}Objective complete.": "{0.00->1.22}目标达成。", + "{0.10->1.52}They might take our lives,{1.93->4.57}but they'll never take our values.": "{0.10->2.01}生命诚可贵,{2.65->4.57}自由价更高。", + "{0.00->1.37}I'll handle the terminal.": "{0.00->1.13}这个终端交给我。", + "{0.00->0.39}Seven.": "{0.00->0.42}拐。", + "{0.00->1.07}I've got the package.": "{0.00->1.07}物品到手了。", + "{0.04->1.40}The Achird system": "{0.04->1.40}王良三星系", + "{0.05->1.45}Make it stop!": "{0.05->1.45}快救救我!", + "{0.01->0.83}Dismount!": "{0.00->0.89}下来了!", + "{0.00->1.79}I won't forget this, Helldiver.": "{0.00->1.79}我不会忘记的,绝地潜兵。", + "{0.07->3.27}And now, another helpful tip from General Brasch.{5.98->13.50}Ah, the simple joy of unloading round after round into the bodies of your enemies. {13.64->16.18}Oh, yeah. That's good...{16.68->19.10}But if you get carried away...{19.97->22.17}your shootin' days are over! {25.17->30.00}Elite soldiers adjust their fire mode, so they can keep the killin'{30.03->31.75}goin' all day long. {34.52->35.58}Oh yeah,{36.39->38.03}that's good. {39.99->43.81}BRASCH TACTICS! Use 'em, or die trying.": "{0.07->3.27}布拉施将军又带来了一条实用提示。{5.98->10.97}啊,不断射中敌人是一种单纯的快乐。{13.64->16.74}耶,实在是太爽了…{17.32->22.11}但是,如果你得意忘形…那就没有机会开枪了!{25.32->28.76}精英士兵懂得调整合适的射击模式,{29.13->31.20}才能不停地战斗下去。{34.64->36.48}啊,很好。{39.92->41.35}布拉施亲传战术!{41.82->44.09}竭尽全力,不死不休。", + "{0.00->1.67}The Urectem System": "{0.00->1.67}乌雷克特姆星系", + "{0.00->1.01}Let's move!": "{0.00->0.66}走吧!", + "{0.00->1.15}Here we go again...": "{0.00->1.93}老娘我回来了……", + "{0.00->0.36}One.": "{0.00->0.35}幺。", + "{0.15->1.45}Step carefully!": "{0.00->1.57}小心,注意脚下!", + "{0.00->3.17}I like it, cuz you can always visualize where you'd be standing on Super Earth if you went straight {3.17->3.36}there.": "{0.00->3.69}这很棒,因为直接能看到舰船笔直返回超级地球后的具体位置。", + "{0.00->4.77}Danny listened to every word, and he got to meet more strangers, and listened to their secrets, too.": "{0.00->4.77}丹尼全神贯注地听完了。他还见到了更多的陌生人,也听完了这些人的秘密。", + "{0.21->1.63}I'm never taking this stim out.": "{0.00->1.82}这一针,扎了就不想拔了。", + "{0.00->5.51}The Ministry of Expansion Exploitation Committee will carry on their legacy.": "{0.00->5.51}超级地球扩张部开发委员会将继承他们的遗志。", + "{0.09->5.59}Cyborgs... I can't believe they used to be real people, real citizens. And{6.19->8.29}they survived all this time... what,{8.62->12.30}sustained only by oil, and hatred for the electoral process.": "{0.10->1.05}生化人……{1.97->4.43}真不敢相信它们曾经是活生生的人,{4.88->6.53}真正的公民。{7.28->8.62}它们居然撑了这么久……{9.02->12.14}靠什么,就靠机油和对选举制度的仇恨?", + "{0.03->0.86}Steering clear.": "{0.03->0.86}绕开这里。", + "{0.01->0.62}Get in!": "{0.00->0.44}上来!", + "{9.03->11.00}Super Earth. {11.00->12.65}Our home. {13.17->14.84}Prosperity. {15.78->17.30}Liberty. {19.66->21.94}Democracy. {21.94->24.20}Our way of life. {28.46->31.39}But freedom doesn't come free. {32.27->33.08}No… {33.20->34.76}sweet Liberty… {35.11->36.41}NOOOO! {38.43->41.49}(laughs) Look familiar? {41.93->46.28}Scenes like these are happening all over the galaxy, right now! {46.28->49.18}You could be next. {49.18->54.27}That is unless you make the most important decision of your life. {55.29->61.66}Prove to yourself that you have the strength and the courage to be free.{61.66->65.42} Join... the Helldivers. {65.42->68.63}Become part of an elite peacekeeping force! {72.90->75.51}See exotic new lifeforms.{79.54->84.26}And spread Managed Democracy throughout the galaxy.{84.80->87.06}Become a HERO. {87.79->89.96}Become a LEGEND.{90.81->94.44}Become a Helldiver!": "{9.03->11.00}超级地球。{11.00->12.65}我们的家园。{13.17->14.84}繁荣。{15.78->17.30}自由。{17.52->18.09}你好啊!{18.10->19.03}嘿!{19.82->20.65}民主。{21.81->23.89}我们的生存正道。{23.89->25.72}噢,你好!{28.52->31.22}但自由…也有代价。{32.40->36.63}不…解放你大业的…不!{40.36->46.62}眼熟吗?这样的场景,此时此刻正在星系各地上演!{47.00->49.46}下一个可能就是你。{49.89->54.79}现在,轮到你做出这个生命中最重要的决定。{54.79->60.99}向所有人证明,你拥有追求自由的力量与勇气。{61.88->64.97}加入…绝地潜兵。{66.06->68.46}成为维和队伍的精英!{72.91->75.48}见识奇异的新生命体。{79.43->83.92}将管理式民主普及整个星系。{84.80->86.43}成为英雄。{86.43->87.50}砰!来吧,兄弟。{87.79->89.96}成为传奇。{90.81->94.44}成为绝地潜兵!", + "{0.00->2.15}Countdown initiated. Stand by for takeoff.": "{0.00->2.15}倒计时开始。准备起飞。", + "{0.00->1.34}They're coming!": "{0.00->1.34}它们来了!", + "{0.03->2.14}Pinned, I'm pinned!": "{0.00->2.22}呃,我被压制了!", + "{0.06->4.66}They say the Void prays on the weak-minded and the easily influenced.{4.66->10.71}I don't know if I believe that though, I'll wait until Coretta Kelly lets us know the facts.": "{0.06->3.96}据说寂域专门蛊惑那些意志薄弱、容易被影响的人。{4.67->10.40}不过我也不知道该不该信,还是等科雷塔·凯利告诉我们真相吧。", + "{0.00->2.74}Don't worry—the Helldivers are protecting us!": "{0.00->2.74}别担心,有绝地潜兵罩着呐!", + "{0.03->1.32}They're coming soon, right?": "{0.03->1.32}他们快到了,对吗?", + "{0.00->5.30}Gas! It's gas!": "{1.33->3.68}毒气!有毒气!", + "{0.01->1.80}Freedom save me!": "{0.65->1.80}自由保佑我 !", + "{0.00->1.94}Rest in pain, dirtbag.": "{0.00->1.94}要你不得好死。", + "{0.00->2.15}Enemy tactical asset within range.": "{0.00->2.15}已进入敌方战术资产范围。", + "{0.66->1.86}Son of a dissident!": "{0.00->1.62}解放你大业的!", + "{0.01->0.89}I'm empty!": "{0.00->1.05}没弹药了!", + "{0.00->1.53}Providing covering fire!": "{0.00->1.61}提供火力掩护!", + "{0.10->1.42}Stinking Fascist.": "{0.10->1.42}法西斯臭虫。", + "{0.05->2.08}This is Pelican 1, preparing for touchdown.": "{0.05->2.08}这里是“鹈鹕”1号,准备着陆。", + "{0.00->2.01}I knew the Helldivers would protect us.": "{0.00->2.52}我就知道绝地潜兵会保护我们。", + "{0.04->2.26}Woo-hoo! Happy to be here!": "{0.00->2.38}呜呼!很高兴能来!", + "{0.00->0.32}You...{0.84->2.01}you saved me!": "{0.00->2.22}是您……救了我!", + "{0.02->1.00}Gotta reload!": "{0.02->1.00}得换弹了!", + "{0.00->0.57}Fall back!": "{0.00->0.57}撤退!", + "{0.00->1.53}The Irulta system": "{0.00->1.53}艾鲁尔塔星系", + "{0.04->1.50}More Automatons!": "{0.04->1.50}机器人又来了!", + "{0.00->1.83}Biological sample secured.": "{0.00->1.83}生物样本到手了。", + "{0.05->0.68}Out of ammo.": "{0.05->0.68}没弹药了。", + "{0.00->2.46}Let the light of Liberty shine!": "{0.00->2.46}解放照亮大地!", + "{0.02->1.73}Freedom never rests!": "{0.02->1.73}自由不能停!", + "{0.35->4.47}The Automatons seek to convert this world into another factory of tyranny. {4.88->6.59}You must stop them.": "{0.00->4.04}机器人想把这颗星球也变成维护暴政的工厂。{4.60->5.97}你必须阻止它们。", + "{0.02->1.10}The tentacles!": "{0.02->1.25}是触手!", + "{0.00->5.45}Don't worry. Top Super Earth scientists have proven that bugs don't feel pain.": "{0.00->5.63}别担心,超级地球顶尖科学家已经证实,虫族没有痛觉。", + "{0.02->0.98}Get down!": "{0.02->0.98}快趴下!", + "{0.00->1.64}This will all be over soon.": "{0.00->1.64}很快就会没事的。", + "{0.00->0.74}Not engaging.": "{0.00->0.74}别打这个。", + "{0.04->2.01}Liberty protect me!": "{0.00->2.10}解放护佑着我!", + "{0.02->0.76}Reloading.": "{0.02->0.76}正在换弹。", + "{0.02->4.84}The enemy has retained its hold upon this world. But we will fight on.": "{0.02->4.84}敌人夺回了这一方世界的掌控权,但我们还会不懈战斗。", + "{0.00->3.09}The Democracy Officer is here to optimize our Citizenship. {3.76->4.31}We're lucky—{4.82->7.95}we should always strive to be the best Citizens we can be.": "{0.00->2.79}民主官负责优化我们的公民义务和责任。{2.98->4.35}我们已经很幸运了,{4.79->7.96}应当时刻争取成为品行皆优的模范公民。", + "{0.00->1.44}Reporting to the front.": "{0.00->1.44}前线少不了我。", + "{0.00->7.77}Alert: Defense of currently orbited planet from Automaton invasion has ended in absolute victory. {8.17->11.19}Planet remains under Super Earth control.": "{0.00->7.30}通知:当前星球抵御机器人入侵的行动已经大获全胜。{7.43->11.19}该星球仍归超级地球统治。", + "{0.04->0.89}We've got equipment.": "{0.04->0.89}那儿有装备。", + "{0.00->1.60}Liberty guides my hand.": "{0.00->1.60}解放指引我。", + "{0.00->6.07}Another triumph for Managed Democracy. May Liberty guide your safe extraction.": "{0.00->3.05}管理式民主又一次迎来胜利,{3.56->6.07}愿解放引领你安全撤离。", + "{0.03->1.11}Somebody help!": "{0.03->1.42}谁来救我!", + "{0.01->1.76}New engagement zone, soldiers.": "{0.00->1.81}士兵们,新的交战区。", + "{0.00->1.44}Calling down support weapon.": "{0.00->1.44}呼叫支援武器。", + "{0.00->1.68}Our banner yet waves!": "{0.00->1.75}旗帜永远飘扬!", + "{0.00->1.06}Requesting tac-pack.": "{0.00->1.06}请求投放战术背包。", + "{0.00->1.65}As Democracy decrees.": "{0.00->1.65}我服从民主。", + "{0.00->1.32}Welcome back, Helldivers. {1.93->7.10}Your comrades who didn't return will rest easy knowing that this mission had a lower than average {7.10->7.89}casualty rate.": "{0.00->1.85}绝地潜兵,欢迎回来。{2.45->4.97}这次任务的伤亡率低于平均水平。{5.40->7.80}那些没能回来的战友可以安息了。", + "{0.04->2.10}Kill it! Destroy it!": "{0.04->2.10}快杀了它!杀了它!", + "{0.02->1.73}I'll never forget this.": "{0.02->1.73}我不会忘记你们的。", + "{0.49->0.65}Tac-pack's empty.": "{0.49->0.65}战术背包空了。", + "{0.00->2.82}Oh wow, so that's how it's done!": "{0.00->2.95}噢哇,原来是这样操作的!", + "{0.00->0.52}Don't need it.": "{0.00->0.52}不需要。", + "{0.00->0.83}Leave me...{1.32->3.11}save Super Earth...": "{0.00->0.83}别管我……{1.32->3.11}去救超级地球……", + "{0.00->1.20}Legendarium acquired.": "{0.00->1.20}传说矿物到手了。", + "{0.05->0.99}Cyberstan, the{1.83->3.95}black heart of Socialism.": "{0.05->4.00}生化斯坦,同盟主义的黑暗核心。", + "{0.00->1.48}The Pathfinder system": "{0.00->1.48}开拓者星系", + "{0.00->2.80}It's fun, but my bugs keep breaking free, again and again. {3.21->4.21}Dunno what I'm doin' wrong.": "{0.00->3.13}很有意思,但是我养的虫子一直在反复逃跑。{3.26->4.49}不知道我是哪里搞错了。", + "{0.01->2.04}Get me out, get me out!": "{0.00->2.08}带我出去,带我出去!", + "{0.01->1.61}They can't keep this up, right?": "{0.00->1.46}对面撑不了多久了吧?", + "{0.00->1.11}Nothing in the chamber.": "{0.00->1.11}子弹都打光了。", + "{0.00->1.54}The Vinge System": "{0.03->1.10}云翼星系", + "{0.04->2.28}Stim me, stim me Helldiver!": "{0.00->2.37}绝地潜兵,扎我,快扎我!", + "{0.00->0.94}Sweet Liberty!": "{0.00->1.10}解放他大业的!", + "{0.01->1.43}Requesting fortifications.": "{0.01->1.43}请求防御工事支援。", + "{0.00->0.47}Bravo": "{0.00->0.47}B", + "{0.00->0.12}I won!": "{0.00->1.20}我赢了!", + "{0.02->2.67}Saving the galaxy AND saving me? You rule!": "{0.00->3.07}不但要拯救星系,还要救我?{3.07->4.80}你是最棒的!", + "{0.02->1.35}My leg!": "{0.02->1.11}我的腿!", + "{0.05->1.63}What are they?": "{0.05->1.63}是什么东西?", + "{0.03->1.75}R-reloading!": "{0.03->1.75}正、正在装弹!", + "{0.01->0.87}Fall back!": "{0.00->0.85}撤退!", + "{0.00->1.53}The Primordia system": "{0.00->1.53}普莱默迪亚星系", + "{0.00->0.64}Mine!!": "{0.00->0.76}有地雷!!", + "{0.01->3.46}Helldiver down! Death to the enemy!": "{0.01->3.46}绝地潜兵阵亡!让敌人去死吧!", + "{0.00->0.78}100 meters.": "{0.00->0.52}100米。", + "{0.00->0.57}South.": "{0.00->0.63}南边,", + "{0.54->5.91}At last, the galaxy is free of the Illuminate Void.": "{0.00->3.34}银河系总算摆脱了{3.54->6.22}光能者的寂域威胁。", + "{0.00->3.43}Sweet Liberty! They got a Helldiver!": "{0.00->3.43}解放你大业的!他们杀了绝地潜兵!", + "{0.00->1.94}Its an honor, Helldiver.": "{0.00->1.94}见到你是我的荣幸,绝地潜兵。", + "{0.00->3.78}Every sector in the galaxy must be purged of the alien menace.": "{0.00->3.84}银河系的每个区域都必须肃清外星威胁。", + "{0.00->0.95}I need stims.": "{0.00->0.95}给我来一针。", + "{0.00->1.74}Automatons!": "{0.00->1.74}机器人!", + "{0.03->1.48}A failed operation. {2.03->3.95}We will rise from its ashes.": "{0.03->1.48}行动失利。{2.03->3.95}但我们将会愈挫愈勇。", + "{0.00->0.61}I've got you.": "{0.00->0.61}我来帮你。", + "{0.02->0.52}Run!": "{0.02->0.52}快跑!", + "{0.00->1.24}That was a close one!": "{0.00->1.24}好他民主的险!", + "{0.00->1.39}A worthy choice.": "{0.00->1.39}不错的选择。", + "{0.00->1.31}The Euphoria system": "{0.00->1.31}欧福利亚星系", + "{0.00->1.21}Gotta be another way...?": "{0.00->1.45}应该还有别的路吧……?", + "{0.31->0.90}Man,{1.33->3.73}Helldivers are the gift that keep giving!": "{0.00->3.99}天哪,绝地潜兵无时无刻不在奉献!", + "{0.00->0.72}Feels like home.": "{0.00->1.49}感觉像回到家一样。", + "{0.00->0.99}You'll pay for that,{1.06->2.21}alien scum!": "{0.00->0.99}外星畜生,{1.06->2.54}都等死吧!", + "{0.01->0.72}Moving out!": "{0.01->0.72}进攻!", + "{0.44->1.04}Terminids!": "{0.44->1.04}终结族!", + "{0.02->1.57}I got the good stuff for you!": "{0.00->1.66}给你带了点儿好东西!", + "{0.00->0.57}Fall back.": "{0.00->0.57}撤退。", + "{0.01->1.49}Stratagems selected.": "{0.01->1.49}战略配备已选定。", + "{0.01->3.81}I feel--I feel--RRAAH!": "{0.00->1.05}我感觉——{1.08->3.77}我感觉,哇哈哈!", + "{0.00->1.48}EAT MY VIRTUE!": "{0.00->1.57}尝尝这发真理!", + "{0.00->3.80}Justice is putting an end to those who would destroy us. {4.25->10.19}Justice is every citizen having an equal chance to excel within their assigned role. {10.61->13.48}Justice is Super Earth.": "{0.00->3.80}正义,就是干掉想干掉我们的人,{4.25->8.35}就是让每位公民能在政府分配的职业范围内,{8.51->10.91}享有平等的发展机会。{11.59->14.32}超级地球就是正义。", + "{0.04->1.53}The bots found us!": "{0.04->1.53}机器人来了!", + "{0.01->3.17}When I vote, I'll think of you, Helldiver.": "{0.01->3.17}绝地潜兵,你就是我投票的动力。", + "{0.00->1.35}Look out! Squids!": "{0.00->1.35}小心!鱿鱼!", + "{0.01->2.07}Son of a dissident!": "{0.79->2.07}解放你大业的!", + "{0.01->0.88}Reloading!": "{0.01->0.88}换弹!", + "{0.00->2.80}Careful, Helldiver, we're tearing this down.": "{0.00->2.92}潜兵,小心,我们要把这里夷为平地。", + "{0.01->2.99}Adversity is the true test of Citizenship!": "{0.01->2.99}不经历风雨,怎能见民主!", + "{0.02->1.99}Kill them! Kill them all!": "{0.02->1.99}杀了它们!统统杀光!", + "{0.00->0.67}Fire in the hole.": "{0.00->0.67}小心手雷。", + "{0.00->2.95}Helldiver?! I—oh.": "{0.00->1.54}是潜兵?!{1.54->3.11}我……噢。", + "{0.00->1.54}The Tien Kwan system": "{0.00->1.54}天关星系", + "{0.00->1.43}The more the mightier.": "{0.00->1.43}人越多越好。", + "{0.00->1.95}Nothing can topple our way of life!": "{0.00->1.95}什么都改变不了正道!", + "{0.02->1.03}Get it away from me!": "{0.02->1.03}别让它们过来!", + "{0.00->0.85}Enemy emplacement.": "{0.00->0.85}敌方炮位,", + "{0.08->1.32}The Zzaniah system": "{0.08->1.32}藏尼亚星系", + "{0.00->3.03}Protecting Freedom isn't just the right thing to do; {3.66->4.73}it's the law.": "{0.00->2.48}维护自由不仅正确,{3.19->4.75}还是铁律。", + "{0.00->4.75}Helldivers are heroes. Helldivers are Liberty.": "{0.00->4.85}绝地潜兵就是英雄,就是解放的化身。", + "{0.09->6.68}All those innocent civilians, lost to the Void. The flowers at their memorials{7.21->9.54}will taste Illuminate blood; {10.10->11.66}the fertilizer of Justice.": "{0.09->3.87}那么多无辜平民,都消失在寂域里。{4.64->8.80}纪念碑上的鲜花一定会痛饮光能者的鲜血,{9.07->10.69}绽放正义的光彩。", + "{0.00->1.45}No pain no Freedom.": "{0.00->1.82}痛苦铸造自由。", + "{0.00->1.63}Liberty watch over me...": "{0.00->1.71}解放护佑我……", + "{0.00->4.87}Ministry astronomers observe fluctuations in the fabric of spacetime {4.87->7.75}not seen since the Meridian Singularity Event.{8.38->11.32}The Illuminate continue meddling with reality - {12.06->13.46}but to what end?": "{0.20->3.21}天文学家观测到时空结构的波动,{3.55->7.89}这种现象自默里迪亚奇点事件以来从未出现过。{8.32->11.10}光能者一直在扰乱现实世界,{11.80->13.29}到底为了什么?", + "{0.00->0.94}Eager to obey!": "{0.00->0.94}乐意效劳!", + "{0.02->1.04}Get it off of me!": "{0.02->1.04}快把它搞走!", + "{0.05->3.36}Terminids exhibiting swarm intelligence shouldn't come as a surprise.{3.75->8.14}Even regular Super Earth ants can solve some group puzzles faster than scientists.{8.71->12.86}Well, they used to be able to. Those ants have all been exterminated.": "{0.00->2.88}终结族表现出的群体智慧不足为奇。{3.04->8.14}就连普通的超级地球蚂蚁都能比科学家更快地解决某些群体难题。{8.54->10.05}至少以前是可以的。{10.46->13.14}后来那些蚂蚁都被消灭了。", + "{0.02->1.27}Requesting orbital strike!": "{0.02->1.27}请求轨道攻击!", + "{0.00->1.33}I need a hand over here!": "{0.00->1.42}我这里需要搭把手!", + "{0.00->1.29}As you command.": "{0.05->1.20}遵从你的命令。", + "{0.00->2.38}Right away. A genius idea.": "{0.00->1.14}马上就去。{1.31->2.38}好主意。", + "{0.00->2.91}You leave a more free city than you found.": "{0.00->2.91}又一座城市因你重获自由。", + "{0.00->4.41}Someday, we'll have killed every last bug, Automaton, and Illuminate, and the galaxy will finally {4.41->4.95}be at peace.": "{0.00->3.19}我们终将消灭所有虫族、机器人和光能者,{3.60->4.95}实现真正的和平。", + "{0.07->1.95}Super Earth's Finest!": "{0.07->1.65}超级地球的精英来了!", + "{0.00->1.72}The Serendipity System": "{0.00->1.18}天缘星系", + "{0.00->1.10}I'm sure you noticed the{1.69->4.26}drop in efficiency among the support crew while I was gone.{4.98->6.61}I hope the Democracy Officer wasn't{6.98->7.69}too hard on them?": "{0.00->1.28}你肯定注意到了,{1.55->4.26}我不在的时候,支援人员的效率有所下降。{5.05->7.68}民主官应该没有对他们太严厉吧?", + "{0.02->1.20}Eat this!": "{0.02->1.20}尝尝这个!", + "{0.04->2.66}Get away from me, bot freak!": "{0.04->2.29}大铁块儿,滚远点儿!", + "{0.00->1.21}Visibility decreasing.": "{0.00->1.21}注意,能见度降低。", + "{0.00->1.61}Good game, Diver, good game.": "{0.00->1.74}干得漂亮,潜兵,干得漂亮。", + "{0.00->0.53}Get 'em...{1.23->1.66}for...{2.34->2.73}me...": "{0.00->0.53}替我…{1.23->1.66}消灭…{2.34->2.73}它们…", + "{0.00->1.72}Hold your ground!": "{0.00->1.72}不要退缩!", + "{0.00->1.79}Wow, that is LOUD!": "{0.91->2.04}真是太吵了!", + "{0.01->2.00}TASTE FREEDOM!": "{0.01->2.23}尝尝自由!", + "{0.00->1.45}Requesting orbital strike!": "{0.17->1.33}请求轨道攻击!", + "{0.00->1.35}The Polaris system": "{0.00->1.35}北极星星系", + "{0.05->12.53}Relax. Float, as if in a hydropod. Now, envision a squid, swimming toward you.{12.53->26.76}Reaching out its tentacles. Now take out your blade, and lop off every single, slimy arm.{26.76->28.81}You are safe.": "{0.00->1.07}放松。{1.53->5.52}漂浮起来,想象自己泡在水舱里。{6.22->11.24}现在,想象一只鱿鱼向你游过来。{12.04->13.86}对你伸出触手。{14.88->25.60}你拔出自己的刀,砍断了每一条黏腻的触手。{26.76->28.85}你安全了。", + "{0.02->0.50}Three.": "{0.02->0.50}三。", + "{0.03->0.82}Look out!": "{0.03->0.82}小心!", + "{0.03->1.66}Pinned down over here...!": "{0.00->1.78}我被压制了……", + "{0.00->3.97}When the undemocratic din of our enemies has at last been silenced, {4.38->10.93}we shall finally perceive the unsullied peal of Democracy, reverberating evermore.": "{0.00->3.97}敌人违抗民主的喧嚣最终被压制时,{4.38->11.51}我们就能听到民主发出无暇的鸣响,在耳边永久回荡。", + "{0.00->0.81}Nevermind.": "{0.05->0.51}算了。", + "{0.00->1.57}The Liberty Ridge system": "{0.00->1.57}解放岭星系", + "{0.01->1.69}I'm out! Cover me!!!": "{0.00->0.92}我没弹药了!{1.15->1.97}掩护我!!!", + "{0.00->1.39}Hive structure destroyed.": "{0.00->1.39}已摧毁虫窝结构。", + "{0.00->1.37}Deploying SOS beacon.": "{0.00->1.53}正在部署SOS信标。", + "{0.06->0.96}Squids!": "{0.06->0.96}鱿鱼!", + "{0.03->1.62}Its about to get kinetic!": "{0.00->1.60}马上要动真格了!", + "{0.03->1.09}There they are!": "{0.00->1.35}它们出现了!", + "{0.03->1.66}GET SOOOOOOME!": "{0.03->1.66}都给老娘死!", + "{0.06->3.46}Freedom must reign over every last star!": "{0.00->3.35}自由之风必将吹遍宇宙繁星!", + "{0.00->1.44}Are you sure it's safe here?": "{0.00->1.44}这里确定安全吗?", + "{0.00->3.80}A Helldiver! A real Helldiver!": "{1.17->4.11}绝地潜兵!真正的绝地潜兵。", + "{1.15->2.48}The blood. Can't stop the blood.": "{0.00->2.48}血,都他民主的流干了!", + "{0.00->0.64}Hold Position.": "{0.00->0.64}原地待命。", + "{0.02->1.59}Get it off of me!": "{0.02->1.59}快把它弄开!", + "{0.00->3.43}Enemy High Priority Target should be nearby. Stay sharp.": "{0.00->3.43}高优先级敌方目标可能就在附近,保持警惕。", + "{0.05->1.25}WATCH OUT!": "{0.00->1.40}小心!", + "{0.00->1.29}Firing orbital laser.": "{0.00->1.29}发射轨道激光炮。", + "{0.00->0.86}Let's play.": "{0.02->0.90}来玩吧。", + "{0.00->0.72}Weapons ready.": "{0.00->0.72}武器确认。", + "{0.00->0.38}Right.": "{0.00->0.38}右边。", + "{0.00->1.58}Who's still with us!?": "{0.00->1.13}还有谁在!?", + "{0.42->0.60}My legs!": "{0.00->1.09}我的腿!", + "{0.01->1.65}Back! Back!": "{0.01->1.94}滚开!滚开!", + "{0.00->1.14}Tac-pack's empty.": "{0.00->1.14}战术背包空了。", + "{0.00->1.54}Concealed System": "{0.00->1.09}隐蔽星系", + "{0.00->0.77}On my position.": "{0.00->0.77}在我这儿。", + "{0.03->2.04}That's the Democratic spirit!": "{0.00->2.20}这就是真正的民主精神!", + "{0.01->1.28}Squid outpost.": "{0.01->1.05}鱿鱼哨站。", + "{0.05->2.15}Yeah, that's Liberty!": "{0.00->2.18}没错,这就是解放!", + "{0.29->1.75}Another Vote stolen!": "{0.29->1.75}又被抢走一张票!", + "{0.07->1.87}Wait 'til I tell my kids about this.": "{0.07->1.87}我要把这件事告诉我孩子。", + "{0.03->5.04}The Cyborgs sent the Automatons, their mindless war-slaves, off-world in secret.{5.48->9.84}Then the Automatons chose to come back to set their masters free, since they aren't sentient{9.84->12.35}enough to even realize that they're slaves to begin with.": "{0.03->4.35}生化人秘密地把这些无脑战争奴隶机器人送到了外星球。{4.83->7.32}然后机器人选择回来解放它们的主人,{7.63->9.37}因为它们根本没有足够的智慧,{9.66->12.09}无法意识到自己本来就是奴隶。", + "{0.00->0.55}Yes!": "{0.00->0.55}好的!", + "{0.01->1.96}Death to Tyranny!": "{0.00->2.27}暴政者,去死!", + "{0.00->1.39}Eat this!": "{0.00->1.39}尝尝这个!", + "{0.01->1.01}Bug tunnel breach!": "{0.01->1.01}虫族隧道出现!", + "{0.02->1.89}Calling in extraction!": "{0.02->1.89}呼叫撤离!", + "{0.04->0.82}Welcome back. {1.23->3.67}The Illuminate might be an advanced species, but {4.09->5.74}they're no match for the Helldivers.": "{0.00->0.95}欢迎归来。{1.44->3.85}就算是光能者这样高度发达的物种,{4.12->6.32}也绝对无法与绝地潜兵匹敌。", + "{0.00->0.88}Helldiver?!{1.41->1.65}I--oh.": "{0.00->1.50}是潜兵?!{1.50->3.10}我……噢。", + "{0.02->1.73}Targets acquired. Engage!": "{0.00->1.78}目标已拿下。开打!", + "{0.00->1.10}I'll handle the terminal.": "{0.00->1.10}这个终端交给我。", + "{0.00->0.47}New mag.": "{0.00->0.47}新弹匣。", + "{0.02->1.56}FLAG-forsake it!": "{0.00->1.59}插了个旗的!", + "{0.00->0.49}Will do!": "{0.00->0.49}好的!", + "{0.03->2.86}OUTTA THE WAY! GO! GO!": "{0.00->3.05}快离开那儿!走开!走开!", + "{0.00->2.72}Soon as those Flag-forsakin' freaks are in range...": "{0.00->2.72}等那些没旗子的废物进入射程…", + "{0.00->2.08}Our heroes will be remembered. {2.53->4.95}And their failure will be redressed.": "{0.00->2.08}英雄永垂不朽,{2.53->4.95}他们的失败也会得到补救。", + "{0.00->1.26}Legendarium acquired.": "{0.00->1.26}传说矿物到手了。", + "{0.00->2.64}That's one less terrorist to worry about.": "{0.00->2.64}从此少了一个恐怖分子。", + "{0.05->2.74}That's right, that's OUR planet!{2.74->6.44}OUR planet, and don't those Bots forget it!{6.44->9.38}Whoo, I might need to have a seat.": "{0.19->2.13}没错,那是我们的星球!{2.40->5.56}我们的星球,那些机器人可别忘了!{7.00->8.60}哇,我得坐下缓缓了。", + "{0.00->1.89}Liberty. Prosperity. {2.25->3.24}Democracy.": "{0.00->2.98}解放,繁荣,民主。", + "{7.76->11.38}Freedom's Greetings, I'm your host, Coretta Kelly.{11.93->16.08}The Helldivers are advancing on Cyberstan for the first time {16.08->18.30}since the planet was seized by the Automatons {18.30->21.34}at the start of the second Galactic War.{21.78->25.44}Cyberstan, once a nexus of dissidence, {25.44->28.68}has served as a center for rehabilitative labor {28.68->33.02}since the end of the First Galactic War, when the Cyborgs were defeated.{33.44->38.79}Now, the question remains: what awaits the Helldivers on Cyberstan,{38.79->42.31}after more than a year under Automaton control?{43.29->47.94}Up next: a participant in a local hackathon successfully programmed {47.94->52.35}an Automaton head to run the hit game Stratagem Hero.{52.87->54.78}You won't believe the high score!{55.10->58.53}That's Liberty's Latest; I'm Coretta Kelly.": "{7.88->11.35}自由向各位问好,我是主持人科雷塔·凯利。{11.85->14.76}绝地潜兵正在向生化斯坦推进,{15.15->19.14}自第二次星系战争爆发、该星球被机器人占领以来,{19.35->21.41}这是我方首次发起反攻。{21.74->24.35}生化斯坦曾是异议分子的集中地,{24.92->28.37}自第一次星系战争结束、生化人被击败后,{28.47->32.17}生化斯坦便成为了劳动改造中心投入使用。{33.47->38.68}现在我们面临的问题是:在机器人控制生化斯坦一年多后,{38.89->42.12}绝地潜兵到了那里到底会遭遇什么?{42.96->46.55}接下来请收看:某本地黑客马拉松参赛者{46.80->51.65}成功用机器人脑袋运行热门游戏《战略配备英雄》。{51.82->54.24}还刷爆了最高分记录!{54.78->58.82}以上就是今天的《解放新闻》,我是科雷塔·凯利。", + "{0.01->2.95}Hostiles! Lock and load, soldiers!": "{0.01->2.95}有敌人!战士们,拿起武器!", + "{0.00->1.60}They died as they fought --{1.97->2.67}a hero.": "{0.00->1.60}战死沙场的{1.97->2.79}都是英雄。", + "{0.00->1.01}Outpost cleared.": "{0.00->1.01}已清除哨站。", + "{0.05->2.27}Taste Justice, robot scum!": "{0.05->2.95}铁皮渣滓,尝尝正义!", + "{0.00->2.08}Civic duty at its finest.": "{0.00->1.87}争当好公民。", + "{0.17->1.38}We knew you'd save us.": "{0.17->1.38}就知道你们会来救我们。", + "{0.15->2.45}Super Earth will...{2.86->3.73}avenge me...": "{0.15->1.63}超级地球……{2.38->3.73}会为我复仇……", + "{0.00->0.71}On my way.": "{0.00->0.71}马上来。", + "{0.01->1.34}SEAF squad on target.": "{0.00->1.46}武装部队前往目标。", + "{0.12->1.53}Steady yourselves!": "{0.00->0.96}稳住!", + "{0.00->1.25}The Turing system": "{0.00->1.25}图灵星系", + "{0.00->1.95}The Mönsterås System": "{0.00->1.79}门斯特罗斯星系", + "{0.00->1.31}I wish I could do what you do.": "{0.00->1.31}真想像你们一样。", + "{0.00->1.39}Loadout confirmed.": "{0.00->1.48}武装配置确认。", + "{0.00->1.65}Requesting advanced weaponry!": "{0.00->1.65}请求高级武器支援!", + "{0.00->2.12}What's the blast radius for these again?": "{1.18->2.40}它能炸多远?", + "{0.02->1.95}You and me, Helldiver!": "{0.00->2.09}你和我,绝地潜兵!", + "{0.02->1.08}Mounting weapon!": "{0.00->1.15}操作武器!", + "{0.01->1.58}That's it, that's the stuff.": "{0.00->1.63}没错,要的就是这个。", + "{0.11->2.25}Nothing can dodge Democracy.": "{0.11->2.60}民主制裁一切。", + "{0.03->4.64}Get in position! Oh uh, not you Helldiver, unless you want to.": "{0.00->2.21}各就各位!呃,潜兵,{2.29->4.54}没有说你,你自己拿主意。", + "{0.03->1.63}This will all be over soon.": "{0.03->1.63}很快就会没事的。", + "{0.00->0.80}Right away!": "{0.00->0.80}马上!", + "{0.00->0.44}Will do!": "{0.00->0.44}好的!", + "{0.01->3.81}Relocate to the coordinates, and get ready for the show.": "{0.00->3.74}转移至该坐标,准备好大干一场。", + "{0.03->4.78}Soon, Cyberstan will be free once more.": "{0.03->4.78}生化斯坦很快就会重获自由。", + "{0.01->2.41}Feed the flames of Justice!": "{0.01->2.41}尝尝正义之火的滋味!", + "{0.00->0.86}Move out!": "{0.00->0.88}转移!", + "{0.00->0.81}For liberty!": "{0.00->0.81}为了解放!", + "{0.76->1.74}How does this even work...": "{0.00->1.83}这玩意儿到底怎么用……", + "{0.03->1.45}The enemy held for now, {2.03->3.95}but they shall crack eventually.": "{0.03->2.09}敌人暂时还能负隅顽抗,{2.38->4.09}但终将一败涂地。", + "{0.04->4.96}I shot a Helldiver! I don't deserve forgiveness!": "{0.84->2.89}我打中了潜兵!{2.90->5.00}我不配得到原谅!", + "{0.00->0.70}First one.": "{0.00->0.70}第一个。", + "{0.03->2.89}Soon, the Cyborgs'll be back in their mines!": "{0.03->3.09}很快,生化人就会重新回到矿井里!", + "{0.00->1.56}The Mekbuda system": "{0.00->1.56}井宿七星系", + "{0.00->3.53}We have failed to disrupt the spread of the Void.": "{0.00->3.34}我们未能阻止寂域的扩散。", + "{0.00->0.95}Think I saw something!": "{0.00->1.13}我似乎看到了什么!", + "{0.01->0.66}Moving up!": "{0.00->0.73}向前推进!", + "{0.00->0.42}Got 'em!": "{0.00->0.42}搞定!", + "{0.02->0.76}Look out!": "{0.02->0.76}小心!", + "{0.09->5.54}I never doubted you for a second, Helldiver! I knew you'd rout the Cyborgs from Cyberstan. {6.13->9.93}I can't wait to see the look on their treacherous faces when we put them right back,{10.40->12.06}in even deeper mines this time!": "{0.28->2.68}绝地潜兵,我从来没有怀疑过你!{3.10->5.49}我就知道你能把生化人赶出生化斯坦。{6.13->8.86}等我们把它们送回去,关进更深的矿井里,{9.22->11.99}真想看看它们那副叛徒嘴脸会是什么表情!", + "{0.03->0.88}There they are!": "{0.03->0.88}它们出现了!", + "{0.04->3.04}Yeah! Come on! Bring it in.": "{0.00->1.88}来,过来,{2.19->3.09}抱一个。", + "{0.00->1.32}I don't deserve the honor.": "{0.00->1.44}我配不上这份荣幸。", + "{0.00->8.26}History matters! Today, we remind you that Super Earth always has been, and always will be.": "{0.00->1.17}铭记历史!{1.60->4.10}今天,请各位勿忘历史,{4.42->9.15}超级地球创立已久,以后也会永垂不朽。", + "{0.00->1.91}Was that them? That was them.": "{0.00->1.91}它们搞的吗?就是它们。", + "{0.00->1.93}Helldiver, reporting for duty.": "{0.00->1.93}绝地潜兵前来报到。", + "{0.00->1.95}Only Justice speaks binary!": "{0.00->1.95}只有正义才是二进制!", + "{0.00->2.10}When the Archives are claimed,{2.49->5.80}they will be given a warriors' burial.": "{0.00->2.10}占领档案阁后,{2.49->5.80}我们就会为他们举办战士的葬礼。", + "{0.08->3.36}What the Illuminate are planning, none can say. {3.79->7.13}The sunless depths of their minds defy comprehension, {7.55->10.96}and plumbing them only turns our eyes from Liberty's light.": "{0.08->2.61}光能者的计划深不可测,{3.19->6.37}他们内心的黑暗更是难以估量。{6.59->10.96}探究这些东西,只会偏离解放之光的指引。", + "{0.03->0.98}This is crazy!": "{0.03->0.98}太可怕了!", + "{0.00->1.43}You're doing Democracy's work.": "{0.00->1.43}你在为民主作出贡献。", + "{0.17->1.41}We're safe now!": "{0.00->1.22}我们安全了!", + "{0.01->1.53}Sweet Liberty!": "{0.01->1.38}解放啊!", + "{1.73->4.01}A draw! And we'll draw together out there, too.": "{1.43->3.71}平局!我们在战场上也会一起拔枪的。", + "{0.00->3.24}We have to get back down there. The city needs us.": "{0.00->2.96}一定要重回战场。城市需要我们。", + "{0.07->3.38}And now, another helpful tip from General Brasch.{6.80->10.12}No Helldiver can Liberate the galaxy alone. {10.70->16.39}That's why we have Team Weapons! One Helldiver shoots. Another reloads.{16.60->21.32}Together, they create an unstoppable path of wanton Liberation! {21.49->27.09}And don't worry, one stratagem comes with both weapon and reload pack.{27.40->29.85}That's a 2-in-1 combo, soldier. {30.16->34.42}BRASCH TACTICS! Use 'em, or die trying!": "{0.07->3.38}布拉施将军又带来了一条实用提示。{6.80->10.51}没有哪个绝地潜兵可以孤身一人解放整个星系。{10.95->12.99}所以我们才准备了团队武器!{13.04->16.15}一位绝地潜兵负责射击,另外一位负责装弹。{16.52->21.32}两个人齐心协力就能所向披靡,为解放之路扫清障碍!{21.49->27.09}另外,别担心,一份战略配备同时配备了武器和弹药包。{27.40->29.56}没错,士兵,二合一包装。{30.42->31.77}布拉施亲传战术!{31.97->34.42}竭尽全力,不死不休。", + "{0.00->3.13}Hellbomb secured. Give the 'divers space to work.": "{0.00->3.13}已找到地狱火炸弹。给潜兵腾出点地方。", + "{0.18->1.74}Socialist scum.": "{0.18->1.74}铁皮渣滓。", + "{0.00->1.37}The Crucible system": "{0.00->1.37}熔炉星系", + "{0.06->2.34}Agh! Lookout—mines!": "{0.00->2.42}啊!当心——地雷!", + "{0.04->1.60}What are those things?": "{0.04->1.60}那都是什么玩意儿?", + "{0.00->0.64}Pack's out.": "{0.00->0.64}背包空了。", + "{0.00->5.85}Each Ministry is a fundamental pillar upon which Managed Democracy rests.": "{0.00->5.85}每一个部门都是支撑着管理式民主正常运转的重要支柱。", + "{0.00->2.95}This bio sample will directly increase our Freedom.": "{0.00->2.95}这份生物样本将会助力自由大业。", + "{0.00->0.72}Enemy spotted.": "{0.00->0.72}发现敌人,", + "{0.00->3.89}If this is the price of Freedom, it's worth every penny.": "{0.00->3.89}生命诚可贵,自由价更高。", + "{0.00->1.89}They all deserve to die.": "{0.00->1.81}它们都该死。", + "{0.02->1.37}The X system": "{0.02->1.37}X星系", + "{0.02->1.53}Requesting advanced weaponry!": "{0.02->1.53}请求高级武器!", + "{0.01->2.45}Changing course -- betters our Cause.": "{0.01->2.91}改变方向…最好是解放的方向。", + "{0.03->3.31}I hope the Helldivers make an example of you.": "{0.03->3.64}希望绝地潜兵拿你开刀。", + "{0.00->1.63}The Fornskogur system": "{0.00->1.63}福恩斯科古尔星系", + "{0.00->2.63}Allied Destroyer coordinates received.": "{0.00->2.63}已收到友方驱逐舰坐标。", + "{0.00->1.21}Calling down supplies.": "{0.00->0.89}呼叫补给。", + "{0.02->0.99}Move, move!": "{0.00->1.06}前进,前进!", + "{0.00->2.49}Hail Freedom!": "{0.00->2.58}自由万岁!", + "{0.00->1.38}The Siemnot system": "{0.00->1.38}席姆纳特星系", + "{0.00->0.51}Vehicle.": "{0.00->0.51}载具,", + "{0.00->0.76}Of course.": "{0.00->0.76}那当然。", + "{0.00->0.54}Help! Help!": "{0.00->2.02}救命!救命!", + "{0.04->1.53}TAKE COVER!": "{0.00->1.69}快找掩护!", + "{0.02->1.02}Cover, cover!": "{0.00->1.09}隐蔽,隐蔽!", + "{0.00->2.04}Mission at 30 minutes remaining.": "{0.00->2.04}任务剩余30分钟。", + "{0.03->0.63}Super Earth's{0.99->1.66}Finest!": "{0.03->1.69}超级地球的精英来了!", + "{0.02->0.74}Be ready!": "{0.02->0.79}做好准备!", + "{0.02->1.35}FIRE IN THE HOLE!": "{0.02->1.35}小心爆炸!", + "{0.00->3.18}We will fight on in the memory of those we lost.": "{0.00->2.84}我们会秉持逝者的遗志,继续战斗。", + "{0.00->1.32}Freedom five!": "{0.00->1.20}自由击掌!", + "{0.00->2.65}Teleportation signature detected. Squids incoming.": "{0.00->2.65}侦测到传送信号。鱿鱼来了。", + "{0.03->1.76}Everyone, take cover!": "{0.00->1.99}所有人,找好掩护!", + "{0.07->2.00}Now that they know they're losing,{2.04->5.81}the Cyborgs are scrambling to build more Megafactories all over.{7.03->8.00}Desperate.": "{0.07->4.58}生化人知道它们没有胜算,就开始忙着到处建超大型工厂。{6.31->7.35}它们很绝望。", + "{0.00->0.44}Look, a{0.87->1.58}good bug.": "{0.00->1.80}虫子死了才好。", + "{0.00->0.66}Follow me.": "{0.00->0.66}跟我走。", + "{0.00->2.12}Now! Attack now!": "{0.00->2.12}冲啊!趁现在!", + "{0.00->2.83}Let's not keep Liberty waiting. Move up.": "{0.00->1.76}别让解放等太久。{1.77->2.89}压上去。", + "{0.00->1.51}The War rages on. {2.34->4.40}Choose where you will give your aid.": "{0.00->1.51}战争如火如荼,{2.34->4.40}请选择你要支援的战场。", + "{0.00->1.88}The greatest hero I've ever seen.": "{0.00->1.88}这是我见过的最伟大的英雄。", + "{0.02->9.58}The valiant efforts of you and your kin have saved the Galaxy once more. The Void is gone at last.{10.19->14.95}And though this will not be the last time the Illuminate bedevil Democracy,{15.57->19.87}when they do, the Helldivers will be here.{20.31->22.90}As they always have been.": "{0.00->5.45}各位与同袍英勇奋战,再次拯救了银河系。{5.85->8.73}寂域终于消失了。{9.46->14.39}光能者肯定不是最后一次妄图破坏民主,{14.95->20.41}但它们无论何时卷土重来,绝地潜兵都会恭候。{20.77->23.31}一如既往。", + "{0.01->0.47}Thank you!": "{0.01->0.47}谢谢!", + "{0.00->0.15}How much longer?": "{0.00->0.99}还得等多久?", + "{0.06->1.56}For Super Earth!": "{0.00->1.64}为了超级地球!", + "{0.03->1.29}What are those things?": "{0.03->1.29}那都是什么东西?", + "{0.00->2.51}You inspire the soldiers, Helldiver.": "{0.00->2.51}绝地潜兵,你是战士们的榜样。", + "{0.00->1.11}Helldivers!{1.53->3.26}They'll never believe this back home!": "{0.00->0.83}绝地潜兵!{1.30->3.07}回头他们又要说我吹牛了!", + "{0.61->1.25}Shoot them! Shoot them!": "{0.00->1.63}快打它们!快打!", + "{0.00->0.56}We're stuck!": "{0.00->0.56}被困住了!", + "{0.00->1.03}This isn't over.": "{0.00->0.93}你们死定了。", + "{0.00->1.19}Need assistance!": "{0.00->1.26}请求救助!", + "{0.04->1.97}Flag-forsaken robots!": "{0.04->1.97}一堆破铜烂铁!", + "{0.00->4.75}Maybe print a trillion pamphlets, or build a billion interplanetary radio stations, something to {4.75->6.64}break through whatever propaganda they're feedin' em.": "{0.00->3.85}也许可以印一万亿张传单,或者修建十亿座星际无线电台,{4.45->6.83}反正就是想办法去打破它们被灌输的思想。", + "{0.03->1.12}Bug tunnel breach!": "{0.03->1.12}虫族隧道出现!", + "{0.03->1.66}The Adhafera system": "{0.03->1.66}轩辕十一星系", + "{0.02->1.52}The Arkturus system": "{0.02->1.52}阿克图勒斯星系", + "{0.03->4.08}They'll never take my... moral fortitude...": "{0.03->4.91}我的信念…不会动摇…", + "{0.00->3.11}Another sweeping victory for Super Earth.": "{0.00->3.11}超级地球再次大获全胜。", + "{0.00->0.79}Over here!": "{0.00->0.79}这里!", + "{0.00->1.31}RUN!": "{0.00->1.31}快跑!", + "{0.00->3.12}I don't know if those Automatons were ever technically alive, {3.49->5.24}but they're definitely dead now.": "{0.00->2.41}我不知道机器人究竟算不算生命体,{3.04->4.90}但它们现在肯定死了。", + "{0.05->1.35}What are they?": "{0.05->1.35}是什么东西?", + "{0.00->1.61}Fall back and regroup!": "{0.00->1.70}先撤退,再集结!", + "{0.00->0.87}There's something here.": "{0.00->0.87}这边有发现。", + "{0.00->3.62}Coordinates received. This is Pelican 1 returning to extraction radius.": "{0.00->3.62}已收到坐标。这里是“鹈鹕”1号,正在返回撤离区。", + "{0.00->0.65}Fifth one.": "{0.00->0.65}第五个。", + "{0.01->1.60}Mines! Stay alert!": "{0.00->1.68}有雷!保持警惕!", + "{0.02->0.95}More Terminids!": "{0.02->0.95}终结族又来了!", + "{0.00->4.89}The Democratic direction of the DSS is an inspiration to behold. {5.67->8.58}It is enough to bring a tear to the eye.": "{0.00->4.89}民主空间站的民主指引有着振奋人心的作用,{5.67->8.58}足以让人热泪盈眶。", + "{0.00->5.30}The Illuminate will stop at nothing to destroy us. They cannot be allowed to survive.": "{0.00->3.17}光能者会不惜一切代价摧毁我们,{3.68->5.30}绝不能让他们继续存在。", + "{0.00->3.77}This is Pelican 1. Helldivers are outside the extraction zone, landing aborted.": "{0.00->3.77}这里是“鹈鹕”1号。绝地潜兵不在撤离区,已放弃着陆。", + "{0.00->3.52}With the Helldivers on our side, we can't lose!": "{0.00->2.10}有绝地潜兵站在我们这边,{2.10->3.66}哼!输不了!", + "{0.00->1.37}Objective defended.": "{0.00->1.37}已守住目标。", + "{0.02->2.20}I'm pinned, need assistance!": "{0.00->2.23}我被压制了,需要支援!", + "{0.00->1.66}The Columbidae System": "{0.00->1.25}和平鸽星系", + "{0.03->1.35}I need help!": "{0.00->1.39}我需要帮助!", + "{0.15->1.33}The Rasp system": "{0.15->1.33}拉斯普星系", + "{0.02->2.60}Thank Super Earth for the Helldivers!": "{0.02->2.94}感谢超级地球派来绝地潜兵!", + "{0.00->3.07}Expunge these Xenophobes from our galaxy.": "{0.00->3.07}彻底抹除这些排外分子。", + "{0.10->4.66}The bots have deployed a strike force known as the Jet Brigade. {5.12->12.29}These rocketeering rabble evidently qualify as \"elite\" amongst the ever-inferior Automatons.": "{0.00->3.69}机器人部署了一支名为“喷气旅”的突击队。{4.25->12.29}与向来表现平平的机器人相比,这些玩火箭的乌合之众显然堪称“精英”。", + "{0.06->0.59}Roger. {0.95->3.58}Pelican 1 will reattempt pickup at extraction zone.": "{0.03->0.66}收到。{0.67->3.58}“鹈鹕”1号前往撤离区,再次尝试接人。", + "{0.21->2.12}For the glory of Super Earth!": "{0.00->1.73}荣耀属于超级地球!", + "{0.01->2.55}Super Earth will avenge you, friend.": "{0.01->2.55}超级地球会为你复仇。", + "{0.01->3.42}I'm okay, I'm okay.": "{0.72->3.42}我没事,我没事。", + "{0.01->1.87}For Liberty, always!": "{0.00->2.10}为了解放,永远!", + "{0.02->2.19}Thanks, good morale boost.": "{0.00->2.24}多谢,士气大振。", + "{0.01->1.99}Reloading...in a minute!": "{0.01->1.99}正在装弹……马上!", + "{0.06->2.18}Kill it! Destroy it!": "{0.06->2.18}快杀了它!杀了它!", + "{0.01->1.13}We made it!": "{0.01->1.13}我们成功了!", + "{0.00->3.63}Well done. The Illuminate can't keep their secrets hidden forever.": "{0.00->3.63}干得好。光能者不可能永远隐藏秘密。", + "{0.00->1.60}Democracy needs me.": "{0.00->1.60}民主需要我。", + "{0.00->1.65}Biological sample secured.": "{0.00->1.65}生物样本到手了。", + "{0.00->0.91}Objective equipment.": "{0.00->0.91}目标装备,", + "{0.00->1.45}SEAF en route to objective.": "{0.00->1.59}武装部队正赶往目标。", + "{0.02->2.20}Just like in the movies...": "{0.02->2.20}跟拍电影一样…", + "{0.00->3.95}Our resolve in the face of Tyranny will be their undoing!": "{0.00->3.14}意志能瓦解暴政。", + "{0.03->1.77}Guh, I'm pinned!": "{0.00->1.82}呃,被压制了!", + "{0.03->1.14}Incoming fire!": "{0.00->1.12}火力来袭!", + "{0.03->1.46}More Terminids!": "{0.03->1.46}终结族又来了!", + "{0.01->1.29}Let's go, come on!": "{0.00->1.38}行动起来,快!", + "{0.00->0.95}Let's go!": "{0.00->1.10}一起上!", + "{0.03->3.68}If I were a Helldiver, I think my favorite enemy to kill would be the Bots.": "{0.03->3.68}我要是绝地潜兵,我最喜欢杀的敌人应该是机器人。", + "{0.01->1.35}It's the Illuminate!": "{0.01->1.35}光能者来了!", + "{0.05->0.83}Fewer bots. {1.25->2.02}More Freedom.": "{0.05->1.22}机器人越少,{1.37->2.57}自由越壮大。", + "{0.01->0.86}Stay low!": "{0.01->0.86}蹲下!", + "{0.12->0.80}100 meters.": "{0.12->0.80}100米。", + "{0.03->1.09}Take cover!": "{0.03->1.09}快找掩体!", + "{0.00->2.39}We're doomed! DOOMED!": "{0.00->2.72}完了!我们完了!", + "{0.06->4.52}This is Pelican 1, requesting all Helldivers to enter the extraction radius.": "{0.06->4.52}这里是“鹈鹕”1号,请所有绝地潜兵立即进入撤离区!", + "{0.02->1.56}Back! Back!": "{0.02->1.56}滚开!滚开!", + "{0.03->1.29}Need assistance!": "{0.00->1.33}请求救助!", + "{0.00->1.45}Calling down a sentry.": "{0.00->1.45}呼叫哨戒炮。", + "{0.00->3.27}Alert: Defense of currently orbited planet from {3.69->7.60}Illuminate invasion has ended in temporary defeat. {8.24->11.20}Planet now under Illuminate control.": "{0.00->7.32}通知:当前星球抵御光能者入侵的行动暂时失利。{7.39->11.20}该星球现在归光能者统治。", + "{0.00->5.42}By desecrating these ruins, the Illuminate are robbing our Museums of Dissidency before they have{5.45->6.41}even been built.{6.82->10.26}How will our children learn about the horrors of Xenophobia?": "{0.00->5.12}光能者亵渎这些遗迹,等于是在抢劫我们还没建成的“异见博物馆”。{5.65->9.34}子孙后代该通过什么渠道了解仇外分子的可怕呢?", + "{0.04->1.79}Bugs! Aaaaaah!": "{0.04->1.79}虫族!啊啊啊啊!", + "{0.00->3.00}That was the coolest moment of my entire life.": "{0.00->3.00}这是我人生中最高光的时刻!", + "{0.04->5.18}The Cyborgs must be so full of themselves, thinking that whatever they come up with is better than{5.18->6.16}Super Earth Freedom.{6.71->7.25}Please.": "{0.13->1.96}生化人一定很自以为是,{2.08->4.01}觉得自己捣鼓出来的任何东西{4.15->6.13}都比超级地球的自由还要好。{6.52->7.16}可笑。", + "{0.00->1.28}Firing orbital strike.": "{0.00->1.28}发射轨道攻击。", + "{0.01->1.48}I'm hit. Patching up!": "{0.01->1.79}我中弹了。正在治疗!", + "{0.05->1.89}It's a good day to die!": "{0.00->1.96}今天战死沙场也值了!", + "{0.02->0.61}Will do!": "{0.02->0.61}好的!", + "{0.00->8.79}The Void neither emits nor reflects any radiation. No light, no sound, no sign of life nor liberty{8.92->10.40}escapes its murk.": "{0.00->3.73}寂域既不发射也不反射任何辐射。{4.08->8.00}无论是光芒、声音,还是生命或自由的迹象,{8.25->10.15}都无法逃脱它的黑暗。", + "{0.09->2.00}What in Liberty's name!?": "{0.09->2.56}解放啊,是真的吗?", + "{0.04->1.39}Everyone into cover!": "{0.00->1.45}所有人进掩体!", + "{0.04->1.49}Mines in the ground!": "{0.00->1.52}小心地下有雷!", + "{0.19->1.44}We're gonna die!": "{0.19->1.93}我们死定了!", + "{0.01->0.93}Out of ammo!": "{0.00->1.01}弹药打光了!", + "{0.00->0.93}Whatever it takes.": "{0.00->0.93}不惜一切代价!", + "{0.00->2.68}Then we'd take our juvenile firearms and blast 'em to pieces. {3.24->4.57}Simpler times.": "{0.00->2.68}然后,我们会用练习枪把它们打成碎片。{3.24->4.57}那段时间真是单纯。", + "{0.01->3.61}We'll finish what you started, Helldiver.": "{0.00->1.12}绝地潜兵,{1.66->3.61}我会完成你的遗志。", + "{0.03->1.31}Not today!": "{0.03->1.31}还不能死!", + "{0.03->1.11}Take cover!": "{0.03->1.11}快找掩体!", + "{0.45->2.76}Wow. You really are a{3.75->4.88}tactical genius.": "{0.96->1.95}哇。{2.00->3.18}哇!{3.21->5.04}你真是一个战术天才。", + "{0.04->2.91}INCOMING! TAKE COVER!": "{0.00->2.96}要来了!找掩护!", + "{0.00->2.51}No retreat! No surrender!": "{0.00->2.10}不抛弃!不放弃!", + "{0.07->3.48}These ancient Illuminate ruins are an important part of our heritage.{3.86->7.01}Through them, our forefathers are immortalized;{7.11->11.05} the forefathers who bombed these xenophobic temples into the ground.": "{0.07->4.15}这些古老的光能者遗迹是我们重要的文化遗产。{4.59->7.73}透过这些遗迹,我们得以凭吊先祖,{8.12->11.77}正是他们把这些排外的神庙炸成了废墟。", + "{0.00->2.95}Their form of government is no match for ours!": "{0.00->2.45}它们的政体根本不是我们的对手!", + "{0.05->10.72}I heard the edge of the Void is a quantum meniscus, and passing through takes all your atoms apart and rearranges them exactly the same, except backwards.{10.72->14.23}I don't feel any different, but...you'd never know.": "{0.00->2.37}我听说寂域的边缘是个量子弯液面。{2.37->4.99}穿过边缘时,全身的原子都会被拆散,{5.02->8.31}然后再组装回去,只不过方向全是反的。{8.77->11.18}我没觉得有什么不同,{11.39->13.69}但是……谁也说不准。", + "{0.03->0.56}Nice.": "{0.03->0.56}很好。", + "{0.01->2.36}INCOMING! RUN!": "{0.00->2.43}要来了!快跑!", + "{0.02->2.80}Prosperous populace, there's too many of them!": "{0.00->3.11}繁荣个祖宗十八代,这敌人也太多了!", + "{0.00->0.42}Help!": "{0.00->0.73}救命!", + "{0.05->3.32}Sick, wow that's sick, stim-pistol sick!": "{0.00->2.09}绝了,哇哦,太绝了,{2.10->3.58}真他民主的绝!", + "{0.00->3.82}You are the tinder, and Liberty is the match!": "{0.00->3.82}你们是干柴,解放是烈火!", + "{0.01->3.34}Our Democracy may be tested, but it will never be tainted.": "{0.01->3.34}民主接受考验,但不接受玷污。", + "{0.00->0.44}5!": "{0.00->0.44}五!", + "{0.00->0.90}I commend you.": "{0.00->0.90}你真厉害。", + "{0.00->3.29}Eyes up front. Helldivers're gonna show us how it's done.": "{0.00->3.29}注意前方。绝地潜兵会做好示范。", + "{0.00->1.89}Swapping Internal Cooling Element.": "{0.00->1.89}更换内部冷却元件。", + "{0.05->4.93}We will never forget those who fell in the defense of Malevelon Creek.": "{0.00->1.63}我们永远不会忘记{1.82->4.84}为保卫麦拉芬蒙河而牺牲的英雄。", + "{0.04->6.33}We must take back our territory, that Freedom may unfurl its alabaster wings.": "{0.04->6.33}我们必将收复失地,帮助自由展开雪白的双翼,傲然飞翔。", + "{0.01->1.62}Don't stop! Go!": "{0.01->1.62}不要停!走!", + "{0.03->1.82}Our banner yet waves!": "{0.00->1.88}旗帜永远飘扬!", + "{0.05->3.52}Sick, wow that's sick, stim-pistol sick!": "{0.00->1.86}绝了,哇哦,太绝了,{1.92->3.39}真他民主的绝!", + "{0.15->1.30}The Zosma system": "{0.15->1.30}太微右垣五星系", + "{0.00->0.30}No.": "{0.00->0.30}不行。", + "{0.03->1.61}The squids are back!": "{0.03->1.61}鱿鱼回来了!", + "{0.01->1.16}Stay low!": "{0.01->1.16}蹲下!", + "{1.09->5.14}Yeah, keep this up, and our soldier production will stay well ahead of theirs.": "{0.96->5.33}照这样下去,我们的战士产量会永远碾压它们。", + "{0.01->1.77}...thank you, Helldiver.": "{0.00->1.82}……谢谢你,绝地潜兵。", + "{0.00->0.68}I'll take it.": "{0.00->0.68}我来。", + "{0.00->1.21}Flag acquired.": "{0.00->1.21}旗帜到手了。", + "{0.00->1.46}Not today, freaks!": "{0.00->1.46}给我,等着瞧吧!", + "{0.00->6.96}Remember: it's not that Super Earth hates aliens. It's that aliens hate Freedom.": "{0.00->0.70}记住,{1.04->6.99}不是超级地球厌恶外星人,是外星人厌恶自由。", + "{0.12->2.26}I've never seen truer courage.": "{0.12->2.26}我从来没有见过这样的勇士!", + "{0.01->1.05}Swapping battery.": "{0.01->1.05}换下电池。", + "{0.00->5.41}With haste, Helldiver. Our forces descend to battle the Cyborgs in the streets of their{5.41->6.22}homeworld. The{6.91->10.05}fight to free Cyberstan is upon us.": "{0.00->1.86}绝地潜兵,抓紧时间!{2.00->3.34}我军正在降落,{3.59->6.73}准备在生化人母星的街巷与它们激战。{6.91->10.05}解放生化斯坦的战斗即将打响。", + "{0.04->2.65}OH NO, I'M SORRY!": "{0.00->2.73}天哪,抱歉抱歉!", + "{0.00->2.64}Mess with eagles, you get talons!": "{0.00->2.30}尝尝飞鹰的利爪!", + "{0.12->5.91}Status: Liberation from Illuminate underway. Helldiver support requested.": "{0.00->5.91}状态:准备解放光能者。请求绝地潜兵支援。", + "{0.00->3.18}Alert: Defense of currently orbited planet from {3.63->7.68}Illuminate invasion has ended in absolute victory. {8.07->11.11}Planet remains under Super Earth control.": "{0.00->7.19}通知:当前星球抵御光能者入侵的行动已经大获全胜。{7.30->11.11}该星球仍归超级地球统治。", + "{0.03->1.67}The Pestis System": "{0.03->1.08}瘟厉星系", + "{0.00->0.91}Nothing in the chamber.": "{0.00->0.91}子弹都打光了。", + "{0.00->1.75}Is that really them?": "{0.00->1.75}这真的是他们吗?", + "{0.00->0.67}Terminid": "{0.00->0.67}终结族", + "{0.04->1.49}Hey, could you teach me that later?": "{0.00->1.60}嘿,待会儿能教教我吗?", + "{0.00->1.95}You being here means everything.": "{0.00->2.33}只要你在,就是最大的帮助。", + "{0.01->1.88}Get d--get down!": "{0.00->1.88}卧倒,快卧倒!", + "{0.00->1.52}Tactical asset nearby.": "{0.00->1.52}战术资产就在附近。", + "{0.00->4.76}Gettin' to show those good-for-nothin' squids that no amount of fancy tech beats good ol' fashioned {4.76->5.46}Democracy.": "{0.00->2.47}我要让那些一无是处的鱿鱼知道,{2.74->5.63}花哨的技术根本比不上传统的民主精神。", + "{0.00->2.92}Let the nutrients of their heroic tissue{3.59->7.95}fertilize the land they freed from mechanized tyranny.": "{0.00->2.34}让他们英勇躯体的养分{2.74->7.89}滋养这片从机械暴政手中解放出来的土地。", + "{0.03->1.39}GET DOWN!": "{0.00->1.43}快趴下!", + "{0.00->5.79}Cyberstan is the core from which the Cyborg and Automaton war machine emanates.{6.22->10.24}We must liberate it -- for the Freedom of the galaxy.": "{0.00->5.66}生化斯坦是生化人和机器人战争机器的核心源头。{6.15->10.28}为了银河系的自由,我们必须解放这颗星球。", + "{0.00->3.18}The Illuminate machinations evolve, Helldiver.{3.77->9.95}Planetwide storms erupt from the Exospires, engulfing planets in chaos.": "{0.00->3.73}绝地潜兵,光能者的阴谋诡计正在升级。{3.96->9.99}异界尖塔爆发出覆盖全球的风暴,将整个星球吞没在混沌之中。", + "{0.00->2.65}Of course. Liberty guide my hand.": "{0.00->2.65}没问题。解放指引我。", + "{0.00->3.78}Soldiers make tough calls, and that sometimes means friendly fire.": "{0.00->4.15}军人要面对艰难的抉择,有时伤害友方也没办法。", + "{0.00->0.47}That one.": "{0.00->0.47}那个。", + "{0.14->0.57}Oh, {1.03->5.72}I see you've secured some research samples. You can spend those at the terminal over there to {5.74->7.20}upgrade the Super Destroyer. {7.77->8.52}Get enough of them, {8.88->11.22}and we'll see what this baby can really do.": "{0.00->3.14}噢,你已经收集了一些研究样本。{3.45->7.46}可以在那边的终端使用样本升级超级驱逐舰。{7.87->12.38}收集足够的样本,我们就能见识这艘驱逐舰的真正实力。", + "{0.03->1.40}This will all be over soon.": "{0.03->1.40}很快就会没事的。", + "{0.02->1.22}Sweet Liberty, {1.87->2.38}my leg!": "{0.02->2.47}我超级自由的腿!", + "{0.00->1.75}Sub-objective near your location.": "{0.00->1.75}次要目标在你们附近。", + "{0.04->3.70}Strategic pivot! PIVOT! Falling back!": "{0.00->1.56}战略转移!{1.57->3.76}转移!先撤退!", + "{0.66->1.41}Take position, soldiers!": "{0.00->1.50}士兵们,各就各位!", + "{0.04->3.55}Super Uranium. Safe enough for babies.": "{0.04->3.55}超铀,对婴儿也完全无害。", + "{0.13->1.64}They died a hero.": "{0.03->1.28}英雄牺牲了。", + "{0.04->3.31}Whoa! That was even better than the recruitment videos!": "{0.00->3.22}哇!简直比征兵宣传片还精彩!", + "{0.04->4.02}My legs! For the love of Liberty, my legs!": "{0.04->4.02}我的腿!我超级自由的腿!", + "{0.00->0.69}Not engaging.": "{0.00->0.69}别打这个。", + "{0.00->0.73}Let's go,{1.10->1.76}Helldiver!": "{0.00->2.05}绝地潜兵,我们走吧!", + "{0.03->1.96}It brings a tear to my eye.": "{0.00->2.06}我热泪盈眶了。", + "{0.00->1.34}Deploying illumination flare.": "{0.00->1.34}部署照明弹。", + "{0.02->2.57}This biological sample will provide excellent data.": "{0.02->2.57}生物样本包含珍贵数据。", + "{0.00->1.38}Weapon Emplacement on its way.": "{0.00->1.38}武器炮台即将抵达。", + "{0.02->1.45}Ready to Liberate.": "{0.02->1.45}准备好解放。", + "{0.00->2.89}The specter of the Void grows.": "{0.00->3.00}寂域的幽魂正在壮大。", + "{1.70->2.12}I did my{2.77->3.12}part...": "{0.09->3.52}我尽力了……", + "{0.00->0.62}We made it!": "{0.00->0.93}我们成功了!", + "{0.02->1.47}It's going to cut me open!": "{0.02->1.47}它要把我给撕了!", + "{0.00->1.54}Super Uranium acquired.": "{0.00->1.72}超铀到手了。", + "{0.00->2.06}Liberty and Democracy!": "{0.00->2.21}解放和民主!", + "{0.01->2.10}The Helldivers will make them pay.": "{0.01->2.10}绝地潜兵会教它做人。", + "{0.00->0.31}No.": "{0.00->0.31}不行。", + "{0.00->0.54}Don't need it.": "{0.00->0.54}不需要。", + "{0.00->1.46}Calling in reinforcements!": "{0.04->1.16}呼叫增援!", + "{3.53->5.95}Nobody could have predicted what we'd find in the Void. But I never thought it would end like this.": "{0.00->3.70}谁也没料到我们会在寂域里发现什么。{4.22->6.73}居然会以这种方式结束。", + "{0.00->1.54}The Nabatea system": "{0.00->1.54}那贝塔星系", + "{0.03->1.89}Just like in the movies.": "{0.00->2.01}简直跟拍电影似的。", + "{0.00->0.90}Dropping package.": "{0.00->0.90}丢下物品。", + "{0.39->1.50}Stinking Fascist.": "{0.00->1.50}法西斯臭虫。", + "{0.00->1.35}Don't jam on me!": "{0.00->1.42}别掉链子!", + "{0.29->6.29}The Automatons desire this planet for their soulless machinations. Go down, and show them the light {6.29->7.20}of Liberty.": "{0.00->3.50}机器人要利用这颗星球实施冰冷的阴谋。{4.26->6.73}让它们见识一下解放之光。", + "{0.00->0.87}Enemy outpost.": "{0.00->0.87}敌方哨站。", + "{0.00->0.71}Right away. A{1.24->2.48}genius idea.": "{0.00->0.90}马上就去。{1.64->2.83}好主意。", + "{0.00->0.88}I need stims.": "{0.00->0.88}给我来一针。", + "{0.01->0.90}Item collected.": "{0.01->0.90}东西到手了。", + "{0.00->0.78}Helldiver.{1.85->5.64}At last, we foray into the Void.": "{0.00->1.69}绝地潜兵。{2.60->5.55}我们终于要深入寂域了。", + "{0.01->1.22}Everyone ok?": "{0.01->1.22}大家都没事吧?", + "{0.00->1.30}The Kuper system": "{0.00->1.30}库珀星系", + "{0.10->0.69}Help{1.15->2.10}me..!": "{0.00->2.32}救救我…!", + "{0.05->2.94}Wonder if I have anything left to donate to the war effort... {4.20->7.71}I could spend less on shower tokens, maybe.": "{0.05->3.14}不知道我还能为战争贡献些什么……{3.86->7.13}或许可以少买点淋浴代币。", + "{0.03->0.99}Over there!": "{0.03->0.99}在那边!", + "{0.00->1.28}Mission map updated.": "{0.00->1.28}任务地图已更新。", + "{0.00->1.52}I'll remember this forever.": "{0.00->1.52}我会永远记住你们的。", + "{0.01->0.57}On my way.": "{0.01->0.57}马上来。", + "{0.01->1.69}Target hit! Target hit!": "{0.01->1.69}命中目标!命中目标!", + "{0.00->3.42}Let us secure the sustinence of Super Earth.": "{0.00->3.42}为超级地球争取更美好的明天。", + "{0.00->0.39}Bugs.": "{0.00->0.39}虫族,", + "{0.02->0.68}Help!": "{0.02->0.68}救命!", + "{0.00->1.57}Their incursion failed, {1.98->3.49}as expected.": "{0.00->0.99}不出所料,{1.49->3.28}敌人的入侵失败了。", + "{0.00->2.93}Recruit expired. Reset course and send in next candidate.": "{0.00->0.94}新兵死亡。{1.14->2.96}重置训练场,叫下一位。", + "{0.04->0.82}Little help?!": "{0.00->0.81}搭把手?!", + "{0.04->2.84}Justice and hope, forever unfurled!": "{0.00->2.73}正义与希望,千载不变!", + "{0.03->1.86}Heroes do exist...": "{0.00->1.87}英雄真的存在……", + "{0.00->4.58}Helldiver! Every day, you put yourself at risk to defend freedom and liberty, and I just wanna say... {5.35->5.80}Thank you.": "{0.00->4.90}绝地潜兵!你每天都在冒着生命危险保卫自由和解放。我只想说…{5.35->5.80}谢谢你。", + "{0.01->1.87}Maybe this way!": "{0.01->1.87}去这边试试!", + "{0.02->1.15}Throwing supply beacon.": "{0.02->1.15}投掷补给信标。", + "{0.00->1.87}Mission preparation aborted.": "{0.00->2.05}当前任务准备已中止。", + "{0.04->2.52}What in the name of Freedom...?!": "{0.04->2.52}自由也有意外…", + "{0.00->1.34}That's how it's done.": "{0.00->1.44}赢得很自然。", + "{0.02->5.03}Let's move, people! Oh uh, out I mean, move out, spread out!": "{0.00->1.51}大家都动起来!{1.51->3.78}噢呃,我是说散开,{3.78->5.21}动起来,散开!", + "{0.03->1.27}This is where the shuttle lands?": "{0.03->1.27}运输船会来吗?", + "{0.00->1.23}I hope it hurt.": "{0.00->1.23}这下够狠了吧。", + "{0.00->1.33}Democracy conquers all.": "{0.00->1.51}民主征服一切。", + "{0.00->1.87}Maintain your resolve!": "{0.00->1.57}坚定决心!", + "{0.00->2.36}Helldiver KIA. Deploying replacement.": "{0.00->2.36}绝地潜兵阵亡。部署替补。", + "{0.05->6.58}The bots will stop at nothing to turn our galaxy into little more than steel and code. {7.06->10.63}Unless we stop them first. Unless we send in...{10.99->12.16}the Helldivers.": "{0.05->2.88}机器人不顾一切也要向我们开战,{3.30->8.15}如果战败,整个星系就会只有冰冷的钢铁和无情的代码,{8.70->12.95}除非我们先下手为强,派出...绝地潜兵。", + "{0.04->2.53}Medic! Now!": "{0.76->2.72}针呢!赶紧的!", + "{0.00->1.22}I'm inspired!": "{0.00->1.33}我充满了力量!", + "{0.00->2.36}This Tyranny will not stand!": "{0.00->2.09}暴政绝不会得逞!", + "{0.00->2.34}Blast 'em back where they came from! Woo!": "{0.00->2.57}把它们轰回老家去!哇哦!", + "{0.00->0.64}What about here?": "{0.00->0.69}要不去这里?", + "{0.06->3.78}Don't let 'em get any closer! Shoot! SHOOT!": "{0.00->1.69}别让它们再靠近了!{1.69->3.83}射击!射击!", + "{0.00->1.36}Welcome aboard, Helldiver, {1.85->4.27}and congratulations on completing your training.": "{0.00->1.96}绝地潜兵,欢迎登舰,{2.26->3.97}还要恭喜你完成训练。", + "{0.00->3.89}Sometimes I read too much and get overly motivated and kinda jittery and need to put it down.": "{0.00->3.89}有时候我读得太多了,斗志会过于旺盛,我就得把书收起来。", + "{0.00->0.95}Take this!": "{0.00->1.05}快用这个!", + "{0.02->5.75}Argh! Always knew I'd... go down... for the right to vote...": "{0.00->3.61}啊!为了捍卫投票权,{3.62->6.08}我无怨无悔……", + "{0.00->1.71}I am a soldier of Democracy.": "{0.00->1.71}我是民主的战士。", + "{0.02->1.62}Everyone into cover!": "{0.00->1.68}所有人进掩体!", + "{0.00->2.32}Only Democracy tells US what to do!": "{0.00->2.28}我们只听民主的号召!", + "{0.00->0.47}3!": "{0.00->0.47}三!", + "{0.00->1.34}Local fauna.": "{0.00->1.34}当地动物。", + "{0.00->0.91}Flag acquired.": "{0.00->0.91}旗帜到手了。", + "{0.00->3.90}Our city returns to Freedom's warm embrace.": "{0.00->3.90}城市重回自由的温暖怀抱。", + "{0.00->6.56}The squids perform some arcane, sickening ritual at the base of their Exospires.{7.09->10.03}We cannot understand their revolting culture;{10.54->12.12}only annihilate it.": "{0.00->5.84}鱿鱼在异界尖塔底部举行某种神秘恶心的仪式。{6.29->12.15}我们无法理解它们的恶心文化,只能将其彻底消灭。", + "{0.00->2.42}We'll finish what you started, Helldiver.": "{0.00->2.69}绝地潜兵,我会完成你的遗志。", + "{0.00->1.88}Let's settle the score!": "{0.00->1.49}我们去找敌人算账!", + "{0.00->2.50}We destroyed the Illuminate once.{2.53->5.17}Now, we will do it again.": "{0.00->2.32}我们曾经消灭过光能者,{2.74->5.40}现在不过是再来一次。", + "{0.06->4.29}The Automatons are stealing from our citizens. We can't let them get away with it.": "{0.06->4.29}机器人在抢夺我们公民的财产。绝不能让它们得逞。", + "{0.00->2.52}Moradesh was lost to the Dark Fluid. {2.95->4.72}Our enemies will pay.": "{0.00->2.52}整颗莫拉戴什星都被暗液体吞噬了,{2.95->4.72}敌人必将为此付出沉重代价。", + "{0.18->0.95}Attack!": "{0.00->1.08}进攻!", + "{0.02->1.02}When's the shuttle coming?": "{0.02->1.17}运输船什么时候到?", + "{0.01->1.04}We're saved.": "{0.01->1.04}我们得救了。", + "{0.00->0.56}Fifth one.": "{0.00->0.56}第五个。", + "{0.02->2.76}Gah! No, this can't--": "{0.00->2.67}呃!不,不可能——", + "{0.22->1.58}It's gonna cut me open!": "{0.00->2.03}它快把我给撕了!", + "{0.01->0.93}My friend!": "{0.01->0.93}战友!", + "{0.02->1.19}This is a nightmare!": "{0.02->1.07}太吓人了。", + "{0.00->1.49}Human assets relocated.": "{0.00->1.49}已转移人力资产。", + "{0.43->1.09}\"Sure,\" Danny said. \"{2.96->3.25}They aren't really my friends anymore, anyway.\"": "{0.10->3.41}丹尼说:“没问题,反正他们已经算不上我的朋友了。”", + "{0.00->1.34}Should'a just shaken hands.": "{0.00->1.58}刚才就该直接握手的。", + "{0.31->2.35}I know what that means!": "{0.89->2.55}这个我可门儿清", + "{0.15->3.66}I've never seen such flawless terminal activation. {4.38->8.27}Now, somewhere around here is the flag of Super Earth. {8.73->13.16}Find it, and plant it where all can see its Democratic glory.": "{0.15->2.26}完美的终端启动操作。{2.78->6.72}现在,附近的某个地方有超级地球的旗帜。{7.24->13.16}找到这枚旗帜,把它竖起来,让所有人都能见到民主之光。", + "{0.00->0.34}Down.": "{0.00->0.49}下方。", + "{0.03->2.55}Back under the control of FREEDOM!": "{0.00->2.51}再次收归自由的掌控!", + "{0.00->3.13}I sure am famished from all that Liberating I've been doing. {3.57->10.94}And when Helldivers get hungry, Helldivers eat Prosperitos. Prosperitos: a little taste of Freedom {11.03->12.18}in every bite.": "{0.00->3.13}一直忙着解放,可把我饿坏了。{3.57->7.54}绝地潜兵饿了就会吃繁荣脆角。{8.09->12.20}繁荣脆角,每一口都是自由的滋味。", + "{0.05->2.60}Ugh, not in front of the Diver...": "{0.00->2.71}呃,不能倒在潜兵面前……", + "{0.00->1.19}Orbital inbound!": "{0.00->1.19}轨道攻击来了!", + "{0.01->2.96}Duty... called...": "{0.01->3.56}使命…在召唤我…", + "{0.00->0.59}Of course.{1.34->3.14}Liberty guide my hand.": "{0.00->0.69}没问题。{1.32->2.68}解放指引我。", + "{0.02->1.71}The Aesir Pass system": "{0.02->1.71}亚萨关隘星系", + "{0.00->2.82}Super Uranium. Safe enough for babies.": "{0.00->2.82}超铀,对婴儿也完全无害。", + "{0.01->1.21}Fire in the hole.": "{0.01->1.21}小心手雷。", + "{0.02->1.22}Sending in an Eagle.": "{0.02->1.22}请求出动“飞鹰”。", + "{0.00->1.73}The Widow's Harbor system": "{0.00->1.73}寡妇港星系", + "{0.04->2.82}Gotta fix this Liberty-forsaken arm.": "{0.04->2.82}必须治好这条耽误解放的胳膊。", + "{0.03->6.92}Alert: Liberation of currently orbited planet from Automaton menace has ended in {7.28->8.52}temporary defeat. {9.07->12.49}Planet remains under Automaton control.": "{0.00->8.00}通知:击退机器人威胁,解放当前星球的行动暂时失利。{8.11->12.49}该星球仍归机器人统治。", + "{1.58->3.21}Managed Democracy: {4.94->7.36}The freedom to make the right choice.": "{1.58->3.21}管理式民主:{4.57->7.36}作出正确选择的自由。", + "{0.01->0.91}Reloading.": "{0.01->0.91}换弹。", + "{0.00->0.62}Engaging.": "{0.00->0.62}打这个。", + "{0.02->3.75}Super Destroyer crew assignments are some of the most sought-after in the fleet. {4.28->6.76}Everyone wants to be on a Helldiver's destroyer.": "{0.02->3.46}在超级驱逐舰服役是舰队里最抢手的职务。{3.72->6.57}所有人都想在绝地潜兵的驱逐舰上效力。", + "{0.00->0.75}Enemy elite.": "{0.00->0.84}敌方精英,", + "{0.00->0.76}Southwest.": "{0.00->0.76}西南,", + "{0.00->2.25}S'gotta be somewhere safe!": "{0.00->2.25}肯定会有安全的地方!", + "{0.08->3.93}Let our enemies choke upon their territorial ambitions.": "{0.08->3.93}让敌人好好反思,自己扩张的野心。", + "{0.00->1.96}Taste Justice, robot scum!": "{0.00->2.19}铁皮渣滓,尝尝正义!", + "{0.00->0.74}Looking good,{1.11->1.87}Helldiver!": "{0.00->2.04}绝地潜兵,干得好!", + "{0.01->1.93}Bugs! Run!": "{0.01->1.93}虫子!快跑!", + "{0.33->1.32}The Oroth system": "{0.33->1.32}欧拉斯星系", + "{1.32->3.00}Ugh, flags in rags, that hurts!": "{0.00->1.99}呃,插他旗的,{2.06->3.70}好疼!", + "{0.03->5.10}It was a little uncomfortable, but every citizen has to learn about the threats to Democracy at some point.{5.10->6.23}Just part of growing up.": "{0.03->3.96}当时感觉有点奇怪,但是每个公民都迟早要了解民主面临的威胁。{4.21->6.23}这是成长的必经之路。", + "{0.03->6.40}Shielded from Super Earth's truth, the Illuminate have fashioned unspeakable horrors.{7.20->9.22}The absence of Democracy,{9.81->11.97}wrought into being.": "{0.00->3.54}光能者躲在真理难以普及的角落,{3.81->7.31}炮制出不可名状的恐怖存在。{7.68->12.71}这就是“缺失民主”的具象化呈现。", + "{0.00->1.34}The Charon system": "{0.00->1.34}卡戎星系", + "{0.00->1.28}They're coming soon, right?": "{0.00->1.45}他们快到了,对吗?", + "{0.00->1.43}Extraction Shuttle inbound.": "{0.00->1.43}撤离运输船即将抵达。", + "{0.33->1.40}No way....": "{0.17->1.26}怎么可能…", + "{0.00->2.91}The Scutum Canis Lupus System": "{0.00->1.05}狼盾星系", + "{0.03->1.23}It's going to cut me open!": "{0.03->1.23}它要把我给撕了!", + "{0.01->1.14}Frag out!": "{0.01->1.14}小心手雷!", + "{0.01->2.04}This can't be happening!": "{0.01->2.04}这不可能!", + "{0.04->1.78}Sweet Liberty, we're saved!": "{0.05->1.62}解放大业来救我了!", + "{0.04->1.49}The Acrux system": "{0.04->1.49}十字架二星系", + "{0.00->1.91}Sweet Liberty, it's the bots!": "{0.00->2.40}解放你大业的,是机器人!", + "{0.03->3.30}Now we're part of Super Earth's victory.": "{0.03->2.89}一切为了超级地球。", + "{0.00->0.31}Take cover!": "{0.00->0.90}快找掩体!", + "{0.06->1.47}Socialist scum.": "{0.06->1.47}破铁皮坨子。", + "{0.00->0.57}You know, {1.13->4.03}this Destroyer has enough ordnance to level a small moon. {4.73->6.51}I've done the calculations myself.": "{0.00->4.42}话说,这艘驱逐舰的武器足以摧毁一颗小型卫星。{4.82->6.51}我自己算过了。", + "{0.02->2.51}The power of a Helldiver...": "{0.00->2.68}这就是绝地潜兵的力量……", + "{0.01->2.73}Helldiver -- no! Noo!": "{0.01->2.73}绝地潜兵,不!不!", + "{1.10->2.07}Hah! As expected!": "{0.00->2.14}哈!毫不意外!", + "{1.06->2.47}Democracy above...": "{1.09->2.19}民主在上…", + "{0.00->1.17}Makes me wanna go Vote right now!": "{0.00->2.25}我现在就想去投票!", + "{0.00->1.73}The Fronteria System": "{0.00->1.04}边陲星系", + "{0.04->1.92}Kill them! Kill them!": "{0.04->1.92}杀了它们!快杀了它们!", + "{0.00->1.65}Uninhabitable System": "{0.03->1.23}不宜居星系", + "{0.03->2.83}To the new front! Liberty awaits!": "{0.00->2.87}继续向前推进!离解放不远了!", + "{0.00->1.28}The Haka system": "{0.00->1.28}哈卡星系", + "{0.02->0.70}They're back!": "{0.02->0.70}它们回来了!", + "{0.01->1.16}They'll regret this.": "{0.01->1.16}它们会后悔的。", + "{0.01->2.05}Shake it off, Helldiver!": "{0.01->2.46}绝地潜兵,坚持住!", + "{0.00->1.49}Item collected.": "{0.00->1.49}东西到手了。", + "{0.00->2.26}DEMOCRACY FOR ALL!": "{0.00->2.32}民主人人有份!", + "{0.00->0.54}Engaging.": "{0.00->0.54}来打这个。", + "{0.00->0.87}ETA T-{1.29->2.86}2 minutes and 30 seconds.": "{0.00->0.87}预计2分3{1.29->2.86}0秒后到达。", + "{0.17->0.76}Yeah!": "{0.00->0.84}没错!", + "{0.02->2.86}Come on team, the Helldiver's watching!": "{0.00->2.90}大家努力,绝地潜兵在看着呢!", + "{0.00->3.24}Super Earth protect us!": "{0.00->4.74}超级地球保佑我们.!", + "{0.00->2.48}Deploying explosive munitions!": "{0.00->2.57}正在部署爆破性炸药!", + "{0.00->1.20}Calling down a vehicle.": "{0.00->1.20}请求载具支援。", + "{0.00->1.54}I fight for Freedom.": "{0.00->1.72}我为自由而战。", + "{0.00->2.49}Managed Democracy calls for aid. {3.01->5.31}Only you can answer, Helldiver.": "{0.00->2.22}管理式民主呼叫援助,{2.79->5.67}绝地潜兵,只有你能应答。", + "{0.01->0.94}Heads down!": "{0.01->0.58}低头!", + "{0.00->2.23}You have maintained our way of life.": "{0.00->2.23}你保卫了我们的生存正道。", + "{0.00->0.84}Deep breaths...": "{0.00->0.97}深呼吸……", + "{0.00->1.35}On your feet, soldier!": "{0.00->1.47}士兵,站起来!", + "{0.02->1.40}Hostiles, inbound!": "{0.02->0.95}敌人要来了!", + "{1.90->5.24}I've... seen worse...": "{1.90->5.61}这…不算什么…", + "{0.00->2.21}One step closer to victory!": "{0.00->2.28}离胜利又近了一步!", + "{0.01->1.24}Watch out for mines!": "{0.00->1.28}小心地雷!", + "{0.00->0.92}Helldiver. {1.39->8.16}The Illuminate raise strange, otherworldly spires from the depths of the planets they occupy.": "{0.00->0.98}绝地潜兵。{1.58->5.29}光能者占领了星球,在星球深处{5.56->8.60}竖起了奇异的异界尖塔。", + "{0.00->0.47}Vehicle.": "{0.00->0.47}载具,", + "{0.00->2.03}Cyberstan used to be a good planet, you know?{2.48->4.45}Wasn't called \"Cyberstan\" back then, of course.": "{0.00->2.43}生化斯坦以前是颗好星球,你知道吗?{3.27->5.43}当然,那时候还不叫\"生化斯坦\"。", + "{7.50->11.92}Freedom's Greetings, I'm Coretta Kelly, with breaking news.{12.15->19.30}A scientific breakthrough has been made using the strange liquid found on Terminid Hive worlds.{19.49->26.09}This biological substance appears to be a more concentrated form of Element 710.{26.09->29.84}Scientists have named it \"Element 711.\"{30.46->32.68}In a watershed moment for science,{32.68->42.96}Element 711 has been successfully converted into Dark Fluid - the first-ever synthetic production of the powerful exotic matter.{43.38->48.10}The Gloom is believed to contain vast reserves of E-711.{48.56->55.89}The Helldivers have been ordered to shift their focus to maximizing extraction of the valuable resource.{56.23->60.04}That's Liberty's Latest; I'm Coretta Kelly.": "{7.50->11.92}自由向各位问好,我是科雷塔·凯利,为您带来突发新闻。{12.15->19.30}我方利用在终结族虫窝世界发现的奇异液体取得了科学突破。{19.49->26.09}这种生物物质似乎是710元素的浓缩形态。科学家将其命名为“711元素”。{26.09->29.84}科学史迎来里程碑时刻,{30.46->32.68}711元素已成功转化为暗液体,{32.68->42.96}这是首次人工合成这种强大的奇异物质。{43.38->48.10}据信“阴霾”蕴含着大量711元素。{48.56->55.89}绝地潜兵奉命将重点转向最大限度开采这种宝贵资源。以上就是今天的《解放新闻》,{56.23->60.04}我是科雷塔·凯利。", + "{0.00->1.13}Sample collected.": "{0.00->1.13}样本到手了。", + "{0.03->1.07}Need stims!": "{0.00->1.16}给我来一针!", + "{0.02->1.00}Get it away from me!": "{0.02->1.00}快帮我把它弄走!", + "{0.16->1.83}I feel stronger already.": "{0.00->1.91}我感受到了力量。", + "{0.02->1.94}Rare sample acquired.": "{0.02->1.94}稀有样本到手了。", + "{0.00->3.51}We'll burn Cyberstan to the ground.": "{0.00->3.19}我们会把生化斯坦烧成灰烬。", + "{0.00->1.45}Requesting sentry.": "{0.00->1.45}请求哨戒炮。", + "{0.04->2.41}Dig in, soldiers! Hold this line!": "{0.00->2.53}守住,战士们!死守防线!", + "{0.05->1.70}For Super Earth!": "{0.00->1.94}为了超级地球!", + "{0.00->0.45}You win.": "{0.01->0.63}你赢了。", + "{0.05->2.17}Super Earth forever!": "{0.00->2.32}超级地球永垂不朽!", + "{0.01->0.80}What is that?": "{0.01->0.89}是什么东西?", + "{0.03->1.95}Enemy outpost spotted. Look alive.": "{0.03->1.95}是敌方哨站,看来有敌人。", + "{0.09->3.61}Did you know that Cyborgs don't have hearts? It's true!{3.61->10.92}And no brains either, apparently—that must be how they were able to betray Managed Democracy a hundred years ago.": "{0.09->2.95}你知道生化人没有心脏吗?真的!{3.52->6.52}显然它们也没有大脑,这样才能解释{6.87->9.94}为什么它们一百年前会背叛管理式民主。", + "{0.03->1.95}I'm up, I'm up!": "{0.00->2.00}我没事了,没事了!" + } +} diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/doc/hd2_zh_full.tsv b/hexi/plugins/nonebot_plugin_helldivers_tools/doc/hd2_zh_full.tsv new file mode 100644 index 0000000..e9727bb --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/doc/hd2_zh_full.tsv @@ -0,0 +1,12740 @@ +Key English 简体中文 +508428638 - - +1151769130 —MINISTRY OF DEFENSE ——国防部 +1852893584 —PRESIDENT OF SUPER EARTH ——超级地球总统 +4264688332 —PRESIDENT OF SUPER EARTH ——超级地球总统 +1594599891 , , +3298627204 , , +1888183316 ? ? +2363985044 .LOG 日志 +1310979905 '#TEXT' “#TEXT” +2024515668 "Alert: due to increased local hostile activity, all funerals are to use Expedited Internment Procedures until further notice." “警告:由于当地敌对活动激增,全部葬礼须使用加急安葬程序,直至另行通知。” +3730334434 "Attention: Your Animal Companion Request for [1] [hamster] has been denied at this time." “注意:你对圈养[1]只[仓鼠]作为陪伴动物的申请本次已拒绝。” +315220150 "Cache Inventory: +-300 rounds Liberator ammo +-14 stims +-12 gallons water +-3 frag grenades" “隐藏库存: +- 300发“解放者”弹药 +- 14支治疗剂 +- 12加仑水 +- 3枚榴弹” +3919223647 "CLOSE CALL" AT DARK FLUID FACILITY 暗液体设施发生“惊险”事件 +1175196149 "Colonial alert: due to budgetary constraints, dwelling temperatures will be lowered by [13%]." “拓殖地警告:由于预算受限,住宅温度将降低[13%]。” +952870686 "Concerns of mine safety, including long hours, dim tunnels, insufficient supports, rickety ladders, etc., have been noted, considered, and addressed. Please continue with renewed confidence in your safety." “工作时间长、隧道昏暗、支援不足、梯子摇晃等矿井安全问题已获关注、斟酌和解决。请重拾对人身安全的信心,继续作业。” +119363641 "Congratulations on Procreation Approval for [1] child. May you multiply the love of Democracy for generations to come." “祝贺你获准生育[1]个孩子。愿你将对民主的热爱传承给后世子孙。” +1290317954 "Congratulations on your acceptance to Trailblazer University, the premier online educational institution for tomorrow's colonial leaders." “祝贺你被开拓者大学录取,这是培养拓殖地未来领袖的一流在线教育机构。” +1455663094 "Deliver to Terminids ASAP" “尽快送至终结族” +1888359229 "Diet Democracy. Free yourself." “饮食民主。解放自我。” +1987986869 "Do not operate without a ground guide." “必须有地勤人员指引。” +1554836788 "Don't forget to vote on YOUR colony's Patriot of the Month!" “别忘了投出宝贵一票,选出你所在拓殖地的‘本月爱国者’!” +2050982497 "Don't forget! Catch the bi-weekly State of the Federation announcement at 8PM tonight (absence must be pre-approved)." “别忘了!请准时收看今晚8点播出的双周联邦政府通报(需获批准才能缺席)。” +4197052020 "Dr. Democracy: With 17 seasonings and additives" “民主博士:包含17种配料和添加剂” +2848746371 "Due to the exceptional hazard of the current posting, all SEAF soldier's and their approved domestic family units will be granted Class C citizenship following mission completion or death." “由于目前外派任务特别危险,所有参加任务的超级地球武装部队士兵与其获批家属都将在任务完成或阵亡后获得C级公民身份。” +1036715918 "EMERGENCY WARNING: Hostile forces incoming. Evacuate immediately. EMERGENCY WARNING: Hostile forces incoming. Evacuate immediately." “紧急警告:敌方军队即将抵达。立即撤离。紧急警告:敌方军队即将抵达。立即撤离。” +2706258613 "Enter Now for a Chance to Win Front-Row Tickets to The Freedomball Galactic Cup!" 立刻参加即有机会获得自由球星系杯比赛前排门票! +2453875425 "Eulogy Template—Soldier, Exemplary Service 121: The heroism of [Rank] [Name] cannot be understated. They did not lose their life in the defense of Super Earth. They gave it, willingly." “悼词模板 - 士兵,模范军人121版:[军衔][姓名]的英勇精神不可估量。这位英雄并非因为保卫超级地球而丧命,而是心甘情愿献出生命。” +599823837 "Eulogy Template—Soldier, friendly fire variation 016: [Name] devoted many hours to the prosperity of Super Earth. They may rest easy in the knowledge that the [bullets/shrapnel/concussive force] that took their life was Democratic in origin and fired in the service of Liberty." “悼词模板 - 士兵,友军误伤016版:[姓名]为超级地球的繁荣鞠躬尽瘁,将安然长眠,因为夺走其生命的[子弹/弹片/武装]是为民主而发,是为解放而战。” +1813328760 "Eulogy Template—Soldier, variation 004: [Rank] [Name] joined the service at [age]. They served [noble adverb] and perished heroically while fighting [enemy]. We will never forget their [unique trait]." “悼词模板 - 士兵,004版:[军衔][姓名]在[年龄]时入伍,[体现崇高品质的副词]服役,在与[敌人]作战时英勇牺牲。我们永远不会忘记这位英雄的[独特品质]。” +390649935 "For alien scum" “致异形渣滓” +3023277177 "FOR THE DISCOVERY AND SYNTHESIS OF TERMICIDE" “发现并合成灭虫终结剂” +1865943011 "Freedom of Expression" Bill Passes Into Law, 《表达自由》法案通过审议 +3637654068 "From Super Earth With Love" “来自超级地球,饱含热爱” +2436288325 "Get some!" “尝尝我们的厉害!” +1778996632 "Handle with care" “小心轻放” +515860602 "Happy Liberty Day, bugs!" “虫子们,解放日快乐!” +3350686635 "Have a taste of freedom!" “这就是自由的力量!” +348575717 "HELLDIVER TRAINING FACILITY +Welcome to Helldiver Training +EARN YOUR CAPE +CHECK YOUR MAP TO FIND THE HELLDIVER FACILITY" “绝地潜兵训练基地 +欢迎接受绝地潜兵的训练 +努力赢得披肩吧 +查看地图,寻找绝地潜兵基地设施” +3833198954 "HELLDIVER TRAINING FACILITY" “绝地潜兵训练基地” +437568186 "IT IS PAST TIME WE RESPONDED TO THIS UNPROVOKED INCURSION AGAINST DEMOCRACY. THE HELLDIVERS ARE DEPLOYING AS WE SPEAK TO STRIKE A NUMBER OF AUTOMATON MILITARY INSTALLATIONS. THESE INVADERS WILL SOON DISCOVER THE STEEL OF SUPER EARTH RESOLVE." “我们早该对这种无端侵犯民主的行为加以还击。就在此时此刻,绝地潜兵已经出动,针对机器人的多处军事设施发起攻击。这些入侵者很快就会发现,超级地球的决心坚如钢铁。” +2654073100 "Local hostile activity is currently assessed as LOW THREAT. All citizens are to continue duties until further notice." “当地敌对活动目前被评估为‘低威胁’。所有公民继续履行职责,直至另行通知。” +2459063269 "Memo to all SEAF forces: Moving forward, frontline mail services will be reserved for soldiers of exceptional democratic service only." “发送给超级地球武装部队全体成员的备忘录:随着部队的推进,前线邮政服务将仅对作出特殊民主贡献的军人开放。” +2719222461 "Memo to Colonial Overseer: Be sure to calibrate the productivity output of your workers in accordance with your Compliance Index." “拓殖地监督员备忘录:务必按照服从指数校准工人的生产力输出。” +2893623201 "Memo to Colonial Overseer: In order to best serve Freedom, the security budget for your colony will be reduced by [23.7%] for the next fiscal term." “拓殖地监督员备忘录:为了更好地为自由服务,你所在拓殖地的安全预算将在下一个财政任期内减少[23.7%]。” +4118649839 "Ministry of Defense study indicates enemy morale reaching new, unprecedented lows." “国防部研究显示,敌人的士气正达到前所未有的低点。” +3255839399 "Ministry of Truth Library Branch 301C" “真理部图书馆301C分馆” +2365925959 "My Son Was An Automaton Sympathizer." One Mother's Valiant Choice To Turn In Her Son. “我儿子同情机器人”——女子大义灭亲,举报亲生儿子 +885191753 "Next week's delivery: + -4 Liberators + -2 cases prefab meals +-Fuel drum" “下周交付: +- 4把“解放者” +- 2箱预制饭菜 +- 燃料桶” +730295732 "Next! + +Buy war bonds." “下一个目标! + +购买战争债券。” +2658730238 "Not suitable for traitors of democracy." “不适合民主的叛徒。” +2572052001 "Note to Grave Preparation Specialist: due to high hostile activity in the area, graves may be required to accomodate more personnel than usual." “墓地整备专员注意事项:由于该区敌对活动频繁,需要下葬的人数多于正常水平。” +3346567964 "Notice to Colonists: A military operation is being conducted in your vicinity. There is no need for alarm. Please remain indoors until further notice." “拓殖地居民请注意:附近正在执行军事行动。不必担心。请留在室内,等待另行通知。” +2082344782 "Offerings include: Dr. Democracy, Mr. Taste, Prof. Delicious, & Yummm, Esq." “供应:民主博士、美味先生、好吃教授与可口先生。” +4054366495 "ORDER: Do not retreat. Defend Liberty at all costs." “命令:不要撤退。不惜一切捍卫解放事业。” +4285699421 "PEACE IS NOT AN OPTION. THE AUTOMATONS “和平共存是不可能的。 +1476542856 "PEACE IS NOT AN OPTION. THE AUTOMATONS ARE PROGRAMMED FOR 2 THINGS: VIOLENCE, AND HATING FREEDOM." “和平共存是不可能的。这些机器人的程序里只写了两样东西:暴力,以及憎恨自由。” +3940634112 "Pesticide" “杀虫剂” +467457185 "Please present this certificate as proof of approval to perform a left-handed salute for the duration of your injury." “请出示这张许可,证明你已获准在受伤期间用左手敬礼。” +2318053846 "Please refrain from operating heavy machinery while consuming this beverage." “享用这种饮料时,请勿操作重型机械。” +2631473995 "Please report immediately to your Loyalty Officer for investigation. Reason: [Citizen Report of Dissident Speech]." “请立即向你的忠诚事务官举报以便展开调查。理由:[公民举报异见分子言论]。” +2662913543 "Please select which delicious flavor you would like to see included in our colony's next seasonal rations: Blueberry, Chocolate, Cinnamon, Birthday Cake." Birthday Cake is selected. “请选择你希望在拓殖地下一季口粮中尝到的口味:蓝莓、巧克力、肉桂、生日蛋糕。”已选择生日蛋糕。 +1115943936 "Prowl like a jaguar, strike like a viper." -Motto of the storied SEAF special operations unit whose real exploits were portrayed in the classic comic book series "Tales of the Viper Commandos." “巡如豹,袭如蛇。”这是传奇超级地球武装部队特别行动组的座右铭。经典漫画《毒蛇突击队的故事》真实描绘了他们的丰功伟绩。 +234584469 "Pulsar Pop" Dance Craze Sweeps Galaxy “脉冲星波普”舞蹈热潮席卷全星系 +4162633951 "Remember: complaints are the gateway to dissidence." “记住:抱怨是通往异见之门。” +1504996095 "Remember: late returns steal from us all." “切记:逾期归还等同于偷窃公共财物。” +2398394710 "Reminder: Planetary Overseer elections are just around the corner!" “提醒:行星监督员选举已近在眉睫!” +574562412 "Super Earth Plasma-Sniper" Smashes Box-Office Records. 《超级地球等离子狙击手》轻松突破票房纪录 +1637054009 "SUPERCOLONY" “超级拓殖地” +667736962 "The Charger continues to display increased agitation upon exposure to imagery of Helldivers. Possible evolved response?" “强袭虫在看到绝地潜兵的图像后越来越躁动不安。可能是进化后的反应?” +683910113 "The Colonial Overseer's Handbook. A guide to Planetary Terraforming, Resource Extraction, and Colonist Management. Approved by the Ministry of Expansion." “《拓殖地监督员手册》,行星地球化、资源开采和拓殖地居民管理指南。经扩张部审核通过。” +2148749086 "The ground is just another obstacle that hasn't yet been cleared." - SGM Janet Jones, Excavation Corps Founder. “大地不过是另一道有待清除的阻碍。”——上士珍妮特·琼斯,挖掘部队创始人。 +1539144554 "The Helldivers are all that stand between Democracy and the Fascist hordes. Trained since birth in the art of Defensive Warfare, they meet mindless legions with the steady aim of one who has seen countless battles." —Excerpt from the journal of a Charan Democracy Officer, ca. 2082 SE “绝地潜兵是阻挡在民主与法西斯暴民之间的唯一屏障。他们自出生起就接受防御战争的训练,以久经沙场的沉稳精准迎击无脑军团。”——摘自常陈四民主官日记,超级地球历2082年前后 +2656947245 "The Ministry of Humanity has processed your missing persons report. Result: [CLOSED.] Conclusion: [Mine mishap.]" “人道部已处理你的失踪人口报告。结果:[已结案。]结论:[矿井事故。]” +1072626935 "The Ministry of Humanity regrets to learn of the tragic loss of your family member. Please follow the enclosed instructions for proper patriot disposal and tax forms." “得知你痛失家人,人道部深表遗憾。请按照随附的说明妥善处理爱国者的遗体及纳税表格。” +2724107978 "The Ministry of Humanity would like to congrulate you on approval for marriage. Enclosed are instructions for consolidating domiciles." “人道部祝贺你们获得婚姻许可。随函附上住所合并说明。” +880679518 "The Ministry of Science reminds all citizens of the numerous citizenship benefits to enrolling yourself and you family in medical studies. Could your body be of greater use to Liberty?" “科学部提醒各级公民全体成员,全家加入医学研究,益处良多。你愿意全身心贡献给解放事业吗?” +4249190617 "The Ministry of Truth would like to remind all citizens that un-Democratic reading material must be reported immediately." “真理部温馨提醒全体公民,如果发现非民主读物,务必立即上报。” +4111700630 "THIS ATTACK OCCURRED AS WE WERE NEARING A “此次袭击的发生时间正值我们 +3908624458 "To Whichever Terminids It May Concern" “至拿到此物的终结族” +2937633613 "Took stash. Needed it. Sorry. + P.S. This man was dead when I got here. +-D" “拿走了隐蔽装备。急需。抱歉。 +注:我到的时候这个男人就已经死了。 +-D” +2988205947 "Was low on supplies. Took ammo. Left oatmeal. Good luck -D" “补给短缺。拿走了弹药。留下了燕麦片。祝你好运 -D” +1181082576 "We fear not poison, fear not death; spite our foes with every breath." From the beloved classic Hazard Pay: The Musical. “我们不惧毒药,不畏死亡;每一次呼吸都让敌人破防”。选自广受喜爱的经典作品音乐剧《危险津贴》。 +425538989 "Welcome! Please note: failure to feel sufficiently welcomed should be reported immediately." “欢迎!请注意:如果未能感受到足够热烈的欢迎,请立即举报。” +1797704118 "Where lesser soldiers break, Helldivers obey. When Tyranny's horrors swarm, Helldivers obey. When death is certain, and hope and sense have fled, Helldivers obey." — Last Lord Governor of Chara. “寻常士兵溃不成军之时,绝地潜兵谨遵号令。暴政恐怖肆虐之际,绝地潜谨遵号令。当死亡已成定局、希望与理智破灭,绝地潜兵谨遵号令。”——常陈四最后一任总督。 +3978938678 "You are legally required to report any Terminid attacks to the authorities!" “依照法规,只要终结族发动攻击,你必须向当局汇报!” +566160508 (#COUNT) (#COUNT) +1620218677 (#MINSm #SECSs) (#MINSm #SECSs) +292118985 (#MINUTES #MIN_UNIT#SEPARATOR#SECONDS #SEC_UNIT) (#MINUTES #MIN_UNIT#SEPARATOR#SECONDS #SEC_UNIT) +1938562248 (personally) (独自) +2126742737 (optional) (可选) +3008445168 [ DATA FOUND ] [ 已找到数据 ] +2136758710 [ Press [ 按下 +2433320646 [#MINUTES:#SECONDS] [#MINUTES:#SECONDS] +1017534811 [#NAME] [#NAME] +823367019 [#X/#Y] [#X/#Y] +1227558885 [none] [无] +3182784048 [Redacted] [已编辑] +83689656 [REDACTED] [已涂黑] +4291384188 [Stuff in the hospital scene, maybe] [疑似医院内物品的场景] +812134137 [THIS TEXT IS NOT IMPLEMENTED] [文本未应用] +652196257 ] ] +769472326 / #CAP / #CAP +3649943605 / #TOTAL / #TOTAL +1752319148 ###COUNT ###COUNT +2565732693 #A (#PERCENT%) #A (#PERCENT%) +4155114762 #A / #B #A / #B +4243487113 #A • #B #A • #B +3452784529 #A • #B • #C #A • #B • #C +2667748644 #A/#B (#PERCENT%) #A/#B (#PERCENT%) +735690599 #AMOUNT #AMOUNT +3696589763 #AMOUNT #AMOUNT +1769576572 #COMMAND #COMMAND +732570791 #COUNT #COUNT +2389233478 #COUNT #COUNT +3330047919 #COUNT #COUNT +1897839356 #COUNT [SC] #COUNT [SC] +3329138841 #COUNT / #TOTAL #COUNT / #TOTAL +3699092797 #COUNT / #TOTAL STREAK #COUNT / #TOTAL次连续击杀 +4012919236 #COUNT BONUS SC #COUNT额外超级货币 +45657933 #COUNT confirmed kills #COUNT次击杀 +1212894817 #COUNT DAYS AGO #COUNT天前 +2353733085 #COUNT HOURS AGO #COUNT小时前 +739334463 #COUNT km #COUNT公里 +3316959333 #COUNT m #COUNT米 +134881717 #COUNT m/s #COUNT米/秒 +3671280983 #COUNT Medal(s) spent 已花费#COUNT枚奖章 +673989104 #COUNT Medals #COUNT枚奖章 +2172682648 #COUNT meters #COUNT米 +1917163885 #COUNT mrad #COUNT毫弧度 +945668272 #COUNT s #COUNT秒 +1248949050 #COUNT SAMPLES #COUNT份样本 +2804993025 #COUNT Samples Extracted 已提取#COUNT份样本 +1590433650 #COUNT SC #COUNT超级货币 +3267783984 #COUNT XP TO NEXT LEVEL 升到下一等级还需要#COUNT经验 +1339589811 #COUNT/#TOTAL #COUNT/#TOTAL +2124155215 #COUNT/#TOTAL (MAX) #COUNT/#TOTAL(最多) +2747465545 #COUNT/#TOTAL objectives completed 达成#COUNT/#TOTAL的目标 +197876886 #COUNT% #COUNT% +1671792695 #COUNT% #COUNT% +4015580041 #COUNT% XP RATING #COUNT%经验等级 +1808282157 #COUNT° #COUNT° +3626201721 #COUNT° #COUNT° +2118334491 #COUNT/#TOTAL Claimed 已领取#COUNT/#TOTAL +374081602 #COUNTdB #COUNTdB +56272429 #COUNTm #COUNT米 +1062099662 #COUNTm #COUNT米 +956860246 #COUNTm #COUNT米 +2526430052 #COUNTm/s #COUNT米/秒 +1276695601 #COUNTrpm #COUNT RPM +3212373153 #COUNTs #COUNT秒 +4033800310 #COUNTx #COUNTx +1585260885 #CURR of #TOTAL #CURR/#TOTAL +1755675706 #CURRENT / #TARGET #CURRENT / #TARGET +2742439966 #CURRENT / #TARGET Rockets #CURRENT / #TARGET火箭弹 +3232640112 #CURRENT / #TOTAL #CURRENT / #TOTAL +2837331439 #CURRENT / #TOTAL kills #CURRENT / #TOTAL次击杀 +936927387 #CURRENT_XP / #NEXT_XP #CURRENT_XP / #NEXT_XP +437129953 #DAYS DAYS #HOURS HOURS #MINUTES MIN #DAYS日#HOURS小时#MINUTES分 +4275589329 #DAYS DAYS #HOURS HOURS #MINUTES MIN #DAYS日#HOURS小时#MINUTES分 +3979887494 #DAYS Days Left 还剩#DAYS天 +2667711223 #DAYSd #HOURSh #MINSm Left 还剩#DAYSd #HOURSh #MINSm +3126444644 #DEGREES°/sec #DEGREES°/秒 +560314369 #DISTANCE km #DISTANCE公里 +2915870982 #DISTANCEm #DISTANCE米 +653025412 #ENTITY is out of range #ENTITY不在范围内 +7134963 #ERROR! #ERROR! +147835329 #ERROR! #ERROR! +1837683881 #FIRST #LAST #LAST#FIRST +344720878 #FOUND found (#TOTAL on ship) 已找到#FOUND份(舰船上总计有#TOTAL份) +2592792787 #GRADE (#PERCENT%) #GRADE (#PERCENT%) +929766607 #HOURS:#MINUTES:#SECONDS #HOURS:#MINUTES:#SECONDS +465767362 #HOURSh #MINUTESm #HOURS小时#MINUTES分钟 +2908936646 #HOURSh #MINUTESm #SECONDSs #HOURS小时#MINUTES分钟#SECONDS秒 +3546768056 #HUNDREDTHS:#MINS:#SECS #HUNDREDTHS:#MINS:#SECS +3030752491 #HUNDREDTHS:#MINUTES:#SECONDS #HUNDREDTHS:#MINUTES:#SECONDS +1058111921 #ITEM #ITEM +3810431183 #ITEM #ITEM +162868928 #ITEM FULL #ITEM已满 +1728719795 #ITEM Medals x#COUNT #ITEM奖章 x#COUNT +4015316504 #LEADIN #DAY #LEADIN #DAY +713394709 #LEADIN #DAY #HOUR #MINUTE #LEADIN #DAY #HOUR #MINUTE +2754851505 #LEADIN #DAY #HOUR #MINUTE #SECOND #LEADIN #DAY #HOUR #MINUTE #SECOND +790885089 #MINS:#SECS #MINS:#SECS +970937181 #MINUTES:#SECONDS #MINUTES:#SECONDS +1558469090 #MINUTES:#SECONDS:#MILLI #MINUTES:#SECONDS:#MILLI +3738101114 #MINUTESm #SECONDSs #MINUTES分钟#SECONDS秒 +536616162 #MISSION_TYPE: #MISSION_NAME #MISSION_TYPE: #MISSION_NAME +4289757524 #NAME #NAME +3965369850 #NAME #NAME +3705698706 #NAME - #STATE [#MEMBERS/#MAXMEMBERS] #NAME - #STATE [#MEMBERS/#MAXMEMBERS] +142423103 #NAME - LEVEL #LEVEL #NAME - #LEVEL级 +1645747778 #NAME #TYPE #NAME#TYPE +4096754490 #NAME didn't make the cut #NAME已被淘汰出局 +463357226 #NAME has been court-martialed #NAME已被移交军事法庭 +350013322 #NAME has joined the mission #NAME加入任务 +384506558 #NAME has timed out #NAME已超时 +2901376465 #NAME is no longer part of the team #NAME不再是团队一员 +2489938042 #NAME joined #NAME加入 +4216434280 #NAME left #NAME已退出 +4061683994 #NAME left the mission #NAME退出任务 +2894401479 #NAME LIBERATED 成功解放#NAME +4226637156 #NAME PERMIT #NAME许可证 +471656001 #NAME Rank #COUNT #NAME 级别#COUNT +1916253483 #NAME returned to civilian life #NAME已回归平民生活 +1668774593 #OBJECTIVE_NAME +#TIME_REMAINING #OBJECTIVE_NAME +#TIME_REMAINING +4256097648 #PERCENT% #PERCENT% +881740510 #PERCENTAGE% #PERCENTAGE% +1198280391 #PERCENTAGE% HELD #PERCENTAGE%保卫成功 +2094457118 #PERCENTAGE% LIBERATED 已解放#PERCENTAGE% +240220138 #PERCENTAGE% of Votes 得票率:#PERCENTAGE% +1330527915 #PLANET #PLANET +2731662120 #PLANET CITIES #PLANET城市 +2305927483 #PLANET MEGAFACTORIES #PLANET超大型工厂 +907336128 #PREFIX #NAME #PREFIX #NAME +1092949246 #RACE #RACE +2308523261 #RACE PRESENCE #RACE势力 +4251373781 #READY MB/#TOTAL MB - #PERCENTAGE % complete +Time Remaining: #SECONDS s #READY MB/#TOTAL MB - 已完成#PERCENTAGE% +剩余时间:#SECONDS秒 +2671556553 #READY MB/#TOTAL MB - #PERCENTAGE% complete #READY MB/#TOTAL MB - 已完成#PERCENTAGE% +2782217639 #SECONDS REMAINING UNTIL LOADOUT! 武装配置还剩#SECONDS! +788411511 #SECONDS sec #SECONDS秒 +2144747701 #SECONDS sec #SECONDS秒 +1121939552 #SECONDS SEC #SECONDS秒 +1461820998 #SECONDS UNTIL MISSION EXPIRES 距离任务过期还有#SECONDS +4234347088 #SECONDSs #SECONDS秒 +2529489660 #SECONDSs #SECONDS秒 +2997344754 #SECTOR #SECTOR +3553803239 #SHIP_PREFIX #SHIP_NAME_A #SHIP_NAME_B #SHIP_PREFIX#SHIP_NAME_B#SHIP_NAME_A +3710378294 #SHORT - #LONG #SHORT - #LONG +3643179164 #SPEAKER: #SUBTITLE #SPEAKER:#SUBTITLE +1970504245 #STATUS on #PLANET 在#PLANET上#STATUS +1250926542 #SUBTITLE #SUBTITLE +36156336 #TEXT #TEXT +806400175 #TYPE: +#AMOUNT/#POTENTIAL #TYPE:+#AMOUNT/#POTENTIAL +4053501475 #TYPE: +#AMOUNT/#POTENTIAL M #TYPE:+#AMOUNT/#POTENTIAL +156634357 #VALUE #VALUE +1446200790 #VALUE day #VALUE天 +3222869178 #VALUE Day #VALUE天 +3137384160 #VALUE DAY #VALUE天 +4250090175 #VALUE days #VALUE天 +2987532778 #VALUE Days #VALUE天 +2287300586 #VALUE DAYS #VALUE天 +3775688985 #VALUE Hour #VALUE小时 +2562534265 #VALUE HOUR #VALUE小时 +2203259731 #VALUE Hours #VALUE小时 +529146598 #VALUE HOURS #VALUE小时 +3845201383 #VALUE Minute #VALUE分钟 +4049372406 #VALUE MINUTE #VALUE分钟 +3240883761 #VALUE Minutes #VALUE分钟 +3535878147 #VALUE MINUTES #VALUE分钟 +1777848808 #VALUE Second #VALUE秒 +15139530 #VALUE SECOND #VALUE秒 +2684728733 #VALUE Seconds #VALUE秒 +2741953390 #VALUE SECONDS #VALUE秒 +1399897974 #VALUEd #VALUE天 +3651033560 #VALUEh #VALUE小时 +1238175497 #VALUEmin #VALUE分钟 +3702434399 #VALUEs #VALUE秒 +3764267998 #WAVES waves completed 击溃#WAVES波攻势 +3837905141 #WEAPON_NAME MAGS #WEAPON_NAME弹匣 +1583484500 #X - #Y #X - #Y +433168853 #X / #Y #X / #Y +3830221876 #X #Y #X #Y +2648738319 #X #Y #Z #X #Y #Z +980029096 #X/#Y #X/#Y +4161303299 #X/#Y #X/#Y +3356860647 #X/#Y #X/#Y +1974299360 ©2024 Sony Interactive Entertainment LLC. Developed by Arrowhead Game Studios AB. Helldivers 2 is a registered trademark of Sony Interactive Entertainment LLC and related companies in the U.S. and other countries. ©2024 Sony Interactive Entertainment LLC. Developed by Arrowhead Game Studios AB. Helldivers 2 is a registered trademark of Sony Interactive Entertainment LLC and related companies in the U.S. and other countries. +3986456025 ©ÅÄÖÉŠČ ©ÅÄÖÉŠČ +1949567130 + + +3103889211 + #PING_AMOUNT Pings + #PING_AMOUNT延迟值 +2822991045 +#COUNT +#COUNT +4262706477 +#COUNT +#COUNT +2157003287 +#COUNT +#COUNT +647077052 +#COUNT SAMPLE +#COUNT份样本 +247841441 +#POINTS +#POINTS +238397465 +1403282299 +1517786633 +2674288863 +2930957344 +3281577556 +3410406414 +496808468 times +1029106029 times +1324082343 +3366721294 +3962239360 +3999261265 +2930240803 controlled planet (任一星球) +3360588677 controlled planet (任一星球) +451773215 times +3954717673 #BONUS chance to not die when taking lethal damage. 受到致命伤害时,不会阵亡的概率额外提高#BONUS。 +3754139674 #SPEAKER #TEXT #SPEAKER #TEXT +277210032 #COUNT/#TOTAL #COUNT/#TOTAL +1065661022 MISSION TIME #HOURS:#MINUTES:#SECONDS 任务时长 #HOURS:#MINUTES:#SECONDS +1700425528 SAMPLES EXTRACTED #COUNT 提取样本数 #COUNT +210707637 TEAM DEATHS #COUNT 团队阵亡数 #COUNT +10195202 TEAM KILLS #COUNT 团队击杀数 #COUNT +324601060 #NAME DIED #NAME阵亡 +3444806745 #NAME discovered #DISCOVERY #NAME已发现#DISCOVERY +1199036355 #NAME has invited you to their squad. #NAME邀请你加入他们的队伍。 +920995590 #NAME invited you to join a Clan #NAME邀你加入中队 +2765439101 #NAME is the new squad leader #NAME成为新的小队长 +3739857149 #NAME: #MESSAGE #NAME:#MESSAGE +1271728107 INBOUND #MM#M:#SS#S 即将抵达 #MM#M:#SS#S +953722791 ONGOING #MM#M:#SS#S 正在进行 #MM#M:#SS#S +2049910172 #NAME #NAME +2092128075 BULLETS FIRED: #VALUE 开火次数:#VALUE +3284998754 ENEMIES KILLED: #VALUE 杀敌数:#VALUE +2883743751 FRIENDS: #VALUE 好友:#VALUE +1118917483 HELLDIVERS: #VALUE 绝地潜兵:#VALUE +3920132753 KIA: #VALUE 阵亡:#VALUE +4052077326 LAT: #VALUE 纬度: #VALUE +1448346078 LOCAL TIME SETU: #VALUE 当地时间(超级地球时间单位): #VALUE +2163192956 LONG: #VALUE 经度: #VALUE +1132095991 PLATOON: #VALUE 特战排:#VALUE +3224337239 REV PERIOD: #VALUE YEARS 公转周期: #VALUE年 +3523340692 ROT PERIOD: #VALUE DAYS 自转周期: #VALUE天 +3130602394 TRACKING: ACTIVE HELLDIVER SQUADS 正在追踪: 正在行动的绝地潜兵小队 +233657198 TRACKING: MISSION REQUESTS 正在追踪: 任务申请 +2466622891 AVERAGE 中等 +2975979471 LOW 低 +4265488473 #NAME #NAME +2376684804 #NAME #NAME +3491418699 HIGH 高 +2778843793 VERY HIGH 极高 +331990041 #NAME #NAME +142315455 次数: +2505675202 次数: +1555503243 #VALUE DAY #VALUE天 +1517240444 #VALUE DAYS #VALUE天 +2412757892 #VALUE HOUR #VALUE小时 +1985620230 #VALUE HOURS #VALUE小时 +2440539975 #VALUE MINUTE #VALUE分钟 +4146883874 #VALUE MINUTES #VALUE分钟 +3964889908 #VALUE SECOND #VALUE秒 +1490709564 #VALUE SECONDS #VALUE秒 +2781299640 AUTOMATED TURRETS fire at hostile targets. Stay clear of the field of fire! 自动炮台会朝敌方目标开火。注意避开射击范围! +2879475963 DIVE to extinguish fire! 飞扑可以灭火! +2410391723 DIVING increases your chances of surviving an explosion. 扑倒在地可增加你在爆炸中幸存的机会。 +67570928 INTEL ACQUIRED! Bring it back to the ship to unlock OPPORTUNITY MISSION. 取得情报!将情报带回舰船,解锁机遇任务。 +201077986 MANUALLY adjust FLOW RATE VALVES. 手动调整流量阀。 +1859686028 MANUALLY align RADAR DISH. 手动校准雷达天线。 +823236048 MANUALLY raise SILO LOCKS. 手动拉起舱门锁。 +203207851 MANUALLY set ENGINE VALVES to maximum output. 手动将引擎阀门设置为最大输出。 +3799342346 MANUALLY set FLOW RATE VALVES to maximum output. 手动将流量阀门设置为最大输出。 +583619049 MANUALLY tighten EXHAUST CLAMPS. 手动解开安全钳。 +3911581617 RADAR activated. Map details revealed. 雷达启动。已显示地图细节。 +2494829952 REARM stratagem sends your Eagle back to reload its weapons. 重新武装战略配备会派你的“飞鹰”返回补充武器弹药。 +2324036538 SUPER DESTROYER departure imminent! STRATAGEMS will become unavailable. Extract now! 超级驱逐舰即将离开!你将无法再使用战略配备。立即撤离! +2949940608 SUPER DESTROYER has departed. STRATAGEMS unavailable. EXTRACTION SHUTTLE enroute. 超级驱逐舰已离开。战略配备无法使用。撤离运输船已经出动。 +4273908290 SUPPLY BACKPACK can carry extra ammo. Use the BACKPACK FUNCTION to resupply yourself. 补给背包可以装载额外的弹药。使用背包功能为自己补充弹药。 +653397606 TEAM WEAPON BACKPACKS allow you to reload support weapons. This is most efficient when working with a teammate. 携带团队武器背包可以为支援武器重新装填弹药。这是与队友合作时效率最高的做法。 +4161686183 TEAM WEAPONS can be reloaded by teammates. 团队武器可由队友装填弹药。 +2327864848 VEHICLES can traverse the mission area quickly and provide extra firepower. 载具可以帮助你在任务区域快速移动,也可以提供额外的火力。 +85066976 次数: +2397886806 +445309889 #BOOSTER is active during missions. 任务期间,#BOOSTER已激活。 +1001719296 #COUNT kills with orbital stratagems 利用轨道战略配备完成#COUNT次击杀 +166062674 #COUNT kills with turret stratagems 利用炮台战略配备完成#COUNT次击杀 +2233178159 #COUNT times 次数: #COUNT +2668536287 #COUNT total kills with grenades 利用榴弹总计完成#COUNT次击杀 +3295025058 #DAY_ZEROS#DAYSD #HOUR_ZEROS#HOURSH #DAY_ZEROS#DAYS天 #HOUR_ZEROS#HOURS小时 +1020964387 #HOUR_ZEROS#HOURSH #MINUTE_ZEROS#MINUTESM #HOUR_ZEROS#HOURS小时 #MINUTE_ZEROS#MINUTES分钟 +1475232210 #MINUTE_ZEROS#MINUTESM #SECOND_ZEROS#SECONDSS #MINUTE_ZEROS#MINUTES分钟 #SECOND_ZEROS#SECONDS秒 +3725451051 #NAME didn't make the cut #NAME已被淘汰出局 +1781337043 #NAME DIED #NAME阵亡 +2458327640 #NAME discovered #DISCOVERY #NAME已发现#DISCOVERY +3808670249 #NAME has been court-martialed #NAME已被移交军事法庭 +2704291316 #NAME has joined the mission #NAME加入任务 +2448077595 #NAME has timed out #NAME已超时 +4017412399 #NAME is no longer part of the team #NAME不再是团队一员 +267741279 #NAME is the new squad leader #NAME成为新的小队长 +2207765754 #NAME joined #NAME加入 +4087818322 #NAME left #NAME已退出 +940987579 #NAME left the mission #NAME退出任务 +2043639537 #NAME leveled up #WEAPON to level #LEVEL #NAME已升级#WEAPON至#LEVEL级 +3922468673 #NAME returned to civilian life #NAME已回归平民生活 +470942591 #NAME: #MESSAGE #NAME: #MESSAGE +2015558774 #ONLINE ONLINE  #COUNT IN GAME #ONLINE人在线 #COUNT人正在游戏 +3569034914 #PLAYER sent a friend request! 来自#PLAYER的好友申请! +177293649 #SPEAKER #TEXT #SPEAKER #TEXT +2449061412 #V_ONE available to all Helldivers. #V_ONE可供所有绝地潜兵使用。 +2912407889 #V_ONE Booster is automatically active for all missions. #V_ONE强化资源在全部任务中自动激活。 +2994723165 #V_ONE effectiveness increase no longer in effect. 不再提升#V_ONE的效果。 +77038681 #V_ONE is temporarily available to all Helldivers. #V_ONE可暂时供所有绝地潜兵使用。 +3853707815 #V_ONE stratagem availability has ended. 现已无法使用#V_ONE战略配备。 +2633483286 #V_ONE stratagem is once again available (if purchased). #V_ONE战略配备再次供应(如已购买)。 +2370462133 #V_ONE stratagem is temporarily available to all Helldivers. #V_ONE战略配备可暂时供所有绝地潜兵使用。 +2956467301 #V_ONE stratagem is temporarily unavailable to all Helldivers. 所有绝地潜兵暂时都不能使用#V_ONE战略配备。 +784485555 #VALUE-second reduction in call-in time for all Orbital stratagems. 所有轨道武器战略配备呼叫时间缩短#VALUE秒。 +672881833 #WEAPON LVL #CURRENT/#MAX #WEAPON等级#CURRENT/#MAX +1918022460 #ZEROES#COUNT #ZEROES#COUNT +1472672983 50% bonus to Requisition and XP awarded per mission 每项任务额外奖励50%申购点和经验 +1846031154 Barrage orbitals fire #VALUE additional salvo(s) per barrage. 火力网轨道武器每次可额外进行#VALUE次齐射。 +954274193 Cast your vote to influence where the DSS will be stationed during its next cycle. + +Donate resources to activate the Station's Tactical Actions: powerful abilities that can dramatically alter the fight for a planet's freedom. Only one Tactical Action can be active at a time. 投票决定民主空间站在下一周期的停靠地点。 + +捐赠资源以激活空间站的战术行动:可扭转星球自由之战局势的强大力量。每次只能激活一场战术行动。 +1619134311 Continuous barrages rain down during missions. 任务期间,连续炮击倾泻而下。 +3490555416 Defense Campaigns cannot originate from this planet. 此星球无法发起保卫战役。 +888961443 Defense Campaigns cannot originate from this planet. The #BOOSTER Booster is automatically active for all missions. 此星球无法发起保卫战役。#BOOSTER强化资源在全部任务中自动激活。 +926675872 Eagle Rearm time is #AMOUNT seconds faster on this planet. 在此星球上的飞鹰时间将加快#AMOUNT秒。 +258430200 Eagle Rearm time is #AMOUNT seconds slower on this planet. 在此星球上的飞鹰时间将减慢#AMOUNT秒。 +999030979 Eagle Rearm time is #V_ONE% faster. 重新武装“飞鹰”的时间加快#V_ONE%。 +3711039703 Eagle Rearm time is #V_ONE% slower. 重新武装“飞鹰”的时间减慢#V_ONE%。 +2349351728 Eagle stratagem cooldown time reduced by #VALUE%. “飞鹰”战略配备的冷却时间缩短#VALUE%。 +3888872278 Effects are temporary alterations to battlefield conditions. They change as the war develops, and may force Helldivers to adapt their tactics. 效果是因应战场状况临时变更的条件,会随着战争局势的发展而变化,可能迫使绝地潜兵调整战术。 +3847318952 Enemy resistance on this Hive World is lowered. 这个虫窝世界的敌军抵抗强度降低。 +2343909414 Extraction time against the Automatons is #V_ONE seconds faster. 对阵机器人时的撤离时间加快#V_ONE秒。 +463730113 Extraction time against the Automatons is #V_ONE seconds slower. 对阵机器人时的撤离时间减慢#V_ONE秒。 +216109097 Extraction time against the Illuminate is #V_ONE seconds faster. 对阵光能者时的撤离时间加快#V_ONE秒。 +1156936261 Extraction time against the Illuminate is #V_ONE seconds slower. 对阵光能者时的撤离时间减慢#V_ONE秒。 +3908391598 Extraction time against the Terminids is #V_ONE seconds faster. 对阵终结族时的撤离时间加快#V_ONE秒。 +3258064410 Extraction time against the Terminids is #V_ONE seconds slower. 对阵终结族时的撤离时间减慢#V_ONE秒。 +3616364457 Extraction time on this planet is #V_ONE seconds faster on this planet. 在此星球上的撤离时间加快#V_ONE秒。 +3764194516 Extraction time on this planet is #V_ONE seconds slower on this planet. 在此星球上的撤离时间减慢#V_ONE秒。 +1264650473 Liberation Impact from completed missions on this planet is #V_ONE% greater on this planet. 在此星球上完成任务所造成的解放影响将扩大#V_ONE%。 +3804225068 Major Orders represent the goals of the Helldiver Community. 重要指令是绝地潜兵社区的共同目标。 +765332655 Map obscured by Bug Spores. 虫族释放的孢子将会遮蔽地图。 +591550370 Mission Timer reduced to 30 minutes. 任务时限缩短至30分钟。 +498089773 Mortar Sentries prioritize fire at marked targets. 迫击哨戒炮优先射击标记的目标。 +3351044875 Objective locations are hidden. 隐藏目标地点。 +3626305844 Orbital stratagem cooldown time reduced by #VALUE%. 轨道战略配备的冷却时间缩短#VALUE%。 +2750396089 Personal Orders are completed by Helldivers individually, and change every day in response to the shifting battlefield. 个人指令由绝地潜兵单独完成,而且每天都会根据战场局势而改变。 +4055018831 Resupply Stratagem boxes refill Support Weapons with the maximum number of carriable magazines. “重新补给”战略配备的补给箱为支援武器补充的可携带弹匣数增加至最大数量。 +2197061274 Stratagem Codes Scrambled. 战略配备代码被扰频打乱。 +3351717482 Stratagem slots reduced by #V_ONE. 减少#V_ONE个战略配备槽位。 +2177273874 Support Weapons deploy with the maximum number of carriable magazines. 支援武器配给的可携带弹匣数增加至最大数量。 +147323792 WEAPON CUSTOMIZATION now available in the ARMORY. 武器自定义内容已在军械库中解锁。 +2526838385 Your Friend Code 你的好友代码 +1600211229 #DAYSD #DAYS天 +842543279 ACHERNAR SECUNDUS FALLEN + +Achernar Secundus has fallen to the Terminids. The AM Defense Factory Hub has been evacuated; FRV cooldown will be increased for #VALUE hours. 水委一次星沦陷 + +水委一次星不幸被终结族攻占。虎将国防工厂中心已完成撤离,快速侦察载具的冷却时间将延长#VALUE小时。 +2366202978 GALACTIC NETWORK UPDATE + +High Command acknowledges recent issues in the Integrated Realtime Galactic Visibility Aid. The cause has been identified as a network systems Team Member who became disoriented in the server farm, leading to decomposition of organic material on critical network components. + +The issue has been resolved and the system has been returned to normal status. Rest assured that the cost of the repair was borne solely by the family of the team member responsible for the issue. 星系网络更新 + +最高指挥部得知集成式星系实时视觉辅助近期出现问题。事故原因已确定,是由于一名网络系统团队成员在服务器农场中迷失方向,导致关键网络元件的有机材料分解。 + +此问题现已修复,系统也已经恢复正常状态。维修费用全部由涉事团队成员及其家人承担,无需担心。 +3814251656 INTELLIGENCE BRIEF + +A new gunship-style unit has been reported across all Automaton battlefronts. No intel indicated the deployment of new Automatons units. Had the Communications Array on Troost been captured, we may have had adequate forewarning to prepare effective countermeasures. + +As it stands, Helldivers will have to rely on currently available resources and their peerless tactical ingenuity to combat this new threat. 情报简报 + +据报告,所有机器人战斗前线都出现了一种新型炮舰单位。没有情报显示有新的机器人单位部署。如果顺利占领特鲁斯特的通讯阵列,我们可能会有足够的预警来准备有效的反击措施。 + +目前的情况是,绝地潜兵将不得不依靠现有的资源和他们无与伦比的战术智慧来对抗这一新的威胁。 +954093558 INTELLIGENCE BRIEF + +As anticipated, the Automatons have deployed a new gunship-style unit on all battlefronts. It was only a matter of time before their totalitarian conquest expanded skyward. + +Fortunately, due to the advance warning provided by the communication array on Troost, Helldiver arsenals have been augmented to combat this threat. Helldivers will continue to find the EAT-17 Expendable Anti-Tank Stratagem included in all loadouts for the near future. 情报简报 + +不出所料,机器人已在所有战场前线部署一种新型炮舰式单位。它们迟早会把极权主义的铁爪伸向我们的领空。 + +万幸的是,特鲁斯特上的通讯阵列已提前发出警告,绝地潜兵武器库得以及时扩充,以应对此次危机。未来一段时间内,绝地潜兵的全部武装配置都将继续追加“EAT-17消耗性反坦克武器”战略配备。 +280616943 MAJOR ORDER WON +Gaellivare has been held for the designated timeframe. However, the planet, and the DSS itself, remain imperiled. The fight is not over. +High Command will monitor the situation. Further guidance will be issued once the fate of Gaellivare is decided—one way or the other. 重要指令达成 +我方在指定时段内守住了耶利瓦勒。但该星球以及DSS本身仍处在威胁中。战斗尚未结束。 +最高指挥部将持续关注局势。无论如何,待耶利瓦勒的命运尘埃落定后,我方将制定进一步的指导方针。 +3533790466 PRESIDENTIAL DECREE + +The President of Super Earth has officially recognized this day as Malevelon Creek Memorial Day. Every year on this day, Super Earth citizens will unite for a full 3 minutes of their lunch break in solemn remembrance of those who gave their lives to free Malevelon Creek. + +In addition, all Helldivers have been issued a special commemorative cape, so they may carry the memory of their fallen companions into battle. 总统令 + + +超级地球总统已正式将这一天定为 "麦拉芬蒙河纪念日"。每年的这一天,超级地球的公民们都会在午餐时间一起为解放麦拉芬蒙河而牺牲的战士默哀三分钟。 + +此外,所有绝地潜兵都会获得一件特殊的纪念披肩,让他们带着牺牲同伴的遗志投身战斗。 +299475150 STRATEGIC ADVISORY + +The Automaton Jet Brigade has been spotted in the #SECTOR Sector. 战略警报 + +#SECTOR发现机器人喷气旅。 +754281439 STRATEGIC ADVISORY + +The Automaton Jet Brigade has been spotted on several planets. 战略警报 + +在数个星球发现机器人喷气旅。 +2206789039 TURING FALLEN + +Turing has fallen to the Terminids, and with it the illustrious Xenoentomology Center. Due to the tragic and unavoidable rupture of several high-pressure #ENEMY1 pheromone tanks, #ENEMY2 presence on Turing is expected to increase substantially. 图灵星沦陷 + +图灵星已落入终结族手中,连同著名的异星昆虫学研究中心也已沦陷。祸不单行,数台#ENEMY1高压信息素储罐发生不可控的破裂事故,图灵星的#ENEMY2活跃度预计将大幅提高。 +2173519201 >> BLOCKED << >> 受阻 << +2262072624 >> UNLOCK << >> 解锁 << +2842725762 0.05% of profits are donated to Superstone National Park, as part of the Ministry of Unity's "Greener Galaxy" campaign. 为支持团结部的“更绿星系”活动,0.05%的利润将捐赠给超石国家公园。 +1959551110 1 1 +2083113135 1 DAY AGO 1天前 +2779436447 1 HOUR AGO 1小时前 +4149833848 1,500 SC 1,500超级货币 +4116153319 1.5x Tube Red Dot 1.5倍红点瞄准镜 +1237147322 1.5x TUBE RED DOT 1.5倍红点瞄准镜 +1444453133 10 10 +108830821 10-STAR GENERAL 十星将军 +2068596849 10-STAR SUPER PRIVATE 十星超级列兵 +705697371 100 SC 100超级货币 +2143456405 100 SC 100超级货币 +1586874850 100kg Bomb 100KG炸弹 +2588157938 100KG BOMB 100KG炸弹 +2318300809 100kg Bomb Mk2 100KG炸弹 MK2 +2778107789 100KG BOMB MK2 100KG炸弹 MK2 +233995848 100kg Bomb Mk3 100KG炸弹 MK3 +3265342382 100KG BOMB MK3 100KG炸弹 MK3 +1164459371 100kg Cluster Bomb 100KG集束炸弹 +3403714418 100KG CLUSTER BOMB 100KG集束炸弹 +3741166472 10g Birdshot 10g鸟弹 +2755224776 10g BIRDSHOT 10g鸟弹 +354025303 10g Buckshot Shells 10g鹿弹霰弹 +3091714181 10g BUCKSHOT SHELLS 10g鹿弹霰弹 +2495515626 10g Bugshot 10g虫弹 +2621718089 10g BUGSHOT 10g虫弹 +2111768563 10g Dual Sabot 10g双萨博特式霰弹 +1975714793 10g DUAL SABOT 10g双萨博特式霰弹 +3875128073 10g Flechettes 10g飞镖弹 +928593591 10g FLECHETTES 10g飞镖弹 +346739478 10g Fragmentation 10g破片弹 +4278309157 10g FRAGMENTATION 10g破片弹 +3644425076 10g HE Rounds 10g高爆弹 +3695835500 10g HE ROUNDS 10g高爆弹 +3780597010 10g High Velocity Sabot 10g高速萨博特式霰弹 +583487571 10g HIGH VELOCITY SABOT 10g高速萨博特式霰弹 +2731845108 10g Liberty Fire 10g“解放之火”霰弹 +2364144613 10g LIBERTY FIRE 10g“解放之火”霰弹 +566653809 10g Magnum 10g马格南霰弹 +2185124783 10g MAGNUM 10g马格南霰弹 +3658534561 10g MAGNUM TRI-BALL 10g马格南三连弹 +648255169 10g Magnum Triball 10g马格南三连弹 +1259065120 10g Rifled Slugs 10g线膛独头弹 +3837994681 10g RIFLED SLUGS 10g线膛独头弹 +3910397585 10g Sabot 10g萨博特式霰弹 +3028854855 10g SABOT 10g萨博特式霰弹 +3282178145 10g Scatter Shot 10g散射弹 +927878793 10g SCATTER SHOT 10g散射弹 +3317342803 10g STUN ROUNDS 10g眩晕弹 +1956039782 10g Tri-Ball 10g三连弹 +3905442367 10g TRI-BALL 10g三连弹 +361043407 10x Sniper Scope 10倍狙击瞄准镜 +372370498 10x SNIPER SCOPE 10倍狙击瞄准镜 +1108427039 110mm Airburst Cannon Round 110mm空爆炮弹 +951616363 110mm AIRBURST CANNON ROUND 110mm空爆炮弹 +4153844710 110mm Airburst Cannon Round Mk2 110mm空爆炮弹 MK2 +2341514623 110mm AIRBURST CANNON ROUND MK2 110mm空爆炮弹 MK2 +2120659629 110mm E.M.S. Cannon Round 110mm电磁冲击波炮弹 +51208102 110mm E.M.S. CANNON ROUND 110mm电磁冲击波炮弹 +3825164669 110mm E.M.S. Cannon Round Mk2 110mm电磁冲击波炮弹 MK2 +980633399 110mm E.M.S. CANNON ROUND MK2 110mm电磁冲击波炮弹 MK2 +2311688101 110mm E.M.S. Cannon Round Mk3 110mm电磁冲击波炮弹 MK3 +1741213838 110mm E.M.S. CANNON ROUND MK3 110mm电磁冲击波炮弹 MK3 +3299776422 110mm Gas Cannon Round 110mm毒气炮弹 +2047321510 110mm GAS CANNON ROUND 110mm毒气炮弹 +521047085 110mm Gas Cannon Round Mk2 110mm毒气炮弹 MK2 +343109918 110mm GAS CANNON ROUND MK2 110mm毒气炮弹 MK2 +326589116 110mm Gas Cannon Round Mk3 110mm毒气炮弹 MK3 +384900567 110mm GAS CANNON ROUND MK3 110mm毒气炮弹 MK3 +2390510946 110mm Standard Rocket 110mm标准火箭弹 +876631720 110mm STANDARD ROCKET 110mm标准火箭弹 +2230439364 110mm Standard Rocket Mk2 110mm标准火箭弹 MK2 +2812156110 110mm STANDARD ROCKET MK2 110mm标准火箭弹 MK2 +1993141852 12.5mm BCHP Rifle Rounds 12.5mm粘合弹芯空尖弹 +1967142512 12.5mm BCHP RIFLE ROUNDS 12.5mm粘合弹芯空尖弹 +2736882039 12.5mm EIT Rounds 12.5mm爆炸燃烧曳光弹 +2922379565 12.5mm EIT ROUNDS 12.5mm爆炸燃烧曳光弹 +3242636709 12.5mm Standard Rifle Rounds 12.5mm标准步枪子弹 +422101497 12.5mm STANDARD RIFLE ROUNDS 12.5mm标准步枪子弹 +4111909320 120mm HE Cannon Round 120mm高爆炮弹 +2683992244 120mm HE CANNON ROUND 120mm高爆炮弹 +4189160103 12g Birdshot 12g鸟弹 +3500789039 12g BIRDSHOT 12g鸟弹 +1037303660 12g Buckshot 12g鹿弹 +2407297704 12g BUCKSHOT 12g鹿弹 +2896843106 12g Buckshot Magnum Shells 12g鹿弹马格南霰弹 +1757675499 12g BUCKSHOT MAGNUM SHELLS 12g鹿弹马格南霰弹 +3918547863 12g Buckshot Shells 12g鹿弹霰弹 +1314579500 12g BUCKSHOT SHELLS 12g鹿弹霰弹 +2390010387 12g Bugshot 12g虫弹 +3960518775 12g BUGSHOT 12g虫弹 +4037759447 12g Flechette Shells 12g飞镖霰弹 +69121929 12g FLECHETTE SHELLS 12g飞镖霰弹 +1491792151 12g Flechettes 12g飞镖弹 +3532118678 12g FLECHETTES 12g飞镖弹 +3317762411 12g Liberty Fire 12g“解放之火”霰弹 +3870342324 12g LIBERTY FIRE 12g“解放之火”霰弹 +1880455446 12g Magnum 12g马格南霰弹 +1121040653 12g MAGNUM 12g马格南霰弹 +3071879380 12g Magnum Triball 12g马格南三连弹 +1744484582 12g MAGNUM TRIBALL 12g马格南三连弹 +4201282979 12g Scatter Shot 12g散射弹 +285598812 12g SCATTER SHOT 12g散射弹 +4195408834 12g Tri-Ball 12g三连弹 +1465740486 12g TRI-BALL 12g三连弹 +1382999144 12mm 12mm +2008452781 12MM 12MM +1185995338 12x25mm Explosive 12x25mm爆炸子弹 +1963170034 12x25mm EXPLOSIVE 12x25mm爆炸子弹 +1514994279 12x25mm Full Metal Jacket 12x25mm全金属被甲弹 +661457705 12x25mm FULL METAL JACKET 12x25mm全金属被甲弹 +3480470718 12x25mm High Velocity 12x25mm高速弹 +3935569760 12x25mm HIGH VELOCITY 12x25mm高速弹 +2103607856 12x25mm Hollow Point 12x25mm空尖弹 +280108911 12x25mm HOLLOW POINT 12x25mm空尖弹 +404114273 12x25mm Plasma 12x25mm等离子弹 +1511224910 12x25mm PLASMA 12x25mm等离子弹 +4111551447 12x25mm Ripper 12x25mm撕裂弹 +2284423736 12x25mm RIPPER 12x25mm撕裂弹 +2463174816 12x25mm Thermite 12x25mm铝热弹 +3116199172 12x25mm THERMITE 12x25mm铝热弹 +3153142401 12x25mm Toxic 12x25mm毒弹 +1035769681 12x25mm TOXIC 12x25mm毒弹 +2775350519 13x40mm Full Metal Jacket 13x40mm全金属被甲弹 +1291552700 13x40mm FULL METAL JACKET 13x40mm全金属被甲弹 +3453969872 13x40mm Hollow Point 13x40mm空尖弹 +944633350 13x40mm HOLLOW POINT 13x40mm空尖弹 +3645480674 13x40mm Magnum 13x40mm马格南子弹 +3716114867 13x40mm MAGNUM 13x40mm马格南子弹 +3211200872 13x40mm Penetrator 13x40mm穿甲弹 +2463266282 13x40mm PENETRATOR 13x40mm穿甲弹 +344072355 13x40mm Ripper 13x40mm撕裂弹 +1891178752 13x40mm RIPPER 13x40mm撕裂弹 +3870871817 150 SC 150超级货币 +989431349 15x100mm Emp-Rounds 15x100mm电磁脉冲弹 +2973554793 15x100mm EMP-ROUNDS 15x100mm电磁脉冲弹 +637719079 15x100mm Fragmentation 15x100mm破片弹 +863548083 15x100mm FRAGMENTATION 15x100mm破片弹 +2281763433 15x100mm High Explosive 15x100mm高爆弹 +157117576 15x100mm HIGH EXPLOSIVE 15x100mm高爆弹 +588576062 15x100mm High Velocity 15x100mm高速弹 +1138755612 15x100mm HIGH VELOCITY 15x100mm高速弹 +142076512 15x100mm Plasma 15x100mm等离子弹 +2005634151 15x100mm PLASMA 15x100mm等离子弹 +540790024 15x100mm Standard Rocket 15x100mm标准火箭弹 +506441583 15x100mm STANDARD ROCKET 15x100mm标准火箭弹 +2388228706 15x100mm Thermite 15x100mm铝热弹 +1308129373 15x100mm THERMITE 15x100mm铝热弹 +115737347 15x100mm Toxic 15x100mm毒弹 +7826706 15x100mm TOXIC 15x100mm毒弹 +3460898800 1ST 第1 +2390390042 2 2 +481620116 200kg Bomb 200KG炸弹 +4282079442 200KG BOMB 200KG炸弹 +304247992 20mm APHET Rounds 20mm穿甲高爆曳光弹 +3919538924 20mm APHET ROUNDS 20mm穿甲高爆曳光弹 +1957494835 20mm Flak Rounds 20mm高射炮弹 +3558706970 20mm FLAK ROUNDS 20mm高射炮弹 +4088907109 20mm HE Cannon 20mm高爆炮弹 +1281078922 20mm HE CANNON 20mm高爆炮弹 +444439542 20mm HVAP Rounds 20mm高速穿甲弹 +912411220 20X FASTER 加快20倍 +2708477764 23mm HE Cannon 23mm高爆炮弹 +3818318720 23mm HE CANNON 23mm高爆炮弹 +357585113 2ND 第2 +1202754851 2x Support Scope 2倍支援瞄准镜 +3888529137 2x SUPPORT SCOPE 2倍支援瞄准镜 +2940193716 2x Tube Red Dot 2倍红点瞄准镜 +3610251186 2x TUBE RED DOT 2倍红点瞄准镜 +2057952192 3 3 +1108214397 300 SC 300超级货币 +3463600927 300 SC 300超级货币 +375831634 30mm APHE Cannon 30mm穿甲高爆炮弹 +1955821453 30mm APHE CANNON 30mm穿甲高爆炮弹 +3283649708 33000000 33000000 +1391564657 33FFFEE1 33FFFEE1 +1500396403 375 SC 375超级货币 +306277038 380mm HE Cannon Round 380mm高爆炮弹 +2909856589 380mm HE CANNON ROUND 380mm高爆炮弹 +593930033 3RD 第3 +3088565990 4 4 +100397000 40-K 40-K +2486949043 40mm APHE Cannon 40mm穿甲高爆炮弹 +3400629146 40mm APHE CANNON 40mm穿甲高爆炮弹 +2731343897 40mm Flak Cannon 40mm高射炮弹 +2092226836 40mm FLAK CANNON 40mm高射炮弹 +77491964 40MM HE 40mm高爆弹 +1639593129 40mm HE Grenade 40mm高爆榴弹 +3162259359 40mm HE GRENADE 40mm高爆榴弹 +2679866361 40mm HE Mortar 40mm高爆迫击炮弹 +900451699 40mm HE MORTAR 40mm高爆迫击炮弹 +4130282705 40mm HEAT Grenade 40mm高爆反坦克榴弹 +3647277445 40mm HEAT GRENADE 40mm高爆反坦克榴弹 +2584047110 40mm Proximity Grenade 40mm感应榴弹 +911637357 40mm PROXIMITY GRENADE 40mm感应榴弹 +420168384 45-Degree Vertical Foregrip 45度垂直前握把 +2492665796 45-DEGREE VERTICAL FOREGRIP 45度垂直前握把 +3950887010 4x Combat Scope 4倍战斗瞄准镜 +201467962 4x COMBAT SCOPE 4倍战斗瞄准镜 +4247313880 5 5 +2675103067 5-STAR GENERAL 五星将军 +3235311858 5-STAR SUPER PRIVATE 五星超级列兵 +1727605984 5.5x50mm Devastator 5.5x50mm“毁灭者”子弹 +1008836023 5.5x50mm DEVASTATOR 5.5x50mm“毁灭者”子弹 +1729276638 5.5x50mm Double Power 5.5x50mm双效子弹 +3032181602 5.5x50mm DOUBLE POWER 5.5x50mm双效子弹 +845341741 5.5x50mm Explosive 5.5x50mm爆炸子弹 +2328689947 5.5x50mm EXPLOSIVE 5.5x50mm爆炸子弹 +575503280 5.5x50mm Full Metal Jacket 5.5x50mm全金属被甲弹 +3312133772 5.5x50mm FULL METAL JACKET 5.5x50mm全金属被甲弹 +2966570029 5.5x50mm High Velocity 5.5x50mm高速弹 +219628234 5.5x50mm HIGH VELOCITY 5.5x50mm高速弹 +1273786716 5.5x50mm Hollow-Point 5.5x50mm空尖弹 +3502913941 5.5x50mm HOLLOW-POINT 5.5x50mm空尖弹 +1535909110 5.5x50mm Penetrator 5.5x50mm穿甲弹 +424697282 5.5x50mm PENETRATOR 5.5x50mm穿甲弹 +74446152 5.5x50mm Ripper 5.5x50mm撕裂弹 +1034583368 5.5x50mm RIPPER 5.5x50mm撕裂弹 +1076076121 5.5x50mm Self Propelled 5.5x50mm自走弹 +3366160039 5.5x50mm SELF PROPELLED 5.5x50mm自走弹 +1742246064 5.5x50mm Subsonic 5.5x50mm亚音速弹 +2564887408 5.5x50mm SUBSONIC 5.5x50mm亚音速弹 +1694926820 5.5x50mm Super Uranium Core 5.5x50mm超铀芯弹 +2711584435 5.5x50mm SUPER URANIUM CORE 5.5x50mm超铀芯弹 +1731333326 50 SC 50超级货币 +4293738038 50 SC 50超级货币 +1860230325 50% of Objectives Completed 达成50%的目标 +3871383257 500kg Bomb 500KG炸弹 +1027666422 500kg BOMB 500KG炸弹 +72712385 500kg Bomb Mk2 500KG炸弹 MK2 +2327923803 500kg BOMB MK2 500KG炸弹 MK2 +106024694 500kg Bomb Mk3 500KG炸弹 MK3 +4259753446 500kg BOMB MK3 500KG炸弹 MK3 +3599293836 5913D460 5913D460 +1834345078 59FF4752 59FF4752 +1449862733 6 6 +2709930160 66FFFEE1 66FFFEE1 +1699114725 66mm Missile 66mm导弹 +1769974695 66mm MISSILE 66mm导弹 +2853175724 66mm Missile Mk2 66mm导弹 MK2 +4061912893 66mm MISSILE MK2 66mm导弹 MK2 +1256670303 7 7 +3725589312 70mm HE Rocket 70mm高爆火箭弹 +3787926408 70mm HE ROCKET 70mm高爆火箭弹 +1236867166 70mm Laser-Guided Missile 70mm激光制导导弹 +3172466473 70mm LASER-GUIDED MISSILE 70mm激光制导导弹 +3562346675 70mm Laser-Guided Missile Mk2 70mm激光制导导弹 MK2 +325884510 70mm LASER-GUIDED MISSILE MK2 70mm激光制导导弹 MK2 +1463594513 70mm Standard Rocket 70mm标准火箭弹 +2721110291 70mm STANDARD ROCKET 70mm标准火箭弹 +665567634 750 SC 750超级货币 +188540169 75mm HEAT Grenade 75mm高爆反坦克榴弹 +1271169426 75mm HEAT GRENADE 75mm高爆反坦克榴弹 +2061243786 79 Million Heroes Added to the Wall in Another Glorious Martyrs' Day. 7900万英雄光荣烈士日送入英烈墙 +2333231349 8 8 +2438969995 80FF4752 80FF4752 +1214176856 82-Year-Old Woman Catches Sedition Group Meeting In Attic. 82岁女性家中阁楼发现叛乱团伙集会 +89657345 85mm Armor-Piercing Grenade 85mm穿甲榴弹 +602679130 85mm ARMOR-PIERCING GRENADE 85mm穿甲榴弹 +2358467843 85mm HEAT Grenade 85mm高爆反坦克榴弹 +4104815779 85mm HEAT GRENADE 85mm高爆反坦克榴弹 +878567138 85mm HEAT Grenade Mk2 85mm高爆反坦克榴弹 MK2 +3114200480 85mm HEAT GRENADE MK2 85mm高爆反坦克榴弹 MK2 +3406929005 85mm High-Explosive Grenade 85mm高爆榴弹 +3584258719 85mm HIGH-EXPLOSIVE GRENADE 85mm高爆榴弹 +124996132 85mm High-Explosive Grenade Mk2 85mm高爆榴弹 MK2 +1252425200 85mm HIGH-EXPLOSIVE GRENADE MK2 85mm高爆榴弹 MK2 +3464640475 8MM 8mm +3317701550 8x60mm Airburst 8x60mm空爆弹 +2455708090 8x60mm AIRBURST 8x60mm空爆弹 +2058398893 8x60mm Devastator 8x60mm“毁灭者”子弹 +1211142157 8x60mm DEVASTATOR 8x60mm“毁灭者”子弹 +4153504313 8x60mm Double Power 8x60mm双效子弹 +210430859 8x60mm DOUBLE POWER 8x60mm双效子弹 +3996198327 8x60mm Explosive 8x60mm爆炸子弹 +4170256899 8x60mm EXPLOSIVE 8x60mm爆炸子弹 +3339839144 8x60mm Full Metal Jacket 8x60mm全金属被甲弹 +1070874442 8x60mm FULL METAL JACKET 8x60mm全金属被甲弹 +1982995052 8x60mm High Velocity 8x60mm高速弹 +277757238 8x60mm HIGH VELOCITY 8x60mm高速弹 +2752003323 8x60mm Liberty Fire 8x60mm“解放之火”子弹 +3623401670 8x60mm LIBERTY FIRE 8x60mm“解放之火”子弹 +980084344 8x60mm Penetrator 8x60mm穿甲弹 +3675562023 8x60mm PENETRATOR 8x60mm穿甲弹 +3106137081 8x60mm Sniper Armor Piercing 8x60mm穿甲狙击弹 +1151249928 8x60mm SNIPER ARMOR PIERCING 8x60mm穿甲狙击弹 +1263422577 8x60mm Subsonic 8x60mm亚音速弹 +662698202 8x60mm SUBSONIC 8x60mm亚音速弹 +3324353248 8x60mm Super Uranium Core 8x60mm超铀芯弹 +1472302649 8x60mm SUPER URANIUM CORE 8x60mm超铀芯弹 +926375565 9 9 +105054415 9+ 9+ +2023625259 99.6% 99.6% +741210402 990C0A05 990C0A05 +2468465243 9x20mm Explosive 9x20mm爆炸子弹 +3211598868 9x20mm EXPLOSIVE 9x20mm爆炸子弹 +4121854553 9x20mm Full Metal Jacket 9x20mm全金属被甲弹 +2276577553 9x20mm FULL METAL JACKET 9x20mm全金属被甲弹 +4219107198 9x20mm High Velocity 9x20mm高速弹 +3088795731 9x20mm HIGH VELOCITY 9x20mm高速弹 +593823393 9x20mm Hollow Point 9x20mm空尖弹 +3007182605 9x20mm HOLLOW POINT 9x20mm空尖弹 +1785353567 9x20mm Plasma 9x20mm等离子弹 +1604083448 9x20mm PLASMA 9x20mm等离子弹 +3781476342 9x20mm Ripper 9x20mm撕裂弹 +1313492103 9x20mm RIPPER 9x20mm撕裂弹 +2189560651 9x20mm Thermite 9x20mm铝热弹 +2283751018 9x20mm THERMITE 9x20mm铝热弹 +1233005872 9x20mm Toxic 9x20mm毒弹 +1477766289 9x20mm TOXIC 9x20mm毒弹 +1738034047 9x70mm Full Metal Jacket 9x70mm全金属被甲弹 +4182010729 9x70mm FULL METAL JACKET 9x70mm全金属被甲弹 +2756506409 9x70mm High Velocity 9x70mm高速弹 +2694217352 9x70mm HIGH VELOCITY 9x70mm高速弹 +2113093791 9x70mm Penetrator 9x70mm穿甲弹 +2071578481 9x70mm PENETRATOR 9x70mm穿甲弹 +1386177237 9x70mm Self Propelled 9x70mm自走弹 +357349411 9x70mm SELF PROPELLED 9x70mm自走弹 +3522846961 9x70mm Sniper Armor Piercing 9x70mm穿甲狙击弹 +3756236745 9x70mm SNIPER ARMOR PIERCING 9x70mm穿甲狙击弹 +214199932 9x70mm Socom Assassin 9x70mm“刺客”特种作战弹 +3561306084 9x70mm SOCOM ASSASSIN 9x70mm“刺客”特种作战弹 +1783580467 9x70mm Super Uranium Core 9x70mm超铀芯弹 +4198529584 9x70mm SUPER URANIUM CORE 9x70mm超铀芯弹 +3306354563 繁體中文 繁體中文 +566372895 简体中文 简体中文 +2022789461 日本語 日本語 +2795304333 中文 中文 +3898950705 A 'compliance weapon' to modify enemy behaviour. Creates a thick smoke screen to block targets' line of sight. 改变敌人行为的“慑敌武器”,可形成一道厚重的烟幕,遮挡目标的视线。 +968200865 A "compliance weapon" to modify enemy behavior. The projectile temporarily stuns all targets within the strike radius. 改变敌人行为的“慑敌武器”。射弹可短时眩晕攻击范围内的所有目标。 +1984855403 A SAMPLE CONTAINER was dropped. Pick it up to retrieve the SAMPLES it contains. 一个样本容器掉落。把它捡起来,收回里面的样本。 +715614302 A backpack containing six adhesive C4 charges and a handheld wireless electronic detonator. Charges can be deployed and detonated individually, or as multiple simultaneous blasts. 背包内装有6枚粘性C4炸药和一个手持式无线电子起爆器。炸药可单独部署并引爆,也可多枚同时引爆。 +1818586518 A backpack which can be wielded as a one-handed ballistic shield, protecting against small arms fire. 可用作单手防弹护盾的背包,能抵挡轻型武器的射击。 +2210047765 A backpack-mounted Hellbomb that can be armed by the wearer or an ally, starting a countdown. Users are recommended to remove the backpack before the countdown reaches zero. 背包式地狱火炸弹,穿戴者或盟友激活后将开启倒计时。建议在倒计时归零前移除背包。 +2253302537 A barrage of bombs creating a non-targeted carpet of explosions. 发动无目标地毯式轰炸的炸弹火力网。 +1374645675 A barrage of gas bombs that leave a corrosive gas cloud in their wake. 连续发射多枚毒气弹,爆炸后形成腐蚀性气团。 +1868966435 A barrage of gas bombs that leave a corrosive gas cloud in their wake. 连续发射多枚毒气弹,爆炸后形成腐蚀性气团。 +1132758889 A barrage of high explosive rounds, fired from the Destroyer's high speed rotary autocannons. 驱逐舰的高速旋转式机炮发射高爆弹,形成火力网。 +459824368 A barrage of napalm bombs, creating a wall of fire which will stop the enemy in their tracks. 凝固汽油弹火力网,可形成一道火墙,阻止敌人进攻。 +3175686507 A barrage of rocket pods, which the Eagle pilot will release on the largest target near the stratagem beacon. 火箭巢火力网。“飞鹰”驾驶员会将其发射至靠近战略配备信标的最大型目标。 +2577236392 A barrage of smoke grenades, creating a thick smoke screen to block enemies' line of sight. 烟雾弹火力网,可形成一道厚重的烟幕,阻挡敌人的视线。 +2748911653 A basic iron sight for Helldivers who want to relive the glorious struggles of their ancestors. 基础机械瞄具,适合希望重温先辈辉煌奋斗历程的绝地潜兵。 +3308224804 A belt-fed minigun with an exceptional ammo capacity. Cannot be reloaded with standard non-belted munitions. 使用弹链供弹的机枪,弹药容量非常充足。无法使用标准无链式弹药装填。 +679349357 A blazing-hot desert planet, its rocky mesas are the sole interruptions to the endless sea of dunes. 灼热的沙漠星球,除了坚硬的平顶山以外,只有数不尽的沙丘。 +1401793427 A cache of 99% purity platinum is located here. The Automatons intend to use this valuable metal to endanger Democracy. Seize it. 这里存有一批纯度高达99%的铂金。机器人企图利用这批贵重金属来危害民主伟业。夺取铂金。 +3592860045 A cache of cutting-edge fusion batteries are located here. They are made with stolen materials. Seize them. 这里存有一批尖端聚变电池。它们是用盗取的材料制造而成的。夺取电池。 +2908523052 A camo paint job for use in arctic environments. 适用于雪地环境的迷彩涂装。 +2098089846 A camo paint job for use in desert environments. 适用于沙漠环境的迷彩涂装。 +4123602578 A camo paint job for use in forest environments. 适用于森林环境的迷彩涂装。 +3405992804 A camo paint job for use in urban environments. 适用于城市环境的迷彩涂装。 +2527031335 A cape commemorating the Helldivers who paved the way for the successful launch of the improved TCS+. An enduring reminder of Super Earth’s engineering power and commitment to suppressing the Terminid horde. 这款披肩旨在铭记为成功启动升级版TCS+扫清障碍的绝地潜兵。它是超级地球工程伟力与誓要消灭终结族决心的永恒见证。 +4201323204 A cape inspired by hypothetical covert operatives—pillars of Democratic order, operating in the hostile abyss where Liberty's light cannot yet reach. 这件披肩的灵感源于幻想的秘密特工,他们被视为民主秩序的支柱,在尚未亮起自由之光的危险深渊中执行任务。 +696286169 A cape that strikes a subroutine emulating fear into the CPUs of all Automatons who conduct visual scans of it. 所有扫描此披肩的机器人,其CPU都将被植入模拟恐惧情绪的子程序。 +2895603657 A catastrophic weather event has decimated enemy forces, leading to a significant friendly advance on #V_ONE. 灾难性天气事件重挫了敌军力量,让我方在#V_ONE上取得重大进展。 +573619187 A Charger was last sighted in this region. 强袭虫的最后目击地点就在这个地区。 +837795733 A choir of patriotic schoolchildren sings the Super Earth anthem to each cape as the final step in its production. 此披肩制作过程的最后一步,是由爱国儿童唱诗班向着每一件披肩唱超级地球国歌。 +1259395942 A cluster fragmentation grenade. The shrapnel submunition allows it to inflict damage over a large area. 一种集束破片手榴弹。弹片能够在大范围内造成伤害。 +655389263 A cluster of hive entrances has been mapped in this region. 这个地区内标记有多处虫窝入口。 +2050963109 A combination assault rifle/grenade launcher. Versatile, but heavy to wield. 突击步枪与榴弹发射器的组合武器。用途广泛,但比较像重型武器的操控手感。 +197005611 A common magazine type in the Super Earth military, favoring sustained fire over handling. 超级地球军队常用弹匣,适合持续提供火力,但操控性较差。 +2752607517 A compact comms relay hub that can be effortlessly deployed on demand. 小巧的通信中继站,可按需轻松部署。 +980576485 A compact handgun-style flamethrower, able to project a jet of fire over short distances. 手枪式便携火焰喷射器,能够喷射近程火焰。 +3067427360 A compact version of the Liberator designed for increased viability in close quarters. Has an increased fire rate at the cost of higher spread. 便携版“解放者”,设计目的是提升近距离交战的生存能力。射速提高,但散射更广。 +781284349 A compact, low caliber machine gun. Trades power for ease of use, with faster reloading than heavier machine guns. 小口径紧凑型机枪。牺牲火力,换取便利性,装弹速度比更重型机枪更快。 +2853784115 A constricted muzzle that forces the shotgun pellets together into a tighter group. 收束枪口,迫使霰弹十分密集地发射。 +2851064640 A contingent of Helldivers have taken the initiative to push for the liberation of Malevelon Creek, even as the activation of the TCS remains an objective. + +As is already understood, Helldivers are peerless strategists, fully entrusted to exercise force wherever they deem Liberty can be best served. Super Earth High Command has total confidence in the ability of the Helldivers to fully consider the relevant risks involved, and whatever consequences may occur, as a result of their strategic decisions. 一支绝地潜兵分遣队已经主动出征,推动麦拉芬蒙河的解放大业发展,与此同时,启动TCS依然是我方的目标。 + +众所周知,绝地潜兵精于战略,能全权决定在其认为适合散播自由精神的任何地方使用武力。超级地球最高指挥部完全相信绝地潜兵有能力充分考虑其战略决策带来的风险,以及可能产生的任何后果。 +456226933 A Counter-Orbital Cannon is positioned at this site. 此处部署有反轨道加农炮。 +186926806 A crashed escape pod in the region contains valuable data. 坠毁在该地区的一个逃生舱中存着有价值的数据。 +4240961977 A crimson algae has propagated wildly across this entire planet, coating its rocky hills with a constant red that masks the spilt blood of the heroes who defend it from tyranny. 一种深红色的藻类在这颗星球大肆繁殖,嶙峋峭壁也通通被染红,掩盖了抵抗暴政的英雄在此洒下的热血。 +1512212255 A Dark Fluid-powered backpack that generates a portable micro-wormhole. This safe and well-understood technology allows the wearer to warp short distances. Warning: do not use while pack is overloaded. 暗液体驱动的背包,可生成便携式微型虫洞。这项安全且成熟的技术可助使用者进行短距离传送。警告:背包过载时请勿使用。 +1185748997 A dart-firing pistol. Each of its six rounds administers a gaseous chemical agent, harmful to hostiles whether organic or artificial, that also induces a state of delirium in the target. 发射飞镖的手枪。其六发飞镖均含有气态化学制剂,对有机或人造敌人都能造成伤害,还会令目标陷入神志不清的状态。 +1541244759 A deadly strain of ground-bursting Terminids is present on this planet. Prepare to face burrowing enemies. 这颗星球上出现了一种从地下破土而出的致命终结族变种。请做好应对钻地敌军的准备。 +3706310389 A dense nest of Stalkers has been sighted in this area. 这个地区内发现有大量追踪虫聚居的巢穴。 +3169288052 A dense swarm of Terminids has amassed in this region. 有大量终结族聚集在这个地区。 +2146788206 A dense Terminid swarm is located here. Eradicate it. 这里聚集着终结族虫群。彻底消灭它们。 +959254541 A desert planet prone to unpredictable and dangerous sand twisters. 沙漠星球,时常发生危险而又难以预测的尘卷风。 +3875504792 A device used to communicate between the Department of Expansion and Colonial Overseers. 拓殖地监督员和扩张部之间的通信设备。 +125076576 A domestic version of this armor is available for citizens who wish to perform efficient home renovation projects. 希望提高住宅装修效率的公民可以购买这套盔甲的家用版本。 +2272579577 A downed recon plane is crashed here. Its data is stored in a black box somewhere amongst the wreckage. 被击落的侦察机在此处坠毁。存有数据的黑匣子就在坠毁点附近。 +3122737775 A drill capable of piercing the tough walls of Terminid hives, and deploying a nuclear charge to collapse all tunnels. 这台钻机能够穿透终结族虫窝的坚硬墙体,还能部署核炸药摧毁所有隧道。 +1310660946 A drone that defends its user by firing caustic gas at nearby enemies, blinding and slowing them temporarily. Returns to backpack to refill. 通过向周遭敌人发射腐蚀气体保护使用者的无人机,可使敌人暂时致盲并减速。收回背包可补充气体。 +826748686 A faithful replica of the armor worn at The Battle of Liberty Peak. Honor their legacy, and wear it with pride. 如实还原解放峰之战的盔甲。尊重他们的遗产,骄傲地将其穿在身上。 +1401993058 A flare that illuminates the battlefield. 可以照亮战场的照明弹。 +3966364180 A flattened muzzle that forces the shotgun pellets into a thin horizontal line. 扁平枪口,迫使霰弹呈水平细线发射。 +3859177696 A frantic final harvest appears to have been attempted during evacuation. 撤离期间似乎有人试图疯狂收割最后一波。 +2618604845 A frozen world covered in ice that is broken only by reddish rock and spongy moss. 冰天雪地的寒冷星球,间或可见浅红色的岩石与海绵般的苔藓。 +805086839 A fuel station in this district powers the Cyborg Production Unit with highly combustible hydrogen. 该区域的燃料站为生化人的生产单元供应高度易燃的氢气能源。 +1147397142 A fully automatic assault rifle featuring a non-removable suppressor and subsonic ammunition. Slower rounds allow low-profile operation. 配备不可拆卸消音器和亚音速弹药的全自动突击步枪。弹药速度较低,便于执行隐蔽行动。 +847218420 A fully-automatic cannon effective against light vehicle armor. Includes support backpack required for reloading. 全自动加农炮,可有效对付轻型载具装甲。包含支援背包,用于装填弹药。 +2856919707 A fully-automatic pistol with an extremely high fire rate, allowing for efficient crowd control. 射速极高的全自动手枪,可以有效对敌人实施群体控制。 +735411736 A fully-automatic shotgun with a high rate of fire, excellent for controlling crowds. Requires frequent reloading. 高射速的全自动霰弹枪是群体控制的绝佳选择。需要频繁装弹。 +2457964233 A Gazer Spire surveys the surrounding area from this vantage point. 一座凝视者尖塔从此处制高点监视着周边区域。 +749051481 A geologically recent cataclysm wiped out nearly all life on this planet. Ash and jagged lava rock seem to be all that's left. 在地质时间尺度上较为近期内发生的一场灾难几乎抹杀了这颗星球上所有的生命。唯一剩下的似乎只有灰烬和凹凸不平的岩浆岩。 +3007597551 A grenade launcher effective against armored infantry. Not intended for use against vehicle armor or fortified buildings. 榴弹发射器,可有效对付装甲步兵。不适合用于攻击载具装甲或防卫森严的建筑。 +1611333158 A grenade launcher that can be fired continuously to deliver a nonstop barrage of explosives. 可持续射击的榴弹发射器,能够不间断地倾泻火力。 +2986000559 A grenade that releases a cloud of toxic gas, effective at temporarily blinding and slowing both organic and inorganic enemies. 释放有毒气团的榴弹,可使有机体和无机体敌人暂时致盲并减速。 +2496593312 A Ground All-Terrain Extraction Rig (GATER) has been deployed to this area, where multiple E-711 reservoirs have been identified. + +You have been summarily certified as Expert Large Vehicle Operators. Deploy to the area and utilize the GATER to extract E-711 from all identified locations. 此区域已部署地面全地形采集钻机(GATER),也已确认存在多个711元素储藏点。 + +仓促间你已被授予大型载具驾驶专家的资格。请部署到该区域并使用GATER从所有确认地点提取711元素。 +1029683930 A Ground All-Terrain Extraction Rig (GATER) has been deployed to this area, where multiple high-value substance reservoirs have been identified. + +You have been summarily certified as Expert Large Vehicle Operators. Deploy to the area and utilize the GATER to extract the mysterious substance from all identified locations. 此区域已部署地面全地形采集钻机(GATER),也已确认存在多个珍贵物质储藏点。 + +仓促间你已被授予大型载具驾驶专家的资格。请部署到该区域并使用GATER从所有确认地点提取神秘物质。 +3680874974 A group of Class-A citizens are stranded at a priority evacuation port. We cannot leave these patriots to be slaughtered by the Terminids. + +Get to the port and secure the evacuation of as many civilians as can fit aboard the designated transport shuttle. 一组A级公民被困在优先级疏散港口。我们不能让这些爱国者为终结族所残杀。 + +前往港口,确保让尽可能多的平民登上指定运输船进行疏散。 +3867962983 A group of Class-A citizens are stranded at an emergency evacuation port. We cannot leave these patriots to be massacred by the Automatons. + +Get to the port and secure the evacuation of as many civilians as can fit aboard the designated transport shuttle. 一组A级公民被困在紧急疏散港口。我们不能让这些爱国者为机器人所屠戮。 + +前往港口,确保让尽可能多的平民登上指定运输船进行疏散。 +2773753195 A half-constricted muzzle that forces the shotgun pellets together into a somewhat tighter group. 半收束枪口,迫使霰弹较密集地发射。 +392655212 A heatsink calibrated to purposely generate heat faster than standard heatsinks. 经过特殊校准,这种散热器的发热速度快于标准散热器。 +2855610300 A heatsink with thinner cooling elements, improving cooling rate. 配备更薄冷却元件的散热器,降温速率更快。 +3822174712 A heavier version of the Breaker shotgun, with higher damage at the cost of recoil and maneuverability. 更重型的“破裂者”霰弹枪,虽然牺牲了后坐力和操控性,伤害却有所提升。 +4232092504 A heavily fortified Automaton position containing an Automaton CPU with valuable secret data. Extract with it, and your counterintelligence support will be rewarded. 防卫森严的机器人据点,内部设置了机器人CPU,存有宝贵的机密数据。携带该CPU撤离,你的反情报支持工作将获得相应回报。 +2090959963 A heavily reinforced Automaton convoy is expected to cross through this region. Intercept and destroy the convoy before it leaves the mission area. 重装强化的机器人车队预计将穿越该区域。在车队离开任务区域之前将其拦截并摧毁。 +3696388150 A heavily-armored tank destroyer armed with a 120mm high-velocity cannon and a heavy coaxial machinegun. 重装甲坦克歼击车,配备120mm高速火炮和重型同轴机枪。 +855357990 A heavily-guarded cache of high-grade platinum is located here. The material is the rightful property of Super Earth and its citizens, and it is your duty to reclaim it. + +Local reinforcements will activate as soon as your presence is detected. Get in, reclaim the material, and get out. 这里存有一批高品质铂金,周围戒备森严。这些物资属于超级地球及其公民的合法财产,将其夺回是你们的职责。 + +敌军在当地的增援部队一旦发现你们,就会立即启动。闯入目的地,夺回物资,然后撤离。 +1561103553 A heavy one-handed blade. Slower to swing than other melee weapons, but deals more damage. 沉重的单手刀。挥舞速度比其他近战武器慢,但造成的伤害更高。 +178234324 A heavy-duty submachine gun that fires large-caliber rounds, with a slower rate of fire to manage the high recoil. Ideal for use at close to medium range. 重型冲锋枪,可发射大口径子弹,但由于后坐力较大,射速较慢。适合中近距离使用。 +868871432 A heavy-hitting, one-handed melee weapon. 重型单手近战武器。 +782020106 A heavy, large-caliber marksman rifle bridging the gap between precision and sheer stopping power. Fires armor-piercing rounds coated in a high-ignition thermite compound to ignite targets. 一款重型大口径精确射手步枪,完美兼顾精准度与强劲的停止作用。发射涂有高燃铝热剂化合物的穿甲弹,可引燃目标。 +1674562767 A Helldiver-operated weapon of mass liberation. Paid for with the blood of soldiers and the credits of taxpayers, this technological marvel is Democracy made manifest. 绝地潜兵操纵的大规模解放武器。用士兵鲜血和纳税人税款铸就的这一技术奇迹堪称民主的象征。 +1976891343 A Hellpod containing a Super Solid State Drive, the peak of secure data storage. Used by Helldivers for everything from transfer of patriotic data to the sabotage of enemy mainframes. 装有最为安全的数据存储,超级固态硬盘的绝地喷射舱。从传输爱国数据到破坏敌人主机,绝地潜兵将其用于各种用途。 +2431441016 A Hellpod containing four supply packs, to replenish personal ammunition and stims in the field. 装有四个补给背包的绝地喷射舱,可在战场上补充个人弹药和治疗剂储备。 +2806852005 A Hellpod containing four supply packs, to replenish personal ammunition and stims in the field. 装有四个补给背包的绝地喷射舱,可在战场上补充个人弹药和治疗剂储备。 +3114376362 A helmet worn by the pioneering Helldivers who first ventured into the Void. Designed by Super Earth scientists with liberated Illuminate blueprints. 这款头盔由首批踏入寂域的先驱绝地潜兵所佩戴。由超级地球科学家利用解放的光能者手中蓝图设计而成。 +1645117720 A HELPING HAND 施以援手 +3890859532 A high explosive grenade which damages lightly armored targets. Creates high damage over a small area when detonated. 高爆榴弹,能伤害轻型装甲的目标。引爆时可在小范围内造成较高伤害。 +497210558 A high explosive grenade which detonates on first impact. 一旦碰撞立即引爆的高爆榴弹。 +3778802681 A high-caliber assault rifle with a restrictive magazine size but more stopping power. 大口径突击步枪,弹匣容量有限,但停止作用较强。 +1263897094 A high-caliber rifle with high damage and penetration. 大口径步枪,拥有超高的伤害和穿透力。 +326359764 A high-caliber sniper rifle effective over long distances against light vehicle armor. This rifle must be aimed downscope. 大口径狙击步枪,在远程范围内可有效对付轻型载具装甲。此步枪必须开镜瞄准。 +149163679 A high-caliber submachine gun which can be fired with one hand. Has a relatively low rate of fire. 可单手操控的大口径冲锋枪。射速相对较低。 +187703435 A high-damage revolver, which can be reloaded with single rounds. A heavy-hitting and reliable sidearm. 伤害较高的左轮手枪,可以装填单发弹药。此随身武器攻击力强大,相当可靠。 +706503498 A high-definition tactical video camera has been deployed to this location. It is critical to recording evidence of the enemy's crimes. 我方已在此处部署一台高清战术摄像机。它对记录敌军罪证至关重要。 +444149039 A high-precision burst-fire plasma rifle that must be charged to fire. 高精度连发等离子步枪,需充能才能开火。 +3561843631 A high-speed Fast Recon Vehicle equipped with an automated defense turret and a mounted supply rack, allowing frontline personnel to fully replenish ammunition and medical supplies on the move. 高速的快速侦察载具,配备自动防御炮台和挂载式补给架,允许前线人员在移动中全面补充弹药和医疗补给。 +576576475 A high-torque laser rifle that fires a continuous beam of thermal energy. If allowed to fully overheat, the weapon discharges a massive, explosive energy burst before requiring a heat sink replacement. 一款高转矩激光步枪,可发射持续的热能光束。若允许其完全过热,该武器在需要更换散热器前会释放出一股巨大的爆炸性能量脉冲。 +3169729221 A high-velocity railcannon round fired at the largest target in close proximity to the beacon. Targeting is automatic. 向信标附近的最大型目标发射高速轨道炮弹。轨道炮自动完成目标定位。 +2684434865 A highly secure facility for the safe growth and breeding of Terminids and low-risk extraction of E-710 is located here. 高度戒备设施,用于安全繁育终结族和低风险提取710元素。 +1672483217 A holographic sight. 全息瞄准镜。 +1225340446 A humane compliance weapon with two separate magazines: one for armor-penetrating flechette rounds and one for stun rounds. 符合人道主义的武器,共有两个独立弹匣:一个装备穿甲飞镖霰弹,另一个装备眩晕弹。 +440691790 A humane grenade launcher firing high-powered arc grenades. 发射高能电弧榴弹的人道主义榴弹发射器。 +2167250335 A humane, autonomous drone equipped with a modified Arc Thrower. Capable of projecting arcs of lightning through multiple targets. Does not need to recharge between shots. 配备改良版电弧发射器的人道主义自主无人机。能够向多个目标发射电弧闪电。每次射击前无需充能。 +760871862 A large Automaton air base in this region is conducting frequent troop deployments by Dropship—a tactical advantage we cannot allow. + +Deploy behind enemy lines and destroy their Dropships and the air base's infrastructure. 机器人在该地区有一座大型航空基地正在频繁使用运输舰调度部队——我们不能放任它们继续占领这种战术优势。 + +深入敌方防线背后,摧毁它们的运输舰,破坏航空基地的基础设施。 +898053559 A large bomb obliterating almost any target close to impact. Make sure to clear the area. 一枚大型炸弹,可湮灭靠近爆炸范围的近乎所有目标。请确保所有人员撤离爆炸区域。 +3549104601 A large-capacity assault rifle firing humane stun rounds. Reports of lethal incidents have been thoroughly debunked. 大容量突击步枪,能发射人道主义眩晕弹药。相关致命事件的报告已被证实为谣言。 +2884787603 A larger heatsink that can store more heat. 容量更大的散热器,可储存更多热量。 +1510362032 A LAS-16 Sickle model with all overheating protections conveniently removed, allowing for far longer bursts of fire. Does more damage when overheated, at the cost of slightly burning the user. 移除所有过热保护机制的LAS-16“镰刀”型号,显著延长连射时间。 过热时会造成更大伤害,但会轻微灼伤使用者。 +866092399 A laser pistol that fires a continuous beam. Does not require ammo but can overheat and need to change batteries. 发射连续激光束的激光手枪。无需装弹,但如果手枪过热,必须更换电池。 +2611051440 A laser rifle firing a continuous beam. Does not need reloading, but if it overheats a new heat sink must be fitted. 发射连续激光束的激光步枪。无需重新装弹,但如果步枪过热,必须安装新的散热器。 +1431416010 A laser rifle, firing in short bursts. Does not need reloading, but if it overheats a new heat sink must be fitted. 可瞬间喷射高能激光束的激光步枪。无需重新装弹,但如果步枪过热,必须安装新的散热器。 +594530405 A laser weapon firing a continuous beam. Doesn't require ammunition, but will need heat sink replaced if it overheats. 发射连续光束的激光武器。无需弹药,但武器过热时需要更换散热器。 +130433830 A lightly-armored Fast Recon Vehicle mounted with a heavy machinegun. 轻型装甲快速侦察载具,搭载重机枪。 +695509966 A lightweight flamethrower. Shoots pressurized fuel through a dispersion nozzle into an open flame. Safe. 轻型火焰喷射器。通过扩散喷嘴喷射加压燃料,形成明火。相当安全。 +2797112084 A lightweight melee weapon that temporarily stuns enemies. 轻型近战武器,可暂时眩晕敌人。 +3997337233 A limited-time expedition is being conducted into the Gloom on this planet, at significant cost. 该星球上正在开展限时“阴霾”探索行动,代价巨大。 +3773653766 A linear artillery barrage which moves at intervals while firing smoke bombs to obscure enemy visibility. 间歇性移动的线形火力网,通过发射烟雾弹,阻断敌方视线。 +1772996316 A linear artillery barrage which moves at intervals while firing smoke bombs to obscure enemy visibility. 间歇性移动的线形火力网,通过发射烟雾弹,阻断敌方视线。 +2367237658 A linear artillery barrage which moves at intervals, driving the enemy out from cover while allowing an advance. 间歇性移动的线形火力网,可将敌人逐离掩体,同时让我方前进。 +130471606 A longer revolver barrel that results in a higher muzzle velocity and lower recoil at the cost of worse handling. 加长版左轮枪管,可有效提升枪口初速并降低后坐力,代价是操控性下降。 +1385974777 A machine gun designed for stationary use. Trades higher power for increased recoil and reduced accuracy. 为固定使用而设计的机枪。提高了火力,但后坐力增加,精准度也降低了。 +1896446197 A magazine with a very high capacity at the cost of being bulky and heavy. 该弹匣的弹药容量极大,但较笨重。 +1867837818 A Major Order has been completed. Check the Galactic Map for more information. 一项重要指令已完成。查看星系地图了解更多信息。 +1801952199 A Major Order has been failed. Check the Galactic Map for more information. 一项重要指令未能完成。查看星系地图了解更多信息。 +2279292804 A manned gun emplacement offering superior firepower against lightly armored targets. Slow to turn, so place it wisely. 手动炮台,强悍的火力能有效对付轻型装甲目标。转向速度较慢,请明智选择部署位置。 +1023956951 A mark of stalwart loyalty bestowed only to those who have proved themselves worthy through unquestioning dedication. 坚定忠诚的标志,仅授予那些通过绝对的奉献来证明自身资格的战士。 +952667345 A massive number of Automaton militants are concentrated in this overrun city. Decisive action must be taken to reduce their numbers. + +Deploy to the middle of the combat zone, and kill as many bots as you can. 大量机器人武装分子集结在这座沦陷的城市中。必须果断采取行动,削减它们的数量。 + +动身前往战区中心,全力消灭机器人。 +2182563833 A massive Terminid Nursery has been discovered here, crawling with millions of freshly-hatched larvae, mere weeks from ravenous adulthood. They must be wiped out, before they reach maturity and kill innocent human children. + +Terminid Nurseries consist of one or more Nursery Chambers. Use the Hive Breaker Drill to deliver a nuclear extermination device to each one. 我方发现此处存在一个巨大的终结族繁育窝,聚集着上百万只刚刚孵化的幼虫,只需几周,它们便能成长为贪婪的成虫。必须将它们铲除,以免其育成并残害无辜的儿童。 + +终结族繁育窝由多个繁育腔室组成。使用“虫窝破裂者”钻机将核试验设备送至每一个腔室。 +3673328843 A massive Terminid Nursery has been discovered here, crawling with millions of freshly-hatched larvae, mere weeks from ravenous adulthood. They must be wiped out, before they reach maturity even if we must sacrifice the city to do so. + +Terminid Nurseries consist of one or more Nursery Chambers. Use the Hive Breaker Drill to deliver a nuclear extermination device to each one. 我方发现此处存在一个巨大的终结族繁育窝,聚集着上百万只刚刚孵化的幼虫,只需几周,它们便能成长为贪婪的成虫。为避免它们育成,必须将它们全部铲除,即使要牺牲整座城市也在所不惜。 + +终结族繁育窝由数量不等的繁育腔室组成。使用虫窝破裂者将核灭绝装置送入各个腔室。 +1117477617 A massive Terminid swarm has gathered in this area. We cannot leave this threat unchecked if we are to take the city back. + +Kill as many Terminids as you can to thin their numbers. 大批终结族已在此区域聚集。要夺回这座城市,我们必须消除这一威胁。 + +全力击杀更多终结族,削减它们的数量。 +4130287931 A massive Terminid swarm is gathering in this region. Left unchecked, it threatens to explode out of control. + +Kill as many Terminids as you can to thin their numbers. 一个庞大的终结族虫群正在该地区集结。如果置之不理,它们可能有失控的风险。 + +尽可能击杀更多终结族,削减它们的数量。 +885841187 A mechanical chiller at this location cools the hydrogen that flows into the Cyborg Production Unit. 这里的机械冷却器为流入生化人生产单元的氢气降温。 +2432112479 A melee weapon tipped with electrified prongs that temporarily stun targets. Can be wielded one-handed. 近战武器,矛头带电刺,可暂时眩晕目标。支持单手操作。 +189073958 A message is etched into the surface: "In everlasting gratitude to the loyal soldiers who gave their lives in the defense of Managed Democracy." 雕像表面刻着一句话:“永远感谢为捍卫管理式民主而牺牲的烈士。” +1309000342 A message is etched into the surface: "In eternal remembrance of the innumerable Helldivers who made the ultimate sacrifice in the First Galactic War." 雕像表面刻着一句话:“永远怀念第一次星系战争中献身的无数绝地潜兵。” +2411766708 A message is etched into the surface: "In memory of Liberty's servants who perished heroically in unavoidable friendly fire incidents." 雕像表面刻着一句话:“纪念因难以避免的友军误伤而英勇阵亡的解放忠仆。” +2647716199 A mid-range precision rifle. Equipped with an integrated suppressor and subsonic rounds for barely-detectable operation. 这是一支中程精准步枪。配备集成式消音器和亚音速弹药,方便执行难以被察觉的行动。 +1046849492 A mighty rifle with a signature lever-action enabling single round reload. Powerful precision suited to mid- and long-range combat. 威力强大的步枪,经典拉柄式设计支持单发装填。精准度极高,适合中远程作战。 +779490921 A mine extracting platinum from deep-seated deposits of igneous rock. 从深层火成岩中开采铂金的矿井。 +1839032438 A modern reinvention of the Lumberers of the first Galactic War, this Exosuit is equipped with a flamethrower and an anti-tank cannon. 这款外骨骼装甲是第一次星系战争中“伐木者”机甲的现代重制版,配备火焰喷射器和反坦克炮。 +2449026855 A modified Breaker shotgun firing birdshot, small pellets which saturate an area to clear up smaller targets. 改良后的“破裂者”霰弹枪,可发射鸟弹,分散的细小弹丸足以清除一定区域内的小型目标。 +1879205579 A modified Breaker shotgun firing incendiary projectiles. Generates heat during use, so limited to burst fire. 改良后的“破裂者”霰弹枪,可发射燃烧弹。在使用过程中会产生热量,因此会限制连发射击。 +682687661 A modified Breaker shotgun offering improved armor penetration and accuracy, with exceptionally high levels of recoil. 改良后的“破裂者”霰弹枪,穿甲性能和精准度有所提升,后坐力尤其高。 +3932879168 A modified Diligence rifle offering increased damage at the cost of some maneuverability. Fires a single bullet at a time. 改良的“勤勉”步枪,伤害有所提高,但牺牲了一点操控性。每次只能发射一发子弹。 +1880175574 A modified Liberator firing concussive rounds which do less damage but stagger enemies. 改良版“解放者”,可连续发射震荡弹。虽然造成的伤害不大,但可击退敌人。 +1362075423 A modified Liberator fitted with a scope and firing armor-piercing rounds, to help users take down armored targets. 改装后的“解放者”搭配瞄准镜,可发射穿甲弹,助力使用者击倒装备护甲的目标。 +432202992 A modified Punisher shotgun firing exploding plasma rounds. Fire carefully - exploding plasma can injure squadmates. 改良后的“制裁者”霰弹枪,可发射会引爆的等离子弹。射击时务必小心,爆炸的等离子体可能会伤及队友。 +3811159907 A modified Punisher shotgun firing heavy, high-damage slug rounds. Perfect for punching big holes in big targets. 改良后的“制裁者”霰弹枪,可发射重型高伤害独头弹,是往大型目标身上开洞的完美之选。 +276825548 A mutated strain of Terminids has been reported on this planet. Expect to encounter cunning hunter bugs. 据报告,该星球上出现了一种终结族变异体。请做好准备,应对狡诈的追猎虫。 +1134814559 A mutation causes Terminids on this planet to generate excess hormonal spores, which drive other similarly mutated Terminids into a frenzy. Prepare to face enemies that bolster each others' speed. 一场突变导致该星球上的终结族产生过量激素孢子,驱使其他发生类似突变的终结族陷入狂暴。准备迎击这些为彼此提速的敌人。 +3264320310 A nest of flying Shriekers has been reported in this area. 这个地区内发现飞空尖啸虫的巢穴。 +802464482 A network of towers stand ready to dispense bug-killing Termicide across the planet. Once they're active, this planet will be cleansed of Terminids, forever. + +Activate the Termicide Dispersion Tower in this region, and bathe it in a purifying haze of Termicide. 巨塔网络已准备好在星球各地喷洒灭虫终结剂。一旦启动,这颗星球就可以永远免受终结族的威胁。 + +启动该地区的灭虫终结剂喷洒塔,让灭虫终结剂的雾气带来净化的洗礼。 +3489906412 A new fleet of Super Destroyers is under construction here. 这里正在打造超级驱逐舰的新舰队。 +583621227 A new Major Order has been issued. Check the Galactic Map for more information. 一项重要指令已发布。查看星系地图了解更多信息。 +2509196198 A new, highly dangerous Terminid Variant has decimated SEAF units in this area. We must limit the spread of this mutant strain. + +Find and eradicate the Variant. Exercise extreme caution. 一种极其危险的新型终结族亚种在该区域重挫了超级地球武装部队。我们必须限制该突变种扩散。 + +找到并铲除该亚种。务必谨慎行事。 +2926213020 A Nursery Chamber is located here, ripe with millions of feeding larvae who tunneled here after hatching on the surface. Use the Hive Breaker Drill to deliver a nuclear payload and wipe them out. 此处有一个繁育腔室,其抚育着数百万只在地表孵化后就钻入地下觅食的幼虫,使用“虫窝破裂者”钻机将核炸药送入腔室,将幼虫铲除。 +3324564789 A one-handed ceremonial sword suitable for use in parades, sabrage, and combat. 单手礼仪刀,适合阅兵、开瓶和战斗。 +2968071618 A one-handed device that deploys a wide energy barrier in front of the user. The barrier is semipermeable and blocks high-speed projectiles from the outside only, leaving the user free to shoot through it. 可单手操作的装置,使用时会在正前方展开宽大的能量屏障。该半透屏障只会抵挡外部高速射弹,使用者发射的子弹能自由穿透屏障。 +1450506817 A paint job for use in arctic environments. 适用于雪地环境的涂装。 +1057583371 A paint job for use in desert environments. 适用于沙漠环境的涂装。 +1651892789 A paint job for use in forest environments. 适用于森林环境的涂装。 +3883362231 A paint job for use in urban environments. 适用于城市环境的涂装。 +1079016720 A paint job that dares to stand out. 敢于引人注目的涂装。 +3434065534 A paint job that is one with the darkness. 与黑暗融为一体的涂装。 +3238307974 A pair of safety goggles hang by a strap, the frames spattered with blood. They seem to have failed their purpose. 一副安全护目镜挂在带子上,镜框上有血迹。看来它没能完成自己的使命。 +1784509355 A Patriotic Miracle? Woman on Pioneer II Finds Flag of Super Earth In Toast 爱国主义奇迹?先驱II星系上的女子在吐司中发现超级地球旗帜 +1511294332 A perenially chilly climate has allowed short, colorful shrubs to flourish across this planet's surface. 这里常年寒冷,颜色各异的矮小灌木在得天独厚的气候条件下占领了这颗星球的地表。 +3835713360 A perfectly balanced multitool, optimized for the displacement of soil and other forms of resistance with surgical precision. 一款完美平衡的多功能工具,经过特别优化,能以外科手术级的精准度移除土壤以及其他形式的抵抗。 +3678248605 A pistol firing bursts of guided, jet-propelled ammunition. Can be set to non-guided mode at any time, removing the need to lock on to targets. 能发射制导喷射弹的手枪。随时可切换为非制导模式,无需锁定目标。 +2682411428 A pistol firing guided, jet-propelled ammunition. It's lock-on feature ensures high accuracy, but the weapon must be reloaded after every round fired. 一款发射喷气推进式制导弹药的手枪。具备锁定功能,可确保高射击精度,但每次开火后均须重新装填弹药。 +3865629619 A pistol front-loaded with a single, powerful explosive. The weight of the projectile limits the weapon's range. 前端加装单颗强力射弹的手枪。射弹重量限制了手枪的射程。 +4013788670 A pistol that fires grenades. Must be reloaded between shots. 发射榴弹的手枪,每射击一发子弹后必须重新装弹。 +4119981266 A pistol with a built-in laser sight, suppressor, and flashlight. +Produced by Martian Armory. 内置激光瞄准器、消音器和手电筒的手枪。 +由火星军械库生产。 +860066182 A plasma pistol that charges each shot until the trigger is released. Plasma projectiles explode on impact. 等离子手枪,每发射击都可充能,松开扳机即可开火。等离子弹触碰着弹点后会爆炸。 +2679742135 A plasma rifle that fires bolts of superheated gas, which can be charged by holding down the trigger. Charging up a shot fully makes the bolt explode on impact. 等离子步枪,可发射过热气体,按住扳机即可为其充能。每发射击完全充能后,触及着弹点后引爆。 +3125008658 A plasma rifle, firing a bolt of superheated gas which explodes on impact. Avoid standing in proximity to the blast. 等离子步枪,可发射一束过热气体,触及着弹点后引爆。请勿站在爆炸点附近。 +469762336 A player cannot be reported for this action. You can take any of the following actions instead. 无法以此行为为由举报玩家,你可以另行选择下列操作。 +1776173825 A powerful automated turret, effective against armored targets. The turret will primarily aim at larger enemies. 强力自动炮台,可有效对付装甲目标。炮台主要瞄准攻击较大型的敌人。 +138799023 A powerful dual magazine pump-action shotgun, with limited armor penetration. Ideal for small and fast targets. 强大的双弹夹泵动式霰弹枪,穿甲力有限,这是攻击小型和快速目标的理想之选。 +1109767528 A powerful manned gun emplacement, capable of taking out armored targets at long ranges. 威力强大的手动炮台,可摧毁远距离装甲目标。 +3280319132 A powerful plasma weapon that fires one blast at a time, each blast exploding on impact. Must be charged to fire. Warning: do not overcharge. 威力强大的等离子武器,每次单发射击,击中目标后爆炸。开火前需要充能。警告:请勿过度充能。 +2167995265 A powerful, single-use, proximity-detonated heat energy mine. During the Fall of Chara, it is said enough Melta Mines were detonated to outshine the planet's sun. + +Produced by ST Construction. 一种威力强大的一次性近炸热能地雷。据说在常陈四陷落期间,巨量热熔地雷被引爆,散发出的光芒甚至比该星系中的恒星更耀眼。 + +由ST建筑公司生产。 +905887718 A precision artillery salvo over a small area, perfect for taking out concentrated enemy units. 向小范围区域齐射的精准火力打击,可完美解决集中在一起的敌方单位。 +1013174421 A product of the Illuminate’s so-called intellectual superiority and experimentation, the Wretch is a vile fusion of once human biomatter and hateful propaganda. These pathetic puppets envy the democratic rights of Super Earth citizens and seek to cut down those still loyal to Liberty. 作为光能者所谓高等智慧与试验测试的产物,悲怜体是一种由昔日人类生物物质与仇恨洗脑的宣传融合而成的邪恶造物。这些可怜的傀儡嫉妒超级地球公民所享有的民主权利,妄图残害仍坚守解放大业的志士。 +3363562662 A projected laser, that is aligned with the barrel of the weapon, which assists the user with landing their shots. 与武器枪管对齐的投射激光,辅助使用者命中目标。 +1385818198 A projectile which explodes while airborne, creating a deadly rain of shrapnel. Not effective against heavy armor. 射弹在空中引爆,而后弹片散落,如同致命的雨点。对重型装甲无效。 +2094967063 A projectile which releases a cloud of caustic gas, blinding and slowing most enemies. 释放腐蚀性气团的射弹,可使大多数敌人致盲并减速。 +2549590927 A prolonged barrage, wreaking extended destruction over a large area. Communication with teammates is advised. 持续输出火力网,可大面积范围造成破坏。使用前建议与队友进行通信。 +4225821927 A pump shotgun that fires a burst of incendiary phosphorus pellets, setting targets ablaze. 泵动式霰弹枪,可连射燃烧磷弹,将目标点燃。 +1285985862 A quality product, this armor can destroy over 300,000 kilometers of fencing with no decline in operational efficiency. 即使撞破30万公里的栅栏,这套高品质盔甲的使用效率也丝毫不会下降。 +658237782 A rack containing every tool one needs to construct a better tomorrow. 一副支架,上面放着构建美好明天所需的所有工具。 +3192210987 A recoilless rifle effective against vehicle armor. Includes support backpack required for reloading. 无后坐力炮,可有效对付载具装甲。包含支援背包,用于装填弹药。 +2133995538 A reliable assault rifle with an antique iron sight, firing incendiary ammunition. 可靠的突击步枪,配备老式机械瞄具,可发射燃烧弹药。 +2284500136 A remote SEAF research station in this region remains structurally intact despite the Void's illegal planetary annexation. Data collected before and after the planet's fall is of critical importance to our efforts to understand this lawless realm. + +Access the station, download the research database, and upload it to the Super Earth mainframe. 尽管寂域非法吞并星球,该地区一座偏远的超级地球武装部队研究站仍然结构完好。该星球陷落前后收集到的数据,对于我们了解寂域这一法外之地至关重要。 + +前往该研究站,下载研究数据库,然后将其上传至超级地球主机。 +1413448488 A replacement for a fallen comrade. 阵亡战友的替补兵员。 +1519932262 A representation of the thankfulness of those infinite descendants whose liberated existence we strive to ensure. 我们竭尽全力让无数后代过上解放的生活,而这代表了他们的感激之心。 +4139348968 A repurposed firework that showers its immediate surrounding area in sparks before exploding. As delightful as it is incendiary. 由烟花改装而成,在爆炸前向四周溅射火花。既绚丽如烟火,又致命如烈焰。 +3864025069 A rocky, lonely moon with extremely valuable mineral deposits underneath the surface. 崎岖不平的孤单卫星,地下埋着极其珍贵的矿产。 +671445976 A SAMPLE FOR YOUR TROUBLES 浅尝麻烦 +742449904 A scope with 10x magnification, good for long range on high accuracy weapons. 10倍放大瞄准镜,适合高精度武器远程打击使用。 +2288844056 A SEAF Reconnaissance aircraft was just shot down at this site. The aircraft had identified critical intelligence of enemy force allocations. + +Infiltrate the area and secure the black box containing the intel. 超级地球武装部队的一架侦察机刚刚在此地被击落。该侦察机发现了敌军兵力部署的关键情报。 + +潜入该区域,取回存有情报的黑匣子。 +1486066125 A SEAF research station in the region has been overrun by Terminids. Their vital work must be recovered. + +Get to the station, download the research database, and upload it to the Super Earth mainframe using the nearby Satellite Uplink Station. 该地区的一座超级地球武装部队研究站已被终结族占领。他们的重要工作必须恢复。 + +前往该研究站,下载研究数据库,然后使用附近的卫星上行链路站点将其上传至超级地球主机。 +1255486553 A semi-automatic ceremonial rifle equipped with a bayonet. Can be set to fire in three-shot bursts, to easily conduct the Fallen Hero's Salute. 配备刺刀的半自动礼仪步枪。可设置为三连发模式,轻松鸣枪致敬陨落的英雄。 +1961315473 A shorter magazine with lower capacity, making it lighter and easier to handle. 弹药容量较小的短弹匣,重量更轻,操控更方便。 +2466410356 A shovel that can be used as a melee weapon or, more conventionally, to dig holes in the ground. 铲子,除了能在地上挖洞,还可用作近战武器。 +2437224263 A sight with thin features to maximize visibility of the target. 纤薄设计的瞄准镜,可最大限度地提升目标可见度。 +359043006 A significant SEAF military outpost is present on this planet. 此星球上坐落着超级地球武装部队的重要军事哨站。 +2698304084 A silenced assault rifle with a built-in suppressor, which won't alert distant targets to the user's position. 内置抑制器的消音突击步枪,可避免向远处的目标暴露使用者的位置。 +2579238661 A silo that fits one single, powerful missile. Comes with a handheld targeting remote. 发射井可容纳一枚强力导弹。配备手持定位遥控器。 +3809290968 A simple vertical foregrip to improve the maneuverability of the weapon. 简单垂直前握把,可提升武器操控性。 +3022121013 A single precision shot from the Destroyer's 'ATLAS' cannon. 来自驱逐舰“阿特拉斯”轨道加农炮的一发精准攻击。 +1021342965 A single-use target-seeking anti-aircraft missile launcher. Must be locked to target before firing. 一次性寻的防空导弹发射器。发射前必须锁定目标。 +141003101 A single-use weapon firing a high-yield missile. Discarded after every use. 发射大当量导弹的一次性武器。用后即弃。 +2066801016 A single-use weapon specialized for damaging vehicle armor. Discarded after every use. 专门破坏载具装甲的一次性武器。用后即弃。 +1446123923 A single-use weapon sporting caseless ammunition stacked in multiple barrels. An electrical firing mechanism releases the rounds in rapid succession upon firing, after which the weapon is to be discarded. 采用无壳弹药与多枪管叠加设计的一次性武器。开火时,电控击发装置会快速清空弹药,弹药清空后即可丢弃该武器。 +1911326461 A single-use weapon that fires a missile containing napalm cluster bombs that release upon impact. 一次性武器,发射的导弹会在撞击时释放凝固汽油集束炸弹。 +3518847546 A slamfire shotgun: fires continuously while the trigger is depressed, via activation of the pump-action mechanism. Loaded with armor-piercing flechettes and equipped with an extended bayonet. 一款速射霰弹枪:扣住扳机即可连续开火射击,采用泵动结构。装填穿甲飞镖弹,并配备加长刺刀。 +2030754614 A sledgehammer that can be wielded with or without an explosive charge attached to its head. 大锤头部可安装炸药,也可单独使用。 +1985611308 A smoke grenade that rapidly deploys a small, dense cloud. Allows for rapid personal concealment and exfiltration. 快速在小范围内释放高密度烟雾的烟雾弹。有助于隐蔽个人行踪和掩护撤离行动。 +2494575413 A smoldering heap of scrap. It got what it deserved. 一堆闷烧的废料。总算是恶有恶报。 +2846526723 A speargun firing heavy-duty projectiles. These projectiles release a cloud of gas on impact, and must be carefully loaded one at a time. 一种发射重型短矛的矛枪。这些短矛在命中时会释放一团气体,装填时必须小心操作,每次装一枚。 +3550526620 A specialized Fast Recon Vehicle equipped with heavier armor, a spiked ramming grille, and a roof-mounted heavy flamethrower at the expense of seating; this FRV can enable up to three Helldivers to deliver high-speed Justice, and forcefully clear obstructed transport routes. 牺牲了座位以换取更厚重的装甲、带刺的冲撞格栅以及车顶安装的重型火焰喷射器。该快速侦察载具最多可承载三名绝地潜兵,高速播撒正义,强力打通受阻的运输路线。 +1132103161 A speed-loaded volley gun with three different firing modes and three different RPM options. Warning: recoil varies significantly between firing modes. 快速装填的齐射枪,具备三种不同的射击模式,以及三种不同射速选项。警告:不同射击模式之间的后坐力差异巨大。 +2256936138 A standard-issue rack of standard-issue tools. 收纳制式工具的制式支架。 +189153727 A stationary ballistic cover with a mounted grenade launcher. Can protect multiple Helldivers from small arms fire. 固定式防弹掩体,架设有榴弹发射器。可抵挡轻型武器的射击,保护多名绝地潜兵。 +1113723435 A stationary ballistic cover with a mounted light machine gun. Can protect multiple Helldivers from small arms fire. 固定式防弹掩体,架设有轻机枪。可抵挡轻型武器的射击,保护多名绝地潜兵。 +3644933986 A stationary energy shield which provides cover against projectiles. Has a limited lifetime once deployed. 固定式能量护盾,可用作掩体抵挡射弹。部署完毕后仅在有限时间内起防护作用。 +3222052854 A strafing run of the battlefield to clear small targets, delivered almost instantly. 机枪扫射清除战场上的小型目标,几乎可在一瞬间内完成扫射。 +2376192175 A subdued cape, for those who need no recognition—save that of their enemies, as their executioner. 为不愿被认出的战士而设计的低调披肩。但敌人一眼就能认出,因为披肩的出现,代表他们死期已到。 +511259600 A submachine gun with a helical-feed magazine, which gives the weapon a higher ammo capacity while making it more front-heavy. Produced by Stål Arms. 冲锋枪,配备螺旋式供弹弹匣,弹药容量增加,但前重后轻。由斯塔尔武装生产。 +1536255450 A submachine gun with a longer barrel, allowing for higher muzzle velocity and increased armor penetration. 配备加长枪管的冲锋枪,枪口初速更高且具备更强的护甲穿透能力。 +1451270601 A submachine gun with an extremely high rate of fire, which can be operated with one hand. Ideal for multitasking. 射速极高的冲锋枪,可单手操控。同时处理多重任务时的理想之选。 +2430531062 A symbol of fierce commitment to Liberty and Democracy, this cape celebrates the Helldivers who have held true to Super Earth values through rain or shine. 这件披肩象征着对自由和民主的坚定承诺,颂扬那些风雨无阻地坚守超级地球价值观的绝地潜兵。 +1566415735 A symbol of Super Earth's Astral Promise: that every star shall one day illuminate throngs of joyous voters. 超级地球星之承诺的象征:终有一日,每一颗星都将因快乐的选民而闪亮。 +2583815220 A symbol of the constant, forward-moving propulsive force of Managed Democracy. This cape honors those who understand that in the race for Freedom, there are no brakes—only degrees of momentum. 胜利矢量象征管理式民主恒定前进的驱动力。这件披肩向那些明白在自由竞赛中没有刹车、唯有动力强弱之分的人致敬。 +1419287698 A targeted air strike unable to destroy buildings, but efficient at clearing smaller targets. 定向空袭,无法摧毁建筑,但可以有效清除较小型目标。 +3775020939 A targeting remote, used in combination with the Solo Silo. 定位遥控器,与单兵导弹发射井配合使用。 +1413828601 A TCS+ station at this site is loaded with refined Termicide 2.0, now with no credible risk of unintended mutagenic side effects. Once initiated, it will sterilize the area with fumes highly lethal to Terminids, yet entirely safe to humans. + +Activate the TCS+ station, and bathe the region in a purifying haze of Termicide. 此处的TCS+站已装载精制灭虫终结剂2.0,无任何可证实的意外诱变副作用风险。一旦启动,它将释放对终结族极度致命但对人类完全安全的烟雾,对该区域进行彻底消杀。 + +启动TCS+站,让这片区域沐浴在灭虫终结剂的净化烟雾中。 +1780333244 A Terminid Nursery has been identified beneath the surface at this location. Millions of Terminid larvae gestate in the underground chambers. + +Terminid Nurseries consist of one or more Nursery Chambers. Use the Hive Breaker Drill to deliver a nuclear extermination device to each one. 此位置地底下发现了终结族繁育窝。数百万只终结族幼虫正在地下腔室中孵化。 + +终结族繁育窝由数量不等的繁育腔室组成。使用虫窝破裂者将核灭绝装置送入各个腔室。 +2191463346 A thermite grenade designed to adhere to surfaces before burning at 2000°C. Capable of burning through some armor. 铝热榴弹,经过专门设计,可附着于表面,燃烧温度高达2000°C,能烧穿部分装甲。 +20063808 A throwable anti-personnel mine, capable of adhering to most surfaces. Upon deployment, emits lights and sounds which attract nearby hostiles to its proximity-activated detonator. 可投掷式反步兵地雷,能附着在大部分表面。部署后发出光和声音,吸引附近敌人靠近它的感应引爆装置。 +2504366851 A throwable device engineered to bounce when hitting the ground, releasing bursts of electricity on each impact. Warning: may bounce unpredictably. 经过特殊设计的投掷设备,击中地面时会弹起,每次撞击都会释放电流。警告:弹跳方向可能难以预测。 +3513035794 A throwable emplacement that generates a spherical, projectile-blocking shield on impact. Has a limited lifetime once deployed. 可投掷的防护装置,落地时生成阻挡投射物的球形护盾。部署后的持续时间有限。 +399898153 A tool is missing from its spot. Likely pilfered by the enemy for some iniquitous application. 工具不翼而飞。很可能是心怀不轨的敌人偷走的。 +3323987103 A tool of tyranny. 实施暴政的工具。 +1254106340 A top-loaded shotgun prominently featured in the final episode of "Obedient Democracy Support Troopers." +Produced by Martian Armory. 顶部装弹的霰弹枪,在《民主光环驰援部队》大结局中有突出表现。 +由火星军械库生产。 +1047010937 A tribute to the Liberation of Choepessa IV in the First Galactic War, in which so much orbital ordnance was detonated that its sun was occluded by ash for an entire lunar cycle. 纪念第一次星系战争的科埃佩萨IV解放战役。彼时投射的轨道火力留下了漫天烟尘,将恒星的光芒遮蔽了整整一个月。 +3849232494 A tribute to the mischief-makers and mavericks, those trailblazers who dutifully execute their orders with universally-endearing panache. The star-crossed trail calls to mind the special kind of Freedom that can only be achieved by going very fast in very expensive state-owned vehicles. 对捣蛋鬼与特立独行者的致敬之作,这些开疆拓土的先锋恪尽职守使命必达,潇洒风度广受拥戴。如星轨交错般的下摆令人联想到一种特殊的“自由”——惟有为国驾驶价值不菲的载具疾速冲锋方能得到的自由。 +2766518568 A triple-barreled, break-action, sawed-off shotgun. Switch firing modes to fire all three barrels at once. 三枪管中折式截短霰弹枪。可将开火模式切换为同时使用三枪管开火。 +2863703793 A tube red dot sight with 2x magnification, good for hitting small targets consistently over medium range. 2倍放大管式红点瞄准镜,适合中程持续精准打击小型目标。 +3418552701 A turret firing powerful and precise laser beams. Warning: overloading heat sink may cause adverse effects. 炮台,可发射威力强悍且精准的激光束。警告:散热器过载可能产生反效果。 +2910711004 A turret firing powerful shells in a high arc. Effective at long ranges, and able to strike at targets behind cover. 以高弧度发射强力弹药的炮台。在远程范围内较为高效,能打击藏于掩体后方的目标。 +914930931 A turret firing static field generators that slow the advance of enemies. 炮台可发射静电场发生器,拖延敌人前进的脚步。 +325063728 A turret which fires electrical charges at targets in close range. To avoid friendly fire, remain prone. 向近程目标释放电击的炮台。为避免误伤,请保持匍匐姿势。 +1565025413 A twisted distortion of one of Humanity's greatest inventions. 人类最伟大的发明之一,现已扭曲变形。 +3287936605 A unanticipated rush of Terminids has overwhelmed SEAF defenses on #V_ONE, leading to a large loss of territory. 突如其来的终结族袭击令#V_ONE上的超级地球武装部队防线崩溃,导致大面积阵地落入敌手。 +1362515695 A useful field-clearing tool for removing trees, obstacles, and unlucky foes. 用于清除树木、障碍物和倒霉敌人的实用野外清理工具。 +2086203058 A variation on the reflex sight. 改良版反射式瞄准镜 +4246890330 A vast network of underground hives has allowed the Terminids in this region to become entrenched, breeding and swelling in number. + +Fortunately, this hive has just gone into a brief hibernation. Infiltrate, and destroy all you can before the Terminids return to full strength. 庞大的地下虫窝网络使终结族得以在该地区根深蒂固,不断繁殖壮大。 + +幸好,这个虫窝刚刚进入了短暂的休眠状态。赶在终结族完全恢复力量之前潜入其中,尽可能摧毁一切。 +4278423406 A versatile missile launcher loaded with seven lock-on homing missiles. These can either be fired from the launcher directly or as an airburst. Includes support backpack required for reloading. +Produced by Stål Arms. 多功能导弹发射器,装载了七枚锁定追踪式导弹。导弹可通过发射器直接发射或作为空爆弹发射。包含支援背包,用于装填弹药。 +由斯塔尔武装公司生产。 +713817588 A versatile submachine gun equipped with iron sights and frontline incineration capabilities. 一款多用途冲锋枪,配备机械瞄具,具备前线炽灼能力。 +526827858 A vertical foregrip with an integrated tactical light. 配备集成战术灯的垂直前握把。 +2064918640 A very powerful but difficult-to-wield machine gun with intense recoil. 火力凶猛的机枪,但后坐力强,较难操控。 +93792649 A welcome sight in all Democratic neighborhoods, this armor inspires both civil pride and civic obedience. 这款盔甲在所有民主社区都备受欢迎,既能激发公民自豪感,又能促进公民服从命令。 +3036570949 A-35 Recon A-35“侦察者” +3953487134 A-35 RECON A-35“侦察者” +1456963500 A-9 Helljumper A-9“地狱伞兵” +373320745 A-9 HELLJUMPER A-9“地狱伞兵” +3638602961 A/AC-8 A/AC-8 +660688178 A/ARC-3 A/ARC-3 +3681724202 A/FLAM-40 A/FLAM-40 +375454065 A/G-16 A/G-16 +457150574 A/GM-17 A/GM-17 +1927106234 A/LAS-98 A/LAS-98 +3899708304 A/M-12 A/M-12 +2658728974 A/M-23 A/M-23 +589817536 A/MG-43 A/MG-43 +2247059156 A/MLS-4X A/MLS-4X +1103811886 AA DEFENSES 对空防御 +4042981686 AA Emplacement 防空炮台 +2956984981 AA EMPLACEMENT 防空炮台 +1121439494 ABANDON MISSION WITH SQUAD 与小队放弃任务 +1428514248 Abandon Operation 放弃行动 +641748280 Abandoned SEAF Anti-Aircraft Missile Launchers will fire on enemy airborne targets when activated. 废弃的超级地球武装部队防空导弹发射器启动时,将向空中的敌方目标开火。 +4166707680 Abandoned SEAF artillery can be reactivated for ground-based support. 重新启动废弃的超级地球武装部队大炮可以提供陆基火力支援。 +3877190422 Able-bodied Citizens 健全的公民 +3656751307 ABOUT GAME DATA 关于游戏数据 +1798079858 ABOUT US 关于我们 +1723987128 ABOVE PRIMARY 主要目标上方 +1221144687 ABUNDANCE 丰饶市 +2283348879 ABUNDANCE BLUFF 丰绝崖 +3494856217 Abundant with life, this wet planet is covered in deep oceans, thick forests, and tall grasses. 这颗湿润的星球既有深海,也有郁郁葱葱的森林和草原,充满了生命的气息。 +3331509342 AC-1 Dutiful AC-1“恪尽职守” +462478699 AC-1 DUTIFUL AC-1“恪尽职守” +3898500608 AC-2 Obedient AC-2“服从指挥” +3633121216 AC-2 OBEDIENT AC-2“服从指挥” +11927780 AC-8 AC-8 +1624648166 AC-8 Autocannon stratagem availability has ended. 现已无法使用“AC-8机炮”战略配备。 +1235215129 ACAMAR IV 天园六IV +287428240 ACCELERATE 加速 +3998730464 Acceleration Exponent 加速指数 +1282991289 Acceleration Speed 加速度 +632861308 Accelerator Rifle 加速步枪 +2806489661 ACCELERATOR RIFLE 加速步枪 +269923895 ACCEPT 接受 +2993112532 ACCEPT 接受 +3261862873 ACCEPT 接受 +1642197796 Access Codes 访问代码 +1518873863 Access codes for the Planetary Defense Cannon are held at this location. 行星防御加农炮的访问代码存放在此处。 +3743248579 Access relay controls 获取中继控制权限 +1906524154 ACCESS RESTRICTED 禁止访问 +132362496 ACCESSIBILITY 协助工具 +2856343176 ACCIDENTALS: 意外阵亡次数: +3241737675 ACCLIMATED 应变自如 +1029794728 According to atmospheric measurements, airborne spore density in this area is reaching critical levels. It is only a matter of hours before this district becomes uninhabitable. + +Destroy the Terminid bio-weapons producing these spores, and allow our citizens to breathe Freely once more. 根据大气测量数据,此区域空气中的孢子密度已接近临界水平。再过几个小时,此区域将变得不适宜居住。 + +摧毁产生这些孢子的终结族生物武器,让我们的公民能再次自由呼吸。 +2612296594 ACCOUNT 账户 +1004615823 Account for PlayStation™Network not allowed to login. Please contact Community managers 账号禁止登录PlayStation™Network。请联系社区管理员 +434681982 Account Link 账户绑定 +1900267339 Account Link Failed 账户绑定失败 +619986769 Account link is active. 账号绑定已开启。 +3509603300 ACCOUNT LINK STATUS 关于账户绑定状态 +1695133110 Account Link Succeeded 成功绑定账户 +2615339905 Account Linked 已绑定账户 +1631896341 Account must be logged in with Playfab to use this functionality 必须通过Playfab登录账号才能使用该功能 +4132611929 Account Not Linked 未绑定账户 +3009292145 ACCOUNTANT GRAEBER 会计格雷伯 +451059295 ACCOUNTING CORRECTIONS 核算修正 +836288058 Accumulation of Space Trash Leads To Formation of Floating Trash Moon 太空垃圾大量积聚组成垃圾卫星 +607964299 ACCURACY: 命中率: +646100137 ACHERNAR SECUNDUS 水委一次星 +3997737977 Achieve rank #COUNT 达到级别#COUNT +2083214352 Achieve a 'Supreme' rating on a difficulty #COUNT mission 在难度系数为#COUNT的任务中获得“杰出”的评价 +798917336 Achieve a #COUNT star rating on a Horde mission 在一次群袭任务中达成#COUNT星评价 +2042206691 ACHIRD III 王良三III +2126828521 Acid 腐蚀酸 +61117111 Acid Storm In Progress 酸雨风暴正在形成 +2805628145 ACID STORMS 酸雨风暴 +2919420525 ACQUIRE EVIDENCE 获取证据 +4202494871 ACQUIRE SOIL SCAN DATA 获取土壤扫描数据 +361154753 ACQUIRED 已获取 +779140024 ACQUIRED 已获取 +3171440668 ACQUIRED E-711 已获取711元素 +4195267459 ACQUISITION CENTER 采购中心 +54274312 Acquisition data downlink from Super Earth has failed. Please check for Automaton interference and try again at a later time. 源自超级地球的数据采集下链发生故障。请检查是否有机器人的干扰,并稍后重试。 +2754520958 ACQUISITIONS 采购 +3657511086 ACQUISITIONS 采购 +1921206358 ACRAB XI 房宿四XI +1485636464 ACRUX IX 十字架二IX +336176798 ACTIONS 行动 +3782415312 ACTIONS 行动 +3647873421 ACTIVATE 启动 +3977166056 ACTIVATE 启动 +1168390666 ACTIVATE 启动 +1350042216 ACTIVATE 启动 +3623688689 ACTIVATE 启动 +3738507221 ACTIVATE 启动 +2891368293 Activate #COUNT #OBJ#RACE_PRE#RACE#RACE_POST#MULTI. 启动#COUNT台#OBJ。#RACE_PRE#RACE#RACE_POST#MULTI +3544944274 Activate all charges to trigger overload 激活所有充电装置以触发过载 +92791499 Activate Aquifer Drill 启动含水层钻机 +4081827893 Activate Artillery 启动大炮 +1828283522 Activate Artillery Terminal 启动大炮终端 +2658584822 Activate Battery Silo 01 启动电池舱01 +728454869 Activate Battery Silo 02 启动电池舱02 +1962369016 Activate Battery Silo 03 启动电池舱03 +1990429936 ACTIVATE DATA TERMINAL 启动数据终端 +1787745812 ACTIVATE DRILL 启动钻机 +1123050000 ACTIVATE DRILL 1? 是否启动1号钻机? +3288991505 ACTIVATE DRILL 2? 是否启动2号钻机? +3992186674 ACTIVATE DRILL 3? 是否启动3号钻机? +256978663 Activate extraction terminal. 激活撤离终端。 +4199732194 Activate Hive Breaker Drill 启动“虫窝破裂者”钻机 +2833945694 Activate Jammer Terminal 启动干扰装置终端 +1065955238 ACTIVATE LAUNCHER SUB-SYSTEMS 启动发射器子系统 +2069716682 Activate Liberated terminal 启动已经解放的终端 +2927224225 Activate Mobile Radar 启动移动雷达 +2271594322 ACTIVATE OIL PUMPS 启动油泵 +2312292744 Activate Prospecting Drill 启动勘探钻机 +3971712790 ACTIVATE PUMPS 启动泵机 +3876322295 Activate relay dish lift mechanism 启动中继天线升降装置 +4167754760 ACTIVATE SEISMIC SCAN? 是否启动地震扫描? +804180263 Activate Shuttle Bay Terminal 启动运输船坞终端 +863497904 ACTIVATE TCS+ 启动TCS+ +1895350756 ACTIVATE TCS+ STATION 启动TCS+站 +3967915737 ACTIVATE TCS+ STATION 启动TCS+站 +321917691 Activate terminal 启动终端 +1225832087 Activate terminal 启动终端 +1328813780 Activate terminal 启动终端 +1471869982 Activate terminal 启动终端 +1589424449 Activate terminal 启动终端 +1740852089 Activate terminal 启动终端 +2081692256 Activate terminal 启动终端 +3223307005 Activate terminal 启动终端 +3226057673 Activate terminal 启动终端 +3328841511 Activate terminal 启动终端 +3887767126 Activate terminal 启动终端 +4003000692 Activate terminal 启动终端 +4142761914 Activate terminal 启动终端 +743640675 Activate terminal at base of Central Tower 在中央巨塔底启动终端 +2575685330 ACTIVATE TERMINID CONTROL SYSTEM 启动终结族遏制体系 +2663400912 ACTIVATE TERMINID CONTROL SYSTEM 启动终结族遏制体系 +653591926 ACTIVATE TERRAIN SCAN 开启地形扫描 +2924561359 Activate the Battlefield Injury Simulator 启动战场损伤模拟器 +3461934406 Activate the communications relay 启动通信转接程序 +2380544313 Activate the Drilling Platform and ensure the successful extraction of E-711. 启动钻机平台并确保成功提取711元素。 +2525564346 Activate the Drilling Platform and ensure the successful extraction of the E-710-like substance. 启动钻机平台并确保成功提取类似710元素的物质。 +2428511542 Activate the Planetary Defense Cannon and use it to bring down the Illuminate Overship. 启动行星防御加农炮,击沉光能者统御舰。 +897258492 Activate the Seismic Scan 启动地震扫描 +3206624266 Activate the TCS+ station to cleanse this area of Terminids. 启动TCS+站,清除该区域的终结族。 +3927933937 Activate the Termicide Dispersion Tower to immunize this area from the Terminids. 启动灭虫终结剂喷洒塔,消灭该区域内的终结族。 +1281099157 ACTIVATE TOWER 启动通信塔 +3930949980 ACTIVATE TRANSFER 开始输送 +3017295425 ACTIVATE UPLINK 启动上行链路 +2224311146 ACTIVATE WARBOND 激活债券 +2434092443 Activating 正在启动 +834600132 Activating these Reinforcement Pods increases your Reinforcement Budget. + +Reinforcements will deploy directly from a Reinforcement Pod site. 启动增援太空舱会增加你的增援预算。 + +增援部队将直接从增援太空舱的位置部署。 +2195387101 Activating this generator will supply critically-needed power to SEAF devices in the region. 启动这台发电机可以为超级地球武装部队在该地区的设备提供急需的能源。 +1295360129 ACTIVATION FAILURE: VALVES BLOCKED 启动失败:阀门受阻 +135296341 Active 已激活 +2239687469 ACTIVE 已启动 +2217463241 ACTIVE ACTION 进行中的行动 +1987017360 Active for: #DAYS d #HOURS h 激活时长:#DAYS天#HOURS小时 +923254790 ACTIVE FOR: #DAYS d #HOURS h 激活时长:#DAYS天#HOURS小时 +1460026889 Active for: #HOURS h #MINUTES m 激活时长:#HOURS小时#MINUTES分 +60611655 ACTIVE FOR: #HOURS h #MINUTES m 激活时长:#HOURS小时#MINUTES分 +2404474839 Active for: #MINUTES m #SECONDS s 激活时长:#MINUTES分#SECONDS秒 +2630923665 ACTIVE FOR: #MINUTES m #SECONDS s 激活时长:#MINUTES分#SECONDS秒 +2111047309 ACTIVE THROUGH THE DEMOCRACY SPACE STATION 通过民主空间站激活 +70623210 ACUBENS PRIME 柳宿增三主星 +3352749549 AD-11 Livewire AD-11“生龙活虎” +1833365456 AD-11 LIVEWIRE AD-11“生龙活虎” +1114234159 AD-26 Bleeding Edge AD-26“血刃科技” +2698867856 AD-26 BLEEDING EDGE AD-26“血刃科技” +3764445519 AD-49 Apollonian AD-49“阿波罗神” +949548653 AD-49 APOLLONIAN AD-49“阿波罗神” +941688055 ADAM PARK 亚当帕克 +3671854941 Add all available STRATAGEMS to your loadout. 将所有可用的战略配备添加至武装配置。 +951158470 ADD TO FAVORITES 收藏 +1702409921 Additional Canisters 附加燃料罐 +1181531416 ADDITIONAL CANISTERS 附加燃料罐 +3648617997 Additional Extraction Zone 其他撤离区 +4061021323 Additional Hardpoints 附加挂载点 +635281574 ADDITIONAL HARDPOINTS 附加挂载点 +351782286 Additional Rocket Pods 附加火箭巢 +1690420521 ADDITIONAL ROCKET PODS 附加火箭巢 +3270663062 ADHAFERA SECUNDUS 轩辕十一次星 +857545008 ADHARA 弧矢七 +4201645655 Adjudicator 审判者 +1536742308 Adjudicator 裁决者 +1854068221 ADJUDICATOR 审判者 +3480845616 Adjust all valves to maximize hydrogen flow 调节所有阀门,使氢气流量达到最高 +1671801984 ADJUST BRIGHTNESS 调节亮度 +4285505595 ADJUST BRIGHTNESS 调节亮度 +759965318 Adjust pipe valves 调整管道阀门 +1265907316 ADJUST PRIVACY SETTING 调整隐私设置 +3454921047 ADJUST ROTATION AND TILT 调整旋转和倾斜角度 +2051218809 Adjust sensitivity of mouse movement. A lower setting moves the mouse more slowly, while higher settings move the mouse more quickly. 调整鼠标移动的灵敏度。下调该设置可以降低鼠标移动的速度,上调则会加快速度。 +1352114650 Adjust the field of view to allow a wider view around the player. 调整视野,允许玩家拓宽视野。 +2058260178 Adjust the intensity of the blur effect applied to moving objects and when rotating the camera. Decreasing motion blur might help with motion sickness as well as seeing moving objects. 调整物体移动和视角旋转时的模糊效果的强度。减少动态模糊或许可以缓解晕动症,有助于看清移动中的物体。 +1961432248 Adjust the opacity of text backgrounds in the HUD. 调整HUD文字背景的不透明度。 +418018538 Adjust the overall brightness of the game. 调整游戏的总体亮度。 +2576568888 Adjust the scale of your HUD. 调整HUD的尺寸。 +1799322827 Adjust Tilt 调整倾斜角度 +1348317433 Adjust valves in Control Chamber to overload engine 在控制室调节阀门使引擎过载 +3651893637 Adjust Wires 调整线路 +2607596535 Adjust zoom level. 调节缩放距离。 +662796926 Adjusts how much acceleration is applied to the controller camera control. Higher values mean much higher sensitivity when the sticks are at max range. 调整游戏控制器操控视角的加速数值。上调数值可提高操作杆在极限位置时的灵敏度。 +1601765673 Adjusts how much acceleration is applied to the controller camera control. Higher values mean much higher sensitivity when the sticks are at max range. 调整游戏控制器操控视角的加速数值。上调数值可提高摇杆在极限位置时的灵敏度。 +1939629971 Adjusts how quickly acceleration is applied to the controller camera control. If set to zero, the movement is linear. 调整控制器操控视角的加速生效速度。设置为零则视角线性移动。 +3934755190 Adjusts how quickly acceleration is applied to the wireless controller camera control. If set to zero, the movement is linear. 调整无线控制器操控视角的加速生效速度。设置为零则视角线性移动。 +1274984970 Adjusts the brightness of the UI on HDR monitors. 调整HDR显示器上的UI亮度。 +1887657809 Adjusts the controller vibration strength. 调整控制器振动强度。 +3107424198 Adjusts the controller vibration strength. 调整控制器震动强度。 +3410403455 Adjusts the intensity of the curved visual effect applied to the Heads Up Display (HUD). 调整抬头显示(HUD)的弧形视觉效果的强度。 +2299949498 Adjusts the overall sharpness of the final image. 调整最终图像的总体锐度。 +3415132323 Adjusts the position of the HUD relative to the edge of your screen. 调整HUD与屏幕边缘的相对位置。 +1535470370 Adjusts the relative sensitivity of camera movement in First Person View (FPV). 调整第一人称视角(FPV)下,视角移动的相对灵敏度。 +2727082084 Adjusts the relative sensitivity of camera movement in First Person View (FPV). 调整第一人称视角(FPV)下,视角移动的相对灵敏度。 +2810302848 Adjusts the relative sensitivity of camera movement while aiming. 调整瞄准时视角移动的相对灵敏度。 +3032891870 Adjusts the relative sensitivity of camera movement while aiming. 调整瞄准时视角移动的相对灵敏度。 +479570486 Adjusts the sensitivity of camera movement. 调整视角移动的灵敏度。 +3016774335 Adjusts the sensitivity of map movement. 调整地图移动的灵敏度。 +863508714 Adjusts the sensitivity of touch pad inputs for map movement. 调整地图移动的触摸板输入灵敏度。 +40677616 Adjusts the sensitivity of vertical camera movement relative to horizontal movement. 调整视角垂直移动相对水平移动的灵敏度。 +2006442341 Adjusts the speed of the cursor when controlled by controller. 调整游戏控制器操控下的光标速度。 +2721266125 Adjusts the speed of the cursor when controlled by controller. 调整游戏控制器操控下的光标速度。 +2014483191 Adjusts the strength of the trigger effect function. 调整扳机效果功能的强度。 +542272717 ADMIN 管理员 +3652369325 ADMIN 管理员 +4070962490 ADMINISTRATIVE CENTER 02 行政总都02 +926009925 ADMIRABLE ADMIRAL 承敬上将 +4161927870 ADMIRAL 上将 +2855703241 ADNAN 安拓市 +3539375605 Adorned with the insignia of the Order of the Venerated Ballot, a Ministry-sanctioned Patriot's Club for citizens who pledge themselves to preserving the sanctity of voting. 饰有神圣投票团的徽章,该组织是由外交部批准设立的爱国者俱乐部,加入其中的公民承诺维护投票权的神圣性。 +626417797 ADRENAL 8 脉涌8 +2198640368 ADRENO-DEFIBRILLATOR 肾上腺素除颤器 +3025804585 Advance your PROGRESSION TRACK 使进度条解锁更多进度 +3770160647 ADVANCED 高级 +2004735727 Advanced Angled Foregrip 高级直角前握把 +3797112165 ADVANCED ANGLED FOREGRIP 高级直角前握把 +3796339880 ADVANCED CONSTRUCTION 高级构造 +1146484879 ADVANCED CREW TRAINING 高级船员训练 +625528357 Advanced Devastator 进阶蹂躏者 +5232386 ADVANCED DEVASTATOR 进阶蹂躏者 +126582437 Advanced Devastators 进阶蹂躏者 +2096098484 ADVANCED FILTRATION 高级过滤能力 +4003069899 ADVANCED GRAPHICS 高级图像 +4006560498 ADVANCED SETTINGS 高级设置 +1441132035 Advanced Vertical Foregrip 高级垂直前握把 +2688006363 ADVANCED VERTICAL FOREGRIP 高级垂直前握把 +2514800411 ADVENTURE 探险市 +702988091 Advertisement 广告播报员 +1457793035 ADVERTISEMENT 广告 +3515658116 ADVERTISEMENT 广告 +407763305 Advertising 广告 +111854113 Advocate 拥护者 +1096775251 Aegis 神盾 +23818252 AERIAL DOMINANCE 制霸高空 +1819981985 Aerial scanning has identified high levels of Automaton production in this area. 空中扫描确认该区域存在大量机器人生产活动。 +306250652 AESIR PASS 亚萨关隘 +3199795572 AF-02 Haz-Master AF-02“危害大师” +3192024450 AF-02 HAZ-MASTER AF-02“危害大师” +2210667779 AF-50 Noxious Ranger AF-50“毒瘴游骑兵” +2788848665 AF-50 NOXIOUS RANGER AF-50“毒瘴游骑兵” +291785917 AF-52 Lockdown AF-52“禁锢” +1721179076 AF-52 LOCKDOWN AF-52“禁锢” +1471503938 AF-91 Field Chemist AF-91“实地化学家” +3973583853 AF-91 FIELD CHEMIST AF-91“实地化学家” +2146292003 AFFECTED AREA 影响范围 +1891203297 AFFECTED STRATAGEMS 受影响的战略配备 +1941770292 AFOYAY BAY 艾福亚湾 +1812232848 After a button has been pushed down for a set amount of time, this starts triggering continuously. 按下按键一定时间后开始连续触发操作。 +3916822154 After a button has been pushed down for a set amount of time, this starts triggering continuously. 按下按钮一定时间后开始连续触发操作。 +3245933610 After colonists of Hellmire recovered a lost shipment of this armor, the local pastime of fence-smashing was born. 海尔迈尔的拓殖地居民寻回一批丢失的这种盔甲后,当地兴起了一种狂打栅栏的娱乐方式。 +2197155395 After days of fighting, Gaellivare has fallen to the Automaton Jet Brigade. However, thanks to shrewd maneuvering of the Helldivers, the DSS is safely out of their reach. +The Helldivers, in their Democratic direction of the DSS, displayed undeniable tactical brilliance, demonstrating once again why they are known as the Galaxy's most elite fighting force. Their efforts held the Automaton onslaught long enough to allow emergency evacuation efforts to save many citizens, many of whom aided in the construction of the space station. +The Jet Brigade remains a significant threat. Meanwhile, the crisis created by the sudden and shocking outbreak at the Terminid Research Center is ongoing. The addition of the DSS to Liberty's arsenal, even in its diminished state, could not have come at a better time. Managed Democracy is imperiled; we need every weapon at our disposal. 经过数天战斗,耶利瓦勒落入了机器人喷气旅手中。不过,幸亏绝地潜兵足够机敏,DSS已安全脱离它们的控制范围。 +绝地潜兵对DSS进行民主指挥,展现无可争议的战术才华,再次证明了他们为何称得上是银河系最精锐的战斗部队。他们拼命拖住了机器人的屠戮,给我方的紧急疏散工作预留足够时间,救出了众多平民,其中许多人还曾协助建造空间站。 +喷气旅依然虎视眈眈。同时,终结族研究中心突如其来的暴乱危机仍在肆虐。解放军械库再添民主空间站这把利器,可谓恰逢其时,即便空间站已受损,仍然无可替代。管理式民主岌岌可危;我们必须动用一切可用的武器。 +1680249784 After extensive testing in Patriotic Rehabilitation Centers, this design was proved most terrifying to dissent-afflicted individuals. 爱国康复中心的详尽测试证明,这是最令异见分子感到恐惧的设计。 +313037045 After years of research into improving the Super Destroyer's firepower, the Ministry of Science concluded that the most effective method was adding more guns. 经过多年对超级驱逐舰火力改进的研究,科学部得出结论,最有效的方法是增加枪炮数量。 +1548482629 Aftermath of Planet Busters: Devastation. “歼星”成效:完全毁灭 +3554369778 against 敌人: +905652168 Against the Tyrant Cloud 破除暴瘴 +1416115244 AGAINST THE TYRANT CLOUD 破除暴瘴 +509426370 AGARTHA 雅戈泰 +1338124960 Agent 桥梁 +3186597808 Agent of Oblivion 湮灭使者 +3142356721 AGENT OF OBLIVION 湮灭使者 +3255323397 AGENT OF OBLIVION 湮灭使者 +1371180916 Agitator 惑乱者 +1966237401 AGITATOR 惑乱者 +339482685 Agitators 惑乱者 +3070340776 AGREE & CONTINUE 同意并继续 +900944397 AIDESVILLE 哈得斯维尔 +642434115 AIM 瞄准 +2462914227 AIM 瞄准 +1991803739 Aim Orbital Cannon 瞄准轨道加农炮 +1928213848 Aim Sensitivity 瞄准灵敏度 +3469065314 AIMING 瞄准 +1342954337 AIN-5 毕宿一5 +1428161101 AIR CONTROL TOWER MAINFRAME 航空控制塔主机 +650351956 Airburst Rocket Backpack 空爆火箭弹背包 +2518059568 AIRBURST ROCKET BACKPACK 空爆火箭弹背包 +2297621495 Airburst Rocket Launcher 空爆火箭弹发射器 +2292840975 AIRBURST ROCKET LAUNCHER 空爆火箭弹发射器 +71980820 AKIRA SECTOR 阿基拉分区 +3667756654 ALADFAR CXI 辇道二CXI +4168695740 ALAIRT III 艾列尔特III +3222410792 ALAMAK VII 天大将军一VII +1220978891 ALARAPH 右执法 +1545408205 ALATHFAR XI 织女增三XI +4137490107 ALDERIDGE COVE 阿尔德里奇湾 +4020124395 ALERT 警告 +927042336 ALERT: ENCRYPTED TRANSMISSION RECEIVED + +DECRYPTING… +. +. +. +CLASSIFICATION: TOP SECRET + +MINISTRY OF DEFENSE +DIRECTORATE OF HELLDIVER READINESS +ORIGINATING STATION: MARS + +MEMORANDUM FOR: Helldiver Readiness Command +SUBJECT: Daily Incoming Recruit Report + +Total Incoming Trainees: 48,736 +Avg. Age (Years): 18.7 +Avg. Combat Readiness Rating: 27.1% +Avg. Patriotism Rating: 97.4% + +Expected Survival Rate: 21.3% +Projected Helldiver Production: WITHIN QUOTA + +END TRANSMISSION 警告:接收到加密传输 + +正在解密…… +. +. +. +级别:绝密 + +国防部 +绝地潜兵备战理事会 +发出站:火星 + +备忘录收件人:绝地潜兵备战指挥部 +主题:新兵招募每日报告 + +受训新兵总数:48,736 +平均年龄(岁):18.7 +平均备战评分:27.1% +平均爱国评分:97.4% + +预期存活率:21.3% +绝地潜兵计划产量:配额内 + +结束传输 +1777619219 ALERT: ENCRYPTED TRANSMISSION RECEIVED + +DECRYPTING… +. +. +. +CLASSIFICATION: TOP SECRET + +MINISTRY OF DEFENSE +DIRECTORATE OF HELLDIVER READINESS +ORIGINATING STATION: UNDISCLOSED LOCATION + +MEMORANDUM FOR: Helldiver Readiness Command +SUBJECT: Daily Incoming Recruit Report + +Total Incoming Trainees: 48,736 +Avg. Age (Years): 18.7 +Avg. Combat Readiness Rating: 27.1% +Avg. Patriotism Rating: 97.4% + +Expected Survival Rate: 21.3% +Projected Helldiver Production: WITHIN QUOTA + +END TRANSMISSION 警告:接收到加密传输 + +正在解密…… +. +. +. +级别:绝密 + +国防部 +绝地潜兵备战理事会 +发出站:机密位置 + +备忘录收件人:绝地潜兵备战指挥部 +主题:新兵招募每日报告 + +受训新兵总数:48,736 +平均年龄(岁):18.7 +平均备战评分:27.1% +平均爱国评分:97.4% + +预期存活率:21.3% +绝地潜兵计划产量:配额内 + +结束传输 +2194002616 ALERT: INCOMING FUEL BLOCKED 警告:燃料输入路径受阻 +503902376 ALIGN SIGNAL 校准信号 +2686416718 ALIGNMENT 同心市 +4193953305 All 全部 +65909927 ALL 全部 +2281903958 ALL 全部 +1999507042 All Emplacement stratagems launch immediately once called in, reducing overall deployment time. 所有炮台战略配备在呼叫后即时发射,缩短整体部署时间。 +2385967566 All Orbital Stratagems have an increased cooldown. 所有轨道武器战略配备都会延长冷却时间。 +4010342575 All Sentry stratagems launch immediately once called in, reducing overall deployment time. 所有哨戒炮战略配备在呼叫后即时发射,缩短整体部署时间。 +1869140098 All Support Weapon stratagems launch immediately once called in, reducing overall deployment time. 所有支援武器战略配备在呼叫后即时发射,缩短整体部署时间。 +1465083245 All assets evacuated. Proceed to extraction. 全部目标已疏散完毕。开始撤离程序。 +1870939921 All Barrels 全枪管 +1604906974 ALL BOOSTERS 所有强化资源 +2837576582 All but ensures ascension to the immortal ranks of those enshrined in the Super Earth Digital Archive of Valorous Acts. 必将收录至超级地球英勇之举数字档案,比肩珍藏其中的不朽藏品。 +747694778 All currently active Orders can be viewed here. 当前可执行指令均可在此查看。 +2372554040 All Hail the Helldivers, who bring untold abundance to Super Earth's citizens. 向绝地潜兵致敬,正是他们为超级地球公民带来了无尽的财富。 +662396263 All Hail the Helldivers, whose devotion to Managed Democracy has never faltered. 向绝地潜兵致敬,他们对管理式民主的忠诚从未动摇。 +2368723721 All Hail the Helldivers, whose resplendent honor makes Tyrants tremble. 向绝地潜兵致敬,他们的荣耀光辉令暴政颤栗。 +161233440 All Helldivers will passively regenerate health at a rate of #V_ONE% per second. 所有绝地潜兵以每秒#V_ONE%的速度被动恢复生命值。 +328518441 All Objectives Completed 达成所有目标 +3951398977 All Objectives Completed 达成所有目标 +4039882095 All of these reviews have been devised by Super Earth's Ministry of Truth after an analysis to reflect the most accurate possible opinions of loyal Super Earth citizenry. In other words, these are not real reviews. 所有评论均由超级地球真理部经过分析后构思编成,以便尽可能准确地反映超级地球忠实公民的意见。换言之,这些都不是真实的评论。 +2344207218 All readings, or the notable lack thereof, indicate that the source of the Void anomaly is located here. All effort must go to enabling FTL travel to these coordinates. 各项读数表明,寂域异常的源头就在这里,部分读数因寂域干扰而缺失,更加证实了这一点。集中全部力量,实现前往该坐标的超光速航行。 +1874868078 All samples extracted with are shared by the entire squad. Work together to advance the science of Super Earth! 全部提取的样本均由整支小队共享。携手推进超级地球的科学发展吧! +3185149527 All Stratagems have their strengths and weaknesses. Choose your Stratagem loadout to best fit the mission and your squad composition. 战略配备全部各有优劣。要根据任务需要和小队阵容来挑选最合适的战略配备。 +33739635 ALL SUB-OBJECTIVES MUST BE COMPLETED FIRST 必须首先完成所有次要目标 +3125862690 ALL SYSTEMS OPERATIONAL 所有系统均正常运行 +1942440765 All that remains of a planet torn apart by the Meridian singularity. A solemn reminder of the desolation Tyranny leaves in its wake. 被默里迪恩奇点摧毁的星球残骸。它庄严地提醒着我们,暴政必将带来毁灭。 +1798419614 ALL YOU +NEED TO KNOW 通晓 +天下 +3648328316 Allied SEAF units are operating on the battlefield. 超级地球武装部队友军正在战场上作战。 +838975314 Allied Tactical Objectives 友方战术目标 +3123331391 Allow Data Collection 允许收集数据 +1557419619 Allow shuttles to collect deposited fuel from reserves. 让运输船从油田采集沉积燃料。 +797196185 Allows all Helldivers to recover faster after being slowed by an attack, such as acid. Does not mitigate "area effects," such as EMS strikes. 加快所有绝地潜兵在因遭受攻击(如腐蚀酸)而减速后的恢复速度。无法减轻“范围效果”的影响,如电磁冲击波攻击。 +1529115295 Allows Helldivers to keep sprinting even when they are out of stamina, draining their health instead. 通过消耗生命值,让绝地潜兵在耐力耗尽时仍能继续冲刺。 +2401556349 Allows Helldivers to traverse difficult terrain with ease. 让绝地潜兵能够轻松穿过复杂地形。 +2410868361 Allows Mortar Targeting Platform to access Helldiver HUD ecosystem through use of third-party conversion software. 利用第三方转换软件,允许迫击炮瞄准平台接入绝地潜兵的HUD生态系统。 +2486107935 Allows the swift completion of Liberty's administrative tasks in an invigorating atmosphere. 在鼓舞人心的氛围下,快速完成解放伟业的行政工作。 +3158883809 ALMINA IV 阿尔米纳IV +570845236 Alpha Commander 阿尔法指挥官 +3621885961 ALPHA COMMANDER 阿尔法指挥官 +4068320987 Alpha Commanders 阿尔法指挥官 +2645715758 Already at maximum capacity. 容量已满。 +3363914814 ALREADY IN USE BY TEAMMATE 队友正在使用 +1295934071 ALSTRAD SECTOR 阿尔斯特拉德分区 +4062718607 Alt. Ammo 备用弹药 +2828870674 ALT. AMMO 备用弹药 +1909354717 ALT. AMMO 备用弹药 +870181849 ALTA V 奥尔塔V +1006830730 Although bulkier, it provides the effects of both a laser sight and a flashlight. 虽然体积更大,但能同时提供激光瞄准器和照明效果。 +1587733194 Although Super Citizen Miranda's true identity has been lost to time, most legal historians agree that she was once a patron of highly-efficient interrogation techniques. 尽管超级公民米兰达的真实身份已被时间湮没,但大多数法律史学家一致认为,她曾是高效审讯技术的赞助人。 +2782204414 ALTONBURG 奥尔顿堡 +754504867 ALTUS SECTOR 阿尔特斯分区 +2207840868 Always 总是显示 +3972729936 ALWAYS 常驻 +51271248 Amazing quality, I bought one for me and TWO for my kid. She loves them. 质量超好。我不仅自己买了一件,还给我女儿买了两件。她爱不释手。 +3044994040 Amazing quality. It even survived atmospheric re-entry... twice! 品质过硬。甚至能顶住穿越大气层的损耗…而且是两次! +1627009442 Ambient Occlusion 环境光遮蔽 +2929862318 AMD Anti-Lag 2 AMD Anti-Lag 2 +700206000 AMD Anti-Lag 2 tries to reduce the system latency and increases responsiveness. AMD Anti-Lag 2旨在降低系统延迟并提升响应速度。 +2613500234 Amendment 修正 +784648118 AMENDMENT 修正 +3940422141 AMITTERE 亚米逝地 +1499930222 AMMO 弹药 +3899009168 AMMO 弹药 +2784761516 AMMO SHORTAGE 弹药短缺 +2654681255 AMMO SURPLUS 弹药过剩 +2525307035 Ammo Type 弹药种类 +1074660280 AMMO TYPE 弹药种类 +3134940036 AMMO TYPE 弹药种类 +3737674903 AMMUNITION 弹药 +1491565330 Ammunition depleted, switch weapon! 弹药耗尽,切换武器! +2034839788 Ammunition for the Guard Dog stratagem can run out and be replenished with ammo packs. “护卫犬”战略配备的弹药会耗尽,可以通过弹药包进行补充。 +3815040364 Ammunition Input Required 需要加入弹药 +2281724484 Ammunition Optimization 弹药优化 +98190143 AMMUNITION OPTIMIZATION 弹药优化 +3871196689 AMMUNITION STATS 弹药数据 +2659977051 AMO 弹药 +152374969 Amount 数量 +474773583 An ENCOUNTER is approaching. Use your STRATAGEMS! 一场遭遇战即将开始。使用你的战略配备吧! +3376195384 An operation is a collection of missions. Complete all missions to succeed with an operation and gain bonus rewards. Failing one mission will fail the rest of the operation. 行动包含一系列任务。完成所有任务即表示行动成功,你将获得额外奖励。只要一项任务失败,此次行动就算失败。 +1794897449 An abandoned SEAF Mobile Radar is located here. It can provide key information on the local area. 这里有台被遗弃的超级地球武装部队移动雷达。可以从中获取当地区域的关键情报。 +3671633165 An abomination constructed by abominations, with abominable intent. 可恶的机器人怀着可恶的用心制造的可恶机械。 +3246484325 An abundant source of E-711, carefully harvested by experienced hands. 富含711元素,由经验丰富的采集人员精心开采。 +3774503774 An Access Node linked to the Exospire's subterranean shield generator is stationed here. 此处部署有接入节点,与异界尖塔地下的防护罩生成装置相连。 +1304003623 An accurate, armor-penetrating rifle, the BR-14 Adjudicator delivers righteous judgement to medium-sized enemies, though its restrictive magazine limits its effectiveness against large groups. “审判者”是精准度较高的穿甲步枪,可对中等体型的敌人进行正义审判,但由于弹匣容量有限,对大群敌人的攻击效果也相对受限。 +4023535266 An accurate, hard-hitting laser revolver with bespoke break action for heat sink swaps. 精准且威力强大的激光左轮手枪,定制中折式设计便于更换散热器。 +1961076281 An advanced angled foregrip to improve weapon stability. 高级直角前握把,可提升武器稳定性。 +3645832110 An advanced vertical foregrip to improve the maneuverability of the weapon. 高级垂直前握把,可提升武器操控性。 +121536852 An advanced, mostly self-operating prospecting drill fitted into a Hellpod. Handles soil sample extraction, analysis and data upload with minimal necessary input from an operator. 一款安装在绝地喷射舱内的先进自动操作勘探钻机。操作员只需手动完成最基本的操作,钻机就能处理土壤样本提取、分析和数据上传的工作。 +1122588897 An agile automated machine gun turret. Will fire at targets even if Helldivers will be caught in the crossfire. 灵活的自动机枪炮台,即便绝地潜兵在交火期间受伤,它依然会向目标射击。 +3886455139 An angled foregrip to improve weapon stability. 直角前握把,可提升武器稳定性。 +1029905686 An angled foregrip with an integrated laser sight. 配备集成激光瞄准器的直角前握把。 +1522649539 An angled vertical foregrip to improve the maneuverability of the weapon. 直角垂直前握把,可提升武器操控性。 +2566951657 An anti-tank homing missile which must lock onto its target before launch. Effective against large and armored enemies. 反坦克追踪式导弹,发射前必须锁定目标。可有效对付大型装甲敌人。 +3925658953 An antipersonnel fragmentation grenade. Creates damage over a large area when detonated. 反步兵破片榴弹,引爆时可在大范围造成伤害。 +2701663299 An arcane Illuminate device at this location is creating a mind-disruption field, filling one's mind with un-Democratic thoughts that make it difficult to think or push Stratagem codes properly. 这个地点有件神秘的光能者设备创造出了干扰思维的域场,令人的大脑塞满不民主的思想,进而难以思考,也难以正确输入战略配备代码。 +4171356355 An armor often worn by frontline surgeons, who are skilled at both putting bodies back together and taking them apart. 前线外科医生的常用盔甲。他们既有出色的缝合技术,也很了解该怎样将敌人大卸八块。 +667858047 An assault rifle with a high-capacity drum magazine, good for providing sustained fire. +Produced by Stål Arms. 突击步枪,配备大容量弹鼓,适合持续提供火力。 +由斯塔尔武装公司生产。 +402309851 An automated assembly line where all Hellpod armaments are constructed by precise, non-sentient robotic arms. 自动化装配流水线,所有绝地喷射舱军备均由无感知的精密机械臂所建造。 +587865164 An automated cannon turret firing anti-tank ammunition over long ranges. Sacrifices agility for range and power. 远程发射反坦克弹药的自动加农炮台。以牺牲灵活性为代价,扩大攻击范围,提升火力。 +2049221350 An automated flamethrower turret. Warning: fuel canister prone to explosion when ruptured. 自动火焰喷射器炮台。警告:燃料罐破裂时易爆炸。 +1868841169 An automated turret that fires gas shells. Its targeting system prioritizes hostiles not yet exhibiting symptoms caused by gas inhalation. Users are advised to stay significantly upwind of the resulting crowd control. 一种发射毒气弹的自动炮塔。其瞄准系统优先锁定尚未中毒的敌对目标。使用者应保持上风方位,避免被群体控制影响。 +150097484 An automated turret with an extremely high rate of fire. Caution: does not check if friendly units are in line of fire. 射速极其高的自动炮台。当心:炮台不会侦测火线内是否存在友方单位。 +4106526805 An Automaton Hulk was last reported in this location. 据报告称,机器人巨型者的最后目击地点就在这个位置。 +2118518394 An Automaton invasion fleet is attacking this planet. + +We must repel the invading forces before it is too late! 机器人的侵略舰队正在攻打这颗星球。 + +我们必须及早击退侵略势力! +2388346408 An Automaton unit equipped with flame throwers and incendiary ammunition is active on this planet. Prepare to face wanton arsonists who will not rest until they have razed all that humankind holds dear. 装备火焰喷射器和燃烧弹药的机器人部队正在该星球上肆虐横行。请做好准备,应对肆无忌惮的纵火犯,他们唯有将人类珍视的一切烧为灰烬,才肯善罢甘休。 +296742774 An autonomous drone equipped with a flamethrower. Returns to backpack to refill fuel canisters. 配备火焰喷射器的自主无人机。收回到背包可补充燃料罐。 +1177236491 An autonomous drone equipped with a laser rifle, providing 360° cover. Returns to backpack to cool down. 配备激光步枪的自主无人机,可提供全方位掩护。需要冷却时会返回背包。 +4200594030 An autonomous drone equipped with a Liberator assault rifle, providing 360° cover. Returns to backpack to rearm. 配备“解放者”突击步枪的自主无人机,可提供全方位掩护。需要补充弹药时会返回背包。 +982871080 An Exosuit equipped with a flak cannon and ballistic shield, optimized for mid-to-close combat range. 配备高射炮与防弹护盾的外骨骼装甲,专为中近距离战斗而优化。 +1244754797 An Exosuit equipped with a rocket launcher and a gatling gun, offering reliable flexibility against both heavy units and swarms of small targets. 搭载火箭发射器和加特林机枪的外骨骼装甲,能够可靠灵活地应对重型单位和成群小型目标。 +3085604271 An Exosuit equipped with dual autocannons, designed for sustained explosive firepower. 搭载两台机炮的外骨骼装甲,可持续提供爆炸性火力。 +865908403 An expendable missile launcher equipped with four laser-guided missiles. 消耗性导弹发射器,配有四枚激光制导导弹。 +1195480985 An experimental lab has been constructed on this planet to synthesize Dark Fluid from E-711. 实验室已经在此星球上建造,用以合成来自711元素的暗液体。 +1622894175 An experimental vessel containing 40 grams of weapons-grade Dark Fluid suspended in a magnetic field. 试验性容器,装载有40克武器级暗液体,悬浮于磁场之内。 +3266438902 An experimental weapon which prioritizes armor penetration. Must be charged between shots - so choose targets carefully. 侧重穿甲能力的试验性武器。两次射击的间隙必须充能,因此,请谨慎选择目标。 +851882018 An illegal propaganda broadcast has been traced to this location. 经追查发现,有非法宣传广播正在此处运营。 +1841093792 An Illuminate Harvester is located in this area. Find it and destroy it. 此区域有光能者猎杀器。找到它,并将其摧毁。 +3695439276 An incendiary device that shatters on impact, without explosive force, instantly creating a localized and persistent combustion field. 一种撞击即碎的燃烧装置,无爆炸力,可瞬间产生局部且持久的燃烧区域。 +665052551 An incendiary grenade which ignites any targets and terrain within the blast radius. Use with caution. 燃烧榴弹,可点燃爆炸范围内任何目标和地面。请谨慎使用。 +3579339289 An incendiary weapon for close range. Will ignite targets, terrain, and any flammable teammates. 用于近程作战的燃烧武器,能点燃目标、地面,以及易燃易爆炸的队友。 +857740671 An internal error occurred during the purchase, please try again later or contact support if this error persists. 购买过程中发生内部错误,请稍后重试。如果问题仍未解决,请联系客服。 +2696420010 An internal error occurred during the purchase, please try again later or contact support if this error persists. 购买过程中发生内部错误,请稍后重试。如果问题仍未解决,请联系客服。 +1866439162 AN OLD ENEMY EMERGES 宿敌现身 +2206768360 An Orbital Cannon is located here. Infiltrate the site and use a Hellbomb to destroy it. 轨道加农炮就位于此处。潜入此地点,使用地狱火炸弹将其摧毁。 +515165111 An orbital strike will be automatically fired whenever a Helldiver is killed. 只要有绝地潜兵阵亡,就会自动触发一次轨道攻击。 +1773921075 An SEAF recon aircraft has been downed by the invaders mid-mission. Recover the aircraft's data drives before they are destroyed. 一架超级地球武装部队侦察机在执行任务期间被入侵者击落。必须在侦察机的数据驱动器被毁前将其找回。 +1756463788 An SEAF reconnaissance plane was shot down over this region. Its top-secret intel must be recovered immediately, before it can be destroyed by the enemy. 超级地球武装部队的一架侦察机在这片沦陷的拓殖地被击落。必须立即取回机上的绝密情报,以免被敌人摧毁。 +676792633 An SMG that fires caseless ammunition and is equipped with a non-removable suppressor. +Produced by Martian Armory. 发射无壳弹药的冲锋枪,且配备了不可拆卸的消音器。 +由火星军械库生产。 +81814212 An SSSD Hard Drive containing valuable data was lost at this location following an ambush of a SEAF squad. It must be recovered. 曾有超级地球武装部队的小队在这里遭遇伏击,他们丢失了一个包含重要数据的超级固态硬盘。必须找回来。 +3811178773 An unanticipated Terminid surge has taken significant ground on Planet #V_ONE. 突如其来的终结族激增势力在#V_ONE星球上占领了重要阵地。 +1321624866 An unanticipated Terminid surge is taking significant ground on Planet #V_ONE. 突如其来的终结族激增势力正在#V_ONE星球上占领重要阵地。 +2708164578 An unknown error has occurred. 发生未知错误。 +1735628038 AN UNKNOWN SERVER ERROR HAS OCCURRED 服务器发生未知错误 +1702909018 An unusually large Terminid spawning has led to sudden, significant loss of ground on Planet #V_ONE. 终结族孵化规模异常激增,突如其来的变化导致我方在#V_ONE星球上损失重要阵地。 +3971606052 AND HATING FREEDOM." 暴力,以及憎恨自由。” +1926035611 ANDAR 安达尔 +725588127 Andersson 安德松 +1044017705 ANDROMEDA SECTOR 仙女座分区 +4092444932 ANDROS DELTA 安德罗斯德尔塔 +3324872373 ANDROS GAMMA 安德罗斯伽马 +833603519 ANDWELL 安得卫 +567695062 ANGEL'S VENTURE 天使投资 +1077727737 ANGEL'S VENTURE DEFENDED +Thanks to the selfless valor of the Helldivers, the citizens of Angel's Venture are safe from the Terminid Menace. 成功保卫天使投资星系 +在无私的绝地潜兵的英勇付出下,天使投资星系的公民终于摆脱了终结族的威胁。 +1564719516 ANGEL'S VENTURE FREED +Angel's Venture has been freed from the Terminids, thanks to your unhesitating sacrifice. It is now under Super Earth control, where it belongs. 天使投资星系已解放 +在你们毫无迟疑的牺牲下,天使投资星系摆脱了终结族的掌控。它现在已经回到超级地球治下,重返家园。 +282106757 ANGEL'S VENTURE LOST +The defense of Angel's Venture has failed. Terminids now run amok on its surface. We cannot allow this corruption of Liberty to stand. 天使投资星系沦陷 +天使投资星系保卫战已宣告失败。终结族现在正四处肆虐。我们不能任由它们继续侵犯自由伟业。 +427983629 ANGEL'S VENTURE UNDER ATTACK +The Terminids have attacked Angel's Venture. All available Helldivers are called to defend it. 天使投资星系遭到袭击 +终结族对天使投资星系发动了袭击。呼唤全体可行动的绝地潜兵前去防卫。 +2856674401 Angled Foregrip 直角前握把 +1168266781 ANGLED FOREGRIP 直角前握把 +22557897 Ankarberg 安卡贝格 +568515485 ANNE'S VIGIL 安妮守望城 +1660885238 ANNEX QUARRY 吞并采石场 +4113146532 ANNEX UNTAPPED MINERAL SITES 吞并未开发的矿点 +19757233 Annihilate 歼灭 +376974669 ANNIHILATED SYSTEM 已歼灭星系 +3455009224 Annihilator Tank 湮灭坦克 +4188679567 ANNIHILATOR TANK 湮灭坦克 +1222875907 Annihilator Tanks 湮灭坦克 +2930778917 ANNWN 安温 +2845604796 ANOMALOUS MATERIAL EXTRACTED 已提取异常物质 +4047525053 ANOMALOUS MATERIAL SITE 异常物质地点 +1755828576 ANOMALOUS SYSTEM 异常星系 +4129150690 ANOMALY LOCATION 异常地点 +302770875 Another Colony Devastated By Surprise Automaton Attack. 机器人再次突袭破坏拓殖地 +2239176341 ANTBOOT 踏虫市 +2079436940 ANTI-AIR 防空 +2468339199 ANTI-AIR EMPLACEMENT 防空炮台 +3217844104 Anti-Air Missile 防空导弹 +1878308225 ANTI-AIR MISSILE 防空导弹 +3151166817 Anti-Aircraft Defenses 对空防御 +1353755478 Anti-Aliasing 抗锯齿 +1391161752 Anti-Democracy Rebels Rounded Up with Stunning Efficiency. 反民主叛乱分子全部落网 +3313983701 Anti-Materiel Rifle 反器材步枪 +3162817893 ANTI-MATERIEL RIFLE 反器材步枪 +4109477478 Anti-Personnel Mine Deployer stratagem availability has ended. 现已无法使用“反步兵地雷部署器”战略配备。 +351997015 Anti-Personnel Minefield 反步兵雷区 +2248440908 ANTI-PERSONNEL MINEFIELD 反步兵雷区 +3591930318 ANTI-TANK 反坦克 +1387831894 Anti-Tank Emplacement 反坦克炮台 +1153871814 ANTI-TANK EMPLACEMENT 反坦克炮台 +1747218844 Anti-tank Mines 反坦克地雷 +721197452 ANTI-TANK MINES 反坦克地雷 +2798947179 Anti-Tank Missiles 反坦克导弹 +1479346973 ANTI-TANK MISSILES 反坦克导弹 +163446619 Any recognizeable form of life is absent in this austere, cold, rocky world. 单调、寒冷、岩石嶙峋的星球,不存在可辨识的生命形态。 +1306411358 Apex Protector 巅峰护卫 +2310432885 APEX PROTECTOR 巅峰护卫 +3601603271 APHET 穿甲高爆曳光弹 +2850359826 Applies the near-frictionless lubricant known as "Super Jelly" to sentry ring mounts, facilitating extremely smooth mechanical operation. 被称为“超级果冻”的润滑剂近乎无摩擦力,将其涂抹在哨戒炮的旋转式支架上,机械操作将变得极为流畅。 +3416891980 APPLY 应用 +3719625712 APPLY NAME 应用名称 +4293335880 Approaching OUTPOST. Call in a GATLING SENTRY for extra firepower. 正在接近哨站。呼叫加特林哨戒炮提供额外火力。 +448966068 Approaching edge of mission area. Return to the mission, or be branded a traitor. 正接近任务区域边缘。请折返执行任务,否则你将被认定为叛徒。 +50109409 APPROPRIATE REFINERY 占领精炼厂 +3264867080 APPROPRIATORS 占领者 +3000372461 APPROVAL CITY 准都 +1087124124 APPROVED BY THE MINISTRY OF TRUTH 经真理部审核通过 +3365027066 Apr 4月 +1460845371 April 4月 +729663239 APW-1 APW-1 +1436471677 AQUIFER DRILL 含水层钻机 +4164526636 AQUILA XXXII 天鹰XXXII +2007538153 AR-2 AR-2 +293165154 AR-20L AR-20L +2781219681 AR-23 AR-23 +225590330 AR-23A AR-23A +1160898002 AR-23C AR-23C +199039471 AR-23P AR-23P +1472134285 AR-32 AR-32 +2937575630 AR-48 AR-48 +1446063753 AR-59 AR-59 +2464525212 AR-61 AR-61 +3490290898 AR/GL-21 AR/GL-21 +2757180352 ARABILITY 沃壤 +1290345510 Arbiter 仲裁 +2463637512 Arc 电弧 +1064601703 ARC 电弧 +3901125769 ARC 电弧 +1828467212 ARC 电弧 +3765721070 Arc Thrower 电弧发射器 +448803819 ARC THROWER 电弧发射器 +1438856980 ARC-12 ARC-12 +3428431296 ARC-3 ARC-3 +22554536 ARCTIC 雪地 +509038649 ARCTIC 雪地 +1009979598 ARCTIC CAMO 雪地迷彩 +3846306529 ARCTIC PLANET 雪地星球 +981932957 ARE PROGRAMMED FOR 2 THINGS: VIOLENCE, 这些机器人的程序里只写了两样东西: +1599802275 Are you sure you want to purchase #COUNT #ITEM Medals for 是否确定购买#COUNT枚#ITEM奖章并花费 +2284239206 Are you sure you want to unbind this input? 确定要解除绑定该键位吗? +2692415803 Are you sure you want to unlink your accounts? 确定要解除账户绑定吗? +1807876149 Are you sure you want to unlock '#WARBOND' standard Warbond for 是否确定要解锁“#WARBOND”标准战争债券并花费 +1981545822 Are you sure you want to unlock "#WARBOND" Legendary Warbond for 是否确定要解锁“#WARBOND”传奇战争债券并花费 +2525808724 Are you sure you want to unlock "#WARBOND" Premium Warbond for 是否确定要解锁“#WARBOND”尊享战争债券并花费 +3034748067 Are you sure you want to unlock #ITEM? 确定要解锁#ITEM吗? +3487168316 Are you sure you want to use your vote? 确定要投票吗? +1543180076 Are you sure you want to use your Warbond Token to unlock '#WARBOND' standard Warbond? 是否确定要使用战争债券代币解锁“#WARBOND”标准战争债券? +2492388615 Are you sure you want to use your Warbond Token to unlock "#WARBOND" Legendary Warbond? 是否确定要使用战争债券代币解锁“#WARBOND”传奇战争债券? +1400248349 Are you sure you want to use your Warbond Token to unlock "#WARBOND" Premium Warbond? 是否确定要使用战争债券代币解锁“#WARBOND”尊享战争债券? +141575091 AREA SECURED 区域现已安全 +58119577 Area under Super Earth control: 超级地球控制区域: +2106060099 ARGENTIS 银辉 +2696343909 ARKTURUS 阿克图勒斯 +920622126 ARLIA 阿利亚 +2512004502 Arm injuries reduce your ability to handle recoil and will cause your aim to sway more. 手臂受伤会令你难以应对后坐力,使得瞄准动作摆动幅度增大。 +830312462 Arm Patch 手臂贴布 +1075117328 Armed Resupply Pods 武装重新补给舱 +3921001162 ARMED RESUPPLY PODS 武装重新补给舱 +3173076563 Armelin 阿默兰 +76425056 Armor 盔甲 +492394509 Armor 盔甲 +3502323650 Armor 盔甲套装 +4133551538 ARMOR 盔甲 +2919751594 ARMOR 盔甲套装 +2128004169 Armor befitting infiltrators of all caliber. Inspired by mythical Democracy-dispensers, whose meticulously undocumented operations remain an inspiration to all students of stealth. 此盔甲适合水平各异的渗透人员。以传说中的民主精神传播者为灵感设计,他们不留痕迹的缜密行动至今仍激励着所有潜行术学员。 +2224592258 ARMOR DESTRUCTION 毁灭装甲 +3219286687 ARMOR DESTRUCTION 毁灭装甲 +88479674 Armor explodes #BONUS after the wearer dies. 盔甲会在穿戴者死后#BONUS引爆。 +598780185 Armor inspired by the legend of the Sanctioner, a figure known only through a bizarrely unanimous patchwork of stifled whispers. As told, this fearsome, covert arbiter of primeval Justice delivered final, state-approved verdicts in the chaotic years before the Federation's founding. 以制裁者的传说为灵感设计的盔甲,虽然这位人物的形象仅由隐蔽的只言片语拼凑而成,但却诡异地一致。据传,这位令人敬畏的隐蔽制裁者在联邦成立前的混乱年代伸张早期的正义,下达国家认可的最终判决。 +1102512017 Armor isn't just for looks—heavier armor makes you more resilient to attacks but slows you down and affects your stamina. 盔甲不只是美观而已——盔甲越重,你的抗击能力越强,但是你的速度会相应变慢,耐力也会受到影响。 +4157609339 ARMOR PASSIVE 盔甲被动加成 +3675831925 ARMOR PENETRATION 穿甲攻击 +2176271297 ARMOR RATING 盔甲等级 +2494716311 Armored enemies are expected on this mission. Anti-tank weaponry is recommended. 本次任务预计会遭遇装备护甲的敌人。建议携带反坦克武器。 +4043068980 ARMORS 盔甲 +1205592845 ARMORY 防具 +1857451040 ARMORY 军械库 +2668711964 ARMORY 军械库 +434732802 ARMORY 军械库 +3159948003 Armstrong 阿姆斯特朗 +1448926797 Arrives in: 抵达倒计时: +3337346642 ARROWHEAD ARROWHEAD +478168078 Artificial Sunlight Determined To Be At Least As Good For You, If Not Better, Than Natural Sunlight. 专业判定人造阳光对你的益处不会逊色于自然阳光 +2151290805 Artillery 大炮 +1843083936 Artillery Activation Required 需要启动大炮 +741830410 Artists and sculptors have made countless attempts at depicting the face of Liberty, but the truth is that any citizen can see it—they need only requisition a mirror. 艺术家和雕塑家曾无数次试图勾勒自由的轮廓,但事实上,任何人只需照照镜子,便能一睹自由的风采。 +151044459 ARTURION SECTOR 阿图里昂分区 +3322677007 As a last resort, you can use melee attacks to fend off enemies. Remember: death is better than cowardice! 万不得已时,近战攻击是你对抗敌人的最后手段。要记住:苟且偷生不如慷慨赴死! +1876089118 As documented in the bestselling graphic novel "The Breach," the final mission of the 361st "Freedom's Flame" saw the storied unit deploy straight into the heart of a Supervolcano, sacrificing themselves to trigger an eruption and wipe out a massive Terminid swarm. 根据畅销图像小说《突破》的描述,大名鼎鼎的361“自由烈焰”部队最后一次执行的任务是直接部署到超级火山的核心地带,英勇地牺牲自我,引发火山喷发,消灭数量庞大的终结族虫群。 +2863970324 As the electric arc generates a strong magnetic field, wearers should avoid use while in vicinity of stapled paperwork. 电弧可产生强大的磁场,穿戴者应避免在装订好的文书附近使用此盔甲。 +3797148908 As this cape flutters in the wind, it evokes a wishful, twinkling star in the sky—a star ripe for conquest. 这件披肩在风中飘扬时,让人不禁联想到空中那颗充满希望、闪闪发光的星星,一颗等待征服的星星。 +641799878 Asking for Personal Information 询问个人信息 +3073176943 Aspect-seeking air-to-air missiles, to eliminate most flying targets in the vicinity. 寻向空对空导弹,可歼灭附近的大部分飞行目标。 +722264741 ASPEN HILLS 阿斯彭山 +2028193710 ASPEROTH PRIME 阿斯佩洛斯主星 +3830647204 Aspirant 志士 +1659216583 ASPIRANT 志士 +2996202865 Assault 特攻 +3478059223 ASSAULT 特攻 +820400939 Assault Commence in: 突袭倒计时: +1631367382 Assault Imminent 突袭即将开始 +3052089928 ASSAULT INFANTRY 特攻步兵 +1467464627 Assault Raider 特攻奇袭者 +1762623544 ASSAULT RAIDER 特攻奇袭者 +1494724485 Assault Raiders 特攻奇袭者 +2975288178 Assault Rifle 突击步枪 +2982624976 Assault Rifle 突击步枪 +3015149262 ASSAULT RIFLE 突击步枪 +626783170 ASSAULT RIFLE 突击步枪 +4268863341 ASSAULT RIFLE 突击步枪 +762117003 Assembled from pieces of recovered Helldiver armor and SEAF gear, for those who won't let a lack of full body protection keep them from the battlefront. 这件披肩由回收的绝地潜兵装甲和超级地球武装部队装备碎片组装而成,专为那些即使缺乏全身防护装备也要奔赴战场的勇士设计。 +2999267083 Assignment Notifications 任务分派通知 +1553470131 Assignments 分派任务 +676187033 Assigns a random voice to your Helldiver when you die. 在死亡时,为你的绝地潜兵随机分配一种声音。 +2124637646 Assist Bonus x#COUNT 助攻加成x#COUNT +1918416101 Astronomers Identify Promising New Exoplanet For Settlement. 天文学家发现可能宜居的新系外行星 +1146528945 At Ease 稍息 +3753061196 AT EASE 稍息 +620277150 At the edge of the Federation, sometimes Democracy has only one representative. 在联邦的边境线,有时民主只有一位代理人。 +1807618860 At this research facility, recovered Voteless are given a fresh chance to aid Managed Democracy. Through processing and analysis of their biomass, our understanding of the Void stands to be significantly advanced. 在这座研究设施中,被回收的“无票者”将获得为管理式民主添砖加瓦的新机会。通过对其生物质进行处理分析,我们定可大幅深化对寂域的了解。 +3862338222 AT-48 Recoilless Rifle stratagem availability has ended. 现已无法使用“AT-48无后坐力步枪”战略配备。 +393226555 Atmospheric Interference 大气干扰 +3267185606 ATMOSPHERIC INTERFERENCE 大气干扰 +3577795458 Atmospheric Lighting Quality 氛围光照质量 +3792591586 ATMOSPHERIC MONITORING 大气监测 +273580744 Atmospheric Spores 孢子气体 +376917040 ATMOSPHERIC SPORES 孢子气体 +3033475065 ATMOSPHERIC STERILIZATION 大气灭菌 +714923769 Atomizes caustic chemicals into a fine mist that liquifies sensitive electronics and tissues. Blinds and slows most enemies. 将腐蚀性化学物质雾化成细密雾气状,使敏感的电子设备和组织液化。可使大多数敌人致盲并减速。 +2793302978 ATRAMA 阿特拉玛 +2731247178 ATTACHMENTS 配件 +3944495922 ATTACK SPEED 攻击速度 +1035927809 ATTACKING 攻击 +1586771010 ATTRITION 消耗战 +365873857 AUDIO 声音 +480760762 Audio Device 音频设备 +4223361121 Aug 8月 +4262519325 Auger 奥格 +3921828165 Augments electrical weaponry by safely connecting multiple interior arc extenders into one long linear chain. 可通过安全方式将多个内部电弧扩展器连接成线性长链,起到增强电子武器威力的作用。 +488540690 August 8月 +3726554027 AURORA BAY 极光湾 +2960440287 AUSPICE 天启 +1201290169 AUTHORITARIAN LIGHT 独裁之光 +22117695 AUTHORIZE NUCLEAR LAUNCH 授权发射核弹 +3805548387 Authorizes an 8-week crew training course in Superior Packing Methodology (SPM), resulting in increased supply box capacity. 授权开展为期8周的高级装填法(SPM)船员培训课程,从而提高补给箱容量。 +2828702105 Authorizes hazard pay for pit crews, allowing them to reload the Eagle Fighter in-spaceflight. 批准向维修人员支付危险津贴,以便他们放心在航天飞行期间重新武装“飞鹰”战斗机。 +1178622153 Auto 自动 +1660961539 Auto 自动 +640375941 Auto Loader 自动装载 +3627220341 AUTO LOADER 自动装载 +1632635711 Auto Reverse Vehicles 载具自动倒车 +469029492 Auto-Climb during Sprint 冲刺时自动攀爬 +727076238 Autocannon 机炮 +3284848821 AUTOCANNON 机炮 +4270905484 Autocannon Backpack 机炮背包 +1597436781 AUTOCANNON BACKPACK 机炮背包 +2460445122 Autocannon Sentry 自动哨戒炮 +3791174808 AUTOCANNON SENTRY 自动哨戒炮 +2275368038 Autocannon Sentry stratagem availability has ended. 现已无法使用“自动哨戒炮”战略配备。 +3352008644 Automatic Braking 自动制动 +3761541353 AUTOMATIC BRAKING 自动制动 +2494015994 Automaton 机器人 +925731532 AUTOMATON 机器人 +1562007656 AUTOMATON BLOCKADE WORLDS 机器人封锁带 +1549509767 AUTOMATON CONTROL 由机器人控制 +2007030524 AUTOMATON COUNTERATTACK +Intercepted messages indicate bot plans for a significant push. Increased resistance on Automaton planets is anticipated. 机器人反攻 +截获的情报显示,机器人计划大举反攻。预计各机器人星球的反抗力度将大幅加剧。 +1485224906 Automaton Dropship 机器人运输舰 +1667436 AUTOMATON DROPSHIP 机器人运输舰 +1746702421 Automaton Dropships are docked at this location. 机器人运输舰停靠于此地。 +50254297 AUTOMATON FORTRESS 机器人堡垒 +1476637725 Automaton glyphs mark the exterior, menacing and power-hungry in their contortions. 电池表面刻着机器人的符号。歪歪扭扭的笔画暴露了它们凶恶的本性以及对能源的渴望。 +1922833675 Automaton Gunships are being manufactured in this area. 这个地区在制造机器人炮舰。 +2961322270 Automaton Horde 机器人群袭 +192407672 AUTOMATON INCURSION 机器人入侵 +740249478 AUTOMATON INCURSION 机器人入侵 +1518361384 AUTOMATON INCURSION 机器人入侵 +298138811 AUTOMATON INVASION 机器人入侵 +1801038402 AUTOMATON INVASION +The Automatons have launched another cowardly assault. All available Helldivers are called to fight them off! Report to the Galactic Map for more information. 机器人入侵 +机器人发动了另一场懦弱的袭击。呼叫所有可行动的绝地潜兵,立刻前去应战!通过星系地图报到,了解更多信息。 +3478602676 Automaton Invasion Shows No Signs Of Losing Steam. 机器人侵略尚无止步迹象 +2106620389 Automaton Kills 机器人击杀数 +2649067399 Automaton Mortar Emplacement 机器人的迫击炮台 +1519030847 AUTOMATON MORTAR EMPLACEMENT 机器人的迫击炮台 +851434747 Automaton Mortar Emplacements 机器人的迫击炮台 +1036926398 AUTOMATON OCCUPIED SPACE 机器人占领的空间 +330847558 AUTOMATON OVERDRIVE 机器人超载驱动 +122742932 AUTOMATON REMAINS 机器人的遗骸 +2601650323 AUTOMATON SURPRISE ATTACK 机器人突然来袭 +2782937074 Automaton Sympathizers Killed in Breathtaking Raid; Collateral Damage Heroically Minimized. 星系大突查,同情机器之人消灭无数;潜兵好英勇,连带伤害微乎其微 +4202429139 AUTOMATON THREAT 机器人危机 +2499558748 Automaton troops are mass produced daily in the bowels of this Megafactory, then deployed in service of the Cyborgs' senseless expansionism. + +Disrupt their industry of death. Destroy their fabricators one by one. 在这所超大型工厂深处,每天都在批量生产机器人的部队,随后被部署并服务于生化人毫无意义的扩张主义。 + +瓦解敌人的死亡工业。逐一摧毁它们的构筑者。 +1045534823 Automatons 机器人 +3259303240 Automatons 机器人 +1450751683 AUTOMATONS 机器人 +2733602713 Automatons "No Match" for Helldivers, Says Ministry of Defense Official. 国防部官员称机器人“完全不敌”绝地潜兵 +1988725196 AUTOMATONS ATTACK DEVELOPED WORLDS 机器人袭击发达星球 +2133176245 AUTOMATONS ERADICATED +Citizens across the Federation celebrate in the streets, hailing the great victory of the Helldivers over the Automatons. Even now, SEAF Engineers dismantle the last of their factories and melt them down into scrap to build new colonial homes. + +Soon, we will no doubt discover where this threat originated. For now, let us celebrate the Freedom that the total annihilation of the Automatons has won, in the best way there is: by pursuing the total annihilation of the Terminids. 机器人已经毁灭 +全联邦的公民走上大街,交相庆贺,为绝地潜兵胜利剿灭机器人而欢呼雀跃。超级地球武装部队工程师直到现在仍在奋力拆除机器人最后的孵化厂,将其融为废料,用于兴建拓殖地的新住宅。 + +我们定将在不久后找到这一威胁的来源。现在,让我们尽情享受彻底剿灭机器人而赢来的自由,最好的庆祝方式莫过于:彻底消灭终结族。 +4089331914 Automatons in this region pose an undeniable and multifaceted threat to Liberty. Do whatever it takes to defend our way of life. 毋庸置疑,该地区的机器人对解放大业的多个方面都构成威胁。不惜一切代价也要捍卫我们的生存之道。 +3411407988 Automatons Invasion Force Constitutes "Grave Threat" to Super Earth. 机器人侵略军“严重威胁”超级地球 +1619497901 Automatons Ultimate Goal Appears To Be Super Earth Itself, According to MOD. 国防部称机器人的终极目标疑为超级地球 +912562356 Automatons' Mass Production Capabilities Exceed Expectations. 机器人量产能力超出预期 +621307500 AUTONOMOUS 自动 +3539910826 AUTONOMY 自固堡 +103735208 Availability of #V_ONE has ended. 现已无法使用#V_ONE。 +3728286212 AVAILABLE AT LEVEL #RANK 达到级别#RANK时开放 +3314278308 Available in: #DAYS d #HOURS h 就位倒计时:#DAYS天#HOURS小时 +3380082604 AVAILABLE IN: #DAYS d #HOURS h 就位倒计时:#DAYS天#HOURS小时 +4201234771 Available in: #HOURS h #MINUTES m 就位倒计时:#HOURS小时#MINUTES分 +3984734498 AVAILABLE IN: #HOURS h #MINUTES m 就位倒计时:#HOURS小时#MINUTES分 +2361739771 Available in: #MINUTES m #SECONDS s 就位倒计时:#MINUTES分#SECONDS秒 +2013995998 AVAILABLE IN: #MINUTES m #SECONDS s 就位倒计时:#MINUTES分#SECONDS秒 +1833447029 AVATAR 游戏形象 +1402331169 AVERT VOID 抵御寂域 +746457430 AVILA 阿维拉 +151696208 Avoid DROWNING by getting out of the water. 脱离水体,避免淹溺。 +3508305550 Avoid killing citizens. Escort them to safety to complete the Objective. 避免伤及公民。护送他们到安全地点才能完成目标。 +1771161994 Awaiting Major Order 等待重要指令 +1587214941 AWAITING REINFORCEMENT 正在等待增援 +581132784 Awarded to those promoted to their point of greatest competency, and beyond. 仅授予已达至臻之境并突破自我极限的战士。 +3074489955 AX/AR-23 AX/AR-23 +4000252291 AX/ARC-3 AX/ARC-3 +3756189260 AX/FLAM-75 AX/FLAM-75 +2859854936 AX/LAS-5 AX/LAS-5 +3677140801 AX/TX-13 AX/TX-13 +2743699188 AXIS 坐标轴 +3642991046 Ayre 艾尔 +4116054022 AZTERRA 艾孜泰拉 +4193991609 AZUR SECUNDUS 艾热尔次星 +2020958113 B-01 Tactical B-01“战术” +1306153500 B-01 TACTICAL B-01“战术” +4165878208 B-02 Gloom Warden B-02阴霾守望者 +1554678688 B-02 GLOOM WARDEN B-02阴霾守望者 +1290089593 B-04 Developer Of Democracy B-04“民主缔造者” +481563344 B-04 DEVELOPER OF DEMOCRACY B-04“民主缔造者” +2129711499 B-08 Light Gunner B-08“轻装枪手” +2202159575 B-08 LIGHT GUNNER B-08“轻装枪手” +910517385 B-1 B-1 +1806271432 B-100 B-100 +1339661327 B-16 Battle-Scarred Veteran B-16“百战老兵” +3475932864 B-16 BATTLE-SCARRED VETERAN B-16“百战老兵” +91112513 B-22 Model Citizen B-22“模范公民” +8334221 B-22 MODEL CITIZEN B-22“模范公民” +1050431518 B-24 Enforcer B-24“执行者” +1079235484 B-24 ENFORCER B-24“执行者” +2574245188 B-27 Fortified Commando B-27“强化突击兵” +1185066006 B-27 FORTIFIED COMMANDO B-27“强化突击兵” +2595831478 B. Silo 01 电池舱01 +3997391343 B. Silo 01 电池舱01 +1274597484 B. Silo 02 电池舱02 +3366451506 B. Silo 02 电池舱02 +924843531 B. Silo 03 电池舱03 +1996039132 B. Silo 03 电池舱03 +2625476061 B/FLAM-80 B/FLAM-80 +2420165896 B/MD B/MD +4054570984 B1qBeefEater 大囗吃牛肉 +886162969 B3FFFBD8 B3FFFBD8 +2131376106 Back 返回 +4011383807 Back 返回 +543684003 Back 返回 +1722931847 BACK 返回 +4048072361 BACK TO GALAXY MAP 返回星系地图 +2185143619 BACK UP EMERGENCY DATABASE 备份紧急数据库 +1197656392 BACK-PACKING A PUNCH 重拳出击 +3714601832 Backend version mismatch - You must update the game to the latest version. 后端版本不匹配 - 你必须将游戏更新至最新版本。 +2315290736 Backpack 装有化学武器的背包 +123252959 BACKPACK 背包 +2200366814 BACKPACK 背包 +3991100215 BACKPACK 背包 +4229291019 BACKPACK 背包 +720507175 Backup Vehicle 备用载具 +3306620154 BACKUP VEHICLE 备用载具 +536959834 Badge of Order 秩序徽章 +1727726490 BADGE OF ORDER 秩序徽章 +4181220349 BAHASA INDONESIAN (Unsupported) BAHASA INDONESIAN (Unsupported) +3780323521 BALANCED 平衡 +3792917764 BALANCED 平衡 +2137230620 BALDRICK PRIME 巴尔德里克主星 +2126903330 BALLISTIC PADDING 防弹内衬 +3265833747 Ballistic Shield Backpack 防弹护盾背包 +430638869 BALLISTIC SHIELD BACKPACK 防弹护盾背包 +1297927281 Ballistic Shield Backpack stratagem availability has ended. 现已无法使用“防弹护盾背包”战略配备。 +2562342867 BALLOT 民望 +2621705030 Baneful Sentinel 祸患光能哨兵 +323559873 BANEFUL SENTINEL 祸患光能哨兵 +2869710000 Baneful Sentinels 祸患光能哨兵 +2944028248 BANKABILITY 金枢 +811469586 Banner 旗帜 +2324026679 BARABOS 巴勒博斯 +965944469 Barbed Wire 倒刺铁丝网 +828944962 Barely able-bodied Citizens 体弱的公民 +987942581 BARNARD SECTOR 巴纳德分区 +2375950297 BARRACKSBURG 兵营堡 +3789599480 BARRAGE 火力网 +3921592399 Barrager Tank 铁幕坦克 +3557245244 BARRAGER TANK 铁幕坦克 +3025038405 Barrager Tanks 铁幕坦克 +3517486397 BARREN WARD 不毛沃德 +2419932919 Barrier planets 屏障星球 +135325812 Base 基地 +1596772767 BASE CAMP 8 8号基地 +3492692240 Based on a colonial surgeon's gown, where surgeries were often interrupted by a need to perform defensive duties. 原型是殖民地外科医生的手术袍。外科医生经常在手术中途被打断,受命立刻前去执行防卫任务。 +2395299620 Based on a SEAF Signaller's Cape, which was intended to enable easy location of fallen heroes by aerial recovery crews. 设计原型是超级地球武装部队的披肩,目的是帮助空中救援小队轻松找到阵亡的英雄。 +3665511317 Based on the ceremonial pennant flags of early Super Earth, which now adorn the entrance to each Ministry. 设计原型是早期超级地球的仪式用三角旗,如今用于装饰各部门的入口。 +113684085 Based on the uniform of Jackle 6, a veteran of the Viper Commandos who held off an entire Terminid brood on Nublaria in the First Galactic War with nothing but a machine gun, pocket knife, and Orbital Laser Strikes. 以毒蛇突击队老兵“杰克尔六号”的制服为基础设计而成。第一次星系战争期间,这位老兵仅凭机枪、小刀和轨道激光炮就拦下了努布拉里亚的整支终结族大军。 +3239741438 BASHYR 巴希尔 +2864309722 BASIC 基础 +4018724654 Baskin 巴斯金 +1657112894 BASQUINE VIII 巴斯金VIII +686081100 Bastion Mk XVI 堡垒Mk XVI +1916631053 BASTION MK XVI 堡垒MK XVI +3844548524 Bastion of Integrity 忠义堡垒 +1323469312 BASTION OF INTEGRITY 忠义堡垒 +3514184557 BASTION OF INTEGRITY 忠义堡垒 +3196977326 BATTERY DISPERSAL INTERFACE 电池分配界面 +2512561516 BATTERY SILO 01 电池舱01 +3971507478 Battery Silo 01 Offline 电池舱01停用 +2103923543 BATTERY SILO 02 电池舱02 +1323381177 Battery Silo 02 Offline 电池舱02停用 +2600483602 BATTERY SILO 03 电池舱03 +906353481 Battery Silo 03 Offline 电池舱03停用 +2850657241 BATTERY SILO ACTIVATING 电池舱正在启动 +3922644143 Battery silo offline 电池舱停用 +1594707715 BATTERY STORAGE STATION CONSOLE 电池储存站控制台 +872291281 BATTLE FOR CYBERSTAN 生化斯坦之战 +1808133179 BATTLE FOR SUPER EARTH 超级地球保卫战 +3637171496 BATTLE ROYALE: Bugs vs. Automatons 绝地乱斗:虫族对机器人 +28815540 Battlefield pickups contain #V_ONE% less ammo. 战场拾取物中将减少#V_ONE%的弹药。 +2051090765 Battlefield pickups on all planets contain #AMOUNT% less ammo. 所有星球上的战场拾取物中将减少#AMOUNT%的弹药。 +1122436356 Battlefield pickups on all planets contain #AMOUNT% more ammo. 所有星球上的战场拾取物中将增加#AMOUNT%的弹药。 +1791460633 Battlefield pickups on this planet contain #AMOUNT% more ammo. 在此星球上的战场拾取物中将增加#AMOUNT%的弹药。 +3009293899 BATU BELIG 巴图贝利格 +3055226511 BAY DOOR CONTROL 坞门控制 +4139471255 BAY DOOR CONTROL 船坞大门控制 +3519611870 Bayrak 巴伊拉克 +3445857369 Be advised that you will shortly expire if you are reading this 注意,读到这条消息意味着你命不久矣 +2049351693 Be injured in all limbs at the same time. 四肢同时受伤。 +3587867250 BEACHVIEW 碧景湾 +4192505977 Beacon 信标 +4281962947 Beacon must be under constant supervision once activated. 信标一旦启动,必须一直监控。 +1148083630 Beacon of Mercy 仁慈信标 +3704058834 BEACON OF MERCY 仁慈信标 +2170674031 BEAM 激光束 +3828783979 Bearer is more resistant to being knocked prone. 配备此盔甲可降低被击倒的概率。 +1312730729 Bearers of this armor ride no equine mount, but are nonetheless borne to battle atop the trusty steed of Liberty. 穿上这套盔甲后虽然不能骑真正的马,却仿佛驾驭自由精神的良驹奔赴战场。 +4207470053 Bearers of this cape take upon a sacred duty: that of delivering righteous retribution to every last deserving being. 穿戴此披肩的人将背负神圣的使命:向每一个罪有应得的生灵发动正义的复仇。 +1032874602 Because this prototype's wires operate at 400,000 volts, it also includes a handy rubber underlayer for insulation. 此原型的电线需要在400,000伏特的电压下运行,因此盔甲配有便利的橡胶绝缘内衬。 +654804006 BEEFBURG 比夫堡 +4265123640 Being prone makes you less susceptible to explosions. When in imminent danger, dive! 扑倒在地可以躲避爆炸。面对迫在眉睫的危险,记得及时闪躲! +4219840211 BEKVAM III 贝克温III +3494209900 BELLATRIX 参宿五 +2495956148 Bellawala 贝拉瓦拉 +2606087619 Belt-Fed Grenade Launcher 弹链式榴弹发射器 +3796576739 BELT-FED GRENADE LAUNCHER 弹链式榴弹发射器 +1312594489 Belt-Fed Grenade Launcher Backpack 弹链式榴弹发射器背包 +2796024923 BELT-FED GRENADE LAUNCHER BACKPACK 弹链式榴弹发射器背包 +495939690 BENEVOLENCE 仁城 +2591525843 Bernklint 柏恩科林特 +1757932330 Beroshi 贝洛西 +3201222154 Berserker 狂暴者 +2154346758 BERSERKER 狂暴者 +1177202472 Berserkers 狂暴者 +1991059820 Better Racks 提高挂架质量 +3735438181 BETTER RACKS 提高挂架质量 +2226413510 BETTER THAN BARE MINIMUM 勉强及格 +3344257325 Bettmann 贝特曼 +2370408778 Beware of blinding blizzards and deep snow. 小心阻挡视线的暴风雪和深厚的积雪。 +1426482906 Beyond 50m, you'll be out of contact range from your squadmates. Stay in proximity to maintain full situational awareness. 和队友相距超过50米就会失联。请避免远离队友,以便全面掌握战场动态。 +2499211273 BFFF4752 BFFF4752 +2841221522 BICEP 擎穹 +1795971311 BIG ROCK 巨岩 +289101936 BIG STRETCH 用力舒展 +3132116140 Big Whoop 喝彩 +2401251969 BIG WHOOP 喝彩 +717622970 Bile Spewer 胆汁喷涌虫 +3302818592 BILE SPEWER 胆汁喷涌虫 +2572786553 Bile Spewers 胆汁喷涌虫 +444529084 Bile Spitter 胆汁吐沫虫 +1524275396 BILE SPITTER 胆汁吐沫虫 +592325338 Bile Spitters 胆汁吐沫虫 +2514244534 Bile Titan 吐酸泰坦 +2614950221 BILE TITAN 吐酸泰坦 +4165766606 Bile Titans 吐酸泰坦 +3365898186 Bile Warrior 吐酸武斗虫 +3306812932 BILE WARRIOR 吐酸武斗虫 +1805104840 Bile Warriors 吐酸武斗虫 +3278267572 Billions of stars. One Federation. + +The Ministry of Expansion. 亿万星辰归属一个联邦。 + +扩张部 +2479285427 Billnert 比尔纳特 +2310120315 BINDINGS 键位绑定 +1233597562 Bio-Genetics Startup Fills Volcano With Mutant Giant Popcorn Kernels 生物基因初创企业向火山内投入大量变种巨型爆米花仁 +918788164 BIOGRAPHY: 生平事迹: +3480261096 BIRCHVILLE 桦木维尔 +1969023152 BIRTH 圣生市 +2936867513 Bjorkman 比约克曼 +4046999266 Black Box 黑匣子 +2101115961 BLACK BOX 黑匣子 +3346432464 BLACK BOX 黑匣子 +3917311779 Black Saffron 番黑花 +3554948094 BLACK SAFFRON 番黑花 +184752654 BLACKVEIN MINES 黑脉矿井 +1411044618 Blade 之刃 +2727431881 BLAST ABSORPTION 爆炸吸收 +1852532685 BLAST RADIUS 爆炸半径 +3331238150 BLAST SIMULATION 爆炸模拟 +659728335 BLAZING SAMARITAN 慈心闪耀 +3473231131 BLAZING SAMARITAN 慈心闪耀 +654079031 Bleeding 出血 +1609021693 BLESTRAIL 圣途市 +3422660136 BLIGHTSMURK 瘟茨默克 +877629863 BLISTICA 布里斯提卡 +2570056183 BLITZ 闪电战 +1310571425 Blitzer 雷霆 +2786999754 BLITZER 雷霆 +635280456 Blizzard In Progress 暴风雪正在形成 +2021867720 BLIZZARDS 暴风雪 +607078834 BLOCK 屏蔽 +2224862582 BLOCKED PLAYERS 已屏蔽玩家 +1418356293 Blood 布拉德 +1186162679 BLOOD-STAINED LIBRARY CARD 血迹斑斑的借书证 +2719120968 Bloom 泛光 +3647147840 Bloom Quality 全屏泛光质量 +4188832216 Bloom Strength 全屏泛光强度 +4237091623 BLOWN FUSES FOUND 发现熔断器熔断 +2922189908 Blunt force trauma 钝性创伤 +3982403047 Board the EXTRACTION SHUTTLE! 登上撤离运输船! +3907595406 BODY ARMOR 躯体盔甲 +580550564 Body Type 体型 +4212648847 BODY TYPE 体型 +3292633095 Body type has no impact on gameplay 体型不影响游戏内容 +3679991512 Body type has no impact on gameplay 体型不影响游戏内容 +3476251425 BOHUS 布胡斯 +741706408 Bolin 博林 +903077010 Bolle 博莱 +2370143250 Bolt Pistol 爆弹手枪 +131884198 BOLT PISTOL 爆弹手枪 +611789294 Bonds Awarded 奖励债券数 +782753749 BONUS SUPER CREDITS 额外超级货币 +1666349407 Boost overall crew efficiency with a suite of proven enthusiasm enhancement initiatives, such as citizenship anniversary celebrations and paid lavatory breaks. 采取一系列行之有效的措施调动积极性,提高船员的总体效率。采取的措施包括举办公民纪念日庆典活动,以及允许带薪如厕等。 +2077605767 BOOSTED 已强化 +3476063430 Booster 强化资源 +309737129 BOOSTER 强化资源 +3042834795 BOOSTER 强化资源 +4220880742 BOOSTER 强化资源 +2462816897 Booster Pack 强化资源包 +2047743615 BOOSTER PACK 强化资源包 +2589774000 Boosters 强化资源 +3368068355 BOOSTERS 强化资源 +1885654624 BOOSTING SIGNAL... #COUNT 正在增强信号……#COUNT +141615983 Boosts Requisition and XP awards by 50% to address accounting errors (responsible parties undergoing re-education). 申购点和经验奖励增加50%以修正核算错误(负责人正接受二次教育)。 +3369110221 BOPSFIELD 波普斯菲尔德 +4068986124 Borderless Window 无边框窗口 +2808893037 Borderline Justice 临界正义 +1487022517 BORDERLINE JUSTICE 临界正义 +459832108 Bore hole completed 博尔虫洞已完成 +4212061343 BORE ROCK 博尔岩 +1451959923 BOREA 博瑞亚 +1364807175 BORGUS SECTOR 博格斯分区 +108165008 Bot Drop Detected 侦测发现机器人 +3215974987 Bot Scrapper 机器人克星 +53785855 BOTEIN 天阴四 +1225804857 Botelho 博特略 +639153789 Both of your legs are injured, severely impairing your movement. 你的双腿都受伤了,你的移动能力将受到严重影响。 +1565933151 BOTSLAYER 机械屠戮者 +2363242992 BOTSLAYER 机械屠戮者 +2633748284 BOTTOM RIGHT 右下 +126660537 Boxer 拳击手 +3429686733 BOXER 拳击手 +759723416 BP-20 Correct Officer BP-20“思想矫正官” +1732453131 BP-20 CORRECT OFFICER BP-20“思想矫正官” +1850940314 BP-32 Jackboot BP-32“杰克军靴” +747912226 BP-32 JACKBOOT BP-32“杰克军靴” +1401822931 BP-77 Grand Juror BP-77“大陪审员” +751476668 BP-77 GRAND JUROR BP-77“大陪审员” +3202104171 BR-14 BR-14 +202906239 BRAKE / REVERSE 刹车/倒车 +803654454 Braking when still will shift the vehicle into reverse. 静止时刹车,载具将进入倒车状态。 +914537891 Brave the Megafactory and liberate this land from Cyborg occupation. 勇闯超大型工厂,将这片土地从生化人的占领中解放出来。 +1191482327 BRAVERY 勇城 +2500585152 BRAWFERMLAND 布劳费尔兰 +1974334302 Brawler 乱斗者 +3870488427 BRAWLER 乱斗者 +3596915833 Brawlers 乱斗者 +779690813 Brawny 健壮 +61347800 BRAWNY 健壮 +93608745 Breach the Illuminate's lair and eliminate the devious threats that lurk within. 突破光能者巢穴,消灭其中的狡诈威胁。 +4009668453 Breaching Hammer 破门锤 +3139950515 BREACHING HAMMER 破门锤 +660349586 BREACHING TERMINID COLONY 攻破终结族拓殖地 +2971672550 Break-Action Shotgun 中折式霰弹枪 +2928423351 BREAK-ACTION SHOTGUN 中折式霰弹枪 +2097159574 Breaker 破裂者 +4200280549 BREAKER 破裂者 +3152471869 Breaker Bugbiter 噬虫“破裂者” +1999641793 BREAKER BUGBITER 噬虫“破裂者” +3437132835 Breaker Incendiary 高燃“破裂者” +736963480 BREAKER INCENDIARY 高燃“破裂者” +155688291 Breaker Nailspitter 尖钉喷射“破裂者” +2655616645 BREAKER NAILSPITTER 尖钉喷射“破裂者” +3510885812 Breaker Spray&Pray 千发百中“破裂者” +3352341534 BREAKER SPRAY&PRAY 千发百中“破裂者” +2219406620 BREAKING NEWS 突发新闻 +4256289693 BREAKING NEWS 突发新闻 +3272005495 BREAKING NEWS: FIRST AUTOMATON FOOTAGE 突发新闻:首获机器人影片 +2305804327 Breakthrough Exosuit “突破”外骨骼装甲 +1386708865 BREAKTHROUGH EXOSUIT “突破”外骨骼装甲 +173031125 Bredberg 布雷德贝格 +3069469219 Brettman 布雷特曼 +1421360586 Brezavscek 布雷扎夫谢克 +1224708308 Bridge 舰桥 +2075951053 BRIDGE 舰桥 +3139500659 BRIDGE 舰桥 +1280384913 BRIDGE 舰桥 +1956039007 BRIDGE 舰桥 +4267041493 BRIEF 简报 +2875263080 Brief But Totally Not Worrying Illuminate Brain Takeover 所幸时间较短,不足为虑 +4194145910 Briefcase 公文包 +2004909665 BRIEFCASE 公文包 +3149676664 BRIEFING 简介 +2908633975 BRIEFING 简报 +3278706819 BRIEFING TRANSMISSION 简报通讯 +970164922 BRIGHT WING 明翼市 +803894884 BRILLIANCE 璨光 +2488533786 Bring each of the three battery silos online to activate this TCS+ station. 启动全部三个电池舱,即可启动这座TSC+站。 +2563272656 Bring up the MAP to view objectives and orient yourself. 调出地图查看目标,确认自己的位置。 +3410743548 Bringer 引路人 +3300214952 BRINK-2 布林克2 +186396141 BRNO 布尔诺 +581172809 BROKER'S WEALTH 经纪财富市 +938290675 Bronko_P4triot 我心向国_布兰科 +3077749065 Brood Commander 虫族指挥官 +3067999294 BROOD COMMANDER 虫族指挥官 +113277221 Brood Commanders 虫族指挥官 +1460486101 Brood Warden 虫族守卫 +1261841844 BROOD WARDEN 虫族守卫 +2725043444 Brood Wardens 虫族守卫 +4262588123 Broomhall 布鲁姆霍尔 +1396376486 Brostrom 布洛斯特伦 +4258233989 BUCU'S REST 布库安息城 +1045564851 BUFFER TANK 缓冲罐 +1437062679 Bug Breach Detected 侦测发现虫族入侵 +283300406 BUG CONTAINMENT 虫族管控 +2464878739 BUG CONTAINMENT 虫族管控 +2835905808 BUG CONTAINMENT 虫族管控 +2359399777 Bug Extermination 歼灭虫族 +3277626454 Bug Hole 虫穴 +1550275945 BUG HOLE 虫穴 +3877198592 Bug Holes 虫穴 +1562356454 BUG HORDE 虫族群袭 +2648272673 BUG QUARANTINER 虫族清道夫 +2258743961 Bug Stomper 虫族克星 +4123362121 Bugs 虫族 +3604350372 Bugslayer 诛虫煞星 +3113764814 BUGSLAYER 诛虫煞星 +3900627240 BUJU 布朱 +644365486 Bulk Fabricator 巨型构筑者 +1485006967 BULK FABRICATOR 巨型构筑者 +208056545 Bulk Fabricators 巨型构筑者 +4291272963 Bullet Storm 子弹风暴 +987248759 BULLET STORM 子弹风暴 +1592000584 Bullets 子弹 +1428857865 Bullets Fired 射击弹药数 +3106913140 Bullying/Harassment 霸凌/骚扰 +710669387 BUNDA SECUNDUS 天垒城一次星 +716998375 BUNKER BUSTER 碉堡克星 +3304043117 BUNKER HATCH LOCKED 掩体舱门未解锁 +3921936527 Bunker Turret 碉堡炮台 +68531086 BUNKER TURRET 碉堡炮台 +2438321228 Bunker Turrets 碉堡炮台 +2687364051 Bunting of the Party Participant 派对彩饰 +406963016 BUNTING OF THE PARTY PARTICIPANT 派对彩饰 +3009428589 BURIER OF HEADS 埋首者 +875994096 Burning 灼烧 +3651111227 Burrows 伯罗斯 +2523245633 Burst 连射 +1598250703 Bushwhacker 游击兵 +833991994 BUSHWHACKER 游击兵 +3893345838 BUSY 忙碌 +2977701482 Buy 购买 +959516526 Buy (RQ) 购买(申购点) +3529660071 Buy (SC) 购买(超级货币) +3453199911 BUY CHARGES 购买炸药 +946922623 BUY ITEM 购买物品 +3126725797 BUY ITEM 购买物品 +195851522 BUY LEGENDARY WARBOND 购买传奇战争债券 +1085746499 BUY LEGENDARY WARBOND 购买传奇战争债券 +3763979263 BUY MEDALS 购买奖章 +1438583820 BUY PREMIUM WARBOND 购买尊享战争债券 +3519688692 BUY PREMIUM WARBOND 购买尊享战争债券 +666200943 BUYING ITEM 正在购买物品 +2058722951 By clicking 'Agree and Continue', you are bound to the terms in the EULA. + +https://www.playstation.com/legal/op-eula/ 点击“同意并继续”即表示你愿意遵守最终用户许可协议的规定。 + +https://www.playstation.com/legal/op-eula/ +2123748982 By reminding Chemical Agents of proper distancing rules, this extraordinary innovation in cape design ensures that they never cause another unfortunate outbreak of Carcino-Plague. 提醒化学专家保持适当距离的创新披肩设计可确保他们不会再引发卡西诺瘟疫灾难。 +4181953786 Bypass terminal security 绕过终端安全系统 +1898505845 C.O.B. Genetics to Donate Last Year's Corn to Hungry Cows. C.O.B.基因公司拟向饥牛捐赠去年所产玉米 +2772570910 C4 Pack C4背包 +4226754563 C4 PACK C4背包 +2333022316 CADET 军校生 +3921710548 CALCULATING EVACUATION FLIGHT PATH 正在计算疏散飞行路线 +3942769164 CALCULATING MISSILE TRAJECTORY 正在计算导弹弹道 +383096607 CALCULATING SHUTTLE FLIGHT PATH 正在计算运输船飞行路线 +3034324044 CALCULATING TRAJECTORY 正在计算轨迹 +3430946630 CALEFACTORIA 炽庭 +2696957758 Calibrate LiDAR tower alignment 校准对齐激光雷达塔 +2785843711 CALIBRATE PROBE 校准探测仪 +2587020879 CALIBRATE VOLTAGE 校准电压 +2790972812 Calibrate voltage to maximize output 校准电压,将输出提升至最大 +3079966101 Calibrating seismic sensor array 正在校准地震传感器阵列 +259851759 CALIBRATING VOLTAGE 正在校准电压 +1473301188 CALL 呼叫 +3495029008 Call down a Hellbomb and use it to destroy the monolith 呼叫地狱火炸弹摧毁巨石 +1290033850 Call down a Hellbomb to destroy the Cannon 呼叫地狱火炸弹摧毁加农炮 +3729817985 Call down a Hellbomb to destroy the Cooling Tower 呼叫地狱火炸弹摧毁冷却塔 +4083735584 Call down a Hellbomb to destroy the Counter-Orbital Cannon 呼叫地狱火炸弹摧毁反轨道加农炮 +3429108108 Call down a Hellbomb to destroy the Gazer Spire 呼叫地狱火炸弹摧毁凝视者尖塔 +472754469 Call down SSSD and insert into Hatch 呼叫超级固态硬盘并将其置入舱门 +100511399 Call For Enlistments Sent To All Citizen Classes. 参军号召已发送至各级公民 +2695342073 Call in EXTRACTION SHUTTLE. 呼叫撤离运输船。 +641234779 Call in a RESUPPLY to refill your AMMUNITION and STIMS. 呼叫重新补给,补充弹药和治疗剂。 +708132202 Call in a Resupply when low on ammo. 弹药不足时可呼叫重新补给。 +3438445098 Call in a large container to load up with liberated goods for secure extraction. 呼叫大型集装箱,装载解放物资以便安全撤离。 +4084206755 Call in an emergency beacon to show other Helldivers that you need assistance. 呼叫求救信标,向其他绝地潜兵表明你需要支援。 +3305068834 CALL IN SUPER DESTROYER 呼叫超级驱逐舰 +2193262763 Call in your Super Destroyer, enabling the usage of stratagems for a limited time. One use per mission. 呼叫超级驱逐舰,启用战略配备,限时生效。每次任务使用一次。 +378967278 Call the Helldivers 呼叫绝地潜兵 +2414167741 CALL THE HELLDIVERS 呼叫绝地潜兵 +1381524075 CALL-IN TIME 呼叫时间 +532323933 CALL-IN TIME 呼叫时间 +4066610996 Caltrops 铁蒺藜 +2484425642 CALTROPS 铁蒺藜 +1437811852 CALYPSO 卡利普索 +4059750260 Camara 卡马拉 +169303566 Camera Shake Strength 视角摇晃强度 +635354976 Camo Cloak 迷彩斗篷 +1917125054 CAMO CLOAK 迷彩斗篷 +3846689033 CAMO CLOAK 迷彩斗篷 +2588078506 CAMP LEIGHTON 莱顿营 +2577515503 CAMPAIGN STATUS 战役状态 +4024417057 CAMPAIGN UPDATE +Due to successful intelligence operations, each completed operation will contribute more than normal to planetary liberation. 战役动态 +由于情报行动大获成功,完成的每一场行动都会比平时更加有效地推动星球的解放大业。 +3987696966 CAMRAT FOR 卡姆拉特堡 +3724327667 Can't Ration My Love 我的爱无法定量配给 +2990234726 Can't start this activity while in a mission 正在执行任务,无法开启这项活动 +378751586 CANCEL 取消 +1556502648 CANCEL 取消 +2729654182 CANCEL 取消 +852429409 CANCEL FRIEND REQUEST 取消好友申请 +2668180337 Cancel Search 取消搜索 +575579583 CANCEL SQUAD INVITE 取消小队邀请 +559406208 CANCRI SECTOR 康古利伊分区 +709049035 CANDIDATE NOT ELIGIBLE FOR VOTES 候选人没有投票资格 +1914672627 Cannon operation can damage hearing. 加农炮操作会损伤听力。 +478200978 Cannon Turret 加农炮台 +3364806074 CANNON TURRET 加农炮台 +1780938436 Cannon Turrets 加农炮台 +1460346823 CANNONS 加农炮 +3593711931 CANNONS 加农炮 +3233921266 CANNOT - MEDICALLY DISQUALIFIED 否,体检不合格 +108768899 CANNOT EDIT 无法编辑 +3796753630 Cannot While In Prone 趴下时无法使用 +3429653155 CANOPUS 老人 +3880800031 CANTOLUS SECTOR 坎托鲁斯分区 +1001285226 CAPABILITY DISRUPTION 军事力量干扰 +30603049 Capable of firing a suite of space-to-ground indirect fire that can quickly free an entire battlefield from oppression. 能发射一组空对地间接火力,快速解救整个受到压制的战场。 +1945047332 CAPACITY 容量 +3174070746 CAPACITY 容量 +721313290 Cape 披肩 +2448026150 Cape 披肩 +2210601203 CAPE 披肩 +2924725942 CAPE 披肩 +2734887707 CAPE 披肩 +312869917 CAPES 披肩 +2418805493 CAPH 王良一 +3384238125 CAPTAIN'S LOG 少校的日志 +114886262 CAPTURE AUTOMATON TERRITORY 占据机器人领地 +3479204370 CAPTURE BUG TERRITORY 占据虫族领地 +3501062405 Capture evidence of Illuminate atrocities 收集光能者暴行证据 +3035241840 CARAMOOR 开勒莫尔 +2868939829 CARBONDALE 卡本代尔 +2457720597 CAREER 生涯 +392137679 Career: Kill #COUNT enemies 生涯:击杀#COUNT名敌人 +4270246281 CARGO CONTAINER 货物集装箱 +581608860 Cargo Truck 货车 +1081588136 Carlberg 卡尔贝格 +1679090488 Carpet Bomb 地毯式轰炸 +1265258834 CARPET BOMB 地毯式轰炸 +247341556 CARRIABLE 可携带 +1411027276 Carve a path through the Megafactories towards the Cyborg Capital—the largest Megafactory and nexus of Cyborg resistance. Destroy it before our Forces in Reserve are depleted to liberate Cyberstan. 从超大型工厂杀出一条血路,直捣生化人首都,那是最大的超大型工厂,也是生化人抵抗势力的核心枢纽。在预备部队耗尽战力之前将其摧毁,解放生化斯坦。 +2683971696 CASE OF "DEMOCRACY DRAFTS" PREMIUM LIGHT BEER “民主之风”至尊淡味啤酒的外包装 +2412064616 CASTELLAN GREEN EXOSUIT PATTERN 卡斯特兰绿外骨骼装甲涂装 +3912751418 CASTELLAN GREEN HELLPOD PATTERN 卡斯特兰绿喷射舱涂装 +2391738712 CASTELLAN GREEN SHUTTLE PATTERN 卡斯特兰绿运输船涂装 +4228051427 CASTELLAN GREEN VEHICLE PATTERN 卡斯特兰绿载具涂装 +1104629083 CASTELLAN'S CREED 卡斯特兰信条 +4005363541 CASTELLAN'S CREED 卡斯特兰信条 +3914500540 CASTOR 北河二 +383980596 Casual Salute 敬礼 +2499442695 CASUAL SALUTE 敬礼 +927196985 CATCHY TUNE 洗脑旋律 +75307050 Caught on fire? Stims will heal you, but won't douse the flames. Instead: stop, drop, and roll! 着火了?治疗剂可以治愈你的伤势,但无法扑灭火焰。不过,你可以立刻停下脚步,扑到地面翻滚起来! +1031312853 Caught them by Supplies! 物资出击! +2989731610 Causes Element 710 Rain Over HydroFall Prime 致710元素洒遍水瀑主星 +1865818670 CAUSTIC 腐蚀气体 +566245999 Caution: deleted data cannot be recovered 当心:已删除的数据无法恢复 +459656999 Caution: loyal civilians are on the battlefield. 当心:战场上发现忠诚平民。 +1688242820 CB-9 CB-9 +2909424452 CE-07 Demolition Specialist CE-07“拆除专家” +3016669355 CE-07 DEMOLITION SPECIALIST CE-07“拆除专家” +2854330936 CE-101 Guerilla Gorilla CE-101“游击猩猩” +808894733 CE-101 GUERILLA GORILLA CE-101“游击猩猩” +614297745 CE-27 Ground Breaker CE-27“裂地者” +3268303935 CE-27 GROUND BREAKER CE-27“裂地者” +1265620134 CE-35 Trench Engineer CE-35“战壕工程师” +2501843501 CE-35 TRENCH ENGINEER CE-35“战壕工程师” +3662120282 CE-64 Grenadier CE-64“掷弹兵” +1477109933 CE-64 GRENADIER CE-64“掷弹兵” +2014104199 CE-67 Titan CE-67“泰坦” +3112422815 CE-67 TITAN CE-67“泰坦” +1410048178 CE-74 Breaker CE-74“破裂者” +3030317504 CE-74 BREAKER CE-74“破裂者” +2907005557 CE-81 Juggernaut CE-81“巨人” +3946533903 CE-81 JUGGERNAUT CE-81“巨人” +3090275867 CELEBRATION 庆祝市 +3677750052 CELESTE SECTOR 塞勒斯特分区 +1970153390 Censor 审查官 +2899640133 CENSOR 审查官 +1987520353 CENTER 中心 +2523019553 CENTER FOR CITIZEN SURVEILLANCE (DESTROYED) 公民监控中心(遗址) +4246407614 CENTER FOR CIVILIAN SURVEILLANCE AND SAFETY 公民监控和安全中心 +1999064883 CENTER FOR THE CONFINEMENT OF DISSIDENCE (CECOD) 异见监禁中心 (CECOD) +2750913230 CENTER OF SCIENCE 科学中心 +717015403 CENTER OF SCIENCE (DESTROYED) 科学中心(遗址) +3235654230 CENTRAL NETWORK 中央网络 +3725356541 CERBERUS IIIc 刻耳柏洛斯IIIc +1129889217 CHAIRMAN OKOTE 主席奥科特 +1928467696 CHAIRMAN OYESLLO 主席奥耶斯洛 +2820793322 CHALLENGING 充满挑战 +1702269750 CHAMELEON CAMO EXOSUIT PATTERN 变色龙迷彩外骨骼装甲涂装 +517761245 CHAMELEON CAMO HELLPOD PATTERN 变色龙迷彩绝地喷射舱涂装 +1007144656 CHAMELEON CAMO SHUTTLE PATTERN 变色龙迷彩运输船涂装 +1876036886 CHAMELEON CAMO VEHICLE PATTERN 变色龙迷彩载具涂装 +4286117683 Champion 斗士 +1531527023 Chandler 钱德勒 +1612104560 Change aim mode while aiming to use WEAPON SCOPE. 瞄准时切换瞄准模式可使用武器瞄准镜。 +3222418800 CHANGE BINDINGS 更改键位绑定 +936803494 Change Button 更改按键 +746656972 CHANGE BUTTON AND ACTIVATE 更改按键并启动 +4089214182 CHANGE CAMERA MODE 更改视角模式 +589636226 CHANGE EQUIPMENT (LONG) 更换装备(长) +1195432865 CHANGE EQUIPMENT (SHORT) 更换装备(短) +3185536337 CHANGE SHIP NAME 更改舰船名称 +1712837066 Change size of subtitles as they are displayed on screen. 选择屏幕上显示的字幕尺寸。 +2064909256 Change the color of your aiming reticle, for greater visibility. 更改准星颜色,更好地调整可视度。 +3460849909 Changing the ATTACHMENTS on your weapon will affect its stats and properties. Changing the PATTERN will affect its visuals. + +Use your weapon in order to level it up and unlock more mods using REQUISITION 更换武器配件会影响武器数据和属性。更换涂装会影响武器外观。 + +使用武器可提升其等级,消耗申购点可解锁更多改装模组 +3722503053 CHARA 常陈四 +429677395 Character 角色 +1387320051 CHARACTER 角色 +3143846020 CHARBAL-VII 查巴尔VII +952503073 CHARGE 充能 +4007451216 Charge into the Exostorm and save this planet from falling to the Void. 挺进异界风暴,拯救这颗星球,使其免于堕入寂域。 +1299714559 Charger 强袭虫 +2864097220 CHARGER 强袭虫 +1076678822 Charger Behemoth 巨兽级强袭虫 +4146569305 CHARGER BEHEMOTH 巨兽级强袭虫 +93572740 Charger Behemoths 巨兽级强袭虫 +3084412776 Chargers 强袭虫 +1021642579 Charges up to fire a powerful, explosive energy burst. Has a long cooldown period after firing. 充能后可发射爆炸性的强力能量炮。发射后的冷却时间较长。 +2297916711 CHARGEUP 充能 +1914518290 CHARGING 正在充能 +1901047489 CHARON PRIME 卡戎主星 +2284698652 CHART TERMINID TUNNELS 绘制终结族隧道网络 +3878204021 CHAT ONLY 仅聊天 +942195533 CHATOYANT 幻彩城 +2190298508 Cheating 作弊 +1868226607 Cheating/Glitching 作弊/利用游戏漏洞 +3124706693 CHECK ALL SUB-SYSTEMS 检查所有子系统 +3407772937 CHECK MEMORY ADDRESS 检查存储器地址 +3954057584 Check your Ammo by holding the Reload button. 按住装填弹药按钮查看弹药数量。 +4239784512 Check your Ammo by holding the Reload button. 按住装填弹药键查看弹药数量。 +2176385321 Check your current ammo and weapon settings in the WEAPON FUNCTIONS MENU. 在武器功能菜单查看当前弹药和武器设置。 +1203706306 Check your ship's TV for news on the war, combat tips, and advertisements for the hottest products in the galaxy. 观看舰船的电视,可以掌握战争的最新动态,了解战斗技巧,以及观赏星系人气产品的广告。 +2477964005 Chemical Agents 化学专家 +3280746776 CHEMICAL AGENTS 化学专家 +3054644200 Chemical Backpack 装有化学武器的背包 +3913619604 Chemist 化学家 +89577386 Chest Hemorrhage 胸腔出血 +2050983655 CHIEF 军督 +3699613863 Child Finds Toy Battleship She Lost In Black Hole 6 Years From Now. 儿童发现自己6年后无意落入黑洞的玩具战舰 +4280421164 Children's Hospital Explosion Linked to Automaton Sympathizer Group "Innominate." 儿童医院发生爆炸,事件与亲机器人组织“无名”存在关联 +1213932068 CHOEPESSA IV 科埃佩萨IV +3402720361 Choking fog and torrential rainfall can affect sight range. 令人窒息的浓雾和暴雨会影响视野能见度。 +2366892687 CHOOHE 丘伊 +4254042897 Choose in what context subtitles are displayed. 选择在哪些情况下显示字幕。 +3423820232 Choose whether you go into matchmaking with other players on the network when looking for a game, or whether you keep your session private and between friends. + +NOTE: The "Invite Only" setting only works with invites sent from the in-game menu 选择匹配寻找游戏时是公开匹配在线玩家,还是只和好友匹配。 + +注意:“仅限邀请”设置只适用于从游戏内菜单发起的邀请 +1163481027 Choose which device to use as your microphone. 选择用作麦克风的设备。 +717825012 Choose your loadout carefully to ensure your squad has all the resources it needs. Democracy depends on it! 谨慎选择武装配置,确保小队具备所有必要资源。这是捍卫民主的基石! +343442322 CHORT BAY 雀特湾 +2713366007 CHURNED EARTH EXOSUIT PATTERN 焦土外骨骼装甲涂装 +4172616071 CHURNED EARTH HELLPOD PATTERN 焦土绝地喷射舱涂装 +1234543540 CHURNED EARTH SHUTTLE PATTERN 焦土运输船涂装 +2998976873 CHURNED EARTH VEHICLE PATTERN 焦土载具涂装 +3147514894 Circle Button 圆圈键 +511125198 CIRCUIT EXPANSION 扩建电路 +2788864241 CIRRUS 希勒斯 +2028104177 Citizen 公民 +3199404057 CITIZEN KILLED 误杀公民 +2483239672 CITIZENS EAGER TO HELP 公民迫切贡献力量 +2852239993 CITY 城市 +2512194864 CITY DEFENSE STATUS 城市保卫状态 +637079656 City Fighter's Resolve 城市战士的决意 +3888364102 CITY FIGHTER'S RESOLVE 城市战士的决意 +2214315056 CITY LIBERATION PROGRESS 城市解放进度 +2274321752 CITY MISSION 城市任务 +180403125 CITY OPERATION 城市行动 +894064163 CITY OPERATION REWARD 城市行动奖励 +2611116152 Civilian 平民 +630395645 Civilian resistance units have taken significant ground from the enemy on Planet #V_ONE. The freedom fighters have been recognized for their duty and rewarded with proper drafting into the SEAF. 平民抵抗组织在#V_ONE星球上从敌方手上夺下重要阵地。这群自由战士的功绩得到了认可,也获得了适当的奖赏:收编进入超级地球武装部队。 +2720395566 CIVILIANS & SEAF IN AREA 区域内有平民和超级地球武装部队 +525501 CIVILIANS IN AREA 区域内有平民 +3118616277 CIVILITY 礼序 +841627405 CLAIM 占领 +3693821121 CLAIM ITEM 领取物品 +3850364391 CLAIM LEGENDARY WARBOND 领取传奇战争债券 +3136073089 CLAIM PREMIUM WARBOND 领取尊享战争债券 +1462597954 Claim rewards 领取奖励 +124187678 CLAIM STANDARD WARBOND 领取标准战争债券 +37463211 CLAIMING ITEM 领取物品 +3279100752 CLAORELL 可洛尔 +1587174419 Clapping 鼓掌 +2808361603 CLAPPING 鼓掌 +655206231 CLASA 克拉萨 +505181551 CLASS 1 EXOSTORM 1级异界风暴 +3997830063 CLASS 1 MEGAFACTORY 1级超大型工厂 +3058724709 CLASS 2 EXOSTORM 2级异界风暴 +3571355349 CLASS 2 MEGAFACTORY 2级超大型工厂 +2161677472 CLASS 3 EXOSTORM 3级异界风暴 +1000490702 CLASS 3 MEGAFACTORY 3级超大型工厂 +497177949 CLASS 4 MEGAFACTORY 4级超大型工厂 +2255878520 Claw 之爪 +1556757292 Claws 螯爪 +1715788834 Claws 螯爪 +3403924736 Claws 螯爪 +4066032861 Claws 螯爪 +3379521453 CLE ELUM REDIVIVA 克利勒姆复兴城 +4178405022 CLEANSE FOUL SHRINE 净化污秽神社 +2662320096 CLEANSE INFESTED DISTRICT 净化侵染区域 +2812025640 Clear area of enemies (#REMAINING Remaining) 肃清敌方区域(还剩#REMAINING) +3264564303 CLEAR ILLUMINATE ENCAMPMENT 摧毁光能者营地 +3234749115 CLEAR ILLUMINATE STRONGHOLD 摧毁光能者要塞 +277583446 Clear the area of Terminid nests to prepare it for Gloom research specialists. 清除该区域的终结族巢穴,为“阴霾”研究专家的考察做好准备。 +3412826211 Cleared Heavy Illuminate Encampment 已摧毁光能者重型营地 +2984854125 Cleared Light Illuminate Encampment 已摧毁光能者轻型营地 +106414693 Cleared Medium Illuminate Encampment 已摧毁光能者中型营地 +1265668144 Cleared Stronghold 已摧毁要塞 +3251804132 CLERICAL ERROR RESOLVED - ITEM RECEIVED 文书错误已修正 - 已收到物品 +3204305803 Client Platform not supported 不支持客户端平台 +1815301764 CLIMB 攀爬 +2117352184 CLOAK OF POSTERITY'S GRATITUDE 后族怀恩披风 +3717369657 CLOCKSTOP 钟停市 +774206641 CLOSE 关闭 +854540367 CLOSE 关闭 +1257796139 CLOSE 关闭 +2885617433 Close BUG HOLES using GRENADES. 用榴弹封闭虫穴。 +3149171670 Close all bug holes 封闭所有虫穴 +2181388342 Close Door 关门 +3608710307 Close orbit superiority will allow faster extractions than normal for the near future 由于我方掌控近地轨道,近期撤离行动效率较平时有所提高 +3814801462 Close valve 关闭阀门 +1582276545 Closed Caption Mode 隐藏式字幕模式 +1928180472 Cluster Bomb 集束炸弹 +2219258544 CLUSTER BOMB 集束炸弹 +2096025240 CM-06 Combat Medic CM-06“医疗兵” +4154864331 CM-06 COMBAT MEDIC CM-06“医疗兵” +526077306 CM-09 Bonesnapper CM-09“碎骨杀手” +2343099532 CM-09 BONESNAPPER CM-09“碎骨杀手” +2778148389 CM-10 Clinician CM-10“临床医师” +1763602207 CM-10 CLINICIAN CM-10“临床医师” +2402119974 CM-14 Physician CM-14“医师” +3046584487 CM-14 PHYSICIAN CM-14“医师” +260795141 CM-17 Butcher CM-17“屠夫” +2177493405 CM-17 BUTCHER CM-17“屠夫” +81991626 CM-21 Trench Paramedic CM-21“战壕护理员” +3650336257 CM-21 TRENCH PARAMEDIC CM-21“战壕护理员” +1734927926 Cognitive Disruption Field detected 侦测发现感知干扰域场 +1751768302 COGNITIVE DISRUPTOR 感知干扰器 +3748665524 Collect a total of #COUNT samples 总计收集#COUNT份样本 +3534933252 COLLECT BLACK BOX 收集黑匣子 +3253580867 COLLECT ENCRYPTED HARD DRIVE 收集加密硬盘 +3109124270 COLLECT GLOOM SPORE READINGS 收集“阴霾”孢子数据 +474072156 COLLECT GLOOM-INFUSED OIL 采集“阴霾”污染的原油 +430512990 Collect medals to progress your Warbond. No rush though—Warbonds can be completed at any time. 收集奖章,推进战争债券的进度。但是不用着急,你随时可以完成战争债券进度。 +3946672309 COLLECT METEOROLOGICAL DATA 收集气象数据 +2619320064 COLLECT MINERAL DATA 收集矿物数据 +120796772 COLLECT SAMPLES 收集样本 +3391960841 Collect the #ENTITY 收集#ENTITY +3017194838 collect the data disc 收集数据磁盘 +2333813626 Collecting sample 正在收集样本 +1925353026 Colonists who escaped Illuminate abduction and mind control—likely the most patriotic and steadfast of their demographic—are trapped in emergency shelters. The enemy is closing in; without rescue, they are doomed. + +Transport ships are inbound, but the evacuation zone is under enemy control. The Helldivers are the colonists' only hope. 逃离了光能者的囚禁及其精神控制的拓殖地居民(可能是该群体中最爱国、最坚定的人)现在困于紧急避难所中。敌人正在逼近,如果不实施营救,这些居民恐怕连性命也保不住。 + +运输舰即将抵达,但撤离区域仍受敌人管控。绝地潜兵是拓殖地居民的最后一丝希望。 +3664780818 Colony 拓殖地 +3799001491 Colony Breach Progress 拓殖地攻破进度 +2190082137 COLONY MISSION 拓殖地任务 +3921291543 COLONY OPERATION 拓殖地行动 +3726974502 COLONY OPERATION REWARD 拓殖地行动奖励 +1702667700 COLONY SAVIOR 拓殖地救星 +1278136431 COLOR PICKER 选取颜色 +3723342013 Colossus 巨匠 +3689757614 COLUMBIDAE 和平鸽 +1649782566 Com.Mission Inf (Community) 完成任务的影响力(社区) +1787625357 Com.Mission Inf (Max) 完成任务的影响力(最大) +1305039869 Com.Mission Inf (Self) 完成任务的影响力(自我) +2126726749 Com.Mission Inf (Start) 完成任务的影响力(初始) +4049493088 COMBAT 战斗 +733296492 COMBAT (BOTS) 作战(机器人) +1952421485 COMBAT (BUGS) 作战(虫族) +1125475403 COMBAT (ILLUMINATE) 作战(光能者) +393183860 Combat Blend 混合作战 +1758285928 Combat Blend 混合作战 +2364437367 Combat Blend 混合作战 +2934560541 Combat Blend 混合作战 +1743428706 COMBAT BLEND 混合作战 +2080084177 COMBAT BLEND 混合作战 +3003541519 COMBAT BLEND 混合作战 +3988789060 COMBAT BLEND 混合作战 +21575910 Combat Engineer 战斗工兵 +3323049326 Combat Hatchet 战斗短柄斧 +2791735802 COMBAT HATCHET 战斗短柄斧 +1788291818 COMBAT STIMS 作战治疗剂 +3303998986 COMBATANT FORCES PRESENT 存在武装力量 +1070271449 COMING SOON! 即将上线! +245997106 Command Bunker 指挥碉堡 +2967066434 COMMAND BUNKER 指挥碉堡 +1441650636 Command Bunkers 指挥碉堡 +1465907482 Command Center of the Super Destroyer. The helm from which Helldivers deliver Freedom's mercy. 超级驱逐舰的指挥中心,绝地潜兵通过这个船舵传递自由精神的仁慈。 +3587077630 COMMAND DIVEMASTER MAJOR 潜兵长少校指挥官 +2497843047 Command Input 指令输入 +781916859 COMMANDER 上尉 +2008789512 Commando 突击兵 +103056538 COMMANDO 突击兵 +1592504616 COMMANDO 突击兵 +1351614953 COMMANDO OPERATION 突击兵行动 +778517830 COMMANDO OPERATION 突击兵行动 +863574571 COMMANDO OPERATION 突击兵行动 +44963207 Commemorating the bold pioneers who first successfully navigated High Command’s newest tactical mechanisms. The distinctive replication of visor scarring represents a close-range ideological exchange with the Terminid scourge, proving that Managed Democracy shall remain unblinded by fascist aggression. 旨在纪念那些最先成功驾驭最高指挥部最新战术机制的英勇先驱。头盔面甲疤痕的独特复刻,代表着与终结族毒瘤进行近距离意识形态交锋,彰显管理式民主绝不会被法西斯侵略蒙蔽双眼。 +1310618246 Commemorating the New Stockholm treaty on prisoners of war, this cape celebrates the right of all enemy combatants to a swift and merciful execution. 该披肩旨在纪念关于战俘的《新斯德哥尔摩公约》,颂扬了敌方战斗人员享有的被迅速、仁慈处决的权利。 +857928321 COMMEND 称赞 +1911074985 Commend other Helldivers for good behavior! 多多称赞其他绝地潜兵的优秀表现! +3553253164 Commend other Helldivers for good behavior! 多多称赞其他绝地潜兵的优秀表现! +448085263 Commend Player 称赞玩家 +305703295 Commend your squadmates on a job well done. We're all on the right side of history! 多多称赞队友的出色表现。我们都走在历史的康庄大道上! +3191847530 Commends 获赞 +621159586 Commissar 机械统帅 +1258196470 COMMISSAR 机械统帅 +1892656262 Commissars 机械统帅 +3817167598 COMMON 普通 +690293147 Common Sample 普通样本 +3369805427 COMMON SAMPLE 普通样本 +1232923576 Common Samples 普通样本 +188329071 COMMON SAMPLES 普通样本 +1583121437 Commonly replicated in stage adaptions of "Lady Liberty's Tower", in which young Diver Beatrick dons this armor to slay Oppressio, the Tyrant Rex. 这套盔甲常见于《自由女神塔》的舞台剧版本,剧中年轻的绝地潜兵比特里克正是身着这套盔甲,斩杀暴君王奥普雷西奥。 +3261476433 COMMS RELAY HUB 通信中继站 +3116282103 Comms Wheel Visibility 通信轮盘可视度 +3172956985 COMMUNEFALLS 公社瀑布 +8683499 COMMUNICATION 通信 +1645271001 Communication Troubles From Terminid Quarantine Zone. 通讯难题困扰终结族隔离区 +11598142 COMMUNICATIONS 通讯 +554934911 COMMUNICATIONS ARRAY 通信阵列 +291289431 COMMUNICATIONS DEVICE 通信设备 +546537153 COMMUNITY IMPACT 社区战役贡献 +667693308 Community Reinforced 增援社区 +3317286805 Community Rewards 社区奖励 +753803428 Community-Target Mission 社区目标任务 +837443102 Compact and flexible, this kevlar armor adds minimal mass, making it a common choice for Helldiver fitness tests. 此芳纶纤维盔甲坚实又灵活,几乎不增加额外重量,是绝地潜兵体能测试的常用配备。 +47641505 COMPARE 对比 +3401389966 COMPARE INFO 对比信息 +814768413 Compass Angle Range 罗盘角度范围 +1469578210 Compass Ordinal Directions 罗盘方位 +834080005 Compass Small Notches 罗盘小刻度 +3237724355 Compass Visibility 罗盘可视度 +193218204 Compass Width 罗盘宽度 +1286216626 Compensator 补偿器 +655552663 COMPENSATOR 补偿器 +2744233581 Complete #COUNT#TYPE #OBJ#RACE_PRE#RACE#RACE_POST#MULTI. 完成#COUNT个#TYPE#OBJ。#RACE_PRE#RACE#RACE_POST#MULTI +1703319218 COMPLETE #CR_DESC#CR_NEWLINE OPERATION TO UNLOCK 完成#CR_DESC#CR_NEWLINE行动后解锁 +1139251439 Complete #COUNT difficulty 6+ missions 完成#COUNT场难度系数为6以上的任务 +2715791332 Complete 10 tactical objectives. 完成10个战术目标。 +1883870398 Complete a difficulty #COUNT or higher mission without dying 在无人阵亡的情况下完成难度系数为#COUNT或以上的任务 +888228522 Complete a difficulty #COUNT or higher mission without taking any damage 在没有受到任何伤害的情况下完成难度系数为#COUNT或以上的任务 +3211646015 Complete a full Extreme difficulty Blitz mission and extract in under 6 minutes. 在6分钟内完成一项难度为“极端”的闪电战任务并撤离。 +3884685493 Complete a full Extreme difficulty Blitz mission and extract in under 6 minutes. 在6分钟内完成一项难度为“极端”的闪电战任务并撤离。 +3377781636 Complete a full Hard difficulty mission or higher without anyone firing their primary or support weapon. 在无人使用主武器或支援武器的情况下,完成一项难度为“困难”或以上的任务。 +28572979 Complete a Hard difficulty mission or higher without anyone firing their primary or support weapon. 在无人使用主武器或支援武器的情况下,完成一项难度为“困难”或以上的任务。 +1476181576 Complete a mission but fail to extract. 完成任务,但撤离失败。 +2697137884 Complete a mission with #COUNT% accuracy 以#COUNT%的命中率完成一次任务 +2816087179 Complete a Stalker Hive tactical objective. 完成追踪虫虫窝战术目标。 +3396949973 Complete all PRIMARY OBJECTIVES to enable extraction. 完成所有主要目标即可撤离。 +2432823045 Complete an Operation#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST 顺利完成行动。#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST +1360527855 Complete an Operation#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST 顺利完成行动。#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST +3625397401 Complete an Extreme difficulty mission or higher without anyone dying. 在无人死亡的情况下完成一项难度为“极端”或以上的任务。 +1842016181 Complete at least 100 missions. 完成至少100项任务。 +74724350 Complete Basic Training. 完成基本训练。 +2820688680 Complete Helldiver Obstacle Course 完成绝地潜兵障碍训练 +263762794 Complete Missions to help push the enemies of Super Earth back. + +You can do Missions on any contested Planet in any of the contested Sectors. 完成任务,协助击退超级地球的敌人。 + +你可以前往处于争夺状态的分区,在任意一颗处于争夺状态的星球上执行任务。 +3372276277 Complete operations in #SECTOR 在#SECTOR完成行动 +1070316424 Complete operations on #PLANET 在#PLANET完成行动 +2411926627 Complete the #OBJ Objective#COUNT_PRE#COUNT#COUNT_POST#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI. 完成#OBJ目标。#COUNT_PRE#COUNT#COUNT_POST#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI +4273808819 COMPLETED 已完成 +2595433212 completed task in [#ASSIGNMENT_TITLE] 已完成[#ASSIGNMENT_TITLE]中的任务 +3969586049 Completed: #AMOUNT M 完成:#AMOUNT +4271408647 Completely sheathed in 14-cm silica fiber foam, except for a thin tube to the ear canal to enable hearing the satisfying screeches of Freedom's enemies as they burn. 14厘米厚的硅纤维泡沫将全身包裹在内,只在耳道处留下了纤细的管道,让穿戴者能够心满意足地听见自由之敌在烈火中痛苦尖叫。 +4153717289 Completing this operation contributes to the planet's Defense. 完成此次行动将推动星球防御进程。 +808072914 Completing this operation contributes to the planet's Liberation. 完成此次行动将推动星球解放进程。 +3370187171 Completing this operation has an impact on the Illuminate Fleet Strength. 完成此次行动将影响光能者舰队战力。 +2772833762 Completing this Operation helps hold this city. Successfully holding cities significantly contributes to the planet's Defense. 完成此次行动有助于保卫这座城市。成功保卫城市将大幅推动星球防御进程。 +2000175962 Completing this Operation helps hold this Mega City. Once a Mega City falls, it cannot be reclaimed. 完成此次行动有助于保卫这座特大城市。特大城市一旦沦陷便无法收复。 +708822192 Completing this Operation helps liberate this Megafactory. Each liberated Megafactory brings us closer to the total liberation of Cyberstan. 完成此次行动有助于解放这所超大型工厂。每解放一所超大型工厂,我们就离彻底解放生化斯坦更近一步。 +1399351634 Completing this Operation helps liberate this Megafactory. Successfully liberating Megafactories significantly contributes to the planet's Liberation. 完成此次行动有助于解放这所超大型工厂。成功解放超大型工厂将大幅推动星球解放进程。 +61153676 Completing this Operation helps reclaim this city. Successfully reclaiming cities significantly contributes to the planet's Liberation. 完成此次行动有助于收复这座城市。成功收复这座城市将大幅推动星球解放进程。 +2190929935 Completion Est: #HOURS h 预计用时:#HOURS小时 +658115724 Complex Stratagem Plotting 复杂的战略配备部署流程 +3665609909 COMPLEX STRATAGEM PLOTTING 复杂的战略配备部署流程 +1557516932 Composed of reclaimed industrial mesh and salvaged banners. This cape celebrates the beauty found in the aftermath of purging Tyranny at high-speeds. The debris of these successes, and those like it, remind us all of the sanctity of Sovereignty. 由回收的工业网格和残破旗帜组成。这件披肩赞美了疾速肃清暴政后产生的美感。这些成功的残骸提醒所有人:主权神圣不可侵犯。 +1336810892 Compressed Explosives 压缩炸药 +2096264212 Compressed Explosives 压缩炸药 +521071804 COMPRESSED EXPLOSIVES 压缩炸药 +3300122689 COMPRESSED EXPLOSIVES 压缩炸药 +4069903258 COMPROMISE AUTOMATON DEFENSES 破坏机器人的防御系统 +890074584 Comptroller 督察者 +1849785256 Concealed Insertion 隐蔽上阵 +2401426028 CONCEALED INSERTION 隐蔽上阵 +3335590414 CONCEALED SYSTEM 隐蔽星系 +255562771 CONCERNING NUMBER OF MONOLITHS 巨石数量令人担忧 +3799172693 CONCRETE JUNGLE EXOSUIT PATTERN 混凝土丛林外骨骼装甲涂装 +2283210632 CONCRETE JUNGLE HELLPOD PATTERN 混凝土丛林绝地喷射舱涂装 +1522055334 CONCRETE JUNGLE SHUTTLE PATTERN 混凝土丛林运输船涂装 +3110738283 CONCRETE JUNGLE VEHICLE PATTERN 混凝土丛林载具涂装 +3327391057 Concrete, undeniable evidence of unspeakable Automaton atrocities are located here. Capture them with the tactical video camera so the truth can be brought to light. 证明机器人暴行的确凿证据就在此处。用战术摄像机录下证据,让真相大白于天下。 +141575155 CONCUSSIVE PADDING, GRENADIER 防震内衬(掷弹兵型) +2634038544 CONCUSSIVE PADDING, HAZMAT 防震内衬(防化型) +3332727941 CONCUSSIVE PADDING, REINFORCED 防震内衬(强化型) +894730804 CONDEMN ILLICIT EXPERIMENTS 谴责非法实验 +3227632520 Conduct a geological survey to assess planetary composition. 开展地质调查,评估星球的构成成分。 +1735277762 Conduct a geological survey to identify valuable ore veins. 进行地质调查,寻找珍贵矿脉。 +2032931639 Conduct a geological survey to identify valuable ore veins. 进行地质调查,寻找珍贵矿脉。 +45516229 Conduct a geological survey to identify veins of valuable ore. 进行地质调查,寻找珍贵矿脉。 +2610886589 CONDUCT GEOLOGICAL SURVEY 开展地质调查 +3125033657 CONDUCT GEOLOGICAL SURVEY 开展地质调查 +3732427795 CONDUCT GEOLOGICAL SURVEY 开展地质调查 +3801761417 Conduct mass-scale Terminid fumigation to ensure planetary safety. 开展大规模终结族熏杀作业,保障星球安全。 +1450979115 CONDUCT MOBILE E-711 EXTRACTION 移动式提取711元素 +3007747450 CONDUCT MOBILE EXTRACTION 移动式提取 +2923422500 CONDUCT MOBILE SUBSTANCE EXTRACTION 移动式提取物质 +3383862050 Conductor of Brilliance 辉煌指挥官 +3498937342 CONDUCTOR OF BRILLIANCE 辉煌指挥官 +602223619 Confidential Data 机密数据 +2800461844 Confidential Data 机密数据 +1769449185 CONFIDENTIAL DATA 机密数据 +3839214628 CONFIDENTIAL DATA 机密数据 +1413914605 Confirm 确认 +3242249721 Confirm 确认 +1312323707 CONFIRM 确认 +3599585416 CONFIRM 确定 +955217368 Confirm depth using drill interface 使用钻机界面确认深度 +1104170543 CONFIRM DRILL POSITION 确认钻机位置 +533059049 Confirm Evacuation Coordinates 确认疏散坐标 +1756452880 CONFIRM JOIN 确认加入 +2803746190 CONFIRM PURCHASE 确认购买 +2972872019 CONFIRM SCAN AREA 确认扫描区域 +574273170 Confirm scan area using probe interface 使用探测仪界面确认扫描区域 +1087423356 Confirm that drill site is safe for operation 确认钻探地点可安全作业 +1128581656 CONFIRM VOTE 确认投票 +2668621417 Confirmed 已确认 +349962696 CONFIRMING COORDINATES 正在确认坐标 +3141709354 CONFISCATE ASSETS 没收资产 +3906982366 Confiscate platinum and fusion batteries at this site. 没收此处的铂金和聚变电池。 +3498181594 Conflagration Devastator 烈火蹂躏者 +1784440447 CONFLAGRATION DEVASTATOR 烈火蹂躏者 +3671149001 Conflagration Devastators 烈火蹂躏者 +2111845990 CONLON COLONY 康伦拓殖地 +3968858894 Connect Battery Silos to Central Tower 将电池舱与中央巨塔连接起来 +3002476963 CONNECTION ERROR 连接错误 +1345210966 Connection regained. 连接已恢复。 +1942794615 Connection to server failed 未能连接至服务器 +4204986708 Conquer #PLANET in the #SECTOR 征服#SECTOR的#PLANET +1926911363 Conquer the #SECTOR 征服#SECTOR +526355675 CONSENSUS 康森瑟斯 +3680443513 Constant eruptions keep this planet covered in lava flows and utterly inhospitable to Democratic life. It also makes it a treasure trove of rare minerals. 火山持续喷发,导致这颗星球被熔岩流覆盖,完全不适宜民主生命居住。但这里也因此成为稀有矿物的宝库。 +3412085850 Constitution 宪法 +3315031899 CONSTITUTION 宪法 +3841653069 CONSTRUCTING GEOGRAPHIC MODEL 正在构建地理模型 +2075705502 Construction has begun on the Democracy Space Station. The local populace is honored to host thousands of construction crews for this historic event. 民主空间站(DSS)的建设工作已经开始。当地居民荣幸地接待了参与此次历史性活动的数千名建筑工人。 +1114624260 Construction of the Democracy Space Station is nearing completion. This project, which has employed millions, will soon take its place among the greatest achievements of Democracy. 民主空间站(DSS)将近完工。这个数百万人参与建设的项目将是民主伟业最伟大的成就之一。 +33358005 CONSUMING VOID 吞噬寂域 +2190508241 Contact Mine 水雷 +717377401 CONTACT MINE 水雷 +2712444983 Contains a grain of sand from Super Earth—so its bearers carry a small piece of Liberty with them, wherever they go. 载有一粒来自超级地球的沙子,让不论穿戴者身在何处,心中都承载着自由。 +3058806105 Contains many small pockets, allowing the user to evenly distribute the weight of ammunition, samples, and cool rocks. 包含许多小口袋,方便使用者根据重量均衡放置弹药、样本和酷炫岩石。 +2488091525 CONTESTED ORBIT 竞相争夺的轨道 +1844119004 CONTINUE 继续 +2957047785 CONTINUE 继续 +1265522119 CONTROL CENTER 控制中心 +758996211 CONTROL CHAMBER LOCKED 控制室已锁定 +3991304024 CONTROL CHAMBER UNLOCKED 控制室已解锁 +3862989608 Control Group 变量控制 +4212104855 CONTROL GROUP 变量控制 +1572058980 CONTROLLER 控制器 +3981871075 CONTROLLER 控制器 +2104221780 Controller only. Selecting Default will swap between primary and secondary weapon when tapping the swap button, whilst holding the swap button will change to your support weapon. +Helldivers Classic will swap between primary and support weapon when tapping the swap button, whilst holding the swap button will change to your secondary weapon. 仅限控制器。选择“默认”时,轻点切换按钮切换主要或次要武器,按住切换按钮切换为支援武器。 +选择“绝地潜兵 经典”时,请点切换按钮切换主要武器或支援武器,按住切换按钮切换为次要武器。 +2450614437 Controller only. Selecting Default will swap between primary and secondary weapon when tapping the swap button, whilst holding the swap button will change to your support weapon. +Helldivers Classic will swap between primary and support weapon when tapping the swap button, whilst holding the swap button will change to your secondary weapon. 仅限控制器。选择“默认”时,轻点切换键切换主要或次要武器,按住切换键切换为支援武器。 +选择“绝地潜兵 经典”时,请点切换键切换主要武器或支援武器,按住切换键切换为次要武器。 +2867590819 Controller Sticky Aim 控制器粘滞瞄准 +3922673638 Controller Sticky Aim 控制器粘滞瞄准 +1318672668 CONTROLS 控制项 +201222417 Controls the quality of the bloom filter. Affects GPU performance. 控制全屏泛光过滤质量。影响GPU性能。 +2892966282 Controls the quality of the scene lighting calculation 控制场景光照计算质量 +1618269950 Controls the strength of the bloom filter. Contributes to the feeling of brightness on highlights. 控制全屏泛光过滤强度。影响玩家对光亮环境的亮度感受。 +154617429 CONVENIENCE 捷城 +1892826563 CONVENTIONAL BLACK HOLE 常规黑洞 +1131505083 Conventional SEAF forces are heavily deployed across this planet, and may directly support Helldiver missions. 常规超级地球武装部队已在该星球上大量部署,可直接为绝地潜兵的任务提供支援。 +777228561 Convoy Destination 车队目的地 +172064230 CONVOY HAS LEFT MISSION AREA 车队已离开任务区域 +1773632087 Cookout 野炊 +9945900 COOKOUT 野炊 +1488816523 Cool guys don't loo- AAAAH! 真男人从不回头看…啊啊啊! +2286666200 COOLDOWN 冷却时间 +2611035692 Cooldown period decrease for #V_ONE stratagem no longer in effect. #V_ONE战略配备冷却时间缩短的效果结束。 +2761612032 Cooldown period for #V_ONE stratagem increased by #V_TWO. #V_ONE战略配备的冷却时间延长#V_TWO。 +2568918320 Cooldown period for #V_ONE stratagem is temporarily increased by #V_TWO. #V_ONE战略配备的冷却时间暂时延长#V_TWO。 +3888729957 Cooldown period for #V_ONE stratagem is temporarily reduced by #V_TWO. #V_ONE战略配备的冷却时间暂时缩短#V_TWO。 +2416591458 Cooldown period for #V_ONE stratagem reduced by #V_TWO. #V_ONE战略配备的冷却时间缩短#V_TWO。 +1192959313 Cooldown period increase for #V_ONE stratagem no longer in effect. #V_ONE战略配备冷却时间延长的效果结束。 +2873566524 Cooldown T-#MINUTES:#SECONDS 冷却倒计时 #MINUTES:#SECONDS +1668745083 COOLDOWN TIME 冷却时间 +3455941334 Coordinates of potential ore strains, identified by the Automatons, are located here. Seize them. 机器人发现的潜在矿脉坐标情报就在此处。夺取坐标。 +310280534 COPY FRIEND CODE 复制好友代码 +3972061569 Copyright 版权 +3312645486 CORNUCOPOLIS 富饶城 +3292948085 Corpeleijn 科尔佩莱因 +1105510156 Corrosive acid storms temporarily reduce armor effectiveness for both enemy and friendly units. 腐蚀性酸雨风暴会暂时削弱盔甲的防护效用,敌我双方都将受影响。 +2616030087 Costly Failure 惨痛失利 +1750282018 COUNCILLOR RORA 议员罗拉 +3642914414 COUNTEROFFENSIVE AGAINST AUTOMATONS COMING 反攻机器人行动即将开启 +2574167973 Courier 信使 +1972178326 Courtly Bow 恭敬鞠躬 +1477912574 COURTLY BOW 恭敬鞠躬 +1797186070 Cover of Darkness 黑夜守护 +2046838101 COVER OF DARKNESS 黑夜守护 +1772916582 Covering Fire 火力掩护 +4001910789 COVERING FIRE 火力掩护 +1751983263 Coyote 野狼 +2934925715 COYOTE 野狼 +878256512 COZY FLATS 馨寓 +2784934547 CPG-48 Sapper CPG-48“工兵” +1950924479 CPG-48 SAPPER CPG-48“工兵” +3123365807 CPH-26 Commandant CPH-26“司令官” +4122605483 CPH-26 COMMANDANT CPH-26“司令官” +3899068957 CPR-80 Bulwark CPR-80 “壁垒” +85526284 CPR-80 BULWARK CPR-80 “壁垒” +1459630170 CQC-1 CQC-1 +1461002790 CQC-19 CQC-19 +3291099282 CQC-2 CQC-2 +3919561454 CQC-20 CQC-20 +2744904675 CQC-30 CQC-30 +3222707032 CQC-42 CQC-42 +3350980592 CQC-5 CQC-5 +1658092087 CQC-72 CQC-72 +1434087097 CQC-73 CQC-73 +3747347702 CQC-9 CQC-9 +552680240 Crafted to deliver Justice to the darkest crevices of the galaxy. 为将正义传递到银河系最黑暗的缝隙而设计。 +3385218089 Created to honor the great Freedom Chant of 2-14, in which over 10,000 loyal citizens united as one to express their undying respect for Freedom. 为纪念伟大的2-14自由颂歌而创作,其时,有超过10,000名忠诚的公民联合表达了他们对自由的永恒敬重。 +1448502892 Creates a #BONUS chance of surviving a lethal hit. 在受到致命一击后有#BONUS的几率存活。 +4058189154 Creates a far-reaching incendiary blast ideal for crowd control against smaller enemies of Freedom. Equipped with a programmable timer for strategic versatility. 引发大范围燃烧爆炸,适合对小规模自由之敌实施群体控制。配备可编程定时器,增强战术灵活性。 +1684652607 Creates a large, thick smoke screen to block targets' line of sight. 可形成一道厚重的大型烟幕,遮挡目标的视线。 +1709216891 CREDITS 工作人员名单 +563225959 Cremator 焚燃者 +3705134773 CREMATOR 焚燃者 +711961656 Cremator Backpack 焚燃者背包 +1752350267 CREMATOR BACKPACK 焚燃者背包 +3877563222 Crescent Overseer 新月监视者 +3896445758 CRESCENT OVERSEER 新月监视者 +1038771782 Crescent Overseers 新月监视者 +613454310 Crest of the Unsullied 无垢徽章 +1554469453 CREST OF THE UNSULLIED 无垢徽章 +1518177291 Cresting Honor 荣誉之巅 +2813674372 CRESTING HONOR 荣誉之巅 +4065232286 CRESTING HONOR 荣誉之巅 +3557337080 Crests the shoulders of those who deliver the final—and most indispensable—stroke of Justice. 献给发起不可或缺的最终正义一击之人。 +122870317 Crew Training 船员训练 +1160544169 Crew Training 船员训练 +1723779337 CREW TRAINING 船员训练 +3097678828 CREW TRAINING 船员训练 +3752863521 Crewspace Removal 移除船员舱 +663874618 CREWSPACE REMOVAL 移除船员舱 +3962567934 CRIMSICA 克里姆西卡 +1630310654 CRIMSICA DEFENDED +The defense of Crimsica has succeeded. The Terminids have been repelled. 成功保卫克里姆西卡 +克里姆西卡保卫战以胜利告终,终结族已被击退。 +514916134 CRIMSICA FREED +Crimsica has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet. 克里姆西卡已解放 +克里姆西卡挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。 +396202355 CRIMSICA LOST +The defense of Crimsica has failed. Terminids now infest its once-pristine surface. 克里姆西卡沦陷 +克里姆西卡保卫战已宣告失败。终结族现在令这块曾经的纯净乐土不得安宁。 +1578469488 CRIMSICA UNDER ATTACK +The Terminids are attempting to spread to Crimsica. All Helldivers are called upon to deploy immediately to the planet's defense. 克里姆西卡遭到袭击 +终结族企图扩张至克里姆西卡。呼唤全体绝地潜兵,立即前去保卫该星球。 +1440298169 Crisper 迅击 +158954270 CRISPER 迅击 +3124935520 CRITICAL SYSTEM FAILURE 系统严重故障 +4004026431 CRITICAL SYSTEMS INTERFACE 关键系统界面 +1286783998 CRITICAL THREAT LEVEL 临界威胁等级 +3635848445 Cross Button 交叉键 +3712456867 CROSS-PLATFORM COMPATIBILITY 跨平台兼容 +46241004 Crossplay 跨平台游玩 +2998587476 CROSSPLAY 跨平台游玩 +2251267452 Crossplay enabled. You may encounter cross-network players. 跨平台游玩已开启。您可能会遇到跨平台玩家。 +530137869 CROUCH 蹲下 +2083818604 CRUCIBLE 熔炉 +3922421925 Crusher 粉碎者 +619042238 CRUSHER 粉碎者 +84388636 Crushers 粉碎者 +2907608837 Crushing 破碎 +3276450960 Crushing Charge 强冲 +2304284359 Crushing Claws 猛爪 +4057070900 Crushing Claws 猛爪 +4136557292 CRYSTAL SLOPES 水晶坡 +3902452526 Crystallized E-710 710元素晶体 +2211291692 CRYSTALLIZED E-710 710元素晶体 +1392270027 CULL SPAWN 抑制孵化 +2257698922 Cull the Terminids' foul brood and their odious progenitors. 剿灭终结族可憎的幼虫和虫族始祖。 +2825278027 CURIA 居里亚 +354695563 CURRENCY 通汇城 +1472930399 CURRENCY 货币 +4129983539 CURRENT CUSTOMIZATION 当前自定义 +601219658 CURRENT LOCATION 当前地点 +452525566 Current Major Order 当前重要指令 +4272867463 CURRENT MAJOR ORDER 当前重要指令 +2569706789 Current Personal Order 当前个人指令 +1597947665 Currently onboard: 目前已登船: +573514879 CURRENTLY UNAVAILABLE 目前无法使用 +1647160913 CURRENTLY UNAVAILABLE 目前无法使用 +2087816161 CURSA 玉井三 +1797656266 Cursor Sensitivity 光标灵敏度 +2511161553 Curtsy 屈膝礼 +1564382890 CURTSY 屈膝礼 +2665180277 Custodian 守护者 +718209201 CUSTOM 自定义 +2242401568 CUSTOMIZABLE 可定制 +80462159 CUSTOMIZATION UNAVAILABLE 自定义内容无法使用 +1509003863 Customize 自定义 +2507586233 CUSTOMIZE 自定义 +3133090661 CUSTOMIZE 自定义 +442059879 Customize your Helldiver with new cape, armor, and helmet. 用新披肩、盔甲和头盔对你的绝地潜兵进行自定义。 +3192711211 CUT OFF REINFORCEMENTS 切断增援 +1107536245 Cut the bots off from their information network by destroying their Command Bunkers. 摧毁指挥碉堡,切断机器人的信息网络。 +3138072003 Cutting Edge 遥遥领先 +254555360 CUTTING EDGE 遥遥领先 +3704135414 CUTTING-EDGE RESEARCH 尖端科研 +3516021318 CW-22 Kodiak CW-22“科迪亚克” +2859881014 CW-22 KODIAK CW-22“科迪亚克” +1617048491 CW-36 Winter Warrior CW-36“冬日战兵” +2141971169 CW-36 WINTER WARRIOR CW-36“冬日战兵” +356014921 CW-4 Arctic Ranger CW-4“极地游骑兵” +3227013992 CW-4 ARCTIC RANGER CW-4“极地游骑兵” +3260894616 CW-9 White Wolf CW-9“白狼” +2266600090 CW-9 WHITE WOLF CW-9“白狼” +942892090 CYBERSECURITY UPDATE +A recent systems security breach has resulted in Galactic War tables displaying inaccurate information. The breach has been addressed, and all systems have been returned to normal operation. Any discrepancies are to be considered the result of dissident misinformation. + +Rest assured that the parties responsible have been identified, arrested, tried, and executed. 网络安全更新 +最近发生的系统安全漏洞攻击事件导致星系战争的议战桌显示信息有误。该漏洞现已修复,所有系统均已恢复正常运行。任何不一致之处均将被视为异见者扭曲信息的结果。 + +肇事者已探明、逮捕、审判和处决,敬请放心。 +3923806493 CYBERSTAN 生化斯坦 +3598277119 CYBERSTAN 生化斯坦 +2707183486 CYBERSTAN 生化斯坦 +3708765037 Cyberstan Identified as Center of Automaton Command. 已发现生化斯坦是机器人指挥中枢 +3787919663 Cyberstan, once again, forms the axis of the Cyborg Legion's insurrection. Massive Megafactories cover its surface, churning out mechanical armies and weapons of mass extinction. + +The Ministry of Defense has ordered the unconditional destruction of Cyberstan. Descend upon their Megafactories and put a permanent end to the Cyborg threat. 生化斯坦再度成为生化人军团叛乱的核心。庞大的超大型工厂遍布地表,源源不断地制造机械军团与灭绝性武器。 + +国防部已下令无条件摧毁生化斯坦。降落到这些超大型工厂,彻底终结生化人威胁。 +1098467888 CYBORGS 生化人 +3033038880 Cyborgs are deployed to the battlefield of this planet, leading their Automaton armies. Expect to encounter vile propagandists trained in both ranged and melee combat. 生化人已部署至该星球战场,率领机器人大军作战。请做好准备,应对经过远近战双重训练的卑劣宣传机器。 +157381894 Cycle Pose 切换姿态 +143556318 CYCLE WEAPON CONFIG 循环选择武器配置 +1994078506 CYGNIA III 西格尼亚III +883290602 D-pad 方向键 +363109145 Dab 嘻哈超人舞 +2681791119 DAB 嘻哈超人舞 +1411936899 Dagger 匕首 +3037255820 DAGGER 匕首 +3193724295 Daily 每日 +2732575818 Daily - #HOURS:#MINUTES:#SECONDS 每日 - #HOURS:#MINUTES:#SECONDS +1702066642 Daily Complete 完成每日任务 +561614387 DAILY ORDER 日常指令 +1342077885 DAILY REWARD 每日奖励 +3141750097 DAMAGE 伤害 +4002873950 DAMAGE / SEC 每秒伤害 +440002655 DAMAGE ALT 其他伤害 +1843982045 Damage Over Time 持续伤害 +1173987893 Damage Type: #DAMAGE_TYPE 伤害类型:#DAMAGE_TYPE +110281808 DAMAGED 受损 +1095379698 DAMAGED FACTORIES 工厂受损 +2210337971 DANGER - ENEMY PRESENCE 危险 - 进入敌人势力范围 +4240804601 DANSK (Unsupported) DANSK (Unsupported) +3115257147 Daredevil Felix Bressler Freefalls 2.8 Billion Miles From Neptune to Super Earth 冒险勇士菲力克斯·布莱斯勒从海王星到超级地球自由落体28亿英里 +1143724091 DARIUS II 大流士II +1085262938 Dark Energy Accumulation 暗物质积聚 +2233202111 DARK FLUID INCIDENT 暗液体事故 +2520880460 DARK FLUID SYNTHESIS LABORATORY 暗液体合成实验室 +2370772246 DARK FLUID VESSEL 暗液体容器 +887712579 DARKWELL 暗井 +303689211 DARROWSHOME 达罗橡 +584255963 DARROWSPORT 达罗斯波特 +807737937 DATA CENTER 数据中心 +4264223109 Data Collection 数据收集 +1159822780 Data Jack 数据接口 +3731882316 DATA JACK 数据接口 +1036133473 DATA JACK OPERATIONAL 数据接口运作正常 +1389824615 Data Jack Status: Critically Damaged 数据接口状态:严重受损 +2545747281 Data Jack Status: Stable 数据接口状态:稳定 +29162783 Data Jack Status: Unstable 数据接口状态:不稳定 +678231927 DATA OPT-IN 同意使用的数据 +2674421567 DATA PACKAGES DELIVERED (#COUNT / #TARGET) 已交付的数据包(#COUNT / #TARGET) +3576715076 DATA TRANSMISSION 数据传输 +2634629103 Database downloading 数据库正在下载 +4268346210 Davidsson 戴维松 +1651252849 Dawn 黎明 +2371609024 DAY #COUNT 第#COUNT天 +3699245977 Day and night sides of a planet are visible during mission selection, allowing you to choose the mission that's right for you! 选择任务时你可以根据星球上的昼夜区域挑选合适的任务! +2345082861 DBS-2 DBS-2 +885747508 De Giorgis 德乔治 +1712527709 De-Escalator 缓和使者 +839881134 DE-ESCALATOR 缓和使者 +2388777114 De-Forester's Sailcloth 伐木工帆布 +136228120 DE-FORESTER'S SAILCLOTH 伐木工帆布 +3618398449 Deactivate Battery Silo 01 关闭电池舱01 +2569398198 Deactivate Battery Silo 02 关闭电池舱02 +1752226463 Deactivate Battery Silo 03 关闭电池舱03 +1462457090 Deactivate corrupted battery silos 关闭出错的电池舱 +1790503876 Deactivate Stratagem Jamming? 是否停止干扰战略配备? +3921356755 DEACTIVATE TERMICIDE TOWER 关闭灭虫终结塔 +270478576 DEACTIVATE TERMINID CONTROL SYSTEM 关闭终结族遏制体系 +2624781890 DEACTIVATE TERMINID CONTROL SYSTEM 关闭终结族遏制体系 +2340015848 Deactivate the battery silos to shut down the dispersion of Termicide. 关闭电池舱,停止喷洒灭虫终结剂。 +1726641594 Deactivating... 正在关闭… +660047342 Dead 死亡 +4169638634 DEAD 死亡 +390984542 Dead Sprint 死亡冲刺 +2365608952 DEAD SPRINT 死亡冲刺 +554425711 Deadeye 鹰眼 +2171894777 DEADEYE 鹰眼 +263642261 Deadzone 盲区 +1270272614 DEATH CAPTAIN 死神少校 +3513703094 Death is a natural part of being a Helldiver. 绝地潜兵必须时刻准备迎接死亡。 +852086541 Deaths 死亡次数 +1935531511 DEATHS: 阵亡次数: +3429370169 DEBTOR'S DOWNS 债丘 +875703432 debug damage 测试伤害 +568258717 Debug UI 测试UI +2865276760 Debuted during the New Mombasa Armor Show, this sleek ensemble is sure to turn heads and blow minds. 这套时髦的盔甲套装在新蒙巴萨盔甲展上首次亮相,必定成为全场焦点。 +1698883689 Dec 12月 +1263564083 Decades-old pumps have been rendered inoperable by unchecked Terminid infestation. But the pumps remain structurally intact, and the reservoirs they once pumped are now filled with a new, strange E-710-like substance. + +Clear the Terminid outgrowth clogging the pipeline, and restore it to operation. 因为终结族肆虐侵染,在这里放置数十年的泵机无法正常运作。但这些泵机的结构仍然完好,从前泵取的库存现在装满了类似710元素的新奇怪物质。 + +清除堵塞管道的滋生终结族,让管道恢复运作。 +1178268125 Decades-old pumps have been rendered inoperable by unchecked Terminid infestation. But the pumps remain structurally intact, and the reservoirs they once pumped are now filled with extremely valuable E-711. + +Clear the Terminid outgrowth clogging the pipeline, and restore it to operation. 因为终结族肆虐侵染,在这里放置数十年的泵机无法正常运作。但这些泵机的结构仍然完好,从前泵取的库存现在装满了极为珍贵的711元素。 + +清除堵塞管道的滋生终结族,让管道恢复运作。 +4094349837 December 12月 +1175345785 DECIMATING THE ENEMY 横扫千军 +3351977030 DECLINE 拒绝 +3920047250 DECLINE 拒绝 +4025776668 DECLINE 拒绝 +3059753801 DECORATED HERO 功勋英雄 +2841630368 Decreases Support Weapon stratagem cooldown by #VALUE%. 支援武器战略配备的冷却时间缩短#VALUE%。 +1924679868 Decreases cooldown for all Backpack stratagems by #VALUE%. 所有背包战略配备的冷却时间缩短#VALUE%。 +17576597 Decreases time to initiate deployment of Support Weapon Stratagems by removing dialog box confirming intent to fire. 通过移除确认发射意图的对话框,缩短支援武器战略配备的部署启动时间。 +2694605575 DEECON 圣侍 +932130225 Deep cover intelligence has, through highly classified and heroic means, identified a mutated strain of larvae in this hive. Find the mutated larvae and retrieve them for study by our heroic Bug Anatomy/Weapons Development (BAWD) Specialists. 我方人员英勇果敢地通过高度保密的途径传回情报,确定此虫窝内存在一种变异幼体。找出并带回变异幼体,供虫族解剖/武器研发(BAWD)的英勇专家进行研究。 +2798682948 DEEP MANTLE FORGE COMPLEX 深部地幔铸造复合体 +3554352793 DEEP MANTLE FORGE COMPLEX (DESTROYED) 深部地幔铸造复合体(遗址) +1676473398 DEEP REFLECTION 沉思 +2963023976 DEEPWELL 深井 +3136422594 Defamation 诽谤 +4118647834 Default 默认 +954643684 DEFAULT 默认 +2084248542 DEFAULT 默认 +1849445015 Default Helldiver Voice 1 绝地潜兵默认声音 1 +1951373264 DEFAULT HELLDIVER VOICE 1 绝地潜兵默认声音 1 +1048652091 Default Helldiver Voice 2 绝地潜兵默认声音 2 +1502976624 DEFAULT HELLDIVER VOICE 2 绝地潜兵默认声音 2 +2441287808 Default Helldiver Voice 3 绝地潜兵默认声音 3 +3193874095 DEFAULT HELLDIVER VOICE 3 绝地潜兵默认声音 3 +3149181118 Default Helldiver Voice 4 绝地潜兵默认声音 4 +534138438 DEFAULT HELLDIVER VOICE 4 绝地潜兵默认声音 4 +2884600217 Default Internal Part 默认内部零件 +899369943 DEFAULT INTERNAL PART 默认内部零件 +2471906021 Default Trigger 默认扳机 +1772318904 DEFAULT TRIGGER 默认扳机 +1538898674 Defeat a Bile Titan. 击败一只吐酸泰坦。 +3982625721 Defeat a Hulk. 击败一只巨型者。 +1734037268 DEFEND 保卫 +2901192254 Defend #PLANET against #COUNT attacks 保卫#PLANET,抵御#COUNT次袭击 +3994852662 Defend #PLANET against #COUNT attacks 保卫#PLANET,抵御#COUNT次袭击 +527016410 Defend #PLANET against #COUNT attacks by #RACE 保卫#PLANET,击退#COUNT次#RACE的进攻。 +3213718299 Defend #PLANET against #COUNT attacks from the #RACE 保卫#PLANET,抵御#RACE的#COUNT次袭击 +1847477750 Defend against #COUNT attacks from #RACE 抵御#RACE的#COUNT次袭击 +3820515876 Defend against #COUNT attacks from #RACE 抵御#RACE的#COUNT次袭击 +3644146541 Defend against #COUNT attacks from the #RACE in the #SECTOR 在#SECTOR抵御#RACE的#COUNT次袭击 +64650471 Defend against #COUNT attacks in the #SECTOR 在#SECTOR抵御#COUNT次袭击 +3900362086 Defend against #COUNT attacks in the #SECTOR 在#SECTOR抵御#COUNT次袭击 +1218451548 Defend against #COUNT attacks on any planet 在任意星球上抵御#COUNT次袭击 +1465528842 Defend against #COUNT attacks on any planet 在任意星球上抵御#COUNT次袭击 +1238788647 Defend Area 守卫区域 +2313924635 Defend Area 保卫区域 +363904388 Defend Battery Silo 01 保卫电池舱01 +235479654 Defend Battery Silo 02 保卫电池舱02 +4287527265 Defend Battery Silo 03 保卫电池舱03 +950693245 Defend Battery Silo until activation is complete 保卫电池舱,直到启动完毕 +1093694372 Defend Drill during deployment 部署期间保卫钻机 +315350949 DEFEND EVACUATION SITE 保卫撤离点 +2330806174 Defend Freedom 捍卫自由 +194624872 Defend generator system until all rockets have launched. + +Rockets launched: #CURRENT/#TARGET 在所有火箭弹发射完毕前保卫发电系统。 + +已发射的火箭弹:#CURRENT/#TARGET +1428945026 DEFEND PLANET 保卫星球 +3332479490 DEFEND PLANET 保卫星球 +3829262661 DEFEND PLANET 保卫星球 +1181578023 DEFEND SUPER EARTH 保卫超级地球 +2768917302 Defend the evacuation of top-secret military assets. 护送绝密军事资产撤离。 +2973916327 Defender 防卫者 +1185375349 Defender 捍卫者 +2275957581 DEFENDER 防卫者 +3838249343 Defender of Our Dream 梦想卫士 +4275591293 DEFENDER OF OUR DREAM 梦想卫士 +3334999697 DEFENDER OF THE WALL 高墙捍卫者 +1245451289 DEFENSE 防御战 +3589166843 DEFENSE CAMPAIGN 保卫战役 +307935590 DEFENSE HELD BY DSS DSS守住防线 +1646626712 DEFENSE NETWORK BREACHED 防御网络已突破 +1679117955 DEFENSE PROGRESS 保卫战役进度 +3324857446 Defense Wall 防御墙 +1219584954 DEFENSE WALL 防御墙 +3866756371 Defense Wall stratagem availability has ended. 现已无法使用“防御墙”战略配备。 +3975465670 DEFENSIBLE 卫戍 +2750058701 DEFENSIVE 防御 +226857251 DEFENSIVE STRATAGEM PERMIT 防御型战略配备许可证 +3027804797 Defensive Stratagems Used 防御型战略配备使用次数 +3689697660 Defoliation Tool 除叶工具 +4000631345 DEFOLIATION TOOL 除叶工具 +3166220323 DEFROSTING HELLDIVER 正在解冻绝地潜兵 +1354835711 Defy invaders who dare forsake our flag. Proudly raise our enduring symbol of Managed Democracy, and reclaim this city in the name of Freedom. 抗击丢弃我方旗帜的入侵者。高举管理式民主的不朽象征,以自由之名收复这座城市。 +596786391 DELIVER 送达 +1339087588 Deliver any SSSD Hard Drives 运送所有超级固态硬盘 +2962041444 DELIVER ANY SSSD HARD DRIVES 运送所有超级固态硬盘 +3128801766 DELIVER CARGO TO THE PICKUP POINT 将货物送到聚集点 +308165448 Deliver SSSD 运送超级固态硬盘 +4208429133 Delivers silent justice to Freedom's enemies. 向自由之敌传递无声的正义。 +3912695888 Delivery Point 交付点 +2822293866 DELIVERY SYSTEM 配送系统 +3937567880 DEMIURG 戴米尔基 +2474948923 Democracy ain't done with you yet 民主大业还需要你的力量 +1099126085 DEMOCRACY ALWAYS 恒民城 +321492180 Democracy Officer 民主官 +1882957075 Democracy Officer #NAME #NAME民主官 +2110167760 Democracy Officers are direct representatives of Super Earth High Command. They augment and enhance the loyalty of all Super Destroyer crew members. 民主官是超级地球最高指挥部的直接代表,他们将增强和提升所有超级驱逐舰船员的忠诚度。 +1236709379 DEMOCRACY PROTECTS 民主护佑 +2353206665 Democracy Space Station 民主空间站 +319758935 DEMOCRACY SPACE STATION 民主空间站 +3271301141 DEMOCRACY SPACE STATION 民主空间站(DSS) +1142717293 DEMOCRACY SPACE STATION 民主空间站 +295451118 Democracy Space Station construction is well underway. The local economy is flourishing as the planet’s populace has centupled, and all the Galaxy can feel their democratic fervor. 民主空间站(DSS)的建设进展顺利。随着该星球的人口增长,经济也飞速蓬勃发展起来,全星系都能感受到他们的民主热情。 +1229632110 DEMOCRACY TERMINAL 民主终端 +1477337926 DEMOCRACY'S LANDING 民主浅滩 +2098426918 Democratic Detonation 民主爆破 +3529979014 DEMOCRATIC DETONATION 民主爆破 +3630364424 Democratize 民主解放 +2189094418 DEMOCRATIZE THE VOID 民主解放寂域 +3021576226 DEMOLISH CYBORG ASSEMBLY UNIT 摧毁生化人的组装单元 +556037519 Demolition sequence initiated 拆除程序已启动 +1166279471 DENEB SECUNDUS 天津四次星 +954976452 Dense fog lightly reduces visibility for both enemy and friendly units. 浓雾会略微降低能见度,敌我双方都将受影响。 +3695557077 Dense fog reduces visibility. 浓雾会降低能见度。 +56725756 Dense sandstorms reduce mobility and greatly reduce visibility for both enemy and friendly units. 铺天盖地的沙暴会削弱行动能力并大幅降低能见度,敌我双方都将受影响。 +2645020198 Dense sandstorms reduce visibility. 铺天盖地的沙暴会降低能见度。 +2704077047 Dense, toxic fumes from deep within the planet's crust seep out of cracks in the earth and coat the ground in a sickly haze. 这颗星球地壳深处的有毒浓烟透过地表的裂隙渗透出来,形成了令人作呕的雾霾。 +4044104569 DENYING A BASE OF POWER 绝不让步 +3627786736 Depending on the war progress, different planets will be available. Select a planet to see what operations are active on it. 可参与行动的星球会随战争局势而变。选择一颗星球,看看上面正在部署哪些行动。 +878199200 DEPLETED 耗尽 +2294615330 DEPLETED 耗尽 +4183999382 DEPLETED 耗尽 +2229240372 DEPLOY 部署 +1865206544 DEPLOY DARK FLUID 部署暗液体 +2401299203 DEPLOY DARK FLUID 部署暗液体 +2912184878 DEPLOY DARK FLUID 部署暗液体 +1585667401 Deploy deep behind enemy lines. Certain missions will have severely limited Super Destroyer support. 深入敌后。部分任务将很难获得超级驱逐舰支援。 +2570186237 Deploy into the Exostorm and shatter the Exospires that sustain it. 部署至异界风暴内部,粉碎维持风暴运作的异界尖塔。 +2152357750 DEPLOY NUCLEAR PAYLOAD 部署核炸药 +793095850 DEPLOY SEISMIC PROBE 部署地震探测仪 +3540696519 DEPLOY SIGNAL PROBE 部署信号探测仪 +1914208299 DEPLOY THUMPER 部署地下发射器 +3441049493 Deploy to the Supercolony, call down the Dark Fluid Vessel, and insert it at each of the payload sites to help destroy the planet. 部署至超级拓殖地,呼叫暗液体容器,然后将其注入各投放点,准备摧毁该星球。 +2989497144 Deploy to the unknown Hive World and reclaim it in the name of Super Earth. 前往未知的虫窝世界部署行动,以超级地球之名收复要地。 +1272669911 Deployed Enemy Ship 已部署敌舰 +535359471 Deploying without ammo will force you to scavenge it during the mission. 如果部署时不携带弹药,你将被迫在任务期间设法搜集弹药。 +4282516705 Deployment magazine allocation will be temporarily increased, in order to expend excess inventory. 为消耗过剩库存,弹匣配额将暂时提高。 +3253166361 Deploys a defensive anti-personnel minefield, to halt enemy advance. 部署反步兵防御雷区,阻止敌人前进的脚步。 +790986208 Deploys a defensive incendiary minefield, which will set both terrain and targets alight when triggered. 部署一片燃烧式防御雷区,一旦触发便会点燃地面和目标。 +763226325 Deploys mines that release gas on activation, temporarily blinding and slowing most enemies. 部署地雷,触发后会释放毒气,可使大多数敌人暂时致盲并减速。 +306294023 Deploys periodic Eagle Airstrikes during missions. Slows enemy progress in Defense Campaigns. 在任务中部署周期性“飞鹰”空袭。减缓敌人在保卫战役中的进展。 +2067123077 Deposit any SSSD Hard Drives in receiving dock 将全部超级固态硬盘存放到接收码头 +1159214809 Deposit Tactical Video Camera in Hub container 将战术摄像机存入中继站储存箱 +4245339465 Depth of Field 景深 +2606029791 Descend upon Cyberstan and free it from the Cyborgs' oppressive grip once and for all. 降临生化斯坦,将这个星球从生化人的压迫统治中彻底解放出来。 +1623929778 Describes, Depicts Illegal Act 描述、描绘非法行为 +896373806 DESCRIPTION 描述 +2944943723 DESCRIPTION 描述 +877078639 DESCRIPTION 描述 +969542968 DESERT 沙漠 +875336036 DESERT CAMO 沙漠迷彩 +3224129712 DESERT STORMER 沙漠突击者 +4065003249 Designated planets must be under Super Earth control when order expires. 指令计时结束之时,指定星球必须收归超级地球管辖。 +2329877324 DESIGNATED TARGET COORDINATES: 指定目标坐标: +1689398047 Designed by fashion legend RH Gant, the pattern seen on this cape also appears on domestic dresses and gun-warmers. 由时尚传奇RH·甘特设计,披肩上的图案同时也用于家居服和暖枪套。 +1831885214 Designed in homage to the triangle—the most immovable of shapes—this cape digs its heels into the eye of the observer, leaving a lasting impression. 这款披肩的设计致敬了三角形这一最稳固的几何形状,以其坚定不移的姿态直击观者眼球,留下深刻印象。 +3876158673 Designed to render even the largest foes into considerably smaller, and vastly more compliant, constituent parts. Sacrifices throwing range for a massive detonation on impact. 旨在将体型最庞大的敌人拆解为体积小得多且远远更易“拿捏”的组成部件。以牺牲投掷距离为代价,换取命中时毁灭性爆炸威力。 +880394900 DESPOTIC EXPLOSIVE 专制炸药 +3030000168 Destroy 摧毁 +3092107522 Destroy #COUNT #OBJ#RACE_PRE#RACE#RACE_POST#MULTI. 摧毁#COUNT次#OBJ。#RACE_PRE#RACE#RACE_POST#MULTI +3921235308 Destroy MALFUNCTIONING HELLPODS for gear. 摧毁发生故障的绝地喷射舱,获得装备。 +3197109771 Destroy #COUNT Automaton AA turrets with the Eagle 利用“飞鹰”摧毁#COUNT台机器人的防空炮台 +2084035735 Destroy #COUNT Automaton Fabricators 摧毁#COUNT个机器人构筑者 +2351894543 Destroy #COUNT Automaton Gunship thrusters 摧毁#COUNT个机器人的炮舰推进器 +4107688522 Destroy #COUNT Automaton Warlords 摧毁#COUNT个机器人的军阀 +3825732283 Destroy #COUNT Bug Charger abdomens 击毁#COUNT只虫族强袭虫的腹部 +3530995197 Destroy Access Node 摧毁接入节点 +1648689263 DESTROY AIR BASE CONTROL TOWER 摧毁航空基地控制塔 +3107900985 Destroy all facility buildings 摧毁设施内的所有建筑 +1462909407 Destroy all Harvesters in the area. 摧毁区域内的所有猎杀器。 +477199191 Destroy all Illuminate Warp Ships in the vicinity 摧毁附近的所有光能者穿梭舰。 +1236304419 Destroy all the mutated Terminid eggs in this area. 摧毁该地区内所有的变异终结族虫卵。 +772113525 Destroy all Warp Gateways in the vicinity 摧毁附近的所有传送门 +604043691 Destroy ammunition stockpiles 摧毁库存弹药 +3436208849 Destroy Antenna transmitters 摧毁天线发射器 +814806505 Destroy Automaton Anti-Air Emplacements 摧毁机器人的防空炮台 +2245869430 DESTROY AUTOMATON COMMAND BUNKER 摧毁机器人指挥碉堡 +2406392610 Destroy Automaton Detector Tower 摧毁机器人探测塔 +910809576 Destroy Automaton Dropships 摧毁机器人运输舰 +240482645 DESTROY AUTOMATON FABRICATORS 摧毁机器人构筑者 +1638385704 Destroy Automaton infrastructure to cripple their troop production capabilities. 摧毁机器人的基础设施,削弱它们的军队生产能力。 +384655321 Destroy Automaton Mortar emplacements 摧毁机器人的迫击炮台 +2814427746 DESTROY AUTOMATON OUTPOST 摧毁机器人哨站 +2268441657 Destroy Automatons 摧毁机器人 +2322933964 Destroy Automatons 摧毁机器人 +1062726371 DESTROY BIO-PROCESSORS 摧毁生物处理器 +3057905493 DESTROY BIO-PROCESSORS 摧毁生物处理器 +3071807180 Destroy buildings within the Megafactory 摧毁超大型工厂内的建筑 +4080344030 Destroy Command Bunker 摧毁指挥碉堡 +2261840423 DESTROY COMMAND BUNKERS 摧毁指挥碉堡 +10771038 DESTROY COOLING TOWER 摧毁冷却塔 +32367396 DESTROY COUNTER-ORBITAL CANNON 摧毁反轨道加农炮 +3819125508 Destroy Dark Fluid cells to destabilize Core 摧毁暗液体电池,破坏核心的稳定性 +3711809192 DESTROY DROPSHIPS 摧毁运输舰 +1740363653 DESTROY EGGS 摧毁虫卵 +479966587 Destroy enemy deployment structures to secure the area 摧毁敌方部署建筑,保障该区域的安全 +809026135 DESTROY EXOSPIRE 摧毁异界尖塔 +1893894578 DESTROY FREIGHTERS 摧毁货轮 +45150644 DESTROY FUEL RESERVES 销毁燃料储备 +1574046645 Destroy fuel silos 摧毁燃料仓 +1175425361 DESTROY GAZER SPIRE 摧毁凝视者尖塔 +2585114060 DESTROY GAZER SPIRE 摧毁凝视者尖塔 +579011766 DESTROY HARD DRIVES 摧毁硬盘驱动器 +2769515979 DESTROY HARVESTER 摧毁猎杀器 +321401577 DESTROY HARVESTERS 摧毁猎杀器 +62823154 Destroy Illuminate Ships 摧毁光能者舰船 +2825582613 Destroy Illuminate Warp Gates 摧毁光能者传送门 +225478926 DESTROY ILLUMINATE WARP SHIPS 摧毁光能者穿梭舰 +2618333657 DESTROY ILLUMINATE WARP SHIPS 摧毁光能者穿梭舰 +3071613578 DESTROY INFESTED TOWER 摧毁侵染塔巢 +3127851830 DESTROY MONOLITH 摧毁巨石 +2252283152 Destroy mutated Terminid eggs 摧毁变异终结族虫卵 +2790627524 Destroy mutated Terminid eggs and deactivate the Termicide Dispersion Tower to prevent any further mutations. 摧毁变异终结族虫卵,关闭灭虫终结剂喷洒塔,预防终结族进一步变异。 +4051337572 DESTROY PROTOSPIRE 摧毁原始虫塔 +4070705890 DESTROY ROGUE RESEARCH STATION 摧毁叛变科研站 +877488575 Destroy Shrieker-infested towers to cleanse this district from its would-be parasites. 摧毁遍地尖啸虫的塔巢,清除此区域中潜藏的寄生虫。 +530098536 DESTROY SPORE LUNG 摧毁孢肺 +3998299206 DESTROY SPORE LUNG 摧毁孢肺 +2831246151 DESTROY SPORE SPEWER 摧毁孢子喷涌虫 +2098994313 Destroy Spore Spewers to allow our citizens to breathe Freely. 摧毁孢子喷涌虫,让我们的公民能够自由呼吸。 +3460953410 Destroy Stalker Lair 摧毁追踪虫巢穴 +3457299463 Destroy statues within the Megafactory 摧毁超大型工厂内的雕像 +3410939179 DESTROY STOCKPILED AMMUNITION 摧毁库存弹药 +3715490140 Destroy Stratagem Jammer 摧毁战略配备干扰装置 +2067205943 Destroy Terminid Spore Spewer 摧毁终结族孢子喷涌虫 +1834399666 Destroy the Automaton Super Weapon 摧毁机器人超级武器 +1404839977 Destroy the Automatons' Counter-Orbital Cannons in the area. 摧毁该区域内机器人的反轨道加农炮。 +359581454 Destroy the Bio-Processors 摧毁生物处理器 +897195810 Destroy the Bio-Processors that fuel synthesis of organic plasma, then extract. 摧毁为合成有机等离子提供动力的生物处理器,然后撤离。 +4057995659 Destroy the Cognitive Disruptor's power supply. 摧毁感知干扰器的能源。 +537651110 Destroy the convoy before it can reach its destination 在车队到达目的地之前将其摧毁 +2960516668 Destroy the Exospire to suppress the growing Exostorm. 摧毁异界尖塔,平息越发狂躁的异界风暴。 +2848580533 Destroy the Illuminate Monolith 摧毁光能者巨石 +1158613982 Destroy the Illuminate's Gazer Spires. 摧毁光能者凝视者尖塔。 +2994133320 Destroy the Illuminate's strange and unnatural spacecraft. 摧毁光能者古怪的飞行器。 +3140272276 Destroy the Megafactory's Counter-Orbital Cannons. 摧毁超大型工厂的反轨道加农炮。 +2070314061 Destroy the Shrieker Nest 摧毁尖啸虫巢穴 +4220528586 DESTROY TRANSMISSION NETWORK 摧毁传输网络 +68190456 DESTROY WARP GATEWAYS 摧毁传送门 +3664626057 destroyed a sample! 摧毁了一份样本! +185689788 Destroyed Fortress 已摧毁堡垒 +4283980414 Destroyed Heavy Automaton Outpost 已摧毁重型机器人哨站 +1595769879 Destroyed Light Automaton Outpost 已摧毁轻型机器人哨站 +2701252726 Destroyed Medium Automaton Outpost 已摧毁中型机器人哨站 +808943995 DESTROYER 驱逐舰 +3114715894 Destroyer has left orbit! 驱逐舰已离开轨道! +3587122524 DESTROYER HAS LEFT ORBIT! 驱逐舰已离开轨道! +3587566801 Destroyer Marker Visibility 驱逐舰标记可视度 +2367732828 Destroying OUTPOSTS gives XP and REQUISITION. 摧毁哨站可以获得经验值和申购点。 +1069719940 DETAILS 详情 +2745536240 DETECTOR TOWER 探测塔 +1653780249 Determines how non-linear mouse movement should be. If non-zero, the sensitivity ramps up with the speed of mouse movement. The higher the value, the more pronounced this acceleration is. 设定非线性鼠标移动的方式。如果不为零,鼠标灵敏度会随移动速度上升。数值越高,加速越明显。 +3348047729 Determines how voice chat transcription is used. Available options: +Off: No voice chat transcription +Incoming only: Transcribe incoming voice chat as text +Outgoing only: Outgoing voice chat is synthesized from text +Full: Combines both of the previous options 决定语音聊天转录的使用方式。可用选项: +关闭:不启用语音聊天转录 +仅输入:将输入设备的语音聊天转录为文字 +仅输出:根据文字合成语音聊天,从设备中输出 +完整功能:结合以上两个选项 +100464181 Determines how you want to navigate the map screen. + +Hybrid: Allows you to move and look around while the map is open. Additional controls are needed in order to navigate the map. +Separated: Allows you to only move while the map is open, relies on your look controls to navigate the map. 决定你浏览地图窗口的方式。 + +混合:可以在打开地图的同时移动和观察四周,需要使用其他按键拖动地图。 +独立:在打开地图的同时只能移动,需要通过视角的操控按键拖动地图。 +2999301584 Determines where the map is placed. 设定地图所在位置。 +1822256274 DETONATE 引爆 +815640498 Detonate #COUNT Automaton Lieutenant fuel tanks 引爆#COUNT个机器人中尉的燃料罐 +2501573715 Detonates in: 引爆倒计时: +876420910 Detonates on impact, covering the immediate vicinity in self-igniting white phosphorus. 受到撞击即引爆,以可自燃的白磷覆盖周边区域。 +3828601879 DEUTSCH DEUTSCH +1649987991 Devastator 蹂躏者 +2617880626 DEVASTATOR 蹂躏者 +102745890 DEVASTATOR SURGE 蹂躏者激增 +2444152049 Devastators 蹂躏者 +1790074216 Developed by the Ministry of Science while investigating the phenomenon known as The Gloom, this armor is non-permeable and squeak resistant. 科学部在调查“阴霾”现象时研制而成,该盔甲防渗透性佳,穿上后也不会吱吱作响。 +845259075 DEVELOPER DEVELOPER +3969632957 Diagram of the Noblest Payload 至高使命图谱 +2467782030 DIAGRAM OF THE NOBLEST PAYLOAD 至高使命图谱 +2236589644 Dialogue Volume 对话音量 +1081371423 Diamond 之钻 +1151272818 DIASPORA X 大流散X +1463595796 Did you know tips are shown during these transition sequences? 你知道传输途中会显示提示吗? +3092476376 Different Game Version 游戏版本不同 +2075723816 Difficult terrain inhibits your movement. Best practices recommend avoiding Snow, Mud, Water, Shrubberies, and Lava. For a complete list, see Manual Section D.198-2. 复杂地形会阻碍你移动。最好避开雪地、泥地、水面、灌木丛和岩浆。如需查看完整列表,请翻阅手册D部分198-2。 +540428555 Difficulty 难度 +146243799 DIFFICULTY 难度 +1395641588 DIFFICULTY 难度 +2489679843 DIFFICULTY 难度 +2466567737 Difficulty 1-3 难度1-3 +773754473 Difficulty 10+ 难度10+ +2467770863 DIFFICULTY 2 TRIAL 难度2级考验 +677301472 DIFFICULTY 3 TRIAL 难度3级考验 +128077582 DIFFICULTY 4 TRIAL 难度4级考验 +226122252 Difficulty 4-6 难度4-6 +2659045338 DIFFICULTY 5 TRIAL 难度5级考验 +469758995 DIFFICULTY 6 TRIAL 难度6级考验 +1114461454 DIFFICULTY 7 TRIAL 难度7级考验 +2567269547 Difficulty 7-9 难度7-9 +1725206083 DIFFICULTY 8 TRIAL 难度8级考验 +231640406 DIFFICULTY 9 TRIAL 难度9级考验 +4036526020 DIFFICULTY LEVEL LOCKED 难度未解锁 +1417539170 DIGITI 迪吉趾 +2241013697 Dignity of Toil 劳作的荣光 +1543354589 DIGNITY OF TOIL 劳作的荣光 +2407159642 Diligence 勤勉 +3001936292 DILIGENCE 勤勉 +3450368998 Diligence Counter Sniper 反狙击“勤勉” +2087547891 DILIGENCE COUNTER SNIPER 反狙击“勤勉” +4224650510 DILUVIA 迪卢维亚 +1954308553 DIPLOMACY 纵横市 +1790910171 Diplomatic Handshake 外交礼节式握手 +2073012404 DIPLOMATIC HANDSHAKE 外交礼节式握手 +3667223735 Directional Buttons 方向键 +3051489675 Directional Shield 定向护盾 +1141542311 DIRECTIONAL SHIELD 定向护盾 +2043720038 DirectX 11 DirectX 11 +584285034 DirectX 12 DirectX 12 +1098929518 DISABLE CROSSPLAY 关闭跨平台游玩 +598604235 Disable Stratagem Blocker 关闭战略配备屏蔽装置 +2059219268 DISABLED 禁用 +3833646123 DISABLED 禁用 +4057328297 DISABLING CRITICAL SYSTEMS... 正在关闭关键系统… +946808779 Disappeared Colony Transmissions Mention "Squids". 中断的拓殖地通讯内容提及“乌贼” +2904604187 Disarm #COUNT Automaton troops 解除#COUNT支机器人军队的武装 +292973657 Disarmingly scrappy and viciously disarming, this armor is a staple of the Balayage FW/2185 collection "Frontline Moxie". 这盔甲看起来破烂,令人放下戒心,实则凶悍得让敌人缴械投降。这套盔甲是巴拉雅奇2185秋冬系列“前线胆魄”的经典款式。 +2667112549 DISCARD 放弃 +3324913111 DISCARD 放弃 +411572063 DISCARD 废弃 +3046866243 discovered 已发现 +3287764042 DISCOVERY GLEN 探索谷 +248190710 DISCREET 简洁 +1195041927 Disgraceful Conduct 可耻行为 +826324111 Disintigration Beam 裂解激光 +163794480 Dismiss 忽略 +894092250 Dispatch 报告 +1478173313 Dispatches 快件 +3963330555 DISPATCHES 报告 +1751900625 DISPATCHES 报告 +425871568 DISPLAY 显示 +1958102909 Display Mode 显示模式 +694708951 Display of Brawn 肌肉展示 +3538001621 DISPLAY OF BRAWN 肌肉展示 +1808365568 Display On-Screen Keyboard 显示屏幕键盘 +3705024369 Display Surveys 显示调查 +404455679 DISRUPT EXOSPIRE CORE 破坏异界尖塔核心 +3951948862 DISRUPT ILLUMINATE 挫败光能者 +2666542614 Disrupt production of organic plasma and secure samples of the liquid for further analysis. 破坏有机等离子的生产过程,获取液体样本供进一步分析。 +1023125839 DISRUPT SHIELD GENERATOR 破坏防护罩生成装置 +1641002756 DISRUPT SOCIALIST INDUSTRY 破坏党同伐异的产业 +3274698570 Disrupt the Illuminate's opaque and sinister machinations in this region. 挫败光能者在该地区的阴谋诡计。 +3461446937 DISRUPT VOID 扰乱寂域 +174549967 Disrupting Gameplay 破坏游戏体验 +578055686 DISSIDENT 异见分子 +3279518460 Dissident Sabotage Blamed For Spike In Aluminum Prices 异见分子大搞破坏致使铝价飙升 +1030151088 Dissident's Nightmare 异见者梦魇 +2842503075 Dissident's Nightmare 异见者梦魇 +3350164383 DISSIDENT'S NIGHTMARE 异见者梦魇 +4029634219 DISSIDENT'S NIGHTMARE 异见者梦魇 +2187013933 DISTANCE #DISTm 距离#DIST米 +2733300016 DISTANCE TRAVELED: 行军距离: +436693484 Distor 迪斯特 +1212246835 Distribute Ballots 派发选票 +3848729746 DISTRIBUTE BALLOTS 派发选票 +4140937866 Distributor 派遣人 +2070138908 DIVE 闪躲 +2708952936 DIVEMASTER 潜兵长 +856177168 DIVEMASTER MAJOR 潜兵长少校 +4274042647 DIVER'S GLORY 潜兵荣光市 +3021705767 DIVER'S REST 潜兵安息市 +2269101269 Diving to the ground can be a life-saver, but it also makes you an easy target for melee units. 扑倒在地或许可以救命,但是也会让你变成近战单位的活靶子。 +2004112673 Divorced from it's tyrannical programming, the metal of this former Automaton is free once more. 摆脱了专制程序,用来构建这个机器人的金属材料重获自由。 +4020457783 DLSS DLSS +1289538445 Do you want to keep these display settings? 要保留这些显示设置吗? +3123505998 Do you want to leave this game? + +You will be returned to your own ship and bring the rest of the squad with you. 要离开游戏吗? + +你将与小队其他成员一同回到自己的飞船。 +2634961094 Do you want to leave this game? + +You will be returned to your own ship and leave the current squad. 要离开游戏吗? + +你将离开当前小队并回到自己的飞船。 +1394403183 Do you want to quit the game? 要退出游戏吗? +1114240328 Do you want to replay the tutorial mission? 要重新执行教程任务吗? +2944663995 Do you want to skip the rest of the credits? 要跳过余下的工作人员名单吗? +118371087 DOCUMENT EVIDENCE 录下证据 +2938726003 Dog Breath 腐息 +2499481182 DOG BREATH 腐息 +2698042019 DOGTOWN 多格镇 +2700797469 Doing your part 履行职责 +655668011 DOLPH 多尔夫 +1151136829 Domestic versions of this armor enable colonial farmers to plant crops and mines side by side, safely. 殖民地农民可以购买这套盔甲的家用版本,确保自己和同伴可以紧贴着彼此,安全地种植农作物以及布设地雷。 +3785289363 Dominator 主宰 +1315043333 DOMINATOR 主宰 +3041702219 Don't die! 别死! +3777116396 Don't drink and drive. 喝酒不开船。 +906876548 Don't forget to take breaks! +… +That is, if you want to be remembered as a coward. 注意休息! +… +前提是你想被当作懦夫的话。 +1025074152 Don't go it alone—join a squad in order to unleash maximum liberation! 不要孤军奋战——加入小队,助敌人实现最大限度的解放! +940932883 Don't panic. 不要惊慌失措。 +2565670278 Don't warn me again 不必再提醒我 +1204783583 Don't worry—stims have zero addictive properties!* +*Study paid for by Permacura. Permacura: put your life in our hands. 不必担心,治疗剂不具备成瘾性!* +*佩玛丘拉资助研究。佩玛丘拉:放心把生命托付给我们。 +1628309491 Don't worry, if you fail an objective, you will NOT be sent to a freedom camp. This is merely a dissident rumor. 不要担心,就算你没能完成目标,你也绝对不会被送入自由营。那只是异见分子散播的谣言。 +2344814250 DONATE 捐赠 +1838305738 Donate #GOAL #GEAR #GEARTYPE 捐赠 #GOAL #GEAR #GEARTYPE +857897876 DONATE RESOURCES 捐赠资源 +2094699857 DONATION ACCESS LICENSE 捐赠物资使用许可 +3749095091 DONATION LIMIT REACHED 已达到捐赠上限 +3993084197 DONATION SUCCESSFUL 捐赠成功 +3770249216 DONE 已完成 +3201091243 DOSTOINSTVO 尊严市 +2580626798 Double Freedom 双重自由 +3159679973 DOUBLE FREEDOM 双重自由 +641386113 Double Machinegun Pod 双机枪喷射舱 +1581878073 DOUBLE MACHINEGUN POD 双机枪喷射舱 +1552736152 Double Tap 连按两次 +839579798 DOUBLE TAP 连按两次 +1984410894 DOUBLE TAP 连按两次 +1253354406 Double-Edge Sickle 双刃镰刀 +3070433448 DOUBLE-EDGE SICKLE 双刃镰刀 +4255508129 DOUBLET II 双子裳II +3040595677 DOWN 下 +2193954572 Down Button 下方向键 +469874939 DOWNLINK FAILED 下链出错 +3163988537 Download failed. +Try again, or select a different language. 下载失败。 +再试一次,或选择其他语言。 +2330167315 Download starting 开始下载 +513800652 DOWNLOADING - PLEASE WAIT 正在下载,请稍候 +2606718182 DOWNLOADING LANGUAGE PACK 正在下载语言包 +1624189459 Downloading research data to SSSD 正在将研究数据下载到超级固态硬盘 +3543116688 DOWNPOUR 暴雨城 +2211494876 DP-00 Tactical DP-00“战术” +1038815510 DP-00 TACTICAL DP-00“战术” +2740153811 DP-11 Champion of the People DP-11“人民捍卫者” +3555499414 DP-11 CHAMPION OF THE PEOPLE DP-11“人民捍卫者” +3554596946 DP-40 Hero of the Federation DP-40“联邦英雄” +3495182510 DP-40 HERO OF THE FEDERATION DP-40“联邦英雄” +4002297555 DP-53 Savior of the Free DP-53“自由救星” +3838621097 DP-53 SAVIOR OF THE FREE DP-53“自由救星” +2036077300 DP-8 Mountain-Scaled DP-8“山峦鳞甲” +4124027049 DP-8 MOUNTAIN-SCALED DP-8“山峦鳞甲” +2976778669 DR. DISSIDENTS? 异见分子博士? +4230181125 Dr. Egon Sonntag 埃贡·松塔格博士 +3745821911 Dr. Freda Harber 弗雷达·哈珀博士 +471554595 Dr. Pauline Dupont 波林·杜邦博士 +2947173848 DRACO SECTOR 天龙座分区 +1378841226 Dragonroach 蟑龙 +2833794131 DRAGONROACH 蟑龙 +3443379122 Dragonroaches 蟑龙 +3580449947 DRAGONROACHES 蟑龙 +572577241 Drape of Glory 荣光加身 +1834175889 DRAPE OF GLORY 荣光加身 +3792296541 DRAUPNIR 德罗普尼尔 +3701264359 DRAUPNIR FREED +The Automaton presence on Draupnir is no more. Push the fight onward. 德罗普尼尔已解放 +机器人不再染指德罗普尼尔的大地。让我们再接再厉,继续战斗。 +838759940 DRAUPNIR LOST +The Automatons have taken Draupnir. A dark day for Managed Democracy. 德罗普尼尔沦陷 +机器人已然占领德罗普尼尔,这是管理式民主史上黑暗的一天。 +503016819 DRAUPNIR UNDER ATTACK +The Automatons are invading Draupnir. Rally to its defense! 德罗普尼尔遭到袭击 +机器人当前正在入侵德罗普尼尔,速速集结,前去保卫该星球! +332932069 Draw! 拔枪! +2487926915 DRAW! 拔枪! +4130011844 Dream 之梦 +2254050036 Drill into the Terminid Hive to analyze its composition. 钻入终结族虫窝分析其组成结构。 +856398682 Drill may disturb subterranean creatures 钻机可能惊扰地下生物 +926567821 Drill may disturb subterranean creatures 钻机可能惊扰地下生物 +3801054157 Drill may disturb subterranean creatures 钻机可能惊扰地下生物 +1342051317 Drill site nearby 附近有钻探点 +1248271221 Drill sites excavated 已挖掘的钻探点 +2665110557 Drill Status: Critically Damaged 钻机状态:严重受损 +1852142797 Drill Status: Damaged 钻机状态:受损 +836203038 Drill Status: Stable 钻机状态:稳定 +1476954631 Drilling Charge 强钻炸药 +716273285 DRILLING CHARGE 强钻炸药 +3665876496 Drilling in progress 正在钻探 +1895124532 DRILLING IN PROGRESS 正在钻探 +2257237107 Drilling in progress... 正在钻探…… +3315565588 DRIVE OF DEMOCRACY 民主渴望 +2538343677 Drive the Automatons off this planet. 将机器人逐出这颗星球。 +2290530748 DRIVE VEHICLE TO DROP-OFF LOCATION 驾驶载具到降落地点 +3664440821 DROP 放下 +468973119 Drop #ENTITY 投放#ENTITY +1615531301 DROP #ITEM 投放#ITEM +4108522692 DROP BACKPACK 放下背包 +1581760067 DROP CARRYABLE 放下携带的物品 +1350573823 DROP LOCATION 降落地点 +4150107695 DROP NEXT INVENTORY ITEM 放下下一件物品 +77991769 DROP OFF 放下 +2882782688 DROP SUPPORT WEAPON 放下支援武器 +3712568750 Drop Wheel Visibility 弃置轮盘可视度 +3702935526 DROPPED 掉落 +2119137213 Dropped #COUNT samples! 掉落#COUNT份样本! +3255616835 Dropped intel! 掉落情报! +549378744 Dropping in 正在降落 +159541688 Dropping In 正在降落 +1954755227 DROPPING IN 正在降落 +554367013 Dropship 运输舰 +401226617 DROPSHIP 运输舰 +3278860284 Dropships 运输舰 +1182663051 Drowning 淹溺 +3815579067 DrSpindleshanks 长腿博士 +740089886 Drum Magazine 弹鼓 +1283921753 Drum Magazine 弹鼓 +2144319744 DRUM MAGAZINE 弹鼓 +2153424507 DRUM MAGAZINE 弹鼓 +1144364846 DRYWELL 干井市 +2281091641 DS-10 Big Game Hunter DS-10“巨兽猎手” +392980386 DS-10 BIG GAME HUNTER DS-10“巨兽猎手” +2736926040 DS-191 Scorpion DS-191“天蝎” +1734352303 DS-191 SCORPION DS-191“天蝎” +3811816814 DS-42 Federation's Blade DS-42“联邦之刃” +2029003593 DS-42 FEDERATION'S BLADE DS-42“联邦之刃” +1297500110 DSS CONSTRUCTION SITE - PHASE 1 DSS建筑工地 - 第1阶段 +2464554102 DSS CONSTRUCTION SITE - PHASE 2 DSS建筑工地 - 第2阶段 +61811930 DSS CONSTRUCTION SITE - PHASE 3 DSS建筑工地 - 第3阶段 +901564350 DSS crews maintain deployment of a 24-hour rotating fleet of Eagle Fighters from the massive three-tiered Convocation Bay, supporting all Helldiver operations on the planet with close air support and halting enemy offensives for a short time. 民主空间站的工作人员在大型三层结构集结湾部署了一支“飞鹰”驾驶员舰队,采取24小时轮班制,为绝地潜兵在星球上的行动提供近距离空中支援,短暂阻止敌人进攻。 +2657511835 DSS LOGISTICS HUB DSS物流中心 +737834656 DSS Orbital Bombardment in #MINUTES:#SECONDS 民主空间站轨道轰炸来袭倒计时:#MINUTES:#SECONDS +2086016164 DSS Tactical Actions become activated when they have met their donation goals. 捐赠目标达成时,相应的DSS战术行动就会激活。 +2748316951 DUAL WIELD FIRE LEFT 双持武器左手开火 +1841648598 DUAL WIELD FIRE RIGHT 双持武器右手开火 +2845474638 Duckbill 鸭嘴枪口 +3079082519 DUCKBILL 鸭嘴枪口 +1331239448 Due to an unexpected pilot shortage, extraction times will be longer than normal for the near future. 由于驾驶员意外短缺,近期的撤离行动耗时较平时有所延长。 +2980070705 Due to the enhanced strength caused by this armor, caution is advised when using door handles or embracing colleagues. 此盔甲可强化穿戴者的力量,因此,建议穿戴时谨慎使用门把手或拥抱同僚。 +1360639492 Due to unmet Helldiver training quotas, personnel loss will need to be decreased for the short term. Therefore, Helldivers will deploy with increased stims until further notice. 由于绝地潜兵训练指标未能达成,短期内需要减少人员损失。因此,绝地潜兵将携带更多治疗剂奔赴战场,直至另行通知为止。 +2194044279 Due to Void interference, no data can be gathered about this planet. There is a high probability of its probable existence. 由于寂域的干扰,我们无法获取该星球的任何数据。但它存在的可能性极高。 +3630129367 DUMA TYR 杜马提尔 +2322307250 DUNOONIA 顿诺尼亚 +1009488447 DUPONT 杜邦 +1754091546 Durable, waterproof, and thermally-lined, surplus units of this cape are favored by domestic campers, to make tents. 耐用、防水,搭配保暖内衬,这款披肩的剩余布料也受到了国内露营爱好者的青睐,用于制作帐篷。 +366016090 DURGEN 德尔根 +572741022 During a mission deplete #REF 在一次任务中耗尽#REF +2181852495 Durney 德尼 +4189136961 Dust Devils 尘卷风 +2633081414 DUST DEVILS 尘卷风 +2761003916 DUST DEVILS 尘卷风 +423790984 Dust Devils Detected 侦测到尘卷风 +1417463969 DYER STREETS 染工街 +3248318589 DYN ALPHA 534-2 沙丘阿尔法534-2 +4115482888 DYNAMIC 动态 +2673484714 Dynamic Aim Mode 动态瞄准模式 +1632936857 Dynamic Resolution Scaling 动态分辨率缩放 +3943216787 DYNAMIC TRACKING 动态追踪 +3552683375 Dynamite 炸药 +2521535586 DYNAMITE 炸药 +2199603501 E 东 +4091600891 E 东 +3412659194 E (#COUNT°) 东#COUNT° +847733001 E-710 FARMS 710元素农场 +36035323 E-710 on Gloom-infested planets exhibits statistically-significant differences in various properties including density, viscosity, oxidation stability. + +Reactivate defunct E-710 pumps on this planet to gather the Gloom-infused liquid for further study. 受“阴霾”侵蚀的星球上的710元素在密度、黏度、氧化稳定性等多项属性上均呈现统计学意义的显著差异。 + +重新启动这颗星球上废弃的710元素泵机,收集被“阴霾”侵蚀的液体以供进一步研究使用。 +4009158833 E-710 OUTFLOW 710元素外流 +2412124646 E-710 RICH STRAIN 富含710元素的突变种 +2642562384 E-710-RICH SYSTEM 710元素富集星系 +3228101244 E-711 711元素 +81388574 E-711 ACQUISITION 获取711元素 +3022209575 E-711 EXTRACTED 已提取的711元素 +3848186075 E-711 EXTRACTION FACILITY 711元素开采设施 +2788352405 E-711 is only found on Hive Worlds. The exotic substance is critical to the maintenance of galactic security. It must be secured, no matter the risk. 711元素只能在虫窝世界里找到。这种异域物质对维持银河系的安全非常关键。无论风险多大,都必须确保拿到这些资源。 +4256548577 E-711 WELLSPRING 711元素之源 +3974048522 E/AT-12 E/AT-12 +2478278237 E/GL-21 E/GL-21 +2113722001 E/M-105 E/M-105 +2510193456 E/MG-101 E/MG-101 +1805609263 Each faction presents unique challenges. Mix up your gear and try new tactics! 不同阵营各有独特的挑战。混合使用装备,尝试新战术吧! +228403120 Each form and application that passes through the hallowed halls of AdminCen is emblazoned with the Stamp of Ages, and should be given a place of honor in the home. 行政中心神圣大厅经手的表格和申请均印有“时代印章”,应当摆放在家中显赫位置。 +3846326328 Each gilded detail is polished to perfection by re-educated dissidents, as part of the Lifelong Post-Infraction Atonement Program. 每一片镀金都由接受再教育的异见分子在终身违纪赎罪计划的监管下精心打磨至完美状态。 +2102410972 Each Order is tied to an enemy faction and a location in space, represented by an icon on the map. 每一项指派任务均针对太空某位置的某一敌方阵营,在地图上以图标标识。 +1200416238 Each Planet has a number Operations available. Complete Operations to reduce enemy presence and earn rewards. 每颗星球都设有一定数量的行动。完成行动即可削弱敌方势力,获得奖励。 +3303112030 Each purchase of this cape comes with a complimentary will and testament amendment form, which guarantees the soon-to-be-deceased a prominent spot on the Wall of Martyrs. 每次购买这件披肩都会附赠遗嘱更改表,确保即将牺牲的战士在烈士墙上占据显眼位置。 +1388196312 Each servo-assisted limb contains 138 miniature motors, to support a natural gait and long-term spinal health. 各伺服辅助肢体包含138个微型马达,以实现自然步态,从长远角度保障脊柱健康。 +3694006643 Each successful mission contributes more to planetary liberation. 每一次成功完成任务都会为行星解放事业带来更大的助力。 +3450039231 EAGLE 飞鹰 +677845368 Eagle 110mm Rocket Pods “飞鹰”110mm火箭巢 +814764658 EAGLE 110MM ROCKET PODS “飞鹰”110MM火箭巢 +2002849930 Eagle 110mm Rocket Pods stratagem availability has ended. 现已无法使用“‘飞鹰’110mm火箭巢”战略配备。 +2994328991 Eagle 500kg Bomb “飞鹰”500kg炸弹 +1057738842 EAGLE 500KG BOMB “飞鹰”500KG炸弹 +342717574 Eagle 500kg Bomb stratagem availability has ended. 现已无法使用“‘飞鹰’500kg炸弹”战略配备。 +391548033 Eagle Air-to-Air Missiles “飞鹰”空对空导弹 +618026027 EAGLE AIR-TO-AIR MISSILES “飞鹰”空对空导弹 +830957581 Eagle Air-to-Air Missiles stratagem availability has ended. 现已无法使用“‘飞鹰’空对空导弹”战略配备。 +1584817746 Eagle Airstrike “飞鹰”空袭 +1481032983 EAGLE AIRSTRIKE “飞鹰”空袭 +3023260311 Eagle Airstrike stratagem availability has ended. 现已无法使用“‘飞鹰’空袭”战略配备。 +3901855692 Eagle Cluster Bomb “飞鹰”集束炸弹 +662406178 EAGLE CLUSTER BOMB “飞鹰”集束炸弹 +1802585353 Eagle Fighter “飞鹰”驾驶员 +513886541 Eagle Gas Airstrike “飞鹰”毒气空袭 +1847228075 EAGLE GAS AIRSTRIKE “飞鹰”毒气空袭 +688156730 EAGLE GAS AIRSTRIKE “飞鹰”毒气空袭 +3263595633 Eagle Kills “飞鹰”击杀数 +1278805896 Eagle Napalm Airstrike “飞鹰”凝固汽油弹空袭 +1829446953 EAGLE NAPALM AIRSTRIKE “飞鹰”凝固汽油弹空袭 +323825976 Eagle Napalm Airstrike stratagem availability has ended. 现已无法使用“‘飞鹰’凝固汽油弹空袭”战略配备。 +2109771423 Eagle Rearm 重新武装“飞鹰” +2306949512 EAGLE REARM 重新武装“飞鹰” +3818832657 Eagle Rearm cooldown further reduced by #VALUE% if called in while Eagle uses still remain. 在“飞鹰”仍有使用次数时,如果呼叫“飞鹰”,重新武装的冷却时间缩短#VALUE%。 +2087441269 Eagle Smoke Strike “飞鹰”烟雾攻击 +4146936660 EAGLE SMOKE STRIKE “飞鹰”烟雾攻击 +1959642724 Eagle Storm “飞鹰”风暴 +3326001771 EAGLE STORM “飞鹰”风暴 +425147060 EAGLE STORM “飞鹰”风暴 +4089075400 EAGLE STORM “飞鹰”风暴 +862552343 Eagle Strafing Run “飞鹰”机枪扫射 +3407205415 EAGLE STRAFING RUN “飞鹰”机枪扫射 +1208798033 Eagle stratagems that drop multiple bombs will drop #VALUE additional bomb(s). 具备投掷多枚炸弹功能的“飞鹰”战略配备可额外投掷#VALUE枚炸弹。 +2536560300 Eagle Stratagems Used “飞鹰”战略配备使用次数 +2884734735 Eagle strikes fire at enemies. “飞鹰”空袭向敌人猛烈开火。 +272085636 EAGLE'S FURY 飞鹰之怒 +848889795 EAGLE'S FURY 飞鹰之怒 +1345534634 EAGLE'S LIKENESS 鹰姿市 +1036818377 EAGLECRY 鹰啸市 +1636563227 EAGLEMOUNT 鹰山 +1789137489 EAGLEOPOLIS 鹰都 +2573284916 Eagles are fast-response strike craft, with much shorter call-in times than Orbital fire support. “飞鹰”是快速反应攻击机,其呼叫时间显著短于轨道火力支援。 +1213486361 EAGLESTAR ETERNAL 鹰星恒市 +1079258265 EARN YOUR HELLDIVER CAPE 努力赢得绝地潜兵披肩 +839134119 EAST EMBANKMENT 东堤 +1846098026 EAST IRIDIUM TRADING BAY 东铱贸易湾 +1867905235 EAST REST 东栖市 +1331573605 EASTCLEFT 东裂谷 +1555761967 EASY 简单 +2006772999 EASY 简单 +3679744062 Eat This! 接招! +2381622963 EAT-17 EAT-17 +768384977 EAT-17 Expendable Anti-Tank stratagem availability has ended. 现已无法使用“EAT-17消耗性反坦克武器”战略配备。 +1032314023 EAT-411 EAT-411 +1925772933 EAT-700 EAT-700 +2435973138 Ecological Disaster or Economical Blessing? Space Tanker Crash 生态灾难还是经济机遇?太空运输船相撞 +3926941105 Edstrom 艾德斯特伦 +1404359855 EDWARD'S GRAVE 爱德华之墓 +3092724322 EFFECTIVE RANGE 有效射程 +4013599258 Effectiveness of #V_ONE increased by #V_TWO%. #V_ONE的效果提升#V_TWO%。 +1469579845 Effectiveness of #V_ONE is temporarily increased by #V_TWO%. #V_ONE的效果暂时提升#V_TWO%。 +187286726 EFFECTS 效果 +4021456882 EFFECTS 效果 +3697831596 EFFECTS [#COUNT] 效果[#COUNT] +2622646871 Efficient Fuel 高效燃料 +2242514025 EFFICIENT FUEL 高效燃料 +799057006 Efficient Reloading 高效装弹 +581433621 EFFICIENT RELOADING 高效装弹 +1211600962 EFFLUVIA 艾芙鲁维亚 +2707159010 Efforts to expand into the Gloom are underway. The Helldivers must support these efforts through data collection and resource extraction. 我们正在向“阴霾”区域扩张。绝地潜兵必须通过收集数据和开采资源提供支援。 +2279661008 EGON 埃贡 +3016206633 EIGHTRINGS 八环城 +2865718745 EJECT HARD DRIVE 弹出硬盘 +2216916513 Elapsed time on surface 行星地表历时 +3800006309 Elected Representative 选举代表 +2565771413 ELECTION ENDS IN: 选举结束倒计时: +2098644286 ELECTION STARTS IN: 选举开始倒计时: +3704017479 ELECTRA BAY 昴宿一湾 +1831948100 Electric Shock 电击 +2165457603 Electrical 电力 +1724458231 ELECTRICAL CONDUIT 电路导管 +4079506549 Electro-Whip 电鞭 +2287695974 Electrocution 触电 +4225679691 Electrocution 触电 +3942793355 Electronic Countermeasures 电子对抗 +4232658408 ELECTRONIC COUNTERMEASURES 电子对抗 +2745056259 Elevated Overseer 崇高监视者 +1012372721 ELEVATED OVERSEER 崇高监视者 +2764865372 Elevated Overseers 崇高监视者 +2266188637 Elggren 埃尔格伦 +3249246944 ELIGIBLE 天契 +513860111 Eliminate Annihilator Tank 消灭湮灭坦克 +2803832294 ELIMINATE ANNIHILATOR TANK 消灭湮灭坦克 +4286421936 ELIMINATE AUTOMATON FACTORY STRIDER 消灭机器人移动工厂 +1751374118 ELIMINATE AUTOMATON HULKS 消灭机器人巨型者 +411369073 Eliminate Bile Titan 消灭吐酸泰坦 +285652382 ELIMINATE BILE TITAN 消灭吐酸泰坦 +3357331302 ELIMINATE BILE TITANS 消灭吐酸泰坦 +962666211 Eliminate Brood Commander 消灭虫族指挥官 +2119525640 ELIMINATE BROOD COMMANDER 消灭虫族指挥官 +2468140080 ELIMINATE BROOD COMMANDERS 消灭虫族指挥官 +3058010335 Eliminate Charger 消灭强袭虫 +4215067358 ELIMINATE CHARGER 消灭强袭虫 +3132517406 ELIMINATE CHARGERS 消灭强袭虫 +613667684 ELIMINATE DEVASTATOR 消灭蹂躏者 +1409573597 Eliminate Devastators 消灭蹂躏者 +694756517 ELIMINATE DEVASTATORS 消灭蹂躏者 +3385979084 Eliminate Factory Strider 消灭移动工厂 +1139955559 ELIMINATE FACTORY STRIDER 消灭移动工厂 +2591985951 Eliminate Hulk 消灭巨型者 +1914950146 ELIMINATE HULK 消灭巨型者 +3358724507 Eliminate Impaler 消灭穿刺虫 +3302521801 ELIMINATE IMPALER 消灭穿刺虫 +3339054218 ELIMINATE OVERSEERS 消灭监视者 +3301571959 Eliminate Terminids underground 消灭地下的终结族 +1390962095 Eliminate Variant 消灭亚种 +3166041053 ELIMINATE VARIANT 消灭亚种 +4076457058 ELIMINATED 阵亡 +2475741675 ELIMINATED 覆灭 +730425751 ELYSIAN MEADOWS 埃律西昂草原 +183779452 Emancipator Exosuit “解放者”外骨骼装甲 +1544072428 EMANCIPATOR EXOSUIT “解放者”外骨骼装甲 +2947914529 Emblazoned with the red, white, and green of the 676th Democracy Regiment, who made their final stand on the slopes of Justice Hill. 饰有第676民主军团的标志性红、白、绿三色,纪念他们在正义山上的殊死一战。 +1091321045 EMBLEM OF FREEDOM 自由象征 +419411210 Embodies the ethos of Manifest Democracy—that it is our voter-given responsibility to emancipate the savage, un-Liberated galaxy. To rest only when every planet is safe, civilized, and Free. 这套盔甲彰显了天定民主的信条:解放蛮荒、未获解放的银河系是选民赋予我们的神圣职责。唯有确保每个星球安全、文明、自由,我们才能功成身退。 +3756969656 EMBOLD 无畏 +3963777507 EMERGENCY 紧急情况 +1200874512 EMERGENCY 紧急情况 +144546756 EMERGENCY EVACUATION 紧急撤离 +1015910248 EMERGENCY EVACUATION 紧急撤离 +1621984480 Emergency Holding Area Terminal System 应急等待区终端系统 +3803588969 EMERGENCY LIGHTS 应急照明 +1031846155 EMERIA 埃梅里亚 +444653002 EMORATH 艾莫拉斯 +1010919807 Emote 表情 +3728886375 Emote 表情 +605472064 EMOTE 表情 +2569232467 EMOTE 表情 +2855304298 EMOTE 表情 +908313274 EMOTE / VICTORY POSE 表情 / 胜利姿势 +972573159 EMOTE OPTION A 表情A +565717705 EMOTE OPTION B 表情B +3616008720 EMOTE OPTION C 表情C +3032626989 EMOTE OPTION D 表情D +2905043787 Emotes 表情 +1627376863 EMOTES 表情 +479462699 Emperor 君主 +2640264077 EMPTY SLOT 空槽 +3735593908 EMS Mortar Sentry 电磁冲击波迫击哨戒炮 +3600967890 EMS MORTAR SENTRY 电磁冲击波迫击哨戒炮 +1302574573 Enable account linking to get started. 启用账号绑定即可开始。 +3989450904 Enable High Dynamic Range (HDR) to your monitor or TV. This can only be enabled on supported devices. 在你的显示器或电视上启用高动态范围(HDR)。受支持的设备才能启用此设置。 +3699768441 ENABLE OIL EXTRACTION 设法采油 +2305462324 Enable Performance Monitor. The Discreet version will show framerate, memory and network statistics in the top left corner, ideal for general gameplay without distraction. While the Base, Graph and Advanced versions will show framerate statistics in the top right corner. 启用性能监视器。简洁版会在左上角显示帧率、内存和网络数据,适合常规游戏,能避免干扰体验。基础版、图表版和高级版则会在右上角显示帧率数据。 +2576340183 Enables a depth of field effect in certain camera views. Disabling depth of field will mean that all parts of the game are in focus at all times. 在特定视角中启用景深效果。禁用景深即表示游戏内的一切将始终呈现清晰对焦状态。 +2226079853 Enables an extensive logistics network to operate within the Gloom, negating adverse Gloom effects on surrounding planets. 促进庞大的后勤网络在“阴霾”内运作,彻底消除“阴霾”对周边行星的负面影响。 +2760012992 Enables an extensive logistics network to operate within the Gloom, negating adverse Gloom effects on surrounding planets. 促进庞大的后勤网络在“阴霾”内运作,彻底消除“阴霾”对周边行星的负面影响。 +271787985 Enables automatic climbing and vaulting while the Helldiver is sprinting. 在绝地潜兵冲刺时,开启自动攀爬或翻越的动作。 +517790385 Enables closed captions, which provides text descriptions of sounds other than dialogue. 启用隐藏式字幕,以文字形式描述对话以外的声音。 +1053958077 Enables melee attacks to remove larger obstacles, such as fences. 近战攻击可拆除更大型的障碍物,例如栅栏。 +3002170611 Enables motion sensor controls while using a controller. 使用控制器时启用动态感测器控制项。 +2757782052 Enables smoothing of mouse inputs. Can make tracking targets easier at the cost of responsiveness. 启用鼠标输入平滑化。有助于跟踪目标,但是会影响灵敏度。 +3461754799 Enables the user to jump higher than 'gravity' and 'safety' would normally allow. Must be charged before use. 可助力使用者跳得更高,无视日常“重力”和“安全规范”的束缚。使用前必须充能。 +1194641531 Enabling this setting approximates bounce lighting from nearby objects. Disabling may slightly improve GPU performance. 启用该设置可概略估算附近物体的反射光。禁用设置或许可以略微改善GPU性能。 +1059428164 Enabling this setting makes bright surfaces glow. 启用该设置可令明亮的表面发光。 +2696287710 Enabling this setting produces more realistic ambient lighting, making nearby surfaces occlude some of the light. 启用该设置可让附近的表面遮挡部分光线,从而产生更加逼真的环境阴影效果。 +1649901542 Enabling this setting produces more realistic shadows by calculating ambient lighting, touching surfaces and objects that are blocking the light. Disabling may slightly improve GPU performance. 启用该设置可计算环境光、接触面和遮光物体,从而产生更加逼真的阴影效果。禁用设置或许可以略微改善GPU性能。 +2714093614 Encloses the wearer in a spherical shield which blocks high-speed projectiles. 以球状护盾包裹佩戴者,抵挡高速射弹。 +1063209201 ENCYCLOPEDIA 百科全书 +435905688 Ends in: 结束倒计时: +2204300642 Ends in: 结束倒计时: +3892073518 ENE 东北偏东 +3076194191 ENE (#COUNT°) 东北偏东#COUNT° +1190000271 Enemies 敌人 +3257677184 Enemies Killed 击败敌人数 +713668384 Enemy 敌人 +1941807368 Enemy Anti-Aircraft 敌方防空范围 +3165219370 ENEMY BIO-PROCESSORS 敌方生物处理器 +102997286 Enemy Class 敌人等级 +2617693583 Enemy defenses have unexpectedly collapsed on Planet #V_ONE, allowing significant ground to be rapidly gained. #V_ONE星球上的敌方防线意外崩溃,我方得以快速占领重要阵地。 +2064403217 Enemy defenses in this area make prolonged Super Destroyer deployment impossible for certain missions. Be prepared to operate with severely limited Super Destroyer support. 该区域敌方防线坚挺,在部分任务中,超级驱逐舰无法长时间部署。请做好无法获得超级驱逐舰支援的准备。 +3922111694 ENEMY FORCE 敌方势力 +2340829721 Enemy forces are trying to claim this planet! Push them back by playing special missions during the specified time frame, or the planet will fall to the enemy. 敌军正试图占领这颗星球!在特定时间段内参与特别战事任务,全力击退敌军,否则这颗星球将落入敌军手里。 +1115518260 Enemy hostiles have located a reserve of classified defensive assets placed in long-term storage for city defense. To prevent the hard-fought cache from falling into the enemy's totalitarian grip, they must be rapidly evacuated off-world. + +Commencing evacuation will reveal your position to the invaders. Defend the site until transport is complete. 敌军已发现一批为城防长期储备的机密防御资产。为防止这批来之不易的储备物资落入敌人极权的掌控之中,必须迅速将其撤离至外太空。 + +启动撤离程序后,入侵者将知晓你的位置。保卫阵地,直至撤离完成。 +319369564 Enemy Indicator Visibility 敌人指示可视度 +4136569010 Enemy Kills 敌方击杀数 +2171714381 Enemy Patrols 敌方巡逻队 +1212122769 Enemy progress in Defense Campaigns is slowed. 敌人在保卫战役中的进展放缓。 +2443881283 Enemy Quantity 敌人数量 +1126925209 ENEMY RETREAT 敌军撤退 +865432226 Enemy ships deployed: #COUNT 已部署敌舰数:#COUNT +1659516311 Enemy ships in reserve: #COUNT 待部署敌舰数:#COUNT +2826211131 Enemy Strongholds 敌方要塞 +188945078 ENEMY SURGE 敌军激增 +2072040952 Enemy Tactical Objectives 敌方战术目标 +3224513262 ENEMY THREAT DETECTED 侦测发现敌方威胁 +689074879 ENEMY UNIT 敌方单位 +823255192 Enemy Wave Detected 侦测发现敌人来袭 +350720471 ENERGY-BASED 能量武器 +4024488009 ENGINEER 工兵 +1005827428 ENGINEERING 工程 +2939299459 ENGINEERING 工程 +31985882 Engineering Bay 工程港 +3098110291 ENGINEERING BAY 工程港 +2768293316 ENGINEERING BAY 工程港 +1160689016 ENGINEERING KIT 工程包 +1951270070 Engines 引擎 +1855354149 ENGLISH (UK) ENGLISH (UK) +2792367458 ENGLISH (US) ENGLISH (US) +64425627 Englund 恩隆德 +4278096162 ENHANCED COMBUSTION 强化燃烧 +677934738 ENHET FABRIK 一体成型厂 +1390337476 ENLIST TODAY 立即入伍 +965807449 ENLISTMENTS RATES SOAR 入伍率飙升 +4146739332 ENTER 进入 +485052284 Enter a HELLPOD to start the mission. 进入绝地喷射舱,开始任务。 +1645631779 Enter a REQUISITION TERMINAL and requisition more STRATAGEMS. 进入申购终端,申购更多战略配备。 +1664794115 Enter an ARMORY STATION and ADVANCE your current PROGRESSION TRACK. 进入军械库站点,推进当前的进度条。 +271220364 Enter any Stratagem Input to Start! 输入任意战略配备代码即可开始! +4192316357 Enter code to begin activation process 输入代码激活启动程序 +879895188 Enter combination to equip STRATAGEM, then throw the BEACON to activate. 输入密码,装备战略配备,然后投掷信标将其启动。 +2144846208 ENTER THE COLOSSEUM: AUTOMATON VS. BUG - WHO WILL WIN!? 走进角斗场:机器人对虫族,谁胜谁负!? +1094134469 Enter the GATER 进入GATER +3060882459 ENTER THE VOID 进入寂域 +507362504 Enter transport pod 进入运输舱 +649545523 ENTER TURRET 进入炮台 +1535789991 Enthusiastic Mirth 开怀大笑 +898848460 ENTHUSIASTIC MIRTH 开怀大笑 +1288283817 Entirely unforeseeable mutations from the Termicide led to hyper-accelerated bug growth on this planet, turning it into a Supercolony. It is corrupted beyond saving. The bugs infest every inch of it, down to the mantle, spawning trillions of spores every day. 灭虫终结剂引发毫无预警的突变,导致虫族极速繁殖,将这颗星球变为了超级拓殖地。星球已经腐化得无可救药,虫族侵染了上面的每一寸土地,连地幔也没有幸免于难,每天都繁殖出数万亿孢子。 +276016493 Entrenched Division 堑壕之师 +934470030 ENTRENCHED DIVISION 堑壕之师 +853109710 Entrenchment Tool 堑壕工具 +3348610193 Entrenchment Tool 堑壕工具 +994866672 ENTRENCHMENT TOOL 堑壕工具 +2383760178 ENTRY ##64 第64条 +3054022597 ENULIALE 安努力亚 +1236481912 Environment 环境 +576427373 EPH 埃夫市 +2108743119 Epoch 纪元 +3391732123 EPOCH 纪元 +2375431518 EPSILON PHOENCIS VI 艾普斯林芬赛斯VI +1777316190 EQUAL-OPPORTUNITY LIBERATION 平等、机遇、解放 +212236813 EQUALITY-ON-SEA 仰齐浜 +4166702756 Equip 装备 +1444368518 EQUIP 装备 +292157369 EQUIP 装备 +2628500700 Equip a booster to increase the chance of a successful liberation! Boosters apply to your entire squad. 装备强化资源,提升解放行动的成功率!强化资源对全队成员生效。 +4202681213 Equip stratagems to be able to drop into a mission! 装备战略配备后才能投身任务! +2853895662 EQUIPMENT 装备 +4245917889 EQUIPMENT 装备 +823091821 EQUIPMENT TESTING 装备试验 +2931881971 EQUIPMENT TESTING 装备试验 +3820781527 EQUIPMENT TESTING 装备试验 +670260102 EQUIPPED BY 已装备 +2233628595 Equipped with the latest computational systems, subsystems, and supersystems, this armor is worth the equivalent of a small Megacity. 这套盔甲配备最新的计算系统、子系统和超级系统,价值相当于一座小型特大城市。 +764869094 EQUIPPING 正在装备 +1731183300 Equips Hellpods to deploy smokescreens on impact, obscuring Helldiver deployment. 为绝地喷射舱配备烟雾弹,在撞击时释放烟幕,掩护绝地潜兵上场。 +390605646 ERADICATE AUTOMATON FORCES 彻底消灭机器人部队 +1899754973 ERADICATE AUTOMATON FORCES 彻底消灭机器人部队 +3301644944 ERADICATE BUG NEST 摧毁虫族巢穴 +1149721372 ERADICATE ILLUMINATE FORCES 彻底消灭光能者部队 +65635277 ERADICATE MUTATED NESTS 彻底摧毁变异巢穴 +877839842 Eradicate Terminid eggs 彻底清除终结族虫卵 +3662324321 ERADICATE TERMINID SWARM 彻底清除终结族虫群 +1239195132 Eradicate the Gloom-producing Spore Lung deep within the Hive. 消灭深藏在虫窝内孕育“阴霾”的孢肺。 +19075861 Eradicate the specified number of adult Terminids and pre-adult Terminids (sometimes called eggs). 消灭指定数量的终结族成虫和幼虫(又称“虫卵”)。 +1865115085 Eradicate the specified number of Terminids and Terminid nests. 消灭指定数量的终结族及其巢穴。 +2829404758 ERADICATE VOID BLOSSOMS 清除寂域之花 +3678132171 Eradicate Void Blossoms in the area 清除该区域的寂域之花 +1703292542 Eradicate Void blossoms to combat planetary mutation. 铲除寂域之花,阻止星球变异。 +3900407341 Eradicated Heavy Bug Nest 已摧毁重型巢穴 +1150782017 Eradicated Light Bug Nest 已摧毁轻型巢穴 +1497655096 Eradicated Medium Bug Nest 已摧毁中型巢穴 +396353427 Eradicated Mega Nest 已摧毁超巨巢穴 +96608276 ERASE TERRORIST MEMORIALS 推倒恐怖分子纪念碑 +3160372667 ERATA PRIME 艾拉特主星 +1101554849 ERATA PRIME DEFENDED +The bugs have been repelled from Erata Prime. Citizens across the planet hold celebrations in honor of the Helldivers' heroism. 成功保卫艾拉特主星 +我们已将虫族逐出艾拉特主星。全星球的公民一起举办了庆典活动,纪念绝地潜兵的英勇之举。 +3771369358 ERATA PRIME FREED +Erata Prime has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet. 艾拉特主星已解放 +艾拉特主星挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。 +969934403 ERATA PRIME LOST +The defense of Erata Prime has failed. Terminids now run amok on its surface. We cannot allow this corruption of Liberty to stand. 艾拉特主星沦陷 +艾拉特主星保卫战已宣告失败。终结族现在正四处肆虐。我们不能任由它们继续侵犯自由伟业。 +644078384 ERATA PRIME SECURED +The Terminid Control System is now fully activated on Erata Prime. 成功占领艾拉特主星 +终结族遏制体系已经在艾拉特主星全面启动。 +1091074192 ERATA PRIME UNDER ATTACK +Terminid spores fill the skies of Erata Prime. All Helldivers are called to the planet's defense! 艾拉特主星遭到袭击 +终结族孢子遍布艾拉特主星上空。呼唤全体绝地潜兵,前去保卫该星球! +2781604833 Ergonomic Drum 人体工学弹鼓 +2433552983 ERGONOMIC DRUM 人体工学弹鼓 +1317133593 ERGONOMICS 人体工学性能 +1169179398 ERIDANI 波江座 +1501649955 Eriksson 埃里克松 +2363299828 Eriksson 埃里克松 +4209107572 ERRANT 艾伦特 +3203990035 Error 错误 +1229826159 ERROR 错误 +3296993247 ERROR 错误 +2582672300 ERROR - MANUAL ALIGNMENT REQUIRED 错误,需要手动对齐 +4154982938 ERROR - TOWER MISALIGNED 错误,卫星塔方向偏离 +887842634 ERROR #ID 错误#ID +1578281421 ERROR: Communication Tower Offline 错误:通信塔离线 +872189308 ERROR: DISENGAGE ALL HATCH LOCKS 错误:请解除所有舱门锁 +2779601448 ERROR: MANUALLY ADJUST BLOCKED VALVES 错误:请手动调整受阻阀门 +3687135479 ERSATZ 厄萨茨 +2563213682 ERSON SANDS 厄尔森桑兹 +385177318 Eruptor 爆裂铳 +837106069 ERUPTOR 爆裂铳 +938483457 ESCAPADE 越矩市 +1375464804 Escort and protect researchers as they travel to the evacuation zone. 护送研究员安全转移至疏散区。 +4035563768 Escort and protect researchers as they travel to the evacuation zone. 护送研究员安全转移至疏散区。 +971650047 Escort Citizens safely to Shuttle Bay 护送公民安全前往运输船坞 +1065335399 Escort facility staff safely to Evacuation Shuttle 将设施人员护送至疏散运输船 +785938722 ESE 东南偏东 +384752805 ESE (#COUNT°) 东南偏东#COUNT° +3166068636 ESKER 艾斯克尔 +2166845819 ESPAÑOL ESPAÑOL +2398403810 ESPAÑOL (LATINOAMÉRICA) ESPAÑOL (LATINOAMÉRICA) +4268641564 ESTABLISH COMMUNICATION UPLINK 建立通信上行链路 +2621362674 Establish connection to SEAF network 与超级地球武装部队网络建立连接 +783509927 Establish connection to Super Destroyer to secure reinforcements 与超级驱逐舰建立连接,获得增援 +1842107720 ESTABLISHING CONNECTION 正在建立连接 +1441453914 ESTABLISHING LINK 建立连接 +606403742 Establishing link... 正在建立连接... +1843178656 ESTABLISHING NETWORK LINK 正在建立网络连接 +900985549 Establishing Up-link to Host Ship 正在建立上链以加入主办者舰船 +2576641352 ESTANU 伊斯塔努 +2986711822 ESTANU DEFENDED +Thanks to the selfless valor of the Helldivers, the citizens of Estanu are safe from the Terminid Menace. 成功保卫伊斯塔努 +在无私的绝地潜兵的英勇付出下,伊斯塔努的公民终于摆脱了终结族的威胁。 +2556439916 ESTANU FREED +Estanu is free at last from the bugs, thanks to your dauntless efforts. Press the fight onward. 伊斯塔努已解放 +在你们英勇无畏的努力下,伊斯塔努终于摆脱了虫族。再接再厉,继续战斗。 +2915613508 ESTANU LOST +The defense of Estanu has failed. Terminids now run amok on its surface. We cannot allow this corruption of Liberty to stand. 伊斯塔努沦陷 +伊斯塔努保卫战已宣告失败。终结族现在正四处肆虐。我们不能允许任由它们继续侵犯自由伟业。 +674244984 ESTANU UNDER ATTACK +Terminid spores fill the skies of Estanu. All Helldivers are called to the planet's defense! 伊斯塔努遭到袭击 +终结族孢子遍布伊斯塔努上空。呼唤全体绝地潜兵,前去保卫该星球! +4228756761 Estimated time until ready: #DAYS d #HOURS h 预计准备时间:#DAYS天#HOURS小时 +451896890 Estimated time until ready: #HOURS h #MINUTES m 预计准备时间:#HOURS时#MINUTES分 +1451918765 Estimated time until ready: #MINUTES m #SECONDS s 预计准备时间:#MINUTES分#SECONDS秒 +3091226237 ESTIMATED TO FALL IN 预计沦陷时间: +714297488 Estlind 埃斯特林德 +2197766385 Eternal Corona 永恒日冕 +447711244 ETERNAL CORONA 永恒日冕 +2543939 EUKORIA 欧科里亚 +2471860090 EUPHORIA III 欧福利亚III +1845692258 EVACUATE CITIZENS 疏散公民 +1344755793 Evacuate civilians trapped behind Automaton lines. 疏散被困在机器人战线后方的平民。 +3512798506 Evacuate civilians trapped deep within the Terminid swarm. 疏散被困在终结族虫群深处的平民。 +935493230 EVACUATE COLONISTS 撤离拓殖地居民 +3933708104 EVACUATE HIGH-VALUE ARTIFACTS 撤走高价值文物 +3724716379 EVACUATE HIGH-VALUE ASSETS 疏散高价值目标 +3780961573 EVACUATE HIGH-VALUE ASSETS 疏散高价值目标 +3042714175 EVACUATE PRIORITY CITIZENS 疏散优先级公民 +2357412450 Evacuate the area 撤离该区域 +3198058331 Evacuated in: 撤离倒计时: +945997508 EVACUATION PROTOCOL: ACTIVE 疏散协议:已启动 +2204289064 Evacuation shuttle en route 疏散运输船即将抵达 +3942753773 EVADING 躲避 +1285430105 Even among the most depraved of dissidents, the mere sight of this armor is enough to inspire a change of heart. 即使是最顽固的异见分子,只要看到这套盔甲,就会弃暗投明。 +3483144750 EVEN MORE ARC SPLITS 增加更多电弧分裂数 +2999110823 EVENT DETAILS 战事详情 +2479667651 EVERWHITE 恒白 +3236495379 EVERY AUTOMATON IS UTTERLY DESTROYED." 所有机器人才有可能实现和平。” +1355619713 Every citizen is equally important to the war effort, but Helldivers are the most important. 对于战争而言,每一位公民的贡献都是同样重要的,但是绝地潜兵最为重要。 +1675993123 Every member of the squad can view the Galactic War table, not just the host of the Super Destroyer. 除了超级驱逐舰的主办者,小队的所有成员都可以查看星系战争的议战桌。 +1850831891 Everything you need to know. + +The Ministry of Truth. 了解你需要知晓的一切。 + +真理部 +2600057462 Evoking legendary Helldiver Ronald Mambo on the eve of his untimely disappearance, the striking silhouette projects power, burliness, and strength. 极具冲击力的轮廓展现出力量、悍勇与威压,令人不禁想起意外失踪前夕的传奇绝地潜兵罗纳德·曼波。 +458093927 EVOLUTION PLATS 演化高地 +2357139039 Ew 好臭 +1027478568 EW 好臭 +72563834 EX-00 Prototype X EX-00“原型X” +3753841326 EX-00 PROTOTYPE X EX-00“原型X” +300356390 EX-03 Prototype 3 EX-03“原型 3” +3129812228 EX-03 PROTOTYPE 3 EX-03“原型 3” +1226988442 EX-16 Prototype 16 EX-16“原型 16” +3342293369 EX-16 PROTOTYPE 16 EX-16“原型 16” +3967877481 EXALT 颂扬市 +1235161681 Exalted Hero 伟人 +4214237080 EXALTED HERO 伟人 +1888907408 EXAMINE 观察 +567515731 Excellent quality! Resistent even against the most gross bug goo. 质量超棒!再恶心的毒虫黏液也不怕了。 +3461470611 Excessive Vulgar Language 言辞过分粗俗 +3817774454 EXCITEMENT 激情市 +3744612820 Execution By Black Hole Spaghettification Ruled Constitutional 最高法院判黑洞面条化死刑符合宪法 +4237708973 EXECUTIONER'S CANOPY 刽子手的披风 +135052481 Executor 执行者 +1960170670 EXEMPLARY SUBJECT 模范试验体 +1991475686 EXHAUST SYSTEM NORMAL 排气系统正常 +547309591 Exit 退出 +1321117487 EXIT 退出 +2552921329 EXO CITY 外骨骼市 +1302324884 Exo Experts 外骨骼装甲专家 +3611318386 EXO EXPERTS 外骨骼装甲专家 +622789768 EXO-45 EXO-45 +2780448514 EXO-49 EXO-49 +696072930 EXO-51 EXO-51 +1622020473 EXO-55 EXO-55 +3679110529 Exostorm fronts are coalescing into a dense system that threatens to engulf the entire planet. 异界风暴锋面正在汇聚,形成质密的风暴系统,恐将吞噬整颗星球。 +642439849 EXOSUIT 外骨骼装甲 +3035121456 EXOSUIT CERTIFIED 外骨骼装甲专家资格 +3502392366 EXOSUIT PATTERN 外骨骼装甲涂装 +2050925525 EXOSUIT RESERVES 外骨骼装甲储备 +99902273 Expanded Bomb Racks 扩展炸弹挂架 +3289686185 Expanded Bomb Racks 扩展炸弹挂架 +3389617937 EXPANDED BOMB RACKS 扩展炸弹挂架 +4126252271 EXPANDED BOMB RACKS 扩展炸弹挂架 +806358289 Expanded Heat Capacity 提升热容量 +2622115209 EXPANDED HEAT CAPACITY 提升热容量 +2017871176 EXPANDED WEAPONS BAY 武器舱扩容 +1603613106 EXPECTED PAYOUT 预期收益 +4104165606 EXPENDABLE 消耗品 +1885509695 Expendable Anti-Tank 消耗性反坦克武器 +2093520486 EXPENDABLE ANTI-TANK 消耗性反坦克武器 +3123874207 Expendable Napalm 消耗性凝固汽油弹 +4072880577 EXPENDABLE NAPALM 消耗性凝固汽油弹 +3143498604 Experience gain decrease no longer in effect. 经验值减少的效果结束。 +2346647635 Experience gain for all Helldivers increased by #V_ONE%. 所有绝地潜兵获得的经验值增加#V_ONE%。 +2415162749 Experience gain for all Helldivers is temporarily increased by #V_ONE%. 所有绝地潜兵获得的经验值暂时增加#V_ONE%。 +1274994819 Experience gain for all Helldivers is temporarily reduced by #V_ONE%. 所有绝地潜兵获得的经验值暂时减少#V_ONE%。 +3885662626 Experience gain for all Helldivers reduced by #V_ONE%. 所有绝地潜兵获得的经验值减少#V_ONE%。 +3963333572 Experience gain increase no longer in effect. 经验值增加的效果结束。 +3184460045 EXPERIMENTAL BOOSTER 实验性强化资源 +3486982023 EXPERIMENTAL HIP POUCHES 实验性腰包 +2314637855 Experimental Infusion 试验性注射剂 +11675250 EXPERIMENTAL INFUSION 试验性注射剂 +2133287516 EXPERIMENTAL INITIATIVE 实验性倡议 +3526613987 EXPERIMENTAL VITAMINS 实验性维他命 +375458016 EXPERIMENTATION PERIOD ENDED +The previous authorization period for global stratagem usage has ended. 试验周期结束 +上一项战略配备获准开放全体使用的周期已结束。 +2528127671 EXPERT EXTERMINATOR 顶级灭杀者 +2331531877 Expert Extraction Pilot 专业撤离飞行员 +2869061844 EXPERT EXTRACTION PILOT 专业撤离飞行员 +898859057 Explodes in: 爆炸倒计时: +4215953165 Exploding Crossbow 爆燃弩 +3021644467 EXPLODING CROSSBOW 爆燃弩 +222601610 EXPLODING SHRAPNEL 高爆弹片 +796263081 Exploration Vessel Claims to Have Detected Illuminate-like Energy Signature. 勘探船声称探测到类光能者能量标志 +2136737967 EXPLORE THE GLOOM 探索“阴霾” +3079655886 Explosion 爆炸 +1325312028 EXPLOSIVE 炸弹 +3306677318 EXPLOSIVE 炸弹 +3329277728 EXPLOSIVE 爆炸品 +1935681857 Explosive Barrel 爆炸桶 +1818238647 EXPLOSIVE BARREL 爆炸桶 +1184748485 Explosive Handshake 热烈握手 +3772792399 EXPLOSIVE HANDSHAKE 热烈握手 +832071150 Explosive Rounds 增加爆炸弹 +925783834 EXPLOSIVE ROUNDS 增加爆炸弹 +214921793 EXPLOSIVES SHORTAGE 爆炸品短缺 +2779744625 EXPLOSIVES SURPLUS 爆炸品过剩 +1816775090 Exposes Hellpod wiring upon surface contact, stunning any units in the vicinity of the drop site. 在绝地喷射舱落地时露出其电线,电晕空投地点附近的所有单位。 +2289976365 Extended Magazine 加长弹匣 +2416744569 EXTENDED MAGAZINE 加长弹匣 +2966433229 Extensive mining and drilling operations are taking place to comb this former Hive World for all traces of the highly valuable substance known as E-711. 目前大规模采矿与钻探作业正在进行,旨在从这个前虫窝世界的地方找到高价值物质711元素的踪迹。 +3000582339 Exterior 外部 +3810233876 Exterminate 消灭 +388131220 EXTERMINATE BUGS NEAR THUMPER 消灭桩锤附近的虫族敌人 +2392465944 EXTERMINATE TERMINIDS 消灭终结族 +2012089685 Extra Backpacks 额外补给 +3486048662 EXTRA BACKPACKS 额外补给 +1004228550 Extra Capacity 额外容量 +211201349 EXTRA CAPACITY 额外容量 +1722015081 EXTRA IS REQUIRED 尚需努力 +3547512313 EXTRA JUDICIAL 法外制裁 +2348117601 EXTRA LARGE 特大 +2171028531 Extra Magazine 额外弹匣 +3784183458 Extra Magazine 额外弹匣 +703727734 EXTRA MAGAZINE 额外弹匣 +996378365 EXTRA MAGAZINE 额外弹匣 +2114630443 Extra Magazines 额外弹匣 +3243312243 EXTRA MAGAZINES 额外弹匣 +4207037112 EXTRA PADDING 额外垫料 +2043037356 EXTRACT 撤离 +490276034 Extract after the timer reaches zero. 在倒计时归零后撤离。 +2032542246 EXTRACT ANOMALOUS MATERIAL 提取异常物质 +2973897446 EXTRACT ANOMALOUS MATERIAL 提取异常物质 +530005346 Extract as soon as possible. When the SUPER DESTROYER departs, you will no longer have access to STRATAGEMS. 尽快撤离。超级驱逐舰离开后,你将无法再使用战略配备。 +1461885605 EXTRACT E-711 提取711元素 +1979930256 EXTRACT E-711 提取711元素 +3508298212 Extract from a mission during nighttime. 夜间从任务中撤离。 +1596628873 Extract from a mission with at least #COUNT sample(s) 从一次任务中携带至少#COUNT份样本撤离 +2845482851 Extract from a successful #MTYPE#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST 成功从#MTYPE撤离。#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST +3110184672 Extract from a successful #MTYPE#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST 成功从#MTYPE撤离。#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST +158061641 EXTRACT INTEL 获取情报 +2506614173 EXTRACT INTEL 获取情报 +826568436 EXTRACT MYSTERIOUS SUBSTANCE 提取神秘物质 +1229741624 EXTRACT MYSTERIOUS SUBSTANCE 提取神秘物质 +2383887678 EXTRACT ORGANIC PLASMA 提取有机等离子 +1965810182 EXTRACT RESEARCH PROBE DATA 提取研究探测仪数据 +484612549 Extract samples of oil that has been exposed to the Gloom. 提取受“阴霾”污染的原油样本。 +3702651477 EXTRACT WITH #ENTITY 携带#ENTITY撤离 +2367885192 Extract with a full squad on a Hard difficulty or more mission. 在一项难度为“困难”或以上的任务中,与整支小队一起撤离。 +3546336164 Extract with a full squad on a Hard difficulty or more mission. 在一项难度为“困难”或以上的任务中,与整支小队一起撤离。 +552362711 Extract with at least 15 common samples. 携带至少15份普通样本撤离。 +854221043 Extract with at least 15 rare samples from a mission as a team. 在一项任务中整个团队携带至少15份稀有样本撤离。 +2742712394 Extract with at least 15 rare samples from a mission as a team. 在一项任务中整个团队携带至少15份稀有样本撤离。 +3791703638 Extract with Black Box 带黑匣子撤离 +4114284942 EXTRACT WITH FOOTAGE 带录像撤离 +3138429204 Extract with Intel Package 携带情报包裹撤离 +2628201221 Extract with SSSD 携带超级固态硬盘撤离 +2053347620 Extract with tactical video camera 携带战术摄像机撤离 +2691266839 Extract with the Specimens 携带样本撤离 +3143868727 Extractamundo! 完全撤离! +1071140672 Extractinating the Countryside 开采乡村 +1351068056 Extracting 正在撤离 +822640880 Extraction 撤离 +1527243143 EXTRACTION 撤离 +3488153744 EXTRACTION 撤离 +4264858903 EXTRACTION AVAILABLE 撤离飞船就位 +3820783881 Extraction available. 撤离飞船就位。 +1171875332 Extraction Beacon 撤离信标 +3109644149 EXTRACTION BEACON 撤离信标 +713672151 Extraction bonus: #AMOUNT M 撤离加分:#AMOUNT +2886553530 EXTRACTION COMPLETE 撤离完成 +2603119609 EXTRACTION FAILED 撤离失败 +2302497810 EXTRACTION FAILED 撤离失败 +2743765109 Extraction in T-#MINS:#SECS:#HUNDREDTHS 撤离倒计时 #MINS:#SECS:#HUNDREDTHS +1899061550 Extraction is now available! Head towards the EXTRACTION BEACON to end the mission. 现在可以撤离!前往撤离信标结束任务。 +908253568 EXTRACTION LANDED 撤离飞船着陆 +1692748917 Extraction Shuttle 撤离运输船 +2998417804 EXTRACTION SUCCESSFUL 撤离成功 +942502855 EXTRACTION TAKEOFF 撤离飞船起飞 +2116313662 Extraction takes #V_TWO additional seconds. 撤离所需时间延长#V_TWO秒。 +989037070 Extraction takes #V_TWO seconds less. 撤离所需时间缩短#V_TWO秒。 +1999107264 Extraction time increase no longer in effect. 撤离时间延长的效果结束。 +2962065378 Extraction time reduction no longer in effect. 撤离时间缩短的效果结束。 +3689672148 Extraction time temporarily decreased by #V_TWO seconds. 撤离时间暂时缩短#V_TWO秒。 +2093838115 Extraction time temporarily increased by #V_TWO seconds. 撤离时间暂时延长#V_TWO秒。 +1566020817 Extraction Timer Visibility 撤离计时器可视度 +1330773859 Extraction Zone 撤离区 +2402855993 EXTRACURRICULAR ACTIVITY 课外活动 +1911921093 EXTRASOLAR ASH EXOSUIT PATTERN 系外星尘外骨骼装甲涂装 +2250985674 EXTRASOLAR ASH HELLPOD PATTERN 系外星尘绝地喷射舱涂装 +861654386 EXTRASOLAR ASH SHUTTLE PATTERN 系外星尘运输船涂装 +4085949055 EXTRASOLAR ASH VEHICLE PATTERN 系外星尘载具涂装 +467439839 EXTREME 极端 +3531421471 Extreme Cold 极寒 +3842398028 EXTREME COLD 极寒 +3892609265 EXTREME TEMPERATURE EXTRACTION PLANT 极温开采厂 +2327521397 Eye 之眼 +3459911301 EYE OF FREEDOM 自由之眼 +419729660 EYE OF LIBERTY 解放之眼 +3291450179 Eye of the Clandestine 隐匿之眼 +285228234 EYE OF THE CLANDESTINE 隐匿之眼 +3794527478 Fabricator 构筑者 +1029235503 FABRICATOR 构筑者 +4159864532 Fabricators 构筑者 +3900259080 Facilitate our deepening understanding of the Gloom, so that it may be ultimately destroyed. 尽快加深我们对“阴霾”的了解,以便最终将其摧毁。 +1893695190 FACILITY OPERATION INACTIVE 设施无法操作 +615835611 Facility Operator 设施操作员 +4168973075 Faction 阵营 +2430987673 FACTION 阵营 +2757673367 FACTORY HUB 工厂枢纽 +2189342716 FACTORY HUB (DESTROYED) 工厂中心(遗址) +1153658728 Factory Strider 移动工厂 +1418245247 FACTORY STRIDER 移动工厂 +3073586861 Factory Striders 移动工厂 +4124075545 FAF-14 FAF-14 +645988482 FAF-14 Spear stratagem availability has ended. 现已无法使用“FAF-14飞矛”战略配备。 +1143206197 FAILED 失败 +747895489 Failed to accept friend request. 未能接受好友申请。 +4071798794 Failed to block player. 未能屏蔽玩家。 +3518351101 Failed to connect to server - Contact support if problem persists 未能连接至服务器 - 如果问题仍未解决,请联系客服。 +2159049877 Failed to create lobby - Contact support if problem persists 大厅创建失败 - 如果问题仍未解决,请联系客服。 +656010496 Failed to establish network connection. 无法建立网络连接。 +532930205 Failed to extract 撤离失败 +1653082617 FAILED TO FILE REPORT! +Try again later. 发送举报失败! +请稍后重试。 +3257682123 Failed to find player. 未能找到玩家。 +2456264573 Failed to get a profile from a Legacy Login token 无法从遗留登录令牌中获取资料 +743960993 Failed to get a Token for PlayStation™Network 无法获得PlayStation™Network令牌 +1195450813 Failed to join as target host is currently in a single-player session. 目标主办者当前设定为单人游戏模式,加入失败。 +2273839364 Failed to join as target host is running a different engine version. 加入失败,你与目标主办者的引擎版本不同。 +242067650 Failed to join as target host is running a different game version. 加入失败,你与目标主办者的游戏版本不同。 +1823187916 Failed to join as target host is running a different network config. 加入失败,你与目标主办者的网络配置不同。 +4183275107 Failed to join because the session is full. 游戏已满员,加入失败。 +2742417987 Failed to join because you have been banned from this session. 已被禁止加入本场游戏,加入失败。 +1193317824 Failed to join game lobby, Helldiver in training. 无法进入游戏大厅,绝地潜兵正在训练。 +3166457040 Failed to join game lobby, Public Key mismatch. 无法进入游戏大厅,公钥不匹配。 +1030782539 Failed to join game lobby, Timed out. 无法进入游戏大厅,已超时。 +2739471958 Failed to join game lobby. 无法进入游戏大厅。 +191529678 Failed to join lobby. The lobby host is not logged into PlayFab. 无法进入大厅。大厅主办者尚未登录至PlayFab。 +2609928291 Failed to join lobby. You're not logged into PlayFab; please restart the application. 无法进入大厅。你尚未登录至PlayFab,请重启应用。 +3575483736 Failed to login to PlayFab. Crossplay is disabled. 无法登录至PlayFab。已禁用跨平台游玩。 +3738628775 Failed to maintain session connection. 游戏连接无法维持。 +1062002957 Failed to remove friend request. 无法删除好友请求。 +3505156900 Failed to retrieve blocked players. 未能检索已屏蔽的玩家。 +1235302446 Failed to send friend request. 未能发送好友申请。 +1222573765 Failed to unblock player. 无法对玩家解除屏蔽。 +3523726710 Failed to unfriend player. 未能解除好友关系。 +4170570577 Failed to validate the Steam token provided by the client 无法验证客户端提供的Steam令牌 +506754096 FAILURE 失败 +136267076 FALLBACK 撤退 +3506624855 Fallen Helldivers will drop any held samples and weapons. Those items can be retrieved. 绝地潜兵持有的样本和武器会在阵亡时全部掉落。你可以取回这些掉落物品。 +2740589457 FALLEN HERO'S VENGEANCE 陨落英雄之崛起 +2794581015 Falling sand reduces visibility. 沙尘从天而降会降低能见度。 +173450602 FALSTAFF SECTOR 法尔斯塔夫分区 +2531617188 FAMEWOLF PEAK 盛狼峰 +4079449855 FAMILY GROVE 家林市 +3886945884 FAMILY-FRIEND 家宜 +3484929273 FamllyMan123 固家男人123 +1165263470 Fangs 尖牙 +2112393491 FARMHANDSTOWN 农工镇 +3257616781 FARSIGHT SECTOR 法尔赛特分区 +2124980752 FAST RECON VEHICLE 快速侦察载具 +2715008863 Faster Deploy Time 缩短部署用时 +2028832109 FASTER DEPLOY TIME 缩短部署用时 +4012632893 Faster Deployment 加快部署 +4260022829 Faster Deployment 加速部署 +1001350245 FASTER DEPLOYMENT 加快部署 +1675545584 FASTER DEPLOYMENT 加速部署 +493602973 FASTER EAGLE REARM 飞鹰时间加快 +1710418119 FASTER EAGLE REARM 飞鹰时间加快 +2241662875 FASTER EXTRACTION 撤离加快 +102495720 FASTER EXTRACTION 撤离加快 +2371571610 FASTER EXTRACTION 撤离加快 +3203613723 FASTER EXTRACTION 撤离加快 +3386335381 FASTER EXTRACTION 撤离加快 +23049047 Faster Lock-On Time 缩短锁定目标用时 +2064882427 Faster Lock-On Time 缩短锁定目标用时 +2778376027 Faster Lock-On Time 缩短锁定目标用时 +670342822 FASTER LOCK-ON TIME 缩短锁定目标用时 +2240834675 FASTER LOCK-ON TIME 缩短锁定目标用时 +3121913483 FASTER LOCK-ON TIME 缩短锁定目标用时 +2297326572 Faster Missiles 提升导弹速度 +517928278 FASTER MISSILES 提升导弹速度 +622084238 Faster Recharge 加速充能 +2826035585 FASTER RECHARGE 加速充能 +3738181443 FASTER RECHARGE 加速充能 +4165098055 Father 之父 +2077769934 Fault For Deadly Hoverboarding Accidents. 就悬浮滑板致死事故承担任何责任 +1908643927 FEARLESS HOLLOW 无畏谷 +4035440828 Features a patented non-stick coating, which makes scraping viscera off after a long day of battle less taxing. 采用专利不粘涂料,方便你在一整天的血战之后轻松去除表面的脏器。 +1809084930 Features a utility belt with pockets that can be filled with any number of things, such as pocket knives, mementos from home, and interesting rocks. 配有带口袋的实用腰带,可装入各式各样的物品,如便携刀具、家乡的纪念品和有意思的石头。 +2751547914 Featuring a high collar scientifically designed to deflect mud, blood, and indirect non-lethal projectiles, this pristine armor bestows the authority to overcome close-quarters combat through a time-honored tradition: the delegation—or court-martialing—of subordinates. 采用科学实用的高领设计,可弹开泥浆、血污以及间接袭来的非致命投射物。这套一尘不染的盔甲赋予使用者在应对近战时实践久经验证传统的权威:委派下属充当肉盾(亦或将其军法处置)。 +1247156468 Featuring a vibrant, high-visibility pattern to signify the inevitable victory of the Federation. This cape reminds all observers that while the road to Liberty is paved with sacrifice, the "podium" at the end is reserved exclusively for the compliant. 采用鲜艳的高可见度图案,预示联邦必定赢得胜利。它提醒所有观察者:通往自由的道路由牺牲铺就,但尽头的“领奖台”专属于顺民。 +1849283292 Featuring an ancient sun symbol and a distressed look, this cape reminds us that the light of Liberty is everlasting, and will keep shining even when we ourselves have become tattered and frayed. 这件破旧的披肩饰有古老的太阳符号,提醒我们自由之光永存不灭,即使我们自身变得残破不堪,它也将继续闪耀。 +2313965449 Featuring patented reverse-seam technology, to reduce the likelihood of bodily fluids entering the armor's interior. 运用专利反向缝合技术,减少体液进入盔甲内部的可能性。 +590455991 Feb 2月 +3009269514 February 2月 +3715890345 Federation's Embrace 联邦怀抱 +3385070843 FEDERATION'S EMBRACE 联邦怀抱 +2458412307 FEET FIRST 护腿为上 +3164522440 FENMIRE 范迈尔 +3480109512 FENRIR III 芬里尔III +584080031 FENRIR III DEFENDED +After countless noble and unavoidable sacrifices, Fenrir III has been defended from the Terminids. 成功保卫芬里尔III +无数不可避免的光荣牺牲终于换来回报,我们顺利从终结族手下守住了芬里尔III。 +2309008345 FENRIR III FREED +Fenrir III has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet. 芬里尔III已解放 +芬里尔III挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。 +2418889021 FENRIR III LOST +The defense of Fenrir III has failed. Terminids now infest its once-pristine surface. 芬里尔III沦陷 +芬里尔III保卫战已宣告失败。终结族现在令这块曾经的纯净乐土不得安宁。 +3917196346 FENRIR III SECURED +The Terminid Control System is now fully activated on Fenrir III. 成功占领芬里尔III +终结族遏制体系已经在芬里尔III全面启动。 +3794551534 FENRIR III UNDER ATTACK +The Terminids are attempting to spread to Fenrir III. All Helldivers are called upon to deploy immediately to the planet's defense. 芬里尔III遭到袭击 +终结族企图扩张至芬里尔III。呼唤全体绝地潜兵,立即前去保卫该星球。 +4016785230 FERRIS SECTOR 费里斯分区 +1102411714 FEWER STIMS 治疗剂减少 +152610670 FF13D460 FF13D460 +1738251304 FF666666 FF666666 +2302376615 FF6ED754 FF6ED754 +1102212871 FF71F5FF FF71F5FF +61738515 FF81ACFE FF81ACFE +2987249681 FFAA000A FFAA000A +703788843 FFB1B1B1 FFB1B1B1 +3129290227 FFC0BEB7 FFC0BEB7 +2189427535 FFE8E5CF FFE8E5CF +4046150128 FFF68AFF FFF68AFF +1473950258 FFFF4752 FFFF4752 +385050608 FFFF9D42 FFFF9D42 +1359740493 FFFFFF5E FFFFFF5E +1732452052 FFFFFFEE FFFFFFEE +3629407012 FIELD PROMOTIONS 战地晋升 +3097894519 Fighting Automatons 抗击机器人 +3224666645 Fighting Illuminate 抗击光能者 +619221101 Fighting Terminids 抗击终结族 +1016063151 File transfer in progress 文件正在输送 +486832087 FILIBUSTER 冗辩市 +3915620353 Fills cockpits with breathable liquid perfluorocarbons, which absorb g-forces and thereby enable pilots to conduct tighter turns without losing consciousness. 在驾驶舱内填充可呼吸的液态全氟化碳,以便吸收重力,使驾驶员能够完成更急促的转向且不会失去知觉。 +4022988243 Filter 筛选 +1614192878 Filter visible Missions based on difficulty. 根据难度筛选显示的任务。 +3714868912 FINAL CHARGE 力挽狂澜 +4195621337 FINAL TEST IN PROGRESS 正在进行终极考验 +3471972786 Find ammo shells and load into artillery gun 找到炮弹,将其装入大炮 +3911419457 Find and close any active Terminid holes 找寻并关闭所有活动的终结族虫穴 +3005923967 Find and collect SAMPLES! These resources are shared by the entire squad and are used to upgrade your Destroyer. 注意搜集样本!这是由整个小队共享的资源,可以用来升级驱逐舰。 +114038008 Find and destroy all Automaton Fabricators 找到并消灭所有机器人构筑者 +3842949158 Find and destroy all Terminid eggs. 找到并摧毁终结族的所有虫卵。 +988370961 Find and destroy any active Automaton fabricators 寻找并消灭所有运作中的机器人构筑者 +623056882 Find and destroy any active Automaton Gunship Fabricators 寻找并消灭所有运作中的机器人炮舰构筑者 +2598690750 Find and eliminate the Terminid Variant. 找到并消灭终结族亚种。 +3585387682 Find and eradicate all Impalers in the region. 找到并铲除该地区所有穿刺虫 +369469234 Find Annihilator Tank 找到湮灭坦克 +2595318786 Find Automaton Devastators 找到机器人蹂躏者 +2613524189 Find Automaton Hulk 找到机器人巨型者 +2147390723 Find Factory Strider 寻找移动工厂 +1345618657 Find Impaler 找到穿刺虫 +1705611194 Find mining sites identified by the Automatons and extract samples to assess their potential. 寻找机器人发现的采矿点,提取样本,评估开采潜力。 +3517608241 FIND ONGOING MISSIONS 查找进行中的任务 +919046200 Find probes sent into the Gloom and extract their research data. 找到发射至“阴霾”的探测仪,提取研究数据。 +477874659 Find target on grid 在网格内寻找目标 +3235089805 Find Terminid Bile Titan 找到终结族吐酸泰坦 +3815568685 Find Terminid Brood Commander 找到虫族指挥官 +2555575705 Find Terminid Charger 找到终结族强袭虫 +2646602779 Find the downed SEAF recon aircraft 找到被击落的超级地球武装部队侦察机 +3564642884 Find the hard disk containing the Launch Codes. 找到存有发射代码的硬盘。 +1551854132 Find the Illuminate altar 找到光能者祭坛 +120771889 Find the nursery chamber drill point 寻找繁育腔室的钻孔点位 +119095182 Find the objective location 确定目标的位置 +3185110553 Find Variant 找到亚种 +4178190608 Finger Guns 手指枪 +4229070637 FINGER GUNS 手指枪 +595420616 Fire 灼烧 +169770323 FIRE 开火 +1830121271 FIRE 开火 +2026353778 FIRE 开火 +3334734628 Fire #COUNT shots on a mission 在一次任务中射击#COUNT次 +3764215285 Fire a total of #COUNT shots 总计射击#COUNT次 +259641832 Fire Artillery 开炮 +3102562666 Fire Artillery Command 开炮指令 +2346618264 Fire at least 150 rounds in one burst, killing at least 10 enemies. 一次性连射至少150发弹药,击杀至少10名敌人。 +3436446815 Fire damage from Stratagems increased by #VALUE%. 战略配备造成的灼烧伤害提高#VALUE%。 +3035455512 FIRE LIMIT 开火限制 +3720826969 FIRE MODE 开火模式 +1583293011 FIRE MODES 开火模式 +3762066586 FIRE RATE 射速 +1710343855 Fire Rate Selection 可选射速 +2650929962 FIRE RATE SELECTION 可选射速 +467066459 FIRE SAFETY OFFICER 消防安全官 +2156827055 Fire Support 火力支援 +1420405460 Fire Tornado Warning 烈焰龙卷风警告 +565044815 FIRE TORNADOS 烈焰龙卷 +2425863048 Firebomb Hellpods 火焰炸弹绝地喷射舱 +2827171814 FIREBOMB HELLPODS 火焰炸弹绝地喷射舱 +4283102512 FIREFLY MEADOWS 萤火草原 +2289877133 Fires a ballistic dart at near-supersonic speeds, allowing the user to stim allies from a distance. Might sting. 以接近超音速的速度发射飞镖,可远程救治盟友。被射中时可能会感到刺痛。 +2694439458 Fires a rocket that detonates within proximity of a target, and deploys a cluster of explosive bomblets. 发射火箭弹,在目标附近引爆,并部署一组小型爆弹。 +2265676492 Fires a short-ranged superheated blast of thermal energy that melts the heaviest armor and thickest chitin into slag. + +Produced by ST Construction. 发射的短程超高温热能冲击,能够熔融最厚重的装甲和最厚实的甲壳。 + +由ST建筑公司生产。 +577591549 Fires concussive rounds that stagger enemies. Slower rate of fire than other SMGs. 可连续发射震荡弹击退敌人。射速比其他冲锋枪慢。 +2217090127 Fires in: 开火倒计时: +1332690519 Fires periodic Orbital Barrages during missions. Accelerates progress in Liberation Campaigns. 在任务期间定期发射轨道火力网。加快解放战役的进程。 +1598078647 Fires powerful exploding bolts which do maximum damage upon direct impact. Gravity must be accounted for when aiming. 发射威力强大的爆炸弩箭,对直接命中的目标造成最大伤害。瞄准时必须考虑重力因素。 +27642371 FIRING 开火 +985325178 Firing jet-propelled rounds, the Dominator trades fire rate and magazine capacity for increased damage per projectile. 发射喷气推进式子弹,这把“主宰”虽然牺牲了射速和弹匣容量属性,却提高了每颗弹丸的伤害。 +3213943293 Firing sequence initiated 发射程序已启动 +1166849866 FIRING SEQUENCE INITIATED 发射程序已启动 +3789879561 First deployed in the Helldivers "Diplomatic" Corps, this armor enables effective non-verbal interspecies communication. 这种盔甲最初投用于绝地潜兵的“外交”部队,非常适用于不同种族之间的非言语交流。 +260330276 First deployed in the mines of Cyberstan, where it offered protection against explosions in the hydrogen-rich caverns. 最初投用于生化斯坦的矿区,帮助穿戴者在富含氢气的矿洞中抵挡爆炸的伤害。 +2158812628 FIRST DIVEMASTER 一等潜兵长 +1322414042 Fist 之拳 +2728206271 Flag 旗帜 +4016667935 FLAG 旗帜 +3461580098 Flag raising 升起旗帜 +1420309294 FLAK 高射炮弹 +743787137 FLAM-40 FLAM-40 +1337083243 FLAM-40 Flamethrower stratagem availability has ended. 现已无法使用“FLAM-40火焰喷射器”战略配备。 +2276454876 FLAM-66 FLAM-66 +879990792 Flame 之火 +2006946784 Flame Sentry 火焰喷射哨戒炮 +2797269927 FLAME SENTRY 火焰喷射哨戒炮 +2037230707 Flames 喷射火焰 +4198878992 FLAMES 喷射火焰 +1986695707 Flames Mk2 喷射火焰 MK2 +897354808 FLAMES MK2 喷射火焰 MK2 +1941940848 Flamethrower 火焰喷射器 +3883099792 Flamethrower 火焰喷射器 +1006230745 FLAMETHROWER 火焰喷射器 +3821189171 FLAMETHROWER 火焰喷射器 +326268472 FLASH 闪光弹 +3679645005 Flash Hider 消焰器 +986973078 FLASH HIDER 消焰器 +3863626217 Flashield 闪光护盾 +1565796503 FLASHIELD 闪光护盾 +2071805061 Flashlight 照明 +4213395149 FLASHLIGHT 照明 +325506183 FLASHLIGHT 照明 +1115343924 FLASHLIGHT VERTICAL FOREGRIP 手电筒垂直前握把 +1884694869 FLECHETTES 飞镖弹 +3275461478 FLEDGE 雏羽 +3686957532 FLEET ADMIRAL 舰队上将 +2880434041 Fleshmob 肉瘤体 +4016445878 FLESHMOB 肉瘤体 +3211639846 Fleshmobs 肉瘤体 +1778656410 Flex 炫耀 +3791298298 FLEX 炫耀 +3944088470 Flexible Reinforcement Budget 灵活增援预算 +951033156 FLEXIBLE REINFORCEMENT BUDGET 灵活增援预算 +2869963044 FLOOD HYDROGEN PIPELINE 灌注氢气管道 +3506421665 Flowers 弗劳尔斯 +3655668821 Fly at least 25 meters from the shockwave of an explosion. 飞至距离爆炸冲击波至少25米远的位置。 +1224989586 FLY LIKE AN EAGLE 鹰击长空 +1588699686 Flying Gunships patrol the battlefield. 战场上有飞空炮舰巡逻。 +3271778464 Flying Leviathan warships patrol the battlefield. 战场上空有利维坦战舰在巡逻。 +3772486163 Flying Shrieker swarms traverse the battlefield. 飞空尖啸虫群会穿过战场。 +1167955701 Focused Prism 聚焦棱镜 +3679759601 FOCUSED PRISM 聚焦棱镜 +680227134 FOCUSED STRATEGY 重点战略 +368782679 FODDER GORGE 草料谷 +374686981 Foe Rent Asunder 敌分四裂 +4281184185 FOE RENT ASUNDER 敌分四裂 +1762386601 Foesmasher 歼敌战士 +2449160969 FOESMASHER 歼敌战士 +3223596516 Fog Generator 雾气生成器 +3592454457 FOLLOW ME 跟我走 +472469401 Following the Great York Conundrum, one City rose above the rest, pledging to hold its Hand over all other Yorks, so that no more blood be spilt between them. 约克大纷争结束后,一座城市力压群雄,誓要统御其他约克市,终结彼此间的流血纷争。 +1262031410 For budgetary reasons, Hellbombs require manual arming. But don't stick around unless you're looking for a spot on the wall of martyrs. 由于预算原因,地狱火炸弹需要手动瞄准。但是千万别愣在原地,除非你想在英烈墙上抢个位置。 +58344118 For more information on the Payment Services Act: https://pscom.jp/lgp - +992841245 For optimal performance, the manufacturer recommends avoiding immersing this armor in salt water for prolonged periods. 为维持盔甲的良好性能,制造者建议避免长时间将盔甲浸入咸水。 +2746702715 FOR SCIENCE! 为了科学! +3525879475 For the greater good! 顾全大局! +761453557 For the near future, an orbital strike will be automatically fired whenever a Helldiver is killed. 近期内,只要有绝地潜兵阵亡,就会自动触发一次轨道攻击。 +3420120836 For the near future, each successful mission will contribute more to planetary liberation. 近期内,每一次成功完成任务都将为行星解放事业带来更大的助力。 +150895216 For the near future, ground will be lost on Planet #V_ONE faster than before. 近期内,#V_ONE星球的阵地将以前所未有的速度沦陷。 +4192344096 For the near future, ground will be lost on Planet #V_ONE faster than before. 近期内,#V_ONE星球的阵地将以前所未有的速度沦陷。 +3469341397 For the near future, ground will be passively re-gained on Planet #V_ONE. 近期内,我们将被动夺回#V_ONE星球的阵地。 +3373568692 For warriors who are so strong and confident that they don't need any reassurance whatsoever. 为那些强大自信到不需要任何保证的战士而设计。 +1569895916 Force 之势 +1207031399 Force of Law 法律铁腕 +2039605284 FORCE OF LAW 法律铁腕 +227224155 Force the Cyborg Production Unit to self-destruct by disrupting its operations. 干扰生化人生产单元的运作,迫使其自毁。 +1372948410 FORCED DECOMMISSIONING 强制报废 +3018654574 FORCES IN RESERVE 预备部队 +4018146404 Forerunner 先驱 +2151041792 FOREST 森林 +1572767304 FOREST 森林 +1473136080 FOREST CAMO 森林迷彩 +2540993890 FOREST PLANET 森林星球 +1074223869 Forged for those watchful protectors who silently guide all Helldivers, asking no recognition whatsoever, besides a simple custom-made suit of armor only they get to wear. 为默默引导所有绝地潜兵的保护者打造,除了简单的专属定制盔甲以外,他们不求得到任何形式的认可。 +916548545 FORI PRIME 佛里主星 +1057866065 FORKLIFT 叉车 +2114321379 FORMER SUPER EARTH COLONY 前超级地球拓殖地 +1748948844 FORNSKOGUR II 福恩斯科古尔II +816167364 FORT BOUNTY 邦蒂堡 +1243225162 FORT JUSTICE 正义堡 +205278761 FORT SANCTUARY 庇护堡 +2348954771 FORT SANGUINE 血色堡 +1181947803 FORT UNION 联合堡 +4113916443 FORTIFICATION 防御工事 +2063895312 Fortification Class 防御工事等级 +1288868496 Fortification Quantity 防御工事数量 +4176618764 FORTIFIED 强化 +1696061154 FORTITUDE 毅城 +4294494078 Fortress 堡垒 +172092461 Fortress Destroyed 堡垒成功摧毁 +2177972845 Founding Father 缔造者 +955678540 FOUNDRY 铸造城 +3389070063 FOUR CROWNS 四冠市 +503725801 FRACTURED 骨折 +1048514854 FRACTURED PLANET 碎裂星球 +1914879563 Frag 破片弹 +3795763272 FRAG 破片手雷 +4226697606 FRAG 破片弹 +574108092 FRAKENEERIA 弗兰科尼亚 +4085443570 Frame buffering 帧缓冲 +2135567438 Framerate Limit 帧率限制 +2922736954 Framerate targeted by Dynamic Resolution Scaling. 动态分辨率缩放调整达到的帧率。 +2896746273 FRANÇAIS FRANÇAIS +1479757392 Frandsen 弗兰德森 +3969578797 Fraser 弗雷泽 +330336451 Fre Liberam 求自由 +681509815 FRE LIBERAM 求自由 +2188537574 FREDA 弗雷达 +1374694211 FREE APARTMENTS 自由公寓 +507275113 FREE COLONY 解放拓殖地 +622010981 FREE OF THOUGHT 思想自由 +3270977612 FREE THE CITY 解放城市 +1709622101 Free this land from Illuminate occupation. 把这片土地从光能者的占领中解放出来。 +3392016075 FREE TRADE 自贸区 +1913688337 Free trapped citizens and escort them to evacuation. 释放受困公民,护送他们前往撤离点。 +1436046545 Free trapped colonists and escort them to safe evacuation. 释放受困的拓殖地居民,护送他们前往安全的撤离点。 +3506896603 Free-Spirited Spangles 自由之魂的辉映 +419364955 FREE-SPIRITED SPANGLES 自由之魂的辉映 +1217738475 FREECREST 自由峰 +555398973 FREEDOM ETERNAL 永恒自由城 +953216843 Freedom isn't free, but this lets you dispense it with glee! 自由不是免费的,但是花在这上面感觉很值! +73196956 FREEDOM PEAK 弗里敦峰 +215973074 Freedom's Flame 自由烈焰 +4243457500 FREEDOM'S FLAME 自由烈焰 +341101903 FREEDOM'S TAPESTRY 自由织锦 +1588080609 FREEDOM'S TAPESTRY 自由织锦 +1731739124 FREEDOM'S TORCH 自由火炬城 +983707629 Freedomball Star Rex Stribling Scores Mega-Goal in Twelfth Consecutive Game. 自由球明星雷克斯·斯特里布林连续12场比赛打进超远大力球 +2954428361 FREQUENCY ALIGNMENT 校准频率 +3979430036 Frequent earthquakes stun players and enemies alike. 频繁的地震会让玩家和敌人都陷入眩晕。 +2989814560 FRESH ORCHARDS 鲜果园 +1589472377 Fresh SEAF recruits filled with patriotic fervor for the destruction of the Automatons have surged to take significant ground on Durgen. 满腔爱国热情、誓要摧毁机器人的超级地球武装部队新进后备军已经在德尔根占领了重要阵地。 +811589761 Fresh SEAF recruits filled with patriotic fervor for the destruction of the Automatons have surged to take significant ground on Maia. 满腔爱国热情、誓要摧毁机器人的超级地球武装部队新进后备军已经在昴宿四占领了重要阵地。 +2540796782 Frezzato 弗雷扎托 +1456023688 Friend 弗兰德 +3020221101 FRIEND REQUESTS 好友申请 +3668162822 FRIENDLY FIRE DAMAGE: 友军误伤造成伤害: +1534328088 Friendly Fire isn't. 友军误伤不算作友好行为。 +3402364570 Friendly Kills 友方击杀数 +4276996798 Friends 好友 +3838049405 FRIENDS 好友 +973323483 Friends Active 活跃好友 +4293783563 FRIENDS ON PLAYSTATION® PlayStation®的朋友 +1932726510 FRIENDS ONLY 仅限好友 +3756643203 Fritzell 弗里策尔 +4044021234 Frob 弗洛伯 +2459288933 from from +1416498899 from any 星球势力: +1968949865 from any 星球势力: +68016543 From the graceful typography to the elegant use of space, this sign is a masterwork of patriotic craftsmanship. 排版优雅、留白高明,这个标牌堪称爱国主义艺术品的杰作。 +663690807 from the planet 星球: +1007359996 from the planet 星球: +913822991 From this terminal you can acquire new stratagems and upgrade your destroyer. +You can use this terminal to manage your Destroyer regardless of which vessel you are currently on. 通过此终端可以获取新战略配备并升级你的驱逐舰。 +无论身处哪艘舰船,你都可以使用此终端管理自己的驱逐舰。 +3523034434 Front-leaning rest position 俯卧撑姿势 +2681683717 FRONT-LEANING REST POSITION 俯卧撑姿势 +2509277034 FRONTERIA 边陲 +3143719551 FROSTOWN 霜镇 +3070458044 FS-05 Marksman FS-05“神射手” +2232103875 FS-05 MARKSMAN FS-05“神射手” +2902624853 FS-11 Executioner FS-11“行刑者” +3058249690 FS-11 EXECUTIONER FS-11“行刑者” +1379640417 FS-23 Battle Master FS-23“战斗大师” +506680647 FS-23 BATTLE MASTER FS-23“战斗大师” +4267611838 FS-34 Exterminator FS-34“灭绝者” +3097522254 FS-34 EXTERMINATOR FS-34“灭绝者” +2721885102 FS-37 Ravager FS-37“破坏者” +1623263170 FS-37 RAVAGER FS-37“破坏者” +4037789759 FS-38 Eradicator FS-38“根除者” +2696078557 FS-38 ERADICATOR FS-38“根除者” +1789418574 FS-40 Diplomat FS-40“外交官” +982417537 FS-40 DIPLOMAT FS-40“外交官” +941001616 FS-55 Devastator FS-55“蹂躏者” +3229667878 FS-55 DEVASTATOR FS-55“蹂躏者” +1892629368 FS-61 Dreadnought FS-61“无畏” +4104147901 FS-61 DREADNOUGHT FS-61“无畏” +2181332236 FSR FSR +670224387 FSR3 FSR3 +4048162659 FSR4 FSR4 +1401129762 Fuel 燃料 +1485000503 FUEL OUTPUT 燃料输出点 +1248557823 Fuel transfer in progress 燃料正在输送 +1319122806 Fuel transport shuttle incoming 燃料运输船即将抵达 +2229511592 FUELING 正在补充燃料 +3983103464 FUELING MISSILE - PLEASE WAIT 正在为导弹添加燃料,请稍候 +786618189 FUELING STATION 燃料站 +2738367032 FULL 已满 +1000362679 FULL 显示所有文字 +1223137345 Full Choke 全喉缩 +4151399226 FULL CHOKE 全喉缩 +2239744702 Full Mobilization Declared; "Super Earth is at War," says President. 全面动员正式开始,总统宣布“超级地球进入战争状态” +2611509743 Fullscreen 全屏 +421687485 Fully operational 火力全开 +1892204483 Further expands Eagle weapons bay by removing unnecessary systems such as fire suppression, ejection, and airbags. 通过移除火力抑制、弹射和安全气囊等不必要的系统,进一步扩大“飞鹰”的武器舱。 +276558649 Further reduces recoil when crouching or prone by #BONUS. 蹲伏或匍匐姿态下,后坐力进一步降低#BONUS。 +2700729919 FURY 费里 +3991282791 FUSE 1 熔断器1 +1673923679 FUSE 2 熔断器2 +3427455294 FUSE 3 熔断器3 +3336821542 FUSE 4 熔断器4 +948824005 FUSE 5 熔断器5 +2929425348 FUSE TIME 引信时间 +280534572 FUSION BATTERY 聚变电池 +2623456461 FUTURE PRIDE 未来荣光市 +2767962404 FUTURIA 未来城 +2185476602 FX-12 FX-12 +2115369190 Fyrvall 菲尔瓦尔 +3094883930 G-10 G-10 +20882451 G-109 G-109 +988887129 G-11 G-11 +2828026946 G-12 G-12 +4022943105 G-123 G-123 +2145965381 G-13 G-13 +3319614808 G-142 G-142 +812349149 G-16 G-16 +1500243627 G-23 G-23 +952990996 G-3 G-3 +1159406071 G-31 G-31 +3391746330 G-4 G-4 +745002750 G-48 G-48 +3823682595 G-50 G-50 +3546044726 G-6 G-6 +2564983548 G-7 G-7 +256705610 G-8 G-8 +2782065547 G-89 G-89 +104444267 G/40-K G/40-K +1706307746 G/SH-39 G/SH-39 +3955894400 GACRUX 十字架一 +3949569347 GAELLIVARE 耶利瓦勒 +2744478874 GALACTIC COMMANDER 星系指挥官 +3342657883 GALACTIC FRINGE 星系边缘 +1012438182 GALACTIC WAR 星系战争 +2378352781 GALACTIC WAR 星系战争 +3591951736 GALACTIC WAR 星系战争 +1899091879 GALACTIC WAR CONNECTION ERROR 星系战争连接出错 +2604396474 GALACTIC WAR UPDATE 星系战争更新 +3262004107 GALACTIC WAR UPDATE +Operation Swift Disassembly continues as planned. The Automatons are in retreat. Press the advantage. Their final resistance will no doubt be fierce, as their anti-annihilation subprotocols activate. Show them no quarter. Remember the fallen. Remember the Creek. And remember that they are unequivocally non-sentient, so all acts of violence are wholly justified. 星系战争战况更新 +急速拆解行动如期进行中。机器人正在撤退,宜乘胜追击。它们最后无疑将负隅顽抗,启动反覆灭次级协议。绝不能对它们手软。铭记陨落的同袍。记住麦拉芬蒙河。别忘了它们毫无感知能力,因此施以任何形式的暴击都是理所当然。 +3451871948 GALACTIC WAR UPDATE +Operation Swift Disassembly faces fierce resistance. Clearly, the Automatons' anti-annihilation subprotocols have activated, as they calculate the inevitability of their doom. Redouble your efforts. Press the assault. Show them no mercy. Remember the fallen. Remember the Creek. And remember that they are unequivocally non-sentient, so all acts of violence are wholly justified. 星系战争战况更新 +急速拆解行动如期面临激烈的反噬。机器人显然已启动反覆灭次级协议,因为它们已经测算出厄运无可避免。诸君须加倍努力,压制顽抗,毫不留情。铭记阵亡的同袍。记住麦拉芬蒙河。别忘了它们毫无感知能力,因此施以任何形式的暴击都是理所当然。 +382907229 GALAXY IN CELEBRATION 全星系欢庆 +2773787987 GALAXY IN MOURNING 全星系哀悼 +1714459044 Gallant 英勇无畏 +1297446258 GALLANT 英勇无畏 +2596970518 Gallantry Beyond Measure 无上英雄 +2466054614 GALLUX SECTOR 加卢克斯分区 +3631657838 GAME 游戏 +3641216836 Game Data is used as explained in our Privacy Policy (www.playstation.com/legal/privacy-policy). + +This includes use of Game Data to: +• Provide you with our games. +• Understand the usage and performance of the game you are playing, and to develop improvements to the game. +• Develop new products and services. +• Detect, investigate, and minimise malicious, unauthorised or fraudulent behaviour. +• Audit, compliance and legal purposes (for example, making or defending claims or activities that are required to comply with a law). 我们将按隐私政策(www.playstation.com/legal/privacy-policy)的规定使用游戏数据。 + +游戏数据的用途包括: +• 为你提供游戏服务。 +• 了解你正在玩的游戏的使用情况和性能,并改良游戏体验。 +• 开发新产品和服务。 +• 检测和调查恶意、未经授权或欺诈的行为,并将这些情况的出现次数降至最低。 +• 审计、合规和法律用途(如提出索赔或为索赔辩护,或为遵守法律规定开展活动)。 +3747118819 Game found, preparing to travel... 发现游戏,准备前往… +200750720 GAME OVER 游戏结束 +146773140 Game session is no longer available. 本场游戏已无法加入。 +1538527214 Game version mismatch, please update your game 游戏版本不匹配,请更新游戏 +963586007 GAMEPLAY 游戏 +265392480 GAR HAREN 轧尔哈伦 +2213492101 GARAGE DUNE 车库沙丘 +2494963809 Gas 毒气榴弹 +3985944090 GAS 毒气榴弹 +974448089 Gas Mines 毒气地雷 +3892287098 GAS MINES 毒气地雷 +1683917631 Gas Mortar Sentry 瓦斯迫击哨戒炮 +2478785269 GAS MORTAR SENTRY 瓦斯迫击哨戒炮 +1870840792 Gatekeeper 御门者 +3757148964 GATEKEEPER 御门者 +2443576485 Gatekeepers 御门者 +959258356 Gather nearby assets and place them in the container 收集附近的资源,放进容器里 +600460786 Gatling Sentry 加特林哨戒炮 +1140023383 GATLING SENTRY 加特林哨戒炮 +1594223240 Gatling Sentry stratagem availability has ended. 现已无法使用“加特林哨戒炮”战略配备。 +2773451630 GATRIA 盖尔崔亚 +797922986 Gauntlet 钢铁手 +1661895142 Gazer 凝视者 +168895875 GAZER 凝视者 +2888074667 Gazers 凝视者 +362988027 Gear 装备 +1585767515 GEAR: #GEAR 装备:#GEAR +855413042 GELLERT SECTOR 盖勒特分区 +260743810 GEM LICKET 晶蚀 +1947642856 GEM LICKET 晶蚀 +546585509 GEMMA 贯索四 +428323897 GEMSTELLE GENERATOR 晶星动力 +2675157762 GEMSTONE BLUFFS 宝石崖 +1327299148 GENE 基因市 +2293727885 General 其他 +2372990033 GENERAL 其他 +3886371824 GENERAL 将军 +3678299227 General Brasch 布拉施将军 +669593876 GENERATE 显示 +603021238 GENERATING DARK ENERGY 正在生成暗物质 +2586492531 GENERATION 源代 +657852966 Generator calibrating 发电机正在校准 +4240780626 GENERATOR CONTROL UNIT 发电机控制单元 +3002077388 GENERATORSVILLE 电机维尔 +2537631 GENESIS PRIME 创世主星 +3933634258 Geneticist Killed In Home By Chicken-Cow-Pig Hybrid. 基因研究人员家中惨遭鸡牛猪杂交生物杀害 +4010359064 Geneticists Create First Chicken-Cow-Pig Hybrid, Dubbed "Perfect Meat." 基因研究人员成功培育首个鸡牛猪杂交生物,冠名”完美肉” +2776790245 Gently stonewashed by experienced hands, this luxury cape exudes the essence of state-approved attitude. 由资深工匠精心水洗做旧,这款奢华披肩散发着经国家认证的气质精髓。 +4164999888 Geological grid map scale 1:100 地质网格地图比例尺 1:100 +3343657947 Get #COUNT kills in 10 seconds 10秒内完成#COUNT次击杀 +3517150810 Get #COUNT kills within 5 seconds of each other 完成#COUNT次击杀,每次击杀间隔时间为5秒 +834385422 Get 10 kills with a single #REF #COUNT times 仅使用#REF一次击杀10名敌人#COUNT次 +1881588906 Get 4 kills with a single #REF #COUNT times 仅使用#REF一次击杀4名敌人#COUNT次 +2854932487 GET READY 准备 +1841056965 Get some! 受死吧! +1989859950 Getting Kicked 被踢出 +1502999680 GETTING SERVERS 正在获取服务器 +2634940767 Ghoul 噬光者 +104744128 GHOUL 噬光者 +171693015 Ghouls 噬光者 +2108628906 Giant 巨人 +1698977452 Giant Pandas Officially Extinct; Giant Panda-Bot ETF Value Skyrockets 大熊猫正式灭绝,机器大熊猫交易所交易基金净值飙升 +2177206078 Gifted to Helldivers whose civilian lives were distinguished by exemplary citizenship, patriotism, and service to the Federation. 授予具有爱国、效忠联邦等优秀品质、为平民竖立楷模的模范公民绝地潜兵。 +938882557 Giga Grenade 千兆级榴弹 +2365825441 GIGA GRENADE 千兆级榴弹 +1155728923 Gilded Quill 镀金羽毛笔 +865901582 GILDED QUILL 镀金羽毛笔 +1287745099 GILE 吉尔 +2347772106 GIRD 戈尔德 +2373092333 GIRI 义理城 +3566112445 Give Health Pack 给出生命包 +1785498444 Give Refill 提供补给 +2635006751 Give Supplies 给出物资 +154851721 Gives access to the Orbital 380mm HE Barrage stratagem during missions. Accelerates progress in Liberation Campaigns. 执行任务时可使用轨道380mm高爆弹火力网战略配备。加快解放战役的进程。 +2848920507 Gives Helldivers a #VALUE chance to retrieve twice the samples on sample pickup. 绝地潜兵有#VALUE的几率可在拾取样本时获得双倍样本。 +4177020126 Gives wearer a #BONUS chance to avoid grievous limb injury. 佩戴者有#BONUS的几率避免四肢重伤。 +2801916509 GL-21 GL-21 +647945653 GL-28 GL-28 +4272980910 GL-52 GL-52 +3983592335 GL-6 Grenade Launcher stratagem availability has ended. 现已无法使用“GL-6榴弹发射器”战略配备。 +3515520839 GLARBLE GARB GORK! News Headline Writer Experiences 叽里呱啦噜!光能者入侵新闻头条写手大脑 +488991355 GLOBAL 全局应用 +4256285820 GLOBULUS 球布勒斯 +565140087 GLOOM BASE ALPHA “阴霾”阿尔法基地 +280230815 GLOOM BASE BRAVO “阴霾”布拉沃基地 +2635225528 GLOOM OUTPOST BRAVO “阴霾”布拉沃哨站 +3552972191 Gloom particles interfere with landing Pelicans, increasing extraction times by 20 seconds. “阴霾”粒子干扰“鹈鹕”运输机着陆,撤离时间延长20秒。 +3771554627 GLOOM RESEARCH EXPEDITION “阴霾”研究考察 +3610215261 GLOOM RESEARCH FACILITIES “阴霾”现象研究设施 +3013802117 GLOOM RESEARCH PROGRESS “阴霾”研究进展 +435602687 GLOOM SOURCE “阴霾”源头 +2349442677 Gloom spores suffuse the planet's atmosphere from the ground to the exosphere. Scattered LiDAR towers can be used to measure the density and composition of Gloom spores. + +Activate the towers, download their data, and transmit it off-planet using the local relay station. 从地面到外逸层,“阴霾”孢子充斥着整个星球的大气层。各地的激光雷达塔可以测量“阴霾”孢子的密度和构成。 + +启动激光塔并下载数据,利用当地中继站将数据传输至星球外。 +3209764160 Gloom-infested planets appear to have more extensive hive patterns than normal. + +Deploy Seismic Probes to collect scans of their tunnel networks, then use a local relay station to upload the data to a Ministry of Science hub. 在受“阴霾”侵蚀的星球上,虫窝的散布范围似乎比普通星球更广泛。 + +部署地震探测仪,收集隧道网络的扫描数据,再利用当地中继站将数据上传至科学部中心。 +1616173269 Glorious Sacrifice 光荣牺牲 +1007294856 Glorious Victory 辉煌胜利 +1121505756 GO TO LINK 前往绑定 +860089702 GO TO LOADOUT 前往武装配置界面 +3057669681 Go to the Armory to view your inventory. 前往军械库查看物品。 +375424051 Go to the DESTROYER BRIDGE and use the WAR TABLE to START A MISSION 前往驱逐舰舰桥,使用议战桌开始任务。 +1375569625 Go to the Ship Management Terminal to acquire new Stratagems and upgrade your Destroyer. 前往舰船管理终端获取新的战略配备,以及升级驱逐舰。 +3773823713 Go to the Shipmaster and hand in your Orders. 去找舰长提交指派任务。 +3678230171 Golf_Dad22 高尔夫_大爹22 +466703045 Gonçalves 贡萨尔维斯 +3328163412 Gone in 360 seconds! 致命360秒! +781923061 Good for medium to long range and the maximum magnification normally used for general weapons. 常规武器常用的最高倍率瞄准镜,适合中远程打击。 +4059362100 Good for stealth. Bad for enemy. 潜行好助手。敌人的噩梦。 +732058021 GOTHENBURG III 哥德堡III +2449050769 GOTHMAR SECTOR 戈特玛分区 +939109424 GP-20 GP-20 +2753361628 GP-31 GP-31 +2149027812 GR-8 GR-8 +465571203 GRACIOUS LIBERTY 仁慈自由市 +1706936029 GRAFMERE 格拉夫米尔 +956015116 GRAFSART 爵心市 +3690945823 GRAFSEAD 爵首市 +1567949647 GRAFSWALLIT 爵囊市 +2985681234 GRAND ERRANT 大艾伦特 +2503399842 Granted to the Truth Enforcers' Informant of the Month, this tasteful cape conjures images of dissident blood on asphalt. 这件品味非凡的披肩属于真理执行者的“月度最佳告密者”,令人联想到沥青路面上异见分子的鲜血。 +1087564350 Grants subscription to data stream of live weather conditions, allowing for increased accuracy in orbital targeting. 可订阅实时天气状况的数据流,提高轨道目标定位的准确性。 +3961242203 GRAPESHOT 葡萄弹市 +2994423178 GRAPH 图表 +2770522832 GRAPHICS 图像 +3873285110 Graphics API 图形API +1411535136 Graphics Device 图形设备 +1860834368 Graphics Preset 图像预设 +208239710 GRASSLAND 草原 +1588759936 GRASSLAND PLANET 草原星球 +1653030344 GRAVITAS 庄严市 +3564151658 GRAVITATIONAL ANCHOR 引力锚点 +79192892 GRAVITATIONAL ANOMALY DETECTED 侦测到引力异常 +2271311985 GRAVITATIONAL COLLAPSE CONFIRMED 侦测到引力坍缩 +1035721014 GREAT EXPEDITIONARY FLEET YARD 远征舰队港 +4120346389 Great for camping trips with the kids! A bit heavy for them though. 很适合跟孩子野营的时候用!虽然对他们来说稍微有点重了。 +1057301920 GREAT HIVES 大虫窝 +3371210796 Greatcloak of Rebar Resolve 钢筋意志大氅 +524662546 GREATCLOAK OF REBAR RESOLVE 钢筋意志大氅 +1169888429 GREATER ATLANTEAN POWER PLANT 大亚特兰蒂斯电厂 +3743479119 GREATER INVESTMENT 巨资市 +2855966001 GREATER STOROUSE 大储仓 +3536341782 GREATWOOD MILLS 巨木米尔斯 +361417381 GREENHOUSE - TYPE 203 温室 - 203型 +1050804124 GRENADE 榴弹 +3838465527 GRENADE BANDOLIERS 榴弹背带 +2087852427 Grenade capacity decrease no longer in effect. 榴弹容量减少的效果结束。 +3732635510 Grenade capacity for all Helldivers decreased by #V_ONE. 所有绝地潜兵的榴弹容量减少#V_ONE。 +1466494124 Grenade capacity for all Helldivers increased by #V_ONE. 所有绝地潜兵的榴弹容量增加#V_ONE。 +3517848091 Grenade capacity for all Helldivers is temporarily decreased by #V_ONE. 所有绝地潜兵的榴弹容量暂时减少#V_ONE。 +430447578 Grenade capacity for all Helldivers is temporarily increased by #V_ONE. 所有绝地潜兵的榴弹容量暂时增加#V_ONE。 +352192220 Grenade capacity increase no longer in effect. 榴弹容量增加的效果结束。 +3798161962 Grenade decrease no longer in effect. 榴弹数量减少的效果结束。 +3113572060 Grenade increase no longer in effect. 榴弹数量增加的效果结束。 +1103679752 Grenade Kills 榴弹击杀数 +449613082 Grenade Launcher 榴弹发射器 +1035420766 GRENADE LAUNCHER 榴弹发射器 +2178309836 Grenade Pistol 榴弹手枪 +3118947918 GRENADE PISTOL 榴弹手枪 +3257328072 GRENADE POUCH SHORTAGE 榴弹袋短缺 +209720307 GRENADE STATS 榴弹数据 +2194832245 Grenades 榴弹 +2584923622 GRENADES 榴弹 +3625143144 Grenadier Battlement 掷弹兵防卫墙 +1044194585 GRENADIER BATTLEMENT 掷弹兵防卫墙 +552388957 Grotesque Monoliths now pepper this city, boldly empowering the Illuminate through unknown means. Their inscrutability is an affront to Liberty. They must be destroyed. 丑陋不堪的巨石遍布城区,堂而皇之地以未知方式赋予光能者力量。它们的不可捉摸是对自由的公然亵渎。必须摧毁巨石。 +3023900891 GROUND ALL-TERRAIN EXTRACTION RIG 地面全地形采集钻机 +2350760417 Ground is being lost on Planet #V_ONE faster than before. #V_ONE星球的阵地正以前所未有的速度沦陷。 +4005066509 Ground is being lost on Planet #V_ONE faster than before. #V_ONE星球的阵地正以前所未有的速度沦陷。 +1882056404 Ground will no longer be lost more quickly on Planet #V_ONE. #V_ONE星球的阵地沦陷的速度不再加快。 +2195933349 Ground will no longer be lost more quickly on Planet #V_ONE. #V_ONE星球的阵地沦陷的速度不再加快。 +3900413013 Ground will no longer be passively re-gained on Planet #V_ONE. 我们不再被动夺回#V_ONE星球的阵地。 +627359968 Grow Up To Be Helldivers. Remaining 2% Under Investigation. 长大以后成为绝地潜兵,剩余2%尚在调查 +1988110370 GROWING STRONGER 茁壮成长 +657353531 GROWL 咆哮市 +598279086 GS-11 Democracy's Deputy GS-11“民主代理人” +2226140047 GS-11 DEMOCRACY'S DEPUTY GS-11“民主代理人” +3911487404 GS-17 Frontier Marshal GS-17“边境元帅” +83359279 GS-17 FRONTIER MARSHAL GS-17“边境元帅” +1507566596 GS-66 Lawmaker GS-66“立法者” +2289519828 GS-66 LAWMAKER GS-66“立法者” +4072255229 GUANG SECTOR 古安分区 +3939201276 Guard Dog “护卫犬” +1615718868 GUARD DOG “护卫犬” +1308260976 Guard Dog stratagem availability has ended. 现已无法使用“护卫犬”战略配备。 +707049770 Guardian 拯护者 +2234330983 GUIDANCE 制导 +4044635637 Guided 制导 +2901461855 GUIDED 制导 +2181856792 GUNNAR 刚纳尔 +196776936 GUNNER FRV 炮手快速侦察载具 +2041442475 GUNNER FRV 炮手快速侦察载具 +90985685 GUNPOWDER MEADOWS 火药草原 +4132805651 GUNS OF LIBERTY 自由利器 +1932062202 Gunship 炮舰 +686156605 GUNSHIP 炮舰 +1029868551 GUNSHIP FACILITY 炮舰设施 +149087144 GUNSHIP PATROLS 炮舰巡逻队 +1131183082 Gunships 炮舰 +4228727062 Gunships are Patroling the Area 炮舰正在巡逻此区域 +306935634 GUNSLINGER 神枪手 +103796783 GUNVALD 古恩瓦尔德 +3293707642 GYEONGSEONG 京城 +1237995462 HABITAT RED-2 栖地红-2 +3870254765 Hack into the terminal to sabotage stationary defenses 入侵终端以破坏固定防御设施 +2616578175 HADAR 马腹一 +1661868344 HAERSTVIK 哈尔斯特维克 +4279955449 Haggstrom 黑格斯特伦 +3692999116 Hair Trigger 微力扳机 +843374261 HAIR TRIGGER 微力扳机 +1585645666 HAKA 哈卡 +3109167484 Hakalax 哈卡拉克斯 +3755650243 HAKU CITY 哈库城 +3692813988 HALDUS 海德斯 +1449081236 Half a message is typed on this blood-spattered tablet: "Request immediate fire support. Taking heavy ca-" 留有血迹的平板上残留着输入到一半的消息:“请求立刻提供火力支援。伤亡惨…” +2390853194 Half Choke 半喉缩 +1271919524 HALF CHOKE 半喉缩 +2726804828 HALIES PORT 海利斯港 +4293347269 Halo 光环 +3506581074 Halt 止息 +3285885726 HALT 止息 +4068217168 HALT CYBORG PRODUCTION 使生化人停产 +3968375375 Halt the extensive Automaton industrial operations on this lava-covered planet. Annex their facilities and seize their stolen goods. 阻止机器人在这颗熔岩覆盖的星球上展开大规模工业活动。占领它们的设施,夺回被盗的物资。 +20832891 Halt the Illuminate and collect crucial data on the Void. 阻止光能者,收集与寂域有关的重要数据。 +810391974 Halt the Illuminate and collect crucial data on the Void. 阻止光能者,收集与寂域有关的重要数据。 +532417488 HAMMARBY 哈马比 +1764769201 Hammer 之锤 +3296291475 HAND CARTS 手推车 +1829293410 Hand in to #NAME 上交给#NAME +2925957429 HANDAKAS 汉达卡斯 +4272289192 HANDBRAKE 手刹 +1056267452 HANDWRITTEN NOTE 手写便条 +729441518 Hangar 机库 +119492969 HANGAR 机库 +2458956922 HANGAR 机库 +3264531083 HANGAR 机库 +3862006380 HANGAR 机库 +3952685120 HANGAR 机库 +51976185 HANGAR 6 6号机库 +3181485734 Hansson-Bjerke 汉松-比耶克 +1857499959 HANZO SECTOR 半藏分区 +1914984859 HARBER 哈珀 +1317135238 Harbinger 之兆 +2450957594 HARBINGER OF TRUE EQUALITY 真正的平等先锋 +3348415410 HARBINGER OF TRUE EQUALITY 真正的平等先锋 +2916359955 HARD 困难 +3876836908 HARD 困难 +2685298705 HARDY 强健市 +1090942724 Harrassment or Hate Speech 骚扰或仇恨言论 +1694948462 Hart 哈特 +1405979473 Harvester 猎杀器 +616251181 HARVESTER 猎杀器 +1081892642 Harvesters 猎杀器 +976163900 HASTILY WRITTEN NOTE 匆匆写下的便条 +3419620263 HATCH OPEN 舱门已打开 +1377858079 Hatch opening. Thank you for your patience. 舱门正在开启。感谢你的耐心等待。 +1632926029 Hatch opening… 舱门正在开启…… +316971668 HATCH OPENING... 舱门正在开启…… +2318515204 Hatch ready for opening 舱门随时可以开启 +1328589529 Have 6 orbital barrage stratagems in the same place at the same time. 在同一地点同时部署6个轨道火力网战略配备。 +3244361341 HAVEN 黑文 +3005393040 Having trouble spreading Democracy in the darkness? Some weapons include top-of-the-line illumination aids. Hold "Reload" to turn them on! 在黑暗中难以传播民主?部分武器配有尖端照明辅助设备,按住“装填弹药”键即可开启照明! +929685836 HAWKING SECTOR 霍金分区 +593084860 HE 高爆弹 +845875583 HE 高爆弹 +1226894239 HE 高爆弹 +1939904337 HE MK2 高爆弹 Mk2 +2940612419 HE MK2 高爆弹 Mk2 +2478231846 Head Tap 动动脑 +1038853051 HEAD TAP 动动脑 +2054485453 HEADER HIDDEN 隐藏标题 +224170049 HEADER VISIBLE 显示标题 +3626628974 HEADLIGHTS MODE 大灯模式 +887248897 HEADPHONES 耳机 +8192687 Heads Up Display (HUD) Curve HUD弧度 +2675540600 Heads Up Display (HUD) Scale HUD大小 +2237848324 Headset Accidentally Linked To Nearby Wolves. 导致研究人员不幸身亡 +3874111423 Headshot #COUNT Automaton Soldiers 爆头击杀#COUNT个机器人士兵 +1647024014 Heal another player using stims. 使用治疗剂治疗其他玩家。 +2816857631 Heal teammate with STIMS. 用治疗剂治疗队友。 +4240196127 Health regeneration no longer in effect. 恢复生命值的效果结束。 +4244474999 Health Visibility 生命值可视度 +3801905866 HEART FLATS 心平市 +3272831933 HEARTWARMING STORY 暖心故事 +624817623 HEAT 高爆反坦克弹 +3746778495 HEAT 高温 +4055908097 HEAT Grenades 高爆反坦克榴弹 +311487137 HEAT MK2 高爆反坦克榴弹 MK2 +3410420208 Heathcote 希思科特 +538574577 HEATHERFIELD 希瑟菲尔德 +552258063 Heavily Armored Enemies 重甲敌人 +2534884336 Heavily insulated from animal bites, enemy fire, and the histrionic diatribes of anarchists. 对野兽啃咬、敌方火攻以及扰乱分子的嬉笑怒骂完全绝缘。 +3330772345 Heavily layered to protect against ocular blistering, subdermal liquification, and gastrointestinal shattering, this armor is a testament to the power of iterative improvements based on user feedback. 这套盔甲层层厚实,可防止眼部起泡、皮下液化和胃肠道碎裂,充分体现了根据用户反馈迭代改进的力量。 +885969512 Heavy 重型 +568245020 HEAVY 重型 +495972049 HEAVY ARMOR PENETRATING 重甲穿透 +658390125 HEAVY ARMOR PENETRATING 重甲穿透 +383938306 HEAVY ARMOR SURGE 重甲敌军激增 +878121724 Heavy Automaton forces are gathered in this location. 大批机器人部队集结于此地。 +4216310019 Heavy Automaton Outpost Destroyed 重型机器人哨站成功摧毁 +3681475254 Heavy Bug Nest Eradicated 重型巢穴成功摧毁 +1074969677 HEAVY COMBAT (BOTS) 重型作战(机器人) +10607875 HEAVY COMBAT (BUGS) 重型作战(虫族) +4233263456 HEAVY COMBAT (ILLUMINATE) 重型作战(光能者) +398976798 Heavy Devastator 重型蹂躏者 +3024067659 HEAVY DEVASTATOR 重型蹂躏者 +4016615575 Heavy Devastators 重型蹂躏者 +35443895 Heavy Encampment 重型营地 +3957075233 HEAVY GLOOM SHROUD 重度“阴霾”笼罩 +1484195672 Heavy Illuminate Encampment Cleared 光能者重型营地成功摧毁 +2050119908 Heavy Machine Gun 重机枪 +1688248653 HEAVY MACHINE GUN 重机枪 +1389118231 Heavy Machine Gun Emplacement stratagem availability has ended. 现已无法使用“重机枪部署支架”战略配备。 +2203633835 Heavy Nest 重型巢穴 +2396621876 HEAVY ORDNANCE DISTRIBUTION 重型军械分发 +2615704050 Heavy Outpost 重型哨站 +519669347 Heavy Outposts 重型哨站 +1187488181 Heavy Recoil Spring 重型复进簧 +479431914 HEAVY RECOIL SPRING 重型复进簧 +1125879968 Heavy SEAF Presence 超级地球武装部队重兵驻守 +2262855397 Hedstrom 赫德斯特伦 +64227820 Heel Kick 踢踏步 +3679678918 HEEL KICK 踢踏步 +340135660 HEETH 希斯 +2576996860 HEETH DEFENDED +After countless noble and unavoidable sacrifices, Heeth has been defended from the Terminids. 成功保卫希斯 +无数不可避免的光荣牺牲终于换来回报,我们顺利从终结族手下守住了希斯。 +410641170 HEETH FREED +Heeth has been cleansed of all Terminid infestation. Well done, Helldivers. Keep pressing forward. 希斯已解放 +肆虐希斯的终结族已被全数剿灭。很好,各位绝地潜兵。再接再厉,继续前进。 +3141989084 HEETH LOST +Heeth has fallen to the Terminid Menace. We cannot allow this infestation to continue to spread. 希斯沦陷 +在终结族的威胁下,希斯已沦陷。我们不能容许虫族继续扩张。 +921762403 HEETH UNDER ATTACK +The bugs have attacked Heeth. Rally to its defense, before they are able to permanently infest it. 希斯遭到袭击 +虫族对希斯发动了袭击。立即集结,前去防卫,避免领地永远落入敌人手里。 +1602327515 HELL COMMANDER 地狱上尉 +2764315601 Hell Dive 绝地俯冲 +124960475 Hellbomb 地狱火炸弹 +4010616934 HELLBOMB 地狱火炸弹 +3989310204 HELLBOMB 地狱火炸弹 +2399747308 Hellbot 绝地机械兵 +4252439335 HELLDIVE 绝境 +2873087446 HELLDIVE 绝境 +2120469618 Helldiver 绝地潜兵 +1715612552 Helldiver 绝地潜兵 +160113341 HELLDIVER 绝地潜兵 +3248238510 HELLDIVER 绝地潜兵 +947161983 Helldiver Dummy 绝地潜兵假人 +2648150009 HELLDIVER FRIENDS 绝地潜兵好友 +476862046 Helldiver Joining 绝地潜兵正在加入 +1863523614 Helldiver Recruit 绝地潜兵新兵 +4184186012 Helldiver Replacements 绝地潜兵替补兵员 +1067047599 HELLDIVER TRAINING FACILITIES 绝地潜兵训练基地 +2374034583 HELLDIVERS 2 must be updated to use network features. 必须更新才能使用《HELLDIVERS™ 2》的联网功能。 +946320087 Helldivers Active 绝地潜兵活跃数 +3137621293 Helldivers are instructed to report to their ship's tailor for measurements. As development of the Advanced Liberation Tools Research Agency (ALTRA)'s new combat asset nears completion, we must ensure that every Helldiver can fit within it. For the good of Managed Democracy. 绝地潜兵在指引下将尺码数据汇报给舰船裁缝师。先进解放工具研究局的新战斗装备开发工作即将完成,我们必须确保每一位绝地潜兵都能穿上装备。管理式民主万岁。 +3677632134 HELLDIVERS CLASSIC HELLDIVERS 经典 +727197425 Helldivers come out of the Hellpod fully stocked on Ammo, Grenades and Stims. 绝地潜兵携带充足的弹药、榴弹和治疗剂补给走出绝地喷射舱。 +3527331608 Helldivers Continue Valiant Fight To Contain Terminids. 绝地潜兵仍在英勇遏制终结族 +1743809366 HELLDIVERS DEPLOY TO RETAKE CYBERSTAN 绝地潜兵出动,重夺生化斯坦 +761483845 Helldivers deploy with #V_ONE% less magazines. 绝地潜兵部署时携带弹匣数减少#V_ONE%。 +1525000887 HELLDIVERS EXTRACTED 绝地潜兵撤离数 +82371251 Helldivers KIA 绝地潜兵阵亡数 +3193324325 Helldivers Mobilize! 绝地潜兵总动员! +3010944915 HELLDIVERS MOBILIZE! 绝地潜兵总动员! +131992695 Helldivers on PlanetX have defeated waves of the Mindless Masses. Genetic material from the Voteless sent to the Ministry of Science show clear markers of adaptation to a rapidly changing environment, potentially giving clues about organisms inside the Void. 镇守X星的绝地潜兵已击溃一波又一波无脑群氓。送往科学部的无票者遗传物质显示出可适应快速变化环境的清晰标记,这或许能为我们提供有关寂域生物的线索。 +980328001 Helldivers operate against the clock. Complete your mission before the SUPER DESTROYER leaves low orbit. 绝地潜兵的行动必须争分夺秒。要在超级驱逐舰离开低空轨道前完成任务。 +3544318250 Helldivers Ordered to Prepare Terminid Cordon Planets for "Purge". 绝地潜兵奉命准备“净化”部署终结族封锁线的星球 +254710586 Helldivers Prepare For Massive Strike on Terminid Hives. 绝地潜兵准备大规模攻击终结族虫窝 +3740991914 HELLDIVERS PUSH TO SUPERCOLONY 绝地潜兵攻向超级拓殖地 +3458008433 HELLDIVERS REDIRECTED 绝地潜兵重新调配 +1939963888 Helldivers Redirected from Automaton Conflict Back To Terminids. 绝地潜兵调离机器人冲突战区,重返抗击终结族前线 +890036569 Helldivers Redirected From Operation Valiant Enclosure To Fully Engage Automatons. 绝地潜兵调离英勇围合行动,全力应战机器人 +1437848943 HELLDIVERS TO HELLPODS 绝地潜兵进入绝地喷射舱 +1399707567 HELLDIVERS TO STRIKE AUTOMATONS 绝地潜兵即将出击机器人 +925995066 Helldivers traveling the galaxy might come across ancient ruins and other curiosities. Just remember: Only a traitor is curious about alien artifacts! 遨游银河的绝地潜兵可能会遇见古代遗迹或其他奇特物品。记住:只有叛徒才会对外星古物好奇! +399202590 Helldivers will soon have even more tools with which to bring Managed Democracy to the enemy. Shipments of new equipment are under way. 绝地潜兵很快将拥有更多工具,向敌人传播管理式民主。全新装备正在运输途中。 +146182837 HelldiVR_91 绝地深潜VR_91 +3157507895 HELLDRIVER 绝地司机 +870111091 Helldrivers 绝地司机 +3950823704 HELLDRIVERS 绝地司机 +771961394 HELLMIRE 海尔迈尔 +1354121990 HELLMIRE DEFENDED +After countless noble and unavoidable sacrifices, Hellmire has been defended from the Terminids. 成功保卫海尔迈尔 +无数不可避免的光荣牺牲终于换来回报,我们顺利从终结族手下守住了海尔迈尔。 +1805161106 HELLMIRE FREED +Hellmire has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet. 海尔迈尔已解放 +海尔迈尔挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。 +2635288014 HELLMIRE LOST +The defense of Hellmire has failed. Terminids now run amok on its surface. We cannot allow this corruption of Liberty to stand. 海尔迈尔沦陷 +海尔迈尔保卫战已宣告失败。终结族现在正四处肆虐。我们不能允许任由它们继续侵犯自由伟业。 +4160807769 HELLMIRE UNDER ATTACK +The bugs have attacked Hellmire. Rally to its defense, before they are able to permanently infest it. 海尔迈尔遭到袭击 +虫族对海尔迈尔发动了袭击。立即集结,前去防卫,避免领地永远落入敌人手里。 +2982270088 Hellpod 绝地喷射舱 +2090438050 HELLPOD 绝地喷射舱 +2476233709 HELLPOD 绝地喷射舱 +3902444015 HELLPOD 绝地喷射舱 +4268849352 Hellpod deployment tips are a collaboration of the Ministry of Defense and Ministry of Truth. 绝地喷射舱的部署技巧由国防部和真理部联合编写。 +2894763526 HELLPOD LAUNCH IMMINENT! 绝地喷射舱即将发射! +3675924335 HELLPOD PATTERN 绝地喷射舱涂装 +4161594482 Hellpod Space Optimization 绝地喷射舱空间优化 +111908364 HELLPOD SPACE OPTIMIZATION 绝地喷射舱空间优化 +3846241460 HELLPODS ACTIVE - PROCEED TO HELLPODS 绝地喷射舱已启动 - 前往绝地喷射舱 +2744106963 Hellpods have basic steering capabilities. Try to drop in on your enemies! 绝地喷射舱具备基础转向功能。尽量降落在敌人周围! +2143284501 Hellpods will be deployed to this location upon mission launch. Due to the Super Destroyer's absence, normal reinforcement will be unavailable. + +Securing this site will give access to additional reinforcements, who will deploy directly from this location. 任务开始时,绝地喷射舱将部署至此位置。因超级驱逐舰不在场,无法获得常规增援。 + +占领此地点可获得额外增援,增援力量将直接部署到此处。 +461577454 Helmet 头盔 +956581541 Helmet 头盔 +215271178 HELMET 头盔 +909045564 HELMET 头盔 +2891543496 HELMET 头盔 +3845827618 Helmets 头盔 +2645373868 HELMETS 头盔 +1151991584 Help us build the best Helldivers 2 experience! +When you play this game, Sony Interactive Entertainment collects data that is necessary to operate the game. +If you agree, Sony Interactive Entertainment may also collect data about your interaction with the game and errors that occur. This data will be used as explained in our privacy policy. +You can change this setting at any time to allow full or limited data collection. 协助我们打造最佳的《Helldivers 2》游戏体验! +在您游玩本游戏时,索尼互动娱乐会收集本游戏运行所需的必要数据。 +如果您同意,索尼互动娱乐可能还会收集其他数据,以便了解您与游戏互动的方式以及期间发生的错误。这些数据的使用方式皆遵守我们的隐私政策。 +您可以随时更改该设置,选择提供全部或部分数据。 +3144888864 Help us build the best PlayStation® experience! +When you play this game, Sony Interactive Entertainment collects data that is necessary to operate the game. +If you agree, Sony Interactive Entertainment may also collect data about your interaction with the game and errors that occur. This data will be used as explained in our privacy policy. +You can change this setting at any time to allow full or limited data collection. 帮助我们打造PlayStation®最佳游戏体验! +在您游玩本游戏时,索尼互动娱乐会收集本游戏运行所需的必要数据。 +如果您同意,索尼互动娱乐可能还会收集其他数据,以便了解您与游戏互动的方式以及期间发生的错误。这些数据的使用方式皆遵守我们的隐私政策。 +您可以随时更改该设置,选择提供全部或部分数据。 +158969120 Helps prevent Helldivers from flinching when hit. 有助于防止绝地潜兵遭受攻击后产生畏缩反应。 +2245967469 Herald 使者 +100428428 HERD THINNING 削减虫群 +2794990445 HERD THINNING 削减虫群 +3163227807 Here you can expand your ships arsenal of helmets, armors and capes. 你可以在这里扩充舰船上储备的头盔、盔甲和披肩。 +3290341695 Here you can unlock new stratagems to use on the battlefield. Initially, your Destroyer only has access to a limited catalog of stratagem permits, but as you level up, more stratagems will become available for purchase. 你可以在这里解锁全新的战略配备,供你在战场上使用。你的驱逐舰最初只能访问有限的战略配备许可目录,但只要升级就能购买更多战略配备。 +2671409608 Here you expand your ships arsenal of firearms and grenades. 你可以在这里扩充舰船上储备的枪械和榴弹。 +3726809868 Here, citizens in well-insulated worksuits operate facilities liberated from the Automatons, and repurposed to sustainably extract rare materials from the highly volcanic planet. 在这里,身着强隔热工作服的公民操作着从机器人手中解放出来的设施。这些设施经过改造,能够在这颗火山活动频繁的星球上可持续地开采稀有资源。 +3156554121 Here, fresh-faced recruits learn what it takes to defend Super Earth and her values. 面带稚气的新兵在这里学会如何捍卫超级地球及其价值观。 +2731914041 Here, the best of the best go through the rigorous Helldiver training that will earn them their capes. 万里挑一的精英在这里接受严格的绝地潜兵训练,争取赢得披肩。 +593716614 HERITAGE OLIVE EXOSUIT PATTERN 经典橄榄绿外骨骼装甲涂装 +2411380547 HERITAGE OLIVE HELLPOD PATTERN 经典橄榄绿绝地喷射舱涂装 +2508206247 HERITAGE OLIVE SHUTTLE PATTERN 经典橄榄绿运输船涂装 +1575607191 HERITAGE OLIVE VEHICLE PATTERN 经典橄榄绿载具涂装 +4169685013 Hero 英雄 +2384505797 HERO 英雄 +3603413043 HERO RATING 英雄评分 +1402635182 Heroic dog rescues boy from plutonium mine shaft 英勇狗狗将男孩救出钚矿井 +1334351473 Heroic Kindergartener Identifies Dissident Classmate 幼儿园英勇儿童发现同班异见分子 +3263009716 HERTHON SECUNDUS 赫尔松次星 +1577431289 HESOE PRIME 海索主星 +2875027973 HETT 炎核 +1539362188 HEZE BAY 角宿二湾 +2867341805 HIDDEN 隐藏 +1248374475 HIDE 隐藏 +2245317431 HIDE DETAILS 隐藏详细信息 +1446065370 HIDE FRIEND CODE 隐藏好友代码 +2939461461 HIDE HEROES OF SUPER EARTH 隐藏超级地球英雄 +32304560 HIDE ORDERS 隐藏指令 +546280855 HIGH 高 +3283042119 High Capacity Heatsink 高容量散热器 +3799349087 HIGH CAPACITY HEATSINK 高容量散热器 +175084695 High Command has identified this Megafactory as one of two potential beachheads for the invasion of Cyberstan. Anti-air fixtures will hamper Pelican extraction. 最高指挥部已将这座超大型工厂认定为入侵生化斯坦的两个潜在滩头堡之一。防空设施将阻碍“鹈鹕”号撤离。 +2798581231 High Command has identified this Megafactory as one of two potential beachheads for the invasion of Cyberstan. Rapid insertion protocols will restrict deployment ammunition. 最高指挥部已将这座超大型工厂认定为入侵生化斯坦的两个潜在滩头堡之一。快速突入协议将限制部署弹药。 +2891850877 High Dissipation Heatsink 高功率散热器 +1691987288 HIGH DISSIPATION HEATSINK 高功率散热器 +3960373350 High Dynamic Range 高动态范围 +1783604047 High Explosive 高爆弹 +2549383367 HIGH EXPLOSIVE 高爆弹 +900034221 High numbers of enemy Hulks have been reported on this planet. Prepare to encounter heavily armored enemies. 据报告称,该星球上出现大量敌方巨型者。请做好应对重甲敌军的准备。 +2806921132 HIGH RECRUITMENT 广纳千军 +3978367569 HIGH SCORES 最高分 +2383369106 HIGH-DENSITY EXPLOSIVES 高密度炸药 +445743664 High-Five 击掌 +1326569050 HIGH-FIVE 击掌 +2434409293 High-Pressure Napalm 高压凝固汽油弹 +3769865145 HIGH-PRESSURE NAPALM 高压凝固汽油弹 +2541221921 High-Pressure Nozzle 高压喷嘴 +617845890 HIGH-PRESSURE NOZZLE 高压喷嘴 +3379144539 HIGH-PRIORITY CAMPAIGN 首要战役 +2539164536 HIGH-PRIORITY CAMPAIGN PROGRESS 首要战役进度 +3192569703 HIGH-PRIORITY CAMPAIGN PROGRESS 首要战役进度 +2460265460 High-priority campaigns contain unique missions related to the current Major Order. Super Earth will liberate High-priority campaign planets just like Liberation campaigns. 首要战役包含与当前重要指令相关的特殊任务。与解放战役一样,超级地球将解放首要战役的目标星球。 +387172282 HIGH-QUALITY LUBRICANT 优质润滑剂 +599422663 High-Speed Servos 高速伺服系统 +3235768546 High-Speed Servos 高速伺服系统 +1237955427 HIGH-SPEED SERVOS 高速伺服系统 +2550889443 HIGH-SPEED SERVOS 高速伺服系统 +2057996380 High-value intel of the enemy's plans is hard-coded onto devices that high-confidence intel indicates is located at this location. + +Infiltrate the site, acquire the intel, and extract with it in your possession. 有关敌军计划的高价值情报已通过硬编码写入设备中,可靠情报显示,该设备就在此处。 + +潜入现场,获取情报,并携带情报撤离。 +1129593185 HIGH-VALUE PICKUPS 高价值拾取物 +2365174493 HIGH-VALUE TARGET DESTROYED 高价值目标已摧毁 +1845748710 HIGH-VALUE TARGETS 高价值目标 +2219486500 High-Velocity Shrapnel 高速榴霰弹 +2219516552 HIGH-VELOCITY SHRAPNEL 高速榴霰弹 +3111416441 Higham 海厄姆 +1436757074 Higher Missile Damage 提升导弹伤害 +2099579348 HIGHER MISSILE DAMAGE 提升导弹伤害 +3033480714 HIGHER STIM CAPACITY 更大治疗剂容量 +3572099144 HIGHER STIM CAPACITY 更大治疗剂容量 +4115703291 Highest priority upload speed 最高优先级上传速度 +4049910288 HIGHLIGHT 高亮 +4287360836 Highly Anticipated Battle of Malavax Prime To Be Broadcast Live - Buy Tickets Here. 万众期待的马拉瓦克斯主星战役现场直播,门票此处购买 +2545239036 HILDOARA CENTRAL 希尔多亚拉中区 +620511651 HILJAISUUS 寂城 +3697309014 Hint Visibility 提示可视度 +468077385 HINTS 提示 +1248813848 Historians Determine "Gaslighting" Never Meant What We Thought It Meant 历史学家认为“煤气灯操纵”实际含义始终不同于大众认知 +2927920965 HIT 'EM WHERE IT HURTS 直击痛处 +922749441 Hive 虫窝 +621653032 HIVE BREAKER DRILL “虫窝破裂者”钻机 +1998289914 HIVE BREAKER DRILL “虫窝破裂者”钻机 +626718113 Hive Guard 虫窝护卫 +3791129379 HIVE GUARD 虫窝护卫 +2657956346 Hive Guards 虫窝护卫 +3929716830 Hive Lord 霸王虫 +326344529 HIVE LORD 霸王虫 +2842546265 Hive Lords 霸王虫 +3709494312 HIVE LORDS 霸王虫 +2286332848 Hive Scanner 虫窝扫描仪 +237983875 HIVE SCANNER 虫窝扫描仪 +3319058865 HIVE WORLD 虫窝世界 +90063288 HMG Emplacement 重机枪部署支架 +1366895198 HMG EMPLACEMENT 重机枪部署支架 +1117201283 Hodges 霍奇斯 +967966310 Hold 按住 +3509340002 Hold 按住 +479904149 HOLD 按住 +1706486345 HOLD 按住 +1671358401 HOLD 按住 +3510888353 HOLD 按住 +3435282359 Hold #COUNT planets in the #SECTOR sector when the order expires 指令过期后,在#SECTOR守住#COUNT颗星球 +1318954455 Hold #LOCATION when the order expires 指令过期后,坚守#LOCATION +1826463299 Hold a grenade before throwing to "cook" it. Time your throw for an air-burst detonation! (Note: waiting too long may lead to unintended death.) 可以将榴弹握在手中进行“温雷”操作,之后再将其丢出。掌握好投掷时间,让榴弹在空中爆炸!(注意:温雷时间过长可能会导致意外死亡。) +2236873416 Hold back 压制 +577739165 HOLD CITY 保卫城市 +1128785210 HOLD CITY 保卫城市 +4073958185 HOLD CITY 保卫城市 +2760552626 HOLD FOR PLANET TRANSIT 长按开始星际传输 +2932688770 Hold My Liber-tea! 尝尝我的解放威力! +254510718 Hold my primary, I'm going in! 帮我拿着主武器,我要冲了! +2020130716 Hold my primary, I'm going in! 帮我拿着主武器,我要冲了! +1145769303 HOLD TO BUY ITEM 按住购买物品 +607745037 HOLD TO CLAIM ITEM 按住领取物品 +1733235098 HOLD TO PURCHASE 按住购买 +4027681874 Holder of the Yellow Line 黄线捍卫者 +853769629 HOLDER OF THE YELLOW LINE 黄线捍卫者 +1462357533 HOLL 霍凉地 +23500266 Holographic Sight 全息瞄准镜 +3401998340 HOLOGRAPHIC SIGHT 全息瞄准镜 +2429688760 HOME CINEMA 家庭影院 +1591080787 Home to the Democratic Council, our proud Capital is a beacon of Progress, Productivity, and Patriotism. 我们引以为傲的首都既是民主委员会的所在地,也是进步、生产力和爱国主义的璀璨灯塔。 +1500341394 HOMESTEAD HILL 家园山 +2736566458 Homing Anti-Air Missile 追踪式防空导弹 +2777619489 HOMING ANTI-AIR MISSILE 追踪式防空导弹 +3841488347 Homing Ground Missile 追踪式地面导弹 +206775492 HOMING GROUND MISSILE 追踪式地面导弹 +2920820585 Homing Ground Missile Mk2 追踪式地面导弹 MK2 +3922652844 HOMING GROUND MISSILE MK2 追踪式地面导弹 MK2 +2049971577 HONK 鸣笛 +3247730854 HONOR THE FALLEN 缅怀烈士 +2385167251 Honorable Duty 忠于使命 +1782107463 Honored Heirloom 荣耀传家宝 +1591164199 HONORED HEIRLOOM 荣耀传家宝 +1626212068 HOPEFUL 希望 +1390745011 HOPESHIRE 霍普郡 +4179653624 HORIZONTAL RECOIL 水平后坐力 +1105824679 HORT 哈尔特 +2184600406 Hot Dog 热狗 +3321311549 HOT DOG 热狗 +1593540412 HOT GATES 炙关 +1741663299 Hot Potato! 烫手山芋! +4179735114 Hot-shot Marksman Rifle 高能精确射手步枪 +2432449572 HOT-SHOT MARKSMAN RIFLE 高能精确射手步枪 +3757615996 Houses the Eagle Fighter & Pelican Shuttle. Also receives deliveries of materiel, supplies, frozen personnel, and fuel. 停放“飞鹰”战斗机与“鹈鹕”运输船,同时还接收运来的材料、物资、冷冻人员以及燃油。 +98611233 Housing Costs On Rise As Even-Greater Greatest Generation Moves Into Retirement 伟大中的伟大世代迎来退休,房价应声走高 +3104461785 Hover over available Campaigns to get more information. 悬停在可选战役上方可以查看更多信息。 +219339929 Hover Pack 悬浮背包 +3727877127 HOVER PACK 悬浮背包 +1081890590 Hovering over a sector shows you how much of it Super Earth has already liberated. All operations contribute to pushing the enemies of Super Earth back. +Select a sector to see what planets are currently playable. 悬停在分区上可看到超级地球在该区的解放进度。所有行动皆能为击退超级地球的敌人贡献助力。 +选择分区,看看当前可以参与哪颗星球的战事。 +1915666706 How quickly the cursor transitions from moving to stabilizing. 光标从移动到稳定的过渡速度。 +2425139947 How sensitive the motion sensor should be in relation to moving the controller. 移动控制器时动态感测器的灵敏度。 +3876920205 HUB OF INDETERMINATE PURPOSE 用途不明的中心 +2590540344 HUD HUD +2969749421 HUD Background Opacity HUD背景不透明度 +73038277 HUD Edge Offset HUD边缘偏移 +3766148759 HUD HIDDEN 隐藏HUD +3429463254 HUE 色调 +2075147815 Hug 拥抱 +4042465716 HUG 拥抱 +790541304 Hulk 巨型者 +236578379 HULK 巨型者 +613980508 Hulk Bruiser 巨型碾压者 +439038884 HULK BRUISER 巨型碾压者 +2768059040 Hulk Bruisers 巨型碾压者 +2090691137 Hulk Firebomber 巨型烈焰轰炸者 +2109890358 HULK FIREBOMBER 巨型烈焰轰炸者 +4230842877 Hulk Firebombers 巨型烈焰轰炸者 +1560770730 Hulk Obliterator 巨型抹煞者 +3135100785 HULK OBLITERATOR 巨型抹煞者 +3401528511 Hulk Obliterators 巨型抹煞者 +1775662925 Hulk Scorcher 巨型炙炎者 +3176114089 HULK SCORCHER 巨型炙炎者 +859021869 Hulk Scorchers 巨型炙炎者 +1483133390 HULK SURGE 巨型者激增 +2368557367 Hulks 巨型者 +762154077 HUMAN WILL 人类意志市 +435429588 HUMANITY 人道市 +3383572735 Humanity's intellect shines brighter than all other, piercing even the treacherous darkness that spawned the Automatons' pseudo-sentience; the darkness known as computer science. 人类的智慧比万物更闪耀,能刺穿孕育机器人伪智能的“计算机科学”诡谲黑雾。 +3182729352 Humble Regalia 谦卑徽记 +3723444904 HUMBLE REGALIA 谦卑徽记 +3330362068 Hunter 追猎虫 +2920989158 HUNTER 追猎虫 +1401399056 HUNTER'S BLUFF 猎人崖 +2480584215 Hunters 追猎虫 +3050699459 HUSARIA 轻骑 +929155643 HVAP ROUNDS 高速穿甲弹 +3420051700 HYBRID 混合 +1694795796 HYDRA SECTOR 长蛇座分区 +774406423 HYDROBIUS 哈卓毕亚斯 +440189837 HYDROFALL PRIME 水瀑主星 +3318361937 Hyena 鬣狗 +111718644 HYENA 鬣狗 +2485789637 I ALREADY HAVE 我已入伍 +4137970869 I already own one but I bought it again to support our heroes out there! 我已经有一件了,但为了支持前线的英雄,我又买了一件! +4090643110 I bought this for my husband and he loves it. 我给我老公买了这个东西,他非常满意。 +737227869 I-09 Heatseeker I-09“热力追踪” +1814943375 I-09 HEATSEEKER I-09“热力追踪” +3970966164 I-102 Draconaught I-102“龙行者” +1254773855 I-102 DRACONAUGHT I-102“龙行者” +2663165311 I-44 Salamander I-44“火蜥” +766068817 I-44 SALAMANDER I-44“火蜥” +674183024 I-92 Fire Fighter I-92“消防队” +3014989336 I-92 FIRE FIGHTER I-92“消防队” +830826286 I'm [redacted] and this is my favorite product in the acquisition center! 我是[已编辑]。这是采购中心里我最喜欢的产品! +227652385 I've used this every day for the past few weeks! 我已经用了几周,天天都用! +4150738687 ICBM Launching 洲际弹道导弹即将发射 +1139125063 ICBM raising into launch position 洲际弹道导弹正在抬升至发射位置 +1004277842 Ice and moss-covered rock can be found across most of the surface of this planet. 这颗星球表面大多是冰雪和长着苔藓的岩石。 +492305305 ICE BEND 冰本德 +4136038538 Idle hands are a fascist's playthings 怠惰是法西斯的陋习 +4234894978 IDUN SECTOR 伊顿分区 +1659520367 IE-12 Righteous IE-12“义士” +2647844829 IE-12 RIGHTEOUS IE-12“义士” +4118311236 IE-3 Martyr IE-3“烈士” +3817297073 IE-3 MARTYR IE-3“烈士” +2429942127 IE-57 Hell-Bent IE-57“奋不顾身” +1377985733 IE-57 HELL-BENT IE-57“奋不顾身” +2113520210 If a squadmate dies during a mission, make sure you pick up their dropped samples. There will be time for mourning later! 若队友在执行任务期间阵亡,请务必捡起他们掉落的样本。以后还会有时间供你追悼他们! +2573598521 If an enemy ever attempts to engage in diplomacy, SHOOT THEM. We musn't believe their lies. 对于试图对话的敌人,要毫不犹豫地开枪击毙。一定不能为花言巧语所欺骗。 +3065005289 If at first you don't succeed, dive, dive again. And again. And again. And again. And again. And again. And again. And again. And again. And again. And again. And again. And again. And again. 如果你在一开始失败了,那就再度空投参战,不断空投。不断、不断、不断、不断、不断、不断、不断、不断、不断、不断、不断、不断、不断空投。 +3297321656 If enabled, crossplay allows you to play with players on other platforms. 启用跨平台游玩后,你可以和其他平台的玩家一起游戏。 +744874584 If enabled, Helldivers II will utilize data collected from your account to improve player experience. 启用时, 《HELLDIVERS™ 2》将使用从你账户中收集的数据来改善玩家的游戏体验。 +1675948414 If enabled, replace your currently held weapon to the one you have picked up. 启用时,将你当前所持武器切换为拾取的武器。 +981331824 If enabled, surveys will be occasionally displayed. 如果开启此功能,系统将偶尔显示问卷调查。 +1159669979 If enabled, tapping the aim button will put you in/out of first person view. + +This only works while the aim trigger type is set to Hold and when not using a controller. 启用之后,轻按瞄准键可以进入/离开第一人称视角。 + +前提是瞄准触发方式设为“按住”,且没有使用控制器。 +4232082462 If enabled, tapping the aim button will put you in/out of first person view. + +This only works while the aim trigger type is set to Hold and when not using a controller. 启用之后,轻按瞄准按钮可以进入/离开第一人称视角。 + +前提是瞄准触发方式设为“按住”,且没有使用控制器。 +1802995937 If enabled, the camera will automatically center itself behind a player-controlled vehicle when not otherwise receiving input. 启用之后,如果没有收到其他输入,会自动将玩家控制的载具置于视角中央。 +1174929162 If enabled, the system tray icon will flash to notify you of important in-game developments, such as players joining your session or a game being found through matchmaking. This will mostly be noticeable when the game window is not in focus or active. 启用后,如果游戏窗口在后台运行或不是当前活跃窗口,系统托盘图标会在游戏内发生重要事件时闪烁提醒,例如有玩家加入游戏或是匹配成功。 +2022070704 If enabled, whenever you equip a weapon, it will recall the last weapon functions you had used, such as the firing mode. 启用该选项后,每次装备的武器都将应用上一次使用过的武器功能,如开火模式等。 +904263061 If no Helldiver is alive to reinforce you, additional reinforcements will automatically be dispatched, if the budget allows. 如果增援的绝地潜兵全部阵亡,在预算允许的情况下,会自动派遣额外的增援。 +104381681 If the enemies just keep coming, find out where they're coming from and unleash hell. Bug hive? Destroy! Bot factory? Destroy! 如果敌人源源不断地涌来,那就找出它们的老巢,将其斩草除根。虫窝?毁掉!机器人工厂?毁掉! +4135441287 If the problem persist contact support. 如果问题仍未解决,请联系客服。 +1930615419 If you don't have a RESUPPLY, scavenge for ammunition or request help from your teammates. 如果你没有重新补给,那就要设法搜集弹药或是向队友寻求帮助。 +2530318538 If you get knocked down while holding a stratagem beacon, it will deploy where you were standing. 如果你在手执战略配备信标的时候被击倒,战略配备将部署在你倒地之前站立的位置。 +2773430401 If you notice a squadmate sympathizing with an enemy, report them to your Democracy Officer. Thoughtcrimes kill! 如果你发现队友同情敌人,请向民主官举报。思想犯罪是会害死人的! +127386449 If you play one of our games, we will always access data from and / or store data on the device that you are using. This data is necessary to deliver our games, and includes: +• Content Data: Game content data, such as video, audio, graphic, text, and game level information that is requested and downloaded for the game that you are accessing online. If you are playing an online game, this includes your online interactions as necessary to reflect those interactions on our game servers. +• Account Data: Information required to sign you into your account for PlayStation™Network. +• Configuration Data: Information about the configuration of your device and the game you are playing , such as the device date, time and language settings and your in-game preference and settings. +• Security Data: Information necessary to detect and investigate malicious, unauthorized or fraudulent activity. +• Legal Data: Information required by applicable law and to demonstrate compliance. +If you agree, we may collect more detailed information about how you interact with our games. +This may include when and how you use the game’s user interface, which parts of the game you visit, which weapons you use, which characters you interact with and any errors that you encounter. +Game Data is usually sent to us and stored with one or more unique network, device and/or account identifiers. Wenn du eines unserer Spiele spielst, greifen wir immer auf Daten von dem Gerät zu, das du verwendest, und/oder speichern Daten auf diesem Gerät. Diese Daten sind für die Durchführung unserer Spiele erforderlich und umfassen: +• Inhaltsdaten: Spiel-Inhaltsdaten, darunter Video-, Audio-, Grafik-, Text- und Level-Informationen, die für das Spiel, auf das du online zugreifst, angefordert und heruntergeladen werden. Wenn du ein Online-Spiel spielst, schließt dies deine Online-Interaktionen ein, die notwendig sind, um diese Interaktionen auf unseren Spielservern wiederzugeben. +• Kontodaten: Informationen, die erforderlich sind, um dich bei deinem Konto für PlayStation™Network anzumelden. +• Konfigurationsdaten: Informationen über die Konfiguration deines Geräts und des Spiels, das du gerade spielst, wie z. B. die Einstellungen für Datum, Uhrzeit und Sprache des Geräts sowie deine Präferenzen und Einstellungen im Spiel. +• Sicherheitsdaten: Informationen, die erforderlich sind, um schädliche, unbefugte oder betrügerische Aktivitäten aufzudecken und zu untersuchen. +• Rechtliche Daten: Informationen, die nach geltendem Recht und zum Nachweis der Einhaltung der Vorschriften erforderlich sind. +Wenn du zustimmst, können wir detailliertere Informationen darüber sammeln, wie du mit unseren Spielen interagierst. +Dazu kann gehören, wann und wie du die Benutzeroberfläche des Spiels verwendest, welche Teile des Spiels du besuchst, welche Waffen du benutzt, mit welchen Charakteren du interagierst und welche Fehler bei dir auftreten. +Die Spieldaten werden in der Regel mit einer oder mehreren eindeutigen Netzwerk-, Geräte- und/oder Kontokennungen an uns gesendet und gespeichert. +3518494018 If you play one of our games, we will always access data from and/or store data on the device that you are using. This data is necessary to deliver our games, and includes: +• Content Data: Game content data, such as video, audio, graphic, text, and game level information that is requested and downloaded for the game that you are accessing online. If you are playing an online game, this includes your online interactions as necessary to reflect those interactions on our game servers. +• Account Data: Information required to sign you into your account. +• Configuration Data: Information about the configuration of your device and the game you are playing , such as the device date, time and language settings and your in-game preference and settings. +• Security Data: Information necessary to detect and investigate malicious, unauthorized or fraudulent activity. +• Legal Data: Information required by applicable law and to demonstrate compliance. +If you agree, we may collect more detailed information about how you interact with our games. +This may include when and how you use the game’s user interface, which parts of the game you visit, which weapons you use, which characters you interact with and any errors that you encounter. +Game Data is usually sent to us and stored with one or more unique network, device and/or account identifiers. 在您游玩我们的游戏期间,我们需要一直处理您使用的设备的数据,并/或在您的设备上储存数据。这些数据是提供游戏服务的必要数据,包括: +• 内容数据:访问在线功能时需要请求并下载的游戏内容数据,例如视频、音频、图像、文本及游戏关卡信息。如果您在线游玩,还将包括在线互动记录,以便游戏服务器处理这些互动操作。 +• 账户数据:您登录账户的必要数据。 +• 设置数据:所用设备以及所玩游戏的设置信息,例如设备日期、时间和语言设置、游戏内的偏好与设置。 +• 安全数据:检测及调查恶意、未经授权或作弊行为所需的必要信息。 +• 法律数据:适用法律所要求以及证明合规的信息。 +如果您同意,我们可能还会针对您与游戏互动的方式收集更详细的信息。 +该类信息可能包括您使用本游戏用户界面的时间与方式、体验过的游戏板块、使用过的武器、有互动的角色以及遇到的错误问题。 +游戏数据通常会发送给我们并使用一个或以上的专属网络、设备和/或账户标识符储存。 +2439731458 IGLA 伊格勒 +2403632757 ILDUNA PRIME 伊尔都纳主星 +3332178855 Illuminate 光能者 +1666367004 Illuminate 光能者 +4075596613 Illuminate 光能者 +815856735 ILLUMINATE 光能者 +1999524414 ILLUMINATE 光能者 +3335887011 Illuminate Artifact 光能者古物 +2009521352 ILLUMINATE ARTIFACT 光能者古物 +3662013215 ILLUMINATE CONTROL 由光能者控制 +4057749174 Illuminate Exospires are channeling an aberrant Exostorm that rages on the surface of this world. The planet is at risk of being consumed by the Void, unless we act now. + +Lay waste to their abyssal sanctums. Not a single Exospire can remain if Freedom’s light is to prevail. 光能者异界尖塔正引导一股畸变的异界风暴,在这个世界的地表肆虐。若不立即采取行动,星球恐将被寂域吞噬。 + +彻底捣毁它们的深渊圣所。只有摧毁所有的异界尖塔,自由之光方能普照。 +2337517887 ILLUMINATE FLEET 光能者舰队 +332764715 ILLUMINATE FLEET STRENGTH 光能者舰队战力 +3058519513 ILLUMINATE FLEET STRENGTH 光能者舰队战力 +3804465095 Illuminate forces are converging on the xenophobic ruins of their former empire. They must not be allowed to restore the relics of their tyrannical order. + +Activate the dormant ICBM silo in this region and reduce these makeshift lairs to ashes. 光能者的部队正在其昔日帝国充满排外色彩的废墟之上集结。我们绝不能纵容他们重建这些象征其暴政秩序的遗迹。 + +启动该地区休眠中的洲际弹道导弹发射井,将这些简陋的据点化为灰烬。 +2576327447 Illuminate forces have aggregated in vast numbers in this region. We must seize this tactical opportunity to annihilate them while they remain clustered. + +Eliminate the squids and their monstrous congregation. Kill as many as possible. 光能者部队已在该地区内大量集结。我们必须抓住这一战术窗口,趁其集结之时将其一举歼灭。 + +消灭那些鱿鱼及其丑陋的聚群。尽可能消灭光能者。 +2391696947 Illuminate forces have encroached upon a region believed to contain rich mineral deposits. If valuable resources do exist here, the enemy cannot be allowed to bend them towards their despotic schemes. + +Deploy the Prospecting Drill and collect soil samples to verify the site’s value. 光能者部队已经入侵据称蕴藏着丰富矿产的地区。若此地确实蕴藏着宝贵资源,绝不能任其沦为敌人推进专制企图的工具。 + +部署勘探钻机并采集土壤样本,核实此地的开发价值。 +2276221414 ILLUMINATE GOALS ACHIEVED: #TIME 光能者目标已达成:#TIME +2054415072 Illuminate Harvesters are patrolling this city block. Seek and destroy the roaming menace. 光能者猎杀器正在该城区巡逻。搜寻并歼灭这股游荡的敌人。 +378247061 Illuminate Harvesters patrol this colony, enforcing the zealous rule of their masters. The unnatural, spindly constructs must be destroyed, so that Freedom can return. 光能者猎杀器会在此拓殖地巡逻,尽心尽力维护它们主人的狂热统治。必须摧毁这些非自然的细长型结构物,我们才能重获自由。 +4098194979 Illuminate invaders have located Priority Emergency Bunkers (available to citizens at Class B and above), and are ruthlessly targeting these non-combatants in clear violation of galactic law. + +Transport ships are inbound to evacuate the citizens. The Helldivers must ensure these patriotic and loyal citizens reach safe harbor. 光能者已发现向B级及以上公民开放的优先紧急掩体,正残忍屠杀这些平民,公然践踏星际法律。 + +帮助公民撤离的运输舰即将抵达。绝地潜兵必须确保这些忠诚的爱国公民安全登舰。 +2933045560 ILLUMINATE INVASION 光能者入侵 +3483139454 ILLUMINATE INVASION PROGRESS 光能者入侵进度 +836022118 Illuminate Kills 光能者击杀数 +315140100 ILLUMINATE OVERSHIP 光能者统御舰 +1834396555 ILLUMINATE RETURNED? 光能者回归? +1851448310 Illuminate Ships Incoming 光能者舰船即将抵达 +1654406343 Illuminate Staff 光能者长杖 +1467471677 Illuminate Warp Ships are docked here. Destroy them while they are vulnerable. 光能者穿梭舰在此停靠。趁它们不备时摧毁穿梭舰。 +3736515091 Illuminate Warp Ships are docked in this area. These ships are critical to the Illuminate invasion, used for all terrestrial military functions including personnel abduction and combatant deployment. + +While the ships are grounded, they are vulnerable. Find them and destroy them. 光能者穿梭舰在此区域停靠。这些舰船对光能者的入侵行动而言非常重要,人员绑架和作战人员部署等所有地面军事行动都需要用到这些舰船。 + +如果舰船无法起飞,它们将无力抵御攻击。找到舰船,并将其摧毁。 +1800386877 Illuminate Warp Ships have docked at this location. Destroy them. 光能者穿梭舰已在此处停靠。消灭它们。 +51779241 Illuminate Warp Ships occupy key intersections in this city. These ships are critical to the enemy's insidious invasion efforts: they are used to deposit hostiles, abduct civilians, and threaten our proudly held air quality scores. + +Seek and destroy all Illuminate Warp Ships in the area. 光能者穿梭舰占领了这座城市的要道。这些舰船对敌人阴险的入侵行动至关重要,被用于投放敌人、绑架平民,还威胁我们引以为傲的空气质量。 + +搜寻并摧毁区域内的所有光能者穿梭舰。 +3909684051 IMBER 因博尔 +290476345 Immediate Auto Loader 即时自动装填 +3164087588 IMMEDIATE AUTO LOADER 即时自动装填 +1694264298 Immolation 焚身 +1218936454 IMMOLATION 焚身 +2759581807 Impact 着陆 +3811481650 Impact 冲击 +2391463327 Impact 冲击弹 +4257459235 IMPACT 冲击弹 +2340823345 IMPACT 影响 +545364779 Impact of each mission returned to normal level. 每次任务的影响力已恢复正常。 +1046000873 Impaler 穿刺虫 +1520751263 IMPALER 穿刺虫 +199397308 IMPALER ELIMINATION 消灭穿刺虫 +1490501681 Impalers 穿刺虫 +1098540788 Impatient 急躁 +2898696143 IMPATIENT 急躁 +910670140 Impersonating a Representative 冒充代表 +2524123562 Impersonating Another User 冒充其他用户 +3212882319 Impersonating developer 冒充官方工作人员 +486634204 IMPOSSIBLE 不可能的任务 +3927902467 Improved Aiming Servos 改良瞄准伺服系统 +232332901 IMPROVED AIMING SERVOS 改良瞄准伺服系统 +3290326175 Improved Air Brakes 改良空气制动器 +2598955031 IMPROVED AIR BRAKES 改良空气制动器 +169627781 Improved Ammo Storage 弹药存储量升级 +2473648600 IMPROVED AMMO STORAGE 弹药存储量升级 +1615043479 Improved Ammo Storage Mk2 弹药存储量升级 MK2 +3060692415 IMPROVED AMMO STORAGE MK2 弹药存储量升级 MK2 +292884218 Improved Ammunition Feed 改良供弹系统 +3704066528 Improved Ammunition Feed 改良供弹系统 +916015842 IMPROVED AMMUNITION FEED 改良供弹系统 +1143933811 IMPROVED AMMUNITION FEED 改良供弹系统 +2038106404 Improved Durability 提升耐久度 +2905541140 Improved Durability 提升耐久度 +2605720433 IMPROVED DURABILITY 提升耐久度 +3373386132 IMPROVED DURABILITY 提升耐久度 +3410171209 Improved Projectiles 改良射弹 +217674314 IMPROVED PROJECTILES 改良射弹 +2847410729 Improved Ready Racks 改良预备弹药挂架 +2348528215 IMPROVED READY RACKS 改良预备弹药挂架 +757071271 Improved Recoil 改善后座力 +331184720 IMPROVED RECOIL 改善后座力 +3868878125 Improved Reloading Process 改良装弹流程 +543125329 IMPROVED RELOADING PROCESS 改良装弹流程 +3913586389 Improved Rounds 改良弹药 +82323331 IMPROVED ROUNDS 改良弹药 +813559744 Improved Servos 改良伺服系统 +1955146623 IMPROVED SERVOS 改良伺服系统 +3681643202 Improved targeting system 改良目标锁定系统 +1643982568 IMPROVED TARGETING SYSTEM 改良目标锁定系统 +214057314 Improves steering for Helldivers during Hellpod deployment. 帮助绝地潜兵在部署绝地喷射舱时更好地把控转向。 +3548404646 Improves weapons handling with less drag on weapon movement. 提升武器操纵性,降低携带武器移动的阻力。 +1657318854 in in +117817201 in multiplayer 模式:多人游戏 +2142785955 in multiplayer 模式:多人游戏 +4205069917 in multiplayer 模式:多人游戏 +2152275488 in multiplayer 模式:多人游戏 +4182686892 in multiplayer 模式:多人游戏 +2829711041 In addition to restoring health, Stims temporarily increase movement speed and damage reduction. 治疗剂除恢复生命值以外,还可以暂时提升移动速度和伤害减免。 +1554222782 In field tests, 84% of users said that the armor improved their posture and self-esteem. 实地测试中,有84%的使用者表示此盔甲改善了他们的体态,也提升了他们的自尊心。 +2372377388 IN GAME 正在游戏 +906120598 In Loadout 正在进行武装配置 +150445754 IN LOADOUT 正在进行武装配置 +3738896347 In Mission 执行任务 +1275858585 In Mission 正在执行任务 +1116992314 In mountainous colonies, domestic variants of this armor are used to throw weather monitoring equipment uphill. 在山区殖民地,这套盔甲的家用版本是用来把天气监测设备丢到山上的好帮手。 +945213331 In Orbit 正在轨道上 +3067375539 In order to conserve medical supplies, Helldivers will deploy with fewer stims until further notice. 为了节约医疗补给,绝地潜兵将携带较少的治疗剂奔赴战场,直至另行通知为止。 +3746555192 In order to support fiscal responsibility, deployment magazine allocation for all weapons will be decreased for a short period of time. 出于履行财政责任的需要,所有武器的弹匣配额都将在短期内降低。 +3538387383 in the 分区: +3606813900 In the nick of time 说时迟那时快 +2808721942 In this abundant garden of flora native to Super Earth, Liberty has taken root on an alien planet. 这花园里长满了超级地球的各种原生植物,有如解放精神在这颗外星球上稳稳扎根。 +1004048437 In this region, orbital bombardment has exposed seams of what appear to be rare and valuable mineral ores. + +We cannot let the Automatons exploit them before the planet is liberated. Get down there and collect soil sample data, to confirm if the material is worth extracting. 该地区在轨道轰炸之后露出的矿层中似乎存在稀有的珍贵矿石。 + +绝对不能放任机器人在我们解放这颗星球前开采这些矿石。前往地表,收集土壤样本数据,确认其开采价值。 +878002307 IN TRANSIT TO MISSION SITE 正在传输至任务地点 +1963764471 In-Mission Time 任务执行时长 +2264859900 IN-WORLD ONLY 仅显示剧情相关文字 +1800244442 Inactive 未激活 +2933843709 Inagaki 稻垣 +4074267144 Inappropriate Online ID 不得体的在线ID +2875412642 INARI 伊纳里 +3040197159 Inbound T-#MINUTES:#SECONDS 抵达倒计时 #MINUTES:#SECONDS +1272518006 Incendiary 燃烧弹 +463816514 INCENDIARY 燃烧弹 +1342481939 INCENDIARY 燃烧弹 +2783978577 INCENDIARY 燃烧弹 +1648363126 INCENDIARY 燃烧弹 +2097258772 INCENDIARY 燃烧弹 +2492608753 INCENDIARY GATLING BARRAGE 燃烧加特林火力网 +1575860721 Incendiary Impact 燃烧冲击弹 +1411256488 INCENDIARY IMPACT 燃烧冲击弹 +75849082 Incendiary MG Devastator 燃烧机枪蹂躏者 +229589206 INCENDIARY MG DEVASTATOR 燃烧机枪蹂躏者 +1227284416 Incendiary MG Devastators 燃烧机枪蹂躏者 +17580256 Incendiary Mines 燃烧地雷 +2772178636 INCENDIARY MINES 燃烧地雷 +3988593673 Incendiary support fed by a massive backpack fuel tank. This heavy flamethrower enables a continuous column of fire to cleanse the battlefield. 由巨型背负式燃料罐提供燃料的燃烧型支援武器。这款重型喷火器能喷射出一道持续的火柱,荡涤净化战场。 +4091309553 Incinerator FRV 炽灼型快速侦察载具 +799811187 INCINERATOR FRV 炽灼型快速侦察载具 +440493654 Include the last #COUNT message(s) from the text chat. 附上文字聊天的最近#COUNT条消息。 +2778815532 Incoming Bombardment 轰击来袭 +3699342800 Incoming DSS Eagle Strike 民主空间站“飞鹰”攻击来袭 +1688107824 Incoming DSS Orbital Bombardment 民主空间站轨道轰炸来袭 +56432069 Incoming Enemy Ship 来袭敌舰 +2992258348 INCOMING MESSAGE FROM SUPER EARTH 来自超级地球的信息 +3287230068 Incoming Meteor Storm 流星风暴即将来袭 +943972559 INCOMING ONLY 仅输入 +288123935 INCONSPICUOUS BLACK EXOSUIT PATTERN 低调黑外骨骼装甲涂装 +1175929609 INCONSPICUOUS BLACK HELLPOD PATTERN 低调黑绝地喷射舱涂装 +1914634922 INCONSPICUOUS BLACK SHUTTLE PATTERN 低调黑运输船舱涂装 +694573192 INCONSPICUOUS BLACK VEHICLE PATTERN 低调黑载具涂装 +4254162676 INCREASE FOOTPRINT 乘胜追击 +114720360 Increase in number of uses of #V_ONE stratagem no longer in effect. #V_ONE战略配备可用次数增加的效果结束。 +667854885 Increase your contribution to The War and your opportunities for additional rewards! 增加你对战争的贡献和获得额外奖励的机会! +1711370733 Increased Enemy Presence 敌人势力增强 +3440356824 Increased Fire Rate 提升射速 +1532989286 INCREASED FIRE RATE 提升射速 +4112944824 Increased Fuel Capacity 提升燃料容量 +1049146617 INCREASED FUEL CAPACITY 提升燃料容量 +593904749 INCREASED IMPACT 扩大影响 +1611270071 Increased Magazine Capacity 提升弹匣容量 +4100826046 Increased Magazine Capacity 提升弹匣容量 +1118540089 INCREASED MAGAZINE CAPACITY 提升弹匣容量 +1394963331 INCREASED MAGAZINE CAPACITY 提升弹匣容量 +4218244224 Increased Overcharge Time 延长超负荷充电时长 +3707094389 INCREASED OVERCHARGE TIME 延长超负荷充电时长 +4000977582 Increased Reinforcement Budget 提高增援预算 +345504525 INCREASED REINFORCEMENT BUDGET 提高增援预算 +2393539781 Increased Shield Power 提升护盾能量 +270843764 INCREASED SHIELD POWER 提升护盾能量 +1042991016 Increased Storage 可携带数量升级 +1355836874 Increased Storage 可携带数量升级 +1978446374 Increased Storage 可携带数量升级 +3062751382 Increased Storage 可携带数量升级 +3272224105 Increased Storage 可携带数量升级 +3382412654 Increased Storage 可携带数量升级 +3583778938 Increased Storage 可携带数量升级 +3802772172 Increased Storage 可携带数量升级 +3955782166 Increased Storage 可携带数量升级 +3975562578 Increased Storage 可携带数量升级 +4153159711 Increased Storage 可携带数量升级 +92480315 INCREASED STORAGE 可携带数量升级 +403784086 INCREASED STORAGE 可携带数量升级 +1039538629 INCREASED STORAGE 可携带数量升级 +1194932624 INCREASED STORAGE 可携带数量升级 +1821048480 INCREASED STORAGE 可携带数量升级 +1862606268 INCREASED STORAGE 可携带数量升级 +2399729328 INCREASED STORAGE 可携带数量升级 +3339618372 INCREASED STORAGE 可携带数量升级 +4005343138 INCREASED STORAGE 可携带数量升级 +4037877717 INCREASED STORAGE 可携带数量升级 +4145747035 INCREASED STORAGE 可携带数量升级 +3723801509 Increased Storage Mk2 可携带数量升级 MK2 +3058287648 INCREASED STORAGE MK2 可携带数量升级 MK2 +2044687034 Increases all Helldivers' effective radar range. 扩大所有绝地潜兵的雷达有效范围。 +2017142171 Increases all Helldivers' stamina capacity and recovery. 提高所有绝地潜兵的耐力上限和恢复力。 +4096946733 Increases ammo capacity of all weapons by #BONUS. Does not affect weapon backpacks. 所有武器的弹药容量增加#BONUS。武器背包除外。 +3720748223 Increases ammo for all Sentry stratagems by #VALUE%. 所有哨戒炮战略配备的弹药量增加#VALUE%。 +2039022973 Increases burning temperature of incendiary weapons by lacing fuel with a precisely-formulated compound of thermite, white phosphorus, capsaicin, allyl isothiocyanate, and 19 other accelerants. 在燃料中加入精确配制的铝热剂、白磷、辣椒素、异硫氰酸烯丙酯和19种其他助燃剂,提高燃烧型武器的燃烧温度。 +2495362886 Increases grenade carrying capacity for all Helldivers. 提高所有绝地潜兵的榴弹携带容量。 +1641080868 Increases health of Sentry stratagems by #VALUE%. 哨戒炮战略配备的生命值提升#VALUE%。 +3264472874 Increases initial inventory and holding capacity of stims by #SIGN#BONUS. 治疗剂的初始库存和持有上限增加#SIGN#BONUS。 +4144979903 Increases initial inventory and holding capacity of throwables by #BONUS. 投掷武器的初始库存和持有上限增加#BONUS。 +117522071 Increases melee damage by #BONUS. 近战伤害提高#BONUS。 +301174212 Increases minimap enemy ping radius by #VALUE%. 小地图上标记敌人的半径范围扩大#VALUE%。 +4106201101 Increases number of Eagle stratagem uses per Rearm by #VALUE. 每次重新武装后,“飞鹰”战略配备的可使用次数增加#VALUE次。 +2523202457 Increases orbital targeting speed by updating cannon targeting software to premium version. 轨道加农炮用于瞄准目标的软件更新到高级版本,提高轨道锁定目标的速度。 +3297369983 Increases point-of-interest identification range by #BONUS. 探索点识别范围扩大#BONUS。 +3205286516 Increases reload speed of primary weapons by #BONUS. 主要武器的装弹速度提高#BONUS。 +347262667 Increases reload speed of support weapons by #BONUS. 支援武器的装弹速度提高#BONUS。 +3466014766 Increases sidearms reload speed by #BONUS. 副武器重装速度提高#BONUS。 +2230489000 Increases stim effect duration by #BONUS. 治疗剂效果持续时间延长#BONUS。 +1126252397 Increases the damage radius on explosions caused by orbital Stratagems by #VALUE%. 轨道战略配备引爆时的伤害半径扩大#VALUE%。 +3494849629 Increases the number of available reinforcements. 增加可用增援次数。 +1467959331 Increases the range of the Helldiver Radar by equipping it with a high-powered Plutonium-210 battery. 配备高能钚-210电池,装备后可扩大绝地潜兵的雷达探测范围。 +190436328 Increases the speed and duration of slides. 可提升滑铲的速度与持续时间。 +878434341 Increases the time between enemy encounters. 延长敌人遭遇战之间的时间间隔。 +3847398060 Increases the wearer's walking and running speed. 可提升穿着者的步行与奔跑速度。 +4083283407 Increases throwing range by #BONUS. 投掷距离延长#BONUS。 +2356747919 Increases weapon ergonomics to reduce drag on weapon movement. 通过提升武器的人体工学性能,降低携带武器移动的阻力。 +2249405204 Incriminating evidence recorded 已录下罪证 +581308584 INDEPENDENCE 独立市 +1923407081 Independence Bringer 独立先驱 +1498594868 INDEPENDENCE BRINGER 独立先驱 +2005465431 INDEPENDENCE BRINGER 独立先驱 +5488478 INDIRECT FIRE EXERCISE 间接火力演练 +1778610710 INDIRECT FIRE EXERCISE 间接火力演练 +2650770347 INDUSTRY ALLATEED 阿拉提德工业 +2313692969 Infectious Disease Expert Calls Terminid Spread An "Epidemic". 传染病专家称终结族扩张为“流行病” +3896690221 Infested Tower 侵染塔巢 +1000270605 INFESTED TOWER 侵染塔巢 +1770066465 Infested Towers 侵染塔巢 +2262724740 Infiltrate Automaton territory and destroy their fuel and munitions stockpiles. 潜入机器人领地,销毁其库存燃料和弹药。 +2499576962 INFILTRATE ILLUMINATE LAIR 潜入光能者巢穴 +1329086705 Infiltrate the site and acquire undeniable evidence of the enemy's unforgivable crimes. 潜入现场,获取敌军不可饶恕罪行的铁证。 +844757833 Infiltrate this site to acquire high-value intel, and extract with it in your possession. 潜入此地获取高价值情报,携带情报撤离。 +2542093959 INFILTRATOR 深入敌阵 +2332776870 INFLAMMABLE 易燃易爆 +763481946 Influence (Community) 影响力(社区) +562487815 Influence (Max) 影响力(最大) +761201047 Influence (Self) 影响力(自我) +1212788409 Influence (Start) 影响力(初始) +2085936962 Info Feed Visibility 动态信息可视度 +277000976 INFORMATION ON THE ENEMY 敌方情报 +4164770624 INGMAR 英格玛 +440785871 INGMAR FREED +Ingmar has been freed from the Automatons. Take the fight to the next planet. 英格玛已解放 +英格玛已经挣脱了机器人的铁爪。该去下一颗星球作战了。 +4219156059 INGMAR LOST +The Automatons have taken Ingmar. A dark day for Managed Democracy. 英格玛沦陷 +机器人已然占领英格玛,这是管理式民主史上黑暗的一天。 +923579868 INGMAR UNDER ATTACK +The Automatons are attempting to steal Ingmar from our noble citizens. Do not let them, Helldivers. 英格玛遭到袭击 +机器人企图从我们高贵的公民手中窃走英格玛,不要让它们得逞,绝地潜兵。 +3357769222 Ingress-81 进军-81 +278490209 INGRESS-81 进军-81 +1269865237 Initial Helldiver Push Against Terminids "Unequivocal Success." 绝地潜兵进攻终结族的初始计划“取得了绝对的胜利” +1349342142 INITIATE AREA SCAN 启动区域扫描 +1767301278 Initiate Data Transmission 启动数据传输 +1527626864 INITIATE DATA WIPE 启动数据抹除 +737422099 INITIATE DRILL SEQUENCE 启动钻机程序 +1521574653 INITIATE EMERGENCY BACKUP 启动紧急备份 +725836760 Initiate Evacuation 启动疏散程序 +2966650247 INITIATE EXTRACTION 开始撤离 +1713443279 Initiate Fire Sequence 启动开炮进攻程序 +1958433982 Initiate Firing Sequence 启动发射程序 +183799415 Initiate off-planet evacuation of high-value artifacts, and defend the site until evacuation is complete. 启动高价值文物撤离星球的程序,并保卫阵地,直至撤离完成。 +3111481652 Initiate off-planet evacuation of high-value assets, and defend the site until evacuation is complete. 启动高价值目标撤离星球的程序,并保卫阵地,直至撤离完成。 +4173320741 INITIATE POWER SURGE 启动电涌 +4176745187 INITIATE POWER TRANSFER 开始输电 +1715450202 INITIATE PRODUCTION SEQUENCE 启动生产序列 +1313086161 Initiate to download data to encrypted SSSD 启动并将数据下载至加密超级固态硬盘 +2940681543 INITIATING ARTILLERY SYSTEM 正在启动大炮系统 +511262727 INITIATING FTL JUMP 正在启动超光速跃迁 +3795917234 Inject Dark Fluid beneath the Supercolony's crust to destroy it once and for all. 将暗液体注入超级拓殖地的地壳内,彻底将其摧毁。 +524457746 Injecting Freedom Protocols (#COUNT remaining) 注入自由协定(还剩#COUNT) +240647037 Injury Widget Visibility 伤势轮盘可视度 +2911170777 INNER RADIUS 内半径 +3173746046 INPUT ACCESS CODE 输入访问代码 +3067058685 Input Access Code: #OTHER 输入访问代码:#OTHER +1095612653 INPUT ACTIVATION SEQUENCE 输入启动程序 +2474759065 Input Callouts 输入口令 +577217099 Input code on terminal 在终端上输入代码 +3100466286 Input code to authorize access 输入代码,授权访问 +2526243565 Input code to authorize ejection 输入代码,授权弹出 +664862597 Input code to finalize virus upload 输入代码,上传病毒 +3124835968 Input code to raise satellite tower 输入代码以抬升卫星塔 +1551824163 Input Device 输入设备 +3953023005 INPUT LAUNCH CODE 输入发射代码 +1776187287 Input launch code: #OTHER 输入发射代码:#OTHER +3837285953 INPUT SYSTEM LOGIN CODE 输入系统登录码 +782587919 INPUT TYPE 输入类型 +676345360 INSERT AMMO 插入弹药 +1255707028 Insert SSSD into hatch 将超级固态硬盘置入舱门 +1255637022 Insert SSSD into receptacle 将超级固态硬盘置入插槽 +1633175426 Insert Vessel into Drill 将容器置入钻机 +541984075 Inside of PLACES OF INTEREST you can find SUPPLIES and SAMPLES. 你可以在特殊地点找到补给和样本。 +1970135019 Inside the collar is embroidered: "Wherever I may plant my shield, know that I will never yield," and "machine washable." 衣领内侧绣有“无论护盾所立何方,我绝不会屈膝投降”和“可机洗”字样。 +3026051750 Inside this towering facility, Cyborgs are grown in pod-like artificial wombs. 在这座高耸的设施内部,生化人在舱形人造子宫中完成培育生长。 +3713896677 Inspect 查看 +2298864128 Inspect 查看 +3224188307 INSPECT 查看 +1775242221 Inspect (Hold) 查看(按住) +3470206455 Inspect (Toggle) 查看(切换) +2647399470 Inspired by the trailblazing agents of the Super Earth Terraforming Company. These rugged adventurers surveyed hostile new planets during the post-GW1 Great Expansion era, preparing the untamed frontier for rapid and efficient assimilation. 设计灵感源自超级地球行星地球化公司的先驱者。在第一次星系战争后的大扩张时期,这些坚韧的冒险家勘测了许多充满敌意的新星球,为快速高效地同化未开发边境奠定基础。 +3667791748 INSPIRED LABORERS 劳动者觉醒 +1185874471 INSTALL ROOTKIT 安装后门程序 +3866735348 Installs a revolving cylinder loading system, with each chamber housing a different ammunition type. 安装旋转弹巢装填系统,每一个弹膛都装载一种不同的弹药。 +2824618998 Installs electronic actuators that augment the standard method of manual, foot-operated Hellpod steering. 安装电子致动器,增强脚踏式手动转向型绝地喷射舱的标准操作。 +877841760 INSUFFICIENT CURRENCY 货币不足 +1898061859 Insufficient donation funds 捐赠资源不足 +1873750698 Insufficient fuel 燃料不足 +4128605319 INSUFFICIENT FUNDS 资源不足 +3919356206 INSUFFICIENT SUPER CREDITS 超级货币不足 +1847246113 INT 枪内 +2043079863 INTEGRATED EXPLOSIVES 集成炸药 +1722220547 Integrated Extinguishers 集成灭火器 +3744156159 INTEGRATED EXTINGUISHERS 集成灭火器 +4027481141 Integrates moderate doses of amphetamines and androgenic steroids into diet of loading crew, leading to increased pace, focus, & stamina, among other effects. 将适量安非他明和雄激素类固醇加入船员的饮食中,获得各方面的提升效果,包括速度、专注力和耐力等。 +1723388426 Intel 情报 +462091496 INTEL 情报 +2932445209 INTEL EXTRACTED 获取情报 +1387716743 INTEL EXTRACTED BY 情报提取人: +1374843215 Intel has pinpointed the storage of two highly valuable products at this location: high-grade platinum and fusion batteries. Produced at extremely high cost, the materials are intended to facilitate the mass murder of innocent civilians. It is imperative that they are seized before this can happen. + +Raid the facility. Secure and extract platinum bars and fusion batteries on-site. 情报部门已确定此处储存着两种高价值物品:高纯度铂金和聚变电池。这些材料耗费巨资生产,敌人意图用来大规模屠杀无辜平民。必须赶在它们达成目标之前夺得这些材料。 + +突袭基地。夺取并撤走现场的铂金条和聚变电池。 +1748495489 Intel indicates a massive and covert Automaton industrial undertaking, which the enemy has taken extreme measures to keep hidden. Further intel is located on the ground at this location. Low orbit interdiction weaponry makes prolonged Destroyer deployment impossible. Once deployed, you're on your own. + +This operation is extremely dangerous. But it is imperative we identify the nature and locations of the Automaton scheme. 情报显示机器人正在秘密开展大规模工业项目,而且已采取极端措施进行隐蔽。在此处的地面上可获取更多情报。低轨道拦截武器使驱逐舰无法长时间部署。一旦部署,接下来就只能靠你们自己了。 + +此次行动极其危险。但我们必须查明机器人阴谋的性质和地点。 +1673870250 Intel indicates that the Automatons are stockpiling ammunition in this location. 情报显示机器人正在此地囤积弹药。 +3717706265 Intel Package 情报包裹 +427985058 INTEL PACKAGE 情报包裹 +201925483 Intel PDA 情报PDA +4293423783 INTEL PDA 情报PDA +717591301 Intel Recovered 已找回情报 +232695806 INTEL RETRIEVED - OPPORTUNITIES REVEALED 已取回情报并发掘机遇 +4208938528 Intelligence 情报 +2120160660 INTELLIGENCE BRIEF 情报简报 +3863269762 INTELLIGENCE BRIEF +A new strain of flying Terminids has suddenly appeared across all Terminid planets, with no prior warning or indication of any kind. While the Ministry of Intelligence has always known this was a possibility, the abruptness of the evolution indicates a high possibility of dissident concealment. + +The deployment of Termicide was fortuitously timed—doubtlessly, it averted an even worse evolution. Helldivers are advised to exterminate these mutations whenever encountered. 情报简报 +所有终结族星球上突然毫无预兆地进化出全新的飞行种终结族。情报部一直知晓终结族的突变可能,如今情况突然发生,表明其内部极可能隐藏了异见分子。 + +我们意外凑巧地部署了灭虫终结剂,无疑给终结族的突变加了一道障碍,防止产生更严重的后果。但凡碰上这些突变体,建议绝地潜兵都要及时扑杀。 +2389664653 INTELLIGENCE BRIEF +Be advised: we have received reports of Terminid hives spawning bugs with limited airborne capabilities. This is likely a random and short-lived genetic anomaly. Nevertheless, Helldivers are ordered to exterminate these strains completely, in the unlikely event they are encountered. 简报 +注意:我们接到报告,发现终结族虫窝正在孕育拥有一定飞行能力的虫族。这很可能是短暂出现的随机基因异变。无论如何,如若遇到这类突变种,绝地潜兵必须将其完全歼灭。 +2842217344 INTELLIGENCE BRIEF +Strains of flying Terminids are becoming more prevalent, especially in vicinity of TCS installations. It is fortunate that the TCS was implemented in time, or this problem would undoubtedly have been much worse. Helldivers are advised to vertically expand their situational awareness when on Terminid planets. 简报 +飞行终结族的突变种越来越普遍,尤其在部署TCS附近的区域。幸好TCS已及时完成部署,否则情况必将更为严峻。在终结族占领的星球上,请绝地潜兵留意垂直方向上的状况,以便掌握战场动态。 +4209515439 INTELLIGENCE BRIEF +The Aerial Terminid Subvariant, dubbed "Shriekers," has become a significant and pervasive strain, spreading across all Terminid planets. The Terminid's tyrannical instinct defies even the laws of nature, and now they infest our spacious skies. Helldivers are advised to stay vigilant for Shrieker nests and purge any they come across. 简报 +飞行终结族亚种,别称为“尖啸虫”,它们已成为随处可见的变异个体且构成严重威胁,蔓延至终结族占领星球的各个角落。终结族凭借暴政本能藐视自然的规则,如今还侵袭了我们广阔的天空。请绝地潜兵警惕尖啸虫的巢穴,一旦遇上这类敌人,立即将其清除。 +50882734 INTELLIGENCE EXTRACTED: 获取情报数: +2674283529 INTELLIGENCE REPORT 情报汇报 +3575339405 Intense blizzards reduce mobility and moderately reduce visibility for both enemy and friendly units. 强暴风雪会削弱行动能力并中度降低能见度,敌我双方都将受影响。 +3408022038 Intense Heat 极暑 +1248749717 INTENSE HEAT 极暑 +3567262339 Intense snowstorms reduce visibility. 强暴风雪会降低能见度。 +1396860769 INTER-GALACTIC NETWORK NODE 星际网络节点 +1677577122 Interact 互动 +1014448518 INTERACT 互动 +2230718828 INTERACT 互动 +2249866370 INTERACT 互动 +3349635337 Interact with the main terminal 与主终端交互 +3820161195 Interaction Visibility 互动可视度 +2719619016 INTERCEPT CONVOY 拦截车队 +3585962803 INTEREST 特殊地点 +3885994214 INTEREST 利息点 +2831181433 Interior 内部 +3178030114 INTERNAL BLEEDING 内出血 +3753208447 INTERNALS 枪内 +2169316289 Interplanetary Data Transmission Ready 星际数据传输就绪 +1299699882 INTO THE GALAXY 向星系进发 +104315069 INTREPIDNESS 勇魄市 +456532099 Introduce Managed Democracy to the Void. 将管理式民主传播到寂域。 +3062607332 Invading Illuminate forces have unleashed Harvesters upon the city. These intolerant machines patrol the streets in this area, devastating once-peaceful neighborhoods and murdering innocent civilians. Destroy them, and reclaim control of this sector. 入侵的光能者部队已在城市投放猎杀器。这些偏狭的机器正在该区域的街道巡逻,摧毁曾经安宁的社区,屠杀无辜平民。消灭它们,夺回该分区的控制权。 +3466954372 Invalid 无效 +4175551779 Invalid Authorization for PlayStation™Network - Token Empty PlayStation™Network的授权无效 - 令牌为空 +207134742 Invalid Authorization for PlayStation™Network - Token Format PlayStation™Network的授权无效 - 令牌格式 +3912818914 Invalid Authorization response from PlayStation™Network, no Claims received 来自PlayStation™Network的授权响应无效,未收到验证声明。 +2113380582 Invalid Authorization response from PlayStation™Network, no Identity received 来自PlayStation™Network的授权响应无效,未收到验证信息。 +3131746521 INVALID DROP POINT 无效降落点 +1960029036 INVASION CAMPAIGN 入侵战役 +3559900755 INVASION CAMPAIGN 入侵战役 +91998981 INVASION CAMPAIGN PROGRESS 入侵战役进度 +810565547 INVASION FLEET 入侵舰队 +2373683900 INVASION LEVEL 入侵等级 +1770619980 INVENTORY OPTIONS 物品栏选项 +4236299635 Inventory Value 生涯消费 +1152275333 Invert Look (Horizontal) 视角翻转(水平) +3565396591 Invert Look (Vertical) 视角翻转(垂直) +2055085405 Invert Motion Sensor (Horizontal) 动态感测器翻转(水平) +53610604 Invert Motion Sensor (Vertical) 动态感测器翻转(垂直) +1105750510 Invert Mouse (Horizontal) 鼠标翻转(水平) +4108551927 Invert Mouse (Vertical) 鼠标翻转(垂直) +1558080264 Invert Mouse Scope (Horizontal) 开镜视角鼠标翻转(水平) +2028428942 Invert Mouse Scope (Vertical) 开镜视角鼠标翻转(垂直) +2944144286 Invert Scope (Horizontal) 开镜视角翻转(水平) +1417921078 Invert Scope (Vertical) 开镜视角翻转(垂直) +88572002 INVERTED 已翻转 +3536920703 Inverts left and right control of mouse direction in First Person View (FPV). 在第一人称视角(FPV)下,鼠标左右方向翻转。 +2011444144 Inverts left and right control of mouse direction. 鼠标左右方向翻转。 +4128841278 Inverts left and right of camera direction in First Person View (FPV). 在第一人称视角(FPV)下,视角左右方向翻转。 +2987263236 Inverts left and right of camera direction. 视角左右方向翻转。 +54377168 Inverts left and right of Motion Sensor control direction. 动态感测器左右方向翻转。 +2728372259 Inverts up and down control of mouse direction in First Person View (FPV). 在第一人称视角(FPV)下,鼠标上下方向翻转。 +3767787385 Inverts up and down control of mouse direction. 鼠标上下方向翻转。 +323048555 Inverts up and down of camera direction in First Person View (FPV). 在第一人称视角(FPV)下,视角上下方向翻转。 +3508396943 Inverts up and down of camera direction. 视角上下方向翻转。 +2006818392 Inverts up and down of Motion Sensor control direction. 动态感测器上下方向翻转。 +1595355818 Investigate and Upload Findings 调查并上传发现的结果 +1614411709 Investigate Rogue Research Station 调查叛变科研站 +4036356053 INVESTIGATE VOID PLANET 调查寂域星球 +4233226811 INVESTIGATE VOID PLANET 调查寂域星球 +4071276717 INVESTMENT 投资点 +1936635273 Invite 邀请 +2966569319 INVITE ONLY 仅限邀请 +3080280732 INVITE SENT 已邀请 +1897366347 Invite to Platoon 邀请加入特战排 +4129012287 INVITE TO SQUAD 邀请入队 +3150375015 Ion Storm In Progress 离子风暴正在形成 +4077571604 ION STORMS 离子风暴 +456680010 Ion storms intermittently disable Stratagems. 离子风暴会间歇性导致战略配备无法使用。 +3525702929 IPTUS SECTOR 伊普都斯分区 +1905935376 IRIDICA 艾丽迪卡 +710416841 IRO 伊罗 +2872599216 Iron Fist 铁拳 +3366822638 Iron Sight 机械瞄具 +1178576085 IRON SIGHT 机械瞄具 +1636541425 IRREGULAR VOTELESS BEHAVIOR 异常无票者行为 +3246104028 IRULTA 艾鲁尔塔 +1768487578 ISEGORIA 思言城 +4210400742 Isolated Exostorm pockets are materializing across the planet and rapidly gaining momentum. 多个异界风暴区分别在星球各地出现,迅速积聚势头。 +406058570 ISOLATING NETWORK 正在隔离网络 +2973387471 ISSUED BY THE MINISTRY OF PROSPERITY 由真理部颁发 +1011072076 Issued to the rapid-response enforcement wings of the Ministry of Prosperity. This armor provides the structural integrity necessary for aggressive pursuit maneuvers and the forceful redirection of traffic—whether civilian, military, dissident or hostile. 配发给繁荣部下属快速响应执法支队。这套护甲提供侵略性追击机动和强行疏导交通所需的结构强度——无论对方是平民、军人、异见分子还是敌军。 +3900747663 It is only a matter of time before this planet grants us safe passage into the Void. The Illuminate have deployed a massive fleet to drive our forces back and prevent the completion of this monumental breakthrough. + +Put an end to their interference. Hold this planet at all costs. 我们借助这颗星球打开安全进入寂域的通道已指日可待。光能者已派出一支大型舰队,企图击退我方部队,阻止我们完成这一重大突破。 + +终结他们的阻挠。不惜一切代价,守住这颗星球。 +3860004010 It is said that only the truly Democratic can lift this cape to their shoulders. 据说,只有真正的民主主义者才能披上此披肩。 +1836967265 It is well-documented that soldiers raised on harsh planets have an advantage when fighting in similar environments; this insight is foundational to the Democratic Youth Scouts Exchange Program. 有充分记录表明,在恶劣星球上成长的士兵在类似环境中作战时具有优势。这样的洞察为民主青少年童子军交流计划奠定了基础。 +651948458 It only takes ONE TRAITOR to destroy Utopia. + +The Ministry of Unity. 一个叛徒足以瓦解乌托邦。 + +团结部 +1638482880 It pays to be a straight shooter—angled fire might glance off your target or even ricochet into your squadmates. 直线射击效果更好,而斜射可能会让子弹从目标身上擦过,甚至有可能反弹到队友身上。 +3751013188 It will feel like you're out there, fighting beside them from your home! 你会感觉虽然身在家中,心却在前线和他们并肩作战! +1280579303 It's the only way to be sure... 别无他选… +1517760049 ITALIANO ITALIANO +339176381 ITEM CLAIMED 已领取物品 +269698166 ITEM INFO 物品信息 +3394549050 ITEM OWNED 已拥有物品 +176263259 ITEM RECEIVED 已收到物品 +1627611489 ITEM REVIEWS 商品评价 +1577434797 ITEM TRAITS 物品特性 +3724530479 ITEMS DROPPED 掉落物品 +501371246 Its unclear if this Automaton can still perceive external stimuli. There's no telling how long it will remain in this state before its battery expires. 这个机器人是否还能感知外部刺激是个未知数。不知道它在电池耗尽之前能保持这种状态多久。 +147228259 IVIS 艾维斯 +833021144 IX-VOIDWALKER IX-寂域行者 +663970055 J. Bender J.本德 +1429123431 Jaeger 耶格 +325188328 Jammed 受到干扰 +2649749292 Jammed Piñata 满载惊喜的皮纳塔 +4066337545 JAMMED PIÑATA 满载惊喜的皮纳塔 +2582160374 Jammer deactivated 干扰装置已关闭 +3587284262 Jan 1月 +972834544 Jansson 扬松 +227909627 January 1月 +1812892752 JAR-5 JAR-5 +2673481423 Jet Brigade Commissar 喷气旅机械统帅 +1615896897 JET BRIGADE COMMISSAR 喷气旅机械统帅 +1849355488 Jet Brigade Commissars 喷气旅机械统帅 +2384335881 JET BRIGADE FACTORIES 喷气旅孵化厂 +3388563093 Jet Brigade MG Trooper 喷气旅机枪装甲兵 +602658912 JET BRIGADE MG TROOPER 喷气旅机枪装甲兵 +4052291412 Jet Brigade MG Troopers 喷气旅机枪装甲兵 +3825421242 Jet Brigade Raider 喷气旅奇袭者 +326167874 JET BRIGADE RAIDER 喷气旅奇袭者 +391151086 Jet Brigade Raiders 喷气旅奇袭者 +2087200088 Jet Brigade Trooper 喷气旅装甲兵 +454992428 JET BRIGADE TROOPER 喷气旅装甲兵 +2825265110 Jet Brigade Troopers 喷气旅装甲兵 +3894418747 JIN XI SECTOR 锦栖分区 +2480962503 Job's done! 完成任务! +4014793201 JOG 小跑 +3782673150 Johansson 约翰松 +3818170022 Join 加入 +1289174472 JOIN FAILED 加入失败 +3532961159 JOIN MISSION 加入任务 +2527619638 JOIN SQUAD 加入小队 +1255597413 Join this server and travel to their ship? 要加入本服务器并登上对方的飞船吗? +3997222774 Joined. 加入成功。 +1665678649 Joining Session. 正在加入游戏。 +3063562552 Joint Operation 联合行动 +3135826091 JOINT OPERATION 联合行动 +3617271490 JOINT OPERATION AVAILABLE 可参与的联合行动 +3768231542 Judge 审判 +1711799005 JUDGMENT DAY 审判日 +2731424545 JUDGMENT DAY 审判日 +1713696910 Jul 7月 +1224007776 JULHEIM 尤尔海姆 +2554560399 July 7月 +2535264136 JUMP 跳跃 +2872120750 Jump Pack 喷射背包 +1369742626 JUMP PACK 喷射背包 +2204198870 JUMP PACK 喷射背包 +341723394 Jump Pack stratagem availability has ended. 现已无法使用“喷射背包”战略配备。 +1845166933 Jump to Current Level 跳到当前关卡 +1409602703 Jump-starts Hellpod firing with an immediate TNT detonation at the time of launch. 快速启动绝地喷射舱发射程序的同时引爆TNT。 +3253001350 Jun 6月 +2887971199 June 6月 +3059762375 JURISPRUDENCE 律裁城 +2054687221 JUST NOW 刚刚 +2737616607 Justice 正义 +4288214437 JUSTICE 正义 +2041808424 JUSTICE FOR ALL 全民正义 +1710870229 K K +2293621472 K-2 K-2 +2696171705 K-9 K-9 +2744645738 K-9 K-9 +2903742424 KALASATAMA 渔港 +882143696 KALASATAMA PORT 卡拉萨塔马港 +238952563 Karen0057 卡伦0057 +916505227 KARLIA 可利亚 +614560108 KARON BAY 凯伦湾 +335550317 KDM-500 Outrider KDM-500“先驱骑兵” +4201560668 KDM-500 OUTRIDER KDM-500“先驱骑兵” +2707764633 KDM-73 Dragoon KDM-73“龙骑兵” +143843098 KDM-73 DRAGOON KDM-73“龙骑兵” +2006721785 KDM-763 Pacesetter KDM-763“领跑者” +2830999836 KDM-763 PACESETTER KDM-763“领跑者” +3573408908 Keep an ear open for TREASON. 时刻警惕叛国。 +4097729569 Keep hands away from extractors 请勿触碰提取器 +315647061 Keep open flames away from missile 导弹周围严禁明火 +2053947121 Keep their tentacles off our children! 不能让它们将触手伸向我们的孩子! +2208700795 Keep yourself updated with the latest happenings in the Galactic War through the News Feed. + +It automatically displays the latest events! 请通过新闻动态随时掌握星系战争的最新动态。 + +最新战事会自动显示动态中! +3743423561 Keeper 看守人 +1317730141 KEID 九州殊口增七 +3772226613 Kelder 凯尔德 +385118865 KELLA METAMORPH 凯拉蜕变城 +4053729028 KELVIN SECTOR 凯尔文分区 +3603869762 KELVINOR 开尔文奥尔 +1883008426 KEPLER-389b 开普勒389b +1420913901 KEPLER-391b 开普勒391b +3861880868 KEPLER-392b 开普勒392b +3350036223 KEPLER-393b 开普勒393b +3737295549 KEPLER-394b 开普勒394b +288067031 KEPLER-395b 开普勒395b +1527892006 KEPLER-396b 开普勒396b +723389311 KEPLER-397b 开普勒397b +3750017930 KEPLER-398b 开普勒398b +4170304953 KEPLER-399b 开普勒399b +2732935113 KEPLER-400b 开普勒400b +539324145 KERTH SECUNDUS 克斯次星 +756866805 KESUMA 花都 +267703664 Key 键 +1905699871 KEY + MOUSE 键盘+鼠标 +2064052499 KEYCARD 钥匙卡 +356613305 KHANDARK 勘达尔克 +4093374049 KHARST 喀斯特 +3673962713 Khatib 哈提卜 +3713933293 KICK (HOLD) 移除(长按) +1773377985 Kill #COUNT #ENEMY#LOCATION_PRE#LOCATION#LOCATION_POST#EQUIP_PRE#EQUIP#EQUIP_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI 击杀#COUNT个#ENEMY#LOCATION_PRE#LOCATION#LOCATION_POST#EQUIP_PRE#EQUIP#EQUIP_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI +1039710571 Kill #COUNT Bug Alpha Chargers 击杀#COUNT只虫族的领头强袭虫 +3509557030 Kill #COUNT Bug Shriekers 击杀#COUNT只虫族的尖啸虫 +873419093 Kill #COUNT Bug Striders 击杀#COUNT只虫族的阔步虫 +1535290886 Kill #COUNT enemies on a mission 在一次任务中击杀#COUNT名敌人 +2742665218 Kill #COUNT enemies using #REF 利用#REF击杀#COUNT名敌人 +3253420627 Kill #COUNT enemies with a single grenade 仅使用一枚榴弹击杀#COUNT名敌人 +1788537953 Kill #COUNT enemies with a single magazine 仅使用一个弹匣击杀#COUNT名敌人 +3289084565 Kill #COUNT enemies with a single orbital stratagem usage 仅使用一次轨道战略配备击杀#COUNT名敌人 +1566218727 Kill #COUNT enemies with Eagle stratagems 利用“飞鹰”战略配备击杀#COUNT名敌人 +2671077924 Kill #COUNT enemies with Eagle stratagems during a single mission 在单次任务中利用“飞鹰”战略配备击杀#COUNT名敌人 +1305262746 Kill #COUNT enemies with Hellpods 利用绝地喷射舱击杀#COUNT名敌人 +1942991823 Kill #COUNT enemies within 10 meters from you with the Eagle 利用“飞鹰”击杀距离你10米内的#COUNT名敌人 +2652312908 Kill #COUNT flying enemies with support weapons 利用支援武器击杀#COUNT名空中的敌人 +662371574 Kill #COUNT heavy or massive enemies 击杀#COUNT名重型武装或体型庞大的敌人 +235196461 Kill 100 enemies using fire damage during the same mission. 在同一项任务中通过灼烧伤害击杀100名敌人。 +3045882396 Kill 150 enemies during the same mission. 在同一项任务中击杀150名敌人。 +3164004999 Kill 25 enemies with one stratagem. 利用一项战略配备击杀25名敌人。 +3552395834 Kill 5,000 enemies. 击杀5000名敌人。 +4011519829 Kill a bug warrior with a shotgun within 1 meter. 使用霰弹枪在1米内击杀一只武斗虫。 +2538735225 Kill a Charger with a resupply pod. 用重新补给舱消灭一只强袭虫。 +3690650666 Kill a target at a distance of over 100m. 击杀一名100米外的目标。 +1697648178 Kill all Terminids 击杀所有终结族 +477609176 Kill Automatons and Cyborgs to reduce their numbers. 击杀机器人和生化人,削减它们的数量。 +2945096755 Kill Automatons to reduce their numbers. 击杀机器人,削减它们的数量。 +1566238134 KILL BUGS 击杀虫族敌人 +622764925 Kill bugs before they get close. Remember, nothing protects your personal space better than bullets. 要在虫族靠近之前将其击杀。要记住,子弹最能保护你的个人空间。 +2242924206 Kill Illuminate forces to reduce their numbers. 击杀光能者部队,削减它们的数量。 +2470414457 Kill Illuminate Overseers 击杀光能者的监视者 +1954310570 Kill it with fire! 烧死它! +2532564609 Kill Score #COUNT 击杀得分#COUNT +2330533729 Kill Terminids to thin their numbers. 击杀终结族,削减它们的数量。 +893045708 Kill the Terminid 击杀终结族 +2654994242 Killed by #KILLER 已被#KILLER击杀 +2916977728 Killed Hive Lord 击杀霸王虫 +3927705822 Killed x#AMOUNT 成功击杀x#AMOUNT +2107318609 KILLJOY TOWN 克乔伊镇 +2455424748 KILLS: 杀敌数: +3198311629 Kimura 木村 +4271562806 KINABATANGAN 京那巴当岸 +205828823 KINETIC DISPLACEMENT MITIGATION 动能位移减缓 +3730705798 King 之王 +3091329534 KIRRIK 基里克 +1560396759 KLAKA 5 克拉卡5 +131300950 KLEN DAHTH II 克伦达斯II +4255330725 KMH 公里/时 +1572521316 KNETH PORT 克奈斯港 +3221073801 Knight 骑士 +506793925 Knight 骑士 +300433678 KNIGHT 骑士 +3495940927 KNIGHT'S HONOR 骑士荣誉城 +695602273 Knittingiscool111 编织好酷111 +2881307731 KNOW THEIR SECRETS 洞察一切 +933811914 KNOW YOUR ENEMY 知己知彼 +2110070363 KNOWLEDGE IS POWER 知识就是力量 +1256884337 KODIAK FALLS 科迪亚克瀑布 +1358608754 KORPUS SECTOR 科普斯分区 +126536216 KORV 科尔脯 +3115822437 KRAKABOS 克拉克博斯 +1857755083 KRAKATWO 克拉克图 +2477683558 Kravchenko 克拉夫琴科 +1570376244 KRAZ 轸宿四 +3626758819 KUMA 天棓二 +2949618488 KUPER 库珀 +4207753621 KURRI KURRI 库里库里 +3645058219 L 升 +492741105 L. ARM 左臂 +2801857303 L. LEG 左腿 +2611934716 L.SHLD 左肩 +1125878261 L'ESTRADE SECTOR 莱斯特拉德分区 +2582617403 LACAILLE SECTOR 拉凯欧分区 +2473806447 LACED STRAIT 莱醒海峡 +2708347302 Lady 圣女 +4160790160 LAELIA 蕾丽兰城 +3089011827 LAGERLÖF CITY 拉格洛夫城 +2755209388 LAMB'S PATCH 羔原 +4185462613 LAMBAST 兰巴斯特 +3966614504 LAMBS TO THE SLAUGHTER 待宰羔羊 +3027588906 LANDMINE TESTING 地雷测试 +3849358231 Language 语言 +4173700458 LARGE 大 +120146337 Large Ammo-Drum 大容量弹鼓 +1947661884 LARGE AMMO-DRUM 大容量弹鼓 +3082458801 Large Drum 大型弹鼓 +3969048007 LARGE DRUM 大型弹鼓 +1126016406 Large enemies now have a small chance of dropping Samples on death. Capped at #VALUE drops per mission. 大型敌人死亡时有小概率掉落样本。每次任务最多掉落#VALUE。 +4251523721 Large Plasma Bolt 大型等离子弹 +3783536724 LARGE PLASMA BOLT 大型等离子弹 +3075043955 Large quantities of eggs are located in this area. Use any means necessary to destroy them. 该区域内发现大量虫卵。使用一切必要手段将它们摧毁。 +4135640449 Larger Ammunition Storage 扩充弹药存储量 +3068832999 LARGER AMMUNITION STORAGE 扩充弹药存储量 +1266947542 Larger Canister 扩容燃料罐 +2592288011 LARGER CANISTER 扩容燃料罐 +3643346196 Larger Explosion 扩大爆炸范围 +3338945353 LARGER EXPLOSION 扩大爆炸范围 +4003245428 Larger Fuel Tank 扩容燃料罐 +2609141543 LARGER FUEL TANK 扩容燃料罐 +35415516 Larger Gatling Magazine 扩容加特林弹匣 +3181410292 LARGER GATLING MAGAZINE 扩容加特林弹匣 +1428099059 Larger Magazine 扩容弹匣 +2833861096 Larger Magazine 扩容弹匣 +3378126666 Larger Magazine 扩容弹匣 +3650763355 Larger Magazine 扩容弹匣 +3906041620 Larger Magazine 扩容弹匣 +4256334414 Larger Magazine 扩容弹匣 +440051979 LARGER MAGAZINE 扩容弹匣 +682467167 LARGER MAGAZINE 扩容弹匣 +1165744546 LARGER MAGAZINE 扩容弹匣 +2886799739 LARGER MAGAZINE 扩容弹匣 +3381983021 LARGER MAGAZINE 扩容弹匣 +3994709620 LARGER MAGAZINE 扩容弹匣 +3054770838 Larger Magazines 扩容弹匣 +3786352253 LARGER MAGAZINES 扩容弹匣 +3340570263 Larger Plasma Container 扩容等离子弹药匣 +3236359595 LARGER PLASMA CONTAINER 扩容等离子弹药匣 +4244823993 Larger Rocket Pods 提升火箭巢装载量 +4215046118 LARGER ROCKET PODS 提升火箭巢装载量 +2074147858 Larger Search Radius 扩大搜索半径 +2986510034 LARGER SEARCH RADIUS 扩大搜索半径 +3126322534 Larger Shield 延展护盾 +1703699279 LARGER SHIELD 延展护盾 +1492050893 Larva Container 幼虫储存器 +2350507039 LAS-13 Trident LAS-13“三叉戟” +2990487434 LAS-13 TRIDENT LAS-13“三叉戟” +1692172242 LAS-16 LAS-16 +3133951912 LAS-17 LAS-17 +796620782 LAS-22 LAS-22 +2891882700 LAS-5 LAS-5 +3833164785 LAS-58 LAS-58 +1443709731 LAS-7 LAS-7 +2724555962 LAS-98 LAS-98 +3671889012 LAS-98 Laser Cannon stratagem availability has ended. 现已无法使用“LAS-98激光大炮”战略配备。 +2532692121 LAS-99 LAS-99 +4024075326 Laser 激光 +2574980224 LASER 激光 +2089910714 Laser Cannon 激光大炮 +4285698599 LASER CANNON 激光大炮 +1422846480 LASER GUIDE 激光制导 +4210616208 LASER PRISM 激光棱镜 +2301866234 Laser Sentry 激光哨戒炮 +2713617172 LASER SENTRY 激光哨戒炮 +3062869501 Laser Sight 激光瞄准器 +3356194155 LASER SIGHT 激光瞄准器 +1512505369 Laser Sight Angled Foregrip 激光瞄准器与直角前握把 +1968520079 LASER SIGHT ANGLED FOREGRIP 激光瞄准器与直角前握把 +2839874015 Laser Sight w/ Flashlight 激光瞄准器带照明 +968450318 LASER SIGHT W/ FLASHLIGHT 激光瞄准器带照明 +3927675035 Lasota 拉索塔 +2222856057 Last Surviving Hero of First Galactic War Passes Away at 103; "Greatest Honor" Was Service. 第一次星系大战最后一位幸存英雄逝世(享年103岁),追授最高战功勋章 +1298431672 LASTOFE 赖斯斗夫 +65932548 LASTOME 归宿市 +767789391 Launch Codes 发射代码 +644090152 LAUNCH ICBM 发射洲际弹道导弹 +1825484540 LAUNCH ICBM 发射洲际弹道导弹 +2840909738 LAUNCH ICBM 发射洲际弹道导弹 +3484875339 LAUNCH ICBM 发射洲际弹道导弹 +981825449 LAUNCH SEQUENCE INITIATED 发射程序已启动 +2424481257 Launch site inoperable. Proceed to extraction. 发射点无法正常运行。开始撤离程序。 +2424425968 LAUNCHERS ACTIVE 发射器已启动 +2876315862 Launches a prolonged barrage of napalm shells over a wide area, setting a swath of land ablaze in mere moments. 持续投射凝固汽油弹火力网覆盖广大区域,顷刻将土地点燃。 +1773290147 Launches in: 发射倒计时: +2897815073 Lead Scientist 首席科学家 +76566228 Leahy 莱希 +1426096779 Lean 清瘦 +2760931918 LEAN 清瘦 +3081023477 LEARN MORE 了解更多 +4163415863 LEAVE HOLOGRAM 退出全息图像 +3196908787 Lee 李 +2082830912 LEFT 左 +2960759687 Left Button 左方向键 +1336364337 LEFT SHOULDER 左肩 +3153320901 LEFT SHOULDERS 左肩 +1398443941 Left Stick 左摇杆 +3942935006 Left Stick 左操作杆 +3606953766 LEG-MUSCLE ENHANCERS 腿部肌肉强化 +1087090632 Legal 法律条款 +199902803 Legalizing 8 New Pre-Approved Comments On News Media. 8条预先批准的新媒体评论现已合法 +888745430 Legend 传奇 +3589272822 LEGEND 传奇 +3108557663 Legend tells of the unnamed Helldiver, wandering the edges of Super Earth's reach, delivering Democracy and leveling lawlessness wherever the tumbleweeds lead. Wear this, and keep the legend alive. 传说有一位无名的绝地潜兵,游荡在超级地球的边境,追随风滚草的引领,传播民主,肃清无序。披上这件披肩,续写传奇。 +4085620482 Legendary 传奇 +1027334985 LEGENDARY 传奇 +1019382416 LEGENDARY WARBOND NEEDED 需要传奇战争债券 +3465122471 LEGENDARY WARBOND UNLOCKED 已解锁传奇战争债券 +3018577702 Legion 军团 +3688481919 Legislator 立规者 +3001533093 Lemaire 勒迈尔 +2864012067 LEMURIA RISING 利莫里亚崛起城 +3024520777 LENG SECUNDUS 蓝恩次星 +1729099758 LEO SECTOR 狮子座分区 +3220476127 LESATH 尾宿八 +3444733359 LESS AMMO 弹药减少 +3373261145 LESS BATTLEFIELD AMMO 战场弹药减少 +3861654825 LESS BATTLEFIELD AMMO 战场弹药减少 +2873246096 Let all who see this cape be struck still with Freedom's beauty, or struck dead with Liberty's bullets. 凡见此披肩者都将为自由之美所震慑,或被自由之弹所击毙。 +1665034634 Let the Second Anniversary of the Second Galactic War be witnessed by the lidless eye of Liberty, that ever-watchful orb which provides safety through its ceaseless surveillance. 自由之眼永不阖目,它将见证第二次星系战争进入两周年,并通过无休止的监视为我们提供安全。 +1104401796 Let's call it a draw 就算平局吧 +227667415 LETHALITY REVIEW 杀伤力鉴审 +2782283100 LETHALITY REVIEW 杀伤力鉴审 +3703953913 LETHALITY REVIEW 杀伤力鉴审 +1976943483 Level #COUNT #COUNT级 +637689560 LEVEL #COUNT 等级#COUNT +3173588283 LEVEL #LEVEL #LEVEL级 +1027813197 Level #LEVEL | #TITLE #LEVEL级 | #TITLE +2178175578 LEVEL UP REWARD 升级奖励 +2354745185 Level up! 升级! +1321978814 Level up! 晋升! +3680660782 Level-Up Reward 升级奖励 +3257725864 Leveller 荡平者 +2486763325 LEVELLER 荡平者 +915107735 Leviathan 利维坦 +3097344451 Leviathan 利维坦 +784544497 LEVIATHAN 利维坦 +2811783031 LEVIATHAN BLOCKADE 利维坦封锁屏障 +1391601310 Leviathans 利维坦 +2672583111 LIBER-TEA TOWNSHIP 解放茶镇 +608996976 Liberate 解放 +2438255294 Liberate #COUNT planets 解放#COUNT颗星球 +3161912129 Liberate #COUNT planets from #RACE 从#RACE手中解放#COUNT颗星球 +754898562 Liberate #LOCATION 解放#LOCATION +981791852 LIBERATE ALL SECTORS 解放全部分区 +222153209 LIBERATE CYBERSTAN 解放生化斯坦 +10440620 LIBERATE HIVE WORLD 解放虫窝世界 +227711647 LIBERATE HIVE WORLD 解放虫窝世界 +4285959407 Liberate Malevelon Creek. 解放麦拉芬蒙河。 +280839759 LIBERATE MEGAFACTORY 解放超大型工厂 +3807044959 Liberate more planets than are lost during the order duration 指令生效期间解放的星球数量超过沦陷的星球数量 +4046331084 Liberate more planets than are lost to #RACE during the order duration 指令生效期间解放的星球数量超过沦陷在#RACE手中的星球数量 +124201287 Liberate Planet 解放星球 +1984443237 Liberate Planet 解放星球 +3691097214 Liberate Planet 解放星球 +3508469820 Liberate the designated planet. 解放指定的星球。 +3016573332 Liberate the designated planets. 解放指定的星球。 +4171468053 Liberate the Hive World to prevent the spread of the Gloom, and extract as much E-711 as possible. 解放虫窝世界,阻止“阴霾”扩散,并尽可能提取更多711元素。 +3042625068 LIBERATING THE ENEMY 解放敌人 +2311243214 LIBERATION 解放战役 +3254570404 LIBERATION EVENT PROGRESS 解放战役进度 +3832881392 LIBERATION FAILED +Angel's Venture remains infested by the Terminid Menace. 解放失败 +天使投资星系依然为终结族所侵占。 +4166637772 LIBERATION FAILED +Crimsica remains infested by the Terminid Menace. 解放失败 +克里姆西卡依然为终结族所侵占。 +4061717203 LIBERATION FAILED +Despite great sacrifice, Ingmar remains under Automaton control. 解放失败 +尽管我方付出了巨大的牺牲,但仍未能让英格玛脱离机器人的铁爪。 +2050063913 LIBERATION FAILED +Despite great sacrifice, Malevelon Creek remains under Automaton control. 解放失败 +尽管我方付出了巨大的牺牲,但仍未能让麦拉芬蒙河脱离机器人的铁爪。 +1980605113 LIBERATION FAILED +Despite innumerable sacrifices, we have failed to liberate Erata Prime from the Terminid's tyrannical clutches. 解放失败 +尽管付出了无数的牺牲,我们还是未能将艾拉特主星从终结族的暴虐魔爪中解放出来。 +3036523060 LIBERATION FAILED +Despite innumerable sacrifices, we have failed to liberate Meridia from the Terminid's tyrannical clutches. 解放失败 +尽管付出了无数的牺牲,我们还是未能将默里迪亚从终结族的暴虐魔爪中解放出来。 +3708698888 LIBERATION FAILED +Despite innumerable sacrifices, we have failed to liberate Turing from the Terminid's tyrannical clutches. 解放失败 +尽管付出了无数的牺牲,我们还是未能将图灵从终结族的暴虐魔爪中解放出来。 +4243678178 LIBERATION FAILED +Despite innumerable sacrifices, we have failed to liberate Veld from the Terminid's claws. 解放失败 +尽管付出了无数的牺牲,我们还是未能将维尔德从终结族的暴虐魔爪中解放出来。 +395940486 LIBERATION FAILED +Our efforts to purge Fenrir III of the Terminid presence have failed. 解放失败 +我们将终结族彻底驱逐出芬里尔III的行动宣告失败。 +817941547 LIBERATION FAILED +Our efforts to purge Hellmire of the Terminid presence have failed. 解放失败 +我们将终结族彻底驱逐出海尔迈尔的行动宣告失败。 +689985751 LIBERATION FAILED +The bots retain their iron grip on Draupnir. 解放失败 +机器人依然牢牢掌控着德罗普尼尔。 +205927833 LIBERATION FAILED +The bots retain their iron grip on Mantes. 解放失败 +机器人依然牢牢掌控着蒙特斯。 +3118444386 LIBERATION FAILED +We have failed to cleanse a planet of the bugs' infestation. 解放失败 +我们未能彻底剿灭占据星球的虫族。 +2060577439 LIBERATION FAILED +We have failed to cleanse Estanu of the Terminid infestation. 解放失败 +我们未能彻底剿灭占据伊斯塔努的终结族。 +1335203689 LIBERATION FAILED +We have failed to cleanse Heeth of the Terminid infestation. 解放失败 +我们未能彻底剿灭占据希斯的终结族。 +2818765819 LIBERATION FAILED +We have failed to liberate Mort from the Automatons. 解放失败 +我们未能从机器人手上解放莫特。 +4185650761 LIBERATION FAILED +We have failed to liberate Vandalon IV from the Automatons. 解放失败 +我们未能从机器人手上解放万达隆IV。 +106265805 LIBERATION FAILED +We have failed to reclaim a planet from the Automatons. 解放失败 +我们未能从机器人手上夺回星球。 +3614743432 LIBERATION UNDERWAY 解放进行时 +4030497262 LIBERATION UNDERWAY 解放进行时 +3089500484 Liberator 解放者 +3507333225 LIBERATOR 解放者 +1318223109 Liberator Carbine “解放者”卡宾枪 +309006382 LIBERATOR CARBINE “解放者”卡宾枪 +3898508327 Liberator Concussive 震荡“解放者” +4094357691 LIBERATOR CONCUSSIVE 震荡“解放者” +4197589684 Liberator Penetrator 穿甲“解放者” +1877315535 LIBERATOR PENETRATOR 穿甲“解放者” +3825744973 LIBERTY DAY CELEBRATION 解放日庆典 +1648015410 Liberty guides our hand 解放精神指引我们行动 +3268782755 LIBERTY OUTLETS + +World's Longest Shopping Mall 解放奥特莱斯 + +全世界历史最悠久的购物中心 +4225321155 LIBERTY RIDGE 解放岭 +364791758 Liberty's Herald 解放预兆 +2555419568 LIBERTY'S HERALD 解放预兆 +3376553025 LIBERTY'S HERALD 解放预兆 +3004132658 LIDAR STATION 激光雷达站 +3588704735 LiDAR Tower activating 激光雷达塔正在启动 +1858881662 LiDAR Tower currently lowered. 激光雷达塔现已降下。 +2615256492 LIFEBLOOD 命脉城 +2069526184 LIFESWORTH 生之意 +3622548958 LIFT-182 LIFT-182 +1981230987 LIFT-850 LIFT-850 +416403214 LIFT-860 LIFT-860 +2504365554 Light 轻型 +2248940060 Light 之光 +3720383656 LIGHT 轻型 +612466998 LIGHT ANTI-TANK 轻质反坦克 +300892437 LIGHT ARMOR PENETRATING 轻甲穿透 +1917390166 LIGHT ARMOR PENETRATING 轻甲穿透 +3903697604 Light Armored Vehicle 轻甲载具 +1235129181 LIGHT ARMORED VEHICLE 轻甲载具 +3008881196 Light Automaton Outpost Destroyed 轻型机器人哨站成功摧毁 +1129403837 Light Bug Nest Eradicated 轻型巢穴成功摧毁 +3868912809 LIGHT COMBAT (BOTS) 轻型作战(机器人) +1733648760 LIGHT COMBAT (BUGS) 轻型作战(虫族) +3178515827 LIGHT COMBAT (ILLUMINATE) 轻型作战(光能者) +3317194938 Light Encampment 轻型营地 +1362615920 LIGHT GLOOM COVER 轻度“阴霾”笼罩 +594822168 Light Illuminate Encampment Cleared 光能者轻型营地成功摧毁 +291938862 Light Nest 轻型巢穴 +2592407121 Light of Eternal Liberty 永恒自由之光 +2658005757 LIGHT OF ETERNAL LIBERTY 永恒自由之光 +4089838094 LIGHT OF ETERNAL LIBERTY 永恒自由之光 +2596810967 Light Outpost 轻型哨站 +3141182007 Light Outposts 轻型哨站 +3283630480 LIGHT-OF-LIBERTY 耀辉自由城 +2201722158 Lightened Casing 轻薄弹壳 +2659322062 Lightened Casing 轻薄弹壳 +328079421 LIGHTENED CASING 轻薄弹壳 +1825206923 LIGHTENED CASING 轻薄弹壳 +889646210 Lighting Quality 光照质量 +4185944745 Lighting Quality 光照质量 +822812238 Lightning arcs, fired from weapons and turrets, jump to one additional enemy. 从武器和炮塔发射的闪电弧可额外跳到一名敌人身上。 +1271321738 Lightning Spire 闪电尖塔 +494018960 LIGHTNING SPIRE 闪电尖塔 +700299634 Lightning Spires 闪电尖塔 +874076756 Lightweight Materials 轻质材料 +2493110577 LIGHTWEIGHT MATERIALS 轻质材料 +2572306280 Likely one of the earliest Megafactories to be constructed on Cyberstan. The most significant producer of Cyborg combatants. Defended by the Incineration Corps. 这可能是生化斯坦最早建造的超大型工厂之一。生化人战斗单位的最主要生产地。由炽灼部队驻守。 +2915575235 LIL'OME 乐居城 +2068623694 Linddqvist 林德奎斯特 +2062195479 Lindgren 林德格伦 +3904473600 LINDOME 林杜默 +1935027866 Lindstrom 林德斯特伦 +2050244406 Lines all Hellpods with volatile incendiaries that detonate upon impact, igniting any units in vicinity of the drop site. 在所有绝地喷射舱中装载易爆燃烧弹,使其在撞击后爆炸,点燃空投地点周围的所有单位。 +1200971310 Lines Sentry pods with shock-absorbing hydrogel, allowing extra ammunition to be packed in the space previously occupied by shock-absorbing springs. 在哨戒炮的弹药筒内涂抹减震水凝胶,即可在减震弹簧原本占用的空间内装入更多弹药。 +3454387374 LINK 绑定 +2769225748 LINK ACCOUNT 绑定账户 +2552540432 LINK B 链枢B +1191354573 LINK HELLPODS TO DESTROYER 将绝地喷射舱连接至驱逐舰 +1190161155 LINK TO SUPER DESTROYER 连接至超级驱逐舰 +871767461 LINKING 正在绑定 +4186399692 Linking your Steam account to a PlayStation™Network account is required for playing the game. 如需游玩该游戏,请将你的Steam账户与PlayStation™Network账户绑定。 +4223286374 LIQUID-VENTILATED COCKPIT 液态通风驾驶舱 +2444029825 LIVE FEED 即时动态 +400566559 LLANFAIRPWLLGWYNGYLLGOGERYCHWYRNDROBWLLLLANTYSILIOGOGOGOCH II LLANFAIRPWLLGWYNGYLLGOGERYCHWYRNDROBWLLLLANTYSILIOGOGOGOCH II +1026152227 LOAD ARTILLERY SHELLS 装填炮弹 +1874084773 Load Fusion Batteries into Cargo Container 将聚变电池装入货物集装箱 +3061226967 Load Platinum Bars into Cargo Container 将铂金条装入货物集装箱 +4166203427 LOAD SHELL 填弹 +2268700696 Load weapon 给武器装弹 +166648085 Loaded with jet-assisted rounds, this pistol is calibrated for creating and maintaining tactical distance from encroaching hostiles. 这款手枪装填喷气助推弹,经过特别校准,可在敌人逼近时与其保持战术距离。 +3519672519 Loading Drills 熟练装载配备 +579530047 LOADING DRILLS 熟练装载配备 +606005343 Loading Optimizations 优化配备装载 +2882634941 LOADING OPTIMIZATIONS 优化配备装载 +588681024 LOADOUT 武装配置 +653034020 LOADOUT 武装配置 +1290845980 Loadout Progression 武装配置进度 +4236226241 Lobby is private. You do not have permission to join. 私密大厅,没有加入权限。 +1706024967 Local communication towers must be located and activated, to enable broadcasts to civilians. 必须定位并启动本地通信塔,才能向平民进行广播。 +3262302717 Local Overseer of Mine 306.7D Found Dead in Sizzle-Fish Smuggling Incident. 嗞啦鱼走私事件306.7D矿井矿长身亡 +527036125 LOCAL STORAGE 本地存储 +2061500051 LOCAL STORAGE 本地存储 +3198780412 LOCAL TERMINAL 本地终端 +4154432606 Localization Confusion 定位混淆 +1185294009 LOCALIZATION CONFUSION 定位混淆 +2141540131 Locate and destroy Automaton Fabricators. 寻找并消灭机器人构筑者。 +1770690761 Locate and destroy Illuminate Warp Gateways. 寻找并摧毁光能者传送门。 +2960174241 Locate and destroy Terminid structures. 找到并摧毁终结族虫窝结构。 +172073450 Locate and eliminate the Automaton Devastators. 找到并消灭机器人蹂躏者。 +2900030328 Locate and eliminate the Automaton Factory Strider 找到并消灭机器人移动工厂。 +1483079969 Locate and eliminate the Automaton Hulk. 找到并消灭机器人巨型者。 +4281409227 Locate and unlock system access port 定位并解锁系统访问端口 +2095994991 Locate broadcast tower 找到广播塔 +1673130948 Locate Pump Site 找到泵机 +2831289147 Locate the Spore Lung underground 在洞穴中搜寻孢肺 +1756746111 LOCATION 地点 +823115776 Location data ready 附近地点的数据已准备就绪 +2760899332 LOCK TARGET COORDINATES 锁定目标坐标 +2452694656 Lock the fuel hose to the transfer pump 将燃料软管锁定在输送泵上 +534530899 Lock the hose to the transfer pump 将软管锁定在输送泵上 +2428973513 LOCKED 未解锁 +1892219584 LOCKING DRILL POSITION 正在锁定钻机位置 +3360781479 LOCKING TARGET 正在锁定目标 +2882251330 Lockstep 齐步行进 +372208650 LOCKSTEP 齐步行进 +3066936216 LOG IN 登录 +3229535766 Log in to Jammer Terminal 登录干扰装置终端 +3795512643 Log in to Missile Control System 登录导弹控制系统 +2079096779 Log in to Shuttle Bay Terminal 登录运输船坞终端 +615400082 Log in to terminal 登录终端 +2379580646 Log in to terminal 登录终端 +3183464015 Log in to terminal 登录终端 +3984183628 Log in to terminal 登录终端 +2003933905 Log in to the probe interface 登录探测仪界面 +3871612166 Log in to the Tower Control Panel 登录广播塔控制面板 +2426789199 Login limit reached. Please wait to be let in. 大厅人数已满,请稍等。 +3030170787 Login required 需要登录 +1962923154 LOGISTICAE 后勤 +654822303 LOGISTICS HUB 188-B 物流中心188-B +3694915461 LOGISTICS HUB 232-B 物流中心232-B +3367789650 LOKAHEIM 洛卡海姆 +3331938550 LONE 独行者 +1094874088 LONG 长 +1414621521 LONG HOLD 长按 +3993846968 LONG PRESS 长按 +1998725604 LONG RELEASE 长按松开 +4106807304 Long Revolver Barrel 左轮手枪长枪管 +608263171 LONG REVOLVER BARREL 左轮手枪长枪管 +1303853887 Long-range laser artillery enforces the Illuminate's tyrannical grip over this area, engaging targets in orbit and on the ground with deadly precision. + +Their presence prevents us from establishing a foothold in this region. Deploy to the area and eliminate all active Gazer Spires. 远程激光大炮维系着光能者对该区域的暴政统治,它们能以致命精度打击轨道和地面目标。 + +这些武器的存在,导致我方无法在该地区内建立据点。部署到该区域,摧毁所有还在运行的凝视者尖塔。 +4050611900 Longato 隆加托 +1340400774 Longer Arc Range 扩大电弧攻击范围 +764776164 Longer Fire Time 射击时间延长 +4136080102 LONGER FIRE TIME 射击时间延长 +4150551872 Longer Grenade Belt 加长榴弹腰带 +55355417 LONGER GRENADE BELT 加长榴弹腰带 +2349026778 Longer Lifetime 提高耐久度 +4010494309 Longer Lifetime 提高耐久度 +2168678415 LONGER LIFETIME 提高耐久度 +3548123759 LONGER LIFETIME 提高耐久度 +4252177627 LOOK DOWN 向下看 +2345947203 LOOK LEFT 向左看 +3871537263 LOOK OUT 当心 +276478947 LOOK RIGHT 向右看 +3088943012 Look Sensitivity 视角灵敏度 +128364677 Look Sensitivity Vertical Multiplier 视角灵敏度垂直乘数 +3626394095 LOOK UP 向上看 +1190478143 LOOKOUT 眺望台 +2919265899 Loosen Up 放松 +3285461088 LOOSEN UP 放松 +4044970926 Loot Update 战利品更新 +3368575056 Lord 之主 +2031524109 Love this item, shipping A+++++++. Would purchase again. Highly recommended!!!! 超级喜欢,A+++++++级物流。还会回购,强烈推荐!!!! +3791235894 LOW 低 +4027814450 Low death bonus: #AMOUNT M 低阵亡率加分:#AMOUNT +357436400 Low Death Count Bonus 低阵亡次数奖励 +458967201 LOW FUNDS 资金不足 +2204628757 Low light and poor weather reduce your vision. (But never fear—they also reduce the vision of our enemies) 光线不足和天气恶劣都会影响视野。(但是完全不必担心,因为敌方视野同样会受到影响) +2634473139 Low Orbit Compromised 低轨道失守 +559292408 LOW ORBIT SUPERIORITY 低轨优势 +2725532411 LOW RECRUITMENT 一卒难求 +1225158720 LOWER STIM CAPACITY 更小治疗剂容量 +3176411850 LOWER STIM CAPACITY 更小治疗剂容量 +2166471181 Lowers the time it takes for the extraction shuttle to reach the extraction beacon. 缩短撤离运输船抵达撤离信标所需的时间。 +464046895 LOWEST 最低 +223807905 Loyalist 忠诚者 +2752747869 LOYALIST 忠诚者 +3698614321 Loyalty is Rewarded. Report any dissident activity. + +The Ministry of Unity. 忠诚有奖。请及时举报任何异见分子活动。 + +团结部 +2283047098 LtBadazz500 暴躁中尉500 +3662990498 Lumberer Exosuit “伐木者”外骨骼装甲 +831139041 LUMBERER EXOSUIT “伐木者”外骨骼装甲 +3821806431 Lure Mine 诱饵地雷 +2545384143 LURE MINE 诱饵地雷 +432827512 LURZA 卢尔扎堡 +4057885278 LUSCIOUS LIBERTY 甘美自由市 +522439088 LUXE POINT 琉角 +2834895362 LUXURIANT 富源 +936299097 LVL #LEVEL #LEVEL级 +2075913385 LYNX LYNX 猞猁 +2566848990 M-1000 M-1000 +1113303914 M-102 M-102 +2838258743 M-103 M-103 +3219331767 M-104 M-104 +183439825 M-105 M-105 +1469457772 M-105 Stalwart stratagem availability has ended. 现已无法使用“M-105‘盟友’”战略配备。 +4030846486 M.O.D. RELEASES VIDEO OF POSSIBLE ILLUMINATE VOID SHIP 国防部公开疑似光能者虚空舰船的录像 +4224673514 M0o0ns22 月月欲试22 +1757457032 M6C/SOCOM M6C/特种作战 +1381867282 M7S M7S +4284803845 M90A M90A +2294259007 MA5C MA5C +2217787087 Machete 砍刀 +3631119937 MACHETE 砍刀 +3663193426 Machine Gun 机枪 +1491926581 MACHINE GUN 机枪 +835760066 MACHINE GUN 机枪 +1936822397 MACHINE GUN 机枪 +4028883813 Machine Gun Sentry 哨戒机枪 +867025332 MACHINE GUN SENTRY 哨戒机枪 +2898463180 Machinery of Oppression 铁腕威压 +2743009270 MACHINERY OF OPPRESSION 铁腕威压 +2049777198 Made famous by the "Truth Enforcers: Enforcers of Truth" mystery novels, this armor calls to mind those paragons of patriotism who protect us from treasonous lies. 这套盔甲因《真理执行者:真理的执行者》悬疑小说而闻名,让人想起那些保护我们免受叛国谎言蛊惑的爱国典范。 +4251554136 Made famous by the Ministry of Intelligence's hide-and-seek-and-destroy champion of '52, this armor has been improved by removing excess shoulder protection. 这套盔甲因赢得情报部52年度“隐蔽歼敌”比赛冠军而闻名。已移除多余的肩部护甲,进一步改良了设计。 +2365875972 Made famous by the SEAF commander of the same name, this seal reminds us that only perfect Unity can ensure perfect Freedom. 此印因同名的超级地球武装部队指挥官而闻名,时刻提醒着我们,唯有绝对的团结,方能确保绝对的自由。 +2982902099 Made Ready 现成补给 +3241807437 MADE READY 现成补给 +1958147905 MAG 弹匣 +2627863304 Magazine 弹匣 +572685722 MAGAZINE 弹匣 +1553791700 MAGAZINE 弹匣 +3417364792 MAGAZINES 弹匣 +425705392 Magistrate 司卫 +1481725166 MAGNITUDE 巨量市 +3972994097 Magus Acolyte 奇能侍僧 +2800784334 MAGUS ACOLYTE 奇能侍僧 +2183385626 Magus Acolytes 奇能侍僧 +2225860827 MAIA 昴宿四 +4068448225 Maiden voyage of the #SHIP_NAME. #SHIP_NAME的首航。 +1021441989 MAIN COMPONENTS 主要组件 +1143828949 MAIN MENU 主菜单 +3194163033 MAIN OBJECTIVES 主要目标 +3678406658 Main Refinery Components Listed 已列出主要精炼厂组件 +236428922 MAIN SILO 主储罐 +3517530400 MAJOR ORDER 重要指令 +2869491808 MAJOR ORDER COMPLETED 已完成重要指令 +4009784460 MAJOR ORDER COMPLETED 已完成重要指令 +1098332139 MAJOR ORDER FAILED 未完成重要指令 +1483652205 MAJOR ORDER FAILED +Operation Swift Disassembly has failed. Though we have made great gains against the Automatons, still their factories remain, fabricating ever-more threats to Liberty. + +The fight does not end here. We will not rest until their despotic presence is utterly annihilated. Our citizens deserve no less. Await further orders. 重要指令失败 +急速拆解行动已宣告失败。虽然我们在对抗机器人的战斗中取得了巨大胜利,但敌方孵化厂依然坚挺,源源不断制造出更多威胁自由之敌。 + +战斗尚未结束。在将它们的暴虐专制彻底消灭前,我们绝不会偃旗息鼓。我们的公民值得享有彻底的和平。等待进一步的命令。 +1379158180 MAJOR ORDER FAILED +We have failed to fully activate the Terminid Control System. Until we do, the Terminids will continue to slip through the cracks, spreading their tyranny to the backyards of our innocent citizens. 重要指令未完成 +终结族遏制体系未能全面启动。终结族将继续穿过裂缝,将暴政传播至无辜公民的后院,直至遏制体系成功启动为止。 +3300193692 MAJOR ORDER ISSUED 重要指令已发布 +2098091969 MAJOR ORDER REWARD 重要指令奖励 +3137857537 MAJOR ORDER SUCCEEDED +The Terminid Control System is now fully activated on all barrier planets. The Terminids are quarantined, and our citizens are forever safe from their ravenous tyranny. You have achieved a great victory for all posterity, Helldivers. 重要指令已完成 +终结族遏制体系已经在所有屏障星球上全面启动。终结族已被隔离,我们的公民亦从此不再受它们贪婪暴政的威胁。绝地潜兵,你们为子孙后代取得了伟大的胜利。 +3114267772 MAJOR ORDER UPDATE 重要指令更新 +697299752 MAJOR ORDERS 重要指令 +2229540422 MAJOR ORDERS 重要指令 +32661982 Major Place of Interest 主要特殊地点 +1505638056 MAJOSYRI 马约叙里 +763846539 Make Snowball 捏雪球 +2182630814 Make sure to pick up your fallen squadmates' sample containers. They're critical for our collective scientific progress! 务必捡起阵亡队友的样本容器。样本对于推动我们的集体科学进步至关重要! +2206946868 MALEVELON CREEK 麦拉芬蒙河 +1359425692 MALEVELON CREEK HAS BEEN LIBERATED +At long last, Malevelon Creek is free. The Automaton's iron grip on the planet has been pried loose. The war-torn planet will forever bear the scars of its struggle, and the sacrifices of the countless heroes lost there will never be forgotten. + +Colonists are returning to the ruins of their settlements, but with hope in their chests. For at last, sunlight dawns upon a free Creek. 麦拉芬蒙河已得到解放 +麦拉芬蒙河终于得到解放,从机器人的铁爪掌控下挣脱。这颗饱受战争折磨的星球将永远背负血汗的疮疤,无数陨落英雄的牺牲也将被铭记。 + +拓殖地居民陆续返回定居点的废墟,但此刻,他们心怀希望。阳光总算照亮了这方大地。 +342355160 MALEVELON CREEK LOST +The defense of Malevelon Creek has failed. The Automatons spread their despotic industry across its surface. 麦拉芬蒙河沦陷 +麦拉芬蒙河的防线已经崩溃,而机器人也将它们暴虐的产业扩张到了该星球的地表。 +2127895461 MALEVELON CREEK UNDER ATTACK +The Automatons have launched yet another cowardly assault on Malevelon Creek. We cannot allow it to fall into their metallic hands. 麦拉芬蒙河遭到袭击 +机器人向麦拉芬蒙河发动了又一场懦弱的袭击。我们不能任由星球落入它们的铁手。 +2802576158 MALLSTRIP NODES 商廊节点 +732414587 MALMBERGET 马尔姆贝吉特 +664928374 Malmborg 马尔姆堡 +1307362764 Man Trades Up Giant Red Paperclip For Asteroid. 男子为购小行星出售巨型红色回形针 +577912884 Managed Democracy is a cornerstone of advanced civilization. 管理式民主是先进文明的支柱。 +467156125 MANDILARIA 曼迪拉里亚 +740756694 Mandilas 曼迪拉斯 +324192824 MANNED 载人 +1554224329 Mansion lost in #TIME 总统府失守倒计时:#TIME +2032929579 MANTES 蒙特斯 +3600594030 MANTES FREED +The Automaton presence on Mantes is no more. Push the fight onward. 蒙特斯已解放 +机器人不再染指蒙特斯的大地。让我们再接再厉,继续战斗。 +1232720103 MANTES LOST +The defense of Mantes has failed. We cannot allow the Automaton aggression to continue. 蒙特斯沦陷 +蒙特斯的防线已经崩溃,我们不能任由机器人继续进犯。 +2169961348 MANTES UNDER ATTACK +The Automatons are invading Mantes. Rally to its defense! 蒙特斯遭到袭击 +机器人当前正在入侵蒙特斯,速速集结,前去保卫该星球! +1975290224 MANTLE OF TRUE CITIZENSHIP 忠诚公民之斗篷 +2265898986 MANTLE OF TRUE CITIZENSHIP 忠诚公民之斗篷 +3892322195 Manual dish adjustment required 需要手动调整天线 +572488351 Manual Function Trigger 手动操作触发 +908777429 MANUAL FUNCTION TRIGGER 手动操作触发 +3067060166 Manual Targeting 手动锁定目标 +243467210 MANUAL TARGETING 手动锁定目标 +1259256715 Manual valve adjustment required 需要手动调整阀门 +60201391 MANUALLY ADJUST VALVES 手动调整阀门 +2402923326 MANUALLY ADJUST VALVES 手动调整阀门 +2844225527 Manually disengage all hatch locks 手动解除所有舱门锁 +2429169727 Manually disengage all silo hatch locks 手动解除所有发射井舱门锁 +3488275447 Manually disengage hatch locks 手动解除舱门锁 +2266578497 Manually realign the satellite tower 手动重新对齐卫星塔 +1467505284 MAP 地图 +3213279283 MAP 地图 +418419001 Map Navigation Mode 地图浏览模式 +3795586844 MAP ONLY 仅在地图显示 +1356760284 MAP PING 地图标记 +2377120900 Map Position 地图位置 +1270966491 Mar 3月 +2454424572 Marauder 劫掠者 +644398554 MARAUDER 劫掠者 +3772752154 Marauders 劫掠者 +105512472 March 3月 +2839195435 Marcus 马库斯 +2795013007 MARFARK 玛尔法克 +1873654179 MARK 标记 +3730475274 MARK 标记 +3242356062 Mark of the Constrictor 缚暴印记 +161726187 MARK OF THE CONSTRICTOR 缚暴印记 +3075982115 MARK OF THE CRIMSON FANG 猩红獠牙之印 +3419579236 MARKER FROM #NAME #NAME的标记 +2051882320 Markers placed on the map will generate radar scans every #BONUS. 地图上的标记每隔#BONUS进行一次雷达扫描。 +2789265709 Marks the most Free of the Free, those who will seize tyranny by the neck and squeeze until no oppression remains. 最自由者的印记,他们必将扼住暴政咽喉,碾尽世间一切压迫。 +3404187476 Marks the most obedient of the obedient, those who will strike headlong at the veins of Tyranny and administer the sweet antidote of Freedom. 最顺从者的印记,当属毫不犹豫打击暴政血脉、为自由精神注入甜美解毒剂的人。 +560467697 MARKSMAN RIFLE 精确射手步枪 +2144389101 MARRE IV 马尔IV +154450414 MARS 火星 +2756193558 Marshal 元帅 +1846720240 MARSHAL 元帅 +1911682224 MARSPIRA SECTOR 马斯皮拉分区 +2013327304 MARTALE 玛尔特 +31863456 Martyr 烈士 +2575476666 MARTYR'S BAY 烈士湾 +1415121350 MARTYRIS REX 殉道之王 +4137989050 MARTYRIS REX 殉道之王 +2103871051 MASKIN 玛斯金 +3486215587 MASS DECOMMISSIONING 大规模报废 +2634513795 MASS SHUTDOWN 大规模关停 +2692899190 Massive Automaton factories in this region are fueling their advance. They must be destroyed. + +This dormant ICBM silo is beyond their range of detection; launch a devastating strike before they can mount a defense. 该地区的大型机器人工厂为机器人的推进行动提供了源源不断的动力。必须将其摧毁。 + +这座暂停使用的洲际弹道导弹发射井位于它们的探测范围之外。在它们构筑防线之前发动毁灭性打击。 +1275097566 Massive Enemies 大型敌人 +1447308211 Massive uncanny storms have erupted on this planet. These "Exostorms" emanate from otherworldly spires, unearthed by the Illuminate from the ruins of their fallen empire. + +The intentions of the Illuminate are unclear, but undeniably sinister. Strike their crude bases and return them to rubble. 这颗星球上爆发了诡异的巨型风暴。这些“异界风暴”的源头是光能者从其陨落帝国废墟中挖掘出的异界尖塔。 + +光能者的意图不明,但无疑邪恶至极。直捣这个粗制滥造的基地,将其再次夷为平地。 +3459484557 MASTER DIVEMASTER 大师潜兵长 +801750565 MASTER DIVEMASTER MAJOR OMEGA 终极大师潜兵长少校 +783035461 MASTER SERGEANT 军士长 +1185389241 Master Volume 主音量 +2616278472 Masters of Ceremony 典礼官 +1103982798 MASTERS OF CEREMONY 典礼官 +909845190 MASTIA 玛斯蒂亚 +4088126157 MATAR BAY 玛塔 +3484787534 Match security grid pattern 匹配安全网格图案 +2643410558 Matchmaking aborted. 匹配中止。 +2813304875 Matchmaking Privacy 匹配隐私 +580630111 Mature - Drugs 成人 - 毒品 +1611882665 Mature - Sexual Content 成人 - 性内容 +18457064 Mature - Violence 成人 - 暴力 +123940318 MAW 深渊 +3721679864 Max Frame Rate 最大帧率 +851523026 MAX RANK 最高等级 +1708145693 MAX RANK INFINITY 无限最高等级 +808992907 MAX RANK INFINITY +1 无限最高等级+1 +1999223573 Maxigun 重装机枪 +369958519 MAXIGUN 重装机枪 +674776290 Maxigun Backpack 重装机枪背包 +2920301911 MAXIGUN BACKPACK 重装机枪背包 +1140488532 May 5月 +2514158914 May 5月 +560284995 McEachern 麦凯克伦 +3296392070 McGregor 麦格雷戈 +2256130684 MD-17 MD-17 +2623866728 MD-6 MD-6 +1435510243 MD-8 MD-8 +2455737686 MD-I4 MD-I4 +1517419263 MEAN GREEN EXOSUIT PATTERN 凶猛绿外骨骼装甲涂装 +1269181160 MEAN GREEN HELLPOD PATTERN 凶猛绿绝地喷射舱涂装 +980516668 MEAN GREEN SHUTTLE PATTERN 凶猛绿运输船涂装 +4149891798 MEAN GREEN VEHICLE PATTERN 凶猛绿载具涂装 +1903402815 Meat Saw 肉锯 +1938376644 MED-KIT 急救包 +3583490699 Medal 奖章 +1438391677 Medal payout decrease no longer in effect. 奖章收益减少的效果结束。 +1550801594 Medal payout increase no longer in effect. 奖章收益增加的效果结束。 +2763456608 Medal payout per mission for all Helldivers increased by #V_ONE. 所有绝地潜兵每次任务的奖章收益增加#V_ONE。 +715841083 Medal payout per mission for all Helldivers is temporarily increased by #V_ONE. 所有绝地潜兵每次任务的奖章收益暂时增加#V_ONE。 +1057931616 Medal payout per mission for all Helldivers is temporarily reduced by #V_ONE. 所有绝地潜兵每次任务的奖章收益暂时减少#V_ONE。 +996991993 Medal payout per mission for all Helldivers reduced by #V_ONE. 所有绝地潜兵每次任务的奖章收益减少#V_ONE。 +3067595088 Medals may be earned by completing missions or purchased with Super Credits 奖章可以通过完成任务获得或使用超级货币购买 +1389363311 MEDALS RECEIVED 已收到奖章 +2927578997 MEDIC BACKPACK 医疗背包 +2673704303 Medical Supplies 医疗补给 +2273284544 MEDICAL SUPPLIES 医疗补给 +2870476391 MEDICAL SUPPLY STRAIN 医疗补给紧张 +3355650295 MEDICAL SUPPLY SURPLUS 医疗补给过剩 +582836190 Medium 中型 +466171216 MEDIUM 中型 +820317221 MEDIUM 适中 +825545214 MEDIUM 适中 +2674423157 MEDIUM 适中 +2809865391 MEDIUM 普通 +3348405905 MEDIUM 适中 +362702031 MEDIUM ARMOR PENETRATING 中甲穿透 +3085090887 MEDIUM ARMOR PENETRATING 中甲穿透 +1149498137 Medium Automaton Outpost Destroyed 中型机器人哨站成功摧毁 +4152059754 Medium Bug Nest Eradicated 中型巢穴成功摧毁 +3417367432 Medium Encampment 中型营地 +840985290 Medium Illuminate Encampment Cleared 光能者中型营地成功摧毁 +165867526 Medium Nest 中型巢穴 +2548239949 Medium Outpost 中型哨站 +1776442652 Medium Outposts 中型哨站 +3092989428 Medium Plasma Bolt 中型等离子弹 +1981652822 MEDIUM PLASMA BOLT 中型等离子弹 +3910555043 MEGA CITY 特大城市 +1837990407 Mega Nest 超巨巢穴 +3614889577 MEGA NEST 超巨巢穴 +2268221856 Mega Nest Eradicated 超巨巢穴成功摧毁 +2832319432 MEGACORPUS 梅加科尔普斯 +1151110921 Megafactories like this one double as strategic command nodes and industrial cores for large-scale Cyborg and Automaton production. + +Storm its walls and reduce this socialist hub to rubble. 这类超大型工厂既是生化人的战略指挥节点,也是它们用于大规模生产生化人和机器人的工业核心。 + +攻破其防御系统,将这个暴政据点夷为平地。 +2448198391 MEGAFACTORY LIBERATION PROGRESS 超大型工厂解放进度 +343399053 MEGAFACTORY MISSION 超大型工厂任务 +3603669543 MEGAFACTORY OPERATION 超大型工厂行动 +820622353 MEISSA 觜宿一 +677430713 MEKBUDA 井宿七 +2376715785 Melee 近战 +681329901 MELEE 近战 +1955083248 MELEE 近战 +2156619321 Melee damage decrease no longer in effect. 近战伤害降低的效果结束。 +1714339271 Melee damage decreased by #V_ONE%. 近战伤害降低#V_ONE%。 +2895551820 Melee damage increase no longer in effect. 近战伤害提高的效果结束。 +3929288014 Melee damage increased by #V_ONE%. 近战伤害提高#V_ONE%。 +1044524616 Melee damage is temporarily decreased by #V_ONE%. 近战伤害暂时降低#V_ONE%。 +2715016726 Melee damage is temporarily increased by #V_ONE%. 近战伤害暂时提高#V_ONE%。 +4019403474 Melee Kill 近战击杀 +277513082 Melee Kills 近战击杀数 +2543277293 MELEE KILLS: 近战击杀数: +3899086608 Melta Mine 热熔地雷 +2081415472 MELTA MINE 热熔地雷 +2228355350 Meltagun 热熔枪 +2119966943 MELTAGUN 热熔枪 +368572468 Melting Icecaps On Gemstone Bluffs Lead To Increase In Superboat-Hotel Prices. 宝石崖冰冠融化导致超级舟船酒店房费升高 +331792922 MEMORIALS 纪念市 +1842172307 MENKENT 库楼三 +3876211975 MENU 菜单 +3519536123 MERAK 北斗二 +2251442607 MERGA IV 玄戈增二IV +3092832165 MERIDIA 默里迪亚 +776840956 MERIDIA DEFENDED +After countless noble and unavoidable sacrifices, Meridia has been defended from the Terminids. 成功保卫默里迪亚 +无数不可避免的光荣牺牲终于换来回报,我们顺利从终结族手下守住了默里迪亚。 +3786652388 MERIDIA FREED +Meridia has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet. 默里迪亚已解放 +默里迪亚挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。 +2804740468 MERIDIA LOST +The defense of Meridia has failed. Terminids now infest its once-pristine surface. 默里迪亚沦陷 +默里迪亚保卫战已宣告失败。终结族现在令这块曾经的纯净乐土不得安宁。 +2756414960 MERIDIA SECURED +The Terminid Control System is now fully activated on Meridia. 成功占领默里迪亚 +终结族遏制体系已经在默里迪亚全面启动。 +1861980327 MERIDIA UNDER ATTACK +The Terminids are attempting to spread to Meridia. All Helldivers are called upon to deploy immediately to the planet's defense. 默里迪亚遭到袭击 +终结族企图扩张至默里迪亚。呼唤全体绝地潜兵,立即前去保卫该星球。 +1741687388 MERIDIAN BLACK HOLE 默里迪恩黑洞 +1927972667 MERIDIAN IIa 默里迪恩IIa +4036369765 MERIDIAN SECTOR 默里迪亚分区 +162355166 MERIDIAN SINGULARITY 默里迪恩奇点 +4009717880 MERITORIOUS COMMENDATIONS 论功行赏 +3847662786 Message 消息 +2955730819 MESSAGE OF MORALE 士气宣言 +4075785797 MESSAGER'S MESA 信使台地 +1640072314 Messages 消息 +2570684122 METEOR STORMS 流星风暴 +1042419338 Meteors impact the surface causing massive damage. 流星会撞击地表,造成大量伤害。 +586021653 MG Raider 机枪奇袭者 +4223909310 MG RAIDER 机枪奇袭者 +4212192829 MG Raiders 机枪奇袭者 +3292527839 MG-206 MG-206 +2615942564 MG-43 MG-43 +1087117852 MG-43 Machine Gun stratagem availability has ended. 现已无法使用“MG-43机枪”战略配备。 +2020318492 MGX-42 MGX-42 +289898661 MIDASBURG 弥达斯堡 +2007900483 Midnight Mode 午夜模式 +1887229825 mike__the_spike 马克__不马虎 +3705650206 MILITARY OPS 军事行动 +1562426815 Military watchdog groups have called exploding shrapnel "savage," "merciless," and "well-suited for spreading Democracy." 军事监督组织认为高爆弹片“野蛮”、“无情”,“非常适合传播民主”。 +1905068482 MilitaryBeefHunk99 军用牛肉块99 +4267067074 Mime Instrumentation 弹空气吉他 +4143519014 MIME INSTRUMENTATION 弹空气吉他 +3978718279 MINCHIR 敏切尔 +1025296589 MINDLESS MASSES 无脑群氓 +3837869994 MINE 地雷 +4157907194 MINE 902 矿洞902 +3673095524 Mine arrived with some real sweat of heroes still inside it! 收到货时,里面甚至还残留英雄的汗水! +2466808441 Mineral analysis complete 矿物分析完成 +301366553 MINERAL REFINEMENT WORKS 矿物精炼厂 +3747586953 MINERAL'S END 矿竭地 +572820359 MINERVA 密涅瓦 +3021800044 MINIMIZE STATS 最小化数据 +302478499 MINING SITE COORDINATES 采矿点坐标 +3209554666 Ministry of Intelligence cryptographers have decoded Automaton chatter including mention of a new "HUMAN KILLING MACHINE." While further analysis is underway, Helldivers combatting the Automatons in high-complexity missions are urged to remain vigilant. 情报部密码学家破译了机器人的通信记录,得知对方掌握一种新型“杀人机器”。尽管该情报有待进一步分析,但是执行复杂任务并与机器人交手的绝地潜兵务必保持警惕。 +173738388 MINISTRY OF PROSPERITY ANNOUNCES CLOSURE OF MIDASBURG MINT AFTER 75 YEARS OF OPERATION 繁荣部宣布关闭运营75年的弥达斯堡造币厂 +2650537364 Ministry of Science Officials Identify Unprecedented Mass Production Technology in Use by Automatons. 科学部官员发现机器人在使用前所未见的量产技术 +4062951277 MINISTRY OF SCIENCE REVEALS SWEEPING ARTIFICIAL INTELLIGENCE RESEARCH PLAN 科学部公开人工智能全面研究计划 +3713389674 Minor Place of Interest 次要特殊地点 +438442448 MINTORIA 敏托瑞亚 +2497327335 MIQÉ 米基 +1334736569 MIRAGE 幻境城 +2661829453 Miranda's Legacy 米兰达的遗志 +1401700439 MIRANDA'S LEGACY 米兰达的遗志 +2565002699 MIRIN SECTOR 米琳分区 +56360453 Mirror 之镜 +3519461357 MISSILE CONTROL SYSTEM 导弹控制系统 +3320340883 Missile fueling in progress 正在为导弹添加燃料 +4112376829 Missile Performance 导弹性能 +850731546 MISSILE PERFORMANCE 导弹性能 +2201877789 Missile Pistol 制导手枪 +2548766534 MISSILE PISTOL 制导手枪 +980743299 Missing Child Astronaut Found In Plutonium Well By Robotic Dog. 机器狗在钚井发现失踪儿童宇航员 +1006242818 Missing Child Found Orbiting Asteroid After Family Spacewalk Mishap. 太空行走事故失踪儿童现已找到,当时正在围绕小行星旋转 +225116831 Mission 任务 +251200848 Mission 任务 +2687979927 Mission 任务 +2540067077 MISSION 任务 +3753992134 MISSION 任务 +2417525045 MISSION 任务 +35824523 MISSION COMPLETED 任务完成 +1512949433 MISSION COMPLETED 任务完成 +2757374885 Mission Control 任务调度员 +2979180939 MISSION DEBUG 任务测试 +2258202023 Mission difficulty is determined in part by the types of enemy units in the area. Make sure you bring the appropriate weaponry! 任务难度也和当地敌方部队的类型有关。一定要带上合适的武器! +612202588 MISSION FAILED 任务失败 +3234001191 MISSION FAILED 任务失败 +938578203 MISSION FAILED 任务失败 +301581254 MISSION FAILED 任务失败 +1691572204 MISSION IMPACT 任务影响 +2616040 MISSION INCOMPLETE 任务未完成 +248798988 Mission Info Position 任务信息位置 +3420284533 Mission Info Visibility 任务信息可视度 +3898010543 MISSION PAYOUT 任务收益 +782436802 MISSION REWARDS 任务奖励数 +2500643197 MISSION SITE 任务地点 +4063884494 MISSION STARTING 任务即将开始 +931461500 Mission starting, Helldivers to Hellpods! 任务开始,请绝地潜兵到喷射舱集合! +1877723293 Mission stats could not be displayed due to a network issue. Mission completion rewards and extracted resources are unaffected and have been handed out normally. 由于网络问题,无法显示任务数据。完成任务的奖励和提取的资源没受到影响,已正常发放。 +4147740137 MISSION STATS UNAVAILABLE 任务数据无法显示 +1855211481 MISSION STRATAGEM PERMIT 任务战略配备许可证 +4129494235 MISSION STRATAGEMS 任务所需战略配备 +4260964306 MISSION SUCCESSFUL 任务成功 +4193304862 MISSION TIME : #MINUTES:#SECONDS 任务用时:#MINUTES:#SECONDS +157970715 Mission time increase no longer in effect. 任务时间延长的效果结束。 +1775883134 Mission time reduction no longer in effect. 任务时间缩减的效果结束。 +1635143847 MISSION TIME REMAINING 任务剩余时间 +1860163325 MISSION TIMER EXPIRED - REINFORCE NO LONGER POSSIBLE 任务过期,无法再呼叫增援 +2001454991 Missions 任务 +3967728374 Missions 任务 +1876552528 MISSIONS 任务 +3213114552 MISSIONS 任务 +2992434631 Missions are filled with unexplored points of interest. Check them out—you never know what you might find. 任务过程中有许多未经探索的特殊地点。去看一看吧,或许你会发现些什么呢! +1081573383 MISSIONS COMPLETED BONUS 任务完成奖励 +3215956270 MISSIONS COMPLETED BONUS 任务完成奖励 +2144530843 Missions Played 任务执行数 +3423859886 Missions Won 任务完成数 +1080811718 Mk5b 'Tactical' Mk5b“战术” +2900528531 MLS-4X MLS-4X +3398129090 MOBERG'S DREAM 莫伯格之梦 +3476536437 MOBILE RADAR 移动雷达 +149849300 MOBILE WHITE EXOSUIT PATTERN 移动白色外骨骼装甲涂装 +4069889950 MOBILE WHITE HELLPOD PATTERN 移动白色绝地喷射舱涂装 +723344253 MOBILE WHITE SHUTTLE PATTERN 移动白色运输船涂装 +805648087 MOBILE WHITE VEHICLE PATTERN 移动白色载具涂装 +2138903194 MOBILIZATION 动员行动 +2294037091 MOBILIZE TO A FRONTLINE PLANET 响应动员奔赴前线星球 +2992438367 Mobilized in: 动员倒计时: +2469777277 Modeled after the myriad Statues of Judicious Liberty, who keep a watchful eye on checkout lines, schoolyards, perpetual rehabilitation communities, and public confession theaters. 这套盔甲的灵感来自不计其数的“公正自由女神像”,她们警惕地注视着收银台、学校操场、永久性矫正社区和公共忏悔剧场。 +2778718509 Modeled after the Statue of Mournful Liberty, who weeps over the existence of tyranny, this armor is worn by those who would give their lives to dry her tears. 这套盔甲的灵感来自因暴政肆虐而哭泣的“哀恸自由女神像”,穿戴者愿以生命拂去自由女神的眼泪。 +1628213888 MODERATE GLOOM BLANKET 中度“阴霾”笼罩 +1016254138 MODIFIERS [#COUNT] 限制条件[#COUNT] +145256226 Modifies how far light from certain light sources reaches. Alters some materials and lighting features. 更改部分光源的光线照射距离。更改部分材质和光照功能。 +427714691 Modifies the resolution of the space backdrop when on missions. Primarily affects stars. 更改执行任务时的太空背景的分辨率,主要会影响太空里的行星。 +2774113209 MODULES UNLOCKED 模块已解锁 +3009003351 MOG 莫格 +2424362352 MOGO PLAINS 莫戈平原 +1788879704 MOMO-1 莫莫-1 +2217667642 MONHEIM 蒙海姆 +1578792227 MÖNSTERÅS II 门斯特罗斯II +2688155711 MONUMENT TO LIBERTY 解放纪念碑 +1177472195 Monuments in this Megafactory twist history to valorize the supposed resolve of Cyborgs to "endure" Super Earth's benevolent attempts to rehabilitate them. + +Anti-air defenses will hinder Eagle operations. 这座超大型工厂的纪念碑扭曲历史,颂扬生化人所谓“忍受”超级地球仁慈改造计划的决心。 + +防空系统将妨碍“飞鹰”的行动。 +2504313014 MOOR 荒地 +3837189790 MOOR PLANET 荒地星球 +921057527 Moore 摩尔 +379673343 MORADESH 莫拉戴什 +1687597886 MORALE AUGMENTATION 提升士气 +1960080764 MORDIA 9 摩帝亚9 +2833159526 MORE AMMO 弹药增加 +2876103297 More Ammo In Backpack 增加背包弹药数量 +3541935699 More Ammo In Backpack 增加背包弹药数量 +1856218035 MORE AMMO IN BACKPACK 增加背包弹药数量 +2139851716 More Arc Splits 增加电弧分裂数 +4203828377 MORE ARC SPLITS 增加电弧分裂数 +660841885 More Autocannon Turret Ammo 增加机炮炮台弹药数 +124851582 MORE AUTOCANNON TURRET AMMO 增加机炮炮台弹药数 +1539723683 More Backpack Ammo 增加备用弹药 +751214977 MORE BACKPACK AMMO 增加备用弹药 +3514565128 MORE BATTLEFIELD AMMO 战场弹药增加 +3670656870 MORE BATTLEFIELD AMMO 战场弹药增加 +2204934809 More Bombs 增加炸弹数 +410594009 MORE BOMBS 增加炸弹数 +2668665442 More challenging missions yield greater rewards. 越具挑战性的任务奖励越丰厚。 +2552962615 More Contestants of "What Planet Am I Standing on or We'll 《行星猜猜猜,猜错送你来》 +54675616 MORE DAMAGE 提高伤害 +3588986772 More Durable Chassis 提升底盘耐久度 +2086046319 MORE DURABLE CHASSIS 提升底盘耐久度 +1959371383 MORE EFFECTIVE MISSIONS 任务效率提高 +658602772 More Explosive Filler 增加爆炸物填料 +3151052906 MORE EXPLOSIVE FILLER 增加爆炸物填料 +1271339915 More Fuel 增加燃料 +1044805146 MORE FUEL 增加燃料 +3544966945 MORE GUNS 增强枪炮火力 +3444434997 More HMG Mount Mags 增加架设型重机枪弹匣 +4122755523 MORE HMG MOUNT MAGS 增加架设型重机枪弹匣 +1507929321 More Info 其他详情 +227864535 MORE INFO 更多详情 +444769171 More LMG Mount Mags 增加架设型轻机枪弹匣 +2790097968 MORE LMG MOUNT MAGS 增加架设型轻机枪弹匣 +3906307244 More Magazines 增加弹匣 +3768371281 MORE MAGAZINES 增加弹匣 +2062497342 More Rounds 增加弹药 +2408305387 MORE ROUNDS 增加弹药 +715927899 More Salvoes 增加齐射炮弹数 +4211984053 MORE SALVOES 增加齐射炮弹数 +2914382311 MORE STIMS 治疗剂增加 +3382493069 Morgan 摩根 +1674292329 MORGON SECTOR 莫根分区 +3054238048 MORSKIE OKO 海洋之眸 +2388292518 MORT 莫特 +4055973028 MORT FREED +Mort is finally free from the oppressive Automaton presence. Our hopeful citizens look forward to the commencement of colonization efforts. 莫特已解放 +暴虐的机器人终于从莫特的土地上消失。满怀希冀的公民此刻开始期待启动拓殖任务。 +1799604546 MORT LOST +The defense of Mort has failed. We cannot allow the Automaton aggression to continue. 莫特沦陷 +莫特的防线已经崩溃,我们不能任由机器人继续进犯。 +3645869111 MORT UNDER ATTACK +The bots seek to add Mort to their despotic domain. We cannot allow this illegal territorial expansion. 莫特遭到袭击 +机器人企图将莫特纳入它们的暴政领域,我们不能放任它们非法扩张领地。 +1823884758 MORTAR EMPLACEMENT 迫击炮台 +286244856 Mortar Sentry 迫击哨戒炮 +2602942644 MORTAR SENTRY 迫击哨戒炮 +2135009396 Mortar Sentry stratagem availability has ended. 现已无法使用“迫击哨戒炮”战略配备。 +4050163919 MORTAX PRIME 摩尔塔克斯主星 +3450849083 Most enemies have both weak spots and armored spots. The SEAF training manual recommends aiming for the weak spots. 大多数敌人既有弱点也有披甲部位。超级地球武装部队训练手册建议你瞄准弱点进行攻击。 +348167236 Most weapons have different fire modes or functions—hold Reload to access them. 大多数武器都设有不同的开火模式或功能,按住装填弹药键可切换模式或功能。 +3150803681 Mother 之母 +572813769 Mother Eagle's Wings 母鹰之翼 +393895245 MOTHER EAGLE'S WINGS 母鹰之翼 +1789956868 Motion Blur 动态模糊 +3660647095 Motion Sensor Acceleration 动态感测器加速 +1545693663 Motion Sensor Acceleration Threshold 动态感测器加速阈值 +2567148580 Motion Sensor Enable Mode 动态感测器启用模式 +637827320 Motion Sensor Sensitivity 动态感测器启用模式 +3699420646 Motion Sensor Steadying Amount 动态感测器稳定量 +1323079865 Motion Sensor Steadying Threshold 动态感测器稳定阈值 +4003809798 Motion Sensor Steadying Transition Duration 动态感测器稳定过渡持续时间 +1015408865 Motivational Shocks 激励性冲击 +3621071191 MOTIVATIONAL SHOCKS 激励性冲击 +795291061 Mountains of sand bake in unrelenting heat on this utter desolation of a planet. 庞大的沙丘在酷热中炙烤。这颗星球荒凉至极。 +196172340 Mounts a modified AR-23 Liberator to all resupply pods, allowing them to double as automatic turrets. 为所有重新补给舱搭载改良版AR-23“解放者”,可充当自动炮台。 +1236536730 Mournful Victory 悲哀得胜 +2814592495 MOUSE & KEYBOARD 鼠标及键盘 +4113469483 Mouse Acceleration 鼠标加速 +2201770761 Mouse Aim Sensitivity 鼠标瞄准灵敏度 +3495809024 Mouse Cursor 鼠标光标 +2875122666 Mouse Map Sensitivity 鼠标地图灵敏度 +2402756435 Mouse Move 鼠标移动 +3791201196 Mouse Scope Sensitivity 鼠标开镜灵敏度 +1028725101 Mouse Sensitivity 鼠标灵敏度 +3202519282 Mouse Smoothing 鼠标平滑 +1418716476 Mouse Wheel 鼠标滑轮 +2642638685 MOVE BACK 向后移动 +3026199176 Move closer to objective 移动至离目标更近的位置 +1060265866 MOVE CURSOR 移动光标 +2146526451 MOVE CURSOR 移动光标 +592385330 MOVE CURSOR 移动光标 +3262619205 Move cursor to pan map. 移动光标可以拖动地图。 +3394710789 Move cursor to pan map. 移动光标可以拖动地图。 +2336690627 MOVE DISABLED 移动禁用 +875473382 MOVE DOWN 向下移动 +2070543290 MOVE FORWARD 向前移动 +3297935694 Move GATER to indicated drill sites 将地面全地形采集钻机移至已标记的钻探点 +1143795330 MOVE LEFT 向左移动 +1341439698 MOVE LEFT 向左移动 +202589535 MOVE RIGHT 向右移动 +2888835542 MOVE RIGHT 向右移动 +76309360 MOVE SELECTION AND SWITCH NUMBERS 行动选择和切换号码 +3537061153 Move through Highly Realistic Battlefield Simulator 通过高度逼真的模拟战场 +3683645478 Move to the SHOOTING RANGE to start the exercise. 前往靶场开始训练。 +1296784418 MOVE UP 向上移动 +1711884652 MOVEMENT 移动 +33025389 Moving makes it harder to aim - Stand still for maximum accuracy! 移动过程中难以瞄准,站立不动才能最大限度提高命中率! +1539464482 Moving to drill position... 移动到钻探位置…… +2700736388 MOX 莫克斯 +3453994849 MP-98 MP-98 +436032589 MS-11 MS-11 +2286463767 MT MONUMENT 纪念碑山 +1789375498 MUDSKIPPER 弹涂鱼 +4108124213 Multi-Launch Protocol 多管发射协议 +75424777 MULTI-LAUNCH PROTOCOL 多管发射协议 +1433736858 MULTIPLAYER 多人游戏 +3719011487 Multiple citizens report having same dream of unseen tentacled mass lurking in shadowy depths 多名平民报告称做了同一个梦:在幽暗的深处,潜伏着一团看不见的触手状巨物。 +2056147079 Multiple Operation Modifiers 多重行动限制条件 +3106377947 Multiple opportunities to disrupt the enemy's opaque and sinister machinations have been identified in this region. Illuminate forces are highly concentrated here; expect significant resistance. + +Disrupt their schemes and restore peace to this area. 在该地区发现多个可挫败敌人阴谋诡计的良机。光能者部队在此处重兵集结;我方预计将遭遇敌人的顽强抵抗。 + +挫败光能者的阴谋,恢复该地区的安宁。 +1909369609 MULTIPLE PLANETS INVADED 多颗星球遭到入侵 +4045585038 MULTIPLE THREATS DETECTED 侦测发现多个威胁 +1606616279 MUNITION CITY 军工城 +570461792 Muscle Enhancement 肌肉强化 +2245752706 MUSCLE ENHANCEMENT 肌肉强化 +48684741 Music Preview 音乐预览 +3602747086 Music Volume 音乐音量 +2351442158 MUSTARD EXOSUIT PATTERN 芥末黄外骨骼装甲涂装 +3063286369 MUSTARD HELLPOD PATTERN 芥末黄绝地喷射舱涂装 +3203913453 MUSTARD SHUTTLE PATTERN 芥末黄运输船涂装 +2240736806 MUSTARD VEHICLE PATTERN 芥末黄载具涂装 +792108617 Mutated Egg 变异虫卵 +555942570 MUTATED EGG 变异虫卵 +956591585 Mutated Eggs 变异虫卵 +943766919 MUTATED EGGS 变异虫卵 +626905797 MUTE 静音 +173697540 MUTED 静音 +2849154934 Mutual Friends 共同好友 +2610998298 MUZ 枪口 +3610079077 Muzzle 枪口 +633489131 MUZZLE 枪口 +1370810082 MUZZLE 枪口 +643498211 Muzzle Brake 枪口制退器 +2353545087 Muzzle Brake 枪口制退器 +2367147337 MUZZLE BRAKE 枪口制退器 +4292516491 MUZZLE BRAKE 枪口制退器 +3508717001 MUZZLE VELOCITY 枪口初速 +1587797497 My only complaint is that I wish I had another one 我唯一不满意的就是我怎么没再买一件 +3445141507 My wife said it's this or her. She will be missed. 我老婆说我买了她就走人。那只能好走不送了。 +863969201 MYRADESH 米拉戴什 +514623903 MYRIUM 梅里翁 +1857416237 N 北 +3764410099 N 北 +4268177862 N (#COUNT°) 北#COUNT° +1861832405 N/A 不适用 +1382288454 NABATEA SECUNDUS 那贝塔次星 +188867800 NAME YOUR SUPER DESTROYER SHIP 为你的超级驱逐舰命名 +1872946157 Named for Helldiver Jack Boote, who shut down 908 illegal broadcasts before retiring with honors. 以绝地潜兵杰克·布特命名,他在光荣退役前曾查封了908个非法广播。 +3671853082 Named for the historic conference where Humanity was found to be the most Equal species in the Galaxy. 因历史性会议而得名,此会议将人类认定为银河系最平等的物种。 +3626458441 Nameplate Visibility 名牌可视度 +955032040 NANOS SECTOR 纳诺斯分区 +1028168550 Napalm Bomb 凝固汽油弹 +3133231213 NAPALM BOMB 凝固汽油弹 +3990334796 Napalm Bomb Mk2 凝固汽油弹 MK2 +96621472 NAPALM BOMB MK2 凝固汽油弹 MK2 +1808877270 Napalm Bomb Mk3 凝固汽油弹 MK3 +4135288639 NAPALM BOMB MK3 凝固汽油弹 MK3 +2898876145 Narrates menus, popups and incoming chat messages. 朗读菜单、弹出窗口和接收的聊天消息。 +2716312739 Narrow Spread 集中 +2423584147 NASCENCE 太初 +2686156913 NATIVE 原始 +96685762 Natural Gas Extraction 提炼天然气 +2544308646 NATURAL GAS EXTRACTION 提炼天然气 +1465854050 NAVI VII 阁道二 +626132148 Nazareno 纳萨雷诺 +1565358089 NE 东北 +4032541409 NE 东北 +4099824196 NE (#COUNT°) 东北#COUNT° +3471435505 Near-Total Victory 几近全胜 +1294042326 NEDERLANDS (Unsupported) NEDERLANDS (Unsupported) +281615503 NEED SUPPLIES 我需要补给 +3539223805 NEGATIVE ENERGY LABORATORY 负能量实验室 +3740715487 NEKK POND 水妖池 +229785699 Net Worth 生涯收入 +4285890418 Network connection lost 网络连接丢失 +3156506602 NETWORK ERROR 网络出错 +2241576450 NEUTRALIZE GROUND-TO-ORBIT DEFENSES 瘫痪地对轨道防御系统 +4168553130 NEUTRALIZE ORBITAL CANNON 阻止敌方使用轨道加农炮 +3635686905 Never 从不显示 +1085861539 NEW 全新 +3886621303 New CUSTOMIZATION available in the ARMORY. 军械库现已开放全新自定义选项。 +1721241425 New STRATAGEMS available for REQUISITION. 全新战略配备可供申购。 +2308530085 New WEAPON CUSTOMIZATION available to purchase in the ARMORY 全新武器自定义内容已在军械库中开放购买 +2399790664 New 3D-Printed Assault Rifle Can Defensively Slaughter Up To 30 Bugs/Second. 新型3D打印突击步枪每秒可以防御性击毙30只虫族 +1647999978 NEW ABERDEEN 新阿伯丁 +1134185291 NEW ALEXANDRIA 新亚历山大城 +762468820 NEW ASPIRATION CITY 志向新城 +4098458068 NEW ASPIRATION CONSTRUCTION SITE 志向新城建造区 +4130639501 New Bill Funds Dissident Identification Training For Schoolteachers 新法案出资开展在校教师异见分子甄别培训 +735840644 NEW BILL WOULD TEMPORARILY GRANT PET FISH AUTHORIZATION TO CLASS C CITIZENS AND ABOVE 新法案将暂时批准C级及以上公民饲养宠物鱼 +3011828639 NEW COB 新科布 +3994226327 NEW DA NANG 新岘港 +277076675 New Difficulty Level 新难度 +3415597541 NEW DIFFICULTY LEVEL 新难度 +2964707347 NEW DIFFICULTY UNLOCKED 已解锁新难度 +2533608836 NEW EAGLE 新鹰城 +1095692006 New equipment has now been deployed to every Super Destroyer in the galaxy. Use it to deliver Freedom, Helldivers. 新装备现已部署至银河系所有的超级驱逐舰上。绝地潜兵,请尽情使用,传播自由。 +421418845 New Evidence Suggests Famous Photo "The Slaying of the Beast of Vog-Sojoth" was Faked. 最新证据表明著名摄影作品《屠杀佛戈索约斯巨兽》主体内容不实 +696807689 New Explosive Filler 新式爆炸物填料 +3882630018 New Explosive Filler 新式爆炸物填料 +1869001254 NEW EXPLOSIVE FILLER 新式爆炸物填料 +2126950968 NEW EXPLOSIVE FILLER 新式爆炸物填料 +2950926631 NEW FRIEND REQUEST 新好友申请 +421621431 NEW HAVEN 纽黑文 +1325663098 NEW HEARTH CITY 新寒炉市 +1150711238 NEW HOPE CITY 希望新城 +2180191348 NEW HOPE CONSTRUCTION SITE 希望新城建造区 +1508181823 NEW INSIGHT 新悟 +3203629918 NEW KATHMANDU 新加德满都 +4062016236 NEW KIRUNA 新基鲁纳 +2509989429 NEW MAJOR ORDER +Activate the TCS on all Barrier Planets. 新重要指令 +启动所有屏障星球上的TCS。 +2029549166 NEW MAJOR ORDER +The Automatons have menaced our citizenry long enough. With the Terminids in check, the time has come at last to eradicate this robot scum from our galaxy. + +Eradicate the Automatons from every single planet they occupy. Leave none in operation. 新重要指令 +长久以来,机器人一直威胁着我们的公民。鉴于终结族已为我方所控制,是时候将这些机器人渣滓彻底逐出我们的星系了。 + +在机器人占据的每一颗星球上,将它们全数剿灭,一个不留。 +1597678314 NEW MAJOR ORDER +Tien Kwan is home to the sole arsenal of new Exosuit technology. It is only a matter of time before the Automatons discover the arsenal and steal it for themselves. Liberate Tien Kwan, before it's too late. 新重要指令 +天关坐落着唯一一家掌握新型外骨骼装甲科技的军械厂。机器人迟早会发现这座军械厂,窃取相关技术,为己所用。立即解放天关,以免为时过晚。 +3608034295 NEW MISSION DIFFICULTY AVAILABLE 已开放全新任务难度 +930644385 New Missions Available 解锁新任务 +1423948427 NEW NEWTONVILLE 新牛顿维尔 +216069095 NEW OPERATION AVAILABLE 有新行动可以参加 +2961331193 NEW PARADISE 新天堂 +2728602421 NEW PENG 新漂市 +3412098611 New Poll Ranks Erson Sands As Best Place To Raise Kids To Be Defenders Of Freedom. 最新民调结果显示厄尔森桑兹星系最适合家长培养自由卫士 +3547528638 New Poll Ranks Terminids As "Most Buglike" Of Super Earth's Enemies. 最新民调结果显示大众认为终结族是超级地球“最像虫子”的敌人 +3646047601 NEW SHIPMENT OF ITEMS IS INCOMING... 全新商品即将上架… +1407696270 NEW STOCKHOLM 新斯德哥尔摩 +702073419 NEW STOROUSE 新储仓 +450787924 New Strain of Bioluminescent Kittens Sells Out In Minutes! 生物荧光猫咪新品种若干分钟售罄! +3323676179 New Study Concludes Male Pattern Baldness a Patriotic Sign of Hair's Freedom to Leave Head. 最新研究发现男性脱发系头发自由脱离头部的爱国表现 +1511706843 New Study Cut Tragically Short by Terminid Strike. 终结族袭击导致最新研究不幸提前终止 +4217315838 New Study Finds Bots Twice as Authoritarian as Previously Expected. 最新研究发现机器社会专制程度为此前预期的两倍之多 +2683120236 New Study Finds Patriotism To Be ##1 Predictor Of Happiness, Longevity, Weight Loss. 最新研究发现爱国情怀是幸福、长寿和减肥的首要前提 +3667104994 New Study Finds Super Eagle to be Most Democratic Bird. 最新研究发现超级雕为最民主的鸟类 +4141672169 New Study Proves 100% of Super Earth Studies to be Accurate. 最新研究证实超级地球所有研究结果100%准确 +422331606 New Study Shows 98% of Children Under Twelve Want To 最新研究发现98%的12岁以下儿童希望 +2902232420 New Study Shows Illuminate Terror Lurks Around Every Corner And Citizens Can Never Be Too Vigilant. 最新研究表明光能者的威胁无处不在,星系公民应当格外警惕 +935670738 NEW TARGET 新目标 +2592843621 NEW TOKYO 新东京 +2121224478 New Ursine Species Discovered on Ridge World, Proven Undemocratic and Promptly Eradicated. 山岭世界发现熊科新物种,证实为非民主物种并当场灭绝 +231775463 NEW VICTORY 新胜利市 +1466635519 NEW WISDOM 新慧 +2906313102 NEW YEARNING CITY 盛盼新城 +4284868403 NEW YEARNING CONSTRUCTION SITE 盛盼新城建造区 +2251391424 NEWLY IDENTIFIED SOLAR SYSTEM MAY HAVE UP TO 3 SUITABLE PLANETS FOR COLONIZATION, ACCORDING TO MINISTRY OF SCIENCE REPORT 根据科学部报告,在新发现的恒星系中,适合建造拓殖地的星球可能多达3个 +4212371007 NEWS ALERT 重大新闻 +2597741134 NEWS FEED 新闻动态 +652439512 NEWS FEED 新闻动态 +3849167748 NEXT 继续 +792804273 NEXT ARC 下一段剧情 +1970845948 Next Category 下一个类别 +780260125 NEXT EVENT 下一战事 +3423298610 Next Location (Current Majority Vote): 下个地点(当前多数得票): +1698456374 Next Reward 下一项奖励 +525660720 NEXT UPGRADE: 下一次升级: +2243877575 NEXT WEAPON 下一件武器 +1823593404 NIBIRU 尼比鲁 +3675634490 Nicholson 尼科尔松 +1345435762 NIGHT 暗夜 +1748301752 Nilsson 尼尔松 +3254426868 Nine out of ten doctors agree that a wound to the chest will make you bleed out if unattended. 九成医生一致认为,如果不处理胸部的伤口,你就会流血致死。 +2983003231 Nitsan 尼岑 +2753928740 NIVEL 43 尼维尔43 +1304361168 NNE 东北偏北 +953064007 NNE (#COUNT°) 东北偏北#COUNT° +948103122 NNW 西北偏北 +3821192943 NNW (#COUNT°) 西北偏北#COUNT° +2532554543 NO 否 +2318849034 NO 否 +4011966658 NO 否 +2716085286 No additional bonuses. 无额外加成。 +1112655242 NO AMMO 没有弹药 +4127517891 NO AMMO 没有弹药 +1150030374 No Attachment 无配件 +2204136156 NO ATTACHMENT 无配件 +3113358465 No blocked players. 没有被屏蔽的玩家。 +1522628849 No Booster 无强化资源 +4064944355 NO BOOSTER 无强化资源 +1345816720 No Broken Limbs 四肢没有受伤 +2446718842 No chat messages to include. 无聊天消息可附加。 +4022404578 No Choke 无喉缩 +3329373305 NO CHOKE 无喉缩 +3745301240 NO COMPOUND 无堡市 +3725770996 No Deaths 从未阵亡 +2788804947 No dissident or alien, no creature big or small, can ever hope to stand against the furious stampede of Managed Democracy. 无论是异见分子还是外星敌人,无论生物体型大小,都休想抵挡管理式民主狂怒奔涌的热潮。 +1657396630 No event lobbies found 未找到战事大厅 +775038990 No friend lobbies found 未找到好友大厅 +3155965288 No friend requests. 没有好友申请。 +4035031808 No friends, yet. 暂时还没有好友。 +4129489932 NO FUEL 没有燃料 +3746915970 No Helldivers on standby 无绝地潜兵待命 +1292790287 No Muzzle 无枪口配件 +3820254624 NO MUZZLE 无枪口配件 +125111073 No muzzle attachment. 无枪口配件。 +2616985430 No muzzle choke. 无枪口喉缩。 +3587897079 No oppressive murk, no fascist penumbra, no dictatorial haze and no unfree emanation; no tyrannical Gloom shall ever stand a chance against the searing light of Helldiver fire. 无论是压迫的黑暗、法西斯的半阴影、独裁的迷雾还是非自由精神的辐射,任何专制的“阴霾”在绝地潜兵烈火般的灼热光芒前都将灰飞烟灭。 +812542269 No optic attachment 无准镜配件 +895229708 No Optics 无准镜 +433925189 NO OPTICS 无准镜 +2605008220 No player found 没有找到玩家 +650313695 No recent players, yet. 暂时还没有近期玩家。 +2094520759 No Reinforcement Pods available 暂无增援舱。 +95873278 No reinforcement point available. 暂无增援点。 +4119587914 NO ROOM 空间不足 +1173448449 NO SERVERS 无服务器 +2961673045 NO SPACE 没有空间 +4018275863 NO SPECIAL TRAITS 无特殊特性 +485709728 NO STRATAGEM 没有战略配备 +2507083482 No unclaimed rewards 没有尚未领取的奖励 +3207559202 No Underbarrel 无下挂 +22916843 NO UNDERBARREL 无下挂 +369780100 No underbarrel attachment. 无下挂配件。 +2505784575 NOISE 噪声 +3978283398 Non-Guided 非制导 +3094051902 NON-PARTISAN 超党市 +619638262 None 无 +3426737172 None 无 +437395298 NONE 无 +1184670874 NONE 无 +2887030368 NONE 无 +4079101462 NORMAL 普通 +3824072831 NORSK (Unsupported) NORSK (Unsupported) +3502399096 NOSSER 诺瑟 +287524967 Not Enough Data To Estimate 数据不足,无法估算 +992266848 NOT ENOUGH MEDALS 奖章不足 +668500134 Not in my backyard. + +Enlist. 绝不能危及家园。 + +应征入伍。 +3415334 Not much is known about this planet. 未知 +14881450 Not much is known about this planet. 未知 +16829487 Not much is known about this planet. 未知 +35452912 Not much is known about this planet. 未知 +37894509 Not much is known about this planet. 未知 +38424495 Not much is known about this planet. 未知 +40790875 Not much is known about this planet. 未知 +70418734 Not much is known about this planet. 未知 +125302513 Not much is known about this planet. 未知 +129724100 Not much is known about this planet. 未知 +149945353 Not much is known about this planet. 未知 +163457594 Not much is known about this planet. 未知 +169372105 Not much is known about this planet. 未知 +171607714 Not much is known about this planet. 未知 +179861588 Not much is known about this planet. 未知 +182613085 Not much is known about this planet. 未知 +196135185 Not much is known about this planet. 未知 +199880516 Not much is known about this planet. 未知 +207159351 Not much is known about this planet. 未知 +222371685 Not much is known about this planet. 未知 +235670415 Not much is known about this planet. 未知 +246067354 Not much is known about this planet. 未知 +265269866 Not much is known about this planet. 未知 +280740600 Not much is known about this planet. 未知 +293424533 Not much is known about this planet. 未知 +318178055 Not much is known about this planet. 未知 +337953497 Not much is known about this planet. 未知 +346314042 Not much is known about this planet. 未知 +346784578 Not much is known about this planet. 未知 +352042548 Not much is known about this planet. 未知 +356236815 Not much is known about this planet. 未知 +366648504 Not much is known about this planet. 未知 +379867334 Not much is known about this planet. 未知 +380809060 Not much is known about this planet. 未知 +381140667 Not much is known about this planet. 未知 +390099180 Not much is known about this planet. 未知 +394682596 Not much is known about this planet. 未知 +405521417 Not much is known about this planet. 未知 +409186856 Not much is known about this planet. 未知 +423571628 Not much is known about this planet. 未知 +476794755 Not much is known about this planet. 未知 +477119209 Not much is known about this planet. 未知 +496937874 Not much is known about this planet. 未知 +498333968 Not much is known about this planet. 未知 +500293760 Not much is known about this planet. 未知 +501613549 Not much is known about this planet. 未知 +513992565 Not much is known about this planet. 未知 +536003898 Not much is known about this planet. 未知 +541236438 Not much is known about this planet. 未知 +543070732 Not much is known about this planet. 未知 +544784714 Not much is known about this planet. 未知 +560244346 Not much is known about this planet. 未知 +563887562 Not much is known about this planet. 未知 +574471121 Not much is known about this planet. 未知 +592732242 Not much is known about this planet. 未知 +607081875 Not much is known about this planet. 未知 +636634761 Not much is known about this planet. 未知 +638005199 Not much is known about this planet. 未知 +644692723 Not much is known about this planet. 未知 +669023182 Not much is known about this planet. 未知 +671564727 Not much is known about this planet. 未知 +691816876 Not much is known about this planet. 未知 +696616553 Not much is known about this planet. 未知 +698845032 Not much is known about this planet. 未知 +710821004 Not much is known about this planet. 未知 +721358359 Not much is known about this planet. 未知 +723927417 Not much is known about this planet. 未知 +734628521 Not much is known about this planet. 未知 +735976853 Not much is known about this planet. 未知 +747167917 Not much is known about this planet. 未知 +759038053 Not much is known about this planet. 未知 +775530628 Not much is known about this planet. 未知 +783681730 Not much is known about this planet. 未知 +815477269 Not much is known about this planet. 未知 +828770804 Not much is known about this planet. 未知 +837262895 Not much is known about this planet. 未知 +845365900 Not much is known about this planet. 未知 +846661856 Not much is known about this planet. 未知 +847861910 Not much is known about this planet. 未知 +849379401 Not much is known about this planet. 未知 +849502854 Not much is known about this planet. 未知 +851158655 Not much is known about this planet. 未知 +860616678 Not much is known about this planet. 未知 +874072646 Not much is known about this planet. 未知 +876330716 Not much is known about this planet. 未知 +905309513 Not much is known about this planet. 未知 +940530831 Not much is known about this planet. 未知 +964957063 Not much is known about this planet. 未知 +979668381 Not much is known about this planet. 未知 +986874313 Not much is known about this planet. 未知 +989136222 Not much is known about this planet. 未知 +991851783 Not much is known about this planet. 未知 +994552698 Not much is known about this planet. 未知 +1052101257 Not much is known about this planet. 未知 +1055503030 Not much is known about this planet. 未知 +1064788115 Not much is known about this planet. 未知 +1096582530 Not much is known about this planet. 未知 +1097082914 Not much is known about this planet. 未知 +1099893987 Not much is known about this planet. 未知 +1100838265 Not much is known about this planet. 未知 +1102455063 Not much is known about this planet. 未知 +1127333130 Not much is known about this planet. 未知 +1128318835 Not much is known about this planet. 未知 +1133331067 Not much is known about this planet. 未知 +1148626776 Not much is known about this planet. 未知 +1153079351 Not much is known about this planet. 未知 +1154884549 Not much is known about this planet. 未知 +1155954398 Not much is known about this planet. 未知 +1188671070 Not much is known about this planet. 未知 +1200775727 Not much is known about this planet. 未知 +1220564275 Not much is known about this planet. 未知 +1234134964 Not much is known about this planet. 未知 +1260781333 Not much is known about this planet. 未知 +1281626413 Not much is known about this planet. 未知 +1302721265 Not much is known about this planet. 未知 +1351573785 Not much is known about this planet. 未知 +1352658065 Not much is known about this planet. 未知 +1360171009 Not much is known about this planet. 未知 +1368910238 Not much is known about this planet. 未知 +1369704001 Not much is known about this planet. 未知 +1377558815 Not much is known about this planet. 未知 +1384800625 Not much is known about this planet. 未知 +1387189142 Not much is known about this planet. 未知 +1393788306 Not much is known about this planet. 未知 +1396646413 Not much is known about this planet. 未知 +1401075638 Not much is known about this planet. 未知 +1436541877 Not much is known about this planet. 未知 +1440367083 Not much is known about this planet. 未知 +1440732110 Not much is known about this planet. 未知 +1444097505 Not much is known about this planet. 未知 +1455812852 Not much is known about this planet. 未知 +1500272076 Not much is known about this planet. 未知 +1509118015 Not much is known about this planet. 未知 +1519537554 Not much is known about this planet. 未知 +1523141570 Not much is known about this planet. 未知 +1544020724 Not much is known about this planet. 未知 +1563519737 Not much is known about this planet. 未知 +1571419000 Not much is known about this planet. 未知 +1592659928 Not much is known about this planet. 未知 +1600569559 Not much is known about this planet. 未知 +1606297654 Not much is known about this planet. 未知 +1616831615 Not much is known about this planet. 未知 +1624199958 Not much is known about this planet. 未知 +1637889699 Not much is known about this planet. 未知 +1651478897 Not much is known about this planet. 未知 +1657727475 Not much is known about this planet. 未知 +1715337177 Not much is known about this planet. 未知 +1741704172 Not much is known about this planet. 未知 +1744150534 Not much is known about this planet. 未知 +1766099987 Not much is known about this planet. 未知 +1768195961 Not much is known about this planet. 未知 +1776879455 Not much is known about this planet. 未知 +1788938205 Not much is known about this planet. 未知 +1794880589 Not much is known about this planet. 未知 +1798420664 Not much is known about this planet. 未知 +1810147530 Not much is known about this planet. 未知 +1813268956 Not much is known about this planet. 未知 +1832315388 Not much is known about this planet. 未知 +1834073347 Not much is known about this planet. 未知 +1840983393 Not much is known about this planet. 未知 +1841826768 Not much is known about this planet. 未知 +1843987253 Not much is known about this planet. 未知 +1856257560 Not much is known about this planet. 未知 +1860113674 Not much is known about this planet. 未知 +1861781896 Not much is known about this planet. 未知 +1863900176 Not much is known about this planet. 未知 +1869137776 Not much is known about this planet. 未知 +1876911081 Not much is known about this planet. 未知 +1877124884 Not much is known about this planet. 未知 +1899890705 Not much is known about this planet. 未知 +1909834013 Not much is known about this planet. 未知 +1910935327 Not much is known about this planet. 未知 +1920797433 Not much is known about this planet. 未知 +1922856298 Not much is known about this planet. 未知 +1954812789 Not much is known about this planet. 未知 +1954863675 Not much is known about this planet. 未知 +1956121965 Not much is known about this planet. 未知 +1960734304 Not much is known about this planet. 未知 +1971579583 Not much is known about this planet. 未知 +1981927828 Not much is known about this planet. 未知 +1986627572 Not much is known about this planet. 未知 +2011403767 Not much is known about this planet. 未知 +2021607808 Not much is known about this planet. 未知 +2036938262 Not much is known about this planet. 未知 +2042181890 Not much is known about this planet. 未知 +2055421011 Not much is known about this planet. 未知 +2056979701 Not much is known about this planet. 未知 +2069462311 Not much is known about this planet. 未知 +2071377108 Not much is known about this planet. 未知 +2088267641 Not much is known about this planet. 未知 +2090195605 Not much is known about this planet. 未知 +2101006324 Not much is known about this planet. 未知 +2137542345 Not much is known about this planet. 未知 +2138647213 Not much is known about this planet. 未知 +2146730072 Not much is known about this planet. 未知 +2171531708 Not much is known about this planet. 未知 +2188248277 Not much is known about this planet. 未知 +2209565657 Not much is known about this planet. 未知 +2243848952 Not much is known about this planet. 未知 +2251917506 Not much is known about this planet. 未知 +2254072857 Not much is known about this planet. 未知 +2292582320 Not much is known about this planet. 未知 +2295362658 Not much is known about this planet. 未知 +2296962065 Not much is known about this planet. 未知 +2307358133 Not much is known about this planet. 未知 +2310758180 Not much is known about this planet. 未知 +2383194414 Not much is known about this planet. 未知 +2386528247 Not much is known about this planet. 未知 +2396194048 Not much is known about this planet. 未知 +2410601166 Not much is known about this planet. 未知 +2413997357 Not much is known about this planet. 未知 +2422343601 Not much is known about this planet. 未知 +2431191520 Not much is known about this planet. 未知 +2459634787 Not much is known about this planet. 未知 +2463363546 Not much is known about this planet. 未知 +2471906713 Not much is known about this planet. 未知 +2480987539 Not much is known about this planet. 未知 +2481539336 Not much is known about this planet. 未知 +2490822601 Not much is known about this planet. 未知 +2495155753 Not much is known about this planet. 未知 +2495253146 Not much is known about this planet. 未知 +2519645656 Not much is known about this planet. 未知 +2520638833 Not much is known about this planet. 未知 +2526165328 Not much is known about this planet. 未知 +2528469051 Not much is known about this planet. 未知 +2533196689 Not much is known about this planet. 未知 +2542905200 Not much is known about this planet. 未知 +2544350923 Not much is known about this planet. 未知 +2574842690 Not much is known about this planet. 未知 +2579047542 Not much is known about this planet. 未知 +2606603087 Not much is known about this planet. 未知 +2608634901 Not much is known about this planet. 未知 +2635626170 Not much is known about this planet. 未知 +2648438993 Not much is known about this planet. 未知 +2665279633 Not much is known about this planet. 未知 +2690990992 Not much is known about this planet. 未知 +2703264067 Not much is known about this planet. 未知 +2709724928 Not much is known about this planet. 未知 +2727007226 Not much is known about this planet. 未知 +2730564149 Not much is known about this planet. 未知 +2752298661 Not much is known about this planet. 未知 +2754737465 Not much is known about this planet. 未知 +2769011681 Not much is known about this planet. 未知 +2777160708 Not much is known about this planet. 未知 +2777631244 Not much is known about this planet. 未知 +2795807034 Not much is known about this planet. 未知 +2798593236 Not much is known about this planet. 未知 +2807326037 Not much is known about this planet. 未知 +2810548766 Not much is known about this planet. 未知 +2822310909 Not much is known about this planet. 未知 +2825040173 Not much is known about this planet. 未知 +2829208561 Not much is known about this planet. 未知 +2846958731 Not much is known about this planet. 未知 +2855846799 Not much is known about this planet. 未知 +2866122630 Not much is known about this planet. 未知 +2866225573 Not much is known about this planet. 未知 +2873462989 Not much is known about this planet. 未知 +2876478471 Not much is known about this planet. 未知 +2888129135 Not much is known about this planet. 未知 +2925450467 Not much is known about this planet. 未知 +2937033102 Not much is known about this planet. 未知 +2958892596 Not much is known about this planet. 未知 +3041244548 Not much is known about this planet. 未知 +3071335446 Not much is known about this planet. 未知 +3080761082 Not much is known about this planet. 未知 +3091609804 Not much is known about this planet. 未知 +3112970015 Not much is known about this planet. 未知 +3135493657 Not much is known about this planet. 未知 +3140249806 Not much is known about this planet. 未知 +3155398956 Not much is known about this planet. 未知 +3207971879 Not much is known about this planet. 未知 +3215105768 Not much is known about this planet. 未知 +3235946435 Not much is known about this planet. 未知 +3260412817 Not much is known about this planet. 未知 +3262651298 Not much is known about this planet. 未知 +3285131061 Not much is known about this planet. 未知 +3294732250 Not much is known about this planet. 未知 +3321373642 Not much is known about this planet. 未知 +3327005717 Not much is known about this planet. 未知 +3339644534 Not much is known about this planet. 未知 +3354493846 Not much is known about this planet. 未知 +3356696792 Not much is known about this planet. 未知 +3358511735 Not much is known about this planet. 未知 +3363201044 Not much is known about this planet. 未知 +3413020356 Not much is known about this planet. 未知 +3414366619 Not much is known about this planet. 未知 +3418968587 Not much is known about this planet. 未知 +3425904814 Not much is known about this planet. 未知 +3438649121 Not much is known about this planet. 未知 +3455993788 Not much is known about this planet. 未知 +3468937862 Not much is known about this planet. 未知 +3472158635 Not much is known about this planet. 未知 +3474023215 Not much is known about this planet. 未知 +3489533456 Not much is known about this planet. 未知 +3494550326 Not much is known about this planet. 未知 +3505533461 Not much is known about this planet. 未知 +3508750577 Not much is known about this planet. 未知 +3534334954 Not much is known about this planet. 未知 +3541023337 Not much is known about this planet. 未知 +3552412487 Not much is known about this planet. 未知 +3578568891 Not much is known about this planet. 未知 +3579090922 Not much is known about this planet. 未知 +3613667837 Not much is known about this planet. 未知 +3625902892 Not much is known about this planet. 未知 +3626549577 Not much is known about this planet. 未知 +3641252510 Not much is known about this planet. 未知 +3662335600 Not much is known about this planet. 未知 +3670045382 Not much is known about this planet. 未知 +3672735503 Not much is known about this planet. 未知 +3680923929 Not much is known about this planet. 未知 +3689153387 Not much is known about this planet. 未知 +3689262198 Not much is known about this planet. 未知 +3690459614 Not much is known about this planet. 未知 +3699173130 Not much is known about this planet. 未知 +3762112087 Not much is known about this planet. 未知 +3765717289 Not much is known about this planet. 未知 +3774133754 Not much is known about this planet. 未知 +3781056562 Not much is known about this planet. 未知 +3786402002 Not much is known about this planet. 未知 +3801573631 Not much is known about this planet. 未知 +3853638486 Not much is known about this planet. 未知 +3859378194 Not much is known about this planet. 未知 +3870546934 Not much is known about this planet. 未知 +3875363401 Not much is known about this planet. 未知 +3883771315 Not much is known about this planet. 未知 +3952083751 Not much is known about this planet. 未知 +3957297661 Not much is known about this planet. 未知 +4002694918 Not much is known about this planet. 未知 +4014468095 Not much is known about this planet. 未知 +4029307286 Not much is known about this planet. 未知 +4038600486 Not much is known about this planet. 未知 +4061126716 Not much is known about this planet. 未知 +4089347326 Not much is known about this planet. 未知 +4093368079 Not much is known about this planet. 未知 +4099756016 Not much is known about this planet. 未知 +4117380630 Not much is known about this planet. 未知 +4121140021 Not much is known about this planet. 未知 +4125819870 Not much is known about this planet. 未知 +4131334693 Not much is known about this planet. 未知 +4137589588 Not much is known about this planet. 未知 +4146967339 Not much is known about this planet. 未知 +4152680051 Not much is known about this planet. 未知 +4160556404 Not much is known about this planet. 未知 +4160586354 Not much is known about this planet. 未知 +4162825007 Not much is known about this planet. 未知 +4168458073 Not much is known about this planet. 未知 +4170693832 Not much is known about this planet. 未知 +4171075538 Not much is known about this planet. 未知 +4198200621 Not much is known about this planet. 未知 +4204853773 Not much is known about this planet. 未知 +4219308386 Not much is known about this planet. 未知 +4226477129 Not much is known about this planet. 未知 +4250663430 Not much is known about this planet. 未知 +4256936100 Not much is known about this planet. 未知 +4260257322 Not much is known about this planet. 未知 +4277436083 Not much is known about this planet. 未知 +4283177289 Not much is known about this planet. 未知 +2961421936 NOT READY 尚未就位 +2877533264 Nothing is bigger than Freedom 自由价更高 +1055870056 NOTICE 通知 +3302043377 Notifying others to follow. 正在通知其他人员跟进。 +3862237568 Nov 11月 +2947940736 November 11月 +2422321216 NOW, IT IS CLEAR THAT THERE CAN BE NO PEACE UNTIL 现在,显而易见,我们必须彻底摧毁 +3261100878 NUBLARIA I 努布拉里亚I +4280970126 Nuclear Missile 核导弹 +3954783990 NUCLEAR RADAR 核动力雷达 +3504847753 Nuke 核弹 +3818032832 NUKE 核弹 +278687057 Nuke all Terminid nurseries and collapse the specified number of nests. 用核武器炸毁所有终结族繁育窝,摧毁指定数量的巢穴。 +2232151788 NUKE NURSERY 用核武器炸毁繁育窝 +1996703633 NUKE NURSERY CHAMBER 用核武器炸毁繁育腔室 +358548648 Number 4 Voted "Most Democratic Number." 数字4获选成为“最民主数字” +420079450 Number of grenades each Helldiver deploys with decreased by #V_ONE. 每位绝地潜兵上阵时配给的榴弹数量减少#V_ONE。 +271258196 Number of grenades each Helldiver deploys with increased by #V_ONE. 每位绝地潜兵上阵时配给的榴弹数量增加#V_ONE。 +1775857616 Number of grenades each Helldiver deploys with is temporarily decreased by #V_ONE. 每位绝地潜兵上阵时配给的榴弹数量暂时减少#V_ONE。 +659452616 Number of grenades each Helldiver deploys with is temporarily increased by #V_ONE. 每位绝地潜兵上阵时配给的榴弹数量暂时增加#V_ONE。 +141087962 Number of magazines for all weapons Helldivers deploy with is temporarily decreased by #V_ONE. 绝地潜兵上阵时配给的所有武器弹匣数量暂时减少#V_ONE。 +1766576141 Number of magazines for all weapons Helldivers deploy with is temporarily increased by #V_ONE. 绝地潜兵上阵时配给的所有武器弹匣数量暂时增加#V_ONE。 +3169807818 Number of magazines Helldivers deploy with for all weapons increased by #V_ONE. 绝地潜兵上阵时配给的所有武器弹匣数量增加#V_ONE。 +4262661334 Number of reinforcements available per mission decreased by #V_ONE. 每次任务的可用增援数减少#V_ONE。 +4134510414 Number of reinforcements available per mission increased by #V_ONE. 每次任务的可用增援数增加#V_ONE。 +1269775050 Number of reinforcements available per mission is temporarily decreased by #V_ONE. 每次任务的可用增援数暂时减少#V_ONE。 +3022153599 Number of reinforcements available per mission is temporarily increased by #V_ONE. 每次任务的可用增援数暂时增加#V_ONE。 +2914005300 Number of stims each Helldiver deploys with decreased by #V_ONE. 每位绝地潜兵上阵时配给的治疗剂数量减少#V_ONE。 +9138940 Number of stims each Helldiver deploys with increased by #V_ONE. 每位绝地潜兵上阵时配给的治疗剂数量增加#V_ONE。 +1388682879 Number of stims each Helldiver deploys with is temporarily decreased by #V_ONE. 每位绝地潜兵上阵时配给的治疗剂数量暂时减少#V_ONE。 +1991087075 Number of stims each Helldiver deploys with is temporarily increased by #V_ONE. 每位绝地潜兵上阵时配给的治疗剂数量暂时增加#V_ONE。 +2635572434 Number of uses of #V_ONE stratagem increased by #V_TWO. #V_ONE战略配备的可用次数增加#V_TWO。 +298108088 Number of uses of #V_ONE stratagem is temporarily increased by #V_TWO. #V_ONE战略配备的可用次数暂时增加#V_TWO。 +3673381184 Number of uses of #V_ONE stratagem is temporarily reduced by #V_TWO. #V_ONE战略配备的可用次数暂时减少#V_TWO。 +436895486 Number of uses of #V_ONE stratagem reduced by #V_TWO. #V_ONE战略配备的可用次数减少#V_TWO。 +705284749 Nummi 努米 +1488299252 NUOVA ROMA 新罗马 +487985459 Nursing Spewer 抚育喷涌虫 +2234285621 NURSING SPEWER 抚育喷涌虫 +1430722332 Nursing Spewers 抚育喷涌虫 +3177759969 NVIDIA Reflex Low Latency NVIDIA Reflex低延迟 +2505236864 NVIDIA Reflex tries to reduce the system latency and increases responsiveness. When enabled, NVIDIA Reflex will reduce latency from the GPU. Boost mode will try to also reduce latency from the CPU. NVIDIA Reflex旨在降低系统延迟并提升响应速度。启用后,NVIDIA Reflex将降低GPU的延迟。增强模式也将尽可能降低CPU的延迟。 +661418041 NW 西北 +1005505770 NW 西北 +4049374668 NW (#COUNT°) 西北#COUNT° +727719679 NYA SKELLEFTEA 新谢莱夫特奥 +3745869348 Nystrom 奈斯特伦 +3878595924 Nystrom 奈斯特伦 +1511917268 O-2 Heavy Operator O-2“重装操作者” +2958374193 O-2 HEAVY OPERATOR O-2“重装操作者” +2732014232 O-3 Free Spirit O-3“自由之魂” +1995236842 O-3 FREE SPIRIT O-3“自由之魂” +1005051052 O-44 Bonded Pilot O-44“契约驾驶员” +588663789 O-44 BONDED PILOT O-44“契约驾驶员” +973640366 OASIS 绿洲 +3868806488 OBARI 欧巴里 +3511132020 OBEDIENCE 服从市 +3290486494 Obedient Democracy Support Troopers 民主光环驰援部队 +2996935564 OBEDIENT DEMOCRACY SUPPORT TROOPERS 民主光环驰援部队 +4046469061 Object Detail Quality 物体细节质量 +4100333583 Objective 目标 +67679472 OBJECTIVE COMPLETED 目标达成 +1897163677 OBJECTIVE FAILED 目标未达成 +3592212003 OBJECTIVE LOCATION UNKNOWN 目标位置未确认 +1271275044 OBJECTIVE UPDATED 目标已更新 +1854029696 Objectives 目标 +14029376 Objectives bonus: #AMOUNT M 目标加分:#AMOUNT +2200219071 Objectives Completed 目标达成数 +2934149411 OBSERVATORY 6 监测站6 +1716249415 Obstructed by Anti-Air 被防空系统阻拦 +279570205 Obtain all trophies of HELLDIVERS™ 2. 获得《HELLDIVERS™ 2》的全部奖杯。 +2554856065 OBTAIN COORDINATES 获取坐标 +3621116014 Obtruder 突入者 +193486143 OBTRUDER 突入者 +4114505470 Obtruders 突入者 +3457318868 Oct 10月 +2306920540 Octagon 之八方 +4192193767 October 10月 +3101528587 ÖDESHÖGRE 厄德斯霍格雷 +824245265 of Allegiance 忠诚 +1375156788 of Audacity 勇猛 +4250292210 of Authority 权威 +378088611 of Battle 激战 +3476617682 of Benevolence 博爱 +488348329 of Conquest 征服 +1865405032 of Conviction 坚定 +857939189 of Conviviality 友善 +1545626923 of Courage 刚毅 +3554691971 of Dawn 破晓 +586869523 of Democracy 民主 +2688256510 of Destiny 天命 +3748497362 of Destruction 毁灭 +292916820 of Determination 坚决 +700370958 of Equality 公正 +3133145775 of Eternity 永恒 +2339943306 of Family Values 情义 +1851392616 of Fortitude 坚韧 +673039732 of Freedom 自由 +2284867278 of Glory 荣耀 +2427721281 of Gold 黄金 +1865951418 of Honor 尊荣 +3460683182 of Humankind 人类 +1870238113 of Independence 独立 +2502682152 of Individual Merit 独贤 +2174969617 of Integrity 诚实 +468658976 of Iron 铸铁 +2179256312 of Judgment 判决 +4224354626 of Justice 正义 +277539039 of Law 法律 +1566867439 of Liberty 解放 +973485101 of Mercy 仁慈 +2128884238 of Midnight 午夜 +4100527148 of Morality 道德 +4106646137 of Morning 清晨 +3059367381 of Opportunity 机遇 +3690215169 of Patriotism 丹心 +3241077179 of Peace 和平 +2613210726 of Perseverance 不屈 +458728157 of Pride 自豪 +2304245072 of Redemption 救赎 +1945792198 of Science 科学 +3483017602 of Self-Determination 自主 +2812246737 of Selfless Service 无私 +3682640031 of Serenity 宁静 +1754556682 of Starlight 星光 +3935517876 of Steel 钢铁 +991891387 of Super Earth 超级地球 +595251819 of Supremacy 至高 +3653296105 of the Constitution 宪法 +2363065433 of the People 民众 +3915924298 of the Regime 政权 +3283474813 of the Stars 星辰 +1780560514 of the State 国家 +1533261444 of Truth 真理 +74872499 of Twilight 暮光 +1627731364 of Victory 胜利 +124817064 of Vigilance 警惕 +3787334875 of War 战争 +1130294731 of Wrath 盛怒 +1613642756 Off 关 +3981595988 Off 关 +2693840430 OFF 关 +3584382195 Off (Diagnostics) 关(诊断) +3491214314 Off: Aiming always starts in third person view aim mode. +Global: All weapons use the last selected aim mode. +Per Weapon: The last used aim mode is stored per weapon. 关:始终默认为第三人称瞄准模式。 +全局应用:所有武器都会使用玩家最后选择的瞄准模式。 +视武器而异:每件武器都会使用玩家上一次使用这件武器时选择的瞄准模式。 +1810107032 OFFENSIVE 进攻 +3809195507 Offensive - Discrimination 冒犯性 - 歧视 +2795043115 OFFENSIVE ADVANTAGE 进攻优势 +30700920 Offensive Language 冒犯性言辞 +1096445162 OFFENSIVE STRATAGEM PERMIT 进攻型战略配备许可证 +328796876 Offering camouflage in snowy environments, surplus sets of this armor are used by nature photographers and keen hunters alike. 适用于雪地环境的迷彩,富余的盔甲在户外摄影师和打猎爱好者手中也相当实用。 +3871291455 Offers its user brief fixed-height flight, stable enough for pinpoint marksmanship. 穿戴者可在固定高度短暂稳定飞行,确保实现精确射击。 +1838907560 OFFERS VALID FOR 优惠有效期: +3797578298 Offline 离线 +185739328 OFFLINE 损毁 +2390757704 Often showcased in the "Obedient Democracy Support Troopers" cartoon, this assault rifle comes with a convenient ammo counter and compass. +Produced by Martian Armory. 这款突击步枪经常在《民主光环驰援部队》卡通片中出现,配备了便捷的弹药计数器和指南针。 +由火星军械库生产。 +3477736393 Oil Extractor 采油机 +3496147451 OIL EXTRACTORS ACTIVATING 采油机正在启动 +3310433830 OIL PUMP CONTROL SYSTEM 油泵控制系统 +1828683420 Oil pumps activating 油泵正在启动 +1866216199 OK 确定 +3321880737 OK 无损 +2810888169 OK. 确定 +413130434 Okane_82 冈根_82 +2879388280 OKUL VI 欧库VI +3130272281 OL' OLDHAM 老奥尔德姆 +822223750 OLD BRANCH 旧枝城 +3235228187 OLD CHEMLAND 旧化工城 +1350043281 OLD CONUNDRUM 旧谜市 +985314915 OLD DOVE 老鸽城 +3569445028 OLD HEARTH CITY 旧寒炉市 +3715919548 OLD INTERNMENTS 旧禁所 +7787042 Olofson 奥洛夫松 +3528833315 Olofsson 奥洛夫松 +729485079 OLUFSEN'S FOOTPRINT 奥卢夫森足迹 +2500578114 OMA PEMMA 欧玛佩玛 +2878495787 OMA PEMMA 欧玛佩玛 +3982424137 Ombudsman 巡察者 +728846548 Ombudsman 巡察者 +3602150526 OMBUDSMAN 巡察者 +3377907980 OMEGA SECTOR 欧米茄分区 +1665734336 OMICRON 奥密克戎 +3908037216 OMNIPARITUS 全诛堡 +2547716136 on on +3597485130 On 开 +3700265673 On 开 +333192610 ON 开 +1489571100 on #PLANET 在#PLANET上 +2808737988 On + Boost 开启 + 增强 +2856343586 on 难度: +3353541931 on 位置: +1583251077 On a mission alone and dying to have someone liberating by your side? Use an SOS beacon to call in a fellow Helldiver. 你是否在独自执行任务,企盼有战友加入你的解放之旅?使用SOS信标呼叫其他绝地潜兵吧。 +1032642173 on a planet controlled by the 星球势力: +3485732402 on a planet controlled by the 星球势力: +1019700723 On Main Menu 浏览主菜单 +4166689017 On Ship 在船舰上 +123065014 ON SHIP 在舰船上 +1343686329 on the planet 星球: +3636211799 on the planet 星球: +3812730735 On the surface, only a lamp, but any true patriot recognizes this for what it is: an abomination. 看似一盏灯,但真正的爱国者都能认出它那面目可憎的本质。 +3862347886 On this planet is one of 3 Maximum Security Cities: impregnable bastions against Tyranny. 三大最高安全级别城市之一坐落在这颗星球上:这是对抗暴政的堡垒,坚不可摧。 +3431457534 On this planet, a network of Termicide-dispensing towers repels Terminids emerging from the Gloom. 在这颗星球上,喷洒灭虫终结剂的高塔网络抵御着源自“阴霾”的终结族。 +3974317902 On this planet, the Ministry of Science’s best and brightest work on their next breakthrough. 在此星球上,科学部的顶尖人才正在全力推动下一项突破。 +4037455426 On this planet, workers are constructing one of 3 Maximum Security Cities: impregnable bastions against Tyranny. 工人正在这颗星球上建设三大最高安全级别城市的其中一座:这是对抗暴政的堡垒,坚不可摧。 +2881482997 ON-EARSAHOU 顿听呼 +673806766 ON-SCREEN ONLY 仅显示游戏指示文字 +2632570592 Once acquired, bring the footage to this location for secure extraction. 获取录像后,将其运至此处进行安全撤离。 +4072697637 Once alive with a calming hum, the abandoned machine now lies dormant. 这台机器曾经能发出让人安心的嗡嗡声,现在则遭到遗忘,在此长眠。 +923261140 Once the black box has been secured, it must be transported to this interplanetary uplink site to upload its data to the Ministry of Defense's top-secret network. 拿到黑匣子之后,必须将它转移到这个星际上行链路点位,将数据上传到国防部的绝密网络。 +4142990363 Once the GATER is secured, use it to extract the resources in this area. GATER到位就绪后,立即使用它在该区域提取资源。 +1336016081 ONE 一 +256689238 ONE HANDED 单手操作 +768786388 ONE HANDED 单手操作 +4044730534 ONE HANDED 单手操作 +2345416589 One leg is injured, slowing you down and making you unable to sprint. 有一条腿受伤,减慢了你的移动速度,导致你无法冲刺。 +985262540 One of 3 Maximum Security Cities. Impregnable to Tyranny; the future of the Federation. 三大最高安全级别城市之一。暴政无法攻破之城,联邦的未来。 +3287745344 One of the earliest to be mass-produced, this cape has been the final sight of untold numbers of Freedom's foes. 作为最早量产的披肩之一,此披肩已经见证了无数自由之敌的陨落。 +663982266 One of the most durable engineer armors available, each set is quality tested by an impact with a full-grown Charger. 最耐用的工兵盔甲之一。每一套盔甲的质量检测流程都是抵挡一只成年强袭虫的冲撞。 +1764323819 One True Flag 唯一真旗 +3861046095 ONE TRUE FLAG 唯一真旗 +1982870314 ONE-HANDED 单手操作 +3098378895 One-Two 幺二 +645907184 ONE-TWO 幺二 +3373431122 Online 在线 +642574783 ONSEN 温泉湾 +1210460507 OPACITY 不透明度 +3816742262 Open 打开 +4038850651 Open STRATAGEM MENU and call in a ORBITAL 120MM HE STRIKE at the remaining targets. 打开战略配备菜单,呼叫轨道120MM高爆弹攻击,瞄准剩下的目标。 +3714758147 Open STRATAGEM MENU and enter code for ORBITAL PRECISION STRIKE and throw BEACON at target. 打开战略配备菜单,输入轨道精准攻击的代码,然后朝目标投掷信标。 +4212716028 OPEN BACK HATCH 打开后盖 +481422540 OPEN BUNKER HATCH 打开掩体舱门 +3936000691 OPEN CHAT 开启聊天 +2826008731 OPEN COMMS WHEEL 打开通信轮盘 +2356532435 Open Door 开门 +3486162981 OPEN DROP WHEEL 打开弃置轮盘 +4056183753 OPEN EMOTE WHEEL 打开表情轮盘 +3181431801 Open hatch to deliver SSSD 打开舱门运送超级固态硬盘 +3027009686 OPEN MAP 打开地图 +1497643302 OPEN MICROPHONE 打开麦克风 +2782525585 Open Shuttle Bay Door 打开运输船坞门 +1268370994 OPEN SILO HATCH 打开发射井舱门 +1449175215 OPEN SSSD HATCH 打开超级固态硬盘舱门 +4096156737 OPEN STRATAGEM LIST 打开战略配备列表 +1018341841 Open the SOCIAL MENU. Here you can see your friends' activities and JOIN A MISSION. 打开社交菜单。你可以在这里查看好友的动态,并且加入任务。 +1063103250 Open valve 打开阀门 +3171252754 OPEN VEHICLE FUNCTION WHEEL 打开载具功能轮盘 +236178681 OPEN WEAPON WHEEL 打开武器轮盘 +2086176844 Operate Data Jack terminal 操作数据接口终端 +3615493305 Operate deep in enemy territory to uncover what vast operation the Automatons want to keep out of Liberty's sight. 深入敌方领地,调查机器人试图瞒过自由锐眼的大规模行动。 +3400225842 OPERATED BY #NAME 操作员:#NAME +1367202795 Operating at 100% efficiency 当前运行效率:100% +828430095 OPERATION 行动 +1409318230 OPERATION "VALIANT ENCLOSURE" BEGINS “英勇围合”行动开始 +2538257809 OPERATION COMPLETE 行动完成 +1405381893 OPERATION COMPLETED 行动完成 +3873985093 OPERATION CONSUMING VOID SUCCESS 吞噬寂域行动成功完成 +2662096373 OPERATION FAILED 行动失败 +785844264 OPERATION FAILED 行动失败 +450606106 OPERATION IMPACT 行动影响 +1175249090 OPERATION IMPACT 行动影响 +2510020937 OPERATION IMPACT 行动影响 +3142675334 OPERATION IMPACT 行动影响 +3987183872 OPERATION IMPACT 行动影响 +979606697 OPERATION MODIFIER ADDED 已添加行动限制条件 +2442819854 OPERATION MODIFIER REMOVED 已移除行动限制条件 +2293035076 Operation Modifiers 行动限制条件 +2186316023 OPERATION MODIFIERS 行动限制条件 +3777103266 OPERATION REWARD 行动奖励 +1108590970 OPERATION STATUS 行动状态 +61509627 OPERATION STATUS 行动状态 +2777830035 OPERATION SUCCESSFUL 行动成功 +2582716817 OPERATION SWIFT DISASSEMBLY CONTINUES 急速拆解行动继续进行中 +1470428275 Operation Valiant Enclosure In Crisis. 英勇围合行动面临危机 +2883316736 Operation Valiant Enclosure Proceeding "As Expected" According to MOD Report. 国防部报告称英勇围合行动“如期”推进 +3134031991 OPERATIONAL SUPPORT 行动支持 +3087338564 OPERATIONAL VARIATIONS 行动变量 +1967726599 OPERATIONS 行动 +2912736999 Operations on higher difficulties are more challenging and contain new Enemies and Missions. + +Complete an Operation on your highest unlocked difficulty to unlock the one above it. 行动难度越高,挑战性越高,还会出现新的敌人和任务。 + +完成已解锁的最高难度行动即可解锁更高难度。 +428146136 Operations on higher difficulties are more challenging, contain new enemies and missions. + +They also have a greater impact on the war, and yield higher rewards. Complete an operation on your highest unlocked difficulty to unlock the one above it. 行动的难度越高,就越具挑战性,其中包含新的敌人和新的任务。 + +它们对战争的影响也会提升,并产生更丰厚的奖励。完成一项已解锁的最高难度行动,即可解锁更高一级的难度。 +1806123560 Operator: 操作员: +939787527 Opportunity Completed 完成机遇任务 +3440423585 Opportunity Mission 机遇任务 +952027228 Opportunity Mission 机遇任务 +2391925668 OPPORTUNITY MISSION 机遇任务 +944677035 OPPORTUNITY REWARD 机遇奖励 +2268392056 OPPORTUNITY TO EXCEL 趁机超越 +1076885230 OPPRESSIVE MACHINE 压迫机器 +218189480 OPT 准镜 +1334774685 Optics 准镜 +3876695064 OPTICS 准镜 +3965496950 OPTICS 准镜 +3772736748 Optimizes the audio experience for the device you are listening on. 优化你使用的音频设备的听觉体验。 +4062007571 Option #NUMBER 选项#NUMBER +1855638012 OPTIONAL OBJECTIVE 可选目标 +2996595955 OPTIONAL OBJECTIVES 可选目标 +1951969997 Options 游戏设置 +1859585614 OPTIONS 游戏设置 +2348989824 OPTIONS 设置 +831568279 or higher 或以上 +2048784726 or sprint to climb obstacles 或冲刺攀爬障碍物 +2620777981 or sprint to traverse multiple obstacles 或冲刺穿过多处障碍 +1832780853 ORBITAL 轨道武器 +1653299843 Orbital 120mm HE Barrage 轨道120mm高爆弹火力网 +1336596117 ORBITAL 120MM HE BARRAGE 轨道120MM高爆弹火力网 +1007592719 Orbital 120mm HE Strike stratagem availability has ended. 现已无法使用“轨道120mm高爆弹攻击”战略配备。 +2042544950 ORBITAL 120MM HE/EMS BARRAGE 轨道120MM高爆/电磁弹火力网 +2843766581 Orbital 380mm HE Barrage 轨道380mm高爆弹火力网 +4043773877 ORBITAL 380MM HE BARRAGE 轨道380MM高爆弹火力网 +681502033 Orbital 380mm HE Barrage stratagem availability has ended. 现已无法使用“轨道380mm高爆弹火力网”战略配备。 +3593752689 Orbital Airburst Strike 轨道空爆攻击 +643358088 ORBITAL AIRBURST STRIKE 轨道空爆攻击 +2980169751 Orbital Airburst Strike stratagem availability has ended. 现已无法使用“轨道空爆攻击”战略配备。 +3075730854 ORBITAL BLOCKADE 轨道封锁 +848932066 ORBITAL BLOCKADE 轨道封锁 +2149309645 ORBITAL BLOCKADE 轨道封锁 +2977726740 Orbital Cannons 轨道加农炮 +641069579 ORBITAL CANNONS 轨道加农炮 +1279850962 ORBITAL CANNONS 轨道加农炮 +2150879167 Orbital Defenses 轨道防御 +2555770549 ORBITAL DEFENSES 轨道防御 +1447724304 Orbital EMS Strike 轨道电磁冲击波攻击 +2006588957 ORBITAL EMS STRIKE 轨道电磁冲击波攻击 +608133461 Orbital EMS Strike stratagem availability has ended. 现已无法使用“轨道电磁冲击波攻击”战略配备。 +4013032932 Orbital Fluctuations 轨道波动 +1959596684 ORBITAL FLUCTUATIONS 轨道波动 +3368107320 ORBITAL FLUCTUATIONS 轨道波动 +131377774 Orbital Gas Round Mk2 轨道毒气弹 Mk2 +3659912596 ORBITAL GAS ROUND MK2 轨道毒气弹 Mk2 +3198677475 Orbital Gas Round Mk3 轨道毒气弹 MK3 +4064814577 ORBITAL GAS ROUND MK3 轨道毒气弹 MK3 +179374902 Orbital Gas Strike 轨道毒气攻击 +887029485 ORBITAL GAS STRIKE 轨道毒气攻击 +236488569 Orbital Gas Strike stratagem availability has ended. 现已无法使用“轨道毒气攻击”战略配备。 +1248707192 Orbital Gatling Barrage 轨道加特林火力网 +2016029820 ORBITAL GATLING BARRAGE 轨道加特林火力网 +800984942 Orbital Gatling Barrage stratagem availability has ended. 现已无法使用“轨道加特林火力网”战略配备。 +2948242315 Orbital HE barrage spread reduced by #VALUE%. 轨道高爆弹火力网覆盖面减少#VALUE%。 +1365642266 Orbital Illumination Flare 轨道照明弹 +1071932953 ORBITAL ILLUMINATION FLARE 轨道照明弹 +3399935348 Orbital infrared scans have detected a Factory Strider in this area. 轨道红外线在该区域内扫描发现一名移动工厂。 +3341604045 Orbital infrared scans have detected the waste heat of an Automaton Factory Strider in this region. If it is allowed to persist, the planet will be overrun with mechanical monstrosities before long. + +End it. 轨道红外线在该区域内扫描发现一名移动工厂的余热。如果放任不管,这颗星球迟早会被机械怪物攻陷。 + +终结它。 +181783696 Orbital Laser 轨道激光炮 +3335448467 ORBITAL LASER 轨道激光炮 +3903115201 Orbital Laser stratagem availability has ended. 现已无法使用“轨道激光炮”战略配备。 +549159351 Orbital Napalm Barrage 轨道凝固汽油弹火力网 +3103421391 ORBITAL NAPALM BARRAGE 轨道凝固汽油弹火力网 +188575064 Orbital Precision Strike 轨道精准攻击 +4018205223 ORBITAL PRECISION STRIKE 轨道精准攻击 +3521674760 Orbital Precision Strike stratagem availability has ended. 现已无法使用“轨道精准攻击”战略配备。 +3145861536 Orbital Railcannon stratagem availability has ended. 现已无法使用“轨道炮”战略配备。 +3194889632 Orbital Railcannon Strike 轨道炮攻击 +826884584 ORBITAL RAILCANNON STRIKE 轨道炮攻击 +2769005858 Orbital Smoke Strike 轨道烟雾攻击 +704804706 ORBITAL SMOKE STRIKE 轨道烟雾攻击 +2328985689 Orbital Stratagems Scatter Increased. 轨道武器战略配备效果范围更加分散。 +831074521 Orbital Walking Barrage 轨道游走火力网 +316604262 ORBITAL WALKING BARRAGE 轨道游走火力网 +1772852609 Orbital Walking Barrage Smoke 轨道游走烟雾火力网 +3460715746 ORBITAL WALKING BARRAGE SMOKE 轨道游走烟雾火力网 +852413008 ORBITAL WALKING BARRAGE SMOKE 轨道游走烟雾火力网 +3487732002 Orbital Walking Barrage stratagem availability has ended. 现已无法使用“轨道游走火力网”战略配备。 +2156814646 Orbital-range cannons in this Megafactory are suppressing our Super Destroyers—a clear violation of war conventions. + +This tactical imbalance will not go unaddressed. Destroy every Counter-Orbital Cannon within the perimeter. 这所超大型工厂内的轨道射程炮正在压制我方超级驱逐舰,这公然违反战争公约。 + +我们必须纠正这种战术上的劣势。摧毁区域内所有反轨道加农炮。 +4075838747 Orbitals Used 轨道攻击次数 +1688428148 ORBSHAM 球珀沙姆 +2928246556 ORDER DETAILS 指令详情 +1208936523 Order of the Venerated Ballot 神圣投票团 +2996293456 Order of the Venerated Ballot 神圣投票团 +1816081651 ORDER OF THE VENERATED BALLOT 神圣投票团 +2695637570 ORDER OF THE VENERATED BALLOT 神圣投票团 +2306361989 ORDER OUTCOME 指令结果 +3614892168 ORDER OVERVIEW 指令概览 +830421671 Order the Eagle Fighter to return to the ship, where it can restock its armaments. 可指派“飞鹰”战斗机返回飞船,重新补充军备物资。 +1892667724 ORDERS 指示 +3984734748 ORDERS 指派任务 +1601524508 ORDERS 指令 +2302787913 ORDERS [#COUNT] 指令[#COUNT] +3495946093 ORESINK 奥尔辛克 +3100570863 ORGANIC PLASMA FLOW BLOCKED 有机等离子流受阻 +87612306 Organic plasma is synthesized in these vats. Siphon it for scientific analysis. 有机等离子在这些槽罐之中合成。抽取样本进行科学分析。 +4104625402 Originally worn by lunar terraformers, this suit can withstand rapid changes in pressure, heat, and personal velocity. 原本是月球地形改造人员的装备,足以承受气压、温度和个人速度的急剧变化。 +2999904680 ORION SECTOR 猎户座分区 +3767503173 OROTH 欧拉斯 +331217504 OSHAUNE 欧绍恩 +3376866480 OSLO STATION 奥斯陆站 +4042534893 Osman 奥斯曼 +2505794238 OSTEHOVEL 酪撕特霍维 +1753892252 OSUPSAM 欧苏普森 +3014106519 OTARU'S PLEDGE 小樽诺城 +1393842677 Other 其他 +3225533687 OTUR 厄图尔 +1471387497 Our enemies have forced conflict upon this region. There can be no peace until they are defeated. 敌军让该地区陷入战火之中。唯有将其击败才能恢复和平。 +3541336633 Our enemies have forced conflict upon this region. There can be no peace until they are defeated. 敌军让该地区陷入战火之中。唯有将其击败才能恢复和平。 +678338962 Our heroic fallen live on in this cape, guiding its bearer's aim to the heart of those who killed them. 这款披肩承载着陨落的烈士之魂,引导穿戴者瞄准凶手的要害,为他们复仇。 +91830704 Out of consumable #SLOT: #NAME. 消耗品#SLOT耗尽:#NAME。 +664277113 Out of Grenades! Call in a Resupply to replenish. 榴弹耗尽!呼叫重新补给进行补充。 +2980966074 Out Of Stims 治疗剂已用尽 +1359440532 Out of Stims! Call in a Resupply to replenish. 治疗剂耗尽!呼叫重新补给进行补充。 +2576582114 Outcast Seeker 逐觅光弃者 +3998109846 OUTCAST SEEKER 逐觅光弃者 +266468165 Outcast Seekers 逐觅光弃者 +3045602539 Outcast Slasher 狂刃光弃者 +1762804888 OUTCAST SLASHER 狂刃光弃者 +701621180 Outcast Slashers 狂刃光弃者 +91568612 Outcast Tracker 循踪光弃者 +1577218460 OUTCAST TRACKER 循踪光弃者 +331578186 Outcast Trackers 循踪光弃者 +229734282 OUTCOME 结果 +36006902 OUTER RADIUS 外半径 +928577212 OUTFLOW 外流 +3918203322 OUTGOING ONLY 仅输出 +2410399265 Outpost 哨站 +188240743 OUTPOST 32 32号哨站 +4053106192 OUTPOST ALPHA 阿尔法哨站 +953532392 OUTPOST ALPHA II 二级阿尔法哨站 +352883173 Outposts 哨站 +4114740790 OUTPOSTS DESTROYED 已摧毁哨站 +583831193 Outstanding Patriotism 爱国精英 +3149253905 Over Artifice Triumphant 巧取豪夺 +2594253167 OVER ARTIFICE TRIUMPHANT 巧取豪夺 +1241011071 OVERALL BIRTH RATE TARGET INCREASED TO 1.4% FROM 1.35% 总出生率目标从1.35%提高至1.4% +1318124552 OVERGOE PRIME 欧维果主星 +1459569146 OVERRIDE HELLPOD STEERING 取得绝地喷射舱控制权限 +3275101465 Override Turret Control 夺取炮台控制权限 +1899936906 Overseer 监视者 +3253076821 OVERSEER 监视者 +1185244299 Overseers 监视者 +4134104203 Overship 统御舰 +2220556432 OVERSHIP 统御舰 +106157565 Overships 统御舰 +2594389917 OVERWHELMING FIREPOWER 火力碾压 +110821011 OVERWRITE CORE PROTOCOLS 覆写核心协议 +3781246102 OWNED 已拥有 +1244403650 OXYGENATOR 供氧器 +254102099 P-11 P-11 +1436016672 P-113 P-113 +2152148492 P-19 P-19 +1696952059 P-2 P-2 +279082357 P-33 P-33 +1643905163 P-35 P-35 +3230852666 P-4 P-4 +4059265139 P-41 P-41 +865067904 P-69 P-69 +948147667 P-72 P-72 +2663300742 P-92 P-92 +961795014 P/40-K P/40-K +661865499 PA System 广播系统 +2675373562 Pacifier 安抚者 +2190029280 PACIFIER 安抚者 +752968066 Package of 1000 (750 + 250 bonus) Super Credits 1000(750 + 额外250)超级货币包 +911872437 Package of 150 Super Credits 150超级货币包 +788445221 Package of 2100 (1500 + 600 bonus) Super Credits 2100(1500 + 额外600)超级货币包 +1456717076 Package of 375 Super Credits 375超级货币包 +3394262305 Package Progress 包裹进度 +642311510 PADOSAN 毗印市 +2996674594 PAGE LOCKED 未解锁页面 +1177294889 PAGE_#PAGE_NUMBER 第#PAGE_NUMBER页 +785463516 Painted by visionary artist Silas Garm during an intense fever, this symbol represents Humanity's great Galactic endeavor: the blood-soaked dawn of Lasting Peace. 这个符号由远见卓识的艺术家西拉斯·加姆在高烧中绘制,象征着人类在银河系卓绝奋斗的痕迹:他们为持久和平的曙光而挥洒的鲜血。 +3243895582 PANDION-XXIV 帕狄恩XXIV +944387173 PANDORA BASE 潘多拉基地 +3871739922 Panther 之豹 +2221338590 PapaPatrioot 爱国老爹爹 +3676441791 PAPER 布 +2286137769 Paradise 乐土 +2440833855 Paragon 模范 +81523500 Parents Frantic After Child Uploads Consciousness Into Cloud Server 儿童意识上传云服务器,引起家长恐慌 +2151011693 PARRHESIA 直言城 +4275167981 PARSH 帕尔什 +3708222031 Part of a long line of experimental armor commonly seen on industrial engineering campuses, in the basements of select science aficionados, and around Super Destroyer Mega Garages. 这件盔甲源于历史悠久的实验性盔甲系列,常见于工业工程学院、部分科学爱好者的地下室,以及超级驱逐舰大型车库内。 +2539179263 PARTIAL REINFORCEMENT, YOU ARE NOW #QUEUE_POS IN QUEUE 部分增援到位,你正在排队,当前位置:#QUEUE_POS +1775261762 Particle Quality 粒子质量 +2588104988 PARTION 帕尔晨 +257295247 Parts for the Democracy Space Station are prefabricated all over the Galaxy, then shipped here to await assembly. 民主空间站(DSS)的部件在星系各地完成预制,然后运往这里等待组装。 +1967742243 PARTY 队伍 +133801951 PAST CAMPAIGNS 过往战役 +1449047029 Paste in a friend code to start searching. 粘贴好友代码,开始搜索。 +4028430388 Patched and tattered, this banner yet waves from the unbowed shoulders of Freedom's most battle-tested warriors. 这面旗帜虽历经修补,却依然飘扬在久经沙场的自由战士们不屈的肩膀之上。 +230047501 PATHFINDER V 开拓者V +2383411647 Patient Zero's Rememberance 零号病人遗思 +573660860 PATIENT ZERO'S REMEMBERANCE 零号病人遗思 +63664792 Patriot 爱国者 +2943934930 Patriot 爱国者 +3355982829 Patriot Blue 爱国蓝 +1357287836 PATRIOT BLUE 爱国蓝 +734964784 Patriot Exosuit “爱国者”外骨骼装甲 +3200900560 PATRIOT EXOSUIT “爱国者”外骨骼装甲 +2397530387 Patriot of Super Earth, your hard work and dedication has not gone unnoticed. This Destroyer has now been automatically enrolled in the Helldiver Weapon Customization Programme! + +Helldiver Primary Weapons can now be leveled up and customized, to adjust each weapon's look and feel. 超级地球爱国者,你的辛勤付出和奉献有目共睹。这艘驱逐舰现已自动加入绝地潜兵武器自定义计划! + +绝地潜兵主要武器现在支持升级和定制,可自由调整每件武器的外观手感。 +3067061402 Patriot_251 爱国者_251 +3425562007 Patriotic Administration Center 爱国行政中心 +1032174673 PATRIOTIC ADMINISTRATION CENTER 爱国行政中心 +2339494427 PATRIOTIC ADMINISTRATION CENTER 爱国行政中心 +1018033629 PATRIOTIC POSTER 爱国海报 +1111578990 PATRIOTIC POSTER 爱国海报 +1289883582 PATRIOTIC POSTER 爱国海报 +1439694785 PATRIOTIC POSTER 爱国海报 +2956446175 PATRIOTIC POSTER 爱国海报 +3665189065 PATRIOTIC POSTER 爱国海报 +4088732588 PATRIOTIC POSTER 爱国海报 +1109668552 Patrols sound the alarm which causes ENCOUNTERS! 巡逻队会发出警报,引发遭遇战! +2692750596 Pattern 涂装 +151992300 PATTERN 涂装 +3361358696 PATTERN 涂装 +1011860833 PAULINE 波林 +3305405987 Pay attention to these tips. They've been carefully calibrated to ensure your success. 请认真阅读提示。这都是精心总结的经验,能确保你夺得成功。 +3141161379 PAYLOAD 炮弹填料 +2538301274 PAYLOAD SITE 投放点 +1209685887 PAYONG 庇永 +417698738 Payout already received 已获得收益 +3984890508 PAYROLL MANAGEMENT SYSTEM 薪金管理系统 +215976645 PEACEKEEPING OPERATION 维和行动 +3152455243 PEACEKEEPING OPERATION 维和行动 +2602817837 Peacemaker 和平制造者 +2209736870 PEACEMAKER 和平制造者 +3970498706 PEACOCK 孔雀十一 +467298293 PEAK PHYSIQUE 健壮体格 +427429682 PEASE 平息市 +2450667324 PEDIS 佩迪趾 +3888437942 Pending... 正在等待… +2276496101 PENETRATION 穿透攻击 +696771573 PENNYBRIDGE 彭尼布里奇 +2109995347 PENSCEWT 彭妮萌 +3985499109 PENTA 彭塔 +3150403879 PEONY 牡丹 +1083408764 PEOPLE'S HAND 民手市 +1045811468 Per Democrasum 于民主 +1193620774 PER DEMOCRASUM 于民主 +3759702237 PER WEAPON 视武器而异 +1172079006 Perfect Bonus 完美加分 +1041666559 Perfect for a true patriot of Super Earth! 真正的超级地球爱国者绝配之选! +3043932542 Perform ASSISTED RELOAD. 执行协助装填弹药。 +723941969 PERFORMANCE 性能 +1352130444 PERFORMANCE 性能 +948715060 Performance Monitor 性能监视器 +2471034422 PERFORMING SYSTEMS CHECK... 正在执行系统检查… +2986604961 Periodic sandstorms pose a significant threat to visibility. 周期性沙尘暴会严重影响能见度。 +1617408679 Periods of freezing temperatures reduce rate of fire and delay heat buildup in weapons. 极寒时段会降低射速,减慢武器升温速度。 +3001978230 Periods of high temperatures increase stamina drain and speed up heat buildup in weapons. 酷热时段会增加耐力消耗,也会加快武器升温速度。 +3622775454 PERIWINKLE MILLS 长春花磨城 +361678444 PERMACURIS 佩玛丘拉斯 +3153730193 PERMANENT END OF CONFLICT WITH THE AUTOMATONS. 即将与机器人永久结束冲突之际。 +3896975057 PERMANENT ITEMS 永久物品 +3548116907 PERSEVERANCE 坚毅市 +1097026828 PERSISTENCE 坚韧市 +332110647 PERSISTENCE GATE 恒久之门 +2298398103 Person 个人 +3978598201 PERSONAL DEVICE 个人设备 +1400878407 Personal Order 个人指令 +3308761296 PERSONAL ORDER 个人指令 +3712239391 PERSONAL ORDER COMPLETED 已完成个人指令 +786290638 PERSONAL ORDERS 个人指令 +18575513 Persson 佩尔松 +3575338644 PEST CONTROL 害虫管制 +2042495118 PESTIS 瘟厉 +2032014327 PH-202 Twigsnapper PH-202“折枝” +3819874910 PH-202 TWIGSNAPPER PH-202“折枝” +3839210593 PH-56 Jaguar PH-56“捷豹” +3904401451 PH-56 JAGUAR PH-56“捷豹” +1644828869 PH-9 Predator PH-9“掠食者” +425467206 PH-9 PREDATOR PH-9“掠食者” +805511186 PHACT BAY 丈人一湾 +4256815515 PHAM'S SITE 范姆镇 +153780622 PHANTOM 1 幻影1 +994759124 PHASE 1 第1阶段 +3856524019 PHASE 2 第2阶段 +99319945 PHASE 3 第3阶段 +1542334916 Phase-Beam 相位光束 +996702475 PHERKAD SECUNDUS 北极一次星 +455117383 Pick up BACKPACK. 拾起背包。 +3090266504 Pick up BLACK BOX. 拾取黑匣子。 +3365287503 Pick up OBJECTIVE ASSET. 拾取目标资产。 +246145121 Pick up ammo 拾取弹药 +5446904 Pick up and use EXPENDABLE ANTI-TANK against ARMORED ENEMIES. 拾取并使用消耗性反坦克武器对付装备护甲的敌人。 +3546516457 Pick up grenades 拾取榴弹 +1700860878 Pick up Secondary Weapon 拾取次要武器 +2238702792 Pick up Stims from Injury Simulator 从损伤模拟器中拾取治疗剂 +534222165 Pick up supplies and load Liberator 拾取补给,为“解放者”装弹 +1786062800 Pick up the AR-23 Liberator 拾取AR-23“解放者” +3746837729 PIEA 皮耶阿 +1375930354 PILEN V 皮伦V +4168292558 Pilestedt 皮勒斯泰特 +1880424678 Pillar of the Abyss 深渊支柱 +2860078854 PILLAR OF THE ABYSS 深渊支柱 +2018191462 Pillars of Democracy 民主之柱 +1376101489 PILLARS OF DEMOCRACY 民主之柱 +4043239536 Pillars of Freedom 自由支柱 +2506982198 PILLARS OF FREEDOM 自由支柱 +1784867704 Pilot 驾驶员 +1762114919 PILOT SHORTAGE 驾驶员短缺 +331197937 PILOT WEAPONS TRAINING 飞行员武器训练 +2542754603 PILOT WEAPONS TRAINING 飞行员武器训练 +1311234619 PILOT'S BERTH 星驭港 +520511467 PINE TAR 松焦 +548900746 Pineapple 菠萝 +4211016667 PINEAPPLE 菠萝 +2609936268 PINESWOLD 派恩斯沃尔德 +1193162707 Pinions of Everlasting Glory 永恒荣耀之羽 +3232673780 Pinions of Everlasting Glory 永恒荣耀之羽 +783007437 PINIONS OF EVERLASTING GLORY 永恒荣耀之羽 +1615123798 PINIONS OF EVERLASTING GLORY 永恒荣耀之羽 +179119539 PIONEER II 先驱II +3218460543 PIONEER'S DREAM 先驱梦城 +1083476041 PIPIONEM 雏鸣 +441539462 Pistol 手枪 +219478707 PISTOL 手枪 +2036443324 PISTOL 手枪 +3285626533 PISTOL 手枪 +3834393618 PIT 8 8号坑 +1990146117 PIT CREW HAZARD PAY 维修人员危险津贴 +179358414 PixiePyxie555 调皮妖精555 +460213010 Place Black Box in input tray 将黑匣子放进输入托盘 +3987795066 PLACE DATA DRIVE IN INPUT TRAY 将数据硬盘放进输入托盘 +3661094070 PLACE MARKER 放置标记 +2318679330 Place markers on the map to help your squad navigate. 在地图上放置标记可以为队友指路。 +756729094 Place switches to indicated positions 将开关调到指定位置 +2621267569 PLANET 星球 +853966900 Planet #V_ONE, on the verge of a successful defense, has fallen to the enemy. #V_ONE星球在成功防御之际落入敌手。 +2970341781 Planet #V_ONE, on the verge of a successful defense, has fallen to the enemy. #V_ONE星球在成功防御之际落入敌手。 +2839861759 Planet #V_ONE, on the verge of falling to the enemy, has been successfully defended. 我们成功守住了濒临沦陷的#V_ONE星球。 +3097330934 Planet #V_ONE, on the verge of falling to the enemy, has been successfully defended. 我们成功守住了濒临沦陷的#V_ONE星球。 +2370354957 Planet Biome 星球生物群落 +3770521993 PLANET EVENTS 星球战事 +839605471 Planet events can happen when enemies are attacking Super Earth controlled planets - Defend Event - or when Super Earth advances in the galaxy - Liberation Events. + +Make sure to do your part! 敌人对超级地球控制下的星球发起攻击时,便会爆发星球战事,名为保卫战事;超级地球在星系中扩大势力时也会爆发星球战事,名为解放战事。 + +请务必参战! +4211030149 Planet is ravaged by deadly fire tornados. 致命的烈焰龙卷在星球上肆虐。 +2456435817 PLANET LIBERATED +We have cleansed a planet of the vile Terminid infestation, returning it to Super Earth's warm embrace. 星球已解放 +我们已彻底剿灭占领星球的邪恶终结族,让它重回超级地球的温暖怀抱。 +2740238390 PLANET LIBERATED +We have driven the Automatons completely from a planet, rightfully reclaiming it for Super Earth. 星球已解放 +我们彻底将机器人逐出了星球,光明正大地夺回超级地球的领地。 +107490755 PLANET LIBERATED - MOVE TO NEW PLANET 星球解放 - 前往其他星球 +852757047 PLANET LOST +Our defenses have failed. The Terminids infest another Super Earth planet. 星球沦陷 +我们的防线崩溃,终结族又占领了超级地球的一颗星球。 +3684130963 PLANET LOST +We have failed to repel the Automatons from one of our planets. We will remember the fallen, and return to take it back. 星球沦陷 +我们未能将机器人从我方的其中一颗星球逐出。我们将铭记陨落的英雄,并发誓收复失地。 +4103555409 PLANET LOST - RETREAT ORDER ISSUED 星球沦陷 - 下令撤退 +2313218327 PLANET SAVED +Thanks to the selfless valor of the Helldivers, the Terminids' attempt to spread their vile tyranny to another one of our planets has been repelled. 星球已获救 +在无私的绝地潜兵的英勇付出下,企图将暴政的种子再次散播到我们其中一颗星球的终结族已被击退。 +538802715 PLANET SAVED +Thanks to the unfailed valor of the Helldivers, the Automatons have been repelled from one of our planets. A glorious day for Freedom. 星球已获救 +在从不失手的绝地潜兵的英勇付出下,我们已将机器人从我方的其中一颗星球逐出。今天又是自由伟业光荣的一天。 +4149383367 PLANET STATUS UPDATING 星球状态正在更新 +3953355018 PLANETARY BLACKOUT 星球失联 +952171788 Planetary Bombardment 星球轰炸 +2921216438 PLANETARY BOMBARDMENT 星球轰炸 +1333202479 PLANETARY BOMBARDMENT 星球轰炸 +2158877299 PLANETARY BOMBARDMENT 星球轰炸 +1070161154 PLANETARY DEFENSE CANNON ARMED 行星防御加农炮已启动 +3443030867 Planetary Defense Cannon in lowered position. 行星防御加农炮处于收起状态。 +303008397 Planetary Defense Cannon raising… 行星防御加农炮正在抬升…… +3835920908 PLANETARY DEFENSE CANNON RAISING… 行星防御加农炮正在抬升…… +2124411631 Planetary Defense Cannon rearming… 行星防御加农炮正在装弹…… +733451672 PLANETARY DEFENSE FAILURE IN: #TIME 行星防御失效倒计时:#TIME +1821642638 PLANETARY FRACTURING CONFIRMED 行星破裂已确认 +548495078 PLANETARY IMPACT 战役贡献 +3310360401 Planetary scanning has identified a vast assemblage of Automaton troops in this region. This may be in preparation for an offensive on nearby Super Earth installations. + +You must reduce their numbers—kill as many bots as you can. 星球扫描的结果显示,该地区聚集有大量的机器人士兵。它们或许正在准备进攻附近属于超级地球的设施。 + +你必须削减其数量——尽可能击杀更多机器人。 +2444304889 Planetary scanning has revealed a number of Automaton supply bases, hidden deep behind their defensive lines. + +Infiltrate quickly and destroy their stockpiles before they can mount a concerted defense. 星球扫描发现机器人有多座补给基地隐藏在防线深处。 + +迅速潜入敌方腹地,在它们组织起有效的防御之前销毁它们的库存物资。 +1801806915 PLANT 插旗 +1158604736 Plant flag in designated area 在指定区域竖立旗帜 +4022679895 PLAS-1 PLAS-1 +3433019171 PLAS-101 PLAS-101 +1154955025 PLAS-15 PLAS-15 +3872480680 PLAS-39 PLAS-39 +2431838851 PLAS-45 PLAS-45 +2737230814 Plasma Bolt 等离子弹 +994006141 PLASMA BOLT 等离子弹 +1283907746 Plasma Igniter Choke 等离子点火器喉缩 +3537136715 PLASMA IGNITER CHOKE 等离子点火器喉缩 +1692584896 Plasma Igniter Compensator 等离子点火器补偿器 +2723689024 PLASMA IGNITER COMPENSATOR 等离子点火器补偿器 +3349008064 Plasma Igniter Muzzle Brake 等离子点火器枪口制退器 +3306288095 PLASMA IGNITER MUZZLE BRAKE 等离子点火器枪口制退器 +338268166 PLATFORM 平台 +734561935 PLATFORM 平台 +2492072473 PLATINUM BAR 铂金条 +1314843501 Platoon 特战排 +3451090161 PLATOON 特战排 +3173156288 PLATOON & FRIENDS 特战排与好友 +106007235 PLAY 开始游戏 +163504066 PLAY 开始游戏 +583223012 PLAY 开始游戏 +701243066 Play #COUNT #OBJ#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI. 参与#COUNT次#OBJ。#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI +3086803146 Play 1 Bot Mission. 参与1项机器人任务。 +1427976274 Play 1 Bug Mission. 参与1项虫族任务。 +3167134455 Play a planet defense mission. 参与1项星球保卫任务。 +2599416825 Play at least 50 missions. 参与至少50项任务。 +3432202568 PLAY TUTORIAL 开始教程 +2234405994 Player 玩家 +957392187 PLAYER 玩家 +1457212130 Player Card 玩家名片 +549860643 Player Card 玩家名片 +606419739 Player Card 玩家名片 +3730054551 PLAYER CARD 玩家名片 +4174538412 PLAYER INTERACTION 玩家互动 +4028773662 Player Marker Visibility 玩家标记可视度 +1982728820 Players associated with an online ID can be reported for breaching the terms of service. This player is not associated with an online ID. 如果关联在线ID的玩家违反服务条款,可将其举报。此玩家并未关联在线ID。 +2972096411 Players can be reported if they have written something in chat that breaches the terms of service. This player has no chat messages to include in a report. 如果玩家在聊天中发表了违反服务条款的内容,可将其举报。此玩家没有可举报的聊天信息。 +4017844830 Playfab account not allowed to login. Please contact Community managers Playfab账号禁止登录。请联系社区管理员 +3857022953 Playfab Session Ticket has expired. Login to Playfab again Playfab会话票据已过期。请重新登录Playfab +1006841149 Playfab Session Ticket Validation Error Playfab会话票据验证错误 +4042196535 PlayStation®Plus is required to play this game. 游玩本游戏需要PlayStation®Plus。 +1579516697 Please access the nearby transmission station to proceed 请前往附近的传输站继续操作 +135130779 PLEASE ACTIVATE TRANSFORMER 请启动变压器 +195806008 Please adjust all indicated valves 请按照提示调整所有阀门 +1921818882 Please adjust all indicated valves. 请按提示调整所有阀门。 +1379114142 Please adjust routing protocol 请调整路由协议 +556769669 Please adjust target storage facility 请调整目标存储设施 +2742807186 Please clear front of surface-to-air launcher 请离开地对空导弹发射器的正面 +976542272 Please clear launch area 请离开发射区域 +2053793640 Please don't touch moving parts 请勿触碰活动部件 +1659902457 PLEASE EVACUATE AREA 请撤离该区域 +1238459202 Please evacuate the premises 请从此处撤离 +2393454283 Please input activation sequence 请输入启动程序 +2507454049 Please keep limbs away from moving drill parts 四肢请勿靠近钻机的活动部件 +297304399 Please log in 请登录 +1719703463 Please log in 请登录 +1817771230 Please log in 请登录 +3199974650 Please log in 请登录 +3296534684 Please log in 请登录 +3393971913 Please log in 请登录 +3545550661 Please log in 请登录 +3843851595 Please log in 请登录 +2859604785 Please Log In 请登录 +1479552987 Please manually disengage all hatch locks. 请手动解除所有舱门锁。 +3152259079 Please manually load all shells 请手动装填所有炮弹 +1562816190 Please observe the following Patriotic Service Announcement. +Deviations in attention will be considered treason. + + +Thank you for your cooperation. 请遵守以下爱国服务公告。 +注意力不集中将被视为叛国。 + + +谢谢配合。 +1063513747 Please reset all blown fuses 请重置所有熔断的熔断器 +3538370981 Please see the "Information Pursuant to the Specified Commercial Transactions Act" +(https://www.playstation.com/ja-jp/legal/games/specified-commercial-transactions-act-jp/##helldivers2) +for details regarding the timing and method of payment, delivery time of the product, +application deadlines, and cancellation or withdrawal of an application. - +- +- +- +2815653243 Please see the "Information Pursuant to the Specified Commercial Transactions Act" (https://www.playstation.com/ja-jp/legal/games/specified-commercial-transactions-act-jp/##helldivers2) for details on the timing and method of payment, delivery time of the product, application deadlines, and cancellation or withdrawal of an application. - +2939559118 Please stand by 请稍候 +1628088293 Please stand by. 请稍候。 +2841000285 Please stand clear of platform. 请远离发射平台。 +3858220824 Please stay clear of all moving parts 请勿靠近所有活动部件 +337839981 PLEASE WAIT 请稍候 +3669227538 PLEASE WAIT 请稍候 +2721501640 PLEASE WAIT 请稍候 +4172719183 PLEASE WAIT 请稍候 +1162026773 PLEASE WAIT 请稍候 +1913835796 PLEASE WAIT DEMOCRATICALLY 请民主地等待 +1647647552 Please wait while Super Earth democratically processes your ballot. 超级地球正在进行民主计票,请稍候。 +2756394578 Pledge 誓约 +4007377380 PLETHORA 普雷索拉市 +3616280245 PO'S RAVENNA 波氏拉文纳 +227037594 Podium of Prosperity 繁荣领奖台 +1150774255 PODIUM OF PROSPERITY 繁荣领奖台 +378151711 Pointless Sacrifice 无谓牺牲 +964199714 POISON 剧毒 +3589842568 POISON 剧毒 +812992035 Polar Patriots 极地爱国者 +3593438329 POLAR PATRIOTS 极地爱国者 +708743426 POLARIS PRIME 北极星主星 +3075853207 POLICY: 政策: +1048855585 POLLUX 31 北河三31 +4099382951 POLSKI POLSKI +3972830455 Poor Intel 缺乏情报 +1985114247 POOR INTEL 缺乏情报 +4128271980 Pop #COUNT Bug Scavengers 射击#COUNT只虫族的食腐虫 +3380571980 PÖPLI IX 珀普利IX +4108211908 Popularized by actor Chip Messiter, who wore this in the action-rom-com-musical "Lost My Heart to a Man in a Helmet." 由演员奇普·梅西特推广,他曾在动作浪漫欢乐音乐剧《爱上一个不脱头盔的人》中穿着这套盔甲。 +3370281534 PORT MERCY 馨家泊 +2240506575 PORTABLE COMMS RELAY 便携式通信中继站 +2306470396 Portable Hellbomb 便携式地狱火炸弹 +861327809 PORTABLE HELLBOMB 便携式地狱火炸弹 +4002995121 PORTE LIBERTÉ 自由门 +3145266038 PORTUGUÊS (BR) PORTUGUÊS (BR) +3855157673 PORTUGUÊS (PT) PORTUGUÊS (PT) +3385193392 PORUGU 毗卢固市 +3086449497 POST MATCH SURVEY 战后调查 +1954171320 POSTERITY'S GRATITUDE 后族怀恩 +908216632 Pouncer 猛扑虫 +787656435 POUNCER 猛扑虫 +3592430137 Pouncers 猛扑虫 +2135121722 Power 之力 +91078680 Power 电力 +1751257426 POWER CORE 动力核心 +3479214686 POWER STEERING 电动转向 +3974077508 Power unavailable 电力不可用 +2537601495 Power up Battery Silos 为电池舱供电 +188118679 Power up data collection uplink 为收集数据的上行链路接入电源 +994838962 Powerful dust devils launch smaller combatants into the air and stun larger combatants. 猛烈的尘卷风会将小型战斗单位卷至空中并且会眩晕大型战斗单位。 +1034551883 Practice your daily desensitization exercises to ensure you remain unfazed by enemy atrocities. 每天进行脱敏训练,确保你能冷静面对敌人的暴行。 +690834076 PRASA 普拉萨 +2721497075 PRAVOGRAD 权右沃格勒 +1776716969 Pre-approves the following forms in the Support Weapon Approval Process: Form 99-C (Justification for Munitions), Form 88-1 (Democratic Impact Worksheet), & Form 104 (Collateral Damage Risk Waiver). 在支援武器审批流程中预先通过以下表格的审批:99-C表格(使用弹药的正当理由)、 88-1表格(民主影响说明工作表)和104表格(附带损害风险弃权声明)。 +1207324607 Precursor 先锋 +3029738043 Predator Hunter 掠食追猎虫 +3865708061 PREDATOR HUNTER 掠食追猎虫 +2523237367 Predator Hunters 掠食追猎虫 +4106686024 Predator Stalker 掠食追踪虫 +3550991066 PREDATOR STALKER 掠食追踪虫 +117029659 Predator Stalkers 掠食追踪虫 +853684841 PREDATOR STRAIN 掠食变种 +399581668 Preliminary Installation Procedures Begin For Terminid Deterrance Network. 终结族威慑网初期建设工作开始 +1154305368 Premium 尊享 +1974467453 PREMIUM 尊享 +4291464926 PREMIUM WARBOND NEEDED 需要尊享战争债券 +3730431240 PREMIUM WARBOND UNLOCKED 已解锁尊享战争债券 +1799389348 Prepare and launch the ICBM. 做好准备工作,发射洲际弹道导弹。 +2508405363 Prepare and launch the ICBM. 做好准备工作,发射洲际弹道导弹。 +3771000953 Prepare and launch the local ICBM. 做好准备工作,发射当地的洲际弹道导弹。 +1819046791 PREPARE FOR FTL JUMP 准备启动超光速跃迁 +2186859217 Prepare your defenses. + +Time left until automatic initiation begins: #TIME 做好防御准备。 + +自动启动程序倒计时:#TIME +3954110561 Prepared Crates 预备弹药箱 +262066552 PREPARED CRATES 预备弹药箱 +3838653553 PREPARING 正在准备 +2207832920 PREPARING AREA SCAN 准备启动区域扫描 +566699175 PREPARING DEMOCRACY 准备播撒民主 +653331449 PREPARING UPLOAD 准备上传 +470922286 Presentable 像模像样 +219421064 PRESENTABLE 像模像样 +2042223451 President Authorizes Use of "Planet Buster" Charges to Contain Terminids. 总统授权动用“歼星”炸药遏制终结族 +3685202125 PRESIDENT PROMISES RETRIBUTION 总统承诺发动反击 +2903429523 Press 按下 +1042736182 PRESS 按下 +2444828115 PRESS 按下 +2560109958 PRESS ANY BUTTON 按任意按钮 +3291882941 PRESS ANY BUTTON 按任意键 +3742132405 PRESS TO ACTIVATE 按下按键即可启动 +2738932960 Pressure 压力 +3402031851 PREVENT SPIRE GROWTH 阻止虫塔繁殖 +2277719467 Prevents all damage from bleeding if chest hemorrhages. 如果胸腔出血,则避免其他所有来自出血的伤害。 +1998348186 Preview 预览 +3901394545 PREVIEW WEAPON 预览武器 +737940232 PREVIOUS ARC 上一段剧情 +1791326416 Previous Category 上一个类别 +2394994623 PREVIOUS EVENT 前一战事 +2768401535 PRICE INDEX #COUNT% 物价指数#COUNT% +3506675719 PRICE: 价格: +874402511 Pride 之傲 +2907397059 Pride of the Whistleblower 检举者的荣耀 +3571107666 PRIDE OF THE WHISTLEBLOWER 检举者的荣耀 +1666079179 Primary 主要 +4040300404 PRIMARY 主武器 +3524300221 PRIMARY 主要武器 +635965522 PRIMARY OBJECTIVE 主要目标 +3566811523 Primary Objective Visibility 主要目标可视度 +2731796619 Primary Objectives 主要目标 +2700887323 PRIMARY OBJECTIVES 主要目标 +4079956993 PRIMARY WEAPON 主要武器 +2485591796 Priming Seismic Probe 地震探测仪正在准备 +3969726549 PRIMING SEISMIC PROBE 地震探测仪正在准备 +1230925792 PRIMORDIA 普莱默迪亚 +2901963580 PRIMORDIAL 原始 +2643234841 PRIMORDIAL PLANET 原始星球 +2141947866 Prince 王子 +2646875211 Princess 公主 +1534342021 PRIORITY MESSAGE FROM SUPER EARTH HIGH COMMAND 来自超级地球最高指挥部的高优先级信息 +1917009630 PRIVATE 列兵 +2233059602 Private Game 私人游戏 +968713913 Pro-Terminid Activists Sentenced To 20 Years In Asteroid Mines By Heroic Judge. 亲虫活动分子被判小行星矿场流放20年 +965162446 PROBABILITY 天机 +2701211260 PROBARE 究理 +752992579 Probe may cause significant hearing loss 探测仪可能会严重影响听觉 +1885611785 Probe may cause significant hearing loss 探测仪可能会严重影响听觉 +301829205 Proceed to facility gate 前往基地大门 +1409974189 Proceed to Final Test 前往终极考验 +2648549122 Proceed to Graduation Chamber and become a Helldiver 前往毕业礼堂,成为绝地潜兵 +4130195386 Proceed to Live Fire Range 前往实弹靶场 +583599188 Proceed to next objective 前往下一个目标 +3220598181 Proceed to Reinforcement Training Area 前往增援训练区 +414629921 Proceed to Stratagem Range 前往战略配备训练场 +946587294 Proceed to Support Stratagem Training Area 前往支援战略配备训练区 +4183229977 Proceed to TCS+ activation terminal 前往TCS+激活终端 +2661577707 Production of new Cyborgs requires a bio-synthetic process conducted in massive production units. They are structurally blastproof, but can be destroyed from within by exploiting the volatile hydrogen fuel used in the process. + +Flood the Production Unit with hydrogen, then destabilize its integrity until it fails safe and self-destructs. 生产新的生化人需要在大型生产单元中进行生物合成工序。生产单元的结构可抵御爆炸,但可以利用工序中使用的易燃氢燃料从内部将其摧毁。 + +向生产单元灌入过量氢气,然后破坏其结构稳定性,直至触发故障保护机制并自毁。 +1910779838 Production Rate 生产率 +908893121 Progenitor 始祖 +3468591970 PROGRAMMABLE AMMO STUN ROUNDS 智能眩晕弹 +1941084964 Programmable Ammunition 智能弹药 +2960842896 Programmable Ammunition 智能弹药 +1732676287 PROGRAMMABLE AMMUNITION 智能弹药 +2536995869 PROGRAMMABLE AMMUNITION 智能弹药 +840174314 Programmable Prism Effect 智能棱镜效果 +2306363495 PROGRAMMABLE PRISM EFFECT 智能棱镜效果 +2239494015 PROGRESS 进步市 +3798493358 Progress in Liberation Campaigns is accelerated. 在解放战役中的进展加速。 +460168420 PROGRESS IS MANDATORY 必须进步 +1846426649 Progression 进度 +3094717709 Progressive Trigger 渐进式扳机 +582668875 PROGRESSIVE TRIGGER 渐进式扳机 +119765763 Projectile 投射 +4061715012 PROJECTILES 射弹 +4158786502 Projects an arc of lightning at close range. Charges up to project bolts, and may discharge through multiple targets. 在近程范围内发射一道电弧。充能可发射电球,然后向多个目标放电。 +926633056 PROMINENCE 峥嵘城 +1905746110 Promising New Study Establishes Link Between 4D Cinema and Real World Violence. 最新研究发现4D电影与现实世界的暴力行为存在关联 +2502670206 Promote Synergy 倡导合作 +335054675 Promotional armor made by SUMY Corp. as part of a highly successful marketing campaign for frozen yogurt. SUMY公司制作的促销盔甲,是大获成功的冷冻酸奶营销策略的一部分。 +366364257 PRONE 趴下 +557923138 Proof of Faultless Virtue 无瑕德行之证 +471020248 PROOF OF FAULTLESS VIRTUE 无瑕德行之证 +439634869 Prophet 先知 +2723795817 Prophet Illusionist 先知幻光大师 +1741057680 PROPHET ILLUSIONIST 先知幻光大师 +1674550622 Prophet Illusionists 先知幻光大师 +662459402 PROPULSION 推进 +2337934883 PROPUS 五诸侯三 +2631236711 Prospecting Drill 勘探钻机 +120574149 PROSPECTING DRILL 勘探钻机 +768517809 PROSPERITY 繁荣市 +58819778 PROSPERITY CITY 荣都 +1642268665 PROSPERITY FALLS 繁荣瀑布 +3791433157 Prosperous Green 繁荣绿 +1631623720 PROSPEROUS GREEN 繁荣绿 +3486805749 Protect 保护 +672372755 Protect #ENTITY during upload 在上传期间保护#ENTITY +2727794726 Protect Eardrums 保护耳膜 +2801406864 PROTECT EARDRUMS 保护耳膜 +1468160281 PROTECT LAUNCHERS 保护发射器 +694379891 Protect Liberty 保卫解放 +3165383649 Protect our citizens' E-711 interests from Terminid despoilment. 保护我们公民的711元素利益免遭终结族破坏。 +1009126933 Protect our way of life from the Automatons by any means necessary. 不惜一切代价也要捍卫我们的生存之道,不能让机器人损害半分。 +2212526227 Protect our way of life from the Terminids by any means necessary. 不惜一切代价也要捍卫我们的生存之道,不能让终结族损害半分。 +2288853684 Protect the President's Mansion! 保卫总统府! +1976322632 Protector 护卫 +158732787 Protector of the Heart 民主之心捍卫者 +34542068 PROTECTOR OF THE HEART 民主之心捍卫者 +1287780346 Protects Individual Right To Own Giant Mechanized Robot 保障个人拥有巨型机械化机器人的权利 +3649078966 PROTEIN SHORTAGE 缺乏蛋白质 +1277432473 Proud Gold 傲金 +3135443249 PROUD GOLD 傲金 +243360535 Provide assisted reload for a teammate. 辅助一名队友装填弹药。 +3104200939 Provided Legacy login token is not valid 提供的遗留登录令牌无效 +3392152803 Provided PlayFab token belongs to a different platform than the one the client is currently using 提供的Playfab令牌不属于客户端当前使用的平台 +3965403289 PROVIDENCE 普罗维登斯 +283424312 Provides #BONUS damage resistance to fire, allowing bearer to rest assured in their inflammability. 提供#BONUS的火焰伤害抗性,穿戴者无需再担心自身的易燃问题。 +980701584 Provides #BONUS resistance to arc damage. 提供#BONUS的电弧伤害抗性。 +698831992 Provides #BONUS resistance to chest damage. 提供#BONUS的胸部伤害抗性。 +3110966073 Provides #BONUS resistance to explosive damage. 提供#BONUS的爆炸伤害抗性。 +1113593779 Provides #BONUS resistance to fire, gas, acid, and electrical damage. 获得#BONUS抵御火焰、毒气、酸液以及电击伤害的能力。 +2613716205 Provides #BONUS resistance to gas damage and effects. 对毒气伤害和效果的抗性增加#BONUS。 +2398339361 Provides #SIGN#BONUS limb health. 提供#SIGN#BONUS的四肢生命值。 +1802981327 Provides a higher armor rating. 提供较高的盔甲等级。 +156052675 Provides hand carts which can carry multiple backpack stratagems from storage, decreasing both reload time and crew lumbar injuries. 手推车可从库存中装载多个背包战略配备,缩短重新装弹的时间,还可以降低船员腰部受伤的几率。 +3559556444 Provides immunity to leg injuries. 免疫腿伤。 +2887229082 Provides minor damage reduction from all sources for all Helldivers. 为全体绝地潜兵提供轻微的减伤效果(伤害来源不限)。 +1426645361 Provides one-time, short-lived resuscitation upon death, given that the Helldiver's body is still intact. 在绝地潜兵躯体完好的前提下,死亡后可获得一次短暂的复活机会。 +1017317795 PROVING GROUND OPERATION 试炼场行动 +2112350519 Prowler 潜掠虫 +2952897881 PROWLER 潜掠虫 +1155147987 Prowlers 潜掠虫 +1095630749 PROXIMITY TO MERIDIA CRITICAL 与默里迪亚的距离达到临界点 +2686508725 Proximity to Source Planet 靠近源头星球 +204409832 PSEUDOTOPIA 伪托邦 +564273434 PUBLIC 公开 +867635046 PUBLIC SERVICE POSTER 公共服务海报 +1687119863 PUBLIC SERVICE POSTER 公共服务海报 +1933276130 PUBLIC SERVICE POSTER 公共服务海报 +2616113535 PUBLIC SERVICE POSTER 公共服务海报 +3348449738 PUBLIC SERVICE POSTER 公共服务海报 +959618138 Pull transformer unit lever 拉动变压器单元操纵杆 +4107864567 Pummeler 暴击斗士 +208882811 PUMMELER 暴击斗士 +1029340711 Pumping in progress... 正在泵取…… +2214671962 Punisher 制裁者 +343629319 PUNISHER 制裁者 +2532953432 Punisher Plasma 等离子“制裁者” +1643867402 PUNISHER PLASMA 等离子“制裁者” +3744082581 PURCHASE 购买 +3213683288 PURCHASE 购买 +393992964 PURCHASE ERROR 购买出错 +655450879 PURCHASE FAILED 购买失败 +1113253114 PURCHASE MEDALS 购买奖章 +2133675346 PURCHASE SUCCESSFUL 购买成功 +2705917558 Purchase Super Credits to access premium content. 购买超级货币,解锁尊享内容。 +3088779196 Purchase Upgrade 购买升级 +3664348543 Purchases permanent access to ammo provided by the "Support Our Heroes" fund, which allows patriotic family members to donate supplies to their loved ones in the field. 购买由“支援英雄”基金会提供的弹药的永久使用权。爱国的家庭成员可通过该基金会向战场上的亲人捐赠物资。 +1199560702 PURGE HATCHERIES 清除孵化点 +3326816535 Purge site of Terminid Matter 抹除目标地点内的终结族物质痕迹 +981754863 Purge Terminid spawn by delivering a nuclear payload to all Nursery Chambers. 将核炸药送入所有繁育腔室,彻底清除终结族幼虫。 +4181311944 Purification 提纯 +3805040370 Purifier 净化者 +1431880950 PURIFIER 净化者 +1259884059 PURIFYING ECLIPSE 净化日食 +4166502146 Purveyor 传承 +1081222658 PUSH-TO-MUTE 按键静音 +915684782 PUSH-TO-TALK 按键说话 +75268102 Pushing the boundaries of bionic engineering, this armor collects and dispenses a number of vital fluids, several of which are soon to be declassified. 这套盔甲突破了仿生工程学的极限,能收集并分配多种重要体液,其中几种即将解密。 +2861014363 Pyro Trooper 炙焰装甲兵 +3086658899 PYRO TROOPER 炙焰装甲兵 +1127649354 Pyro Troopers 炙焰装甲兵 +820522057 Pyrotech 烟花术 +4118932090 PYROTECH 烟花术 +1761328847 PYTHON COMMANDO 蟒蛇突击兵 +1847400093 Python Commandos 蟒蛇突击兵 +115579674 PYTHON COMMANDOS 蟒蛇突击兵 +1643550039 QUALITY 画质 +1863098243 QUALITY 画质 +3573535254 Quality is out of this world! Sometimes I put it on just to wear around the house. 质量真是没的说!有时候穿起来只是为了在家附近逛逛。 +843419660 Quality Profile 画质设置 +1097723180 QUASAR 魁霎 +2709430291 QUASAR 魁霎 +2557128977 Quasar Cannon 类星体加农炮 +3774930640 QUASAR CANNON 类星体加农炮 +671395036 Queen 女王 +2686205325 QUELL EXOSTORM 平息异界风暴 +1414353920 QUELLED DISSENT 戡异市 +2899188129 QUENCH 淬火市 +1256112630 Quick Play 快速进攻 +2664916455 Quick Play with friends 与好友参与快速进攻 +777230933 QUICK STIM 快速使用治疗剂 +3957888732 QUICK THROWABLE 快速投掷武器 +2480599126 QUICK WEAPON WHEEL DOWN 快速向下转动武器轮盘 +472151788 QUICK WEAPON WHEEL LEFT 快速向左转动武器轮盘 +3114265484 QUICK WEAPON WHEEL RIGHT 快速向右转动武器轮盘 +4080586754 QUICK WEAPON WHEEL UP 快速向上转动武器轮盘 +1750847689 Quickly navigate between available Missions. 快速浏览各项可选任务。 +3185807915 QUICKPLAY 快速匹配 +654493443 Quinto 昆托 +3256192545 QUINTUS SECTOR 昆图斯分区 +527431779 QUIT GAME 退出游戏 +3725149159 QZ-4 疫区4 +452094343 R-2 R-2 +2337522152 R-2124 R-2124 +2518813155 R-36 R-36 +1422895272 R-4 R-4 +3073761045 R-6 R-6 +82468757 R-63 R-63 +3489949763 R-63CS R-63CS +373655897 R-72 R-72 +2878721283 R. ARM 右臂 +1292709609 R. LEG 右腿 +2450333705 R.SHLD 右肩 +4028707199 R/40-K R/40-K +759918452 R/G/B R/G/B +862842794 R&D UPDATE 研发更新 +1705872161 R#RANK 级别#RANK +1799635206 RADAR 雷达 +2931280706 Radar scans of this region have detected anomalous subsurface readings. By analyzing the signatures of extracted material, we can trace their source of origin and uncover the path to our final destination within the Void. + +You have been authorized one GATER, already deployed. Use it to extract anomalous material from all indicated sites. 该地区的雷达扫描检测到异常的地下读数。通过分析提取物的特征,我们就能寻踪溯源,找到通往寂域内部最终目的地的路线。 + +你已获准使用一台已部署的地面全地形采集钻机。使用这台地面全地形采集钻机从所有已标记地点提取异常物质。 +910757278 Radar Wagon 雷达车 +846947020 Radar Wagon 雷达车 +4242369091 Radar Wagons 雷达车 +3102055785 RADIAL MENU ABSOLUTE SELECTION 圆盘菜单绝对选取 +1080635773 RADIAL MENU DOWN 圆盘菜单下 +2217063829 RADIAL MENU LEFT 圆盘菜单左 +747225446 RADIAL MENU RELATIVE SELECTION 圆盘菜单相对选取 +51134916 RADIAL MENU RIGHT 圆盘菜单右 +4236289002 RADIAL MENU UP 圆盘菜单上 +3776001239 Radiation Poisoning 辐射中毒 +23741406 Radical 激进先锋 +996634095 RADICAL 激进先锋 +2893465092 Radicals 激进先锋 +1720300639 Rags of the Fashionable 时尚褴褛 +4005155989 RAGS OF THE FASHIONABLE 时尚褴褛 +2000862158 Raider 奇袭者 +1682713724 RAIDER 奇袭者 +732537577 Raider's Cheer 奇袭者的欢呼 +1345295618 RAIDER'S CHEER 奇袭者的欢呼 +1531255622 Raiders 奇袭者 +1392519706 Rail Cannon Round 轨道炮弹 +2920710188 RAIL CANNON ROUND 轨道炮弹 +3834075640 Railgun 磁轨炮 +3276705068 RAILGUN 磁轨炮 +1110476060 Railgun Round 磁轨炮弹 +3597164050 RAILGUN ROUND 磁轨炮弹 +790006583 Railgun Stun Round 磁轨炮眩晕弹 +426646695 RAILGUN STUN ROUND 磁轨炮眩晕弹 +4059426536 RAIN DOWN FROM ABOVE 天降民主雨露 +3364434386 RAINSTORMS 暴雨 +2080857789 RAISE DISH 抬升天线 +1084788693 RAISE FLAG OF SUPER EARTH 升起超级地球旗帜 +1549706842 RAISE FLAG OF SUPER EARTH 升起超级地球旗帜 +2298091595 RAISE LAUNCHER 抬升发射器 +2259728881 RAISE LIDAR TOWER? 升起激光雷达塔? +2323084938 RAISE PLANETARY DEFENSE CANNON 抬升行星防御加农炮 +4129187251 RAISE SATELLITE TOWER 抬升卫星塔 +3772123343 RAISE SIGNAL STRENGTH 提高信号强度 +2212595391 Raise signal strength to 100% 将信号强度提高至100% +2453551750 Raise signal strength to 100% 将信号强度提高至100% +3661789117 Raise signal strength to 100% 将信号强度提高至100% +1247038911 Raise the Super Earth flag as an unassailable beacon of Liberty. 升起超级地球旗帜,犹如树立起一座坚不可摧的解放灯塔。 +3477060221 Raise the Super Earth flag as an unassailable beacon of Liberty. 升起超级地球旗帜,犹如树立起一座坚不可摧的解放灯塔。 +3829936903 Raise the Super Earth flag as an unassailable beacon of Unity. 升起超级地球旗帜,犹如树立起一座坚不可摧的团结灯塔。 +3331866376 RAISE TOWER 升起信号塔 +1205931341 Raise Weapon 高举武器 +4118666908 RAISE WEAPON 高举武器 +2627013640 Raises your mission priority to all other Helldivers, increasing the odds of others joining your squad. 将你的任务优先级提升到所有其他绝地潜兵之前,增加其他士兵加入你小队的几率。 +1280777009 RAISING LAUNCHER 正在抬升发射器 +3404502543 RAISING MISSILE - PLEASE WAIT 正在抬升导弹高度,请稍候 +4206114036 Raising satellite tower 正在抬升卫星塔 +3711914546 RAISING SURFACE-TO-AIR LAUNCHER 正在抬升地对空导弹发射器 +1496010243 Raising the symbol of Managed Democracy will send an undeniable message that Freedom reigns in this land once more. 举起象征管理式民主的标志将传递出毋庸置疑的信息:自由精神再次征服这片拓殖地。 +660251208 RAISING TOWER - PLEASE WAIT 正在抬升卫星塔,请稍候 +582321042 Random 随机 +357711635 RANDOM 随机 +2442443121 Randomize Voice 随机分配声音 +3141673940 RANDOMIZE VOICE 随机声音 +2093618509 Ranger 游骑兵 +2913428209 Ranger 漫游者 +928137782 RANGER 游骑兵 +3092248647 RANGER 游骑兵 +1113008379 RANGER, BALD EAGLE CLASS 白头鹰级游骑兵 +4129085568 RANGER, EAGLE CLASS 飞鹰级游骑兵 +3703101407 Rank #RANK - #RANKNAME 级别#RANK - #RANKNAME +3286869295 RANK 300 300级 +4078219332 RAPID ACQUISITION 快速夺取 +3491726516 Rapid Heatsink 快速散热器 +1055226367 RAPID HEATSINK 快速散热器 +4024778921 RAPID LAUNCH SYSTEM 疾速发射系统 +3369979481 Rapidly clear the area 迅速肃清该区域 +3691054321 Rapidly clear the area 迅速肃清该区域 +2561390394 RARE 稀有 +111881309 Rare Sample 稀有样本 +1784802496 RARE SAMPLE 稀有样本 +2169242309 Rare Samples 稀有样本 +2688300659 RARE SAMPLES 稀有样本 +65032978 Rare Samples are only available on more challenging missions. 稀有样本只能在挑战性较高的任务中获得。 +3458804072 RAS ALGETHI 帝座 +3607018920 RASP 拉斯普 +523421401 RATCH 拉奇 +2016621289 RATE OF FIRE 射速 +99741084 RATTLESNAKE EXOSUIT PATTERN 响尾蛇外骨骼装甲涂装 +1984391101 RATTLESNAKE HELLPOD PATTERN 响尾蛇绝地喷射舱涂装 +400095188 RATTLESNAKE SHUTTLE PATTERN 响尾蛇运输船涂装 +1625389836 RATTLESNAKE VEHICLE PATTERN 响尾蛇载具涂装 +3728828182 Raw ore is refined into high-grade platinum at this refinery. Seize control of it. 这座精炼厂将原矿加工成高品质铂金。夺取控制权。 +2765000052 RAYSTING 雷斯汀 +844635607 RAZE STRATEGIC INFRASTRUCTURE 摧毁战略基础设施 +298103205 Razor Sharp Claws 利爪 +4176286499 Razor Sharp Claws 利爪 +1070913489 RD-4 RD4 +2725300846 RE-1861 Parade Commander RE-1861“阅兵指挥官” +1574114144 RE-1861 PARADE COMMANDER RE-1861“阅兵指挥官” +2852294319 RE-2310 Honorary Guard RE-2310“荣誉卫队” +4082436246 RE-2310 HONORARY GUARD RE-2310“荣誉卫队” +1853943253 RE-824 BEARER OF THE STANDARD RE-824“执旗手” +3666626223 Re-educator 思想改造 +3518850509 RE-EDUCATOR 思想改造 +1477469637 RE: MINE SAFETY 回复:矿山安全 +1478360991 Reach max level on one ship module. 一个舰船模块提升至最高级别。 +1989698991 REACTIVATE POWER GENERATOR 重新启动发电机 +3787456298 Reactivating these abandoned SEAF LiDAR towers will provide invaluable geographical data of the area. 重新启用这些废弃的超级地球武装部队激光雷达塔,即可生成该地区的宝贵地理数据。 +2823894811 Ready 就位 +520710174 READY 就位 +1190377439 READY 就位 +2512910497 READY IN #MINS:#SECS 准备倒计时 #MINS:#SECS +1805815248 Ready to Fire Orbital Cannon. Find target using adjacent control terminal 准备启动轨道加农炮。利用邻近控制终端寻找目标 +1705537422 Ready to initiate reloading sequence for M723 Orbital Slag Shell 即将启动M723轨道熔渣炮弹装填程序 +4152596005 READY TO LAUNCH 准备发射 +521947591 READY UP 准备就绪 +1443392861 REAF 利夫 +257989422 Real_NovaStarz 真_新星 +3153686785 Reaper of Bounties 赏金收割者 +3049468859 REAPER OF BOUNTIES 赏金收割者 +489511134 REARMING CANNON… 加农炮正在装弹…… +629809380 REASON 理由 +682820004 Rebar Resolve 钢筋意志 +3284519404 REBAR RESOLVE 钢筋意志 +929215876 REBELSGRAVE 叛军墓 +3359442388 RECEIVE SCAN DATA 接收扫描数据 +2449841149 Received #TIME ago... #TIME前收到… +2506700969 RECEIVED: #MINS DAYS AGO 接收:#MINS天前 +751886418 RECEIVED: TODAY 接收:今天 +1104365853 RECEIVED: YESTERDAY 接收:昨天 +3741841818 Receiving Confirmation 正在接收确认信息 +2456567278 Receiving Data 正在接收数据 +2663773781 Receiving Geodetic Data... 正在接收大地测量数据…… +2118449224 Recent 最近 +270351231 RECENT PLAYERS 近期玩家 +1237474346 RECHARGING 正在充能 +2267094068 Reckoning's Cheer 清算颂歌 +3048987541 RECKONING'S CHEER 清算颂歌 +1190975309 RECLAIM CITY 收复城市 +1778488497 RECLAIM CITY 收复城市 +2194282969 RECLAIM CITY 收复城市 +653354594 RECOIL 后坐力 +2670540436 RECOIL SIM 后坐力模拟 +3802654976 RECOIL SIMULATION 后坐力模拟 +1764965163 Recoilless Rifle 无后坐力炮 +689663659 RECOILLESS RIFLE 无后坐力炮 +1756239011 Recoilless Rifle Backpack 无后坐力炮背包 +1376224625 RECOILLESS RIFLE BACKPACK 无后坐力炮背包 +2722528211 Recommended by 9 out of 10 dentists 90%的牙医鼎力推荐 +1222861557 RECON CAMPAIGN 侦察战役 +3247523256 RECON CAMPAIGN PROGRESS 侦察战役进度 +282407560 RECON HEIGHTS 侦察高地 +493427676 Reconnaissance has pinpointed a number of key Automaton fuel and munitions depots within the city. + +Infiltrate quickly and destroy their supply bases before they can mount a defense. 侦察部队已确定城内多个机器人燃料和弹药关键补给站的位置。 + +快速潜入,摧毁补给基地,别让它们有机会筑起防线。 +3683690394 RECOVER SCIENTIFIC SPECIMENS 找回科学样本 +1592613774 RECOVER SSSD 找回超级固态硬盘 +1121413222 Recover the dropped #ENTITY 取回掉落的#ENTITY +2349064975 Recover top-secret intel from a downed SEAF reconnaissance aircraft. 从被击落的超级地球武装部队侦察机找回绝密情报。 +528213554 Recover top-secret intel from a downed SEAF reconnaissance plane. 从超级地球武装部队侦察机找回绝密情报。 +220335740 Red Planet's Memory 红星回忆 +477559844 RED PLANET'S MEMORY 红星回忆 +4013364623 Redacted Regiment 绝密军团 +1531056520 REDACTED REGIMENT 绝密军团 +151176181 Redeemer 救世主 +1416711028 REDEEMER 救世主 +1016650357 REDFIELD 雷德菲尔德 +1624905625 REDIRECT FUEL FLOW 更改燃料流向 +1360343155 Redirect fuel to new target 更改燃料流向,将其输送至新目标 +1732619482 REDIRECT FUEL TO NEW TARGET 更改燃料流向,将其输送至新目标 +2714055298 Redirect fuel to Transfer Station 更改燃料流向,将其输送至中转站 +230559838 REDIRECT HYDROGEN FLOW 更改氢气流向 +3152417024 Redirects propellant gases to compensate for muzzle climb when firing the weapon. 通过更改推进气体流向,抵消射击时的枪口上扬。 +3870315363 Redirects propellant gases to reduce recoil when firing the weapon. 通过更改推进气体流向,减少射击时的后坐力。 +692892828 Redondo 雷东多 +1159272209 REDTHORN 赤棘 +1190235804 Reduce the bug population by any means necessary. 不惜一切手段减少虫族数量。 +3160067283 REDUCED SIGNATURE 隐迹潜踪 +3489438173 Reduces Eagle Rearm time by #VALUE%. “飞鹰”重新武装的时间缩短#VALUE%。 +4094415381 Reduces call-in time for all orbital stratagems by#VALUE seconds. 所有轨道武器战略配备的呼叫时间缩短#VALUE秒。 +3142390756 Reduces cooldown time for all Stratagems by #VALUE%. 所有战略配备的冷却时间缩短#VALUE%。 +2015236172 Reduces cooldown time for Sentry, Emplacement, and Resupply stratagems by #VALUE%. 哨戒炮、炮台和补给战略配备的冷却时间缩短#VALUE%。 +3861381223 Reduces damage falloff from center of explosions caused by orbital Stratagems. 轨道战略配备引爆后从中心向外扩散的伤害衰减有所下降。 +2852813790 Reduces damage taken from impact and collisions by #BONUS. 将撞击和碰撞造成的伤害降低#BONUS。 +3031268253 Reduces range at which enemies can detect the wearer by #BONUS. 敌人探测佩戴者的范围缩小#BONUS。 +160917296 Reduces reload time for all support weapons by #VALUE%. 所有支援武器的装填时间缩短#VALUE%。 +3838118295 Reduces the dynamic range of in-game audio. Beneficial if you are listening at a low volume, quiet sounds become louder. 缩小游戏内音频的动态范围。有利于低音量的玩家,因为较轻的声音会变响。 +3092875128 Reduces the size of the muzzle flash by dispersing the burning propellant when firing the weapon. 通过分散燃烧的推进剂,减少射击时的枪口火焰大小。 +2192648194 Reduces time until new reinforcements are granted once they've been depleted. 缩短增援耗尽后获得新增援的时间。 +1673988944 Reduction in number of uses of #V_ONE stratagem no longer in effect. #V_ONE战略配备可用次数减少的效果结束。 +1679544793 REFINERY CENTRAL CONTROL 精炼厂中央控制 +2037673288 Refinery products are shipped for further processing via freighters docked here. Destroy them. 精炼厂的产品通过停靠此处的货轮运往后方进行深加工。摧毁它们。 +1128374590 Reflection Quality 反射质量 +3322485573 Reflex Sight 反射式瞄准镜 +3650167756 REFLEX SIGHT 反射式瞄准镜 +303505535 Reflex Sight Mk2 反射式瞄准镜Mk2 +3674314040 REFLEX SIGHT MK2 反射式瞄准镜MK2 +2895661664 REFORMED-BY-TRUTH 真理改造市 +4092874468 REFRESH 刷新 +4007176464 REGISTER 登记市 +1654759752 REGNUS 雷格努斯 +2626097776 Regulate engine output in Control Chamber 在控制室调节引擎输出 +3006600704 Reign 支配 +3241609005 Reinforce 增援 +3973386260 REINFORCE 增援 +436551541 Reinforce available 增援就位 +4246218593 REINFORCE AVAILABLE 增援就位 +192916041 REINFORCE AVAILABLE IN: 增援就位倒计时: +3532785264 REINFORCE DEAD TEAMMATES 增援已牺牲的队友 +1775245603 REINFORCE READY 增援就绪 +1297961099 Reinforce Stratagems Used 增援战略配备使用次数 +2823336101 REINFORCE UNAVAILABLE 增援不可用 +2813945735 REINFORCED EPAULETTES 强化肩章 +1871700431 Reinforced Scout Strider 强化侦察纵步者 +2209646811 REINFORCED SCOUT STRIDER 强化侦察纵步者 +135647353 Reinforced Scout Striders 强化侦察纵步者 +2574726151 REINFORCEMENT AVAILABLE IN #SECONDS SECONDS 增援就位倒计时:#SECONDS秒 +1411615216 Reinforcement increase is no longer in effect. 可用增援数增加的效果结束。 +2510839207 REINFORCEMENT PODS 增援太空舱 +3103904605 Reinforcement reduction is no longer in effect. 可用增援数减少的效果结束。 +1094761735 Reinforces sentries with expanded polystyrene pieces (peanut-shaped variety), which absorb thermal and blast energy. 利用可吸收热量和爆炸能量的膨胀聚苯乙烯片(形如花生)强化哨戒炮。 +2363011164 Reinforces sentries with state-of-the-art cyanoacrylate adhesives, greatly improving their durability under fire. 利用先进的氰基丙烯酸酯粘合剂加固哨戒炮,大幅提升其在炮火攻击下的耐久度。 +286268883 Rejoining mission 正在重新加入任务 +2476456312 RELATE TERMINAL TEXT 叙述终端文本 +1549126177 Relay Tower 中继塔 +1086883894 Release 松开 +1003483781 RELEASE 松开 +2253317857 RELEASE 松开 +893081203 RELEASE STERILIZING AGENT 释放灭菌剂 +2572958008 Release the fuel hose 卸除燃料软管 +1437066282 Release the hose 卸除软管 +2151944345 Reload 装填弹药 +1917768645 RELOAD 装填弹药 +537334413 RELOAD 装填弹药 +2032138018 RELOAD 装填弹药 +2608388352 Reload Artillery 为大炮装填弹药 +1105913844 Reload Drills 熟练装弹 +1898044942 Reload Drills 熟练装弹 +3743329545 Reload Drills 熟练装弹 +1127913161 RELOAD DRILLS 熟练装弹 +1997458346 RELOAD DRILLS 熟练装弹 +3018960979 RELOAD DRILLS 熟练装弹 +2952330711 Reload Orbital Shell 装填轨道炮弹 +1747936322 RELOAD TIME 装弹时间 +3670353506 Reloading 正在装填炮弹 +3641932052 Reloading discards any remaining ammunition. Plan your reloads wisely! 重新装填弹药会丢弃所有剩余弹药。请规划好装弹时机! +2860894091 Reloading discards the remaining rounds in your magazine. 重新装填弹药会丢弃弹匣内所有剩余弹药。 +4011610410 Reloading... 正在装弹…… +1147461061 REMAINING PLANETS COULD BECOME SUPERCOLONIES 剩余星球可能成为超级拓殖地 +2939230271 Remember Aim Mode 记住瞄准模式 +3762269985 Remember Outpost 32 铭记32号哨站 +785173364 Remember that armored enemies require heavy weapons. Bring the appropriate equipment for your selected difficulty. 记住,对付装备护甲的敌人要用重型武器。根据选定的难度挑选合适的装备。 +3977425510 Remember to fill in your C-01 permit before any act that could result in a child. 进行可能产生孩子的行为之前,记得先填好C-1授权表格。 +4129987753 Remember Weapon Functions 记住武器功能 +3048749003 Remember: Freedom! 牢记自由! +1742855267 REMEMBRANCE 缅城 +4214034559 REMOVE FRIEND 移除好友 +4257725743 REMOVE FROM FAVORITES 取消收藏 +3222875698 Removes stabilizing phlematizer agents from explosive material used to pack orbital shells, allowing for more powerful payloads. 从装填轨道炮弹的炸药物质中移除稳定减敏剂,增强炮弹的威力。 +3558858480 Render Distance 渲染距离 +19889008 Render Scale 渲染比例 +3868128225 Rendering the Helldiver's descent to the battlefield in splendorous foil, this cape illustrates that in any successful military machinery, heroic humans are the most vital piece. 这件披风以华丽烫印工艺展现了绝地潜兵空降战场的英姿,向世人昭示了一个真理:对于任何运转良好的军事机器来说,英勇无畏的人类都是最关键的部件。 +206215500 RepeatCustomer: Nice improvement on the previous identical model 回头客:比上一代版本做得更好 +2481837058 Repel 击退 +3897456562 Repel #COUNT Illuminate invasions 击退#COUNT 次光能者的入侵 +3051974986 Repel #COUNT Illuminate invasions in the #SECTOR 在#SECTOR击退#COUNT次光能者的入侵 +638501850 Repel #COUNT Illuminate invasions on #PLANET 在#PLANET上击退#COUNT次光能者的入侵 +606835900 Repel #COUNT invasions by #RACE 击退#COUNT#RACE的入侵。 +1763202421 REPEL INVASION 抵御入侵 +1983239401 REPEL INVASION FLEET 击退入侵舰队 +2527498143 Repel the Automaton invasion fleet attacking this planet. 击退正在攻打这颗星球的机器人侵略舰队。 +1236457519 Repel the enemy forces attempting to claim this city. 击退企图占领这座城市的敌军。 +2608438244 Repel the enemy forces attempting to claim this city. 击退企图夺取这座城市的敌军。 +4176568594 Repel the enemy forces attempting to claim this city. 击退企图占领这座城市的敌军。 +3425708434 Repel the fleet of invading Illuminate ships before they can seize control of the area. 在敌人夺取该区域之前,击退入侵的光能者舰队。 +1813416016 Repel the Illuminate contingent attacking this planet. 击退正在攻打这颗星球的光能者分遣队。 +2101446058 Repel the Illuminate invaders before they can do whatever it is they are doing. 在光能者采取任何举动之前将它们驱逐。 +608341943 Repel the Terminid swarm threatening to infest this planet. 击退企图占领这颗星球的终结族虫群。 +1333305891 Replaces the current method of loading cannons—manual shell insertion down the front of the barrel—with rear loading, which is much faster. 更替目前的装弹方式,用更迅速的枪管后部装弹方式取代目前在枪管前部手动装弹的方式。 +2184683383 REPORT 举报 +445898866 REPORT PLAYER 举报玩家 +1153925056 Reports indicate that a Bile Titan was last observed in this location. 报告显示,吐酸泰坦的最后目击地点就在这个位置。 +3863667165 Reports indicate that the Annihilator Tank was last observed in this location. 报告显示,湮灭坦克的最后目击地点就在这个位置。 +755435899 Representative 代表 +1841767958 Reprimand 训斥 +158155517 REPRIMAND 训斥 +73723553 REPRODUCTION 繁殖速度 +1498859373 Repurposed surveillance technology allows the Sentry Deployment Cannon to closely track the user at all times, no matter where they go or what they do, ready to fire at any second. 重新改造监控技术的用途,使哨戒部署炮能够随时密切追踪使用者,无论他们去哪里或在做什么,炮台随时都能开火。 +653919702 Request #REF stratagem #COUNT times 请求#REF战略配备#COUNT次 +317200030 REQUEST REINFORCE 请求增援 +3157864059 REQUEST REINFORCEMENT 请求增援 +2795189545 Request: #REQ +Error: #ERR +Status: #STAT 请求:#REQ +错误:#ERR +状态:#STAT +2764477544 Request: #REQ, Error: #ERR, Status: #STAT 请求:#REQ,错误:#ERR,状态:#STAT +2093976461 REQUIEM 安魂城 +187646075 REQUIREMENT: #MODULE 条件:#MODULE +1692908063 Requires another item you do not yet own. 需要另一件你尚未拥有的物品。 +3920963891 Requires base stratagem 需要基础战略配备 +3624359764 Requires Level #COUNT 需要达到等级#COUNT +356982805 Requisition 申购点 +421153617 REQUISITION 申购点 +1991686861 Requisition GRENADE LAUNCHER Stratagem permit. 申购榴弹发射器战略配备许可证。 +59972582 Requisition GRENADE LAUNCHER stratagem. 申购榴弹发射器战略配备。 +207788799 Requisition MACHINE GUN SENTRY Stratagem permit. 申购哨戒机枪战略配备许可证。 +4079514054 Requisition MACHINE GUN SENTRY stratagem. 申购哨戒机枪战略配备。 +979832500 Requisition ORBITAL SHELL stratagem. 申购轨道炮弹战略配备。 +1665907747 Requisition RESUPPLY Stratagem permit. 申购重新补给战略配备许可证。 +4058823741 Requisition RESUPPLY stratagem. 申购重新补给战略配备。 +2711534939 Requisition may be earned by completing missions 完成任务可以赚取申购点 +2410138797 Requisition slips 申购单 +879771045 Requisition: #COUNT 征用:#COUNT +2740703266 Reroute command path to override automaton control. 更改命令路径,夺取机器人的控制权限。 +2876745143 Rerouting Turret Control... 正在变更炮台控制路径… +109231288 RESCUE SCIENCE TEAMS 救援科学团队 +819011526 Research data available and ready for upload 研究数据准备就绪,可供上传 +992180888 RESEARCH INITIATIVE 研究倡议 +1526876604 Research Point 研究点数 +4232442047 Research suggests that Helldivers wearing this cape are seen as 17% more patriotic. 研究表明,绝地潜兵如果穿着这件披肩,所展现的爱国程度将提升17%。 +1401708733 Researchers Declared Dead After Canine Neural Communication 犬类神经通信装置意外接入附近狼类大脑 +704190118 RESET 重置 +3984996359 RESET CAMERA LOOK 重置视角 +1401146664 RESET TO DEFAULT 重置为默认 +1166766769 Reset Tower Alignment 重置激光雷达塔对齐 +1547267502 RESILIENCE 韧城 +3019919758 RESILIENCE 百炼 +1248590461 RESISTANCE 抵抗强度 +3162493476 Resolution 分辨率 +1252876522 RESOLVE 决心市 +1392572693 RESPAWN IN 复活倒计时: +3045085994 RESPITE 统息市 +114154817 RESPOND 回答 +4152257954 RESTART 重新开始 +2931876529 RESTART PUMPS 重启泵机 +3739334762 RESTART PUMPS 重启泵机 +192298931 RESTART REQUIRED 需要重启 +278936848 Restart the pumps located in this region. 重启该地区的泵机。 +2045888767 Restock ammo 补充弹药 +2267878169 RESTORE AIR QUALITY 恢复空气质量 +3909101812 Restore functionality to the E-711 pump site. 使711元素泵机恢复运行。 +2439699512 Restore functionality to the pump site. 使泵机区恢复运作。 +360320316 Restore power to the satellite tower 恢复卫星塔的电力输送 +1447250441 RESTRICTED AREA 禁区 +1375331670 RESUME 继续游戏 +949000562 Resuming Hosting. 正在恢复主办者状态。 +1673875834 Resupply 重新补给 +1263463686 RESUPPLY 重新补给 +3784950890 RESUPPLY 重新补给 +4138268575 Resupply stratagem availability has ended. 现已无法使用“重新补给”战略配备。 +2929529678 Reticle Color 准星颜色 +3344277774 Reticle Outline 准星轮廓 +3306673261 Reticle Visibility 十字线可视度 +2578681002 RETRIBUTARY 天谴 +1925796709 Retrieve WEAPON. 取回武器。 +1651671499 RETRIEVE ACCESS CODES 取回访问代码 +2102569661 Retrieve and transmit the vital research data. 检索并传输关键研究数据。 +2314593523 Retrieve and transmit the vital research data. 检索并传输关键研究数据。 +4042961494 Retrieve and transmit the vital research data. 检索并传输关键研究数据。 +4065130128 Retrieve coordinates 获取坐标 +1294020786 RETRIEVE ESSENTIAL PERSONNEL 找回重要人员 +2290550427 RETRIEVE ESSENTIAL PERSONNEL 找回重要人员 +3962314254 RETRIEVE KEYCARD 取得钥匙卡 +752565445 RETRIEVE LAUNCH CODES 取回发射代码 +2712777207 RETRIEVE MUTANT LARVA 取回变异幼虫 +3644855652 RETRIEVE RECON CRAFT INTEL 取回侦察机情报 +2759938366 RETRIEVE THE BLACK BOX 取回黑匣子 +1039398966 RETRIEVE THE CHEMICALS 回收化学原料 +2161574821 Retrieve the Flag of Super Earth 取回超级地球旗帜 +704813543 RETRIEVE THE GENERAL'S ORDERS 取回将军的命令 +1013604829 RETRIEVE VALUABLE DATA 检索有价值的数据 +2483189490 RETRIEVE VALUABLE DATA 检索有价值的数据 +2573125048 RETRIEVE VALUABLE DATA 检索有价值的数据 +4053983656 Retrying In #TIME 将在#TIME秒后重试 +2540642156 RETURN TO AREA 返回区域 +3135604915 RETURN TO SHIP 返回飞船 +2149500903 RETURN TO SHIP ALONE 独自返回飞船 +741863023 Return to Super Earth flag 返回超级地球旗帜所在位置 +2656897333 Return to terminal and force-start unit 返回终端并强制启动装置 +988047652 Return to the DEMOCRACY OFFICER. 返回民主官处。 +578353884 RETURN TO THE COMBAT ZONE: #SECONDS 返回作战区域:#SECONDS +1762594634 REVEAL FRIEND CODE 显示好友代码 +1834813801 Revenge orbital strike no longer in effect. 复仇轨道攻击不再生效。 +933561028 Reverse Gear Inverts Throttle 倒挡反转油门 +3305067854 REVERT 撤销 +862852696 REVERTING 撤销中 +4208152169 Review under investigation for treason 该评论涉嫌叛国,正在接受调查 +2982366424 REVOKED 已撤销 +3561232676 REVOLVER 左轮手枪 +3448492292 REVOLVING CYLINDERS 旋转弹巢 +4070447728 REWA 流望市 +1058222205 REWARD 奖励 +4242976058 Reward: #TYPE 奖励:#TYPE +149059891 REWARDS 奖励 +431499258 REWARDS 奖励 +172989294 RICOCHET 跳弹 +734122764 RICTUS SECTOR 瑞克图斯分区 +552725071 RIFLE 步枪 +1560758003 RIGEL SECTOR 参宿七分区 +3254491676 RIGHT 右 +3192900373 Right Button 右方向键 +876337019 RIGHT SHOULDER 右肩 +2527296573 RIGHT SHOULDERS 右肩 +2087390665 Right Stick 右摇杆 +4135045716 Right Stick 右操作杆 +3851712342 Righteous Revenants 正义复仇者 +336799220 RIGHTEOUS REVENANTS 正义复仇者 +947962593 Rightful Occupier 正当占领者 +4071531620 RIGHTFUL OCCUPIER 正当占领者 +999130615 RINKTOWN 冰场镇 +1916939864 Rip Gustafson Wins Yet Another Mr. Multiverse Competition 利普·古斯塔夫松再次荣获“多重宇宙先生”称号 +3176756443 RIRGA BAY 里尔加湾 +2516460275 Risen from the ashes of an ancient city, Rememberance is a monument to the Perseverance of Humankind. 自古城废墟中涅槃重生,缅城乃人类不屈精神的丰碑。 +3453655297 RIZIO'S VISION 里齐奥愿景 +2913710944 RL-77 RL-77 +3325227555 ROBOTICS 机械 +1447900565 ROBOTICS 机械 +2123662425 Robotics Workshop 机械工坊 +3533982950 ROBOTICS WORKSHOP 机械工坊 +3128840099 ROBOTICS WORKSHOP 机械工坊 +72977338 ROCK 石头 +4153486966 Rock Paper Scissors 石头剪刀布 +1742756661 ROCK PAPER SCISSORS 石头剪刀布 +232359449 ROCK-SOLID 坚如磐石 +2365630221 Rocket Devastator 火箭蹂躏者 +2122916248 ROCKET DEVASTATOR 火箭蹂躏者 +4038356158 Rocket Devastators 火箭蹂躏者 +1660115203 Rocket Launch in Progress 准备发射火箭弹 +3112705780 Rocket Raider 火箭奇袭者 +2587632663 ROCKET RAIDER 火箭奇袭者 +3545192316 Rocket Raiders 火箭奇袭者 +3009882761 Rocket Sentry 火箭哨戒炮 +3633384189 ROCKET SENTRY 火箭哨戒炮 +4032160005 Rocket Sentry stratagem availability has ended. 现已无法使用“火箭哨戒炮”战略配备。 +1474817139 Rocket Tank 火箭坦克 +1452679308 ROCKET TANK 火箭坦克 +2097521099 Rocket Tanks 火箭坦克 +945439925 ROCKY 岩地 +1394082721 Rocky outcroppings punctuate fields of tall grass in a planet dominated by misty highland terrain. 这颗星球地表大多是雾气氤氲的高地。茂盛的草原上不时冒出裸露的岩石。 +1246250826 ROCKY PLANET 岩地星球 +2831328950 ROGUE 5 罗格5 +451441290 Rohde 罗德 +3650776164 Roll 'Em 骰子定胜负 +738391381 ROLL 'EM 骰子定胜负 +3651448712 ROOKIE 菜鸟 +4162284233 ROOT OUT HIVES 清除虫窝 +3391266100 Root out the Terminid infestation on this planet. 彻底清除侵袭这颗星球的终结族。 +1725665992 Rotate 旋转 +2813115601 Rotate 旋转 +2317708011 ROTATE 旋转 +1974801601 Rotate Antenna 旋转天线 +297720264 ROTATING ITEMS 轮换物品 +1823257906 Roughly translates to "All Humans Must Die." One of the largest Megafactories on Cyberstan. A critical military production node. Defended by the Jet Brigade. 大意为“全人类必须死”。生化斯坦最大的超大型工厂之一。关键军事生产节点。由喷气旅驻守。 +2915230518 Roughly translates to "Destroy Freedom At All Costs." Significant conventional SEAF assaults will be required to support an offensive here, straining ammunition resources. 大意为“不惜一切代价摧毁自由”。在此发动攻势需要超级地球武装部队进行大规模常规突击支援,弹药资源将十分紧张。 +4226785777 Round 回合 +2693813631 Round Bonus 本轮加分 +1666122047 ROUNDS 弹药 +2037572983 ROUNDS 炮弹 +1501540430 ROUNDS RELOAD 逐发装弹 +2902819083 Rover 漫游车 +3575690541 ROVER 漫游车 +295786814 ROVING SHRIEKERS 漫游尖啸虫 +1459066230 RPM 转速 +2328034250 RR NEWS RR新闻 +2769135006 RS-100 Sanctioner RS-100“制裁者” +849272024 RS-100 SANCTIONER RS-100“制裁者” +2140503526 RS-11 RS-11 +543446303 RS-20 Constrictor RS-20“绞杀者” +3799869640 RS-20 CONSTRICTOR RS-20“绞杀者” +913017115 RS-40 Beast of Prey RS-40“掠食凶兽” +3258246494 RS-40 BEAST OF PREY RS-40“掠食凶兽” +919028186 RS-422 RS-422 +1227007866 RS-422 Railgun stratagem availability has ended. 现已无法使用“RS-422磁轨炮”战略配备。 +942247207 RS-6 Fiend Destroyer RS-6“歼魔者” +533278085 RS-6 FIEND DESTROYER RS-6“歼魔者” +3578495106 RS-67 Null Cipher RS-67“空密码” +1400346687 RS-67 NULL CIPHER RS-67“空密码” +3949936246 RS-89 Shadow Paragon RS-89“暗影典范” +1002465957 RS-89 SHADOW PARAGON RS-89“暗影典范” +362963850 Rude, Vulgar Language 语言粗鲁、粗俗 +4042032021 Ruggedized for extended operation beyond the reach of paved logistics. This armor's heavy plating is intended for the "unpaving" of hostile territory, providing a mobile bulkhead for Helldivers who don't know the meaning of "environmental obstacles." 为执行铺装物流以外的长时间任务而强固处理。这款护甲的重型装甲旨在“铲平”敌方领土,为不懂“环境障碍”为何物的绝地潜兵提供移动堡垒。 +4142342788 RUINED SYSTEM 废墟星系 +2107988609 RUMORS OF ILLUMINATE SIGHTINGS ARE WORK OF DISSIDENTS 目击光能者的谣言属异见分子所为 +4010007762 RUN SABOTAGE SOFTWARE 运行破坏软件 +3903153972 Rupture Charger 爆裂强袭虫 +3799701609 RUPTURE CHARGER 爆裂强袭虫 +2780462932 Rupture Chargers 爆裂强袭虫 +2270698456 Rupture Spewer 爆裂喷涌虫 +2318718576 RUPTURE SPEWER 爆裂喷涌虫 +560040805 Rupture Spewers 爆裂喷涌虫 +510506755 RUPTURE STRAIN 爆裂虫族变种 +953392591 Rupture Warrior 爆裂武斗虫 +3454838263 RUPTURE WARRIOR 爆裂武斗虫 +2493835917 Rupture Warriors 爆裂武斗虫 +3731034809 Ryhre 吕勒 +512338801 S 南 +3604997028 S 南 +4033132166 S (#COUNT°) 南#COUNT° +4271154730 S-11 S-11 +1825331623 SA-04 Combat Technician SA-04“技术兵” +1152717697 SA-04 COMBAT TECHNICIAN SA-04“技术兵” +2501206090 SA-12 SERVO ASSISTED SA-12“伺服辅助” +1458358876 SA-12 Servo-Assisted SA-12“伺服辅助” +504081326 SA-25 Steel Trooper SA-25“钢铁士兵” +1737597269 SA-25 STEEL TROOPER SA-25“钢铁士兵” +282273878 SA-32 Dynamo SA-32“精力充沛” +2245482128 SA-32 DYNAMO SA-32“精力充沛” +787710913 SA-7 Headfirst SA-7“冲锋者” +1998980000 SA-7 HEADFIRST SA-7“冲锋者” +489706864 SA-8 Ram SA-8“蛮悍” +1070374087 SA-8 RAM SA-8“蛮悍” +2666785586 Saber 军刀 +3476675802 SABER 军刀 +1255258576 SABOTAGE AIR BASE 破坏航空基地 +3657966445 Sabotage Automaton air capabilities in the region. 破坏机器人在该地区的空运能力。 +2219413559 SABOTAGE ORGO-PLASMA SYNTHESIS 破坏有机等离子合成 +3657147869 SABOTAGE SUPPLY BASES 破坏补给基地 +3909745087 Sabotage the Megafactory's air capabilities. 破坏超大型工厂的空中作战能力。 +1519500037 Sabotage the Megafactory's fuel and ammunition depots. 破坏超大型工厂的燃料和弹药库。 +782820489 Safe 安全 +4044971392 SAFEGUARD VITAL E-711 保卫VITAL E-711 +3069390405 SAFETY ORANGE EXOSUIT PATTERN 安全橘外骨骼装甲涂装 +3353006053 SAFETY ORANGE HELLPOD PATTERN 安全橘绝地喷射舱涂装 +69604317 SAFETY ORANGE SHUTTLE PATTERN 安全橘运输船涂装 +2398327890 SAFETY ORANGE VEHICLE PATTERN 安全橘载具涂装 +2121888692 SAGAN SECTOR 萨根分区 +2519064414 SALERIA SECTOR 萨勒莉亚分区 +611110727 Sales of Super Credits are disabled because the Steam Overlay is disabled. Please enable the Steam Overlay in your Steam settings. If this error persists after enabling the overlay and restarting the game, please refer to Steam support for assistance. 由于尚未开启Steam界面,你无法购买超级货币。请在你的Steam设置中开启Steam界面。如果启用界面并重启游戏后,问题仍未解决,请联系Steam客服寻求帮助。 +191450921 Sall 萨尔 +2666076354 Salute 敬礼 +2283776772 SALUTE 敬礼 +825026804 Salute the Flag of Super Earth 向超级地球旗帜敬礼 +538069015 Salvaged from a deep-storage vault, this well-ventilated cape symbolizes tenacious survival. Its visible scars bestow immediate veteran status, reminding all onlookers that the spirit of tireless service is immortal. 回收自一座长期储藏库,这款“千疮百孔”的披风象征着顽强的生存意志。清晰可见的“战损伤疤”平添资深行伍光环,并时刻警醒旁观者:百战不殆的奉献精神永垂不朽。 +3459865388 Salvo Fire 炮弹齐射 +2799678137 SALVO FIRE 炮弹齐射 +216050054 SALVOS 齐射 +1563965062 SAM Launcher 地对空导弹发射器 +1645613822 SAMEN-STARK 萨门-斯塔克 +3632688076 SAMMELSURIUM 喧沌 +2252001681 Sample 样本 +3030207280 Sample 样本 +72181546 Sample 样本 +2698026689 SAMPLE 样本 +470760097 SAMPLE 01 样本01 +2669057553 SAMPLE 02 样本02 +1170483735 SAMPLE 03 样本03 +1380527507 SAMPLE COLLECTION IN PROGRESS 正在收集样本 +2436561314 Sample Container 样本容器 +2712099845 SAMPLE CONTAINER 样本容器 +3856949076 SAMPLE CONTAINER 样本容器 +4016559333 Sample Count Visibility 样本数量可视度 +3017216974 Sample Extricator 样本拯救者 +2334087255 SAMPLE EXTRICATOR 样本拯救者 +2633969293 Sample Pickup Visibility 样本拾取可视度 +2798035968 Sample Scanner 样本扫描仪 +1834847904 SAMPLE SCANNER 样本扫描仪 +4268597147 Samples 样本 +97437033 Samples 样本 +2365423054 Samples 样本 +1941420908 SAMPLES 样本 +2655487228 SAMPLES 样本 +331887065 Samples are a diver's best friend 样本是潜兵最好的伙伴 +1874589215 Samples are a diver's best friend 样本是潜兵最好的伙伴 +1172245468 Samples Collected 收集样本数 +1653375691 SAMPLES EXTRACTED: 提取样本数: +4097714902 Samples Found 已找到样本数 +407681137 SAMPLES: 样本: +658025856 SAND RAIN 沙雨 +323114399 Sandberg 桑德贝格 +2585685866 Sandstorm In Progress 沙尘暴正在形成 +883460329 SANDSTORMS 沙暴 +3121815003 SANDY 沙地 +1234533814 SANDY PLANET 沙地星球 +3251726327 SANGIS 赤血 +1057921479 SAORSA GLEN 萨奥萨谷 +4289452968 SAPPHIRE LAKE 蓝石湖 +1854681309 SAPPORO 札幌 +3300297336 SAR-1 Sniper Rifle stratagem availability has ended. 现已无法使用“SAR-1狙击步枪”战略配备。 +3578469809 SARAH SWIFT DAM 莎拉斯威夫特大坝 +2838153097 SATELLARIA 卫环 +2982138088 Satellite imagery confirms that the Automatons are operating a fuel depot in this area. 卫星图像证实机器人在该区域内有一座正在运作的燃料库。 +28055569 Satellite imagery has revealed that entire skyscrapers in this district are infested with Terminids. These beautiful homes and prosperous offices are now nothing but Shrieker breeding grounds. + +Destroy the former icons of Prosperity that have been so cruelly parasitized. 卫星图像显示,该区域内的整栋摩天大楼都已经被终结族侵占。曾经美丽的家园和繁荣的办公室,如今沦为尖啸虫的繁殖之地。 + +摧毁被这些寄生虫残忍霸占的昔日繁荣象征。 +1683637306 SATURATED RANKS 军衔晋升饱和 +1815803393 SATURATION 饱和度 +2985529596 SAVANNA 稀树 +1294782553 SAVANNA PLANET 稀树星球 +1872692966 SAVE 保存 +1669407857 SAVE & CLOSE 保存并关闭 +3154920935 SAVE WEAPON CONFIG 保存武器配置 +2317508651 SC-15 Drone Master SC-15“无人机大师” +525109127 SC-15 DRONE MASTER SC-15“无人机大师” +2299388240 SC-28 Stealth Ranger SC-28“潜行游侠” +2787970405 SC-28 STEALTH RANGER SC-28“潜行游侠” +3161943025 SC-30 Trailblazer Scout SC-30“开路侦察兵” +3046397365 SC-30 TRAILBLAZER SCOUT SC-30“开路侦察兵” +1155286393 SC-34 Infiltrator SC-34“深入敌阵” +1374581174 SC-34 INFILTRATOR SC-34“深入敌阵” +3707804375 SC-37 Legionnaire SC-37“军团士兵” +3675650842 SC-37 LEGIONNAIRE SC-37“军团士兵” +4116583190 SCALD 烧卡尔德 +716447849 Scales the distance and screen sizes at which objects are drawn. Reducing this improves CPU performance. 调整绘制物体的距离和屏幕尺寸。下调该数值可以改善CPU性能。 +4000019774 Scan the QR code or press the button below to begin linking your accounts from Steam and PlayStation™Network 扫描二维码或按下方按键即可开始将你的Steam账户与PlayStation™Network账户绑定 +2658759976 Scan the QR code to participate in the post match survey. 扫描二维码参与战后调查。 +2683089800 SCANNER RECHARGING... #COUNT 扫描仪正在充能……#COUNT +322354744 SCANNING... 正在扫描…… +1927541015 SCANNING... 正在扫描…… +1016107533 SCARLET HAVEN 绯红湾 +3345385259 Scatters powerful anti-tank mines that deal heavy, armor-penetrating damage. Minefield is less densely packed relative to smaller mines. 发射强力的反坦克地雷,可造成严重的穿甲伤害。与较小型的地雷相比,雷区的部署密集度较低。 +4212839382 Scavenger 食腐虫 +2502973376 SCAVENGER 食腐虫 +2208968160 Scavengers 食腐虫 +4094305762 Schema Laid Bare 解封蓝图 +2590487532 SCHEMA LAID BARE 解封蓝图 +262003986 Schmid 施密德 +3484155856 SCHOLAR'S MOOR 学者荒原 +4172658715 Schonberger 舍恩伯格 +4149219876 Schrödinger's Cat Definitively Determined Dead Following 核武器试验成功,薛定谔的猫 +472312330 Science is done by quantity 科学以量取胜 +298949484 Science strike teams—each consisting of a xenobiologist, a theoretical physicist, an astro-meteorologist, and a psychologist—will conduct expeditions to the planet's surface at key locations. + +Clear the area of Terminid nests to secure the research site. 科考突击队将对星球表面的重要地点进行考察,每支突击队由一名异星生物学家、一名理论物理学家、一名天文气象学家和一名心理学家组成。 + +清除该区域的终结族巢穴,保障研究地点的安全。 +3860979267 Scientists vital to the continued war effort were working in this top-secret research facility when the invasion hit. + +They are currently kept safe inside emergency bunkers that must be opened from the outside to allow for an authorized evacuation. 遭到入侵时,在这场持久战中起到至关重要作用的科学家正在这座绝密研究设施中孜孜不倦地工作。 + +他们目前在紧急掩体里很安全,必须从外侧打开该掩体,才能执行授权撤离行动。 +37208441 Scientists without fear of implosion or spaghettification study negative energy here. 无惧内爆与意大利面条化风险的科学家在这里研究负能量。 +793359876 SCISSORS 剪刀 +1891490952 Scope Sensitivity 开镜灵敏度 +2153591729 SCOPED 开镜 +1101658926 Scorcher 焦土 +1998675254 SCORCHER 焦土 +4271615407 Scorching temperatures, high winds, and low precipitation cause a near-constant cycle of fires to sweep this planet, punctuated by short bursts of lush rebirth between infernos. 酷热、强风和稀少的降水导致席卷这颗星球的烈火灾害几乎从未间断,茂密复生的绿色植被在这个炼狱里只有极其短暂的喘息之机。 +3698888839 SCORE 得分 +3580562284 SCOUR SURFACE 肃清地表 +2285567490 Scourge of Tyranny 暴政克星 +1233838964 SCOURGE OF TYRANNY 暴政克星 +3682222023 SCOUT 侦察 +4196722877 Scout Handshake 侦察兵式握手 +2474302144 SCOUT HANDSHAKE 侦察兵式握手 +2319746535 Scout Raider 侦查奇袭者 +3895550358 SCOUT RAIDER 侦查奇袭者 +4277211858 Scout Raiders 侦查奇袭者 +20706814 Scout Strider 侦察纵步者 +3261365930 SCOUT STRIDER 侦察纵步者 +149196 Scout Striders 侦察纵步者 +1839035128 Scrambler 扰频器 +1857062393 SCRAMBLER 扰频器 +825679587 Scraps of Sovereignty 主权碎片 +2414516585 SCRAPS OF SOVEREIGNTY 主权碎片 +3849701791 Scratched into the pedestal: "They will save us." 底座上刻着:“他们会救我们。” +2993355447 Screen Brightness 画面亮度 +4185417461 Screen Device 屏幕设备 +1223048391 Screen-Space Ambient Occlusion 屏幕空间环境光遮蔽 +758937481 Screen-Space Global Illumination 屏幕空间全局光照 +4005693733 Screen-Space Reflections 屏幕空间反射 +629282362 SCROLL 滚动 +3349220266 SCUTUM CANIS LUPUS 狼盾 +876154545 Scythe 长柄镰 +1388808029 SCYTHE 长柄镰 +1529407345 SE 东南 +3711136636 SE 东南 +4248187236 SE (#COUNT°) 东南#COUNT° +2909500440 SEAF 超级地球武装部队 +441886279 SEAF Advance Against Automatons Stalls. 超级地球武装部队向机器人据点进发 +472605007 SEAF Artillery 超级地球武装部队大炮 +1044595250 SEAF ARTILLERY 超级地球武装部队大炮 +2591631933 SEAF ARTILLERY 超级地球武装部队大炮 +1253787405 SEAF Artillery Ammo Rack 超级地球武装部队炮弹挂架 +242831539 SEAF Artillery System 超级地球武装部队大炮系统 +646892390 SEAF Artillery System 超级地球武装部队大炮系统 +1289270262 SEAF ARTILLERY: EXPLOSIVE 超级地球武装部队大炮:炸弹 +1741039648 SEAF ARTILLERY: HIGH-YIELD EXPLOSIVE 超级地球武装部队大炮:高爆弹 +918325647 SEAF ARTILLERY: MINI NUKE 超级地球武装部队大炮:迷你核弹 +950118620 SEAF ARTILLERY: NAPALM 超级地球武装部队大炮:凝固汽油弹 +157842484 SEAF ARTILLERY: SMOKE 超级地球武装部队大炮:烟雾弹 +3466045009 SEAF ARTILLERY: STATIC FIELD 超级地球武装部队大炮:静电场 +1725267452 SEAF BASIC TRAINING FACILITIES 超级地球武装部队基础训练基地 +2120670482 SEAF Combat Botanists have confirmed: the Illuminate are seeding Void-altered blossoms to reshape this world's ecosystem. Their alien pollen contaminates native flora through cross-pollination, spreading a toxin that gradually mutates the entire planet. + +This bioengineered sickness must be cut off at its roots. Eradicate every single one of these flowers. 超级地球武装部队战斗植物学家证实:光能者正在播撒因寂域而变异的花种,试图重塑该星球的生态系统。这些异星花粉正通过异花授粉污染本地植物,传播一种会令整颗星球逐渐变异的毒素。 + +必须将这种生物工程病害斩草除根。铲除每一朵寂域之花。 +4206715437 SEAF Combat Engineers have deployed a Rapid Modular Drilling Platform above a pool of a mysterious E-710-like substance deep within the Terminid caves. High Terminid activity has made the area extremely dangerous and made extraction impossible. + +Deploy to the Hive World and manually activate the Rig. Protect the extraction process until the substance is safely airlifted away. 终结族洞穴深处有整整一池的类710元素神秘物质,超级地球武装部队战斗工程师已在其上方部署了快速模块化钻机平台。终结族活动频繁,导致该区域变得异常危险,提取难度极大。 + +前往虫窝世界并手动激活钻机装置。提取过程中要捍卫阵地,保护神秘物质安全空运离开。 +3714755758 SEAF Combat Engineers have deployed a Rapid Modular Drilling Platform above a pool of E-711 within the Terminid caves. High Terminid activity has made the area extremely dangerous and made extraction impossible. + +Deploy to the Hive World and manually activate the Rig. Protect the extraction process until the E-711 is safely airlifted away. 终结族洞穴深处有整整一池的711元素,超级地球武装部队战斗工程师已在其上方部署了快速模块化钻机平台。终结族活动频繁,导致该区域变得异常危险,提取难度极大。 + +前往虫窝世界并手动激活钻机装置。提取过程中要捍卫阵地,保护711元素安全空运离开。 +2752474601 SEAF COMMUNICATIONS DEVICE 超级地球武装部队通信设备 +4276858195 SEAF COUNTEROFFENSIVE 超级地球武装部队的反攻 +2371122801 SEAF Fight Against Bots Augmented By Limited Helldiver Operations. 绝地潜兵的局部行动助力超级地球武装部队扩张抗击机器人的规模 +2211654071 SEAF Forces Cede Another Planet to Advancing Automatons. 机器人逼近,超级地球武装部队再次割让一颗星球 +3364339856 SEAF in this region have reported sightings of Chargers exhibiting dangerous new mutations. + +These specimens must be eliminated before their mutant strain spreads. 该地区的超级地球武装部队报告称,发现强袭虫表现出危险的新型突变属性。 + +必须在突变种扩散之前将其消灭。 +3409838466 SEAF MILITARY OUTPOST 超级地球武装部队军事哨站 +2724329671 SEAF REINFORCEMENTS 超级地球武装部队的增援 +3334285492 SEAF SAM-SITE 超级地球武装部队地对空导弹基地 +2982012972 SEAF scouts have reported contact with airborne enemy units. The enemies of Freedom now terrorize the sky itself. Helldivers are advised to stay alert for aerial threats, and to free the sky of terrorism whenever possible. 超级地球武装部队的侦察兵报告称曾与敌方空军交火。威胁自由的大敌现在染指了天空。建议绝地潜兵警惕空中威胁,并尽可能肃清天空的威胁。 +1333134146 SEAF Soldier 超级地球武装部队战士 +1449420233 SEAF Squad 超级地球武装小队 +1356373844 SEAF troops report sightings of a Devastator in this area. 超级地球武装部队士兵报告称,在这片区域发现了蹂躏者。 +4014396602 SEAF units and loyal civilians are both on the battlefield. 战场上同时发现超级地球武装部队和忠诚平民。 +848244517 SEAF units have encountered Impalers in this region. They are not capable of dealing with this threat. + +As elite Helldivers, you must hunt down and kill all Impalers in the area. 超级地球武装部队已在该地区遭遇穿刺虫。他们无法应对这一威胁。 + +作为精锐部队的绝地潜兵,你必须找到并消灭该地区所有穿刺虫。 +3067367692 SEAF UNITS IN AREA 区域内有超级地球武装部队 +2597423876 SEAL BUG HOLES 封闭虫穴 +3978113817 Seal indicated exhaust pipes 密封已标记的排气管 +636846248 Seal of General Consensus 康森瑟斯将军之印 +4015722465 SEAL OF GENERAL CONSENSUS 康森瑟斯将军之印 +2027681036 Search 搜索 +3239385449 SEARCH 搜索 +2577581064 SEARCH AND DESTROY 搜寻并摧毁 +3347495776 SEARCH AND DESTROY 搜寻并摧毁 +3385297386 SEARCH FOR SURVIVORS ONGOING 生还者搜索行动仍在进行中 +3563930713 Search for the target in the indicated map area 接近目标区域 +2756104411 Search Friends List 搜索好友列表 +3973482337 Search Platoon Members 搜索特战排成员 +2767203608 Search Recently Played 搜索近期共同游戏的玩家 +2376449040 SEARCH RESULT 搜索结果 +2714866341 Search Territory #TERRITORY on Planet #PLANET 搜索#PLANET星球上位于#TERRITORY的敌方领地 +1019331223 Searching for active SOS beacons... 正在寻找激活的S.O.S.求救信标… +1709336004 SEARCHING FOR MISSIONS IN PROGRESS 正在寻找进行中的任务 +3056397440 Searching for problems. Please wait. 正在查找问题。请稍候。 +2554711351 Season ends in: #DAYS Days #HOURS Hours 赛季倒计时:#DAYS天#HOURS小时 +3356322774 Season ends in: #DAYS Days #HOURS Hours 赛季倒计时:#DAYS天#HOURS小时 +775063648 Season I 第I赛季 +456674217 SEASON I 第I赛季 +3112928938 Season II 第II赛季 +1690926318 SEASON II 第II赛季 +3762867952 Season III 第III赛季 +211519948 SEASON III 第III赛季 +3329970575 Season Premiere of "Surviving the Galactic" Strands 18 Citizens on Kryx's Ice Moon For 39 Days 《星系求生》本季首播导致18名公民滞留克里克斯冰质卫星39天 +122093803 SEASSE 西斯 +531700056 SEASSEFYRE 息战市 +4065182789 Secondary 次要 +2096205813 SECONDARY 次要 +4138815719 SECONDARY 次要武器 +574592446 SECONDARY EXTRACTION ZONE 次级撤离区 +224325025 Secondary Objective Visibility 次要目标可视度 +3701975858 Secondary Objectives 次要目标 +2893930481 Secondary Objectives Completed 达成次要目标 +1743686795 SECONDARY WEAPON 次要武器 +2546218986 SECONDARY WEAPON 次要武器 +2067612636 SECONDARY WEAPONS 次要武器 +3820768900 Sector 分区 +324886748 SECTOR 分区 +2035440895 SECTOR INTRUSION DETECTED 侦测发现分区遭到入侵 +1816240066 SECTOR MAP 分区地图 +1344003897 Secure a black box containing critical intel from a downed SEAF recon aircraft. 从被击落的超级地球武装部队侦察机中取回存有关键情报的黑匣子。 +766592482 SECURE BLACK BOX 取回黑匣子 +1559577929 SECURE BLACK BOX 取回黑匣子 +35026167 SECURE GROUND ALL-TERRAIN EXTRACTION RIG 控制地面全地形采集钻机 +935971687 SECURE RESEARCH SITE 保障研究地点的安全 +1895607022 SECURE TACTICAL VIDEO CAMERA 获取战术摄像机 +2586556407 Secure the black box from a crashed weather reconnaissance aircraft and transmit the data off-planet. 从坠毁的气象侦察机中取出黑匣子,并将数据传输至星球外。 +3908101367 Secure the SSSD containing the top-secret Cannon Access Codes. 找到内含机密加农炮访问代码的超级固态硬盘。 +2473378639 See a planet that's on the brink of falling under enemy control? Rally your fellow Helldivers and mount a defense. Every mission counts! 一颗星球即将落入敌人的铁蹄之下,你看见了吗?快号召其他绝地潜兵一起建立防线。每一场任务都至关重要! +1907319741 Seeker 寻踪者 +2604654866 SEEKER 寻踪者 +324859132 SEISMIC PROBE 地震探测仪 +2354025483 SEISMIC PROBE 地震探测仪 +3702832474 SEISMIC SCAN RESULT: 地震扫描结果: +4060481832 SEIZE FUSION BATTERIES 夺取聚变电池 +3847588790 SEIZE HIGH-GRADE PLATINUM 夺取高品质铂金 +367155459 SEIZE INDUSTRIAL COMPLEX 占领工业联合体 +2197847436 Seize the Automaton industrial complex in the name of Managed Democracy. 以管理式民主之名占领机器人工业联合体。 +1591269562 SEIZE THE CIVILIAN SATELLITE TOWERS 夺取民用卫星塔 +1666934667 Select 选择 +4229762283 SELECT 选择 +954575608 Select a mission and get ready to dive! 选择任务,准备俯冲降落。 +1858480289 Select a Mission and get ready to dive. 选择一项任务,准备深潜绝地。 +1785205442 Select a location where you want to drop in on the mission. 选择你计划在任务中降落的位置。 +3764011922 Select an Operation area to do Missions in - You can either join an ongoing Operation or start a new one. 选择行动区域,前去执行任务 - 你既可以参加正在进行中的行动,也可以发起新的行动。 +19041633 SELECT AND ADJUST 选择并调整 +1610686869 SELECT CAMPAIGN 选择战役 +3667133920 SELECT DATA MODULE FOR UPLOAD 选择上传数据模块 +2190481941 Select designated coordinates in grid 选择网格中的指定坐标 +3279099082 SELECT DROP ZONE 选择空投地点 +1294922204 Select hydrogen outflow target 选择氢气流出目标 +2444111178 Select if anti-aliasing will be applied to smoothen jagged edges. 选择是否启用抗锯齿处理锯齿状边缘。 +269788141 Select level of detail of shadows, as well as the amount of lights that cast. 选择阴影细节层次,以及投射的光照数量。 +2446803322 Select level of geometry detail. Lower values increase GPU performance, at the cost of silhouette detail on objects. 选择几何图形细节层次。下调数值可以改善GPU性能,但是会弱化物体的轮廓细节。 +646890793 Select level of quality of reflections. Most noticeable on glossy surfaces. The high setting enables Screen Space Reflections, which improves the appearance of shiny surfaces. 选择反射质量的等级。效果常见于光滑表面。设置为高等级将启用屏幕空间反射,优化光亮表面的显示效果。 +215978558 SELECT MISSION 选择任务 +713902898 SELECT OPERATION 选择行动 +2534741534 SELECT PLANET 选择星球 +3054612013 Select quality level of reflections on certain surfaces. Higher settings allow for more accurate reflections but may affect performance. 选择特定表面的反射质量等级。上调该设置可以提高反射的精确度,但是可能会影响性能。 +3291120685 Select quality profile. +Quality targets the highest visual fidelity at a lower framerate. +Performance targets a higher framerate for a smoother experience at a lower rendering resolution. 选择画质设置。 +“画质”会以降低帧率为代价,提供最逼真的视觉效果。 +“性能”会追求较高的帧率带来更顺畅的体验,但是会降低渲染分辨率。 +1045001578 SELECT REINFORCEMENT LOCATION 选择增援地点 +2117228825 SELECT SECTOR 选择分区 +1248889248 SELECT SLOT 选择槽位 +2154001434 Select systems to sabotage 选择要破坏的系统 +3853961699 Select target network coordinates in grid 选择网格中的目标网络坐标 +1640275889 Select the Equipment and Stratagems to bring on this Mission. 选择你要在此次任务中携带的装备和战略配备。 +393068769 Select the angle range of the compass. 选择罗盘的角度范围。 +2745355461 Select the behaviour of the crosshair visibility during gameplay. 选择游戏过程中十字准星可视度的变化方式。 +720487348 Select the default audio language spoken by characters. 选择角色音频的默认语言。 +766568577 Select the default language for text and audio. 选择文本和音频的默认语言。 +731071688 Select the default language for the text that appears in menus, subtitles and captions. 选择菜单、字幕和隐藏式字幕的默认语言。 +3539126901 Select the desired anti-aliasing and upscaling algorithm. These are used to provide improved visuals as well as to improve performance. This includes TAA, NVIDIA DLSS, AMD FSR and Intel XeSS, if supported. 选择所需的抗锯齿与增强算法模式。这些技术用于提升画质并改善游戏性能。包括TAA、NVIDIA DLSS、AMD FSR以及Intel XeSS(如果设备支持)。 +2432548796 Select the display resolution. This is the pixel count of the final image. Lower values will have less detail. In windowed mode this setting also dictates the size of the window, in the other modes we recommend using the resolution of the display device and adjusting the Render Scale setting to achieve desired performance. 选择显示的分辨率。该数值为最终图像的像素点总数。数值越低,显示的细节越少。在窗口模式中,该选项也会决定窗口的尺寸。在其他模式中,我们推荐使用与显示设备相同的分辨率,然后调整渲染比例,从而实现理想的性能。 +2799325677 Select the game display mode. Fullscreen has the fastest response time, but may make switching to other applications slower. 选择游戏的显示模式。全屏模式响应速度最快,但是可能会导致切换至其他应用程序的速度变慢。 +3452866512 Select the graphics device that will be used to render the game. This should normally be set to the highest performance graphics device in your system. 选择用于渲染本游戏的图形设备。通常应将此项设置为系统内性能最高的图形设备。 +2697243894 Select the intensity of sudden camera movements. 选择视角突然移动的幅度。 +3819890633 Select the level of quality for particle effects. 选择粒子效果的质量等级。 +4183940597 Select the resolution of textures. Higher settings provide more detail at the cost of memory (VRAM) and performance. This is the primary setting to adjust on devices with lower than recommended VRAM. Recommended VRAM for each setting: +Ultra - 10GB +High - 8GB +Medium - 6GB +Low - 3GB 选择贴图分辨率。较高的选项可以提供更加细致的图像,但是会占用显存(VRAM),影响性能。在VRAM未达到推荐值的设备上,这是首先需要调整的设置选项。各项设置推荐VRAM: +超高 - 10GB +高 - 8GB +适中 - 6GB +低 - 3GB +133707452 Select the screen device where the game will be displayed. 选择用以显示本游戏的屏幕设备。 +825003035 Select the visibility of hints during gameplay. 选择游戏过程中的游戏提示可视度。 +773844293 Select the visibility of interaction prompts during gameplay. 选择游戏过程中的互动提示可视度。 +641713639 Select the visibility of mission information. 选择任务信息的可视度。 +2414774680 Select the visibility of ordinal directions on the compass. 选择罗盘的方位可视度。 +567605588 Select the visibility of player markers during gameplay. 选择游戏过程中的玩家标记可视度。 +4293218971 Select the visibility of player nameplates during gameplay. 选择游戏过程中的玩家名牌可视度。 +2003493097 Select the visibility of primary objectives. 选择主要目标的可视度。 +787690621 Select the visibility of sample count during gameplay. 选择游戏过程中的样本数量可视度。 +3230504138 Select the visibility of secondary objectives. 选择次要目标的可视度。 +3240365449 Select the visibility of Stratagems during gameplay. 选择游戏过程中的战略配备可视度。 +3709301333 Select the visibility of teammate direction during gameplay. 选择游戏中的队友方位可视度。 +1118854312 Select the visibility of teammate status during gameplay. 选择游戏中的队友状态可视度。 +2465839687 Select the visibility of the compass. 选择罗盘可视度。 +3395846550 Select the visibility of the grid lines in the top compass. 选择顶部罗盘的网格线可视度。 +1088938228 Select the visibility of the info feed during gameplay. 选择游戏过程中的动态信息可视度。 +3411838192 Select the visibility of the injury widget during gameplay. 选择游戏中的伤势轮盘可视度。 +1304201243 Select the visibility of the player's health status during gameplay. 选择游戏过程中的玩家生命值状态可视度。 +3548906657 Select the visibility of the stamina bar during gameplay. 选择游戏过程中的耐力槽可视度。 +1560210930 Select the visibility of tooltips during gameplay. 选择游戏过程中的提示信息可视度。 +2936206351 Select the visibility of vehicle info during gameplay. 选择游戏过程中的载具信息可视度。 +2421295770 Select the visibility of weapon status during gameplay. 选择游戏过程中的武器状态可视度。 +2604615832 Select the visibility of your destroyer marker during gameplay on city maps. 选择游戏过程中城市地图上你的驱逐舰标记的可视度。 +4081003228 Select the width of the compass. 选择罗盘宽度。 +2746560797 Select the width of the stamina bar during gameplay. 选择游戏过程中的耐力槽宽度。 +559486909 Select when an on-screen option will be shown. Default behavior is to only display the on-screen keyboard if a keyboard was not used to enter the text input state. 选择何时显示屏幕选项。默认是仅在未使用键盘输入文本时才显示屏幕键盘。 +2400709038 Select when an on-screen option will be shown. Default behavior is to only display the on-screen keyboard if a keyboard was not used to enter the text input state. May require Steam Big Picture mode on PC. 选择何时显示屏幕选项。默认是仅在未使用键盘输入文本时才显示屏幕键盘。可能要在PC上使用Steam的大屏幕模式。 +1121777298 Select your Drop Location anywhere on the mission map - Try to avoid dangerous locations. 在任务地图上选择任意降落地点,尽量避开危险地点。 +161220911 Select your gear and Stratagems. 选择你的装备和战略配备。 +3217996618 Selectively lower resolution where detail is less necessary. 在细节需求不高时,选择性降低分辨率。 +1722303028 Selects the graphics API used. 选择使用的图形API。 +2937837820 Selects the text to speech narrator voice type 选择文字转语音的旁白声音类型 +4239770158 Self inflicted 自伤 +3784605505 Sellerfors 塞勒福什 +1469190083 Semi 半自动 +256058930 Senator 参议员 +1208200869 Senator 参议员 +3480856186 SENATOR 参议员 +893408910 Senator Killjoy Jr. Gives Stirring Speech: "Super Earth Stronger Than Ever!" 小克乔伊参议员言论引起轰动:“超级地球目前实力胜过任何一个历史时期!” +2902346740 SENATOR PEAKS 议员峰 +2024183631 Send chat logs (optional) 发送聊天记录(可选) +197789485 SEND FRIEND REQUEST 发送好友申请 +2418336066 SEND REPORT 发送举报 +1542765264 Send You There" Stranded Behind Enemy Lines. 继续爆出参赛选手被困敌阵 +4165159481 SENGE 23 新戈23 +786752156 Sentient Computer Network Swiftly Deleted By Quick-Thinking IT Laborer. IT劳工反应迅速,第一时间删除感知电脑网络 +200062099 Sentinel 哨兵 +161598459 Sentries rotate towards new targets more quickly. 哨戒炮可更快地转向新目标。 +155504147 Sentries take #VALUE% less damage from explosions. 哨戒炮受到的爆炸伤害减少#VALUE%。 +18899425 SENTRY 哨戒炮 +2819358962 SEORAKSAN 雪岳山 +2394933301 Sep 9月 +3283252062 SEPARATED 独立 +1534576226 September 9月 +2971614211 Septic Breath 脓毒吐息 +2424499063 SEQUIM 猎城 +3461599670 SERENDIPITY XI 天缘XI +399006276 SERENITY SUMMIT 静峰 +2864776199 SERGEANT 中士 +1831453784 Serrated Claws 锯齿螯爪 +644683477 SERVANT OF FREEDOM 自由公仆 +1309239989 Servants of Freedom 自由公仆 +1526662829 SERVANTS OF FREEDOM 自由公仆 +2791493808 Server request failed - Error code: 服务器请求失败 - 错误代码: +2513414885 Servers at capacity. Please try again later. 服务器爆满,请稍后再试。 +1264502471 Service Technician 维修技术员 +1864553949 Service Technician #NAME #NAME维修技术员 +1713165955 SERVITUDE 奴役市 +142525292 SERVO-ASSISTED 伺服辅助 +959402628 SES SES +2642707696 SEST #HOURS:#MINUTES:#SECONDS 超级地球标准时间#HOURS:#MINUTES:#SECONDS +3139599101 Set the default audio language spoken by characters. 设置角色音频的默认语言。 +3504573238 SETIA 赛提亚 +904306987 SETTLEMENT 定居点 +124315771 SETTLEMENT 7 7号定居点 +1940364089 SETTLER'S HONOR 开拓者荣誉市 +96623372 SETUP 设置 +3394888049 SETUP 设置 +3581530276 SEVENSEAL 七印城 +2458729587 Several districts of this Megafactory contain supplies that fuel the Automatons' radicalized war machine. + +Breach their supply depots and destroy their stockpiles. 这所超大型工厂内多个区域存储的物资正在为机器人的激进战争机器提供补给。 + +突破敌方补给库,摧毁它们的物资储备。 +3207161693 Severien 塞韦连 +3545171052 SEVERIN SECTOR 塞弗林分区 +628685971 SEVERITY 严峻市 +2402248837 SEYSHEL BEACH 塞舌尔海滩 +1844554020 SG-20 SG-20 +2334545640 SG-22 SG-22 +504280703 SG-225 SG-225 +2667149792 SG-225BB SG-225BB +2872464260 SG-225IE SG-225IE +4270941544 SG-225NS SG-225NS +3223082271 SG-225SP SG-225SP +1011607504 SG-451 SG-451 +59792671 SG-8 SG-8 +3318448997 SG-8P SG-8P +1803690144 SG-8S SG-8S +1292558029 SG-97 SG-97 +4135624003 SH-20 SH-20 +2111132037 SH-32 SH-32 +3510710515 SH-51 SH-51 +1418104632 Shadow Quality 阴影质量 +2318804196 SHADY OAKS 荫橡 +2388297546 Shafts of Despair 绝望之柱 +3926434439 SHAFTS OF DESPAIR 绝望之柱 +1066909283 SHALLUS 沙勒斯 +4159608762 Shameful Return 屈辱归来 +1113086077 Sharpness 锐度 +1404797742 Shear 切变 +2907822320 SHEAR 切变 +1861970315 SHED 囤仓 +436121739 SHELT 谢尔特 +2180236555 SHELTER 谢尔特 +1710555974 SHETE 赛特 +3633567300 Shield 盾雷 +1881166987 Shield 之盾 +2082964483 SHIELD 盾雷 +1111626971 Shield Generator Pack 防护罩生成包 +2859707695 SHIELD GENERATOR PACK 防护罩生成包 +913638062 Shield Generator Pack stratagem availability has ended. 现已无法使用“防护罩生成包”战略配备。 +4198351113 Shield Generator Relay 防护罩生成中继器 +1557897402 SHIELD GENERATOR RELAY 防护罩生成中继器 +2406613085 Shield Generator Relay stratagem availability has ended. 现已无法使用“防护罩生成中继器”战略配备。 +274492318 SHIFT DOWN 降档 +267289365 SHIFT UP 升档 +2324381091 Ship 舰船 +4005927254 SHIP 舰船 +1144600268 Ship it! 赶紧送! +132107702 SHIP LOG 舰船日志 +3640293861 SHIP MANAGEMENT 舰船管理 +655788126 SHIP MANAGEMENT 舰船管理 +2306151992 SHIP MANAGEMENT 舰船管理 +2357224115 Ship Master 舰长 +1182365708 Ship Master #NAME #NAME舰长 +4142720788 Ship Module 舰船模块 +2277672883 SHIP MODULE 舰船模块 +3980566610 SHIP MODULE 舰船模块 +2359791162 SHIP MODULE LEVEL UNLOCKED 已解锁舰船模块等级 +4177152212 SHIP MODULE UNLOCKED 舰船模块已解锁 +4256814372 SHIP MODULES 舰船模块 +202223022 SHIP NAME 舰船名称 +3897427012 SHIP PROGRESSION 舰船进度 +652874502 Ship TV 舰船电视 +2901609208 SHIRAHAMA 白滨 +1281194164 SHOCK ABSORPTION GEL 减震凝胶 +3501910474 Shock and Awe Improvement 提高震慑威力 +1407844961 SHOCK AND AWE IMPROVEMENT 提高震慑威力 +1266360816 Shoot off both arms on a Hulk and then extract while it's alive. 射下巨型者的两只手臂,在它尚存活的时候撤离。 +3152128903 Shoot the TARGETS. 射击目标。 +2953375795 SHORT 短 +164440591 SHORT 短 +3487124909 Short Magazine 短弹匣 +1621453557 SHORT MAGAZINE 短弹匣 +3385613566 Short Revolver Barrel 左轮手枪短枪管 +2296560981 SHORT REVOLVER BARREL 左轮手枪短枪管 +3313875777 Shorter Charge Time 缩短充电用时 +212917193 Shorter Cooldown 冷却用时缩短 +1325032292 Shorter Cooldown 冷却用时缩短 +2194799191 Shorter Cooldown 冷却用时缩短 +2987690624 Shorter Cooldown 冷却用时缩短 +2114069446 SHORTER COOLDOWN 冷却用时缩短 +2565062870 SHORTER COOLDOWN 冷却用时缩短 +2579776943 SHORTER COOLDOWN 冷却用时缩短 +4245841999 SHORTER COOLDOWN 冷却用时缩短 +4224695336 Shorter Cooldown Mk2 冷却用时缩短 Mk2 +2511762224 SHORTER COOLDOWN MK2 冷却用时缩短 Mk2 +1452107233 Shorter Recharge Delay 缩短充能延迟 +831483073 SHORTER RECHARGE DELAY 缩短充能延迟 +2851548532 Shorter Shot Cooldown 缩短射击冷却用时 +1228538033 SHORTER SHOT COOLDOWN 缩短射击冷却用时 +3107649755 Shotgun 霰弹枪 +4283105677 SHOTGUN 霰弹枪 +710460903 SHOTGUN 霰弹枪 +1348789176 Shotgun Show 霰弹枪表演 +1448634636 SHOTGUN SHOW 霰弹枪表演 +650739694 SHOTGUN SUMMIT 霰弹枪峰 +2224700323 Shots Fired 开火次数 +3707106438 SHOTS FIRED: 开火次数: +3276738319 Shots Hit 命中次数 +2845539153 SHOTS HIT: 命中次数: +4042984776 Should the wearer of this cape perish at the hands of Freedom's enemies, it is customary to pass the cape on to their bravest child during the funeral, inspiring the next generation to take up arms. 若这件披肩的佩戴者死于自由之敌手中,按照传统,葬礼上会将披肩传给其最勇敢的子女,激励下一代拿起武器继续战斗。 +3007825625 Shoulder (L) 左肩 +2842063344 Shoulder (R) 右肩 +3786403278 SHOULDER-MOUNTED 肩架式 +3930232458 Show PATRIOTISM. 展现爱国精神。 +2178961703 Show Details 显示详情 +4274339261 SHOW HEROES OF SUPER EARTH 显示超级地球英雄 +677567210 SHOW KEYBOARD BINDINGS 显示键位绑定 +3174686750 SHOW ORDERS 显示指令 +4052131195 SHOW PLAYER PROFILE 显示玩家个人资料 +1800791385 Shrapnel 榴霰弹 +1730845486 SHRAPNEL 榴霰弹 +2267597799 SHRAPNEL 榴霰弹 +3635343795 Shredder Tank 碎裂坦克 +599741968 SHREDDER TANK 碎裂坦克 +1683172633 Shredder Tanks 碎裂坦克 +793026793 Shrieker 尖啸虫 +2469966431 SHRIEKER 尖啸虫 +3496786382 Shrieker Nest 尖啸虫巢穴 +3608538404 SHRIEKER NEST 尖啸虫巢穴 +4073866658 SHRIEKER NEST 尖啸虫巢穴 +3209402160 Shrieker Nests 尖啸虫巢穴 +182124759 Shrieker Swarms Traverse the Skies 尖啸虫群穿过空域 +1963526343 Shriekers 尖啸虫 +669774230 Shriekers: #CURRENT / #TOTAL kills 尖啸虫:#CURRENT / #TOTAL次击杀 +3252341478 Shuttle 运输船 +1409671235 SHUTTLE 运输船 +3243447279 Shuttle aborting. +Return to extraction zone. 运输船将中止接送。 +请返回撤离区域。 +1017160350 Shuttle approaching. +Defend extraction zone. 运输船即将驶近。 +请在撤离区坚守。 +900525200 SHUTTLE ARRIVES IN T-#MINS:#SECS:#HUNDREDTHS 运输船抵达倒计时 #MINS:#SECS:#HUNDREDTHS +3330228555 SHUTTLE BAY 运输船坞 +2814058652 Shuttle Bay System 运输船坞系统 +4218405003 Shuttle Bay Terminal System 运输船坞终端系统 +467401189 SHUTTLE DEPARTING 运输船即将出发 +4246382052 Shuttle Departing In T-#MINUTES:#SECONDS:#MILLI 运输船出发倒计时 #MINUTES:#SECONDS:#MILLI +569149673 SHUTTLE DISPATCHED FROM SHIP 运输船离开飞船 +3848177901 SHUTTLE ENROUTE 运输船正在航行 +2434958540 Shuttle Inbound In T-#MINUTES:#SECONDS:#MILLI 运输船抵达倒计时 #MINUTES:#SECONDS:#MILLI +266919797 Shuttle incoming. +Defend extraction zone. 运输船接近中。 +请在撤离区坚守。 +1725190934 Shuttle landed. +Board shuttle. 运输船着陆。 +请迅速登船。 +387910293 Shuttle Landing 运输船即将着陆 +3022269814 Shuttle landing. +Clear landing zone. 运输船即将着陆。 +请肃清降落点。 +3247307197 SHUTTLE LEAVING WITH VEHICLE 运输船已带着载具离开 +3014984313 Shuttle leaving. +Board shuttle. 运输船即将驶离。 +请迅速登船。 +1868043609 SHUTTLE PATTERN 运输船涂装 +1202698051 SHUTTLE REPAIR BAYS 运输船维修坞 +3683560299 SICK CHILD'S WISH GRANTED 病童愿望成真 +2776071049 Sickle 镰刀 +2797456803 SICKLE 镰刀 +2946206347 SIDE ARM 副武器 +80576839 Sidearm draw/holster speed increased by #BONUS. 副武器拔枪/收枪速度提高#BONUS。 +1582813692 Sidearm recoil reduced by #BONUS. 副武器后坐力降低#BONUS。 +1515211992 Siege Breakers 破围先锋 +664558047 SIEGE BREAKERS 破围先锋 +1511760777 SIEGE-READY 蓄势出击 +2662394754 SIEMNOT 席姆纳特 +3469476920 Signal Left Turn 指示左转 +599283720 SIGNAL LOST 信号丢失 +411184533 Signal Right Turn 指示右转 +934573539 SIGNAL STRENGTH 信号强度 +429407252 Signal: Group Up 信号:集合 +248056682 SIGNAL: GROUP UP 信号:集合 +2589306793 Signal: Hold 信号:等待 +3562238942 SIGNAL: HOLD 信号:等待 +2804301735 Signal: Silence 信号:安静 +2671545204 SIGNAL: SILENCE 信号:安静 +593093703 Signed in as: 登录身份: +257436714 Signs Of Sentient Life Discovered On Okul VI; Safely Eradicated. 欧库VI发现感知生命体存在的迹象,现已妥善消除 +2117764786 Silencer 消音器 +3338094672 SILENCER 消音器 +1755343141 SILO A A舱 +1576177655 SILO FULLY CHARGED 舱体充能完毕 +858415206 SILO HATCH LOCKED 发射井舱门未解锁 +3527940356 SILO HATCH UNLOCKED 发射井舱门已解锁 +841369837 Silo Power Module 舱体电力模块 +470267116 Silo Status: Critically Unstable 舱体状态:极其不稳定 +727251212 Silo Status: Stable 舱体状态:稳定 +2948338180 Silo Status: Unstable 舱体状态:不稳定 +384675702 Silo Unstable. Aborting Activation. 舱体不稳定。即将停止启动。 +2822674398 Since ancient times, the yellow line has symbolized an uncrossable boundary. To don this cape is to draw that line between tyranny and liberty, between alien monstrosities and Super Earth property, and never yield the right of way. 自古以来,黄线就象征着不可逾越的边界。穿上这件披肩,意味着在暴政与解放、外星怪物与超级地球财产之间划清界线,并发誓绝不退让。 +1550630253 Since sheltering millions of loyal refugees in the Last Great War, Port Mercy has been a safe haven for any class-A citizen in need. 自终极大战中庇护数百万忠诚难民起,仁慈港便成为所有A级公民危难时的安全港湾。 +156216577 Singe 焦痕 +266451220 SINKING IN #SECONDS SECONDS 沉没倒计时:#SECONDS秒 +2210014777 SIRIUS 天狼星 +3570922568 SIRIUS II 天狼星II +2639736168 SITE FOR VENGEFUL CONTEMPLATION OF TYRANNY'S CRIMES 暴政罪行警示地 +2096738172 Sjostrom 舍斯特伦 +782903598 SKAASH 斯卡什 +3276302871 SKAR'S GARDENS 斯卡斯加登斯 +1137964607 SKAT BAY 斯卡特湾 +1380169976 SKIP 跳过 +3670495573 SKIP 跳过 +4122616254 SKIP DIALOGUE 跳过对话 +948019727 SKITTER 斯基特 +964156153 SKN 涂装 +1562436935 Skogsberg 斯科格斯贝格 +3361168857 SKULL ADMIRAL 骷髅上将 +981392219 SLAYER CITY 弑亚城 +288468253 SLIF 斯利夫 +873843443 Slightly increases weapon ergonomics to reduce drag on weapon movement. 通过小幅提升武器的人体工学性能,降低携带武器移动的阻力。 +964858956 SLOWED 减速 +798143765 SLOWER EAGLE REARM 飞鹰时间减慢 +2646332237 SLOWER EAGLE REARM 飞鹰时间减慢 +4092004871 SLOWER EXTRACTION 撤离减慢 +2077824803 SLOWER EXTRACTION 撤离减慢 +2305057086 SLOWER EXTRACTION 撤离减慢 +2714423684 SLOWER EXTRACTION 撤离减慢 +3038375954 SLOWER EXTRACTION 撤离减慢 +932838791 Slugger 重炮手 +25668848 SLUGGER 重炮手 +676547820 SLUGS 独头弹 +2173530146 SMALL 小 +2445569551 Small Plasma Bolt 小型等离子弹 +3675628564 SMALL PLASMA BOLT 小型等离子弹 +1084439566 Smelting 冶炼 +999591236 SMG 冲锋枪 +2404806899 SMG 冲锋枪 +2984165005 SMG 冲锋枪 +3021877995 SMG 冲锋枪 +3444086720 SMG-203 SMG-203 +3556256646 SMG-32 SMG-32 +658497370 SMG-37 SMG-37 +1670510815 SMG-72 SMG-72 +2563245393 SMG/FLAM-34 SMG/FLAM-34 +1499917639 Smoke 烟雾弹 +460039667 SMOKE 烟雾弹 +2299230930 SMOKE 烟雾弹 +2305793144 SMOKE 烟雾弹 +2482482071 SMOKE-ENHANCED WALKING BARRAGE 烟幕增强型游走火力网 +3740465736 Smokescreen 烟幕 +1585416923 SMOKESCREEN 烟幕 +2481293071 SNIPER RIFLE 狙击步枪 +2573941259 So easy to use even my grandma loves it 简单易用,就连我奶奶都很喜欢。 +1333514364 So long as even one Mega City stands, so does Super Earth. Illuminate Fleet Strength must be depleted before the last one falls. 只要还有一座特大城市屹立不倒,超级地球便不会沦陷。在最后一座特大城市沦陷前,必须耗尽光能者军队战力。 +2828286460 SOCIAL 社交 +2965008007 SOCIAL 社交 +2022919698 SOCIAL 社交 +1475087488 SOCORRO III 索科罗III +4128108508 Sodermark 索德马克 +87675210 SOL SYSTEM 太阳系 +1820072234 Solar Storm Edna Reclassified As Solar Hurricane Edna. 太阳风暴埃德娜被重新界定为“太阳飓风埃德娜” +1497903780 Soldier 战士 +4155803285 SOLGHAST 索尔加斯特 +734989203 Solicit Transportation 请求运输 +210509947 SOLICIT TRANSPORTATION 请求运输 +1883014216 Solicitation for Personal Info 诱导收集个人信息 +1173171100 Solid Black 纯黑 +994545747 SOLID BLACK 纯黑 +4249093861 SOLIDARITET 团结堡 +568371220 Solo Silo 单兵导弹发射井 +999321846 SOLO SILO 单兵导弹发射井 +3454569427 Solo Silo Targeting Remote 单兵导弹发射井定位遥控器 +2411907752 SOLO SILO TARGETING REMOTE 单兵导弹发射井定位遥控器 +1740922716 Some DualSense® wireless controller and DUALSHOCK®4 wireless controller features may not work as intended with Steam Input enabled, and the default layout may not work as expected. We recommend disabling Steam Input for these controller types. 启用Steam Input后 DualSense®无线控制器和DUALSHOCK®4无线控制器的部分功能可能无法正常运行,默认布局也可能无法正常运作。我们建议禁用这类控制器的Steam Input功能。 +2909808366 Some say that a mere glimpse of this cape, fluttering majestically in the breeze, is enough to spur a squad to victory. 有人说,只需一瞥此披肩在微风中飘扬的庄严模样,就足以激励整支战队披荆斩棘,迈向胜利。 +3575945766 Some soldiers report picking up strange radio interference when wearing this armor near alien artifacts. 部分士兵报告称,穿着这套盔甲接近外星古物时,会接收到奇怪的无线电干扰信号。 +2160400619 Some stratagems have limited uses per mission. 部分战略配备在一场任务中的使用次数有限。 +2812747934 Some stratagems have unlimited uses, while others do not. 部分战略配备拥有无限使用次数,而其他则是有限的。 +1382359126 Some systems may see a performance boost from using async compute while others may experience reduced performance. This setting does not affect visual quality. 使用异步计算可能会提高某些系统的性能,而其他系统的性能则可能会降低。此设置不影响视觉质量。 +1121107411 Some targets are HEAVILY ARMORED. Hit weak spots or use armor-piercing weapons! 部分目标装备了重型护甲。要攻其弱点或是使用穿甲武器! +2280386015 Something unexpected went wrong while trying to communicate with our server. Try again in a few seconds. 尝试与服务器通讯时出错,请稍后再试。 +570847599 Something went wrong while attempting to establish the connection to PlayStation™Network. Error codes: 尝试与PlayStation™Network建立连接时出现问题。错误代码: +2713129353 Something went wrong while attempting to reach PlayStation™Network. Error codes: 尝试访问PlayStation™Network时出现问题。错误代码: +61825897 Something went wrong while trying to add the currency to your account. Please contact our support team. 尝试将货币添加到账号时出错。请联系我们的支持团队。 +961857577 Something went wrong while trying to add the currency to your account. We will retry in a few seconds. 尝试将货币添加到账号时出错。我们将在几秒后重试。 +435988855 Something went wrong, invalid upgrade. 发生意外,升级无效。 +147367428 Sonesson 索内松 +4067743828 Song 之歌 +2430884717 SONGGUO CUN 松果村 +926415749 SONNTAG 松塔格 +1810526558 SORRY 对不起 +1486628187 Sort 排序 +2716080683 SOS Beacon S.O.S.求救信标 +1477555005 SOS Beacon S.O.S.求救信标 +2283448041 SOS BEACON S.O.S.求救信标 +1591988575 Soul 灵魂 +3460881878 Sound Effects Volume 音效音量 +3662203830 SOUNDBAR 回音壁 +4206657615 SOURCE PLANET 源头星球 +24503646 Sovereign 主宰 +436363760 SPACE CADET 太空军校生 +3534500369 SPACE CHIEF PRIME 太空军督 +2905139828 Space Quality 太空画质 +1752849254 Spaceship of Theseus Destroyed Piece By Piece 忒修斯太空飞船已逐渐解体 +3112086663 Spacetime Fluctuation Indicator 时空波动指示器 +665275490 Spaghettification Visualization 面条化影像 +380744916 Spam 滥发消息 +2816667559 Spattered gore marks those heroes who braved the harrowing first days of the war for Managed Democracy. 飞溅的血迹代表着那些为实现管理式民主而在早年战争中英勇奋战的英雄。 +2193864165 Spear 飞矛 +1013395843 Spear 之矛 +4200412969 SPEAR 飞矛 +1202496589 Spear Backpack 飞矛背包 +410163817 SPEAR BACKPACK 飞矛背包 +167214020 Speargun 矛枪 +2728146884 SPEARGUN 矛枪 +451523455 Specctrei 幽灵子 +134629440 SPECIAL 特殊 +751975560 SPECIAL 特殊 +275136079 SPECIAL STRATAGEM PERMIT 特殊战略配备许可证 +1894592665 SPECIAL THROWABLE 特殊投掷武器 +587996530 SPECIALIST 专家 +2093651165 SPECIALTY 特别资源 +740065728 Specifies the maximum framerate. 限定最高帧率。 +1332022394 Specimen Case 样本箱 +3578122536 SPECIMEN CASE 样本箱 +1216056391 SPECIMEN VESSEL 样本容器 +1197227568 SPECTATE NEXT 观战下一个玩家 +3894063849 SPECTATE PREVIOUS 观战上一个玩家 +393673667 Spectating: 正在观战: +1237853859 Speech Language 音频语言 +2170158080 Speech Language 音频语言 +4250262731 Speech To Text 语音转文字 +1546456299 SPEED 速度 +3862013352 Spend #COUNT more medals to unlock 再花费#COUNT枚奖章解锁 +3419560736 Spend RESEARCH POINTS in the ARMORY. 在军械库使用研究点数。 +3652364732 Spend #COUNT Credits on Eagle 在“飞鹰”上花费#COUNT货币 +1429330936 Spend #COUNT Credits on stratagems 为战略配备花费#COUNT货币 +2640642124 Spend #COUNT Credits on weapons 为武器花费#COUNT货币 +1322329952 Spend your RESEARCH POINT to ADVANCE your HELLDIVER PROGRESSION TRACK. 花费研究点数,推进绝地潜兵进度条。 +817785996 SPHERION 斯飞利昂 +1879500218 SPIKE IN SALES OF HELLDIVER TOYS ATTRIBUTED TO NEW DEPLOYMENT 近期新行动部署推动绝地潜兵玩具销量剧增 +3964760731 Spire Sterilizer 虫塔杀菌器 +2281275566 SPIRE STERILIZER 虫塔杀菌器 +1210082392 Spore Burst Hunter 孢裂追猎虫 +3295615380 SPORE BURST HUNTER 孢裂追猎虫 +777820648 Spore Burst Hunters 孢裂追猎虫 +2842755544 Spore Burst Scavenger 孢裂食腐虫 +2136621536 SPORE BURST SCAVENGER 孢裂食腐虫 +2666845429 Spore Burst Scavengers 孢裂食腐虫 +1147205144 SPORE BURST STRAIN 孢裂变种 +2115960485 Spore Burst Warrior 孢裂武斗虫 +275534196 SPORE BURST WARRIOR 孢裂武斗虫 +2410831279 Spore Burst Warriors 孢裂武斗虫 +1939105083 Spore Charger 孢子强袭虫 +689998581 SPORE CHARGER 孢子强袭虫 +939195481 Spore Chargers 孢子强袭虫 +772000433 SPORE CLOUD POCKETS 局部孢云 +989829386 Spore Lung 孢肺 +2591340960 SPORE LUNG 孢肺 +2314638779 Spore Lungs 孢肺 +3139947901 SPORE SPEWER 孢子喷涌虫 +3544433562 Spot Available 可用点位 +2047661864 SPOYLE 斯珀伊尔 +3606740236 SPREAD 散射 +3893145155 SPREAD 散射 +338132755 SPREAD DEMOCRACY 传播民主 +1745697805 SPREAD DEMOCRACY 传播民主 +3319315263 SPREAD DEMOCRACY 传播民主 +3882332237 SPREAD DEMOCRACY 传播民主 +1956109868 Spread Managed Democracy 散播管理式民主 +4130686120 SPREADING DEMOCRACY 播撒民主 +1319560887 SPRINT 冲刺 +2109111286 SQUAD 小队 +2473476479 SQUAD IMPACT #INFLUENCE 小队影响力 #INFLUENCE +3054021438 SQUAD INVITE 小队邀请 +2423069214 Squad is full. Matchmaking aborted. 小队已满员,匹配中止。 +1813849392 SQUAD PAYOUT 小队收益 +2272224534 SQUAD RECONNECT 小队重连 +507412910 Squad Saves 小队救援次数 +3137391907 SQUADRON 中队 +438693837 SQUADS IN MISSION 正在执行任务的小队 +2528307071 Square Button 正方键 +3786196171 Squat 蹲坐 +2408336922 SQUAT 蹲坐 +446478236 Squelching mud, twisting roots; the odor of rot and anarchy. A teeming, endless morass. 地面泥泞不堪,树木盘根错节,散发着腐烂与混乱的恶臭。一片无边无际的沼泽。 +2016694799 SR-18 Roadblock SR-18“路障” +992229319 SR-18 ROADBLOCK SR-18“路障” +3708144977 SR-24 Street Scout SR-24“街头侦察兵” +973409261 SR-24 STREET SCOUT SR-24“街头侦察兵” +1512362192 SR-64 Cinderblock SR-64“煤渣砖” +1606981338 SR-64 CINDERBLOCK SR-64“煤渣砖” +481491340 SS LIBERTY 星舰解放号 +2841817963 SSA Radar has identified a fleet of Illuminate invasion ships descending upon this sector from the close orbit. They intend to seize control of the area in an aerial blitz. + +You are the last line of defense. Destroy all enemy ships as quickly as possible. SSA雷达侦测到光能者入侵舰队正从近地轨道登陆该分区,企图通过空中闪电战夺取区域控制权。 + +你是最后一道防线。迅速摧毁所有敌舰。 +3370714613 SSE 东南偏南 +3031381676 SSE (#COUNT°) 东南偏南#COUNT° +2164341014 SSSD 超级固态硬盘 +3463544321 SSSD Delivery 运送超级固态硬盘 +1683937559 SSSD DELIVERY 运送超级固态硬盘 +714952129 SSSD Hard Drive 超级固态硬盘 +2029045988 SSSD HARD DRIVE 超级固态硬盘 +646126172 SSW 西南偏南 +2252152107 SSW (#COUNT°) 西南偏南#COUNT° +2402483643 ST-1 ST-1 +372178714 ST-1 Stinger stratagem availability has ended. 现已无法使用“ST-1毒刺”战略配备。 +739698093 StA-11 StA-11 +2020578531 StA-52 StA-52 +2080117504 StA-X3 StA-X3 +2909063579 Stable 稳定 +2980267130 STACY 斯特西 +2387277009 Stalker 追踪虫 +129667267 STALKER 追踪虫 +3672690944 STALKER LAIR 追踪虫巢穴 +1328010974 Stalkers 追踪虫 +1495807816 Stalking is illegal 跟踪违法 +4081554920 Stallion 神驹 +225756131 Stalwart 盟友 +2839507768 STALWART 轻机枪 +4124031159 STALWART 盟友 +123425058 STAMINA BOOST 耐力提升 +4226720897 STAMINA DRAIN 耐力消耗 +2676755704 Stamina Enhancement 耐力强化 +936048090 STAMINA ENHANCEMENT 耐力强化 +284920123 STAMINA REGEN 耐力恢复 +3805485153 Stamina Visibility 耐力槽可视度 +3284860939 Stamina Width 耐力槽宽度 +534797284 Stand by for further orders from Super Earth High Command 等待超级地球最高指挥部的进一步指令 +1913949765 Stand clear of parts being raised 离开正在抬升的部件 +3103569246 STANDARD 标准 +3359063774 Standard Barrel 标准枪管 +1221303241 STANDARD BARREL 标准枪管 +1012577819 Standard Drum 标准弹鼓 +2367164855 STANDARD DRUM 标准弹鼓 +21450105 STANDARD EXOSUIT PATTERN 标准外骨骼装甲涂装 +2740898511 Standard Heatsink 标准散热器 +3681591456 STANDARD HEATSINK 标准散热器 +3946592432 STANDARD HELLPOD PATTERN 标准绝地喷射舱涂装 +1555196278 STANDARD ISSUE 标准制式 +640655993 Standard of Safe Distance 安全距离标准 +2830585278 STANDARD OF SAFE DISTANCE 安全距离标准 +1047373621 Standard plasma bolt 标准等离子弹 +1916050994 Standard Plasma Container 标准等离子弹药匣 +2948490704 STANDARD PLASMA CONTAINER 标准等离子弹药匣 +3831536216 Standard Prism 标准棱镜 +1628682067 STANDARD PRISM 标准棱镜 +457281052 STANDARD SHUTTLE PATTERN 标准运输船涂装 +3593288476 STANDARD TANK PATTERN 标准坦克涂装 +3478081446 STANDARD THROWABLE 标配投掷武器 +1889131823 STANDARD VEHICLE PATTERN 标准载具涂装 +1212835062 STANDARD WARBOND 标准战争债券 +76991841 Standby 随时待命 +684129410 STANDBY 随时待命 +2503642914 Star 之星 +2534283905 STAR KIELD 星陨堡 +3016462333 STAR MARSHAL 星级元帅 +3778758163 StarfQtr_97 星战之_97 +213050795 STARPASS 星通市 +3145320394 STARS AND SUFFRAGE 群星与选举 +2964567034 Start a quick play session 开始一场快速进攻 +2771110748 Start a quick play session with friends only 仅与好友组队参与一场快速进攻 +768540070 START FUEL PUMPS 启动燃料泵 +1660724659 START MISSION 开始任务 +986079424 Start Searching 开始搜索 +4258562522 START UP 出发 +2336243886 START UPLOAD AT TRANSMISSION STATION 在传输站开始上传 +2318467471 Station active 站点已启动 +3255152215 STATION INOPERABLE 站点无法运转 +4290448000 Station inoperable at current time 站点目前无法运转 +1505203428 Station moves in: 空间站即将移动: +2623638484 STATIONARY RELOAD 固定填弹 +4140404007 Stats 数据 +854091980 STATS 数据 +3807102993 STATS 数据 +3595694412 STATS 数据 +2094576477 STATS SCREEN 数据界面 +1923650587 STATUE 雕像 +2285096076 Stave Off 拖延 +4078744051 STAY 原地待命 +90534478 Stealing Resources 偷取资源 +459768309 Steam account not allowed to login. Please contact Community managers Steam账号禁止登录。请联系社区管理员 +121644859 Steam AppId supplied is invalid or not allowed 提供的Steam AppId无效或遭到禁止 +3989767731 STEAM DECK™ STEAM DECK™ +3340856362 STEAM FRIENDS STEAM好友 +3807359689 Steam Login denied by the remote party 远端拒绝登录Steam +2755862014 STEAM NOT DETECTED 未检测到STEAM +3769648768 Steel Fist 钢拳 +1553157530 Steel Foot 钢足 +1105991516 STEEL RESOLVE 钢铁意志城 +73287709 Steeled Veterans 铁血老兵 +2748957512 STEELED VETERANS 铁血老兵 +724779259 STEN SECTOR 斯坦分区 +1223276667 Sterilizer 灭菌器 +926933616 STERILIZER 灭菌器 +1474753867 Steward 管理者 +1582959385 STICKY 粘性 +1584801921 STILL STANDING 屹立不倒 +1325898713 STIM 治疗剂 +2107483823 Stim capacity decrease no longer in effect. 治疗剂容量减少的效果结束。 +1857535277 Stim capacity for all Helldivers decreased by #V_ONE on all planets. 所有星球上的所有绝地潜兵的治疗剂容量减少#V_ONE。 +3007670585 Stim capacity for all Helldivers decreased by #V_ONE on this planet. 在此星球上的所有绝地潜兵的治疗剂容量减少#V_ONE。 +2679897061 Stim capacity for all Helldivers increased by #V_ONE on all planets. 所有星球上的所有绝地潜兵的治疗剂容量增加#V_ONE。 +715753515 Stim capacity for all Helldivers increased by #V_ONE on this planet. 在此星球上的所有绝地潜兵的治疗剂容量增加#V_ONE。 +2284968224 Stim capacity for all Helldivers is temporarily decreased by #V_ONE. 所有绝地潜兵的治疗剂容量暂时减少#V_ONE。 +2012858935 Stim capacity for all Helldivers is temporarily increased by #V_ONE. 所有绝地潜兵的治疗剂容量暂时增加#V_ONE。 +12348112 Stim capacity increase no longer in effect. 治疗剂容量增加的效果结束。 +2913529528 Stim Pistol 治疗剂手枪 +4191647537 STIM PISTOL 治疗剂手枪 +304564667 STIMS 治疗剂 +1547141993 STIMS USED: 治疗剂使用次数: +3952269953 STIMULATIVE 治疗剂 +3924705555 Stinger 毒刺 +1881325850 STINGER 毒刺 +4160806915 Stingray 刺魟 +2399137569 STINGRAY 刺魟 +1149332144 Stingrays 刺魟 +1467403759 Stocked Hellpods 备量充足的喷射舱 +1458498559 STOCKED HELLPODS 备量充足的喷射舱 +1039991308 Stoker 司炉者 +2058817503 STOKER 司炉者 +462740898 STOLTHET 荣傲 +580912811 Stone-Wrought Perseverance 磐石毅力 +2474097758 STONE-WROUGHT PERSEVERANCE 磐石毅力 +4051101358 Stop 制止 +1707707501 STOP 暂停 +3167436133 STOP SEARCH 停止搜索 +4279615051 Stop the infestation! 制止侵袭! +2450040168 STOR THA PRIME 斯特萨主星 +459696352 STORAGE 存储 +2826323141 STOUT 斯图尔特 +1491917287 STRAIN CULLING 斩草除根 +3332462352 STRAIN CULLING 斩草除根 +3671353308 STRAIN CULLING 斩草除根 +2836167700 Strange Illuminate monoliths seem to be creating fields of negative energy. We do not understand their purpose or their true nature. That is why they must be destroyed. 古怪的光能者巨石似乎创造出了负能量的域场。我们不知道巨石的目的,也不清楚其中的性质。所以只能将它们全部摧毁。 +3959584611 Strapping young lad 时空悍将 +2476504093 Stratagem 战略配备 +3876105547 Stratagem 战略配备 +1653518103 Stratagem 战略配备 +486029182 STRATAGEM 战略配备 +1687322066 STRATAGEM 战略配备 +1316641959 Stratagem Call-in time increased by #V_ONE%. 战略配备的呼叫时间增加#V_ONE%。 +3323477698 Stratagem cooldown increased by #V_ONE%. 战略配备的冷却时间增加#V_ONE%。 +1927515828 STRATAGEM ACQUIRED 已获取战略配备 +2797583739 STRATAGEM ACQUIRED 已获取战略配备 +3786833707 STRATAGEM AVAILABLE 战略配备可用 +1261799441 STRATAGEM CONSERVATION 节省战略配备 +2519708566 Stratagem Failed 战略配备失败 +3359978789 STRATAGEM HERO 战略配备英雄 +3486506679 STRATAGEM JAMMER 战略配备干扰装置 +1899611438 Stratagem Jamming Inactive 战略配备干扰程序停止 +3767077291 Stratagem Permit 战略配备许可证 +400836074 STRATAGEM PERMIT 战略配备许可证 +3766386699 STRATAGEM STATS 战略配备数据 +30763115 STRATAGEM SURPLUS 战略配备过剩 +2726585911 STRATAGEM TRAITS 战略配备特性 +742877763 Stratagem Visibility 战略配备可视度 +1430480690 STRATAGEMS 战略配备 +1489058186 STRATAGEMS 战略配备 +2634740248 STRATAGEMS 战略配备 +2813359426 STRATAGEMS 战略配备 +1715366343 STRATAGEMS 战略配备 +3007654530 STRATAGEMS 战略配备 +3462362020 STRATAGEMS USED: 战略配备使用次数: +2620623882 Streamlined for maximum velocity, this armor was inspired by long-distance couriers who prioritized the delivery of ballots over personal safety, exemplifying our patriotic bonds. Features reinforced joints to withstand the violent transitions between high-speed travel and abrupt, unplanned stops. 为追求极致速度,这套护甲采用流线型设计,其灵感源于将递送选票置于个人安全之上的长距离运送者,彰显我们的爱国纽带。其特点是对关节连接处进行了强化处理,可承受高速行驶与突发或计划外停靠之间的剧烈转换。 +4275273032 STREAMLINED LAUNCH PROCESS 简化发射流程 +1483429303 STREAMLINED REQUEST PROCESS 简化申请流程 +382253008 STRENGTH 力量市 +2553558215 Strength in Our Arms 武器之力 +2867428340 STRENGTH IN OUR ARMS 武器之力 +554663829 STRIKE 打击武器 +1267495668 Strive_to_Dive_16 使劲_俯冲_16 +4221807892 STROHMANN 斯托曼 +1384218265 STROHMANN NEWS 斯托曼新闻 +1976703928 STROHMANN NEWS 斯托曼新闻 +3648034434 STRONG 强 +3311517734 STRONGFORT 斯特朗福特 +2381157765 Stronghold 要塞 +2170663657 Stronghold Cleared 要塞成功摧毁 +2023465344 Struggling to input a code while in a distracting and/or stressful war zone? Just remember: Countless civilian lives are in your hands! 战区的环境令你难以集中注意力并且紧张焦虑,难以输入代码?此刻只需记住:无数公民的性命就掌握在你的手中! +3821064877 Student Group Carries Out Public Deletion of Undemocratic E-Books 学生团体开展公共活动,当众删除非民主电子书籍 +900097455 Study Finds Galactic Warming Due To Natural Causes 研究发现星系变暖与自然因素有关 +3807486766 Stun 眩晕弹 +53671078 STUN 眩晕弹 +3881079595 STUN 眩晕弹 +414151451 STUN 眩晕弹 +1485721627 STUN 眩晕弹 +2080585689 STUN 眩晕弹 +2770058262 Stun Baton 眩晕短棍 +1697416330 STUN BATON 眩晕短棍 +4193727853 Stun Explosion 眩晕爆炸 +1141595527 STUN EXPLOSION 眩晕爆炸 +3109890851 Stun Lance 眩晕长矛 +3900912102 STUN LANCE 眩晕长矛 +3333813002 Stun Pods 眩晕喷射舱 +3014642806 STUN PODS 眩晕喷射舱 +1156093318 Stun Rounds 眩晕弹 +1510487287 STUN ROUNDS 眩晕弹 +25284148 STUN TIME 眩晕时间 +1763361023 Stuns enemies performing melee attacks. Must recharge for #BONUS. 眩晕发动近战攻击的敌人。必须充能#BONUS。 +2274956459 Sturdier Wheels 加固轮胎 +396976080 STURDIER WHEELS 加固轮胎 +3825277513 Sturk 斯图克 +4143101273 SUB-OBJECTIVE 次要目标 +1755559725 SUBMACHINE GUN 冲锋枪 +3131923926 Submerged in eternal winter, this world's frosty peaks glimmer in the light of its too-distant star. 这颗星球处于永恒的寒冬之中。星球上冰冷的山峰隐约反射着遥不可及的恒星之光。 +3330197906 SUBMIT 提交 +1734506049 Subtitle Mode 字幕模式 +2018974922 Subtitle Size 字幕字号 +889015451 SUBTITLES 字幕 +1250959666 SUCCEEDED 成功 +2998873950 SUCCESS 成功 +1624799956 Successful Extraction 成功撤离 +3577376556 Successful Extraction 成功撤离 +271316207 Successful Extractions 成功撤离次数 +1739141267 Successful Nuclear Weapons Test 确定为死亡状态 +2185441936 Successfully complete #COUNT objectives on missions 在任务中完成#COUNT个目标 +3004775832 Successfully extract with #COUNT #EQP_PRE#EQP#EQP_POST#EXT_PRE#EXT#EXT_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI. 携带#COUNT个#EQP_PRE#EQP#EQP_POST成功撤离。#EXT_PRE#EXT#EXT_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI。 +2310572910 Successfully extract#EXT_PRE#EXT#EXT_POST#COUNT_PRE#COUNT#COUNT_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI. 成功撤离#EXT_PRE#EXT#EXT_POST#COUNT_PRE#COUNT#COUNT_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI +796195229 sudden loss of health 生命值骤减 +236643916 SUDDEN ROUTING 急转直下 +2812548386 SUDDEN SPAWNING 幼虫孵化激增 +3401809146 SUICIDE MISSION 玩命任务 +119892493 SULFURA 萨尔弗拉 +257955149 SUMMARY 总结 +1631481238 Sundstrom 森德斯特伦 +754377750 SUOMALAINEN (Unsupported) SUOMALAINEN (Unsupported) +2311231392 Super Citizen 超级公民 +131627305 SUPER CITIZEN 超级公民 +2846437244 Super Credits 超级货币 +1332726318 SUPER CREDITS 超级货币 +1527003711 SUPER CREDITS 超级货币 +2622639188 SUPER CREDITS 超级货币 +3368061165 Super Credits may be purchased from the Super Credits tab 超级货币可以在相应的标签页中购买 +2417654263 Super Destroyer Unavailable 超级驱逐舰不可用 +949098447 Super Destroyer withdraws in #MINUTES:#SECONDS 超级驱逐舰撤离倒计时 #MINUTES:#SECONDS +777106965 Super Earth 超级地球 +2172175966 Super Earth 超级地球 +2509512676 SUPER EARTH 超级地球 +791315064 SUPER EARTH 超级地球 +1441504339 SUPER EARTH 超级地球 +2948862277 SUPER EARTH 超级地球 +4139107168 SUPER EARTH 超级地球 +3859521726 SUPER EARTH CONTROL 由超级地球控制 +2281165846 Super Earth Flag 超级地球旗帜 +2378431612 SUPER EARTH FLAG 超级地球旗帜 +363103857 Super Earth has many holidays, but the most important is October 26th—Liberty Day! 在超级地球的众多节日当中,最重要的当属10月26日——解放日! +2683508963 SUPER EARTH ISSUED TOOL RACK 超级地球常规工具架 +1518758231 Super Earth Mandatory Reading 超级地球必读事项 +3723290289 Super Earth Ministry of Truth 超级地球真理部 +1868192951 Super Earth PSA 超级地球PSA +365829372 Super Earth recommends spending at least 2.4 seconds per mission enjoying the scenery. A happy Helldiver is a deadly Helldiver. 超级地球建议你每次执行任务时,至少花2.4秒欣赏景色。心情舒畅的绝地潜兵会变得更加强大。 +3732778833 Super Earth thanks you for your generous support of Managed Democracy. 超级地球感谢你对管理式民主的慷慨支援。 +2842185114 Super Earth will not liberate Recon campaign planets, but they will remain available as long as the sector is active. 超级地球不会解放侦察战役中的星球,但只要该分区坚持反抗,这些星球就仍有希望。 +3988232937 Super Earth, our home, is the center of Liberty Day Festivities. Together, all citizens can watch on television the annual Defense Parade, the Justice Executions, and of course, the Freedom Fireworks. + +On this special day, Helldivers are encouraged to visit Super Earth and watch this year's fireworks from their Super Destroyers. 超级地球,我们的家园,是解放日庆典的中心。所有公民都能在电视上观看年度阅兵、正义裁决,当然还有自由烟花秀。 + +在这特别的日子里,所有绝地潜兵都可以前往超级地球,并在自己的驱逐舰上观看今年的烟花秀。 +1372632824 Super Earth's ancient enemy, the Illuminate, have returned to menace our peaceful colonies. Our innocent colonists are being abducted, and turned into the mindless monstrosities known as the Voteless. What the Illuminate want, we do not know—but they must be stopped. 超级地球的宿敌“光能者”卷土重来,威胁到我们拓殖地的和平。无辜的拓殖地居民遭到掳掠,被转变为名叫“无票者”的无脑怪物。虽然我们不清楚光能者的意图,但必须立即阻止它们。 +931844671 Super Earth's price index is undergoing fluctuation; please review the current pricing info and re-issue your requisition. 超级地球的物价指数目前忽起忽落。请核实当前的价格信息,然后重新申购。 +661319112 SUPER GLOOM BASE ALPHA 超级“阴霾”阿尔法基地 +3998055819 SUPER GLOOM BASE BRAVO 超级“阴霾”布拉沃基地 +2143388062 SUPER HELLDIVE 超级绝地俯冲 +4068335640 SUPER PEDESTRIAN 超级步兵 +938564653 Super Person 超人 +2386983514 SUPER PERSON 超人 +739236005 SUPER PRIVATE 超级列兵 +4159604643 SUPER RARE 超稀有 +3692665358 Super Sample 超级样本 +3707441282 SUPER SAMPLE 超级样本 +3638352813 SUPER SHERIFF 超级警长 +4228009849 Super Uranium 超铀 +4141972074 SUPER URANIUM 超铀 +311608928 Super Weapon Fires in #TIME 超级武器开火倒计时:#TIME +1454971004 SuperCitizen_2 超级公民_2 +753164234 SUPERCOLONY DESTROYED 超级拓殖地毁灭 +1477759539 Superintendent 至尊 +6392759 SUPERIOR PACKING METHODOLOGY 高级装填法 +2383338337 Superior Valor 卓越勇士 +3512800577 SUPERIORIA LV 卓尊 +2523375574 SUPERIORITY 优越市 +4006750519 SUPERSAMPLING 超级采样 +1304631953 SUPERSTORE 超级商店 +828730877 SUPPLEMENTAL ADRENALINE 肾上腺素补充剂 +2067880461 SUPPLEMENTAL STEROIDS 类固醇补充剂 +142136397 SUPPLIES 物资 +3988866513 SUPPLY 补给 +1088538005 Supply Backpack stratagem availability has ended. 现已无法使用“补给背包”战略配备。 +3975000072 Supply boxes containing ammunition, with a backpack that allows the user to distribute boxes to fellow Helldivers. 装着弹药的补给箱,配有背包,可供使用者将箱子分配给其他绝地潜兵。 +3069741418 SUPPLY CHAIN CHALLENGES 补给链挑战 +3807063955 Supply FRV 补给型快速侦察载具 +3947494337 SUPPLY FRV 补给型快速侦察载具 +2260948921 Supply Pack 补给背包 +2410151153 SUPPLY PACK 补给背包 +1284189971 SUPPLY STRATAGEM PERMIT 补给型战略配备许可证 +1895980108 Supply Stratagems Used 补给战略配备使用次数 +3461799397 SUPPORT 支援 +119576005 SUPPORT WEAPON 支援武器 +3025303146 SUPPORT WEAPON 支援武器 +4035473426 SUPPORT WEAPON 支援武器 +3445341515 SUPPORT WEAPON 支援武器 +3996062870 Support Weapons can be carried in addition to your primary weapon. Call in a MACHINE GUN. 你可以同时携带主武器和支援武器。呼叫机枪吧。 +3323893382 Support weapons have long cooldown periods. Make sure to retrieve them should the wielder die. 支援武器冷却时间较长。使用者阵亡以后,务必将其取回。 +1571812265 Supported modes are: + +Open Microphone +Push-To-Talk (PTT) +Push-To-Mute (PTM) +Muted +Disabled (not recommended) +Toggle Microphone 支持以下模式: + +打开麦克风 +按键说话 +按键静音 +静音 +禁用(不推荐) +切换麦克风 +2878468283 SUPPRESS TOXIC POLLINATION 遏制毒素授粉 +1933041026 SUPPRESSED 消音 +623612841 Suppressor 消音器 +141161975 SUPPRESSOR 消音器 +781677224 Supreme Court of Super Earth Rules Amendment 超级地球最高法院规则通过修正案 +3564181953 SURGE PRODUCTION 机械产量激增 +2493471413 Surveillance suggests a Brood Commander is in this location. 监控显示,虫族指挥官正位于此处。 +2652834629 Surveying unexplained spacetime fluctuations 勘测无法解释的时空波动 +4263860899 Susnjar 舒什尼亚尔 +2589407457 SVENSKA (Unsupported) SVENSKA (Unsupported) +332181063 SVITJOD 斯维特约德 +344826227 SW 西南 +558811378 SW 西南 +3444637203 SW (#COUNT°) 西南#COUNT° +3434031175 SWAMP 沼泽 +1608848462 SWAMP IV 沼泽IV +738463181 SWAMP PLANET 湿地星球 +3750283492 SWAMP V 沼泽V +3878090408 SWAMP VI 沼泽VI +593729951 Swarm 虫群 +3902389152 SWAY 摆动 +3833272338 Sweeper 扫荡者 +4272670043 SWEEPER 扫荡者 +76819432 Swiftly secure the platinum at this site and extract before enemy reinforcements overwhelm you. 迅速夺取此地的铂金并撤离,否则敌方的增援会将你们击溃。 +3363315792 SWITCH 1 开关1 +1765705860 SWITCH 2 开关2 +3032463011 SWITCH 3 开关3 +2368120173 SWITCH 4 开关4 +2762045800 SWITCH 5 开关5 +2000621332 SWITCH AIM MODE 切换瞄准模式 +4116922102 SWITCH AIM SIDE 瞄准换边 +3528346757 Switch between predefined graphics setting configurations. 切换预定义的图像设定配置。 +3788292950 SWITCH CAMERA SIDE 视角换边 +791217094 Switch Headlight Mode 切换大灯模式 +2048957465 Switch Number 切换号码 +442933647 SWITCH SEAT (NEXT) 切换座位(下一个) +3109739838 SWITCH SEAT (PREVIOUS) 切换座位(上一个) +3463016771 Switch Weapon On Pickup 武器即捡即用 +2511016458 Sword 之剑 +1658081283 SYCAMORE GARDENS 梧桐苑 +2969884428 Synchronizing Spacetime 正在同步时空 +660002635 Syncing Server Data 正在同步服务器数据 +4268862703 SYNTHETIC SUPPLEMENTATION 合成补给 +1184433395 System Access Module 系统访问模块 +3716410937 SYSTEM BOOTING 系统正在启动 +1134842368 SYSTEM BOOTING... 系统正在启动… +2510614687 SYSTEM ERROR 系统错误 +532889341 System is loading - Please wait 系统正在加载,请稍候 +3642923213 System override successful 成功取得系统权限 +3395090182 SYSTEM PROCESSING... 系统正在处理… +169702535 SYZYGY 朔望 +3937829206 T - #SECONDS 倒计时#SECONDS +2272830189 T- 倒计时 +2647440251 T- #DAYSd:#HOURS:#MINUTES:#SECONDS 倒计时#DAYSd:#HOURS:#MINUTES:#SECONDS +2968988351 T- #HOURS:#MINUTES:#SECONDS 倒计时#HOURS:#MINUTES:#SECONDS +41071803 T- #DAYSD:#HOURSH:#MINUTESM 倒计时-#DAYS日:#HOURS时:#MINUTES分 +2148920330 T-: #MINS:#SECS:#HUNDREDTHS 倒计时:#MINS:#SECS:#HUNDREDTHS +1157079216 T-#MINUTES:#SECONDS:#MILLI 倒计时#MINUTES:#SECONDS:#MILLI +2410361446 T-#SECONDS 倒计时#SECONDS +4151724965 TAA TAA +2031304254 TAA Sharpness TAA锐度 +2470229218 TACTICAL ACTION 战术行动 +2807101694 Tactical Map Disrupted 战术地图受到干扰。 +2258550792 TACTICAL OBJECTIVE (OPTIONAL) 战术目标(可选) +2887369089 Tactical Objectives Increase 战术目标增加 +2071327434 TACTICAL VIDEO CAMERA 战术摄像机 +207489081 Tactically eliminate all obstacles standing in the way of peace. 在战术层面上彻底铲除所有阻碍和平实现的障碍。 +3481173040 Tactically eliminate all obstacles standing in the way of peace. 在战术层面上彻底铲除所有阻碍和平实现的障碍。 +3433401964 TAKE #ITEM 拿起#ITEM +2252673352 Take back this city from its illegal occupants. 夺回这座城市,驱逐非法入侵者。 +3340732873 Take back this city from its illegal occupants. 夺回这座城市,驱逐非法入侵者。 +3989096872 Take back this city from its illegal occupants. 夺回这座城市,驱逐非法入侵者。 +689761469 Take control of the planet to unmake the Void. 夺取星球的控制权,瓦解寂域。 +3657744474 TAKE DOWN OVERSHIP 击沉统御舰 +1609303434 Take down the Harvester 解决猎杀器 +284418045 Take Health Pack 获得生命包 +3018350677 TALK 对话 +1321059767 Talk to the DECK OFFICER. 与舱面事务官对话。 +3035740306 Talk to the HELLBOT. 与绝地机械兵对话。 +1220458627 Tall, gnarled trees flourish across the surface of this forested world. Sunlight filters past dangling vines, to the saturated undergrowth below. 蟠枝虬根的参天大树在这片植被茂密的地表蓬勃生长。阳光穿过垂悬的藤蔓,落入色泽饱和的林下灌丛中。 +3320328107 Talon 猛爪 +323843437 TALON 猛爪 +391138216 TALUS SECTOR 塔洛斯分区 +3835584257 TANDEM 天腾 +1785959411 TANIS SECTOR 塔尼斯分区 +1098847091 TANK 坦克 +4056137100 TANK SURGE 坦克激增 +353112388 Tap 轻按 +2181174064 TAP 轻按 +643839570 TAP 轻按 +4177347360 Target Account Profile is not found 未找到目标账号资料 +16135344 TARGET COORDINATES: 目标坐标: +4274817244 TARGET DESTINATION 目的地 +3868042496 Target Framerate 目标帧率 +2198767723 TARGET NETWORK COORDINATES 定位网络坐标 +3837575192 Target Sighted 索敌雷 +3687426286 TARGET SIGHTED 索敌雷 +2398211331 TARGETING 锁定目标 +429291484 Targeting Communication System 正在锁定通信系统 +4282447891 TARGETING DISTANCE 目标距离 +2105846750 Targeting Sensors 目标锁定传感器 +560618224 TARGETING SENSORS 目标锁定传感器 +3978949594 TARGETING SOFTWARE UPGRADE 目标瞄准软件升级 +2064715177 TARRAGON SECTOR 塔拉戈分区 +689956975 TARSH 塔尔什 +309967671 TCS ACTIVATION UNDERWAY TCS启动工作进行中 +3855853787 TCS FAILURE TCS的失败 +1437872379 TCS FAILURE: WHAT WE KNOW TCS的失败:我们掌握的信息 +138375429 TCS FULLY OPERATIONAL TCS全面运作 +3533673621 TCS INSTALLATION PROGRESS TCS建设进度 +3649530245 TCS SCIENTISTS UNDER INVESTIGATION TCS科学家正在接受调查 +3966965660 TCS SHOWS PROMISE TCS未来可期 +1304788798 TCS+ activation complete TCS+激活完成 +2503736186 TCS+ ACTIVATION TERMINAL TCS+启动终端 +1777030275 TD-220 TD-220 +1362806826 Team Killing 击杀队友 +3304537724 TEAM WEAPON 团队武器 +3408600132 TEAM WEAPON 团队武器 +3762881955 Teammate Direction Visibility 队友方位可视度 +1984285633 Teammate Status Visibility 队友状态可视度 +2605052915 Teammate Stratagem Visibility 队友战略配备可视度 +339848168 Tech Specialist 技术专家 +826937044 TECHNOLOCKIA ALLATEED 科锁洛基亚-阿拉提德 +3839817662 TECHOLOCKY 锢技坊 +236587135 Tectonic disturbances indicate the presence of an Impaler in this area. 地壳扰动显示该区域存在穿刺虫。 +3177142887 TECTONIC DRILL 地壳钻机 +818916233 TED-63 TED-63 +129905506 Temperature 温度 +3042160115 Temporarily stuns all targets within the effective radius. 可短时眩晕效果范围内的所有目标。 +2376871409 Temporary magazine increase no longer in effect. 弹匣数量临时增加的效果结束。 +1761921686 Temporary magazine reduction no longer in effect. 弹匣数量临时减少的效果结束。 +1334423676 TEMPORARY PERMIT 临时许可 +688917118 Temporary stim decrease no longer in effect. 治疗剂数量临时减少的效果结束。 +3666873906 Temporary stim increase no longer in effect. 治疗剂数量临时增加的效果结束。 +2454588206 Tenderizer 肉锤 +3399333856 TENDERIZER 肉锤 +2562325679 TENDRA 坦德拉 +1864299915 Term #TERM 任期:#TERM +3800224967 TERM #TERM 任期:#TERM +462171068 TERMADON 特尔玛登 +2291091215 TERMICIDE 2.0 RESEARCH UNDERWAY 灭虫终结剂2.0研究正在进行中 +2389229260 TERMICIDE CAUSED INCREASED REPRODUCTION 灭虫终结剂导致繁殖加速 +2232461206 Termicide effect 灭虫终结剂效果 +437355611 TERMICIDE EXTREMELY EFFECTIVE 灭虫终结剂极其有效 +673302493 TERMICIDE SCIENTISTS RECOGNIZED 灭虫终结剂科学家身份确认 +3217509125 TERMICIDE SCIENTISTS RECOGNIZED 灭虫终结剂科学家身份确认 +4234884333 Terminal 终端 +751661238 Terminal System 终端系统 +1722699279 TERMINATE ILLEGAL BROADCAST 关停非法广播 +549742559 Terminid 终结族 +4251058721 TERMINID 终结族 +1178286781 TERMINID 终结族 +4059463681 Terminid Biologist 终结族生物学家 +3671853690 TERMINID CONTROL 由终结族控制 +41194867 TERMINID CONTROL SYSTEM+ 终结族遏制体系+ +2554621228 TERMINID CONTROL SYSTEM+ 终结族遏制体系+ +3576100908 TERMINID CONTROL SYSTEM+ 终结族遏制体系+ +1486726561 Terminid Deterrance Network Ready For Implementation Following Cordon Establishment. 继封锁线后,终结族威慑网也已准备部署应用 +4215606859 Terminid Detterance Network Installation Heavily Delayed by Terminid Swarm Event. 终结族虫群活动严重阻碍终结族威慑网建设 +1017745296 Terminid Dragonroaches menace the skies of this planet. Prepare to encounter airborne enemies. 终结族的蟑龙变种威胁着这颗星球的领空。请做好应对空中敌军的准备。 +1122786168 TERMINID FRENZY 狂暴终结族 +4189958024 Terminid Hive Lords have been detected on this planet. Prepare to face massive burrowing enemies. 已在这颗星球上探测到终结族的霸王虫。请做好应对巨型钻地敌军的准备。 +2039291506 TERMINID INVASION 终结族入侵 +970590890 TERMINID INVASION +The bugs are attempting to spread to another one of our planets. We must drive them off! Report to the Galactic Map for more information. 终结族入侵 +虫族企图扩张至我们的另一颗星球。我们必须驱逐它们!通过星系地图报到,了解更多信息。 +46290093 Terminid Kills 终结族击杀数 +2115022363 TERMINID OUTBREAK 终结族暴乱 +2408405158 TERMINID OUTBREAK 终结族暴乱 +851413624 TERMINID QUARANTINE ZONE 终结族隔离区 +2393862676 TERMINID QUARANTINE ZONE 终结族隔离区 +1561068448 TERMINID RESEARCH PRESERVE 终结族研究保护区 +702892206 TERMINID SURGE +Ministry of Science reports an unanticipated spike in Terminid spore counts. Expect a severe increase in resistance on Terminid planets. 终结族势力激增 +科学部通报,终结族孢子数量意外激增,预计各终结族星球的反抗力度将大幅加剧。 +1202503064 Terminid Swarming in Unprecedented Numbers, Defying Expert Explanations. 终结族数量增速前所未见,专家理论纷纷破产 +1152525653 Terminids 终结族 +3973182985 TERMINIDS 终结族 +1914367317 Terminids are held safely within massive compounds on this planet for study and E-710 extraction. 此星球上设有安全管控的大型终结族保护区,专门用于研究终结族并提取710元素。 +1275834881 Terminids in this area are multiplying exponentially. Left unchecked, this infestation will soon grow out of hand. + +Destroy their hives and kill as many bugs as you can. 该地区的终结族正以指数级增长。如不加以管控,虫害很快就会到了一发不可收拾的地步。 + +摧毁它们的虫窝,竭力消灭这些虫族。 +2328705886 Terminids in this region threaten Freedom in a variety of ways, each more despicable than the last. They must be stopped. 该地区的终结族不择手段地威胁着我们的自由,使出的手段越发卑鄙。我们必须阻止它们。 +4152509598 TERMINIDS OUT OF CONTROL 终结族失控 +4207523721 Terminids Threaten To Break Free of Cordon. 终结族威胁或突破封锁线 +209945840 Terrain features like water and foliage will slow the Helldiver down. 积水覆盖和满地枝叶等地形状况会拖慢绝地潜兵的前进速度。 +2094484599 Terrain Quality 地形质量 +1968906060 Terrain Scan will reveal nearby locations 地形扫描可显示附近的地点 +775857686 TERREK 泰雷克 +2868446843 TERRENE 类地 +2151512108 Territory #COUNT 领地#COUNT +2415134279 TERRITORY CLAIMED 领地已收复 +4049901344 Tesla Tower 特斯拉塔 +2489495420 TESLA TOWER 特斯拉塔 +2749628958 Tesla Tower stratagem availability has ended. 现已无法使用“特斯拉塔”战略配备。 +4205365705 Test account not allowed to login. Please contact Community managers 测试账号禁止登录。请联系社区管理员 +2698360086 TEST OF CONVICTION 信念试炼 +3168547122 Test w/ Above Settings 测试上述设置 +4068334059 Testament to Attrition 百战不殆的明证 +432406798 TESTAMENT TO ATTRITION 百战不殆的明证 +4083736579 Tests and implements the most advanced stratagem technology that funding has been allocated for. 测试与应用受拨款支持的顶尖战略配备技术。 +1546330539 Text Chat 文字聊天 +4054156595 Text Language 文本语言 +3956559543 Text To Speech 文字转语音 +2289611988 Text To Speech Voice 文字转语音的声音 +3677253621 Text To Speech Volume 文字转语音的音量 +1428312421 Texture Quality 贴图质量 +3893766986 TG-122 Demo-Trooper TG-122“爆破兵” +3684112822 TG-122 DEMO-TROOPER TG-122“爆破兵” +165114243 TG-8 Sharpshooter TG-8“神枪手” +571376114 TG-8 SHARPSHOOTER TG-8“神枪手” +3337628772 THANK YOU FOR REPORTING! 感谢你的举报! +4035486382 Thank you for your cooperation 感谢您的配合 +690489551 Thank you for your patience 感谢您耐心等待 +759173569 Thank you for your patience 感谢您耐心等待 +2116361915 Thank you for your patience 感谢您耐心等待 +3687086493 Thank you for your patience 感谢您耐心等待 +4254765959 Thank you for your service 感谢你的付出 +3283821912 THANKS 谢谢 +2817236126 That which does not kill you... 但凡杀不死你的… +4026104845 the the +2151089975 The #V_ONE stratagem is available to all Helldivers. #V_ONE战略配备可供所有绝地潜兵使用。 +2051691805 The #V_ONE stratagem is unavailable to all Helldivers. 所有绝地潜兵都不能使用#V_ONE战略配备。 +4145734300 The EXO-45 PATRIOT EXOSUIT is ready for use. Helldivers are advised to familiarize themselves with its features—ideally during live combat situations—as quickly as possible. EXO-45“爱国者”外骨骼装甲已经准备就绪。建议绝地潜兵尽快熟悉装甲的功能特性(最好是在实战环境中)。 +3787865575 The Orbital 120mm HE Barrage is experimentally modified with additional HE rounds, EMS rounds, and a tighter radius. 轨道120mm高爆弹火力网经实验性调整,增加了额外高爆弹与电磁电磁冲击弹,并缩小了效果范围半径。 +1203572315 The Orbital Gatling Barrage is experimentally modified to use incendiary rounds instead of HE rounds. 轨道加特林火力网经实验性调整,改用燃烧弹替代高爆弹。 +3387915863 The Orbital Walking Barrage is experimentally modified to have smoke rounds mixed into its salvos. 轨道游走火力网经实验性调整,在齐射弹中混入了烟幕弹。 +1028349052 The 11th in the "Loyalty" series, this sign is a return to form after the extravagance of version 10. “忠诚”系列的第11版标牌。相比华丽的第10版,这一版标牌可谓返璞归真。 +597619832 The AC-8 Autocannon stratagem is temporarily available to all Helldivers. “AC-8机炮”战略配备可暂时供所有绝地潜兵使用。 +2668736157 The AC-8 Autocannon stratagem is temporarily available to all Helldivers. “AC-8机炮”战略配备可暂时供所有绝地潜兵使用。 +2965983111 The account has a session token for PlayStation™Network but it's not authenticated 该账号在PlayStation™Network上有一个会话令牌,但未经验证 +3960339541 The account has a Steam session token but it's not authenticated 账号拥有Steam会话令牌,但是该令牌尚未验证 +3950633724 The account link failed, please try again. 账户绑定失败,请重试 +754185377 The Advanced Liberation Tools Research Agency (ALTRA) has completed final approval of a new combat asset: the EXO-45 PATRIOT EXOSUIT. Models are anticipated to be available for requisition within a week. 先进解放工具研究局(ALTRA)开发的新型作战装备:EXO-45“爱国者”外骨骼装甲已通过最终审核,样机将在一周内开放申购。 +1537596860 The Advanced Liberation Tools Research Agency (ALTRA) has tested successful prototypes of a new combat asset. Helldivers are advised to review proper mechanical operation procedures in preparation for the incoming asset. 先进解放工具研究局(ALTRA)开发的新型作战装备样机顺利通过测试。建议绝地潜兵提前复习正确的机械操作步骤,准备将来使用该装备。 +2917097801 The alloy in these long-range rifles includes metals from the dead planet Chara, overrun in the First Galactic War. + +Produced by ST Construction. 在用于制造这些远程步枪的合金中,有部分金属来自第一次星系战争中被敌军攻陷的死寂星球常陈四。 + +由ST建筑公司生产。 +952750931 The amount of stablization applied to the aim cursor in order to compensate for small unintentional movements. 用以抵消瞄准光标小幅意外移动的稳定量。 +3431988577 The antenna responsible for the local Automaton Transmission Stream is thought to be located here. 据悉,机器人的本地数据传输天线应该就在这里。 +666928538 The Anti-Personnel Mine Deployer stratagem is temporarily available to all Helldivers. “反步兵地雷部署器”战略配备可暂时供所有绝地潜兵使用。 +2350849714 The Anti-Personnel Mine Deployer stratagem is temporarily available to all Helldivers. “反步兵地雷部署器”战略配备可暂时供所有绝地潜兵使用。 +75445877 The ARC-3 Arc Thrower stratagem is temporarily available to all Helldivers. “ARC-3电弧发射器”战略配备可暂时供所有绝地潜兵使用。 +336774918 The arid, rocky biome covering this world has driven the evolution of exceptionally efficient water usage in its various organisms. 这颗星球遍布由岩石构成的干燥生物群落,其中各式各样的有机体经过进化,对水分的利用效率已十分惊人。 +2064126481 The AT-48 Recoilless Rifle stratagem is temporarily available to all Helldivers. “AT-48无后坐力步枪”战略配备可暂时供所有绝地潜兵使用。 +2569598906 The AT-48 Recoilless Rifle stratagem is temporarily available to all Helldivers. “AT-48无后坐力步枪”战略配备可暂时供所有绝地潜兵使用。 +1581728388 The Autocannon Sentry stratagem is temporarily available to all Helldivers. “自动哨戒炮”战略配备可暂时供所有绝地潜兵使用。 +3029166506 The Autocannon Sentry stratagem is temporarily available to all Helldivers. “自动哨戒炮”战略配备可暂时供所有绝地潜兵使用。 +1174286117 The Automaton Legion relies on its strict hierarchical structure; remove the leaders, and the ranks will fall easily. + +We believe there are Devastators present in the region. Find them, and destroy them. 机器人军团依赖于严格的层级结构。清除领袖,它们的军队就会土崩瓦解。 + +据悉,该地区存在蹂躏者。找到它们并将其摧毁。 +2316288590 The Automaton offensive has taken this area, leaving one of our top secret research stations surrounded by the enemy. + +Use your clearance to unlock the emergency bunker doors, and defend the facility staff as they transfer to the evacuation shuttle. 机器人的部队已经占领了这个地区,我们的绝密研究站被敌人包围。 + +使用你的权限打开紧急掩体的门,将该设施中的人员转移到疏散运输船,并在这个过程中保卫他们的安全。 +3282349580 THE AUTOMATONS 机器人 +1477149023 The Automatons are conducting mineral surveys to identify rich ore veins to recklessly exploit. It is critical that we secure those sites first, so that this planet's resources are used responsibly. + +Expropriate the coordinates of this region's prospective sites from the Automatons, and extract site samples to assess their potential. 机器人正在开展矿物勘探,寻找能够供它们肆意开采的富矿脉。我们必须抢先占领这些地点,确保该星球的资源得到合理利用。 + +从机器人手中没收该地区勘探点的坐标,并提取现场样本,评估开采潜力。 +1882925335 The Automatons are deploying an abnormal amount of War Striders and Tanks to this planet. Prepare to encounter high numbers of heavily armored enemies 机器人正在向该星球部署异常数量的战争纵步者与坦克。请做好应对大量重甲敌军的准备 +2324693644 The Automatons are equipped with hyper reactive protocols, making them susceptible to suppressive fire. The more you shoot at them, the less accurate they'll be. 机器人配备过度反应协议,因此,火力压制对付它们格外有效。你击中它们的次数越多,它们还击的命中率越低。 +322244446 The Automatons are stealing the minerals of this planet from our citizens at this quarry. Take it back. 机器人正在这座采石场内从我们公民的手中窃取这颗星球的矿物。将资源夺回来。 +4094579242 The Automatons are synthesizing some kind of nutrient-dense plasma from organic material. Undeniable intel shows 100% of this organic material came from loyal citizens with high potential and excellent facial symmetry. The purpose of this plasma is yet unknown, but its production is extremely costly. + +Disrupt the plasma production and secure samples of the liquid for further analysis. 机器人正在用有机物质合成某种富含营养的等离子。有确凿情报显示,这些有机物质100%来自潜力巨大而且面部完美对称的忠诚公民。这种等离子用途尚不明确,但其生产成本极其高昂。 + +破坏等离子的生产过程,获取液体样本供进一步分析。 +799787116 The Automatons are synthesizing some kind of nutrient-dense plasma from organic material. Undeniable intel shows 100% of this organic material came from loyal citizens with high potential and excellent facial symmetry. The purpose of this plasma is yet unknown, but its production is extremely costly. + +Due to enemy anti-air, this mission must be extremely rapid. Destroy the Bio-Processors that fuel plasma synthesis, then extract. 机器人正在用有机物质合成某种富含营养的等离子。有确凿情报显示,这些有机物质100%来自潜力巨大而且面部完美对称的忠诚公民。这种等离子的具体用途尚未明确,但其生产成本极其高昂。 + +因敌方出动防空火力,此次任务的行动必须极其迅速。摧毁为合成等离子提供动力的生物处理器,然后撤离。 +2684746728 The Automatons are using augmented cannons with high-orbit reach to bombard our Super Destroyers. + +We cannot allow our aerospace superiority to be challenged. Deploy to the area and destroy any active Counter-Orbital Cannons. 机器人正在使用具有高轨道射程的增强型加农炮轰击我方的超级驱逐舰。 + +我方的空天优势不容挑战。部署到该区域,摧毁所有还在运行的反轨道加农炮。 +130689954 The Automatons have a mortar emplacement in the area. They will fire on anyone that moves in the vicinity. 机器人在该区域设有迫击炮台,会向范围内任何移动目标开火。 +161452983 The Automatons have captured a SEAF research station, slaughtering the brave scientific staff. + +Get to the station, download the research database, and upload it to the Super Earth mainframe using the nearby Satellite Uplink Station. 机器人占领了一座超级地球武装部队研究站,正在残杀勇敢的科研人员。 + +前往该研究站,下载研究数据库,然后使用附近的卫星上行链路站点将其上传至超级地球主机。 +1345231973 The Automatons have constructed an air base where our citizens' homes once stood, allowing them to dominate the city's airspace. + +Breach the base and raze it to the ground. Don't leave a single Dropship standing. 机器人在公民家园的废墟上建造起了空军基地,借此掌控了城市的制空权。 + +突入基地,将它夷为平地。运输舰一艘都不要留。 +796165462 The Automatons have deployed a series of specialized models on this planet. Prepare to face bots upgraded with stolen Jump Pack technology. 机器人在这颗星球上部署了一系列特殊型号。请做好应对利用失窃的喷射背包技术升级优化的机器人。 +219493118 The Automatons have deployed high numbers of Devastators to this planet. Prepare to encounter heavily armored enemies. 机器人已向该星球部署了大量蹂躏者。请做好应对重甲敌军的准备。 +4040542804 The Automatons have established footholds on many Super Earth planets. Citizens have lost their homes, and now significant resources must be expended to regain the lost territory. 机器人在许多属于超级地球的星球上建立了据点。无数公民因此流离失所。现在我们不得不耗费大量资源才能收复失地。 +1898283179 The Automatons have gained ground in this city, constructing a network of Fabricators which allow them to replicate extremely rapidly. + +Their locations have been identified. We must strike now before they self-replicate out of control. 机器人在这座城市中夺得了一席之地,建立起构筑者网络,大幅提高了增殖速度。 + +它们的位置已确定。我们必须立即行动,防止敌人失控地自我增殖。 +2547152065 The Automatons have gained ground in this region, constructing a vast network of Fabricators which allow them to replicate extremely rapidly. + +We have detected a narrow window of maintenance, giving us a chance to strike at their facilities. Destroy all that you can. 机器人在该地区内夺得了一席之地。它们建立起庞大的构筑者网络,大幅提高了增殖速度。 + +我们侦测发现短暂的维护窗口期,这是发动突袭的宝贵时机。尽可能摧毁一切。 +4069339786 The Automatons have heavily industrialized this region and are producing a nonstop supply of fresh troops. + +Destroy their infrastructure and kill as many bots as you can. 机器人已经在该地区实现重度工业化,同时在源源不断地为自己的军队输送新鲜血液。 + +摧毁它们的基础设施,尽可能击杀机器人。 +2347079025 The Automatons have illegally occupied and mined Malevelon Creek for too long. The time has come to take it back. 机器人非法占领和开采麦拉芬蒙河已久。是时候收复它了。 +510496601 The Automatons store large amounts of encrypted information here. 机器人将大量加密信息储存在这里。 +703225368 The Automatons use a highly-advanced keycard security system. A keycard located here will grant access to their secure containment unit. 机器人使用高度先进的钥匙卡安全系统。此处的钥匙卡可打开它们的安全收容装置。 +3443951726 The Automatons' grip on this planet has been greatly weakened. We must press the advance now, before they have a chance to bolster their forces. + +As Helldivers, you can reach their last holdouts and deal the final blow, to drive them off this planet for good. 机器人对这颗星球的掌控已经大幅减弱。我们必须立刻向前推进,不给它们喘息之机。 + +作为绝地潜兵,你们可以奔袭最后的顽固分子,给予它们致命一击,将其彻底逐出这颗星球。 +220517326 The Automatons' losses have begun to impact their ability to supply fresh units. Their resistance is crumbling. Press the assault! 机器人的落败开始影响它们补充新兵力的能力。它们的抵抗逐渐崩溃,请乘胜追击! +2845922418 The Ballistic Shield Backpack stratagem is temporarily available to all Helldivers. “防弹护盾背包”战略配备可暂时供所有绝地潜兵使用。 +3493908691 The Ballistic Shield Backpack stratagem is temporarily available to all Helldivers. “防弹护盾背包”战略配备可暂时供所有绝地潜兵使用。 +838865818 The best thing I've bought since my Combat Knife! 少有的优质产品,仅次于我上次买的格斗匕首! +1676571676 The bio-processors here are the first step in synthesis of organic plasma. They must be destroyed. 这里的生物处理器是合成有机等离子的第一步。必须将其摧毁。 +1561295478 The black box must be delivered to the interplanetary uplink site at this location, for encrypted upload to the Ministry of Defense. 必须将黑匣子转移到该位置的星际上行链路点位,以便加密上传至国防部。 +2256945266 The blinding beacon that illuminates the stars with the light of Democracy. The patriotic paradise for citizens who truly serve their Federation. And the utopian future awaiting the entire galaxy. 炫目的灯塔,以民主之光照亮宇宙群星。真正效忠联邦的爱国公民心中的乐土。为整个银河系描绘了未来乌托邦的蓝图。 +486596800 The bots are breaking down organic matter for use in some twisted, un-Democratic purpose. 机器人正在分解有机质,将其用于某种不民主的扭曲用途。 +2680163087 THE BREACH 突破 +1451716287 The breathing apparatus built into this equipment helps both soldiers and colonists thrive, even when assigned to planets with atmospheres rated "suboptimal," "extreme," and "character building." 这套装备的内置呼吸装置能帮助士兵和拓殖地居民畅快呼吸,即使被派往评级为“次优”、“恶劣”和“磨练性格”的星球也应付自如。 +729150380 The brilliant scientists of this SEAF research station were abducted following an Illuminate hostile takeover. They would have wanted their life's work to be recovered and put in the service of Super Earth. + +Access the station, download the research database, and upload it to the Super Earth mainframe. 由于光能者的入侵占领,驻守超级地球武装部队研究站的杰出科学家们惨遭绑架。他们肯定希望自己毕生的研究成果能够被妥善寻回,为建设超级地球贡献力量。 + +前往该研究站,下载研究数据库,然后上传至超级地球主机。 +1724005326 THE BUG QUARANTINE 防虫 +3590471824 The burnished blood-red plates are forged in righteous fire, like the heroes they were wrought to protect. 这闪闪发亮的血红色盔甲跟它保护过的英雄一样经受过正义之火的考验。 +3329345530 The cache of high-value assets is located here. Fortify your defenses, then initiate evacuation and defend the site until evacuation is complete. 高价值目标的隐匿之处就在这里。加强防御然后开始撤离,并保卫此处,直至撤离完成。 +233472851 THE CAPE OF STARS AND SUFFRAGE 群星与选举之披肩 +2082227149 The cape's shredded hem presages the unrelenting savagery its wielder will visit upon the nemeses of Freedom. 此披风的碎边预示着穿戴者将对自由死敌发动无情蛮攻。 +476382944 The cascade of sparks is like a patriotic celebration of triumph over this threat to Democracy. 星火流瀑,仿佛是战胜民主威胁的爱国庆祝活动。 +2756412499 The citizens are safe for now, trapped inside emergency bunkers. They must be released and escorted to the facility's shuttle bay for extraction. 困在紧急掩体里的公民们暂无危险。你必须把他们放出来,护送至该设施的运输船坞,帮助他们撤离。 +866947018 The clasps on this cape are made from melted down Automaton housings—evidence of Democracy's inevitable triumph. 披肩上的扣子是通过熔化机器人外壳制作而成的,有力证明了民主的胜利势不可挡。 +588878433 The classic Helldiver paint job. 经典绝地潜兵涂装 +4238053578 The closer you are to the edge of the map, the steeper the angle of incoming orbital bombardments. Physics! 你越接近地图边缘,轨道轰炸的角度就越高。这就是物理! +3268314306 The Combat Walker's fuel capacity is increased by 50%. 战斗步行机甲的燃料容量提升50%。 +3367142121 The cracked device displays a photo of a smiling child with a pickaxe over their shoulder. 被破解的设备上显示一张照片,上面是肩扛鹤嘴锄、露出微笑的孩子。 +2091239789 The crest on this armor's shoulder shows friendlies that safety is near, and foes that they have reached the end of the road. 盔甲肩部的徽章向友军传递安全已近在咫尺的信息,同时向敌人宣告它们已走投无路。 +377777281 The crimson glow, no doubt with nefarious intention, is now used by discerning Helldivers as a indicator of this device's explosive nature. 绯红的光芒赫然彰显着邪恶意图,但敏锐的绝地潜兵一眼就能看出这个装置属于炸弹。 +832345547 The Crusher is the Illuminate’s most depraved advancement to date in the horrific process of mind control and manipulation. They are brute enforcers of the Illuminate agenda, whatever human matter that remains is long gone. 粉碎者是光能者通过可怕的精神控制和操纵所创造出的终极堕落产物。粉碎者是推进光能者阴谋诡计的残暴爪牙,体内残存的人类痕迹早已荡然无存。 +2516822592 The current network connection has been lost. 当前网络连接已断开。 +2098422287 The CW-22 Kodiak armor was thoroughly pressure-tested by patriotic volunteers, as part of the "Test Subjects for Super-Earth" Citizen Advancement Program. 该“科迪亚克”盔甲作为“超级地球测试对象”公民进步计划的一部分,其经过了爱国志愿者全面的压力测试。 +1418066194 The Cyborgs dictate the surrounding air domain from this fortified air base. It must be decisively obliterated. + +Infiltrate the base and tear it down. Destroy any grounded Dropships in sight. 生化人凭借这座要塞化空军基地掌控着周边空域。必须将其彻底摧毁。 + +渗透基地并将其拆毁。摧毁看到的所有停靠运输舰。 +2673838474 The Cyborgs have assembled a large detachment of Automatons in this sector. They must be dismantled, before they march upon our homes and leave orphans in their wake. + +Their numbers must be thinned. Destroy as many as possible. 生化人已在该分区集结了大批机器人部队。必须将它们通通拆解,不能让它们进军我们的家园、造成无数孤儿寡母的惨况。 + +必须削减敌方兵力。尽可能消灭敌人。 +1454666953 The dauntless pioneers of the Great Expansion, facing the un-Democratic unknown, adopted the Way of the Bandolier. With the gusto of their covering fire making up for their modest accuracy, they strived to be perfectly aligned in their shared values, and ready to serve when called upon by the machine gun of civic duty. 面对尚未民主化的未知世界,大扩张时期的无畏先驱者践行弹带之道。他们用狂热的火力掩护弥补射击准度的不足,奋力追求共同价值观的完美统一,并时刻响应公民责任机枪的召唤,随时准备投身战斗。 +3402773896 The default paint job for this weapon. 该武器默认涂装。 +148778530 The Defense Wall stratagem is temporarily available to all Helldivers. “防御墙”战略配备可暂时供所有绝地潜兵使用。 +2144369469 The Defense Wall stratagem is temporarily available to all Helldivers. “防御墙”战略配备可暂时供所有绝地潜兵使用。 +3343499495 The degree to which the aim sticks to a target when passing over it. 准星经过目标时附着在目标上的程度。 +1120779106 The Democracy Space Station is a strategic tool that gives Helldivers more power in the Galactic War. 民主空间站是在星系战争中赋予绝地潜兵更大力量的战略利器。 +1276736246 The Democracy Space Station is currently unavailable. 民主空间站目前无法使用。 +4275777923 The Democracy Space Station is currently unavailable. 民主空间站目前无法使用。 +472407317 The design of the Demo-Trooper armor has been a corporate secret since ST Construction first issued it to the Charan Colonial Guard in the early days of the Galactic Federation. Now, STC has contracted with the Ministry of Defense to issue the storied armor of its fallen homeworld to the Helldivers. 自星系联邦初期,ST建筑公司首次将“爆破兵”护甲配发给常陈四拓殖卫队以来,其设计一直属于该公司的商业机密。如今,ST建筑公司已与国防部签订合同,将这套承载着传奇历史、来自其沦陷母星的护甲配发给绝地潜兵。 +4107041000 The Destroyer has left orbit 驱逐舰已离开轨道 +1202939756 The Destroyer's laser cannon will sweep over the designated area, vaporizing all targets within the effective radius. 驱逐舰的激光加农炮扫射指定区域,令效果范围内的目标全数蒸发。 +4067475808 The distinctive red, white, and green of the Intergalactic Medical Corps signal to all Helldivers that help is at hand. 看见星际医疗部队标志性的红白绿三色,所有绝地潜兵都会意识到医疗援助即将到来。 +2266806766 The downed SEAF aircraft is located here. Its black box contains crucial intel. 被击落的超级地球武装部队飞行器就位于此处。它的黑匣子内存有关键情报。 +3632158433 The DSS activates its highly experimental Atmospheric Autoclave, killing 50 km³ of Gloom Spores per minute. The reduced spore cover exposes photosensitive Terminid variants to atmospheric UV radiation. DSS启动仍在实验阶段的大气高压灭菌器,每分钟可消灭50立方千米的“阴霾”孢子。孢子层减少,使部分对光敏感的终结族亚种暴露在大气紫外线辐射下。 +1824396202 The DSS activates its Zero G Anti-Ship Missile System, targeting all large enemy spacecraft attempting to exit the planet's atmosphere. In addition, diverts excess manpower to Super Destroyer logistical support. 民主空间站启动零重力反舰导弹系统,瞄准所有试图离开星球大气层的敌方舰船。此外,将多余战力投入到超级驱逐舰的后勤支援。 +588827542 The DSS deploys Eagle Strafing Runs during missions. 民主空间站在任务中部署“飞鹰”机枪扫射。 +1198664072 The DSS fires Orbital Barrages during missions. 民主空间站在任务中发射轨道火力网。 +3294946153 The DSS fires nonstop orbital bombardments from its suite of 77 PRESIDENTIAL-Class Cannons, providing planetwide artillery support and accelerating liberation efforts. Temporarily, also increases Reinforcement Budget by +1 per squad member and augments all loadouts with FX-12 Shield Generator Relay Stratagem. 民主空间站利用其77门总统级加农炮不间断地进行轨道轰炸,为整个星球提供炮火支援,加速解放进程。同时提高增援预算,每位队员增援+1,此外利用“FX-12防护罩生成中继器”战略配备强化所有武装配置。 +4162129764 The DSS Logistics Armada supplies all Super Destroyers orbiting the planet with surplus 380mm shells. Ordnance support is also provided to SEAF operations, accelerating liberation efforts. 民主空间站后勤舰队为环绕星球的各艘超级驱逐舰提供富余的380mm爆弹。超级地球武装部队的行动也将获得军械支援,从而加速解放进程。 +2022304852 The Eagle 110mm Rocket Pods stratagem is temporarily available to all Helldivers. “‘飞鹰’110mm火箭巢”战略配备可暂时供所有绝地潜兵使用。 +2537322567 The Eagle 110mm Rocket Pods stratagem is temporarily available to all Helldivers. “‘飞鹰’110mm火箭巢”战略配备可暂时供所有绝地潜兵使用。 +990898661 The Eagle 500kg Bomb stratagem is temporarily available to all Helldivers. “‘飞鹰’500kg炸弹”战略配备可暂时供所有绝地潜兵使用。 +1740259294 The Eagle 500kg Bomb stratagem is temporarily available to all Helldivers. “‘飞鹰’500kg炸弹”战略配备可暂时供所有绝地潜兵使用。 +1495667994 The Eagle Air-to-Air Missiles stratagem is temporarily available to all Helldivers. “‘飞鹰’空对空导弹”战略配备可暂时供所有绝地潜兵使用。 +2069818539 The Eagle Air-to-Air Missiles stratagem is temporarily available to all Helldivers. “‘飞鹰’空对空导弹”战略配备可暂时供所有绝地潜兵使用。 +2986036167 The Eagle Airstrike stratagem is temporarily available to all Helldivers. “‘飞鹰’空袭”战略配备可暂时供所有绝地潜兵使用。 +3822540736 The Eagle Airstrike stratagem is temporarily available to all Helldivers. “‘飞鹰’空袭”战略配备可暂时供所有绝地潜兵使用。 +72582816 The Eagle Napalm Airstrike stratagem is temporarily available to all Helldivers. “‘飞鹰’凝固汽油弹空袭”战略配备可暂时供所有绝地潜兵使用。 +2996003713 The Eagle Napalm Airstrike stratagem is temporarily available to all Helldivers. “‘飞鹰’凝固汽油弹空袭”战略配备可暂时供所有绝地潜兵使用。 +528459454 The EAT-17 Expendable Anti-Tank stratagem is temporarily available to all Helldivers. “EAT-17消耗性反坦克武器”战略配备可暂时供所有绝地潜兵使用。 +3897481459 The EAT-17 Expendable Anti-Tank stratagem is temporarily available to all Helldivers. “EAT-17消耗性反坦克武器”战略配备可暂时供所有绝地潜兵使用。 +4145325589 The eerie calm of the exterior masks the autocratic potential energy trapped within. 平凡却怪异的外表下掩藏着束缚在内的专制能量。 +3785567689 The embroidered pattern uses aluminium from Automaton motherboards, granting the once-wretched metals a new and noble purpose. 刺绣图案采用了机器人主板上的铝材,为这些卑劣的金属赋予了更崇高的新使命。 +3264096004 The encrypted drives were abandoned at these coordinates. 加密硬盘被遗弃在这些坐标处。 +392929288 The end result of several billion Super Credits and 12 years of research into creating "the Soldier of Tomorrow." 这是为打造“明日战士”而投入数十亿超级货币并耗费12年研究得出的最终成果。 +173830828 The enemy has flooded this planet with Automaton Tanks. Expect increased encounters with heavy armor. 敌人已向该星球大量投放机器人坦克。预计将频繁遭遇重甲敌军。 +718238054 The enemy is attacking this planet. If they are not repelled in time, it will be lost. 敌人正在袭击这颗星球。如果不及时驱逐敌人,星球就会沦陷。 +2782615518 The enemy is closing in on a cache of high-value assets that have been sequestered since the First Galactic War. We cannot allow them to be captured. + +The enemy will be alerted to your position as soon as the evacuation process is initiated. Defend the site until all assets have been safely transported off-planet. 敌人正逼近一批自第一次星系战争以来一直处于封存状态的高价值目标。我们不能让其落入敌人魔爪。 + +撤离程序一旦开始,敌人就会注意到你的位置。保卫阵地,直到所有目标安全运离星球。 +2570980737 The Epitome of Super Earth 超级地球典范 +994779380 The eternal colors of Super Earth can never be tainted. Only quenched, by the blood of its enemies. 超级地球的永恒颜色绝不能被玷污。唯有沾染敌人的鲜血方可罢休。 +3410273134 The Exospire is located here. Its power core is housed in a subterranean chamber at its base. 异界尖塔矗立于此。其动力核心位于底部的地下密室中。 +1801911661 The Exospire rising from these ruins is defiling the atmospheric integrity of the planet. +It is protected by a force field that blocks access to its core chamber. Electromagnetic interference may hinder Stratagem usage. + +Breach the Exospire's defenses, and destroy its core to trigger its collapse. 这座从废墟中拔地而起的异界尖塔正在玷污星球大气的完整性。 +它受到力场的保护,通向其核心密室的路径被这一力场所封锁。电磁干扰可能会阻碍战略配备的使用。 + +突破异界尖塔的防御,通过摧毁其核心促使其坍塌。 +1662564892 The Exostorm has reached critical mass, enveloping the planet in an ominous tempest that defies atmospheric physics. 异界风暴已达到临界质量,整颗星球都被这场不祥的风暴所裹挟,彻底颠覆大气物理定律。 +196875495 The experimental weapons R&D corporation Zizer has unveiled this altered "Senator" revolver, with a longer barrel that is clinically proven to make its wielder up to 23% more secure in themselves. 实验性武器研发企业“自捷”推出改装版“参议员”左轮手枪,配备加长枪管,经临床验证可为使用者带来多达23%的自信心加成。 +1423642964 The extensive Terminid enclosures here allow scientists to study Terminid behavior, and civilians to take pictures with Brood Commanders. 大量终结族圈养在这里,方便科学家研究它们的行为,公民也可以和虫族指挥官拍照留念。 +2644461509 THE EXTRA MILE 锲而不舍 +2366202284 The extractors over this massive repository of crude oil have ceased functioning and must be re-activated. 这里储存着大量原油,但采油机已停止运转,需重新启动。 +3971198333 The facilities on this planet help the Illuminate turn citizens into Voteless. 光能者在这颗星球上利用这类设施将公民转化为无票者。 +1259927622 The FAF-14 Spear stratagem is temporarily available to all Helldivers. “FAF-14飞矛”战略配备可暂时供所有绝地潜兵使用。 +2756304220 The FAF-14 Spear stratagem is temporarily available to all Helldivers. “FAF-14飞矛”战略配备可暂时供所有绝地潜兵使用。 +2437991538 The featherlight construction belies the heavy burden this cape entails—to live the Creed of the True Citizen. 轻如鸿毛的结构掩盖了此披风的沉重意义:践行忠诚公民的信条。 +968859159 The fire rate of the autocannons is increased from 200 to 300 rounds per minute. 机炮的射速从每分钟200发提升至每分钟300发。 +1912858900 The first and most well-defended Megafactory. The nexus of Cyborg command. Its destruction will trigger the collapse of the enemy's defenses on Cyberstan. Expect extreme resistance. 最早建成、防御最坚固的超大型工厂。生化人的指挥中枢。摧毁此目标将导致敌军在生化斯坦的防线全面崩溃。预计将遭遇极端抵抗。 +3203365490 The first manned site established in Gloom-infested space, standing steadfast against all forces who would tear it down. 首个在“阴霾”侵蚀星域建立的人类驻军据点,仍然巍然屹立着抗击一切妄图将其摧毁的势力。 +173940336 The first manned site established in Gloom-infested space. 首个在“阴霾”侵蚀星域建立的人类驻军据点。 +1147063964 The flagship Maximum Security City. Impregnable to Tyranny; the future of the Federation. 最高安全级别城市中的王牌。暴政无法攻破之城,联邦的未来。 +3381496091 The FLAM-40 Flamethrower stratagem is temporarily available to all Helldivers. “FLAM-40火焰喷射器”战略配备可暂时供所有绝地潜兵使用。 +3753359961 The FLAM-40 Flamethrower stratagem is temporarily available to all Helldivers. “FLAM-40火焰喷射器”战略配备可暂时供所有绝地潜兵使用。 +3299192766 The following stratagems can now be purchased from the stratagems tab: 现可从战略配备页面购买以下战略配备: +1982258300 The former site of the AM Defense Factory Hub. AM Defense was fortuitously able to reclaim its losses through insurance; the lives that were lost, however, can never be adequately compensated for. 虎将国防工厂中心遗址。虎将国防尚有保险弥补损失,但那些逝去的生命如何弥补? +2728865019 The former site of the Center for Citizen Surveillance. The tragic loss of the facility further evidences the critical imperative of comprehensive domestic surveillance. 公民监控中心遗址设施的惨重损失进一步证明了全面监控的迫切必要性。 +1057123789 The former site of the Center of Science. Once a beacon of technology, it now lies in ruins following a violent Terminid assault. 科学中心遗址。曾经的科技灯塔,在一次终结族的猛烈进攻下沦为废墟。 +671544406 The former site of the Deep Mantle Forge Complex, stolen by the Automatons and destroyed. 深部地幔铸造复合体遗址,被机器人窃取并摧毁。 +2866294438 The former site of the Xenoentomology Center, destroyed by the Terminids. Many scientists were horrifically massacred in the unprovoked attack. 异星昆虫学研究中心遗址,被终结族摧毁。在这次无端袭击中,许多科学家遭到惨绝人寰的屠杀。 +1581316934 THE GALACTIC WAR 星系战争 +2347407351 THE GALACTIC WAR 星系战争 +3346496568 The Galactic War is a united effort. Only by working together can we ensure planets don't fall to the enemy. 星系战争是我们共同的责任。只有团结一致,才能确保我们的星球不会落入敌人手中。 +678545314 The Game Data settings allow you to control what Game Data we access and store from this device. + +You can change your settings at any time. 你可以通过游戏数据的设置控制我们从本设备访问和存储的游戏数据。 + +你可以随时更改设置。 +2708010566 The gas-operated, semiautomatic P-113 chambers the 14mm "Rapid Deliberation," the largest centerfire cartridge of any magazine-fed pistol. 这支半自动P-113型气动式手枪采用14毫米的“速决”子弹,这是弹匣式手枪中最大的中心底火子弹。 +575509922 The Gateways at Giza. Modern living with an age-old charm. Units available. 吉扎之门。古色古香的现代生活。正在出售。 +2241719727 The Gatling Sentry stratagem is temporarily available to all Helldivers. “加特林哨戒炮”战略配备可暂时供所有绝地潜兵使用。 +3527094628 The Gatling Sentry stratagem is temporarily available to all Helldivers. “加特林哨戒炮”战略配备可暂时供所有绝地潜兵使用。 +1203435533 The GL-6 Grenade Launcher stratagem is temporarily available to all Helldivers. “GL-6榴弹发射器”战略配备可暂时供所有绝地潜兵使用。 +3082330525 The GL-6 Grenade Launcher stratagem is temporarily available to all Helldivers. “GL-6榴弹发射器”战略配备可暂时供所有绝地潜兵使用。 +2158648524 The Gloom covers this planet completely, obstructing a variety of logistical operations. +Extraction times are increased by 30 seconds and Eagle Re-arm time is increased by 20%. “阴霾”已完全笼罩这颗星球,阻碍我们开展各类后勤行动。 +撤离时间延长30秒,“飞鹰”重新装弹时间延长20%。 +2969720127 The Gloom may be compounded by the Terminid scum overrunning the planet's surface. + +Wipe the region clean of all Terminid presence, including their fetid nests. 由于可憎的终结族在星球上四处肆虐,“阴霾”可能会愈发猖獗。 + +清除该区域的所有终结者,包括它们臭气熏天的巢穴。 +3569259283 The glory of Super Earth is mirrored in it's production value! 它的产品价值映照出了超级地球的荣光! +1003978479 The glow of the interior bulb is out, leaving the artful branding a pale shadow of its former vivid glory. 内部灯泡不再发光,这份精致的宣传仅剩往昔熠熠光辉余留的一丝苍白残影。 +3303496283 The golden, piercing quills symbolize the deadly and poetic Justice delivered to seditious oppositionists. Silent sanctions, delivered with unerring precision and incontestable deniability. 锐利的金色羽毛笔,象征着凭借充满诗意的致命正义严惩煽动叛乱的反对派。以精准无误和无可辩驳的手段实施无声的制裁。 +1538538866 The Great Host 大军 +2411531247 The Great Host of the Illuminate is flooding this planet. Their numbers must be thinned. 光能者大军正席卷这颗星球。必须削减敌方兵力。 +472562261 The greenhouse maintains an atmosphere nearly identical to that of Super Earth. 这间温室维持着与超级地球几乎相同的空气成分。 +3631705424 The Ground All-Terrain Extraction Rig (GATER) is located here. 地面全地形采集钻机(GATER)在这里。 +4198746132 The Ground All-Terrain Extraction Rig (GATER) is located here. 地面全地形采集钻机(GATER)在这里。 +638493401 The Guard Dog stratagem is temporarily available to all Helldivers. “护卫犬”战略配备可暂时供所有绝地潜兵使用。 +3219545753 The Guard Dog stratagem is temporarily available to all Helldivers. “护卫犬”战略配备可暂时供所有绝地潜兵使用。 +1716114649 The hard workers on this planet produce goods vital to the war effort, as well as to the prosperity of Super Earth. 此星球上的辛勤工人生产重要物资,用于支援战争以及超级地球的光明未来。 +122818609 The Heavy Machine Gun Emplacement stratagem is temporarily available to all Helldivers. “重机枪部署支架”战略配备可暂时供所有绝地潜兵使用。 +2615229268 The Heavy Machine Gun Emplacement stratagem is temporarily available to all Helldivers. “重机枪部署支架”战略配备可暂时供所有绝地潜兵使用。 +3094543434 The heavy plate used in this armor is sustainably sourced from the corpses of non-sentient Automatons, then processed by other, similarly non-sentient Automatons. 这套盔甲使用的重型装甲板是可持续地取材于无感知能力的机器人残骸,并由其他同样无感知能力的机器人加工而成。 +2445428481 The heavy rubber tunic and reflective limb guards, originally designed to save citizens from burning buildings, now enable the liberal application of the cleansing fires of Justice. 这厚重的橡胶外衣和反射隔热的肢体护具原本是用来在火场中营救公民的,如今则让穿戴者可以毫无顾忌地喷射正义的净化烈焰。 +3384196968 The Hellbomb is a tactical nuke powerful enough to destroy any perceivable target in its blast zone. For safety and budgetary reasons, it has to be armed manually once deployed. 地狱火炸弹是一种战术核武器,威力足以摧毁轰炸范围内的任何可见目标。出于安全和预算的原因,地狱火炸弹部署后必须手动启动。 +823777731 The Helldiver Skull is said to strike fear in the hearts of foes attempting to sneak up on those wearing this cape. 据说,妄图偷袭穿戴此披肩之人的敌人,都会被绝地潜兵的骷髅头图案所震慑。 +2888682480 The Helldivers must liberate this planet before time runs out. Failure will have severe consequences. 绝地潜兵必须在时间结束前解放这颗星球。如果失败,后果将不堪设想。 +3497502743 The Helldivers successfully fended off the Automaton invasion. Our citizens thank you. 绝地潜兵成功击退了机器人的入侵。无数公民对你们感激不尽。 +4279826208 The high-value intel is located here. It is locked inside a secure containment unit. 高价值情报位于此处。情报被锁在安全收容装置内。 +3165389159 THE HIVE 虫窝 +122469893 The horrors of Tyranny are manifold, their minions many, but they are naught before Democracy's twin swords: overwhelming firepower, and those trained elite who unquestioningly wield it. 暴政恐怖千变万化且爪牙众多,但对于民主的“雌雄双剑”——压制性火力以及训练有素、坚定驾驭这股力量的精英而言,一切皆不足为惧。 +3386649103 The host has left the game. 主办者已退出游戏。 +3127123521 THE ILLUMINATE 光能者 +1579975284 The Illuminate are attacking our prosperous colonies, raising strange structures and terrorizing our loyal citizens. While their aim does not seem to be planetary conquest their invasion must nevertheless be repelled before they can accomplish their mysterious, malevolent aims. 光能者正袭击我们繁荣的拓殖地,还立起了奇怪的建筑物,吓坏了我们忠诚的公民。虽然光能者的目的似乎并非侵略星球,但必须击退它们的入侵,防止其恶毒的神秘目的达成。 +684104261 The Illuminate are attempting to steal this planet from our citizens. + +We must repel them before it is too late! 光能者企图从我们的公民手中窃取这颗星球。 + +我们必须及早击退它们! +1683778021 The Illuminate are converting large numbers of Super Earth citizens into Voteless-type enemies on this planet. Prepare to face a twisted, indoctrinated horde. 光能者正在这颗星球上将大批超级地球公民转化为无票者型敌人。准备迎战这群遭到洗脑、思维扭曲的暴徒。 +3643666565 The Illuminate are deploying only their own kind to this planet, a clear indication of the operation's importance and/or xenophobic nature. Prepare to face foot soldiers, drones, and piloted mechanical constructs. 光能者部署在这颗星球上的只有同族,这抑或说明此次行动至关重要,抑或暴露出他们排外的本性。准备迎击他们的步兵、无人机以及操作型机械体。 +500598816 The Illuminate are generating Dark Energy on this planet, which they are using to move the Meridian Singularity toward Super Earth. They must be stopped at all costs. 光能者正在该星球上生成暗物质,并用此物质将默里迪恩奇点移至超级地球。必须不惜一切代价阻止它们。 +2025791024 The Illuminate are invading our loyal, prosperous, peaceful colony, seeking to turn our citizens into Voteless abominations and create strange energy fields for some unknown, un-Democratic purpose. They must be stopped. 光能者准备入侵我们忠诚、繁荣、和平的拓殖地,企图将我们的公民变为无票者那样的怪物,然后创造奇怪的能量场,以满足它们非民主的不明目的。必须阻止它们。 +4064243582 The Illuminate are moving the Meridian Singularity toward Super Earth. Anything caught in its path will be torn apart. 光能者正将默里迪恩奇点移至超级地球。任何挡在其移动轨迹上的东西都将被摧毁。 +2358017004 The Illuminate are spreading across this planet, seizing our colonies and citizens. They must be expunged. 光能者正在这颗星球上大肆扩张,掠夺我们的拓殖地和公民。必须将它们彻底清除。 +3980829391 The Illuminate have carved a totalitarian lair amid this region's tangled growth. Heretical altars and foul laboratories create unspeakable horrors that would terrorize every household in the galaxy. + +Infiltrate this twisted cradle of corruption. Expose and put an end to their depravity. 光能者在该地区茂密的丛林深处建造了一座极权主义巢穴。它们在异端祭坛和肮脏实验室里炮制出的不可名状的恐怖存在,足以令银河系的每家每户都活在恐惧之中。 + +潜入这个扭曲的腐化巢穴。揭露并终结它们的邪恶勾当。 +4070900997 The Illuminate have corrupted this planet after sequestering it within the Void. Stop this planetary degradation, and aid in the collection of data that will lead us further into the Void. 光能者将这颗星球困在寂域中,然后对其进行了彻底腐化。阻止这颗星球的进一步恶化,协助我们收集数据,为深入寂域开辟道路。 +4154677153 The Illuminate have discovered a long-sequestered cache of top-secret, highly valuable assets, frozen in cryostasis since the First Galactic War. These assets cannot be allowed to fall into the Illuminate's clutches. + +Defend the site long enough for all evacuation rockets to launch. 光能者发现了一处尘封已久的绝密贵重资产库,该库存自第一次星系战争以来就利用冷冻技术封存至今。不能让这批资产落入光能者手中。 + +坚守撤离点,直至所有撤离火箭发射完毕。 +3086413166 The Illuminate have erected more monoliths than usual on this planet. 光能者在这颗星球上立起的巨石数量超乎寻常。 +373941581 The Illuminate have fashioned crude gateways through which they warp interloping forces from afar. A poor imitation of our FTL technology. + +Many of these structures have been located in this region. Destroy as many as you can. 光能者建造简易的传送门,用于远距离传送入侵部队。这不过是对我方超光速跃迁技术的拙劣模仿。 + +该地区内已发现大量此类建筑。尽可能摧毁这些传送门。 +735021036 The Illuminate have invaded this colony, turning its citizens into Voteless hordes. They have raised uncanny, malevolent monoliths that generate some kind of exotic energy fields. We know neither their function nor their true nature—that is why we must destroy them. + +We must cast off their occupation. Deploy to the colony, tear down the invaders' structures, and raise the flag of Super Earth once more. 光能者入侵了这片拓殖地,将其中的公民变为了无票者。它们立起了邪恶的诡异巨石,想打造某种奇异的能量场。我们不知道巨石的功能,也不了解其中的性质,所以必须将它们摧毁。 + +我们必须让拓殖地摆脱敌人的占领。前往拓殖地,摧毁入侵者的建筑,再次升起超级地球的旗帜。 +3243066383 The Illuminate have invaded this region and promptly raised a blasphemous monolith as a symbol of their occupation. We must show the galaxy that even in the face of oppression, Freedom remains defiant. + +Tear down their tyrannical emblem, and raise our Flag as an unassailable beacon of Liberty. 光能者入侵了该地区,并迅速立起了一块亵渎性的巨石作为占领标志。我们必须让整个银河系都知道,纵使面对压迫,自由仍傲然不屈。 + +推倒它们暴政的象征,升起我方旗帜,犹如树立起一座坚不可摧的解放灯塔。 +2457510246 The Illuminate have laid false claim to this city, besmirching our streets with more of their despotic monoliths. + +Deploy to the city, raze the enemy's totalitarian monuments, and raise the Flag of Super Earth to restore hope to our citizens. 光能者以不义之名占领这座城市,立起更多专制的巨石,玷污我们的街道。 + +前往城市,摧毁敌人极权主义的象征,升起超级地球旗帜,重燃公民的希望。 +1319973008 The Illuminate have unleashed the next wave of their democratically voided thralls on this planet. Expect violent voter suppression tactics. 光能者在该星球上释放了新一波毫无民主理念的奴仆。请准备好迎接暴力的选民压制手段。 +707866417 The Illuminate invasion fleet, constructed in secret behind the veil of the Meridian Wormhole. It is headed for Super Earth itself. 在默里迪恩虫洞掩护下秘密建造的光能者入侵舰队。目前正向超级地球进发。 +1170260091 The Illuminate masses overwhelmed the Helldiver forces and spread unchecked to planetX. The loss of these planets mean that strategic resources to Helldivers may encounter logistic issues, please report to your Ship Master for more information. + +If the spread is not contained here, it is not an exaggeration to assume that mindless masses could be walking the streets of Super Earth within weeks. 光能者群氓势头力压绝地潜兵部队,并肆无忌惮地蔓延至X星。这些星球的沦陷可能导致战略资源的后勤供应受阻,请向您的舰长报告以获取更多信息。 + +如果不遏止这一蔓延,数周之内,无脑群氓大军可能会出现在超级地球的街道。 +3015566700 The Illuminate monoliths on this planet use Dark Fluid to affect the gravity of other celestial bodies. 该星球上的光能者巨石利用暗液体影响其他天体的引力。 +2261684477 The Illuminate's insidious schemes to subvert Managed Democracy are futile. Even in the most unfree depths of the Void, Liberty shall reign supreme over tyranny. + +Topple their monoliths and hoist the Flag of Super Earth. Let it stand as an eternal beacon of Light against the Void's fleeting darkness. 光能者企图颠覆管理式民主的阴险诡计注定徒劳无功。即使在最不自由的寂域深处,自由亦将凌驾于暴政之上。 + +推倒光能者巨石,升起超级地球的旗帜。让这面旗帜成为永恒的光明灯塔,照耀着寂域短暂的黑暗。 +2399209115 THE INCINERATION CORPS 炽灼部队 +1760171012 THE JET BRIGADE 喷气旅 +1623115737 The Jump Pack stratagem is temporarily available to all Helldivers. “喷射背包”战略配备可暂时供所有绝地潜兵使用。 +2907327826 The Jump Pack stratagem is temporarily available to all Helldivers. “喷射背包”战略配备可暂时供所有绝地潜兵使用。 +3209106735 The LAS-98 Laser Cannon stratagem is temporarily available to all Helldivers. “LAS-98激光大炮”战略配备可暂时供所有绝地潜兵使用。 +3245996303 The LAS-98 Laser Cannon stratagem is temporarily available to all Helldivers. “LAS-98激光大炮”战略配备可暂时供所有绝地潜兵使用。 +91781305 The left side of the skull should be barely visible. 请将亮度调至骷髅头左侧勉强可见的程度。 +2267936639 The lifeless grey of this planet is interrupted only by the violet flowers that grow from strange, parasitic outcroppings. 灰色是这颗星球的主色,唯有从彷如寄生一般的奇异裸露地表长出的紫罗兰色花朵能打破这股死气沉沉的格调。 +414432940 The loadout for this mission has already been selected. Any loadout changes will be applied to the next mission. 此任务使用的武装配置已经选定。对武装配置作出的更改将在下一场任务中生效。 +7350021 The long arm of Justice 法网恢恢 +2106475086 The longer a mission takes, the heavier the enemy presence gets. 任务耗时越久,敌方兵力越强。 +170919653 The M-105 Stalwart stratagem is temporarily available to all Helldivers. “M-105‘盟友’”战略配备可暂时供所有绝地潜兵使用。 +1039556110 The M-105 Stalwart stratagem is temporarily available to all Helldivers. “M-105‘盟友’”战略配备可暂时供所有绝地潜兵使用。 +518966165 The machine appears to be empty of its delicious, refreshing beverages. 售货机里清爽可口的饮料似乎已售罄。 +3533018389 The main invasion fleet of the Illuminate, from arrogant Overseers to throngs of brainwashed Super Earth civilians, are present on this planet. Exterminate on sight or else risk violent resistance, or worse, treasonous propaganda. 光能者主力入侵舰队已降临该星球,既有傲慢的监视者,也有成群结对、遭到洗脑的超级地球公民。一旦发现,立即击杀,否则将面临暴力的抵抗,甚至遭遇叛国宣传。 +1863999293 The memory of the Martian training grounds will endure, even after all the Helldivers who trained there have passed, some day in the far future. 即使在遥远的未来,所有曾在火星训练场接受训练的绝地潜兵都已逝去,关于那里的记忆也永远不会褪色。 +1867310690 The Meridian Singularity speeds up as Dark Energy accumulates 暗物质积聚,默里迪恩奇点加速移动 +3567969782 The Meridian Wormhole was created by the Illuminate and wielded to destroy entire planets and threaten Super Earth itself. Here, authorized visitors may view the destructive singularity and remind themselves why our enemies deserve total annihilation. 默里迪恩虫洞出自光能者之手,用于摧毁整颗星球,一度威胁到超级地球。在此,获准访客可观摩毁灭性奇点,提醒自己我们的敌人为何应被彻底歼灭。 +2637750421 The MG-43 Machine Gun stratagem is temporarily available to all Helldivers. “MG-43机枪”战略配备可暂时供所有绝地潜兵使用。 +3049338773 The MG-43 Machine Gun stratagem is temporarily available to all Helldivers. “MG-43机枪”战略配备可暂时供所有绝地潜兵使用。 +1443491514 The Mindless Masses continue to emerge from the Void with persistent arrogance. Continue to cull the voteless near the Void while holding planetX and planetY against the Illuminate. The more Illuminates that fall, the greater chance Super Earth scientists will be able to find a way to penetrate the Void and bring the fight to them. + +The FRV campaign has been highly effective against the mindless masses. However, Helldivers are needed to acquire precious metals to support production demands of FRVs called to the front. These resources are found by melting down the carcasses of the unfeeling Automaton units - for every Bot cut down in combat, a Helldiver is that much closer to joyriding a new FRV over the bodies of countless Illuminate. A cause worth fighting for. 无脑群氓带着傲慢不停地从寂域中涌出。在寂域周边继续剿杀无票者,同时坚守X星和Y星,抵御光能者侵略。倒下的光能者越多,超级地球的科学家们就越有可能找到穿透寂域、直捣其大本营的方法。 + +快速侦察载具在对抗无脑群氓方面卓有成效。为了支持前线的生产需求,我们需要绝地潜兵获取贵金属。通过熔毁冷血机器人部队的残骸可以获得这些资源——每砍翻一个机器人,绝地潜兵就更接近驾驶崭新快速侦察载具,体验碾压光能者尸体的快感。这是一项值得为之战斗的事业。 +2621608221 The Mindless Masses have overrun planetX. Any information that the enemy forces may have had is now irretrievable. 无脑群氓大军已经淹没X星。任何敌军可能掌握的情报现已无法追回。 +2539261245 The Ministry of Defense has announced increased production of FRV units to support a quick response on the Illuminate front. Increased munitions available to Helldivers effective immediately. 国防部宣布增加快速侦察载具的产量,以支持在光能者前线的快速响应。增拨绝地潜兵的弹药供应即刻生效。 +2169557395 The Ministry of Defense is responsible for the defense of Liberty against all enemies, human and non-human, realized and potential. 国防部负责保卫自由精神,抵御所有已知和潜在的外敌,不论是人类或是非人类。 +1022607378 The Ministry of Expansion tirelessly works to expand the reach of Freedom and secures vital resources for our society to thrive. 扩张部在不眠不休地设法扩张解放大业的势力,为我们的社会获取繁荣发展的必要资源。 +2386082671 The Ministry of Humanity maintains healthy, productive voters by managing education, healthcare, social grading, and gene management. 人道部通过教育、医疗保健、社会分级和基因管理,培育生产能力较高的健康投票人。 +3653989852 The Ministry of Prosperity ensures every colony has access to the latest beverages, extending libationary ingenuity to all Super Earth's citizens. 繁荣部保证每一个拓殖地都能享用最新的饮品,让向全体超级地球公民传播独创的饮料文化。 +4022269421 The Ministry of Prosperity manages Super Earth's economy and ensures a steady flow of resources to the most deserving. 繁荣部负责管理超级地球的经济,确保资源能够源源不断地流往最有价值的地方。 +1346729511 The Ministry of Science has launched hundreds of thousands of robotic space probes into the Gloom. The Gloom interferes with signal transmission. One is crashed in this area. + +Find the probe, and boost its signal to transmit its data past the atmospheric Gloom to the Super Destroyer. 科学部向“阴霾”发射了数十万个机器人太空探测仪。但“阴霾”会干扰信号传输。有一个探测仪在此区域坠毁。 + +找到探测仪并增强其信号,将数据穿越大气层中的“阴霾”传至超级驱逐舰。 +76002444 The Ministry of Science has relocated its best and brightest here to study the interstellar spore cloud known as The Gloom. 科学部将绝顶聪明的精英安排到这里研究名为“阴霾”的星际孢子云。 +3498260589 The Ministry of Science is responsible for continuous scientific progress, augmenting our moral superiority over our enemies with technological superiority. 科学部负责不断推动科技进步,利用技术优势增强我们压倒敌人的道德优越感。 +3595804220 The Ministry of Truth analyzes citizens' activity, speech, data, DNA, RNA, and neural topology here. 真理部在这里分析公民的活动、言论、数据、DNA、RNA和神经拓扑结构。 +1398288249 The Ministry of Truth is responsible for keeping all citizens well-informed and mentally equipped to withstand our enemies' vile propaganda. 真理部负责为所有公民提供最新动态,武装公民的头脑,抵挡敌人居心不良的宣传攻势。 +1169607363 The Ministry of Unity ensures that all of mankind is united as one by protecting us from internal threats, such as deviant behavior and expression of dangerous ideas. 团结部负责保护我们免受内部威胁,例如反常行为以及表达危险思想,继而确保所有人类团结一致。 +2333834422 The missile launch code disk was left at a base in this region. 存有导弹发射代码的磁盘遗落在该地区的一座基地里。 +3178802138 The Mortar Sentry stratagem is temporarily available to all Helldivers. “迫击哨戒炮”战略配备可暂时供所有绝地潜兵使用。 +4229317978 The Mortar Sentry stratagem is temporarily available to all Helldivers. “迫击哨戒炮”战略配备可暂时供所有绝地潜兵使用。 +1983191482 The muted colors and relaxed, high-mobility fit make this a favorite among long-distance snipers and hide-and-seek champions alike. 这套装备还采用暗沉色调与宽松灵活的版型,深受远程狙击手和潜行高手的喜爱。 +2508685465 The nearby Gloom Base's logistics fleet supports operatives on this planet, counteracting all negative effects of the Gloom. 附近“阴霾”基地的后勤舰队为这颗星球上的作战人员提供支援,希望能抵消“阴霾”带来的所有负面影响。 +1866044944 The nearby Gloom Base provides logistical support to this Hive World, mitigating some of its extreme logistical challenges. +Extraction times are increased by 30 seconds and Eagle Re-arm time is increased by 20%. 附近的“阴霾”基地为这个虫窝世界提供后勤支援,缓解了严峻的后勤压力。 +撤离时间延长30秒,“飞鹰”重新装弹时间延长20%。 +748810899 The number of frame buffers to use. Lower values yield more responsive input, while higher values yield smoother frame rates. 要使用的帧缓冲数值。数值越小,输入响应越快,数值越大,帧率越平稳。 +3628603089 The number of Voteless on this planet appears to increase more quickly than on other planets. 该星球无票者的增速似乎高于其他星球。 +3347550390 The oases that bespeckle this desert planet present the closest approximation of tranquility one can find this far from Super Earth. 在这颗沙漠星球上,只有零星点缀的绿洲能让人回想起远方的超级地球,获得片刻宁静。 +3876419466 The official uniform of the League of Patriotic Arm Wrestlers, this armor's lycra base layer is supple and sweat-wicking for maximum flexing comfort. 爱国腕力联盟的官方制服,其莱卡底层布料柔软且兼具吸湿排汗功能,可为高强度的掰手腕动作提供极致舒适性。 +2371863565 The omission of upper-limb coverings allows for optimized freedom of movement, perspiration, and communication of upper body strength to squadmates. 省去覆盖上肢的布料,自由行动的空间、排汗,以及与队友之间的上肢力量交流都将得到优化。 +67045919 The Orbital 120mm HE Strike stratagem is temporarily available to all Helldivers. “轨道120mm高爆弹攻击”战略配备可暂时供所有绝地潜兵使用。 +2337748496 The Orbital 120mm HE Strike stratagem is temporarily available to all Helldivers. “轨道120mm高爆弹攻击”战略配备可暂时供所有绝地潜兵使用。 +1430621983 The Orbital 380mm HE Barrage stratagem is temporarily available to all Helldivers. “轨道380mm高爆弹火力网”战略配备可暂时供所有绝地潜兵使用。 +3208135968 The Orbital 380mm HE Barrage stratagem is temporarily available to all Helldivers. “轨道380mm高爆弹火力网”战略配备可暂时供所有绝地潜兵使用。 +329443307 The Orbital Airburst Strike stratagem is temporarily available to all Helldivers. “轨道空爆攻击”战略配备可暂时供所有绝地潜兵使用。 +4013240943 The Orbital Airburst Strike stratagem is temporarily available to all Helldivers. “轨道空爆攻击”战略配备可暂时供所有绝地潜兵使用。 +1175505148 The Orbital EMS Strike stratagem is temporarily available to all Helldivers. “轨道电磁冲击波攻击”战略配备可暂时供所有绝地潜兵使用。 +2674681081 The Orbital EMS Strike stratagem is temporarily available to all Helldivers. “轨道电磁冲击波攻击”战略配备可暂时供所有绝地潜兵使用。 +900452567 The Orbital Gas Strike stratagem is temporarily available to all Helldivers. “轨道毒气攻击”战略配备可暂时供所有绝地潜兵使用。 +2023248821 The Orbital Gas Strike stratagem is temporarily available to all Helldivers. “轨道毒气攻击”战略配备可暂时供所有绝地潜兵使用。 +1991556873 The Orbital Gatling Barrage stratagem is temporarily available to all Helldivers. “轨道加特林火力网”战略配备可暂时供所有绝地潜兵使用。 +2879703857 The Orbital Gatling Barrage stratagem is temporarily available to all Helldivers. “轨道加特林火力网”战略配备可暂时供所有绝地潜兵使用。 +27832939 The Orbital Laser stratagem is temporarily available to all Helldivers. “轨道激光炮”战略配备可暂时供所有绝地潜兵使用。 +3453882851 The Orbital Laser stratagem is temporarily available to all Helldivers. “轨道激光炮”战略配备可暂时供所有绝地潜兵使用。 +269334634 The Orbital Precision Strike stratagem is temporarily available to all Helldivers. “轨道精准攻击”战略配备可暂时供所有绝地潜兵使用。 +3983056343 The Orbital Precision Strike stratagem is temporarily available to all Helldivers. “轨道精准攻击”战略配备可暂时供所有绝地潜兵使用。 +584424596 The Orbital Railcannon stratagem is temporarily available to all Helldivers. “轨道炮”战略配备可暂时供所有绝地潜兵使用。 +2474213151 The Orbital Railcannon stratagem is temporarily available to all Helldivers. “轨道炮”战略配备可暂时供所有绝地潜兵使用。 +1366592442 The Orbital Walking Barrage stratagem is temporarily available to all Helldivers. “轨道游走火力网”战略配备可暂时供所有绝地潜兵使用。 +1370699443 The Orbital Walking Barrage stratagem is temporarily available to all Helldivers. “轨道游走火力网”战略配备可暂时供所有绝地潜兵使用。 +3979455691 The Overship is the command-and-control nexus of Illuminate forces in this sector. Its oppressive presence must be destroyed. + +A Planetary Defense Cannon in this area can penetrate its shields. Activate the Cannon and use it to bring down the Overship. 统御舰是该分区光能者部队的指挥中枢。必须摧毁这艘暴政舰船。 + +该区域的行星防御加农炮可穿透其护盾。启动加农炮,击沉统御舰。 +550229856 The pale gleam of the lamp is sinister and alien, doubtlessly due to its un-Democratic fashioning. 这盏灯苍白的微光十分邪恶和诡异。毫无疑问,这是非民主设计方式导致的。 +2153709012 The patented fabric absorbs visible, infrared, and ultraviolet radiation, to prevent detection by all known species. 享有专利的纤维材料可吸收可见光、红外线和紫外线辐射,躲过所有已知物种的侦测。 +1913704561 The path has been cleared to the Barrier Planets. SEAF Engineers will now begin constructing the Terminid Control System. Well done, Helldivers. 前往屏障星球的路线已经打通。超级地球武装部队的工兵即将着手建设终结族遏制体系。干得好,绝地潜兵。 +4237357784 The patriotic hues are enough to stir the heart of any true patriot. 浓厚的爱国色彩足以打动每一个真正爱国者的心。 +2104428022 The pattern used for this armor is the result of the Winter Camouflage Improvement Effort, which considered 136 entrants before determining the color white would best blend in with snow. 此盔甲的图案是冬季迷彩优化工作的成果。在综合考虑136位参与者的提案后,最终决定白色与雪地的融合度最高。 +4128937436 The player has no messages in the chat so they cannot be reported. You can take any of the following actions instead. 这位玩家没有在聊天中发送消息,无法举报。你可以另行选择下列操作。 +2384738129 The player or squad you want to join has crossplay disabled. 你要加入的玩家或小队没有开启跨平台游玩。 +240084251 The power of Democracy 民主之力 +3205119654 The presence of the DSS near this planet provides a -35% cooldown reduction to all Exosuit stratagems. DSS停靠在这颗星球附近,可使所有外骨骼装甲战略配备冷却时间缩短35%。 +765324963 The presence of the DSS near this planet provides a slight boost to Liberation Campaign progress. DSS停靠在这颗星球附近一定程度上也有助于推进解放战役。 +3346853673 The presence of the Void cuts off communication with your Destroyer. 由于寂域的存在,我们无法与你的驱逐舰建立通讯。 +1549756075 The Prospecting Drill in this location can extract sediment cores, analyze their composition, and upload the generated data. 这里的勘探钻机可以提取沉积物核心,分析其成分,并上传产生的数据。 +2371709060 The prosperous Meridia was corrupted into a Terminid Supercolony, necessitating its destruction using the mysterious Dark Fluid. This galactic scar is all that remains. 曾经欣欣向荣的默里迪亚沦为终结族超级拓殖地,不得不使用神秘的暗液体将其摧毁。如今唯有这道银河系的疤痕,昭示着它曾经的存在。 +832453372 The prosperous Meridia was corrupted into a Terminid Supercolony, necessitating its destruction using the mysterious Dark Fluid. This galactic scar is all that remains. Advisory: volatile spacetime fluctuations currently prohibit FTL travel to the Meridian Black Hole. 曾经欣欣向荣的默里迪亚沦为终结族超级拓殖地,不得不使用神秘的暗液体将其摧毁。如今唯有这道银河系的疤痕,昭示着它曾经的存在。警告:时空波动不稳定,目前无法通过超光速跃迁前往默里迪恩黑洞。 +1963310271 The purchase has already been authorized by Steam, but we are currently experiencing a high volume of requests. +We haven’t been able to add the currency to your account yet, but we will continue retrying in the background. + +Thank you for your patience! +If the issue persists, please contact our support team. + +Next attempt in #TIME seconds. 购买操作已获得Steam授权,但目前存在大量请求等待处理。 +暂时无法将货币添加到账号,我们会在后台继续重试。 + +感谢您的耐心等待! +如果问题仍然存在,请联系我们的支持团队。 + +#TIME秒后将重试。 +3258667075 The pure fountain from which Managed Democracy springs forth. It must be defended at all costs. 孕育出管理式民主之花的沃土。必须不计代价保卫其存续。 +1366620121 The purpose of this machine is unknown, it is as irredeemable as its creators. 这台机器用途不明,跟它的制造者一样无药可救。 +2368800424 The quality of atmospheric lighting. Reducing this may introduce noise and ghosting but improve GPU performance. 氛围光照的质量。下调该选项或许会导致出现噪点和重像,但是可以改善GPU性能。 +377018496 The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. +23663294 The Rapid Modular Drilling Platform is located here. 快速模块化钻机平台在这里。 +3385453702 The Real Deal 动真格 +3089029877 The recon aircraft is located here. Its precious black box must be recovered. 侦察机位于此处。必须取回机上珍贵的黑匣子。 +1718818796 The relay towers on this planet are important to Automaton communications. 这颗星球上的中继塔是机器人通信的重要工具。 +41599991 THE RESOURCES OF PROGRESS 进步的资源 +2115313058 The Resupply stratagem is temporarily available to all Helldivers. “重新补给”战略配备可暂时供所有绝地潜兵使用。 +3021947593 The Resupply stratagem is temporarily available to all Helldivers. “重新补给”战略配备可暂时供所有绝地潜兵使用。 +2649909856 The robotic manipulators at the end of the arm can grasp nothing, save oppression. 在背后操控这支机械臂的那些家伙除了施加压迫以外,什么也抓不住。 +1397951729 The Rocket Sentry stratagem is temporarily available to all Helldivers. “火箭哨戒炮”战略配备可暂时供所有绝地潜兵使用。 +1910438702 The Rocket Sentry stratagem is temporarily available to all Helldivers. “火箭哨戒炮”战略配备可暂时供所有绝地潜兵使用。 +2052096401 The RS-422 Railgun stratagem is temporarily available to all Helldivers. “RS-422磁轨炮”战略配备可暂时供所有绝地潜兵使用。 +3741917828 The RS-422 Railgun stratagem is temporarily available to all Helldivers. “RS-422磁轨炮”战略配备可暂时供所有绝地潜兵使用。 +1633278767 The SAR-1 Sniper Rifle stratagem is temporarily available to all Helldivers. “SAR-1狙击步枪”战略配备可暂时供所有绝地潜兵使用。 +2479997013 The SAR-1 Sniper Rifle stratagem is temporarily available to all Helldivers. “SAR-1狙击步枪”战略配备可暂时供所有绝地潜兵使用。 +641985862 The screen is frozen on a rousing reminder of the value of strenuous labor. 画面定格在一条宣扬辛勤劳动价值的提醒上。 +2693768507 The screen is frozen on one final message: "Hold." 画面定格在最后一条消息:“坚持住。” +2946371041 The screen shows a picture of what must be a SEAF soldier's family, holding a banner saying "Defend our Freedom." 画面的照片里想必是超级地球武装部队士兵的家人,他们手举带有“捍卫自由”字样的横幅。 +2174348946 The SEAF standard assault rifle, balancing power, fire rate, and weight for a reliable weapon against smaller targets. 超级地球武装部队的制式突击步枪,火力、射速和重量各方面均较为平衡,是对付小型目标的可靠武器。 +1151116802 The SEAF standard pistol - offering a high fire rate, generous capacity, and fast reloading. 超级地球武装部队制式手枪。射速较高、弹药容量理想,装弹速度也比较快。 +1717653672 The second manned site established in Gloom-infested space. 第二个在“阴霾”侵蚀星域建立的人类驻军据点。 +16489650 The Seismic Probe in this location can be used to confirm the likely locations of sub-surface geological features. 这里的地震探测仪可以确认出现地下地质特征的可能位置。 +2840481794 The set's classic advertising campaign "Have you tried a grenade?" has remained unchanged for over 70 years. 70多年以来,本套装的广告词一直都是:“试过手雷了吗?” +410498120 The Shield Generator Pack stratagem is temporarily available to all Helldivers. “防护罩生成包”战略配备可暂时供所有绝地潜兵使用。 +1695074190 The Shield Generator Pack stratagem is temporarily available to all Helldivers. “防护罩生成包”战略配备可暂时供所有绝地潜兵使用。 +2030180306 The Shield Generator Relay stratagem is temporarily available to all Helldivers. “防护罩生成中继器”战略配备可暂时供所有绝地潜兵使用。 +2835334755 The Shield Generator Relay stratagem is temporarily available to all Helldivers. “防护罩生成中继器”战略配备可暂时供所有绝地潜兵使用。 +2126159813 The signature orange pauldron allows easy battlefield detection of the bearer, alive or dead, on ash-strewn battlefields. 橘黄色护肩非常醒目,哪怕在遍布灰烬的战场上也能让你轻易找到穿戴者,无论他们是生是死。 +1180336201 The size of the area where the right stick and left stick input is not registered. 左摇杆和右摇杆输入的区域大小无效。 +1738318242 The size of the area where the right stick and left stick input is not registered. 左操作杆和右操作杆输入的区域大小无效。 +2792856870 The smelters and refineries on this planet turn crude materials into usable hardware. 此星球上的冶炼厂和精炼厂可将原料变为实用的硬件。 +2692472091 The Source planet holds a unique and unknowable structural role in the Void space. Deal with the Source planet to return the abducted planets to where they belong and expel this Void region from the galaxy. 源头星球在寂域中扮演着独特而又难以解明的结构性作用。妥善处理源头星球,就能让遭到劫持的星球重返原位,彻底抹除这片寂域,还银河系一片清朗。 +698713821 The speed at which the cursor movement increases as the controller is moved. 光标随游戏控制器移动的加速度。 +1107085700 The speed at which the cursor movement increases as the controller is moved. 光标随游戏控制器移动的加速度。 +3265967288 The Spore Lung is located deep within this Terminid tunnel complex. 孢肺位于这个终结族地下网络通道的深处。 +1106899537 The ST-1 Stinger stratagem is temporarily available to all Helldivers. “ST-1毒刺”战略配备可暂时供所有绝地潜兵使用。 +2553646586 The ST-1 Stinger stratagem is temporarily available to all Helldivers. “ST-1毒刺”战略配备可暂时供所有绝地潜兵使用。 +2292887042 The standard heatsink for laser rifles. 激光步枪的标准散热器。 +2654556013 The standard scope for most weapons, provides a good and accurate scope picture. 适配多数武器的标准瞄准镜,提供清晰精准的瞄准视野。 +4232324917 The SteerComfort fit of this armor allows the wearer to feel every curve, bump, and jostle of their Exosuit, as if they were one single being. 这套盔甲的“舒适贴合驾控”设计能让穿着者感知外骨骼装甲的每一次弯折、颠簸与震动,仿佛人机合一。 +2987454492 The strange subversion of photosynthesis that sustains the oddly-hued flora that flourishes on this planet remains an intriguing mystery to Super Earth's greatest exo-biologists. 这颗星球颠覆性的神奇光合作用是如何让这里色调奇特的植物群维持生长?超级地球最出色的外星生物学家至今仍未解开此谜团。 +739907706 The streets of this Megafactory are riddled with terrorist emblems and Cyborg propaganda. It is your duty to redress this affront, and to bring Democracy to this oppressed place. + +Storm the Megafactory and raise the flag of Super Earth, the one true symbol of Unity. 这座超大型工厂的街道随处可见恐怖分子的标志和生化人的宣传物。你的职责是纠正这种冒犯行为,并将民主带到这片受压迫的土地。 + +突袭超大型工厂,升起超级地球的旗帜,这是唯一真正的团结象征。 +2330051607 The structures on this planet allow the Illuminate to communicate outside the galaxy. 光能者利用星球上的这种建筑与星系外的同类通讯。 +4217970983 The substance known as E-711 is the key to synthesizing Dark Fluid, an immensely powerful exotic material. Acquiring it is of utmost importance. 711元素是极其强大的异域物质,也是合成暗液体的关键成分。获取这些元素至关重要。 +372008487 The suit was once designed to hold a variety of battlefield medical equipment. Now it holds a generous supply of stims. 按照原本的设计,这套盔甲应该配备多种战地医疗设备,现在则是携带了大量的治疗剂。 +1837678100 The Super Destroyer can only stay in low orbit for a limited time—watch that mission clock! 超级驱逐舰在低空轨道上停留时间有限——注意任务时长! +3803997722 The Super Destroyer cannot remain in this area for long. + +Each Helldiver may call it back once per mission using the CALL IN SUPER DESTROYER Stratagem. 超级驱逐舰无法在此区域长时间停留。 + +每位绝地潜兵在单场任务中可使用呼叫超级驱逐舰战略配备召回驱逐舰一次。 +4048435997 The Super Store is currently undergoing maintenance, and is unavailable. Please try again later. Thank you for your understanding. 超级商店正在进行维护,暂时无法使用。请稍后再试。感谢你的理解。 +832857255 The Supply Backpack stratagem is temporarily available to all Helldivers. “补给背包”战略配备可暂时供所有绝地潜兵使用。 +1753680151 The Supply Backpack stratagem is temporarily available to all Helldivers. “补给背包”战略配备可暂时供所有绝地潜兵使用。 +1700998578 The symbol on this cape represents the pillars of freedom: duty, obedience, and loyalty. 披肩上的标志象征着自由的三大支柱:责任、服从、忠诚。 +3639189188 The synthetic marble figure communicates a message of proud freedom that crosses all boundaries of species and sapience. 这座人造大理石雕像传达以自由为傲的理念,已超越一切种族与智慧界限。 +921854660 The taller they are... 他们越高就… +3220926236 The TCS created several fissures in the planet's crust in this area. A Drill stratagem can be used to deploy Dark Fluid payloads in these locations. 这片区域内,星球的地壳因TCS而出现了一些裂缝。钻机战略配备可以用于在这些地点部署暗液体。 +3834330026 The TCS has been fully activated on half of the Barrier Planets. 半数屏障星球上的TCS已经全面启动。 +1880335159 The TCS is ready. Secure this planet from the bugs forevermore. TCS准备就绪。让这颗星球永远免受虫害。 +1157625947 The Terminid advance has swarmed across this region, leaving one of our top secret research stations surrounded by the enemy. + +Use your clearance to unlock the emergency bunker doors, and defend the facility staff as they transfer to the evacuation shuttle. 终结族的大军已经席卷了这个地区,我们的绝密研究站被敌人包围。 + +使用你的权限打开紧急掩体的门,将该设施中的人员转移到疏散运输船,并在这个过程中保卫他们的安全。 +3283335602 The Terminid Control System is complete. All across the planet, Termicide Dispersion Towers await activation. This planet won't be completely immunized from the Terminids until every single Tower is activated. 终结族遏制体系业已建成,遍布星球的灭虫终结剂喷洒塔只待启动。必须启动每一座喷洒塔才能让终结族彻底从这颗星球上消失。 +3654963471 The Terminid swarm has descended on this planet and threatens to infest it. + +We must repel this vile incursion before it is too late! 终结族虫群涌入这颗星球,企图将其占领。 + +我们必须及早挫败它们邪恶的入侵行动! +406958566 The Terminid Variant was last reported in this area. 有报告称,终结族亚种的最后目击地点就在该区域。 +4036424274 THE TERMINIDS 终结族 +691698893 The Terminids are mutating. Deactivate the TCS before it's too late. 终结族发生变异。尽快关闭TCS。 +2606323274 The Terminids have stolen highly valuable specimens of enemy larvae and eggs. Recover them. 终结族偷走了极为珍贵的敌方幼虫样本和虫卵样本。请把样本找回来。 +173821335 The Terminids have transformed this world into a bastion of Fascist oppression. But it can still be restored to Liberty's Light. + +Deploy to the Hive World and raise the Flag of Super Earth. 终结族已将这个世界改造成法西斯压迫的堡垒。但我们仍然可以让它恢复自由的荣光。 + +前往虫窝世界,升起超级地球的旗帜。 +395775944 The Terminids on this planet are mutating in response to the Termicide. With every passing minute, they threaten to turn this world into another Supercolony. + +Eradicate the mutated Terminid eggs and deactivate the corrupted Terminid Control System before its too late. 这颗星球上的终结族正在灭虫终结剂的影响下快速变异。它们随时都有可能将这个世界变成又一个超级拓殖地。 + +彻底清除变异终结族虫卵,尽快关闭出错的终结族遏制体系。 +1818520133 The Terminids on this planet have evolved to yield more E-710 than other specimens. 此星球上的终结族经过进化,能产出比其他虫族更多的710元素。 +549040800 The Terminids' grip on this planet has been weakened. We must attack now, before they have a chance to regenerate. + +As Helldivers, you can take the fight to the Terminids' remaining hive cores, and root out the infestation for good. 终结族对这颗星球的掌控有所减弱。我们必须立刻出击,避免它们恢复实力。 + +作为绝地潜兵,你们可以直接袭击终结族剩余的虫窝核心,将其彻底清除。 +929394276 The Tesla Tower stratagem is temporarily available to all Helldivers. “特斯拉塔”战略配备可暂时供所有绝地潜兵使用。 +3811000733 The Tesla Tower stratagem is temporarily available to all Helldivers. “特斯拉塔”战略配备可暂时供所有绝地潜兵使用。 +1836024379 The three stripes on the pauldrons stand for the three principles of Super Earth: Liberty, Democracy, and Prosperity. 护肩上的三条纹象征着超级地球的三大原则:解放、民主与繁荣。 +2183908730 The threshold at which stabilization stops being applied. 不再启用稳定量的阈值。 +4190388144 The threshold at which the cursor movements stop increasing in speed. 光标停止提高移动速度的阈值。 +810343458 The top-secret site where augmentations to the DSS are constructed. DSS强化设施的绝密搭建地点。 +3633071572 The TS-4 Arc Thrower stratagem is temporarily available to all Helldivers. “ARC-3电弧发射器”战略配备可暂时供所有绝地潜兵使用。 +578553929 The two stripes serve as a reminder of the two pillars of successful military campaigns: attack, and further attack. 双条纹代表着成功的军事行动有两大支柱:进攻,以及进一步进攻。 +66334679 The uncanny illumination seeping from the bulb stains the surroundings with its tyranny. 灯泡中散发出的诡异光芒让周围笼罩在暴政的阴影之中。 +2048386029 The understated color scheme and precision-molded armor plates make this armor a sensible choice for the Helldiver on the go. 精密铸造的护甲板加上低调的配色,这套护甲是绝地潜兵在配置行动装备时的明智之选。 +3777779738 The unimpeachable justice of this cape's design is said to blind the enemies of Freedom with its glorious light. 据说,此披肩无懈可击的正义设计将以荣耀光辉蒙蔽自由之敌的双目。 +810343589 The unjust wave of Illuminate migration following the Void surge has been slowed, thanks to the quick response of Helldivers in the region. No additional planets have fallen, but little information about how to penetrate the Void has been revealed. The Ministry of Science indicates that the mindless masses that come from the Void may have valuable information about what lies on the other side. 多亏了该地区绝地潜兵的快速响应,伴随寂域激增的不义光能者移民浪潮已放缓。没有更多星球陷入寂域,但关于穿透寂域的方法几乎没有新信息。科学部指出,源自寂域的无脑群氓可能掌握着关于“另一边”的宝贵情报。 +90879794 The unthinking, amoral bots may now violate the very air as well. Keep an eye to the skies, Helldivers. Reports are suggesting the presence of flying Automaton threats. 毫无思考能力和道德底线的机器人现在甚至开始侵犯空中领域。绝地潜兵,务必留意天空的情况。报告显示,战场上出现了飞行机器人。 +1189218670 The utilitarian sidearm that was standard-issue to the Charan Colonial Guard in the early days of the Galactic Federation. + +Produced by ST Construction. 在星系联邦初期,这种实用的随身武器曾是常陈四拓殖卫队的制式装备。 + +由ST建筑公司生产。 +4084546271 THE VILLAS 别墅区 +1608266009 THE VOID 寂域 +1622248549 The Void, a region of space that has gone completely dark under Illuminate control, expanded without warning. Two planets are gone and nearby planets are overrun with deceitful Illuminate interlopers. The Void surge must be stopped before any additional planets fall. 数个银河标准小时前,受到光能者控制、陷入彻底黑暗的星域——寂域,在毫无预警的情况下发生了扩张。两颗星球已消失,而邻近星球则被狡诈的光能者入侵者淹没。我们必须在更多星球惨遭吞噬之前,遏止寂域的扩张。 +1305900485 The Void's loitering presence has visibly reshaped the surface of this world. Further analysis is required to determine how deep this corruption extends below ground. + +You have been issued a reinforced Prospecting Drill. Collect soil samples to assess the full extent of the Void's unnatural influence. 寂域盘踞附近,已明显重塑该星球的地表环境。需开展进一步分析,查明这种腐化现象在地下的渗透深度。 + +你已获得一台加强版勘探钻机。采集土壤样本,评估寂域所带来的异常影响范围。 +417920220 The voltage of these batteries has been temporarily saved from being yoked to the expansion of the Automaton menace. 这些电池暂时得救了,不必在机器人威胁扩张之下遭受奴役。 +2439654161 The volume of all audio combined. 所有声音的总音量。 +1255879588 The volume of text to speech. 文字转语音时的音量。 +2038920506 The volume of the in-game dialogue. 游戏内对话的音量。 +3359844858 The volume of the in-game music. 游戏内音乐的音量。 +3108837132 The volume of the in-game sound effects. 游戏内音效的音量。 +1568886992 The volume of the in-game voice chat. 游戏内语音聊天的音量。 +1309198938 The voteless have taken planetX and planetY by sheer numbers, but they haven’t broken the spirit of the Helldiver resistance. + +The Illuminate, who will only be satisfied when the galaxy bends to their liberal will, may think that they are victorious against the forces of Super Earth - but they could never know the hot-blooded Democratic drive for vengeance. That will be their downfall. Helldivers take back what is ours and if that means cleaning squid guts from the tire tracks of our FRV fleet, so be it. 无票者凭借绝对的数量优势占领了X星和Y星,但未能击垮绝地潜兵的抵抗意志。 + +只有当整个星系都屈服于光能者的自由意志时,他们才会心满意足。他们或许认为已经战胜超级地球的军队——但他们永远无法理解激荡着热血的民主复仇渴望。而这将令他们走向覆灭。绝地潜兵定会夺回属于我们的东西。如果需要从快速侦察载具车队的轮胎印里清理鱿鱼内脏,那就这么办吧。 +2981498537 The way to HEETH is nearly clear. Push now to clear the way for construction of the Terminid Control System. 通往希斯星系的路线即将打通。继续推进,为构建终结族遏制体系清除所有障碍。 +1749038307 THE WEIR 维尔 +3659389670 The yellow is the exact shade of the Ministry of Unity's 'Golden Gate', leading to the Chamber of Unanimous Decision. 这正是团结部“金门”的颜色,打开大门便能前往统一决策大厅。 +2483028481 There are crucial oil reserves in this area needed to fuel our continued war effort. + +Navigate the Terminid swarm, reactivate the pumps, and transfer the fuel to the waiting transport shuttles. 这块区域内的油田对于支撑我们的长线战争至关重要。 + +绕开终结族虫群,重新启动泵机,将燃料转移到待命的运输船上。 +2246173906 There are millions of kilometers of Terminid tunnels beneath the surface of this planet. A detailed subterranean mapping is necessary to identify critical targets. + +Utilize a repurposed Prospecting Drill to collect samples of the infested mantle. Analyses will identify properties of local Terminid structures. 这颗星球地表下有长达数百万公里的终结族通道。需要进行细致的地下测绘确定关键目标。 + +使用改装过的勘探钻机收集被侵染地幔的样本。通过分析即可确定当地终结族结构的特性。 +1722268113 There are unsaved changes to your weapon config. Would you like to accept these changes or continue without saving? 武器配置存在未保存的更改。是否接受这些更改,或放弃保存以继续? +3108634152 There is a SEAF aircraft repair facility present on this planet. 此星球上坐落着超级地球武装部队的飞行器维修设施。 +1063797720 There is already another upgrade request on flight, try again in a few seconds. 正在处理另一项升级请求,请稍后再试。 +2748947600 There is currently no active action 目前没有进行中的行动 +3248706805 There is reason to believe this facility holds undeniable proof of socialist war crimes. Weapons of mass destruction, breaches of interstellar humanitarian law, unspeakable threats to our citizens. Held deep behind enemy lines. + +You must bring the truth to light. Infiltrate the site and obtain footage of this wrongdoing. Our citizens must see the true face of the enemy. 我方有理由相信这座设施内有敌方战争罪行的确凿证据。大规模杀伤性武器、违反星际人道主义法、对我方公民构成不可言说的威胁,全都深藏于敌后。 + +你必须揭露真相。潜入现场并录下他们的罪行。必须要让我们的公民看清敌人的真面目。 +142046361 There's no one right way to skin a bug. Experiment with different tactics and see what works! 一千个人有一千种对付虫族的办法。尽情尝试不同的战术,看看效果如何! +308205375 Thermite 铝热弹 +4075340772 THERMITE 铝热弹 +1983164658 These are the active missions that you must complete to succeed in the operation. + +Select your first mission in the operation. 你必须完成已激活的任务才能顺利完成这次行动。 + +请选择你在本次行动中的第一项任务。 +927788013 These batteries fuel the Automaton war machine. 这些电池为机器人的战争机器补充能源。 +1840545502 These plants are beginning to wilt in the absence of Democracy's tender care. 没有了民主的呵护,这些植物便开始枯萎。 +1912909754 THESEUS SECTOR 忒修斯分区 +432134967 They don't call it Tacticool for nothin' “战术咖”并非浪得虚名 +1332152835 They don't call it Tacticool for nothin' “战术咖”并非浪得虚名 +3175499143 They mostly come at night... 夜访异形… +3609232618 Thick Fog 浓雾 +1728812511 THICK FOG 浓雾 +3903318432 This aim-stabilizing armor found surprising secondary market success among alien birdwatching enthusiasts. 这套可稳定瞄准动作的盔甲出乎意料地受到了外星观鸟爱好者的青睐,在二级市场大获成功。 +4010410735 This altar’s wellspring is crawling with Illuminate tadpoles, poised to evolve into fully fledged war criminals at any moment. 这座祭坛的泉眼中爬满了光能者蝌蚪,它们随时可能蜕变为彻头彻尾的战犯。 +108221082 This ancient, likely allegorical, illustration of Might triumphing over the Anguiform is seen by scholars as a symbol of humankind's supremacy in the art of violence. 这幅可能深藏寓意的古老插图描绘了力量战胜蛇形生物的场景,学者认为这象征着人类在暴力艺术的至高地位。 +1387930949 This anti-aircraft emplacement is preventing the spread of liberty across the skies of this planet. Take it out before any more families are forced to attend martyrdom celebrations for their fallen heroes. 此对空炮台将妨碍自由在这颗星球的天空中传播。越快摧毁,越少家庭被迫感受阵亡英雄哀悼会的痛楚。 +3437936223 This area is overgrown with noxious blossoms that spread the Void's taint. 该区域长满了散播寂域污秽的毒花。 +1044960240 This armor celebrates the wearer's close relationship to their Exosuit---as intimate as is possible without succumbing to cyborgry. 此套盔甲旨在彰显穿着者与外骨骼装甲之间的紧密羁绊——极致亲密贴合,但不至于堕入生化人之境。 +2896191570 This armor is based on the antique uniforms of the 'Super Earth Legion', a less patriotic precursor to the Helldivers. 这套盔甲脱胎于古老的“超级地球军团”制服。后者是绝地潜兵的前身,但是不像绝地潜兵这样忠心爱国。 +2719181791 This armor is the required uniform for many Super Earth Citizens operating heavy machinery. Long-time users will be delighted to learn that as of this year's Efficiency in Machine Operation Symposium and Gala, wearing this armor is no longer itself considered operating heavy machinery. 这套盔甲是许多操作重型机械的超级地球公民的必备制服。从本年度“机械操作效能研讨会暨晚宴”举办之日起,穿戴这套盔甲将不再被视为操作重型机械,这对于长期穿着者而言无疑是个好消息。 +3813003853 This armor is the Super Earth Standard Issue, made from the same titanium alloy as the Destroyer's hull. 超级地球制式盔甲,使用驱逐舰舰体的同种钛合金制成。 +146259175 This armor pays tribute to the immoveable heroes of the front line—those who refuse to acknowledge incoming fire, and consider "dodging" to be an abstract concept akin to cowardice. 这套盔甲旨在致敬那些岿然不动的前线英雄——他们毫不畏惧来袭火力,并将“闪避”视为与怯懦无异的抽象概念。 +2694900440 This armor recalls the legendary heroes who scared a ravenous Hive Lord away from a colony village, using only the village's battery of patriotic fireworks. 这套盔甲纪念的是那些传奇英雄,他们仅凭村里的一批爱国烟花,就吓退了一只贪婪的霸王虫,拯救了拓殖地的村落。 +3008890038 This armor set first appeared in the music video for the summer anthem 'Our Love is Like Liberty (Indestructible)'. 这套盔甲的首度亮相是在夏日圣歌“爱如解放(坚不可摧)”的MV中。 +1993438296 This armor uses repurposed metal from verified sources, such as vending machine packaging and Automaton scrap, making it a sustainable choice for the environmentally conscious Helldiver. 这套盔甲采用来源经核实的回收金属材料,如自动售货机外壳和机器人废料,是具有环保意识的绝地潜兵的可持续之选。 +1596178626 This armor was designed by PFC Rodney A. Carmichael, the first Helldiver to use a stim on an ally instead of himself. 此盔甲由一等兵罗德尼·A.·卡迈克尔设计,他是首位将治疗剂用在队友身上(而不是自用)的绝地潜兵。 +2093158570 This armor, coated in radar-absorbent polymers and a null-signature heat baffle, reportedly turns its wearer into a sensor ghost—a claim attributed to individuals who, curiously, appear to have never existed. 盔甲的外层是雷达吸波聚合物和匿迹热隔板,据称能让穿戴者变成传感器探测不到的幽灵,有趣的是,如此声称的人似乎从未存在过。 +2165143260 This armor, together with its friendly-faced helmet, is instantly recognizable from the beloved children's show "Jen Shriver the Science Diver." 这套盔甲配套看似友好的头盔,一眼就能辨别灵感源自深受孩童喜爱的节目“科研潜兵珍·施莱佛 ”。 +637388300 This armor's nostalgic color scheme brings to mind beloved trappings of colonial yesteryear: concrete frontier domiciles, slate-colored civilian jumpsuits, and Space Settlers' Pie. 这套盔甲的怀旧配色让人联想到昔日拓殖地时期的时尚潮流:混凝土筑成的边境住所,石板色平民连体服,太空居民馅饼。 +358046681 This Automaton device prevents the use of any stratagems in the area. 机器人的这台装置令我们无法在该区域内使用任何战略配备。 +210713076 This black hole is all that remains of the hopes and dreams of the colonists who could have built a life here. Our enemies would sooner see the entire galaxy sucked into an endless void than allow our way of life to prosper. 拓殖地居民的希冀与幻想湮灭在黑洞之中,他们原本可以在这里创造幸福的生活。我们的敌人宁愿亲眼看着整个星系被吸入无尽的虚空,也不愿意看见我们的文明繁荣发展。 +2253660066 This black hole is all that remains of the singularly beautiful planet that was once Moradesh. Its endless wavy dunes and abundant resources were destroyed by an unavoidable accident at the Dark Fluid Research Facility, as its heroic scientists strived to save our citizens from the first Terminid Supercolony. The Terminids took Moradesh from us, leaving this scar as a reminder of their boundless barbarity. 莫拉戴什曾是一颗美丽绝伦的星球,如今,一切化为黑洞。星球上连绵起伏的沙丘和丰饶的资源因暗液体研究设施的突发事故而毁灭。当时,英勇的科研人员曾在该设施中致力于对抗首个终结族超级拓殖地,拯救我们的公民。终结族让我们痛失莫拉戴什,留下的疮疤将永远警示着我们,敌人是多么野蛮残暴。 +3298452307 This bolt-action rifle fires jet-assisted shells that explode shrapnel in all directions upon impact. Not recommended for close-quarters use. 这种栓动步枪透过喷气辅助发射炮弹,炮弹触及撞击面时向四面八方崩裂碎片。不建议近战使用。 +1839599612 This building has been overrun by Terminids and is now a Shrieker breeding ground. 这栋建筑已被终结族攻陷,现在成为了尖啸虫的繁殖之地。 +267001981 This cape celebrates the one Veridical Ideology—Managed Democracy—a truth so self-evident, it requires no proof beyond the unwavering obedience of its champions. 披肩颂扬唯一的真理意识形态:管理式民主。此中真理不言自明,也无需证明,只需要拥护者绝对服从。 +189221078 This cape depicts the inner workings of a medical device submitted to the Ministry of Science 70 years ago, and is bound to clear their patent approval process any day now. 这件披肩绘制了70年前提交到科学部的医疗设备内部构造,相信很快就能通过专利审批流程了。 +3731430141 This cape has a visual pattern that when scanned by Automaton sensors translates to “defile your microwave mother, bot scum.” 这款披风上的视觉图案被机器人传感器扫描时,会显示为“回你妈炉里重造吧,铁皮渣滓。” +748534083 This cape honors the Eagle pilots who would follow a Stratagem beacon into the very jaws of tyranny, even when the beacon's placement seems inscrutable to the non-Helldiver mind. 这件披肩旨在纪念那些追随战略配备信标直捣暴政巢穴的飞鹰飞行员,即便信标位置在非绝地潜兵者看来难以理解也义无反顾。 +1838016973 This cape recalls the popular folk tale of the "Freedomslingers": re-educated dissidents, seeking redemption on the Federation's Borderline, hunting dangerous thought-traitors in exchange for ballot bounties. 这件披肩让人想起民间广为流传的“自由神枪手”的故事:接受过再教育的异见分子在联邦边境线上寻求救赎,通过追捕危险的思想叛徒换取选票赏金。 +2905387404 This cape reminds us that even faced with the abyssal darkness of space, nothing can stand against our human ingenuity, our powers of collaboration, or our sheer overwhelming numbers. 这件披肩提醒我们,即使面对太空万籁俱静的黑暗,任何力量都无法对抗人类的智慧、协作能力以及人海战术的优势。 +3854959750 This cape signifies that its wearer thinks, feels, and acts correctly at all times, and thus bears the responsibility to educate and re-educate their fellow citizen. 这件披肩象征着穿戴者的思想、情感和行为一向无可指摘,因而肩负着教育和再教育同胞的重任。 +577500218 This cape's cropped length symbolizes the brevity of galactic conflicts, thanks to the efficiency of the Helldivers. 这款披肩的剪裁长度象征着星系冲突之短暂,一切归功于绝地潜兵的作战效率。 +819134360 This cape's retro print, first made popular in GW1 cereal merchandising, helps children remember that not all machines are twisted mechano-socialists; some are piloted by true-hearted humans, and we can all rest easy in their gaze. 这款披风的复古印花最初作为第一次星系战争的麦片周边商品而爆红,它能帮助孩子们牢记这一事实:并非所有机器的操控者都是扭曲的机械党同伐异者;有些机器由诚挚人类所驾驶,而我们正是在它们的注视下得以安然入睡。 +3209030358 This ceremonial rifle is modeled after antique relics from pre-Democratic times. It is traditionally gifted to every citizen upon turning 16 to encourage service. 以前民主时代文明的遗产为模型制作的礼仪步枪,传统会赠给满16周岁的公民,鼓励他们服役。 +2926773604 This city is under attack. It cannot be allowed to fall to the forces of oppression. 这座城市遇袭。绝不能让它落入压迫者之手。 +3533302151 This city is under attack. It cannot be allowed to fall to the forces of oppression. 这座城市遇袭。绝不能让它落入压迫者之手。 +3869794299 This city is under attack. It cannot be allowed to fall to the forces of oppression. 这座城市遇袭。绝不能让它落入压迫者之手。 +417512741 This city is under enemy control. It must be reclaimed in the name of Freedom. 这座城市已落入敌手。必须以自由之名收复。 +1988242305 This city is under enemy control. It must be reclaimed in the name of Freedom. 这座城市已落入敌手。必须以自由之名收复。 +3152484562 This city is under enemy control. It must be reclaimed in the name of Freedom. 这座城市已落入敌手。必须以自由之名收复。 +1031102422 This classic armor set is recognized by every citizen: worn by the heroic Helldivers who battled and forever defeated the Terminids, Cyborgs, and Illuminate in the First Galactic War. 每位市民都认识这套经典盔甲:在第一次星系战争,绝地潜兵英雄就是穿着它彻底击败终结族、生化人和光能者。 +2237064223 This colony is occupied by the Illuminate invaders. It must be freed. 此拓殖地被入侵的光能者所占领。必须解放这里。 +1770769441 This Control Tower is the nexus of enemy aerial operations in the region. 该控制塔是敌方在此区域空中作战的指挥中枢。 +3322311510 This convenient cape can double as ground insulation, warming blanket, or camp roofing to the enterprising defoliator. 这款便利披肩可兼作地面隔离垫、保暖毯或营地遮顶,为富有开拓精神的伐木工提供多种用途。 +2172345078 This dark abyss is all that remains of the verdant paradise that was once Meridia. Its breathtaking forests and abundant resources were corrupted and destroyed by the Terminids, leaving no choice but to use Dark Fluid to destroy it completely. Now, this singularity remains as a memorial, reminding us all of the consequences of defying Freedom. 默里迪亚曾经富饶的天堂如今只剩下黑暗的深渊。令人叹为观止的森林和丰富的资源遭到了终结族的腐化与摧毁,我们别无他法,只能利用暗液体将其完全销毁。现在,这个奇点已成为纪念碑,时刻提醒着我们藐视自由的代价。 +312223767 This Data Jack is carefully engineered to slot seamlessly into Illuminate Access Nodes. Once engaged, it initiates a sophisticated system disruption sequence, requiring little more than user confirmation. 这个精心设计的数据接口可完美插入光能者的接入节点。一旦成功对接,就会发起复杂的系统破坏程序,几乎仅需用户确认即可完成。 +2304136058 This facility contains unpatriotically produced research data, and must be razed to the ground. 该设施产生的研究数据有违爱国精神,必须将其夷为平地。 +3172306278 This forklift is the red blood cell of Managed Democracy, conveying vital necessities to wherever they are needed. 这辆叉车是管理式民主的红细胞。哪里需要重要物资,哪里就有它们的身影。 +1661251297 This former planet is now nothing but a normal, stable black hole. 这颗昔日行星现在不过是一个没什么特别的稳定黑洞。 +3736660687 This fuel facility can be used to transfer crucial reserves to hovering shuttles. 这座燃料设施可以将宝贵的储备资源输送至悬停的运输船。 +1902302378 This fueling station is offline. It must be reactivated to initiate fuel distribution. 这座燃料站已停止运转,需重新启动才能恢复燃料输送。 +1954197593 This fully-upgraded facility enables deep operations within the Gloom. Operations on surrounding planets will be significantly supported. 该设施全面升级,能在“阴霾”内展开深入运作。在周围星球的行动将得到大力支援。 +2927807501 This fully-upgraded facility enables deep operations within the Gloom. Operations on surrounding planets will be significantly supported. 该设施全面升级,能在“阴霾”内展开深入运作。在周围星球的行动将得到大力支援。 +2012659085 This Great Heart of Commerce is renowned galaxy-wide for its Grand Shopping Malls and Splendorous Entertainment Centers. 这座伟大商贸中枢因宏伟的购物商场和繁华的娱乐中心而闻名整个银河系。 +2394271256 This grenade delivery drone follows the user until it detects an enemy nearby, then flies toward it and explodes on impact. Has a limited battery life. 这款榴弹投掷无人机会紧跟使用者飞行,探测到附近敌人后飞向目标,撞击后引爆。电池续航时间有限。 +2960877391 This Guy 这家伙不得了 +3694530584 THIS GUY 这家伙不得了 +3250980093 This heavily-guarded bunker is thought to contain a vital Command Node for the Automaton Transmission Stream. 据悉,这座防备森严的碉堡中可能有机器人数据传输流的重要指挥节点。 +977851826 This high-caliber marksman rifle trades magazine capacity and rate of fire for powerful, accurate shots. 大口径狙击步枪,虽然牺牲了弹匣容量和射速,却提高了射击精准度和威力。 +194848098 This high-visibility armor allows it's bearer to be easily seen through smoke, fog, and spewing viscera. 穿上这套可见度极高的盔甲,缭绕烟雾和喷溅的内脏都挡不住你的风采。 +2250960762 This Hive World produces Gloom spores deep within the extensive Terminid cave networks. They are also the sole known source of extremely valuable E-711. + +Nothing is more important than freeing our citizens from the threat of the Gloom. The acquisition of E-711 is also the top priority for galactic security. Your orders are clear. 这个虫窝世界在纵深复杂的终结族洞穴网络里生产“阴霾”孢子。它们也是极为珍贵的711元素唯一已知的来源。 + +眼下最重要的是让我们的公民摆脱“阴霾”的威胁。获取711元素也是确保银河系安全的首要任务。指令十分明确。 +3675373706 This humane device attaches to its target and dispenses repeated electrical pulses, keeping the target in place for humane apprehension and/or termination. 附着在目标上反复释放电击脉冲的人道主义设备,能将目标固定在原地,方便实施人道主义逮捕或处决。 +1283217108 This input is bound to another action. Proceeding will bind several actions to the same input. Continue? 该输入键已与其他操作绑定。如果继续,则会将多个操作绑定至同一输入键。是否继续? +3718459561 This is a Commando Mission. +This far behind enemy lines, hostiles are everywhere. Every time they call for reinforcements, the threat level is increased. Higher threat level means more hostile units in the area. 这是突击兵任务。 +深入敌后,群敌环伺。每当敌军呼叫增援时,威胁等级就会提升。威胁等级越高,该区域内出现的敌方数量越多。 +1348005262 This is a Commando Operation. It contains Commando missions. + +In Commando missions, access to your Super Destroyer and Stratagems will be limited. Choose your engagements carefully. 这是突击兵行动。其中包含突击兵任务。 + +在突击兵任务中,使用超级驱逐舰和战略配备都将受限。请谨慎选择交战对象。 +3416752180 This is a potential platinum-rich site identified by the Automatons. Take a site sample to determine its viability. 这是机器人发现的潜在富铂金矿点。采集现场样本,确定开采价值。 +2325179655 This Is Democracy 恭迎民主 +391207303 THIS IS DEMOCRACY 恭迎民主 +2449145890 This is the best thing I've ever seen in my life! Can not live without! 从没见过这么棒的产品!没有它我就活不下去! +181032423 This is the maiden voyage of the #SHIP_NAME. Its first trial is to carve a democratic path towards the indicated region and provide critical support in suppressing a small-scale Terminid outbreak. + +Helldiver, this is not a drill. Apply every invaluable lesson you learned at the Helldiver Training Facility. May Liberty guide you. 这是#SHIP_NAME的首航。它的首次试炼是向指定区域开辟民主之路,并为镇压小规模终结族爆乱提供关键支援。 + +绝地潜兵,这不是演习。请学以致用,发挥你在绝地潜兵训练设施中学到的每一条宝贵经验。愿解放保佑你们。 +1421982955 This is the ship's armory. Here you can get an overview of the ship's arsenal and prepare for the next mission. 这里是舰船的军械库。在这里你可以了解这艘舰船上的军火储备概况,为下一项任务做准备。 +762981298 This is where you upgrade your Destroyer to better support you in the field. Upgrading modules will improve the effectiveness of stratagems you already own. 你可以在这里升级自己的驱逐舰,以便在战场上为你提供更有利的支援。升级模块将提高已有战略配备的效能。 +733052649 This item is already owned. 你已拥有此物品。 +3216959719 This item is not available for sale at this time. 这件商品目前未上架。 +1251107930 This item is temporarily disabled 这件商品被暂时禁用 +2749032513 This location has been strategically chosen to maximize the flag's inspirational impact. 这个位置经过精心选择,目的是最大限度地发挥旗帜鼓舞人心的力量。 +3947210492 This machine gives no sign of sapience, but one can never be too sure. 这台机器看起来不具备智慧,但是世上没有绝对之事。 +900204596 This massive infestation contains a rare mutated egg of high value to Terminid research. Extract with it, and your support of scientific advancement will be rewarded. 此处大型侵染扩张的虫群里有一颗稀有的变异虫卵,对终结族的研究价值颇高。携带该虫卵撤离,你对科研的支持工作将获得相应回报。 +3242992993 This Megafactory contains significant Automaton production facilities. Anti-orbital defenses will tax Super Destroyer resources, resulting in longer orbital cooldowns. 这座超大型工厂拥有大量机器人生产设施。反轨道防御设施将消耗超级驱逐舰资源,导致轨道支援冷却时间延长。 +1726909297 This modest cape has been worn by those guarding the Chamber of Unanimous Decision since time immemorial. 这件简朴的披肩自古便由统一决策大厅的守卫佩戴。 +4287782710 This multi-layered protective armor keeps rough sand, spores, and other coarse granules from irritating the skin. 这套多层防护盔甲能有效阻隔粗糙沙粒、孢子和其他颗粒物,防止皮肤受到刺激。 +3334983283 This Nuclear Missile travels over long distances at high speeds, to strike before the enemy has time to retreat or retaliate. 这枚核导弹能以极快的速度击中超远距离外的目标,不给敌人撤退或反击的机会。 +3089283956 This once-beautiful planet has been twisted into a hive of tyranny, corrupted beyond recognition by the ravenous spread of the Terminids. 这颗曾经美丽的星球被扭曲为暴政的巢穴,在终结族的贪婪扩张下面目全非。 +1825268973 This patriotic armor comes recommended by the Ministry of Expansion, empowering the wearer to re-seize from our enemies any territory that any human has laid claim to, at any point in time. 扩张部强烈推荐这款宣扬爱国主义的装甲,它将赋予穿戴者力量,帮助他们从敌人手中夺回人类在各历史时间节点曾宣称主权的领土。 +3934376796 This planet appears to have been monstrously transformed by the Terminids. It may be a source of Gloom spores. Exercise caution. 这颗星球似乎遭到了终结族骇人的改造。有可能变成“阴霾”孢子的来源。务必小心行事。 +1427924894 This planet continually produces a thick atmospheric Gloom cover, rendering logistical support extremely challenging. +Total Reinforcements are reduced by 20%, Eagle Re-arm time is increased by 30% and Ammo from pickups is reduced by 50%. 这颗星球持续积累厚重的“阴霾”孢子层,使后勤支援变得极其困难。 +总增援数减少20%,“飞鹰”重新装弹时间延长30%,拾取获得的弹药数量减少50%。 +2451430413 This planet has been completely infested by the Terminids, transformed inside and out into a hive of Tyranny. It is a source of Gloom spores. 这颗星球已被终结族彻底侵占,从内到外被改造成了暴政的虫巢。现已变成了“阴霾”孢子的来源。 +3795703857 This planet has been subjected to extended Illuminate debasement, and its corruption runs deep. Analysis of its corrupted biome will enable continued progress through the Void. 这颗星球长期遭受光能者的侵蚀,腐化已经根深蒂固。分析这颗星球被腐化的生态系统,可以帮助我们继续深入寂域。 +2171378463 This planet is believed to contain valuable ores, but intense Terminid activity (and elevated mortality rates for civilian geologists) have so far hindered surveying efforts. + +Activate the Prospecting Drill to collect soil sample data and verify the planetary composition. 据悉,这颗星球拥有珍贵的矿藏,但是由于终结族频繁活动(同时平民地质学家死亡率上升),我们的调查工作一直困难重重。 + +启动勘探钻机,收集土壤样本数据,核实这颗星球的构成成分。 +688744041 This planet is completely engulfed by the Gloom, severely impeding logistical support. +Extraction times are increased by 40 seconds, Eagle Re-arm time is increased by 30% and Ammo from pickups is reduced by 50%. 这颗星球完全被“阴霾”吞没,严重阻碍后勤支援。 +撤离时间延长40秒,“飞鹰”重新装弹时间延长30%,拾取获得的弹药数量减少50%。 +1221361339 This planet is considered enemy territory. The Helldivers must reclaim it from its oppressive occupants. 这颗星球被列为敌占领地。绝地潜兵必须从残暴入侵者手中夺回控制权。 +1117755848 This planet is so thoroughly infested that it appears to be a single interconnected Terminid hive. Gloom spores originate from somewhere inside this planet. + +It is difficult to predict what threats will be encountered on this planet. The Helldivers must delve into the enemy's caves to expunge their secrets. Reclaim the Hive World and free our citizens from the terror of the Gloom. 这颗星球彻底被侵染,看起来就像内部互相连通的巨大终结族虫窝。“阴霾”孢子源自这颗星球内部某处。 + +我们很难预测会在这里遭遇怎样的威胁。绝地潜兵必须深入敌方洞穴,抹除它们的秘密。收复虫窝世界,让我们的公民摆脱对“阴霾”的恐惧。 +3939027357 This planet is the center of Illuminate operations within the Void. They have constructed extensive facilities, whose nature is bewildering to Democratic minds and affronts to all things Free. Tear them down, and put an end to the Void. 这颗星球是光能者在寂域中的行动枢纽。他们建造了规模庞大的设施,民主的思维难以理解其中的本质,这些地方全都是对一切自由事物的公然亵渎。将这里夷为平地,终结寂域的存在。 +308082714 This planet is trapped in the Void. It will remain trapped here until the Source planet is found and dealt with, at which point this planet will return to its native galaxy. 这颗星球被困在寂域之中。我们必须找到并妥善处理源头星球,否则这颗星球将永困于此,无法回归原本所在的星系。 +3539536174 This planet is under attack. The Helldivers must defend it against the forces of tyranny. 这颗星球遇袭。绝地潜兵必须保卫星球,抵御暴政军队。 +1946080706 This planet serves as a connective point between this galaxy and the Void, allowing travel between the two spaces. 这颗星球是本星系与寂域之间的连接点,可以让舰船在二者之间穿梭。 +3442881362 This planet shows clear signs of Illuminate construction. 光能者的建筑活动迹象在该星球明显可见。 +3281557964 This planet was purged of the Gloom at great cost. Now, a Terminid outbreak threatens to mutate it into a festering Hive World once again. Our ethically sourced E-711 deposits and the lives of hard-working pump inspectors are imperiled. + +You must stop the bugs from despoiling what we have rightfully secured. Do not let this planet sink back into the Gloom. 这颗星球曾为肃清“阴霾”付出巨大的代价。现在,一场终结族暴乱使其再次面临沦为腐化巢窝世界的威胁。我们以道德方式采集的711元素,以及辛勤工作的泵机督察员的生命都将危在旦夕。 + +必须阻止这些害虫破坏我们正大光明取得的一切。绝不能让这颗星球再次深陷“阴霾”。 +2539971084 This planet-wide, ultra-high-security facility provides ample space for the secure confinement of terrorist dissidents until they are fully rehabilitated and re-educated. 这座覆盖全星球的超高安全设施收容空间充足,信奉恐怖主义的异见分子可以在这里接受安全监禁,直到全面改造并接受再教育。 +4241424972 This player is currently your friend on PC, Xbox and/or PlayStation™Network. They must be removed from your friends list on those services before they can be removed from your in-game friend list. 该玩家目前是您的PC、Xbox和/或PlayStation™Network好友,必须先将其从这些服务平台的好友列表中删除,然后才能从游戏内的好友列表删除该玩家。 +2947503342 This player is currently your friend on Xbox network and/or other Helldivers 2 platforms. They must be removed from your friends list on those services before they can be removed from your in-game friend list. 该玩家目前是你在Xbox 网络和/或其他《Helldivers 2》平台的好友。必须先将其从这些服务平台的好友列表中删除,然后才能从游戏内的好友列表删除该玩家。 +2995505816 This player is not associated with an ID on PlayStation™Network and cannot be moderated. You can take any of the following actions instead. 这位玩家没有关联PlayStation™Network上的ID,无法对其进行审核。你可以另行选择下列操作。 +3853228634 This SEAF communication relay can be used to send information to ships in planetary orbit. 这个超级地球武装部队通信转接设备可以用于给行星轨道上的舰船发送信息。 +439775170 This sector is occupied by Illuminate invaders. It must be freed. 该分区被入侵的光能者所占领。必须解放这里。 +915985776 This setting determines what resolution the game will render at, before scaling it to your selected display resolution. Decreasing this value may improve performance while increasing it will improve visual quality. 该设置将决定了游戏在等比缩放至你选中的显示分辨率之前将以多高分辨率完成渲染。降低该数值或许可以改善性能,而增加该数值将提高画质。 +55885433 This setting increases the amount of grass, rocks, etc that are scattered on the ground. 该设置可提高散布在地面的草和岩石等元素的数量。 +773438267 This setting modifies the fidelity of the terrain. The lowest setting disables faded transitions between some objects and the terrain. 该设置可调整地形的逼真度。设为最低将禁用部分物体与地形之间的渐变过渡。 +3914614320 This setting modifies the resolution of the volumetric clouds to render a more realistic sky. 该设置可调整体积云的分辨率,进而渲染出更逼真的天空。 +1347666334 This setting modifies the resolution of the volumetric fog to create clearer light shafts. Lower settings remove some light influence. 该设置可调整体积雾的分辨率,进而创造出更清晰的光束。较低的设置值将消除部分光照的影响。 +3464042826 This setting will only take effect after restarting the game 该设置必须重启游戏才能生效 +4060448903 This shotgun blasts a wide burst of high-voltage electricity that arcs between all units—enemy or otherwise—within range. 这把霰弹枪能在大范围内释放高压电流,在效果范围内的所有敌我单位之间形成电弧。 +3811864611 This sigil reaffirms the Helldiver's pledge to protect Managed Democracy, serve Managed Democracy, and uphold Managed Democracy. 这枚徽章再次强调了绝地潜兵对管理式民主的誓言:保卫、效命、秉持管理式民主。 +1927913734 This square is lined with statues of tyrants and war criminals, hailed by the Cyborgs as visionaries. 这个广场上矗立着暴君和战犯的雕像,生化人却把他们奉为远见卓识之士。 +221570490 This suit's plutonium-238 nuclear battery enables environmental scanning long after the user has ceased operation. 这套服装配备钚238核能电池,在穿戴者失去体征很长时间之后,电池依然能支撑设备完成环境扫描。 +623985071 This Terminid hive node emits a dense fog which reduces visibility. 此终结族虫窝节点释放出一种降低能见度的浓雾。 +2039095996 This Terminid hive node emits a dense fog which reduces visibility. 此终结族虫窝节点释放出一种降低能见度的浓雾。 +2649333397 This time-honored shotgun-like weapon has been improved since the First Galactic War, and now fires six beams instead of three. 这款霰弹枪式经典武器自第一次星系战争以来历经改良,射出的激光束从三道增加到了六道。 +3490648312 This tower will summon Bot Dropships if intruders are detected. 探测到入侵者后,这座塔将呼叫机器人运输舰。 +4101843045 This traditional armor has remained unchanged since time immemorial. Now with self-heated padding. 这套传统盔甲自古至今一直保持原样。而今配备了自热内衬。 +2038974779 This value controls the tradeoff between flicker and ghosting. Higher values reduce ghosting and may help with motion sickness, while lower values offer smoother edges. 该数值可以协调闪烁和重像。上调数值可以减少重像,或许也可以缓解晕动症。下调数值则可以让边缘变得更加平滑。 +1489041550 This vision-disruptive pattern cloaks the silent crusaders whose untraceable deeds are a pure expression of true Freedom: freedom from accountability. 这种干扰视觉的图案能够有效掩护寂静无声的圣战士,他们难以捉摸的行踪纯粹地展现了真正的自由,即免责的自由。 +2582063161 This will reset all settings in this tab to default. +Are you sure you want to continue? 该操作将把本页面设置重置为默认状态。 +是否确定要继续? +815619217 This will unbind another action. Continue? 该操作将取消另一项动作的键位绑定。是否要继续? +561917006 This will unlink your accounts. +Are you sure you want to continue? 此操作将解绑账号。 +确定要继续吗? +3991486518 This world teems with ethereal, boundless, and peculiar plant life that spreads silent and uninterrupted across its entire surface. 这颗星球表面布满了缥缈、奇特的植物,营造出无限蔓延的静谧感。 +2774811376 Thomasson 托马松 +2801286457 Thompson 汤普森 +3517854229 THORACIC COLLISION EXULTATION MANEUVER 碰胸庆祝 +626292720 Thorns 尖刺 +4250191189 Those taken under the wings of the Law can rest easy knowing that their transgressions will soon be laid bare, their harms amended, and their citizenship safely sequestered. 那些在法律羽翼庇护下的人将无需再担忧,因为他们的罪行很快就会揭露无遗,曾经造成的伤害会得到弥补,而他们的公民身份也将被安全并妥善地剥夺。 +2679525580 Those who serve Liberty from the shadows often elect to stay anonymous, moving like traceless specters through the night. May they watch over us always. 那些在黑暗中为自由而战的人往往选择隐姓埋名,如同幽灵般穿行于夜色之中,不留一丝痕迹。愿他们永远守护着我们。 +3669186559 Those who study Terminid behavior, ecology and E-710 potential gather here for cross-disciplinary research. 研究终结族行为、生态学以及710元素潜能的学者在此汇集进行跨学科研究。 +2846151139 Though originally intended solely for ceremonial use, its inspirational energy proved equally useful on the battlefield. 设计初衷是用于仪式,但事实证明,它鼓舞人心的力量在战场上同样奏效。 +3049055479 Though the nearby Gloom Base provides logistical support, the spore cover on this planet is heavy enough to cause issues for all landing Pelicans. +Extraction times are increased by 20 seconds. 虽然附近的“阴霾”基地能够提供后勤支援,但这颗星球上的孢子密度过高,令所有的“鹈鹕”难以降落。 +撤离时间延长20秒。 +62844138 THRASH IV 萨尔什4号 +1585556354 THREAT 威胁 +2543912374 THREAT LEVEL: HIGH 威胁等级:高 +1103087785 THREAT LEVEL: LOW 威胁等级:低 +2388077047 THREAT LEVEL: MAXIMUM 威胁等级:最高 +3851493511 THREAT LEVEL: MODERATE 威胁等级:中 +4169211635 THREAT LEVEL: SUBSTANTIAL 威胁等级:较高 +1141843610 THREE 三 +3947908635 Throw 投掷 +1734039293 THROW 投掷 +738053806 Throw GRENADE into FACTORY to destroy it. 把榴弹丢进工厂,将其摧毁。 +1190819594 Throw GRENADES into bug nests to destroy them. 把榴弹丢进虫族巢穴,将其摧毁。 +3383073796 Throw back a live grenade. 掷回一颗已激活的榴弹。 +1457853290 Throw grenade into artificial bug hole 将榴弹丢进人造虫穴 +1308163535 THROWABLE 投掷武器 +3267212639 THROWABLE 投掷武器 +3483584090 THROWABLE 投掷武器 +1415503235 Throwable Weapon 投掷武器 +2401509335 Throwing Knife 飞刀 +931105430 THROWING KNIFE 飞刀 +715492973 Thumb of Approval 赞许之指 +40709597 THUMB OF APPROVAL 赞许之指 +1923094316 Thumper 桩锤 +2296159403 Thumper 桩锤 +73853870 THUMPER 桩锤 +2012586173 Thundering Hooves of Loyalty 忠诚惊雷之蹄 +681969521 THUNDERING HOOVES OF LOYALTY 忠诚惊雷之蹄 +3621980142 TIBIT 提比特 +1764903446 Tideturner 力挽狂澜 +1895924945 TIDETURNER 力挽狂澜 +2644250342 TIDETURNER 力挽狂澜 +212590513 TIEN KWAN 天关 +2494260566 TIER #COUNT #COUNT阶 +2476950432 TIER #COUNT COMPLETED 已完成#COUNT阶 +132760796 TIER #TIER UPGRADES #TIER阶升级项目 +423684070 Tier 1 1阶 +971526200 Tier 2 2阶 +3049951433 Tier 3 3阶 +3598836844 Tighten all exhaust pipe clamps 紧固所有排气管管夹 +1448271014 Tighter Breech Lock 收紧枪闩锁 +2671643921 TIGHTER BREECH LOCK 收紧枪闩锁 +2345954630 Time Bonus 时间加分 +2876468059 Time to complete all missions increased by #V_ONE%. 完成所有任务的时间延长#V_ONE%。 +1327984623 Time to complete all missions is temporarily increased by #V_ONE%. 完成所有任务的时间暂时延长#V_ONE%。 +3093738873 Time to complete all missions is temporarily reduced by #V_ONE%. 完成所有任务的时间暂时缩减#V_ONE%。 +4074421269 Time to complete all missions reduced by #V_ONE%. 完成所有任务的时间缩减#V_ONE%。 +2175182123 TIMELY 甘霖城 +4187584156 TIMEOUT IMMINENT 即将超时 +4170163439 TIMEOUT IN #MINS:#SECS 超时倒计时 #MINS:#SECS +3300532350 TIMES REINFORCING: 增援次数: +1881325251 TIN SHORTAGE 锡资源短缺 +1431043704 Tip Hat 脱帽致意 +3561029309 TIP HAT 脱帽致意 +2135548423 Tired of missing your target? Use First Person View (FPV) to make long-distance shots. 不想再打空了?使用第一人称视角(FPV)进行远距离射击吧。 +4165434863 Titan 泰坦 +4209295102 TITLE 头衔 +271477812 TLdyHero 乱室英雄 +1696831565 TM-1 TM-1 +3478073223 to to +3733450085 to request reinforcement 请求增援 +1025026144 to adjust relay dish 调整中继天线 +4227282978 to adjust valve 调整阀门 +1334671958 to aim 瞄准 +2801833803 To Any Citizen Who's Lost a Home Thanks to Enemy Activity, We Say: 如果你的家园毁于敌人手中,没有关系 +1775757362 to check map waypoint 查看地图路径点 +2448214982 to crouch 蹲下 +2530061352 To curb Terminid population growth, we must strike at their vile hatcheries. + +Find and destroy all Terminid eggs in the area before the enemy has a chance to react. 为了抑制终结族种群数量增长的速度,我们必须袭击它们可恨的孵化点。 + +迅速行动,找到并摧毁该区域内所有终结族虫卵,不给它们反击的机会。 +84384593 to dial stratagem 拨通战略配备 +1801819105 to Discharge Dark Fluid 释放暗液体 +2638564397 to dive into prone 飞扑进入匍匐姿态 +1481877713 to equip your Grenades 装备榴弹 +4160678551 to equip your Primary Weapon 装备主要武器 +3707648774 to equip your Sidearm 装备随身武器 +2885402002 to equip your Support Weapon 装备支援武器 +2890594467 to find new missions 寻找新的任务 +2181221179 to fire your weapon 武器开火 +125898937 to go prone 匍匐 +3677938169 To honor the heartfelt siblinghood of the heroes who stood together, bled together, and laid down their lives together in defense of Equality-On-Sea, all Helldivers are awarded one (1) commemorative polyester cape. 为致敬在仰齐浜保卫战中共同浴血奋战的同志情谊,所有绝地潜兵将获赠一件(1)聚酯纪念披风。 +1828776547 To limit Terminid population growth, we must strike at their mature hives. + +Activate a dormant ICBM silo on the planet to wipe out massive concentrations of bugs at once. 为了限制终结族种群数量增长的速度,我们必须袭击它们成熟的虫窝。 + +启动这颗星球上一座暂停使用的洲际弹道导弹发射井,瞬间抹除多个大型虫族聚居地。 +4209637764 to look around 环顾四周 +2504599628 to maneuver Hellpod 操纵绝地喷射舱 +2291736181 to melee 近战 +4125114671 to move 移动 +2444145415 to open the Stratagem menu 打开战略配备菜单 +1242187832 to place a waypoint on the map 在地图上标记路径点 +3774522945 to quick throw a Grenade 快速投掷榴弹 +4204822440 to reload your weapon 为武器装弹 +3181175354 to salute the Flag 向旗帜敬礼 +1953514864 to sprint 冲刺 +3249773462 to switch between PRIMARY-, SECONDARY-, and SUPPORT WEAPONS. 切换主武器、副武器和支援武器。 +1211054850 to switch between PRIMARY and SUPPORT WEAPON. 切换主武器和支援武器。 +3174013524 to switch weapon 切换武器 +2646101367 to throw 投掷 +8126575 to throw a Grenade 投掷榴弹 +2267174837 to throw stratagem ball 投掷战略配备球 +3536334514 to use a Stim on a wounded squad member 对受伤的队友使用治疗剂 +1437330470 to use a Stim on yourself 对自己使用治疗剂 +4276582894 to use stim 使用治疗剂 +3384585722 to view the map 查看地图 +3138140906 Today we praise the steadfast logistics operators. They have just deployed new equipment to all Super Destroyers. Perhaps one day, they too can reach the heights of loyalty that our Helldivers demonstrate every single day. 今天,我们赞美忠诚的物流操作员,他们已顺利将全新装备送达各艘超级驱逐舰。或许有一天,他们也会达到绝地潜兵那样的高度,时刻都会彰显内心的忠诚。 +3019621030 TOGGLE AMMO 切换弹药 +2328490271 Toggle Emergency Lights 切换紧急照明 +195338518 Toggle Headlight Power 切换大灯供能源 +672612253 TOGGLE HEADLIGHTS 切换大灯 +1056438189 TOGGLE HUD 切换HUD +3657897086 Toggle Info 切换详情 +1340249464 TOGGLE INFO 切换详情 +2539601384 Toggle Laser Designator 切换激光指示器 +3178254909 TOGGLE LASER GUIDANCE SYSTEM 切换激光制导系统 +1336786945 TOGGLE MENU 切换界面 +280014435 TOGGLE MICROPHONE 切换麦克风 +1830826216 TOGGLE READY 切换准备状态 +1916745962 Toggle View 切换视图 +332354099 Toggles the outline on your aiming reticle on or off, for greater visibility. 显示或隐藏准星轮廓,更好地调整可视度。 +1280955084 TOIL 劳作市 +1495811592 TOILET STALLS: DISSIDENT HIDEOUTS? 厕所隔间:异见分子的秘密基地? +2922615489 Tongue 虫舌 +2790576967 TOO FAR FROM EXTRACTION 距离撤离点太远 +342275086 Too Far From Extraction - Shuttle Aborting In T-#MINUTES:#SECONDS:#MILLI 距离撤离点太远 — 运输船中止倒计时 #MINUTES:#SECONDS:#MILLI +830482194 Too many requests coming in. Please wait a moment. Error codes: 请求过多,请稍等片刻。错误代码: +1983790063 Tools are hung neatly, in accordance with governmental guidelines. 工具摆放得整整齐齐,严格遵守政府规定。 +681133012 Tooltip Visibility 提示信息可视度 +3728668558 TOP DOWN 自上而下 +2383255078 TOP SECRET RESEARCH FACILITY 高度机密研究设施 +154042933 Top-of-the-line accounting software automates payroll calculations, freeing up HR associates to lubricate support weapons in their spare time. 顶级会计系统软件实现自动化薪金计算,让人力资源助理腾出空余时间为支援武器上油润滑。 +2703085897 TOPSOIL 表土市 +276813339 TOR E 托尔E +2232598179 Torcher 火炬手 +2424163971 TORCHER 火炬手 +1949115573 Torrential rainstorms reduce visibility. 倾盆暴雨会降低能见度。 +592333538 TORSO 躯干 +1915489855 TORSO 躯干 +3133893560 TORSO 躯干 +4282560876 Total 全射 +2988495375 Total Score 总分 +1573437979 Total Stratagems Used 战略配备总使用次数 +4235590190 TOTAL VALUE 总价值 +524423319 Total XP Earned 所获总经验值 +4272049039 TOTAL: +#AMOUNT M 总计:+#AMOUNT +3734930328 TOUCH 触碰 +1764357457 Touch Pad Map Sensitivity 触摸板地图灵敏度 +407444091 TOWER CONTROL PANEL 广播塔控制面板 +3839515680 TOWER CONTROL TERMINAL 通信塔控制终端 +2715793094 TOWER MISALIGNED 卫星塔方向偏离 +2920986948 Tower supports demolished 塔巢支撑结构已摧毁 +4129291016 TOWN 城镇 +3251497283 Toxic gas 毒气 +820717204 Toxic Gas 毒气 +2301784568 TR-117 Alpha Commander TR-117“阿尔法指挥官” +415996760 TR-117 ALPHA COMMANDER TR-117“阿尔法指挥官” +662852761 TR-40 Gold Eagle TR-40“金鹰” +4045553464 TR-40 GOLD EAGLE TR-40“金鹰” +1136470459 TR-62 Knight TR-62“骑士” +3891717296 TR-62 KNIGHT TR-62“骑士” +3713235989 TR-7 Ambassador of the Brand TR-7“形象大使” +2827223430 TR-7 AMBASSADOR OF THE BRAND TR-7“形象大使” +2146393453 TR-9 Cavalier of Democracy TR-9“民主骑兵” +3591901479 TR-9 CAVALIER OF DEMOCRACY TR-9“民主骑兵” +1553767011 TRACE LOCAL DEFENSE NETWORK 追踪本地防御网络 +557216270 Track down and eliminate the Bile Titan. 追踪并消灭吐酸泰坦。 +4229860194 Track down and eliminate the Brood Commander. 追踪并消灭虫族指挥官。 +3645281821 Track down and eliminate the Charger. 追踪并消灭强袭虫。 +1500194762 Training Maneuvers 军事演习 +179795039 TRAINING MANEUVERS 军事演习 +1184273578 TRAINING MANUAL TIPS 训练手册提示 +1377774134 Trains pit crew members to employ situational protocol adaptations, such as leaving unused ammo loaded instead of replacing it. 训练维修组成员,让他们采用情景协议调整机制,例如保留已上膛但尚未使用的弹药,不进行替换。 +478982282 TRAITOR DETECTED 发现叛徒 +3119992422 TRAITOR'S END 终叛城 +1815342243 TRANDOR 特兰道尔 +591531681 TRANSCENDENCE 超验枢 +3717530748 Transfer in progress 正在输送 +2854257115 TRANSFER OIL TO SHUTTLE 将油输送至运输船 +1339239938 TRANSFER STATION 中转站 +3413068530 Transferring data from SSSD 从超级固态硬盘传输数据 +3791375433 TRANSMISSION STATION UPLOAD READY 传输站上传程序准备就绪 +2911136799 Transmission to Super Earth Mainframe in progress 正在向超级地球主机进行传输 +3682003740 Transmit data burst 传输数据冲压包 +4169747191 TRANSMIT DATA PACKAGE 传输数据包 +845126010 TRANSMITTING DATA 传输数据 +3137933119 Transport Black Box to Communications Relay 将黑匣子转移至通信中继站 +2182114170 Transport Shuttle 运输船 +85108748 Transport shuttle incoming 运输船即将抵达 +115668252 Transport shuttle incoming 运输船即将抵达 +1696158145 Transport SSSD Hard Drive to Communications Relay 将超级固态硬盘转移至通信中继站 +1319105446 Transport Vessel to Payload Site 运送容器至投放点 +3859574095 Transporting a large shipment of flamethrowers. Heavy enemy presence - delivery expected to take the whole day. Derek forgot the fire extinguisher but I'm sure we'll be fi- 正在运输大量火焰喷射器。敌人攻势强劲,预计要花一整天才能送到。德里克忘了带灭火器,但肯定不会出意…… +1421050814 TRAVEL 前往 +2106278125 Travel to this Campaign to participate in planetary liberation. 前去参加这场战役,共同解放星球。 +3450536231 Treasure Hunt 寻宝 +4020719270 TREASURE HUNT 寻宝 +2201953643 TREMORS 地震 +3469100847 Tremors Detected 侦测到地震 +2060964145 TRG 扳机 +3171575544 Triangle Button 三角键 +146591054 Triangulation Veil 三角定位披纱 +2077736904 TRIANGULATION VEIL 三角定位披纱 +3728317380 Tried to log in using a platform id the game does not support 请勿使用游戏不支持的平台ID进行登录 +4197449621 Tried to log in using legacy login with a non-test account 请勿使用非测试账号执行遗留登录 +837307712 TRIGGER 扳机 +3445009551 TRIGGER 扳机 +3872011624 Trigger Effect Strength 扳机效果强度 +379660095 TRIGGER TYPE 触发方式 +3407735719 Triggers after a button has been pushed down for a set amount of time. 按下按键一定时间后触发操作。 +3512889973 Triggers after a button has been pushed down for a set amount of time. 按下按钮一定时间后触发操作。 +481737484 Triggers as soon as a button is pushed down. 只要按下按键就立即触发操作。 +2574186296 Triggers as soon as a button is pushed down. 只要按下按钮就立即触发操作。 +2477943940 Triggers continuously while a button is being pushed down. 只要按下按键就连续触发操作。 +2881973953 Triggers continuously while a button is being pushed down. 只要按下按钮就连续触发操作。 +1577796006 Triggers on the second press if you quickly push down the same button twice. 如果连续两次快速按下同一按钮,第二次按下时触发操作。 +2814788231 Triggers on the second press if you quickly push down the same button twice. 如果连续两次快速按下同一按键,第二次按下时触发操作。 +2422030322 Triggers only when a button is pushed down and released quickly. 仅在快速按下并松开按键时触发操作。 +3353253004 Triggers only when a button is pushed down and released quickly. 仅在快速按下并松开按钮时触发操作。 +2145993648 Triggers when the button is released after being pressed down. 按下按键后松开时触发。 +3284702303 Triggers when the button is released after being pressed down. 按下按钮后松开时触发。 +1172950089 TRIGON SECTOR 特里贡分区 +745391401 Trims excess leg space in the cockpit, allowing the Eagle to carry additional payloads. 削减驾驶舱内多余的腿部空间,增加“飞鹰”的有效载荷。 +2906903631 Triumph 的胜利 +1467045295 TRIVIAL 易如反掌 +4039692928 Trooper 装甲兵 +4138482718 TROOPER 装甲兵 +1251671830 Troopers 装甲兵 +2225234085 TROOST 特鲁斯特 +2724000483 TROPHY HUNT 荣耀猎杀 +3977251416 Trucker's Triumph 卡车司机的胜利 +2749716801 TRUCKER'S TRIUMPH 卡车司机的胜利 +2583035357 TRUE BLUE EXOSUIT PATTERN 忠诚蓝外骨骼装甲涂装 +1345310449 TRUE BLUE HELLPOD PATTERN 忠诚蓝绝地喷射舱涂装 +1744179903 TRUE BLUE SHUTTLE PATTERN 忠诚蓝运输船涂装 +3278799117 TRUE BLUE VEHICLE PATTERN 忠诚蓝载具涂装 +4225753900 TRUE GRIT 坚韧不拔 +2467146338 Truly Exceptional Heroism 非凡英杰 +4195231865 Truth Enforcers 真理执行者 +1702796742 TRUTH ENFORCERS 真理执行者 +166510538 Truth Whisperer 真理低诉者 +1419033513 TRUTH WHISPERER 真理低诉者 +1391731473 Truth: the backbone of Democracy. + +The Ministry of Truth. 真理乃民主之本。 + +真理部 +4126424963 Trying to upgrade an already fully upgraded weapon/stratagem. 你正在尝试升级一项已经升至满级的武器/战略配备。 +1914480073 TS-4 Arc Thrower stratagem availability has ended. 现已无法使用“ARC-3电弧发射器”战略配备。 +3075334835 Tune probe to lock onto signal 调节探测仪,锁定信号 +549189300 Tune to Super Earth frequency 调至超级地球的频率 +3342924444 TURING 图灵 +673479554 TURING DEFENDED +The bugs have been repelled from Turing. Citizens across the planet hold celebrations in honor of the Helldivers' heroism. 成功保卫图灵 +我们已将虫族逐出图灵。全星球的公民一起举办了庆典活动,纪念绝地潜兵的英勇之举。 +2206005523 TURING FREED +Turing is free at last from the bugs, thanks to your dauntless efforts. Press the fight onward. 图灵已解放 +在你们英勇无畏的努力下,图灵终于摆脱了虫族。再接再厉,继续战斗。 +161750712 TURING LOST +Turing has fallen to the Terminid Menace. We cannot allow this infestation to continue to spread. 图灵沦陷 +在终结族的威胁下,图灵已沦陷。我们不能容许虫族继续扩张。 +701203373 TURING SECURED +The Terminid Control System is now fully activated on Turing. 成功占领图灵 +终结族遏制体系已经在图灵全面启动。 +3581418548 TURING UNDER ATTACK +The bugs have attacked Turing. Rally to its defense, before they are able to permanently infest it. 图灵遭到袭击 +虫族对图灵发动了袭击。立即集结,前去防卫,避免领地永远落入敌人手里。 +753673852 Turn all valves indicated by the terminal 按照终端的提示,调整所有阀门 +2950948763 Turn all valves indicated by the terminal 按照终端的提示,转动所有阀门 +3410342490 Turn all valves indicated by the terminal 按照终端的提示,转动所有阀门 +3398395316 TURN LEFT 左转 +1111436140 Turn Off 关闭 +1455983201 Turn On 开启 +1789121834 TURN RIGHT 右转 +1012936790 TURN SIGNAL LEFT 左转向灯 +662871195 TURN SIGNAL RIGHT 右转向灯 +42057101 Turn the cranks on the side of the Cannon to rotate it 转动加农炮侧面曲柄进行转向 +1680964422 Turning V-Sync on synchronizes the frame rate to the display device's refresh rate. Enabling this setting prevents visual artifacts such as screen tearing, but can cause lower framerate if your computer cannot keep up with the monitor. 开启垂直同步会将帧率同步为显示器的刷新率,可以防止画面撕裂等画面现象,但如果电脑性能无法与显示器保持同步,则可能会导致帧率降低。 +3157013588 Turret reload sequence initiated... 炮台装弹程序已启动… +2533332710 Tutorial Mission 教程任务 +2516049895 TV SPEAKERS 电视喇叭 +3931430370 TVENNE BOTTOMS 双瓣谷 +1002982797 TWO 二 +3533820337 TX-41 TX-41 +158857161 TYPE 种类 +1436263504 Tyranny contained within a matrix of anodes and cathodes. 暴政就在阳极和阴极组成的矩阵之内。 +862979628 TYRANNY PARK 2 第二代暴政公园 +3657693272 Tyranny's Bane 暴政的毁灭 +1840564097 TYRANNY'S BANE 暴政的毁灭 +2985753563 TYRANT HUNTER 猎暴人 +3773599036 TYRANT HUNTER 猎暴人 +1748003784 UAV Recon Booster UAV侦察强化资源 +322444584 UAV RECON BOOSTER UAV侦察强化资源 +270165902 UAV RECON SUPPORT UAV侦察支援 +3891463586 UBANEA 乌巴尼亚 +2969398782 UBR 下挂 +454883555 UF-16 Inspector UF-16“督察员” +1290747180 UF-16 INSPECTOR UF-16“督察员” +2766414075 UF-50 Bloodhound UF-50“猎犬” +1322492062 UF-50 BLOODHOUND UF-50“猎犬” +1750576249 UF-84 Doubt Killer UF-84“疑虑克星” +3619549886 UF-84 DOUBT KILLER UF-84“疑虑克星” +2165407893 UI Brightness UI亮度 +1331549189 Ultimatum 最后通牒 +828864864 ULTIMATUM 最后通牒 +2583671960 ULTRA 超高 +1584426594 ULTRA PERFORMANCE 超高性能 +3684909524 ULTRA QUALITY 超高画质 +98658779 Ultra Quality Plus 超高画质+ +1645750965 ULTRA SUPERSAMPLING 强化超级采样 +3372702334 ULTRAMAFIC MINE 超镁铁矿井 +4003330548 UMLAUT SECTOR 乌姆劳特分区 +742788434 Unable to authenticate your account on Microsoft, please try again later or contact support if this error persists. 无法验证你的Microsoft账号,请稍后重试。如果问题仍未解决,请联系客服。 +4117581814 Unable to authenticate your account on PlayStation™Network, please try again later or contact support if this error persists. 无法验证你的PlayStation™Network账号,请稍后重试。如果问题仍未解决,请联系客服。 +214107114 Unable to establish a connection to game. 无法连接至游戏。 +2938175656 Unable to establish a connection to game. 无法与游戏建立连接。 +2798815782 Unable to finalize the purchase, please try again later or contact support if this error persists. 无法完成购买,请稍后重试。如果问题仍未解决,请联系客服。 +1255517193 Unable to initialize the purchase, please try again later or contact support if this error persists. 无法开始购买,请稍后重试。如果问题仍未解决,请联系客服。 +1088091351 Unable to join game 无法加入游戏 +117947345 Unable to login into PlayFab, try again in a few minutes. Contact support if the problem persists. + +Status code: #STATUSCODE +Error code: #ERRORCODE 无法登录PlayFab,请过几分钟后再试。如果问题仍未解决,请联系客服。 + +状态代码:#STATUSCODE +错误代码:#ERRORCODE +2319937242 UNABLE TO REPORT 无法举报 +796575870 UNANIMITY 统一市 +540423199 Unanticipated Automaton reinforcements are taking significant ground on Planet #V_ONE. 突如其来的机器人增援部队正在#V_ONE星球上占领重要阵地。 +807709475 Unanticipated Automaton reinforcements have taken significant ground on Planet #V_ONE. 突如其来的机器人增援部队在#V_ONE星球上占领了重要阵地。 +136327622 Unanticipated Automaton reinforcements have taken significant ground on Planet #V_ONE. 突如其来的机器人增援部队在#V_ONE星球上占领了重要阵地。 +2891862420 UNAPPLIED CHANGES 未应用更改 +494516296 Unavailable 不可用 +3979874122 UNBIND INPUT 解绑键位 +3370951090 Unblemished Allegiance 无瑕忠诚 +1798629526 UNBLEMISHED ALLEGIANCE 无瑕忠诚 +4257722516 UNBLEMISHED ALLEGIANCE 无瑕忠诚 +2095370897 UNBLOCK 取消屏蔽 +2761160728 UNDER COMPASS 罗盘下方 +757157929 Underbarrel 下挂 +168771947 UNDERBARREL 下挂 +300696188 UNDERBARREL 下挂 +432072323 UNDERGROWTH EXOSUIT PATTERN 灌木外骨骼装甲涂装 +824552187 UNDERGROWTH HELLPOD PATTERN 灌木绝地喷射舱涂装 +1149778595 UNDERGROWTH SHUTTLE PATTERN 灌木运输船涂装 +2862867325 UNDERGROWTH VEHICLE PATTERN 灌木载具涂装 +2207334030 UNDERVATTEN 水下城 +2591249663 UNDISCLOSED LOCATION 机密位置 +3637004657 Unexpected SEAF reinforcements are taking significant ground on Planet #V_ONE. 意料之外的超级地球武装部队增援力量正在#V_ONE星球上占领重要阵地。 +2944563374 Unexpected SEAF reinforcements have taken significant ground on Planet #V_ONE. 意料之外的超级地球武装部队增援力量在#V_ONE星球上占领了重要阵地。 +3851872716 UNFLINCHING 毫不畏缩 +645085199 UNGU 紫都 +3704112830 Unhappy with who you are? Change your appearance and voice in the customization chamber. It's that easy! 想要改变自己?前往自定义房间,更改外貌和声音。一切就是那么简单! +2134740993 UNIDENTIFIED PLANET 未识别星球 +1009772021 UNINHABITABLE SYSTEM 不宜居星系 +3887939125 UNISON 和谐市 +1417553908 United in Equality 仰齐与共 +3055483883 UNITED IN EQUALITY 仰齐与共 +2504204569 University of Super Earth Adopts New Standardized Patriotism Test For Admissions 超级地球大学入学考试采用新版标准化爱国主义测验 +1938834551 Unknowable Forces 未知力量 +332478520 Unknown 未知 +1797787423 UNKNOWN 未知 +1400993941 Unknown and unexpected system error 未知意外系统错误 +2893255745 Unknown Name 未知名称 +1869076182 UNKNOWN SIGNATURE 不明标志 +3170157393 UNKNOWN SYSTEM 未知星系 +2580213184 Unlimited 无限 +4193418343 UNLIMITED 无限 +3895530999 UNLINK 解除绑定 +374881894 UNLINKING 正在解除绑定 +2634188326 Unlocks new discoverable samples and enemy types. 解锁全新可供探索的样本和敌人类型。 +770494850 UNMAPPED SYSTEM 未测绘星系 +3120901567 UNMUTE 取消静音 +4218892298 UNREGISTERED SYSTEM 未注册星系 +622682013 Unsafe 不安全 +520221179 Unstable 不稳定 +3398823357 Until further notice, all Helldivers will passively regenerate health at a rate of #V_ONE% per second. 所有绝地潜兵暂时以每秒#V_ONE%的速度被动恢复生命值,直至另行通知为止。 +1185004327 Unverified Reports of Illuminate Sightings Attributed to Dissident Disinformation. 未经证实的光能者目击报道助长异见分子的造谣气焰 +2131964075 UP 上 +1220084517 Up Button 上方向键 +2724403315 UPGRADE +AVAILABLE 升级 +可用 +3075683100 UPGRADE #MODULE FOR MORE 升级#MODULE解锁更多 +2692147882 Upgrade all ship modules at least 1 level. 将所有舰船模块提升至少1个等级。 +2333439841 UPGRADE COST 升级消耗 +2800451454 UPGRADE EFFECT 升级效果 +2517810371 Upgrade your ship modules to enhance the capabilities of your Stratagems! It's the perfect way to turn samples into Liberty. 升级舰船模块可提升战略配备的性能!这是将样本转化为解放之火的完美渠道。 +1315174793 Upgraded Afterburner 升级后燃器 +1597760513 Upgraded Afterburner 升级后燃器 +2636041274 UPGRADED AFTERBURNER 升级后燃器 +3067346159 UPGRADED AFTERBURNER 升级后燃器 +2823872429 Upgraded Ammunition Feed 升级供弹系统 +3244064634 UPGRADED AMMUNITION FEED 升级供弹系统 +1157962409 Upgrades Helldiver uniforms with form-fitting, automated, rapid-response fire suppression systems. Significantly reduces the time it takes for a burning Helldiver to naturally extinguish flames without the need to conduct rapid ground-aided smothering maneuvers. 为绝地潜兵制服升级贴合体型的自动快速反应灭火系统。显著缩短炽灼小队绝地潜兵自然熄灭火焰时间,无需通过在地面上快速打滚来执行灭火动作。 +3609805218 UPLOAD BLACK BOX DATA 上传黑匣子数据 +2087215146 Upload Data 上传数据 +1418558378 UPLOAD DATA 上传数据 +3433639232 UPLOAD DATA VIA LOCAL RELAY 通过当地转接设备上传数据 +2338099950 UPLOAD ESCAPE POD DATA 上传逃生舱的数据 +3841851005 Upload sample data using drill interface 使用钻机界面上传样本数据 +2073441684 UPLOAD SAMPLE DATA? 是否上传样本数据? +1357339998 Uploading data to Super Earth Mainframe 正在向超级地球主机上传数据 +73600892 UPLOADING VIDEO FILES 正在上传视频文件 +1404743455 Upon initial impact, the deployer scatters a wide field of proximity-detonated submunitions. These charges deal minimal damage, but will heavily stun and decelerate encroaching hostiles. 刚落地时,部署器会撒布大片近炸子弹药场。这些炸药造成的伤害极小,但能对逼近的敌军产生强力眩晕和减速效果。 +3715932053 URBAN 城市 +1356111458 URBAN CAMO 城市迷彩 +2572553124 Urban Legends 都市传奇 +2838569178 URBAN LEGENDS 都市传奇 +1403939755 Urchin 海胆 +1473448864 URCHIN 海胆 +514325094 URECTEM 乌雷克特姆 +1649129897 URGENT LIBERATION 亟待解放 +1012377516 URSA SECTOR 大熊座分区 +1650103832 URSICA XI 厄西卡XI +3267641248 URSOOT NINE 乌尔苏特九号 +30705468 USE 使用 +98177851 Use COMPUTER TERMINAL. 使用计算机终端。 +827263007 Use REINFORCE to call in dead teammates. 使用增援呼叫已牺牲的队友。 +1373695715 Use #COUNT defensive stratagems 使用#COUNT次防御战略配备 +1345055336 Use #COUNT orbital stratagems 使用#COUNT次轨道战略配备 +1079990460 Use #COUNT stratagems 使用#COUNT次战略配备 +1208786668 Use #COUNT supply stratagems 使用#COUNT次补给战略配备 +347564326 Use a Stim to heal your wound 使用治疗剂疗愈伤口 +309264725 Use adaptive controller stick ranges. 使用自适应游戏控制器摇杆范围。 +2543274618 Use adaptive controller stick ranges. 使用自适应游戏控制器操作杆范围。 +2871102989 Use Async Compute 使用异步计算 +4257441747 Use at least #COUNT stratagems during a single mission 在单次任务中至少使用#COUNT次战略配备 +4194213520 Use Backpack 使用背包 +3316166426 USE BACKPACK FUNCTION 使用背包功能 +308546301 Use door controls to release civilians from Emergency Bunkers 使用门控装置将平民从紧急掩体中放出去 +1754035950 Use door controls to release facility staff from Emergency Bunkers 使用门控装置将设施中的人员从紧急掩体中放出去 +2645065579 Use drill interface to deploy Nuclear Payload 使用钻机界面部署核炸药 +3578603899 Use drill interface to deploy sterilizing agent 使用钻机界面部署灭菌剂 +3976434132 Use drill interface to switch drills 使用钻机界面切换钻机 +921938397 Use hub terminal to upload recordings 使用中继站终端上传记录 +803352399 Use LiDAR towers to gather Gloom spore data and upload it from a communication relay. 使用激光雷达塔收集“阴霾”孢子数据,并通过通信中继站上传数据。 +2893569738 Use Machine Gun Stratagem to call in Support Weapon 使用机枪战略配备,呼叫支援武器 +3787792250 Use map to navigate to Helldiver Training Facility 使用地图前往绝地潜兵训练基地 +1522495655 Use Orbital Precision Strike Stratagem to kill enemies 使用轨道精准攻击战略配备击杀敌人 +1154328682 Use Prospecting Drill to retrieve final sample 使用勘探钻机取得第三份样本 +1964072812 Use Prospecting Drill to retrieve first sample 使用勘探钻机取得第一份样本 +602067977 Use Prospecting Drill to retrieve second sample 使用勘探钻机取得第二份样本 +601721506 Use Raw Mouse Input 使用原始鼠标输入 +473650171 Use Reinforce Stratagem to bring back fallen squadmate 使用增援战略配备复活阵亡的队友 +2324676534 Use Reinforce Stratagem to bring back fallen squadmate 使用增援战略配备复活阵亡的队友 +3360278549 Use Resupply Stratagem to call in supplies 使用重新补给战略配备,呼叫补给物资 +18895859 Use Seismic Probes to chart the Terminid tunnel networks in this region. 使用地震探测仪绘制该地区的终结族隧道网络。 +3405759123 Use Stims to heal your injuries and replenish your stamina—or that of your fellow Helldivers, in a pinch! 使用治疗剂可治疗伤势,补充耐力。危急关头,也可以救助绝地潜兵同伴! +1584528805 Use Stratagem: #ENTITY 使用战略配备:#ENTITY +643241865 Use Terminal to activate Communication Tower 使用终端启动通信塔 +1420875237 Use terminal to activate fuel transfer 使用终端,重新启动燃料运输 +649111536 Use terminal to activate surface-to-air launcher sub-systems 使用终端启动地对空导弹发射器子系统 +929233412 Use terminal to align communication signal 使用终端校准通信信号 +3658735782 Use terminal to calibrate generator voltage 使用终端,校准发电机电压 +3388756109 Use terminal to commandeer refinery 使用终端接管精炼厂 +2468812125 Use terminal to complete sabotage 使用终端完成破坏 +2066712812 Use terminal to complete takeover 使用终端完成占领 +3692892761 Use terminal to complete TCS+ activation 使用终端完成TCS+激活 +834060969 Use terminal to direct hydrogen into Power Core 使用终端将氢气导入动力核心 +3401560691 Use terminal to eject SSSD Hard Drive 使用终端弹出超级固态硬盘 +2696192217 Use terminal to establish communication with Super Destroyer 使用终端与超级驱逐舰建立通信 +1523476421 Use terminal to initiate emergency data backup 使用终端启动紧急数据库备份 +2191483918 Use terminal to initiate launch 使用终端,下令发射 +4243103919 Use terminal to lock the target coordinates 使用终端,锁定目标坐标 +3497544006 Use terminal to log in to research database 使用终端登录研究数据库 +1354134375 Use terminal to open bunker hatch 使用终端,打开掩体舱门 +4271378695 Use terminal to open silo hatch 使用终端,打开发射井舱门 +393933864 Use Terminal to open SSSD Delivery Hatch 使用终端打开超级固态硬盘运送舱门 +3409498073 Use terminal to raise Planetary Defense Cannon 使用终端抬升行星防御加农炮 +4070404232 Use terminal to raise satellite tower 使用终端抬升卫星塔 +1804508227 Use terminal to raise surface-to-air launcher 使用终端抬升地对空导弹发射器 +59567021 Use terminal to reactivate pumps 使用终端,重新启动泵机 +810653429 Use terminal to reset fuses 使用终端重置熔断器 +1048553999 Use terminal to sabotage Control Tower 使用终端破坏控制塔 +478584601 Use terminal to trace defense network 使用终端追踪防御网络 +2231291483 Use terminal to unlock Control Chamber 使用终端解锁控制室 +3660928596 Use terminal to upload virus 使用终端上传病毒 +3272915477 Use terminal to wipe sensitive data 使用终端抹除敏感数据 +1233839833 Use the #ITEM#COUNT_PRE#COUNT#COUNT_POST#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI. 使用#ITEM。#COUNT_PRE#COUNT#COUNT_POST#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI +2969926662 Use the WAR TABLE to travel to a war front. 使用议战桌前往战争前线。 +2918259917 Use the Cannon to shoot down the Overship 使用加农炮,击沉统御舰 +3769109997 Use the Eagle Rearm stratagem during calmer periods to ensure you have those Eagle Strikes available when you need them. 在比较空闲的时段使用重新武装“飞鹰”的战略配备,可以确保关键时刻你能呼叫“飞鹰”空袭。 +175011852 Use the GATER to extract anomalous material from all sites. 使用地面全地形采集钻机从所有地点提取异常物质。 +3313460170 Use the Hive Drill to destroy all subterranean Terminid structures in the area. 使用虫窝钻机摧毁该地区内所有终结族地下结构物。 +4211765665 Use the Portable Hellbomb to destroy the Hive Lung 使用便携式地狱火炸弹摧毁虫窝孢肺 +2293397614 Use Upload Data stratagem to begin upload 使用“上传数据”战略配备,开始上传 +1396651258 Used to transport ore, modular dwellings, and dissident holding pens. 用于运输矿石、模块化住房和异见分子的关押栏。 +2934051739 User is not currently signed in. 用户尚未登录。 +1956974167 Users are advised not to scratch at the lacquer, as the Red 20,000 pigment that gives this armor its signature sheen may be correlated with rapid DNA unspooling. 赋予盔甲标志性光泽的红色20,000颜料恐会导致DNA快速解旋,建议用户不要划伤漆面。 +2604642556 USES 使用次数 +1589265459 USES 使用次数 +2372506000 using the 使用: +2395107031 USTOTU 伍斯特图 +1330906044 Utilize the GATER to extract the E-711 from all identified sites. 使用GATER从所有确认地点提取711元素。 +1755054833 Utilize the GATER to extract the mysterious substance from all identified sites. 使用GATER从所有确认地点提取神秘物质。 +717047736 UTOPIA VAREN 瓦伦乌托邦 +2951703094 UVP ALPHA UVP阿尔法 +3749126267 UVP BETA UVP贝塔 +1019995927 UVP DELTA UVP德尔塔 +3227753500 UVP GAMMA UVP伽马 +2738708967 V-Sync 垂直同步 +2648074741 VACCA 瓦卡 +4194957957 VÁHTJER 瓦赫特耶尔 +3473770236 VALDIS SECTOR 瓦尔迪斯分区 +1582178959 VALGAARD 瓦尔加德 +381901259 VALIANT ENCLOSER 英勇围合战士 +3464528044 Validate data checksum to confirm data integrity 验证数据校验和,确认数据完整性 +740173750 VALMOX 瓦尔莫克斯 +4268295195 VALUE 色值 +1244395985 VANDALON IV 万达隆IV +584433110 VANDALON IV FREED +Vandalon IV has been freed from the Automatons. Take the fight to the next planet. 万达隆IV已解放 +万达隆IV已经挣脱了机器人的铁爪。该去下一颗星球作战了。 +430148665 VANDALON IV LOST +Vandalon IV has fallen to the Automatons. We cannot allow this travesty to go unanswered. 万达隆IV沦陷 +万达隆IV已落入机器人的铁爪。我们不能任由这一闹剧继续发展。 +3759870706 VANDALON IV UNDER ATTACK +Automaton dropships fill the skies of Vandelon IV. All Helldivers are called to its defense! 万达隆IV遭到袭击 +机器人的运输舰遍布万达隆IV上空。呼唤全体绝地潜兵,前去保卫该星球! +1825524640 Vanderheide 范德海德 +2531817086 VANQUISHMENT 征服市 +4131574864 Variable 变数 +1864827762 VARIABLE 变数 +925599844 Variable Rate Shading 可变速率着色 +2810431090 VARIANT ERADICATION 铲除亚种 +2200938833 Various Ministries report that the Void expanded rapidly without any warning from monitoring systems. Rirga Bay and Hort are assumed to have been consumed by the Void as Super Earth loses all communications with the planets. 各部委报告称,寂域正迅速扩张,尽管监测系统未发出任何警告。由于超级地球与这些星球全然失去联系,推测里尔加湾和哈尔特已被寂域吞噬。 +568622358 VARYLIA 5 瓦瑞拉亚5 +1850808595 VAULT CITY 金库市 +3653323664 Vector of Victory 胜利矢量 +3262991996 VECTOR OF VICTORY 胜利矢量 +2967304390 VEGA BAY 织女一湾 +3791435462 Vegetation and Rubble Density 植被与碎石密度 +1842143325 VEHICLE 载具 +3672987515 VEHICLE 载具 +4208767437 Vehicle Action Wheel Visibility 载具行动轮盘可视度 +2058166148 VEHICLE BAY 载具停靠港 +2090187556 Vehicle Camera Centering 载具视角居中 +2878227674 VEHICLE CUSTOMIZATION 载具自定义 +508599478 Vehicle Info Visibility 载具信息可视度 +1199118075 VEHICLE PATTERN 载具涂装 +4174933374 VEHICLES #COUNT/#TOTAL 载具 #COUNT/#TOTAL +2816576345 VEHICULAR VENGEANCE 载具式复仇 +1647662801 VEIL 帷幕 +1376207881 Veil of the Valorous Vagabond 英勇游侠之披纱 +2063997701 VEIL OF THE VALOROUS VAGABOND 英勇游侠之披纱 +1911274390 VELD 维尔德 +1125545112 VELD DEFENDED +The defense of Veld has succeeded. The Terminids have been repelled. 成功保卫维尔德 +维尔德保卫战以胜利告终,终结族已被击退。 +2130805532 VELD FREED +Veld has been liberated from the Terminid Menace. Take the fight to the next planet. 维尔德已解放 +维尔德已经挣脱终结族的魔爪。该去下一颗星球作战了。 +207804496 VELD LOST +We have failed to repel the bugs from Veld, and now they multiply in deep hives across the planet. We will return, to free it once more. 维尔德沦陷 +我们没能将虫族赶出维尔德,现在它们在遍布整颗星球的虫窝深处不断繁殖壮大。我们定会回转,重新解放维尔德。 +216208626 VELD UNDER ATTACK +The Terminids are attempting to spread to Veld. All Helldivers are called upon to deploy immediately to the planet's defense. 维尔德遭到袭击 +终结族企图扩张至维尔德。呼唤全体绝地潜兵,立即前去保卫该星球。 +1869845624 Velocity 速率 +398354838 VENDING MACHINE 自动售货机 +1588988532 Venerate 敬仰 +2843947910 VENERATE 敬仰 +617869677 VENERATION 敬仰市 +638999427 VENUS 维纳斯 +3776682558 Veracitor 证真者 +1927613493 VERACITOR 证真者 +3042667112 Veracitors 证真者 +385554983 Verdict 裁决 +163449559 VERDICT 裁决 +4040092621 Veridical Ideology 真理意识形态 +1444669283 VERIDICAL IDEOLOGY 真理意识形态 +1655329074 Verify all readings are within unsafe limits 确认所有读数都在非安全限度内 +1715589653 Verify post-landing integrity 核实着陆后完整性 +3318819568 VERIFY TRANSFER AT TERMINAL 在终端验证传输 +776586177 VERIFY TRANSFER CHECKSUM 验证传输校验和 +3584260041 VERNEN WELLS 佛农井 +1025260979 Vertical Field of View 垂直视野 +867992933 Vertical Foregrip 垂直前握把 +821632868 VERTICAL FOREGRIP 垂直前握把 +576792479 VERTICAL RECOIL 垂直后坐力 +3618005346 Vertically enhanced Jet Brigade soldiers are produced here. 经过垂直强化的喷气旅士兵就在这里出产。 +1657172675 VERVE 精力市 +2948935378 Very authentic and easy to put on. I am very satisfied! 货真价实,穿脱便捷。我很满意! +636332646 VERY HARD 极难 +3434970484 VERY LONG 非常长 +92731928 VERY SHORT 非常短 +3510721544 Veteran Controller Mode 老兵控制器模式 +4256281366 Veteran Controller Mode 老兵控制器模式 +2269430321 VETERAN'S BANNER 老兵旗帜 +4168280481 Veto 否决者 +739758268 VETO 否决者 +3314823015 VG-70 VG-70 +3457638201 VIBRANCY 活力市 +155683851 Vibration Strength 震动强度 +2096686340 Vicente 维桑特 +1372441245 Victory 胜利 +2095944889 VICTORY 胜利市 +3508647759 Victory Pose 胜利姿势 +3244995178 Victory Pose 胜利姿势 +3298793650 Victory Pose 胜利姿势 +2203290174 VICTORY POSE 胜利姿势 +1307370235 VIEW 查看 +2463758952 Vigorous Thrusting 盛气凌人 +4150712925 VIGOROUS THRUSTING 盛气凌人 +4260496089 VILHELMINA DOROTHEA FREDRIKA 维尔赫尔米娜·多罗茜娅·弗蕾德里卡 +1003401731 VINDEMITARIX PRIME 文德米塔里克斯主星 +2111649283 VINGE 云翼 +3786098155 VIOLATION PUNISHABLE BY DEATH OR WORSE 违法者可处以死刑或更严厉的处罚 +1699375645 VIPER COMMANDO 毒蛇突击兵 +2811274626 Viper Commandos 毒蛇突击兵 +2854071061 VIPER COMMANDOS 毒蛇突击兵 +2531725087 VIRIDIA PRIME 维尔伊迪亚主星 +110359831 Virydian Toys Corp. Deemed Not At 洛绿玩具公司无需 +3165349897 VISIBLE 显示 +861012034 Vision of Freedom 自由愿景 +1150283817 VISION OF FREEDOM 自由愿景 +822435040 VISUALS 图像 +1186649585 VITAL SYSTEM 关键星系 +2360256987 VITALITY BOOST 生命力增强 +3946144595 Vitality Enhancement 生命力强化 +3375151195 VITALITY ENHANCEMENT 生命力强化 +222072050 VOG-SOJOTH 佛戈索约斯 +1272804622 VOICE 1 声音 1 +509354804 VOICE 2 声音 2 +1992120651 Voice Chat 语音聊天 +3227748318 Voice Chat 语音聊天 +2967004302 VOICE CHAT ACTIVATION 启动语音聊天 +205809341 Voice Chat Transcription 语音聊天转录 +919752984 Voice Chat Volume 语音聊天音量 +1891074940 Voice of the People 人民之声 +1344503496 VOICE OF THE PEOPLE 人民之声 +1177118534 Voice Pack 语音包 +1223078174 Voice Pack 语音包 +1222028762 VOICE PACK 语音包 +803855769 VOID EXPLORATION 寂域探索 +3702357685 VOID GATEWAY 寂域通路 +2495065364 VOID INTERFERENCE 寂域干扰 +2144174422 Volatile Plasma Bolt 易气化等离子弹 +3939727225 VOLATILE PLASMA BOLT 易气化等离子弹 +2173681534 Volatile Plasma Igniter 易气化等离子点火器 +3064134875 VOLATILE PLASMA IGNITER 易气化等离子点火器 +3603056465 VOLCANIC ACTIVITY 火山活动 +3424531003 Volcanic Activity Detected 侦测到火山活动迹象 +1394558076 Volcanos throw burning rocks around this planet. 火山会将灼热的岩石喷射至这颗星球各处。 +4253970205 Volley 齐射 +846577287 VOLTERRA 沃尔泰拉 +678595308 VOLUME: #COUNT 音量:#COUNT +2787485826 Volumetric Clouds Quality 体积云质量 +1119060417 Volumetric Fog Quality 体积雾质量 +35708001 Vote 投票 +2232969418 VOTE 投票 +3161593322 VOTE FAILED 投票失败 +1173246150 VOTE SNATCHERS 窃票者 +157403948 VOTE SUCCESSFUL 投票成功 +1657196527 VOTED 已投票 +2817045657 Voteless 无票者 +4211847317 Voteless 无票者 +632178296 VOTELESS 无票者 +3488776402 VOTELESS PROCESSING PLANT 无票者转化处理厂 +184619790 VOTER'S FALLOW 选民荒地 +1830005331 VOTING DISTRICT F-012357 F-012357选区 +3380905028 VOTING FAILED 投票失败 +1652084725 Voting failed, please try again. 投票失败,请重试。 +4066406510 Vox Engine 噪轰引擎 +1368779007 VOX ENGINE 噪轰引擎 +755328709 Vox Engines 噪轰引擎 +3994324289 vs. Genetically-Altered Giant Turtles. Tickets on Sale! 对基因改造的巨龟。门票特惠,售完即止! +1230498468 W 西 +2004685136 W 西 +504355811 W (#COUNT°) 西#COUNT° +2816181366 W.A.S.P. Launcher W.A.S.P.发射器 +1085917305 W.A.S.P. LAUNCHER W.A.S.P.发射器 +3647497209 W.A.S.P. Launcher Backpack W.A.S.P.发射器背包 +264352850 W.A.S.P. LAUNCHER BACKPACK W.A.S.P.发射器背包 +1210569969 Wait 请稍候 +229508142 WAIT 等等 +85322608 Wait for artillery system to initiate 等待大炮系统启动 +1608834297 Wait for Data Jack to deploy 等待数据接口部署 +1802135572 Wait for generator diagnostics sequence to complete 请等待发电机诊断程序完成 +4254208535 Wait for power charge 等待充电 +2284375065 Wait for reroute to complete 等待完成重新路由 +2054436670 WAITING FOR BEACON 正在等待信标 +250176528 Waiting for Host 正在等待主办者 +1826913012 Waiting For Players 等待玩家加入。 +2499260075 WAITING FOR PLAYERS 正在等待玩家 +2153587569 Waiting for players 00:#MINS 等待其他玩家加入 00:#MINS +1234386790 Waiting for players 00:#MINS 等待其他玩家加入 00:#MINS +4204316645 Waiting for Super Earth approval of purchase... 正在等待超级地球批准购买… +3030272495 WALKAWAY 逍遥道 +2819645409 WALNUT ACRES 胡桃木埃克斯 +2416660199 Want to show off how firmly you support capitalism? Spend medals on a Warbond! 想要展示你支持资本主义的决心?为战争债券多花费一些奖章吧! +304838764 War - #HOURS:#MINUTES:#SECONDS 战争 - #HOURS:#MINUTES:#SECONDS +631381900 War Horses 战马 +346834056 WAR HORSES 战马 +1364087615 WAR IMPACT 战争冲击 +4152541200 WAR INFLUENCE: #WAR_INFLUENCE 战争影响力:#WAR_INFLUENCE +2961397754 WAR SONG TOPS CHARTS 战歌高居音乐榜首 +523260929 War Strider 战争纵步者 +1487385132 WAR STRIDER 战争纵步者 +339057435 War Striders 战争纵步者 +1104478706 WARBOND MEDAL 战争债券奖章 +2754737932 WARBOND MEDAL 战争债券奖章 +3636902427 WARBOND MEDAL 战争债券奖章 +854444579 WARBOND PROGRESSION 战争债券进度 +2715652416 WARBOND PROGRESSION 战争债券进度 +2792401146 WARBONDS 战争债券 +815219129 WARHEAD 弹头 +1009070099 Warning: Critically Unstable 警告:状态极其不稳定 +3874453496 Warning: Silo susceptible to damage while charging 阻止终结族靠近电池舱 +1341626796 Warning: Starting a new Operation will abandon your currently active Operation 警告:开始新行动将终止目前进行中的行动。 +1977308076 WARNING: STATION INOPERABLE 警告:站点无法运转 +3297441256 Warning: Stay Clear of Launchers 警告:请远离发射器 +76944018 WARP GATEWAY 传送门 +2771179215 Warp Pack 传送背包 +3940822269 WARP PACK 传送背包 +3579113113 Warp Ship 穿梭舰 +166687808 WARP SHIP 穿梭舰 +4224862544 Warp Ships 穿梭舰 +2184876447 Warrant 法令 +2985774568 WARRANT 法令 +100334534 Warrior 武士 +3564923972 Warrior 武斗虫 +1723671216 WARRIOR 武斗虫 +4050848585 Warriors 武斗虫 +963452240 WarwLzard66 战争诬师66 +3939430458 WASAT 天樽二 +1727897935 WASTEMOUNT 韦斯特蒙特 +1813736098 Watch out for alien storms. Super Earth scientists have officially classified many of them as dangerous. And freaky. 小心外星风暴。超级地球的科学家们已经正式宣布许多种风暴不仅危险,而且十分反常。 +2616020441 Watch: A Helldiver Returns To His Robo-Canine Partner After 4-year Deployment. 观察:绝地潜兵执行任务4年终于回到机器狗伴侣身边 +702284474 WATCHDOG 5 守犬5 +886803190 Watcher 守望者 +3628262152 WATCHER 守望者 +462878521 Watchers 守望者 +4270320858 Watchful Compatriot 守望同胞 +979608541 WATCHFUL COMPATRIOT 守望同胞 +2839780331 Wave #WAVE_NUMBER 第#WAVE_NUMBER波攻势 +1420091860 Way of the Bandolier 弹带之道 +3328664087 WAY OF THE BANDOLIER 弹带之道 +3661515115 Waypoints you have placed on the map are visible on your compass 你在地图上设置的路径点会显示在罗盘上 +664680323 WAYWARD 逸泊 +2517836643 We are passively re-gaining ground on Planet #V_ONE. 我们正在被动夺回#V_ONE星球的阵地。 +3414412610 We are Sony Interactive Entertainment. Please see our privacy policy for further information on how we collect and process your Personal Information, and how to contact us at www.playstation.com/legal/privacy-policy. 我们是索尼互动娱乐有限公司。有关我们如何收集和处理你的个人信息以及如何通过 www.playstation.com/legal/privacy-policy与我们联系,请参阅我们的隐私政策了解详情。 +3561698279 We defend Democracy's Future. + +The Ministry of Defense. 捍卫民主的未来。 + +国防部 +4003196211 We have discovered extensive Automaton mining and processing operations on this previously uninhabited planet. This lava-covered world is rich in mineral resources, but constant eruptions and a noxious atmosphere makes it unsuitable for human habitation. + +The Automatons are recklessly exploiting the natural riches of this planet, stealing them from our citizens and transforming them into tools of Socialist oppression. We must stop them, annex their industry, and seize their stolen goods. 我们发现机器人在这颗此前无人居住的星球上进行大规模采矿和加工作业。这颗被熔岩覆盖的星球矿物资源丰富,但上面的火山持续喷发,大气环境有毒,不适合人类居住。 + +机器人肆意开采这颗星球的自然财富,从我们公民手中窃取资源,并转化为党同伐异的工具。我们必须阻止它们,吞并它们的产业,夺回被盗的物资。 +2457977188 We have failed to clear the way to the Barrier Planets in time. This will severely impact implementation of the Terminid Control System. A disappointing outcome. 我们未能及时打通前往屏障星球的路线。终结族遏制体系的构建会受到严重的影响。这个结果实在是令人失望。 +2503033309 We have identified a number of heavily-guarded bunkers in this region. We suspect they contain Command Nodes central to linking in to the Automaton Transmission Stream. + +Destroy the bunkers, and cut the bots off from the flow of information. 该地区内发现有多座防备森严的碉堡。我们怀疑其中存在连接机器人数据传输流的重要指挥节点。 + +摧毁这些碉堡,切断机器人的信息传输。 +3854725346 We have identified the source of the Gloom: large subterranean fruiting bodies known as Spore Lungs. Larval Terminids within the Lungs appear to produce the Gloom spores, while the Lung itself pumps it into the exosphere. + +The exact biology is unimportant. Delve deep into the Hive and detonate a Hellbomb within to eradicate the Spore Lung. 我们已确认“阴霾”的源头是被称为“孢肺”的巨型地下子实体。该结构内的终结族幼虫似乎会产生“阴霾”孢子,再由孢肺泵入大气外逸层。 + +眼下最重要的不是弄清楚其中具体的生物学原理。而是要深入虫窝内部,引爆地狱火炸弹,彻底毁灭孢肺。 +3239007371 We have located a key facility in the Automaton's mining operations. Platinum ore is extracted, refined, and shipped to other facilities for further processing. + +These assets have been deemed forfeit to the Federation. Seize them. 我们已找到机器人采矿作业的关键设施。它们在此开采和加工铂金矿石,然后运往其他设施进行深加工。 + +这些资产已认定为归联邦所有。夺取它们。 +3306914533 We have received credible reports of brutal Automaton Hulks in the region. Destroying them would weaken the Automaton command structure. + +Locate the Hulks, and eliminate them. 据可靠消息称,该地区内存在着残暴的机器人巨型者。将其摧毁可以削弱机器人的指挥结构。 + +找到巨型者,将其消灭。 +4214767359 We have received reports from this region of Brood Commanders exhibiting dangerous new mutations. + +Find and eliminate them before they can breed. 我们收到了来自该地区的报告。据称,虫族指挥官表现出危险的新型突变属性。 + +在此类生物繁殖之前找到它们并将其消灭。 +1737162772 We have received reports of the presence of Bile Titans in this region, posing a considerable threat to our operations. + +Any specimen encountered must be eliminated before it has a chance to breed. 我们收到的报告显示,该地区内出没的吐酸泰坦对我们的行动构成了巨大的威胁。 + +一旦遇到该生物,立即将其消灭,以防其繁殖。 +1150338544 We must seize this opportunity to destroy the Terminid Supercolony. Helldivers all across the planet will deploy with a limited supply of the exotic matter known as Dark Fluid, and insert it at critical points in the planet's crust. + +Once critical mass is reached, the planet will collapse into a black hole, destroying the threat to Liberty once and for all. 我们必须抓住这次机会,摧毁终结族超级拓殖地。全星球的绝地潜兵将携带名为“暗液体”的限量供应奇异物质上阵,须将这种物质注入星球地壳的临界点。 + +一旦达到临界质量,星球就会坍缩成黑洞,彻底摧毁所有威胁自由的敌人。 +2144732626 We must show the galaxy that even in the face of oppression, Freedom remains defiant. + +Infiltrate behind Automaton lines and raise our Flag as an unassailable beacon of Liberty. 我们必须让整个银河系都知道,纵使面对压迫,自由仍傲然不屈。 + +潜入机器人的防线后方,升起我们的旗帜,犹如树立起一座坚不可破的解放灯塔。 +1276323300 We must show the galaxy that even in the face of oppression, Freedom remains defiant. + +Infiltrate this Terminid-infested region and raise our Flag as an unassailable beacon of Liberty. 我们必须让整个银河系都知道,纵使面对压迫,自由仍傲然不屈。 + +潜入终结族占据的这个地区,升起我们的旗帜,犹如树立起一座坚不可破的解放灯塔。 +1954555863 We stay INFORMED to inform YOU. + +The Ministry of Truth. 追求真理,传播真理。 + +真理部 +3887608622 WEAK 弱 +2981863855 WEAPON CUSTOMIZATION 武器自定义 +3987967654 Weapon Customization is now available. Click the CUSTOMIZE button to begin adjusting your weapon. 武器自定义内容现已解锁。点击自定义键开始调整武器。 +1879826530 WEAPON CUSTOMIZATION UNLOCKED 武器自定义已解锁 +4152168219 WEAPON EXPERIMENTATION +The AC-8 Autocannon stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“AC-8机炮”战略配备暂时获准供全体绝地潜兵使用。 +3612035102 WEAPON EXPERIMENTATION +The Autocannon Sentry stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“自动哨戒炮”战略配备暂时获准供全体绝地潜兵使用。 +1669765041 WEAPON EXPERIMENTATION +The Ballistic Shield Backpack stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“防弹护盾背包”战略配备暂时获准供全体绝地潜兵使用。 +970783414 WEAPON EXPERIMENTATION +The Eagle 500kg Bomb stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“‘飞鹰’500kg炸弹”战略配备暂时获准供全体绝地潜兵使用。 +3053765686 WEAPON EXPERIMENTATION +The Eagle Napalm Airstrike stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“‘飞鹰”凝固汽油弹空袭”战略配备暂时获准供全体绝地潜兵使用。 +789440696 WEAPON EXPERIMENTATION +The FLAM-40 Flamethrower stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“FLAM-40火焰喷射器”战略配备暂时获准供全体绝地潜兵使用。 +31952089 WEAPON EXPERIMENTATION +The GL-6 Grenade Launcher stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“GL-6榴弹发射器”战略配备暂时获准供全体绝地潜兵使用。 +309304609 WEAPON EXPERIMENTATION +The Guard Dog Rover stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“‘护卫犬’漫游车”战略配备暂时获准供全体绝地潜兵使用。 +2729513910 WEAPON EXPERIMENTATION +The Guard Dog stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“护卫犬”战略配备暂时获准供全体绝地潜兵使用。 +903929422 WEAPON EXPERIMENTATION +The Heavy Machine Gun Emplacement stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“重机枪部署支架”战略配备暂时获准供全体绝地潜兵使用。 +3799803411 WEAPON EXPERIMENTATION +The Jump Pack stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“喷射背包”战略配备暂时获准供全体绝地潜兵使用。 +1793666817 WEAPON EXPERIMENTATION +The LAS-98 Laser Cannon stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“LAS-98激光大炮”战略配备暂时获准供全体绝地潜兵使用。 +752121942 WEAPON EXPERIMENTATION +The Mortar Sentry stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“迫击哨戒炮”战略配备暂时获准供全体绝地潜兵使用。 +1020532600 WEAPON EXPERIMENTATION +The Orbital 380mm HE Barrage stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“轨道380mm高爆弹火力网”战略配备暂时获准供全体绝地潜兵使用。 +495597554 WEAPON EXPERIMENTATION +The Orbital EMS Strike stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“轨道电磁冲击波攻击”战略配备暂时获准供全体绝地潜兵使用。 +3978253915 WEAPON EXPERIMENTATION +The Orbital Gas Strike stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“轨道毒气攻击”战略配备暂时获准供全体绝地潜兵使用。 +2800191259 WEAPON EXPERIMENTATION +The Orbital Laser stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“轨道激光炮”战略配备暂时获准供全体绝地潜兵使用。 +537232563 WEAPON EXPERIMENTATION +The Orbital Railcannon stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“轨道炮”战略配备暂时获准供全体绝地潜兵使用。 +2659382106 WEAPON EXPERIMENTATION +The RS-422 Railgun stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“RS-422磁轨炮”战略配备暂时获准供全体绝地潜兵使用。 +2251893773 WEAPON EXPERIMENTATION +The SAR-1 Sniper Rifle stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“SAR-1狙击步枪”战略配备暂时获准供全体绝地潜兵使用。 +4049208789 WEAPON EXPERIMENTATION +The Shield Generator Pack stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“防护罩生成包”战略配备暂时获准供全体绝地潜兵使用。 +1766819433 WEAPON EXPERIMENTATION +The Shield Generator Relay stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“防护罩生成中继器”战略配备暂时获准供全体绝地潜兵使用。 +68914610 WEAPON EXPERIMENTATION +The ST-1 Stinger stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“ST-1毒刺”战略配备暂时获准供全体绝地潜兵使用。 +789486835 WEAPON EXPERIMENTATION +The Tesla Tower stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“特斯拉塔”战略配备暂时获准供全体绝地潜兵使用。 +2300981817 WEAPON EXPERIMENTATION +The TS-4 Arc Thrower stratagem has been temporarily authorized for use by all Helldivers. 武器试验 +“ ARC-3电弧发射器”战略配备暂时获准供全体绝地潜兵使用。 +998276167 WEAPON FUNCTION 1 武器功能1 +3958424697 WEAPON FUNCTION 2 武器功能2 +2971105635 WEAPON FUNCTION 3 武器功能3 +688949496 Weapon Function Visibility 武器功能可视度 +1270852926 WEAPON PROGRESSION 武器进阶 +1452088920 WEAPON SKIN 武器涂装 +766584831 WEAPON STATS 武器数据 +2227427360 Weapon Status Visibility 武器状态可视度 +1086265916 Weapon Switch Mode 武器切换模式 +1806799332 WEAPON TRAITS 武器特性 +2424573116 WEAPON WHEEL DOWN 向下转动武器轮盘 +549865373 WEAPON WHEEL LEFT 向左转动武器轮盘 +1971147390 WEAPON WHEEL RIGHT 向右转动武器轮盘 +1838143030 WEAPON WHEEL UP 向上转动武器轮盘 +3804742152 WEAPONRY 武器 +2597877971 Weapons 武器 +1100499816 WEAPONS 武器 +77306762 WEAPONS EXPERIMENTATION 武器试验 +104772162 WEAPONS EXPERIMENTATION 武器试验 +159552540 WEAPONS EXPERIMENTATION 武器试验 +249507806 WEAPONS EXPERIMENTATION 武器试验 +399173704 WEAPONS EXPERIMENTATION 武器试验 +440415104 WEAPONS EXPERIMENTATION 武器试验 +502012056 WEAPONS EXPERIMENTATION 武器试验 +530653442 WEAPONS EXPERIMENTATION 武器试验 +740677481 WEAPONS EXPERIMENTATION 武器试验 +826900961 WEAPONS EXPERIMENTATION 武器试验 +990366181 WEAPONS EXPERIMENTATION 武器试验 +1032974617 WEAPONS EXPERIMENTATION 武器试验 +1077822980 WEAPONS EXPERIMENTATION 武器试验 +1181673243 WEAPONS EXPERIMENTATION 武器试验 +1199081198 WEAPONS EXPERIMENTATION 武器试验 +1335028754 WEAPONS EXPERIMENTATION 武器试验 +1432392942 WEAPONS EXPERIMENTATION 武器试验 +1460918234 WEAPONS EXPERIMENTATION 武器试验 +1552724045 WEAPONS EXPERIMENTATION 武器试验 +1574302876 WEAPONS EXPERIMENTATION 武器试验 +1766908181 WEAPONS EXPERIMENTATION 武器试验 +2074393271 WEAPONS EXPERIMENTATION 武器试验 +2129095230 WEAPONS EXPERIMENTATION 武器试验 +2189446260 WEAPONS EXPERIMENTATION 武器试验 +2718162576 WEAPONS EXPERIMENTATION 武器试验 +2859517006 WEAPONS EXPERIMENTATION 武器试验 +2923344480 WEAPONS EXPERIMENTATION 武器试验 +2969104525 WEAPONS EXPERIMENTATION 武器试验 +2977252622 WEAPONS EXPERIMENTATION 武器试验 +3036081418 WEAPONS EXPERIMENTATION 武器试验 +3099561362 WEAPONS EXPERIMENTATION 武器试验 +3226304447 WEAPONS EXPERIMENTATION 武器试验 +3293632592 WEAPONS EXPERIMENTATION 武器试验 +3726538024 WEAPONS EXPERIMENTATION 武器试验 +3802611417 WEAPONS EXPERIMENTATION 武器试验 +3833236254 WEAPONS EXPERIMENTATION 武器试验 +4082794250 WEAPONS EXPERIMENTATION 武器试验 +4091665372 WEAPONS EXPERIMENTATION 武器试验 +4136698015 WEAPONS EXPERIMENTATION 武器试验 +4169143112 WEAPONS EXPERIMENTATION 武器试验 +4281386727 WEAPONS EXPERIMENTATION 武器试验 +4179127827 Weapons like pistols and submachine guns can be used with one hand—perfect for when you need to carry objects in the other hand. 手枪和冲锋枪等武器是可以单手使用的,非常适合在另一只手执物体时使用。 +154117770 WEAPONS QUALIFICATION 武器资质 +184178740 WEAPONS QUALIFICATION 武器资质 +1907510616 WEAPONS QUALIFICATION 武器资质 +3470508852 WEAPONS QUALIFICATION 武器资质 +2341805933 Wearer makes #BONUS less noise when moving. 穿戴者移动时产生的噪音减少#BONUS。 +432713945 Wearers of this cape know that even enemies of Freedom deserve to be equal. Equally dead. 穿上这件披肩的战士都明白,即使是自由的敌人,也值得平等对待,让他们平等地死去。 +4289418781 Wearers of this stealthy armor are seldom seen by their targets—or squadmates. No refunds if misplaced. 穿戴这套潜行盔甲的人鲜少被目标(或队友)发现。如被队友误认,恕不退款。 +1158974024 Weather Reconnaissance aircraft that were in operation when the Gloom originally spread to this planet may contain useful data on Gloom-infused atmosphere. + +Find their black boxes and use a local relay station to decrypt and upload the research data to the Ministry of Science mainframe. 在“阴霾”最初蔓延至该星球时,恰有气象侦察机在空中作业,或许能提供有关“阴霾”侵袭大气层的有用数据。 + +找到黑匣子,利用当地中继站解密研究数据并上传至科学部主机。 +2036289419 Wedgeful Tricorn 楔形三角披肩 +1754694292 WEDGEFUL TRICORN 楔形三角披肩 +1021417441 Weekly 每周 +3289665011 Welcome to Voragon Systems Generic Military Terminal. 欢迎使用沃瑞肯系统通用型军用终端。 +3484407334 WELCOME ADORATION 尽情崇拜 +3066659304 WELCOME SIGN - HOMELY VARIANT 02 欢迎标牌 - 家常版02 +22428682 Welcome to the Galactic Map - This is where you navigate your Destroyer to the frontlines and select Missions to play. + +In the galactic war, the entire Helldivers Community fights together against the enemies of Super Earth. 欢迎查看银河地图 - 你将在此指挥驱逐舰奔赴前线,并且选择你要执行的任务。 + +在星系战争中,整个绝地潜兵社区都在共同对抗超级地球的敌人。 +322782799 Welcome to the Galactic War. + +Here the community fights together against its common enemies. 欢迎参加星系战争。 + +全体绝地潜兵在此齐心协力对抗共同的敌人。 +1902198544 Wesolowski 韦索洛夫斯基 +2570163700 WEST BROKER 西贸经纪区 +940091660 WEST MANAGEMENT 西治市 +3383944595 WEZEN 弧矢一 +4218706212 What are you waiting for? 你还在等什么? +273743268 WHAT DO THE GAME SETTINGS CONTROL? 游戏设置可以控制什么? +4291692188 WHAT DO WE USE GAME DATA FOR? 我们使用游戏数据的目的是什么? +916343357 WHAT IS GAME DATA? 游戏数据是指什么数据? +4273486865 When carrying something in one hand, you can only wield one-handed weapons. 其中一只手携带物体时,你只能持有单手武器。 +3239753995 When children have trouble sleeping, tucking them in under this cape reminds them that they are never alone, for Liberty's unseen defenders are always watching over them. 为难以入睡的孩子盖上这件披肩,提醒他们并不孤单,看不见的自由卫士一直守护在侧。 +1647614316 When donning the One True Flag, one must face the direction of Super Earth, recite the Super Earth Anthem, and salute one's own image in the nearest reflective surface. Wrongful discarding of this cape is a capital offense. 身披这件印有“唯一真旗”的披肩时,必须面朝超级地球,唱响超级地球国歌,并向最近反光面中的自己敬礼。错误丢弃此披肩者,罪当处死。 +2035183884 When enabled, raw mouse input is used. At low frame rates disabling this may lead to smoother mouse input at the cost of slightly higher latency. 启用时,使用原始鼠标输入。在低帧数下禁用该选项可能会导致鼠标输入变得更加流畅,但也会略微增加延迟。 +1583207890 When enabled, voice transcription is used as an input source for text chat. Enabling this may cause additional configuration windows to appear for initial setup on a new device. 启用时,语音转录将被用作文字聊天的输入源。启用该选项后可能会出现额外的设置窗口,用于在新设备上完成初始设置。 +3329249686 When enemy infrastructure is in need of destruction, Super Earth helpfully provides a Hellbomb stratagem to all Helldivers, free of charge. 如果有敌方的基建亟需摧毁,超级地球会施以援助,为所有绝地潜兵提供一枚地狱火炸弹,不收取任何费用。 +4032607812 When facing the enemies of Freedom this Reckoningtide, keep up the festive spirit by recalling the opening line of A Vengeant Carol: "They'll soon be dead, to begin with." 在这个清算时节面对自由之敌时,请牢记《复仇颂歌》的开场白,坚守我们的节日精神:“它们很快就会死去,这是故事的开始。” +55215852 When in doubt, don't think—simply shout "For Democracy!" and charge head-first into your problems. 困惑之时,不要思考——只需大喊 “为了民主!”,然后勇敢地冲锋陷阵。 +3819953344 When on, automatically adjusts render resolution to achieve target framerate. 开启后将自动调整渲染分辨率以达到目标帧率。 +3629395632 When playing solo, auto-reinforce is active and you will automatically drop down in a Hellpod on death. 单人游戏启用自动增援。阵亡后,你将自动乘坐绝地喷射舱降落。 +1661508052 When the enemy successfully calls for reinforcements, threat level increases. + +This means higher enemy presence for the duration of the mission. 当敌人成功呼叫增援,威胁等级便会提升。 + +也就是说,任务期间敌人数量更多。 +907460586 When the Illuminate threatened Super Earth, the very Heart of Democracy, the Helldivers answered the call. 当光能者威胁超级地球这颗民主之心时,绝地潜兵应召而战。 +3989053456 When the mission timer runs out, the Super Destroyer will leave low orbit and you'll lose access to stratagems and reinforcements. 任务倒计时结束后,超级驱逐舰就会离开低空轨道。之后,你无法再使用战略配备,也无法呼叫增援。 +416307315 When the wearer takes damage, they regain some stamina. 穿戴者受到伤害时恢复部分体力。 +2475549888 When wearers stand shoulder to shoulder, this cape shows them as they truly are: an unbreakable defense, keeping Freedom safe behind an impregnable wall. 肩并肩穿戴披肩站立时,便会展现真实风采:化身坚不可摧的防线,将自由守护在固若金汤的墙后。 +3970820792 When you're prone you fire more accurately. 匍匐姿态下射击更精准。 +3293136271 When you're up against the bots, remember the 3 Cs: +Cover, Courage, and more Cover. 对抗机器人要牢记三大准则: +找掩体,要勇敢,然后继续找掩体。 +2323712408 When your stamina is depleted, your sprint speed is slower and your accuracy is worse. 耐力耗尽以后,你的冲刺速度和命中率都会下降。 +3284598023 Whether this Automaton can ever have been said to be alive is a question for the philosophers. In either case, it is definitely dead now. 这个机器人能否算得上“活着”是个哲学问题。但不论它有没有“活过”,现在肯定已经死透了。 +607365520 While early prototypes used shock-absorbing gels, this armor stabilizes aim with the use of internal gyroscopes. 早期原型曾使用减震凝胶,而此盔甲利用内置陀螺仪稳定瞄准动作。 +4246223436 While in reverse, braking input will throttle, and throttling will brake. 倒车时,刹车变油门,油门变刹车。 +292648953 while map is open to look around the map 在地图打开时浏览地图 +1630466920 While most Terminids were killed by the Termicide, some survived and adapted. Now, they threaten to evolve further and take over the entire planet. Every Termicide Dispersion Tower on this planet must be shut down as soon as possible. 尽管灭虫终结剂消灭了大部分终结族,但是仍有一部分幸存了下来,并且适应了灭虫终结剂。现在,它们甚至有可能进一步进化,占领整颗星球。必须尽快关闭这颗星球上的每一座灭虫终结剂喷洒塔。 +46540775 While the Helldiver training program is undeniably infallible, you can always repeat your training from the game menu. 绝地潜兵训练项目当然是完美无缺的,但是你随时可以在游戏菜单中再次参加训练。 +2537357154 While using a jump pack, knock yourself into a ragdoll state. 使用喷射背包时,让自己陷入僵直状态。 +3235683262 Whisper 的低语 +1034277673 Who can say what heinous deeds this machine was intended to carry out? 谁知道它们打算用这台机器干出何等令人发指的罪行? +816596200 WIDE 宽 +1256045010 Wide Prism 加宽棱镜 +1966586923 WIDE PRISM 加宽棱镜 +1515040346 Wide Spread 扩散 +4082023109 WIDOW'S HARBOR 寡妇港 +1928893546 Wiklund 维克隆德 +4165395098 WILE 千惑 +2188495010 WILFORD STATION 威尔福德站 +4207312615 Will 意志 +2202550849 Will of the People 人民的意志 +3054225665 WILL OF THE PEOPLE 人民的意志 +3548141040 Winaldy 维纳尔蒂 +2271314631 Window 窗口 +413620605 Window Notifications 窗口通知 +783083856 Windswept Wayfinder 风驰引路者 +3753743289 WINDSWEPT WAYFINDER 风驰引路者 +3269908804 Winganon_59 温加农_59 +1503418004 Wings 之翼 +297881557 Wings of Valor 勇气之翼 +1168428838 WINGS OF VALOR 勇气之翼 +2520271295 Wirz 维尔斯 +2006144803 WITH CORETTA KELLY 主持人:科雷塔·凯利 +2416187473 With extra capacity for storing throwable munitions, this armor ensures every enemy stronghold can be tactically ventilated, as per forceful de-fortification protocols. 这套盔甲具备收纳投掷弹药的额外空间,可确保对每个敌军据点以符合“强制去工事化协议”的方式进行“战术通风”。 +449364219 With genuine gold accents, 74% of colonists voted this armor the set they would most like to be buried in. 真金装饰。74%拓殖地居民投票表示死后最希望穿这套盔甲下葬。 +2111302236 With its rustic charm and huntsmanlike detailing, this armor evokes those heroic expansionists who braved the alien wilds and ushered in our current age of bio-uniformity. 这套盔甲充满猎装细节,质朴的风格另有一番魅力,唤起人们对英雄开拓者的敬意,正是前辈勇闯异星荒野,引领我们迈入当今的生物统一时代。 +504678613 With its two barrels, one trigger, and vintage feel, this shotgun is perfect for historical reenactments. 双管单扳机的复古设计,这把霰弹枪是重现历史场景的绝佳道具。 +2167258369 With sharp geometric angles to symbolize the rigid chain of command, this cape embodies the sanctity and moral fortitude of unblemished leadership over the mud-caked warriors they direct. 用锐利的几何棱角象征严苛的指挥链,这件披风体现了完美无瑕的将领在统御满身泥泞的战士时,所闪耀的神圣光辉与道德毅力。 +500173640 With the arrival of Freedom to this newfound world, the bugs have been driven into a fascist frenzy. Their destructive urge is denying our citizens the prosperous future they were always meant to inherit on this soil. + +A new generation of TCS+ towers stands ready to neutralize this threat and ensure total planetary safety through controlled fumigation. See that they are activated and fully operational. 随着自由降临这片新世界,虫族陷入法西斯般的狂暴状态。它们按耐不住肆意破坏的冲动,正在剥夺我们的公民自始至终理应在这片土地上继承的繁荣未来。 + +新一代TCS+塔已准备就绪,将通过可控式熏杀手段铲除这一威胁,保障星球的绝对安全。务必确保TCS+塔成功启动并全面投入运行。 +3823751890 With the borders of the Void contained and the Mindless Masses pushed back, Helldivers drove Democracy into the skulls of the Illuminate. The Ministry of Science has ample material from Voteless who emerged from the Void and will begin learning what they can about conditions within the Void. + +Victory belongs to Super Earth. + +Any damages to allocated FRVs will be taken from Helldiver pay. 随着寂域的边界得到控制,无脑群氓被击退,绝地潜兵将民主狠狠砸入光能者的脑壳。科学部已经从寂域中涌出的无票者身上取得充足的材料,并将开始尽其所能地研究寂域内部的情况。 + +胜利属于超级地球。 + +配给快速侦察载具的损坏费用将从绝地潜兵的薪水中扣除。 +2661853600 With this cape we honor the bio-warfare pioneers of Division Zero, conscripted from quarantine zones and hospices to spread their Carcino-Plague on the battlefield. 我们设计这件披肩是为了向“零号”师的生物战先驱致敬。他们从隔离区和临终关怀医院应征入伍,在战场上传播他们携带的卡西诺瘟疫病毒。 +3749728924 Within this laboratory, vile experiments twist upstanding citizens into grotesque thralls. 在这座实验室内,邪恶的实验将正直的公民扭曲为丑陋的奴仆。 +203787011 Without power, this vendor of beverages is only a lifeless husk. Another innocent casualty of Tyranny. 没了电,这台自动饮料售货机不过是一具空壳,也是暴政的无辜受害者。 +2484985017 Without the Destroyer nearby, normal Reinforcements are unavailable. + +Clusters of Reinforcement Pods have been deployed throughout the area. Once activated, you will be able to utilize those reinforcements. 如果驱逐舰不在附近,就无法使用常规增援。 + +我方已在该区域各处部署多部增援舱。激活后即可使用这些增援。 +1301405564 WNW 西北偏西 +3934806965 WNW (#COUNT°) 西北偏西#COUNT° +2115010351 Wolterbeek Muller 沃尔特贝克·穆勒 +1373264655 WORDS SCRIBBLED ON BOMB 炸弹上的潦草文字 +4011376215 WORKHOUSE 239-C 救济所239-C +2229584013 WORKSONG 劳歌市 +2802985877 WORLD LIBERATED 解放的星球 +3570977272 Worthwhile Sacrifice 死得其所 +867908736 WORTHY I 英杰I +3176556315 WOULD YOU ENLIST TO FIGHT THE AUTOMATONS? 你是否愿意应征入伍,对抗机器人? +1739684799 Would you like to reconnect to your last squad? 你希望与上个小队重新建立连接吗? +3187441995 Woven for the trailblazers who successfully led the way during the first sanctioned deployment of a new tactical paradigm. This cape’s bold shoulder mount design ensures that while the Helldiver continues to ever look toward the future, enemies of Freedom shall gaze upon an extinction of their own making. 专为在首个获批全新战术范式部署中成功领跑的开拓者们织就。这件披风采用大胆的肩部挂载设计,旨在确保当绝地潜兵继续放眼未来时,自由的敌人却将亲眼见证其自取灭亡的下场。 +2782235542 Woven from coarse, industrial fibers designed to absorb sweat and oil, this cape features a spade emblem to honor Super Earth's groundbreakers, who ensure Liberty’s light finds its way through any planet’s crust. 采用粗糙的工业纤维织就,旨在吸收汗水与油污。这款披风饰有铁锹纹章,致敬为超级地球“破土奠基”的先辈们——感谢他们确保自由之光能穿透任何星球的地壳。 +3063232163 Woven in honor of our loyal citizens, who by raising their voices have supported the war effort more than they can ever know. 这件披肩旨在纪念忠诚的公民,他们大声疾呼,为战争提供了超乎想象的支持。 +2852851210 Woven in honor of our loyal Helldivers, whose commitment to Democracy, through rain or shine, is an inspiration to all. 这件披肩旨在纪念忠诚的绝地潜兵,他们风雨无阻地坚守对民主的承诺,激励着所有人。 +3627624756 Woven in honor of our loyal Helldivers, whose heart's blood is the foundation on which Super Earth is built. 这件披肩旨在纪念忠诚的绝地潜兵,他们的一腔热血是超级地球的发展根基。 +778160541 WRAITH 幽灵 +3349510183 WRESTLE 掰手腕 +3926987470 Wrestle (MASH) 摔角(MASH) +2118086817 Wretch 悲怜体 +2244644008 WRETCH 悲怜体 +2473223615 Wretches 悲怜体 +3294191248 WSW 西南偏西 +1828456541 WSW (#COUNT°) 西南偏西#COUNT° +4042552256 x_Roocketman_x x_火箭新手_x +2592040639 X- AXIS X-轴 +2901475147 X-45 X45 +2587365295 x#COUNT x#COUNT +1713492572 x#VALUE x#VALUE +308939854 X+ AXIS X+轴 +709014848 x10 Rare Samples x10稀有样本 +969299076 x10 RARE SAMPLES x10稀有样本 +3382765520 x20 Common Samples x20普通样本 +1608171747 x20 COMMON SAMPLES x20普通样本 +3363066353 Xenobite Ardent 炽热异噬者 +46404066 XENOBITE ARDENT 炽热异噬者 +401074256 Xenobite Ardents 炽热异噬者 +4101241081 XENOENTOMOLOGY CENTER 异星昆虫学研究中心 +3979919195 XENOENTOMOLOGY CENTER (DESTROYED) 异星昆虫学研究中心(遗址) +3649073332 XeSS XeSS +853869815 XI TAURI SECTOR 金牛座分区 +3263174413 XIAMEN ANEW 尚厦门 +1915898238 XIN FUZHOU 新福州 +3215785011 XIRAN'S CLAIM 希兰领地 +864632211 XP 经验 +338409938 XP 经验值 +2017155486 XP Awarded 奖励经验 +1265822393 XXL WEAPONS BAY XXL号武器舱 +1630007655 XZAR SECTOR 兹亚尔分区 +1676335027 Y- AXIS Y-轴 +3688201538 Y+ AXIS Y+轴 +2045427074 YATAKHANE 263 宿舍263 +2531925644 YDINKESKUSTA 中心城 +3709010725 YED PRIOR 天市右垣九 +1330041521 YELLOW JACKET EXOSUIT PATTERN 黄色被甲弹外骨骼装甲涂装 +2198854748 YELLOW JACKET HELLPOD PATTERN 黄色被甲弹绝地喷射舱涂装 +778063718 YELLOW JACKET SHUTTLE PATTERN 黄色被甲弹运输船涂装 +2356589594 YELLOW JACKET VEHICLE PATTERN 黄色被甲弹载具涂装 +2027946256 YES 是 +2553968432 YES 是 +819714857 YES 是 +3645601288 YES 是 +1785813534 YMIR SECTOR 土卫十九分区 +2260123791 YORK SUPREME 棒约克 +746261490 You are able to requisition STRATAGEM PERMITS. Exit the menu when you're done. 你现在可以申购战略配备许可证。完成后退出菜单。 +3214188048 You are able to requisition STRATAGEMS. Exit the menu when you're done. 你现在可以申购战略配备。完成后退出菜单。 +4069052301 You are already in this game session. 已加入本场游戏。 +1216425242 You are not authorized to access the Acquisition Center until you've completed your first mission. 你必须完成首次任务才能前往采购中心。 +3283800348 You are Super Earth's elite. Never forget that. 你是超级地球的精英,时刻牢记这一点。 +2014704512 You can change and customize these settings at any time during gameplay 您可以在游戏期间随时更改或自定义这些设置 +380121167 You can change and customize these settings at any time during gameplay. 你可以在游戏期间随时更改或自定义这些设置。 +2057624003 You can change the name of your Super Destroyer through the Ship Management menu. 你可以通过舰船管理菜单更改超级驱逐舰的名称。 +1637815167 You can pick up active grenades and toss them away before they explode. Give it a try, it's fun! 你可以捡起已激活的榴弹,在它爆炸前丢出去。很有意思,值得一试! +4165077128 You can tell by just touching it, that this was made for real heroes. 摸一摸就能感觉到这是给真英雄打造的。 +3443980220 You can use STIMS on your teammates. 你可以对队友使用治疗剂。 +1266880478 You do not have access to ship management yet. Complete missions and collect resources to upgrade the Destroyer. 你现在还不能进行舰船管理。请先完成任务并收集资源来升级驱逐舰。 +885527372 You do not have enough funds to make this donation. 你的资源不足,无法完成这次捐赠。 +1888698058 You do not meet the level requirements to unlock this item. 等级不符,无法解锁此物品。 +2619802004 You have a limited amount of reinforcements available in a mission. If you run out they will be replenished slowly on a timer. 在一次任务中,你能获得的增援数量有限。一旦耗尽就必须等待计时,缓慢补充。 +1956182611 You have almost taken all planets en route to ANGEL'S VENTURE. We are on the verge of clearing the way for construction of the Terminid Control System. Press on! 你们几乎已经占领通往天使投资星系的所有星球。我们即将为构建终结族遏制体系扫清所有障碍。继续努力! +835580544 You have attained the rank of ASPIRANT. 你已成为志士。 +3543858428 You have attained the rank of CHAMPION. 你已成为斗士。 +1911643135 You have attained the rank of EXALTED HERO! You have a 5% discount on all premium items. 你已成为伟人!购买所有尊享物品均可享受5%的折扣优惠。 +1883077636 You have attained the rank of HERO. 你已成为英雄。 +3477071466 You have been disconnected due to inactivity 你处于不活跃状态,已断开连接 +2454935245 You have been kicked from the game. 你已被移出游戏。 +938792079 You have been temporarily suspended. 你已暂时被封禁。 +661925081 You have commended other players five times during this mission. You can offer more commendations in the next mission. 本次任务你已称赞了其他玩家五次,下一次任务可以继续称赞他人。 +2971559833 You have commended this player five times today. Further commendations will not count towards their score. 今天你已称赞了这名玩家五次,继续称赞也无法提高其分数。 +734770525 You have insufficient funds to purchase this item. 资金不足,无法购买此商品。 +800743787 You have insufficient progression to purchase this item. 进度不足,无法购买此商品。 +1136217013 You have new rewards to collect! 你有新的奖励可以领取! +432275452 You have performed your democratic duty +WELL DONE! 你已履行你的民主职责 +干得漂亮! +26981275 You have reached the approved generosity limit. Please wait #DAYS d #HOURS h before donating again. 你已达到批准的捐赠上限。请在#DAYS天#HOURS小时后再尝试。 +3218362271 You have reached the approved generosity limit. Please wait #HOURS h #MINUTES m before donating again. 你已达到批准的捐赠上限。请在#HOURS小时#MINUTES分后再尝试。 +286179274 You have reached the approved generosity limit. Please wait #MINUTES m #SECONDS s before donating again. 你已达到批准的捐赠上限。请在#MINUTES分#SECONDS秒后再尝试。 +1443315300 You have sustained an INJURY. Injuries make you move slower, aim worse or can even make you bleed to death. 你受到了损伤。损伤会降低你的移动速度,削弱你的瞄准能力,甚至有可能导致流血至死。 +1815370878 You need to link your Steam account to a PSN ID in order to report another player. 你需要将Steam账户与PSN ID绑定才能举报其他玩家。 +1363933163 You will be fighting the #RACE. 你将会迎战#RACE。 +3680203702 You will deploy to the surface of the Supercolony in vicinity of former TCS nodes, where the crust has been weakened. Once on the surface, call down the Dark Fluid Vessel and deliver it to each Payload site. + +The Supercolony is like nothing you have deployed to before. Expect extreme resistance. All of Super Earth is counting on you. 你将部署至超级拓殖地的地表,靠近以前TCS节点的位置,该处的地壳较为薄弱。一旦降落,立即呼叫暗液体容器,并将其运送至各投放点。 + +超级拓殖地不同于你们曾经战斗过的任何战场,你们可能会遭遇极端反抗。超级地球一切都靠你了。 +3564677393 You're Next 轮到你 +3848706698 YOU'RE NEXT 轮到你 +900827791 You've unlocked a new PRIMARY WEAPON. Return to the DEMOCRACY OFFICER for your next MISSION. 你已解锁一件新的主武器。返回民主官处开展下一项任务。 +2726860847 Young 扬 +1322234803 Your account has been suspended for breaching the terms of service. +For more information about account suspensions, visit +https://www.playstation.com/support/account/suspensions-psn/ 你的账号因违反服务条款而被封禁。 +有关账号封禁的更多信息,请访问https://www.playstation.com/support/account/suspensions-psn/ +2632265563 Your changes have not been applied. 你的更改尚未应用。 +1660722673 Your chest is bleeding, causing continuous health loss. 你的胸腔在出血,将导致你持续损失生命值。 +2264505198 Your commendation level has increased. 你的嘉赞等级现已提高。 +2533705905 Your Contribution: #COUNT 你的贡献:#COUNT +1964067103 YOUR FINAL SCORE 你的最终得分 +1781637563 YOUR FIRST DIVE 第一次作战 +1633838774 Your game version is out of date, please update your game 你的游戏版本过低,请更新游戏 +4075271598 Your left arm is injured, impacting your ability to aim. 你的左臂受伤了,你瞄准的能力将受到影响。 +3993757602 Your right arm is injured, impacting your ability to aim and throw. 你的右臂受伤了,你瞄准和投掷的能力将受到影响。 +2731309671 Your stance has a significant impact on accuracy. The SEAF manual lists the following stances in order of least to most accurate: Moving < Standing < Crouching < Prone. 你的姿势会显著影响命中率。超级地球武装部队手册按照命中率从低到高的顺序列出了以下姿势:移动<站立<蹲下<趴下。 +4259560067 Your Steam and PSN accounts are now linked. 你的Steam和PSN账户现已绑定 +1217678385 Yousefi 优塞菲 +858987625 Yu Villa 优·维拉 +2894427085 Z- AXIS Z-轴 +3487780899 Z+ AXIS Z+轴 +2155068571 ZAGON PRIME 扎贡主星 +1441994227 Zamora 萨莫拉 +4185597853 ZEA RUGOSIA 泽亚鲁戈西亚 +3636423311 Zealot 狂热战士 +3505595200 ZEALOT 狂热战士 +3042591905 Zealots 狂热战士 +954678793 ZEFIA 赛飞亚 +992619516 ZEGEMA PARADISE 泽格马乐土 +3190734847 ZENITH 穹顶 +492721671 ZERO-G BREECH LOADING 零重力后膛装弹 +4187755040 ZEROING 归零 +656203130 ZONE 3 3区 +2031340410 ZOOM 缩放 +3688574071 ZOOM IN 视角推近 +2865381799 ZOOM OUT 视角拉远 +2992138395 ZOSMA 太微右垣五 +2351373725 ZYGOS 齐戈斯 +1468076040 ZZANIAH PRIME 藏尼亚主星 +2546320491 РУССКИЙ РУССКИЙ +2667782002 한국어 한국어 \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/doc/hd2_zh_map.json b/hexi/plugins/nonebot_plugin_helldivers_tools/doc/hd2_zh_map.json new file mode 100644 index 0000000..815d0ad --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/doc/hd2_zh_map.json @@ -0,0 +1,10214 @@ +{ + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7", + "8": "8", + "9": "9", + "10": "10", + "33000000": "33000000", + "MISSION INCOMPLETE": "任务未完成", + "Pick up and use EXPENDABLE ANTI-TANK against ARMORED ENEMIES.": "拾取并使用消耗性反坦克武器对付装备护甲的敌人。", + "to throw a Grenade": "投掷榴弹", + "HEAVY COMBAT (BUGS)": "重型作战(虫族)", + "COMMUNICATIONS": "通讯", + "SENTRY": "哨戒炮", + "SELECT AND ADJUST": "选择并调整", + "Welcome to the Galactic Map - This is where you navigate your Destroyer to the frontlines and select Missions to play.\n\nIn the galactic war, the entire Helldivers Community fights together against the enemies of Super Earth.": "欢迎查看银河地图 - 你将在此指挥驱逐舰奔赴前线,并且选择你要执行的任务。\n\n在星系战争中,整个绝地潜兵社区都在共同对抗超级地球的敌人。", + "FIRING": "开火", + "USE": "使用", + "WEAPON EXPERIMENTATION\nThe GL-6 Grenade Launcher stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“GL-6榴弹发射器”战略配备暂时获准供全体绝地潜兵使用。", + "Major Place of Interest": "主要特殊地点", + "Moving makes it harder to aim - Stand still for maximum accuracy!": "移动过程中难以瞄准,站立不动才能最大限度提高命中率!", + "CONSUMING VOID": "吞噬寂域", + "Heavy Encampment": "重型营地", + "MISSION COMPLETED": "任务完成", + "CLAIMING ITEM": "领取物品", + "THE RESOURCES OF PROGRESS": "进步的资源", + "Terminid Kills": "终结族击杀数", + "AUTOMATON FORTRESS": "机器人堡垒", + "STUN": "眩晕弹", + "#COUNTm": "#COUNT米", + "Requisition GRENADE LAUNCHER stratagem.": "申购榴弹发射器战略配备。", + "Acid Storm In Progress": "酸雨风暴正在形成", + "FF81ACFE": "FF81ACFE", + "Destroy Illuminate Ships": "摧毁光能者舰船", + "ALL": "全部", + "INTEL ACQUIRED! Bring it back to the ship to unlock OPPORTUNITY MISSION.": "取得情报!将情报带回舰船,解锁机遇任务。", + "OBJECTIVE COMPLETED": "目标达成", + "WEAPON EXPERIMENTATION\nThe ST-1 Stinger stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“ST-1毒刺”战略配备暂时获准供全体绝地潜兵使用。", + "ROCK": "石头", + "MOVE SELECTION AND SWITCH NUMBERS": "行动选择和切换号码", + "Armor": "盔甲", + "to dial stratagem": "拨通战略配备", + "Chest Hemorrhage": "胸腔出血", + "The unthinking, amoral bots may now violate the very air as well. Keep an eye to the skies, Helldivers. Reports are suggesting the presence of flying Automaton threats.": "毫无思考能力和道德底线的机器人现在甚至开始侵犯空中领域。绝地潜兵,务必留意天空的情况。报告显示,战场上出现了飞行机器人。", + "The left side of the skull should be barely visible.": "请将亮度调至骷髅头左侧勉强可见的程度。", + "Out of consumable #SLOT: #NAME.": "消耗品#SLOT耗尽:#NAME。", + "No reinforcement point available.": "暂无增援点。", + "Use COMPUTER TERMINAL.": "使用计算机终端。", + "PHASE 3": "第3阶段", + "9+": "9+", + "PLAY": "开始游戏", + "LIBERATION FAILED\nWe have failed to reclaim a planet from the Automatons.": "解放失败\n我们未能从机器人手上夺回星球。", + "Bot Drop Detected": "侦测发现机器人", + "CANNOT EDIT": "无法编辑", + "DAMAGED": "受损", + "Rare Sample": "稀有样本", + "Find and destroy all Automaton Fabricators": "找到并消灭所有机器人构筑者", + "RESPOND": "回答", + "Unable to login into PlayFab, try again in a few minutes. Contact support if the problem persists.\n\nStatus code: #STATUSCODE \nError code: #ERRORCODE": "无法登录PlayFab,请过几分钟后再试。如果问题仍未解决,请联系客服。\n\n状态代码:#STATUSCODE \n错误代码:#ERRORCODE", + "SUPPORT WEAPON": "支援武器", + "Projectile": "投射", + "Steam AppId supplied is invalid or not allowed": "提供的Steam AppId无效或遭到禁止", + "BACKPACK": "背包", + "CLAIM STANDARD WARBOND": "领取标准战争债券", + "to go prone": "匍匐", + "DIFFICULTY 4 TRIAL": "难度4级考验", + "Helldivers on PlanetX have defeated waves of the Mindless Masses. Genetic material from the Voteless sent to the Ministry of Science show clear markers of adaptation to a rapidly changing environment, potentially giving clues about organisms inside the Void.": "镇守X星的绝地潜兵已击溃一波又一波无脑群氓。送往科学部的无票者遗传物质显示出可适应快速变化环境的清晰标记,这或许能为我们提供有关寂域生物的线索。", + "SPECIAL": "特殊", + "Active": "已激活", + "Base": "基地", + "FALLBACK": "撤退", + "AREA SECURED": "区域现已安全", + "Boosts Requisition and XP awards by 50% to address accounting errors (responsible parties undergoing re-education).": "申购点和经验奖励增加50%以修正核算错误(负责人正接受二次教育)。", + "SUPPLIES": "物资", + "CYCLE WEAPON CONFIG": "循环选择武器配置", + "DIFFICULTY": "难度", + "Game session is no longer available.": "本场游戏已无法加入。", + "WEAPON CUSTOMIZATION now available in the ARMORY.": "武器自定义内容已在军械库中解锁。", + "REWARDS": "奖励", + "IN LOADOUT": "正在进行武装配置", + "Avoid DROWNING by getting out of the water.": "脱离水体,避免淹溺。", + "PATTERN": "涂装", + "Amount": "数量", + "FF13D460": "FF13D460", + "#VALUE": "#VALUE", + "Cycle Pose": "切换姿态", + "Select your gear and Stratagems.": "选择你的装备和战略配备。", + "TURING LOST\nTuring has fallen to the Terminid Menace. We cannot allow this infestation to continue to spread.": "图灵沦陷\n在终结族的威胁下,图灵已沦陷。我们不能容许虫族继续扩张。", + "#ITEM FULL": "#ITEM已满", + "Medium Nest": "中型巢穴", + "UNDERBARREL": "下挂", + "FIRE": "开火", + "CONVOY HAS LEFT MISSION AREA": "车队已离开任务区域", + "Fortress Destroyed": "堡垒成功摧毁", + "RICOCHET": "跳弹", + "ITEM RECEIVED": "已收到物品", + "Shrieker Swarms Traverse the Skies": "尖啸虫群穿过空域", + "OFFLINE": "损毁", + "COMMON SAMPLES": "普通样本", + "ENEMY SURGE": "敌军激增", + "Failed to join lobby. The lobby host is not logged into PlayFab.": "无法进入大厅。大厅主办者尚未登录至PlayFab。", + "REINFORCE AVAILABLE IN:": "增援就位倒计时:", + "Toggle Headlight Power": "切换大灯供能源", + "BUY LEGENDARY WARBOND": "购买传奇战争债券", + "GAME OVER": "游戏结束", + "MANUALLY adjust FLOW RATE VALVES.": "手动调整流量阀。", + "Intel PDA": "情报PDA", + "LIBERATION FAILED\nThe bots retain their iron grip on Mantes.": "解放失败\n机器人依然牢牢掌控着蒙特斯。", + "Invalid Authorization for PlayStation™Network - Token Format": "PlayStation™Network的授权无效 - 令牌格式", + "Requisition MACHINE GUN SENTRY Stratagem permit.": "申购哨戒机枪战略配备许可证。", + "VELD LOST\nWe have failed to repel the bugs from Veld, and now they multiply in deep hives across the planet. We will return, to free it once more.": "维尔德沦陷\n我们没能将虫族赶出维尔德,现在它们在遍布整颗星球的虫窝深处不断繁殖壮大。我们定会回转,重新解放维尔德。", + "Terrain features like water and foliage will slow the Helldiver down.": "积水覆盖和满地枝叶等地形状况会拖慢绝地潜兵的前进速度。", + "SEASON III": "第III赛季", + "Unable to establish a connection to game.": "无法连接至游戏。", + "HELMET": "头盔", + "SELECT MISSION": "选择任务", + "VELD UNDER ATTACK\nThe Terminids are attempting to spread to Veld. All Helldivers are called upon to deploy immediately to the planet's defense.": "维尔德遭到袭击\n终结族企图扩张至维尔德。呼唤全体绝地潜兵,立即前去保卫该星球。", + "OPT": "准镜", + "PISTOL": "手枪", + "The Automatons' losses have begun to impact their ability to supply fresh units. Their resistance is crumbling. Press the assault!": "机器人的落败开始影响它们补充新兵力的能力。它们的抵抗逐渐崩溃,请乘胜追击!", + "Mission": "任务", + "WAIT": "等等", + "Net Worth": "生涯收入", + "DIFFICULTY 9 TRIAL": "难度9级考验", + "Failed to join as target host is running a different game version.": "加入失败,你与目标主办者的游戏版本不同。", + "CARRIABLE": "可携带", + "+#POINTS": "+#POINTS", + "Waiting for Host": "正在等待主办者", + "ONE HANDED": "单手操作", + "Activate extraction terminal.": "激活撤离终端。", + "Complete Missions to help push the enemies of Super Earth back.\n\nYou can do Missions on any contested Planet in any of the contested Sectors.": "完成任务,协助击退超级地球的敌人。\n\n你可以前往处于争夺状态的分区,在任意一颗处于争夺状态的星球上执行任务。", + "SINKING IN #SECONDS SECONDS": "沉没倒计时:#SECONDS秒", + "Shuttle incoming.\nDefend extraction zone.": "运输船接近中。\n请在撤离区坚守。", + "#NAME is the new squad leader": "#NAME成为新的小队长", + "ITEM INFO": "物品信息", + "Enter any Stratagem Input to Start!": "输入任意战略配备代码即可开始!", + "Successful Extractions": "成功撤离次数", + "Atmospheric Spores": "孢子气体", + "INFORMATION ON THE ENEMY": "敌方情报", + "#COUNT/#TOTAL": "#COUNT/#TOTAL", + "Melee Kills": "近战击杀数", + "NEED SUPPLIES": "我需要补给", + "ANGEL'S VENTURE LOST\nThe defense of Angel's Venture has failed. Terminids now run amok on its surface. We cannot allow this corruption of Liberty to stand.": "天使投资星系沦陷\n天使投资星系保卫战已宣告失败。终结族现在正四处肆虐。我们不能任由它们继续侵犯自由伟业。", + "Take Health Pack": "获得生命包", + "Rejoining mission": "正在重新加入任务", + "Light Nest": "轻型巢穴", + "(#MINUTES #MIN_UNIT#SEPARATOR#SECONDS #SEC_UNIT)": "(#MINUTES #MIN_UNIT#SEPARATOR#SECONDS #SEC_UNIT)", + "while map is open to look around the map": "在地图打开时浏览地图", + "ROTATING ITEMS": "轮换物品", + "Razor Sharp Claws": "利爪", + "STRATEGIC ADVISORY\n\nThe Automaton Jet Brigade has been spotted in the #SECTOR Sector.": "战略警报\n\n#SECTOR发现机器人喷气旅。", + "LIGHT ARMOR PENETRATING": "轻甲穿透", + "STIMS": "治疗剂", + "WEAPON EXPERIMENTATION\nThe Guard Dog Rover stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“‘护卫犬’漫游车”战略配备暂时获准供全体绝地潜兵使用。", + "BOOSTER": "强化资源", + "CAPES": "披肩", + "REQUEST REINFORCE": "请求增援", + "SCANNING...": "正在扫描……", + "#NAME DIED": "#NAME阵亡", + "Jammed": "受到干扰", + "FLASH": "闪光弹", + "#NAME": "#NAME", + "PLEASE WAIT": "请稍候", + "ITEM CLAIMED": "已领取物品", + "Too Far From Extraction - Shuttle Aborting In T-#MINUTES:#SECONDS:#MILLI": "距离撤离点太远 — 运输船中止倒计时 #MINUTES:#SECONDS:#MILLI", + "MALEVELON CREEK LOST\nThe defense of Malevelon Creek has failed. The Automatons spread their despotic industry across its surface.": "麦拉芬蒙河沦陷\n麦拉芬蒙河的防线已经崩溃,而机器人也将它们暴虐的产业扩张到了该星球的地表。", + "SW": "西南", + "#NAME has joined the mission": "#NAME加入任务", + "ENERGY-BASED": "能量武器", + "Tap": "轻按", + "ACQUIRED": "已获取", + "MEDIUM ARMOR PENETRATING": "中甲穿透", + "Go to the DESTROYER BRIDGE and use the WAR TABLE to START A MISSION": "前往驱逐舰舰桥,使用议战桌开始任务。", + "EXPERIMENTATION PERIOD ENDED\nThe previous authorization period for global stratagem usage has ended.": "试验周期结束\n上一项战略配备获准开放全体使用的周期已结束。", + "The quick brown fox jumps over the lazy dog.": "The quick brown fox jumps over the lazy dog.", + "CANCEL": "取消", + "Call the Helldivers": "呼叫绝地潜兵", + "Casual Salute": "敬礼", + "#NAME has timed out": "#NAME已超时", + "ESE (#COUNT°)": "东南偏东#COUNT°", + "FFFF9D42": "FFFF9D42", + "Shuttle Landing": "运输船即将着陆", + "Atmospheric Interference": "大气干扰", + "Spectating:": "正在观战:", + "LIBERATION FAILED\nOur efforts to purge Fenrir III of the Terminid presence have failed.": "解放失败\n我们将终结族彻底驱逐出芬里尔III的行动宣告失败。", + "CRIMSICA LOST\nThe defense of Crimsica has failed. Terminids now infest its once-pristine surface.": "克里姆西卡沦陷\n克里姆西卡保卫战已宣告失败。终结族现在令这块曾经的纯净乐土不得安宁。", + "Helldivers will soon have even more tools with which to bring Managed Democracy to the enemy. Shipments of new equipment are under way.": "绝地潜兵很快将拥有更多工具,向敌人传播管理式民主。全新装备正在运输途中。", + "HEETH FREED\nHeeth has been cleansed of all Terminid infestation. Well done, Helldivers. Keep pressing forward.": "希斯已解放\n肆虐希斯的终结族已被全数剿灭。很好,各位绝地潜兵。再接再厉,继续前进。", + "Signal Right Turn": "指示右转", + "The loadout for this mission has already been selected. Any loadout changes will be applied to the next mission.": "此任务使用的武装配置已经选定。对武装配置作出的更改将在下一场任务中生效。", + "Tier 1": "1阶", + "Dust Devils Detected": "侦测到尘卷风", + "ANGEL'S VENTURE UNDER ATTACK\nThe Terminids have attacked Angel's Venture. All available Helldivers are called to defend it.": "天使投资星系遭到袭击\n终结族对天使投资星系发动了袭击。呼唤全体可行动的绝地潜兵前去防卫。", + "Character": "角色", + "VANDALON IV LOST\nVandalon IV has fallen to the Automatons. We cannot allow this travesty to go unanswered.": "万达隆IV沦陷\n万达隆IV已落入机器人的铁爪。我们不能任由这一闹剧继续发展。", + "Something went wrong, invalid upgrade.": "发生意外,升级无效。", + "Reinforce available": "增援就位", + "INGMAR FREED\nIngmar has been freed from the Automatons. Take the fight to the next planet.": "英格玛已解放\n英格玛已经挣脱了机器人的铁爪。该去下一颗星球作战了。", + "High-Five": "击掌", + "Approaching edge of mission area. Return to the mission, or be branded a traitor.": "正接近任务区域边缘。请折返执行任务,否则你将被认定为叛徒。", + "ACCOUNTING CORRECTIONS": "核算修正", + "Current Major Order": "当前重要指令", + "Pick up BACKPACK.": "拾起背包。", + "SEASON I": "第I赛季", + "STORAGE": "存储", + "Steam account not allowed to login. Please contact Community managers": "Steam账号禁止登录。请联系社区管理员", + "SMOKE": "烟雾弹", + "PROGRESS IS MANDATORY": "必须进步", + "Helmet": "头盔", + "INTEL": "情报", + "#NAME has been court-martialed": "#NAME已被移交军事法庭", + "INCENDIARY": "燃烧弹", + "MEDIUM": "中型", + "SHUTTLE DEPARTING": "运输船即将出发", + "Drop #ENTITY": "投放#ENTITY", + "DIFFICULTY 6 TRIAL": "难度6级考验", + "#NAME: #MESSAGE": "#NAME: #MESSAGE", + "An ENCOUNTER is approaching. Use your STRATAGEMS!": "一场遭遇战即将开始。使用你的战略配备吧!", + "TRAITOR DETECTED": "发现叛徒", + "HOLD": "按住", + "Enter a HELLPOD to start the mission.": "进入绝地喷射舱,开始任务。", + "L. ARM": "左臂", + "Unavailable": "不可用", + "WEAPON EXPERIMENTATION\nThe Orbital EMS Strike stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“轨道电磁冲击波攻击”战略配备暂时获准供全体绝地潜兵使用。", + "HEAVY ARMOR PENETRATING": "重甲穿透", + "DRAUPNIR UNDER ATTACK\nThe Automatons are invading Draupnir. Rally to its defense!": "德罗普尼尔遭到袭击\n机器人当前正在入侵德罗普尼尔,速速集结,前去保卫该星球!", + "FRACTURED": "骨折", + "W (#COUNT°)": "西#COUNT°", + "Squad Saves": "小队救援次数", + "S": "南", + "CRIMSICA FREED\nCrimsica has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet.": "克里姆西卡已解放\n克里姆西卡挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。", + "READY": "就位", + "READY UP": "准备就绪", + "Total XP Earned": "所获总经验值", + "Injecting Freedom Protocols (#COUNT remaining)": "注入自由协定(还剩#COUNT)", + "LOCAL STORAGE": "本地存储", + "QUIT GAME": "退出游戏", + "Extract as soon as possible. When the SUPER DESTROYER departs, you will no longer have access to STRATAGEMS.": "尽快撤离。超级驱逐舰离开后,你将无法再使用战略配备。", + "Deploying without ammo will force you to scavenge it during the mission.": "如果部署时不携带弹药,你将被迫在任务期间设法搜集弹药。", + "WEAPON EXPERIMENTATION\nThe Orbital Railcannon stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“轨道炮”战略配备暂时获准供全体绝地潜兵使用。", + "PLANET SAVED\nThanks to the unfailed valor of the Helldivers, the Automatons have been repelled from one of our planets. A glorious day for Freedom.": "星球已获救\n在从不失手的绝地潜兵的英勇付出下,我们已将机器人从我方的其中一颗星球逐出。今天又是自由伟业光荣的一天。", + "Difficulty": "难度", + "Inside of PLACES OF INTEREST you can find SUPPLIES and SAMPLES.": "你可以在特殊地点找到补给和样本。", + "Exit": "退出", + "Dropping in": "正在降落", + "STRIKE": "打击武器", + "MUTATED EGG": "变异虫卵", + "MARKSMAN RIFLE": "精确射手步枪", + "PREPARING DEMOCRACY": "准备播撒民主", + "HEAVY": "重型", + "Debug UI": "测试UI", + "SHUTTLE DISPATCHED FROM SHIP": "运输船离开飞船", + "MAGAZINE": "弹匣", + "RETURN TO THE COMBAT ZONE: #SECONDS": "返回作战区域:#SECONDS", + "Medium": "中型", + "A new Major Order has been issued. Check the Galactic Map for more information.": "一项重要指令已发布。查看星系地图了解更多信息。", + "FENRIR III DEFENDED\nAfter countless noble and unavoidable sacrifices, Fenrir III has been defended from the Terminids.": "成功保卫芬里尔III\n无数不可避免的光荣牺牲终于换来回报,我们顺利从终结族手下守住了芬里尔III。", + "VANDALON IV FREED\nVandalon IV has been freed from the Automatons. Take the fight to the next planet.": "万达隆IV已解放\n万达隆IV已经挣脱了机器人的铁爪。该去下一颗星球作战了。", + "LOADOUT": "武装配置", + "TORSO": "躯干", + "Signed in as:": "登录身份:", + "Light Illuminate Encampment Cleared": "光能者轻型营地成功摧毁", + "Fire": "灼烧", + "DELIVER": "送达", + "SIGNAL LOST": "信号丢失", + "Confidential Data": "机密数据", + "EMOTE": "表情", + "HOLD TO CLAIM ITEM": "按住领取物品", + "MISSION FAILED": "任务失败", + "Fighting Terminids": "抗击终结族", + "Unsafe": "不安全", + "Thorns": "尖刺", + "SCROLL": "滚动", + "Civilian resistance units have taken significant ground from the enemy on Planet #V_ONE. The freedom fighters have been recognized for their duty and rewarded with proper drafting into the SEAF.": "平民抵抗组织在#V_ONE星球上从敌方手上夺下重要阵地。这群自由战士的功绩得到了认可,也获得了适当的奖赏:收编进入超级地球武装部队。", + "MUZZLE": "枪口", + "Blizzard In Progress": "暴风雪正在形成", + "Both of your legs are injured, severely impairing your movement.": "你的双腿都受伤了,你的移动能力将受到严重影响。", + "Call in a RESUPPLY to refill your AMMUNITION and STIMS.": "呼叫重新补给,补充弹药和治疗剂。", + "ERATA PRIME SECURED\nThe Terminid Control System is now fully activated on Erata Prime.": "成功占领艾拉特主星\n终结族遏制体系已经在艾拉特主星全面启动。", + "SSW": "西南偏南", + "+#COUNT SAMPLE": "+#COUNT份样本", + "ENTER TURRET": "进入炮台", + "TEAM WEAPON BACKPACKS allow you to reload support weapons. This is most efficient when working with a teammate.": "携带团队武器背包可以为支援武器重新装填弹药。这是与队友合作时效率最高的做法。", + "Bleeding": "出血", + "Failed to establish network connection.": "无法建立网络连接。", + "Complex Stratagem Plotting": "复杂的战略配备部署流程", + "Syncing Server Data": "正在同步服务器数据", + "Dead": "死亡", + "NW": "西北", + "You have commended other players five times during this mission. You can offer more commendations in the next mission.": "本次任务你已称赞了其他玩家五次,下一次任务可以继续称赞他人。", + "Out of Grenades! Call in a Resupply to replenish.": "榴弹耗尽!呼叫重新补给进行补充。", + "Increase your contribution to The War and your opportunities for additional rewards!": "增加你对战争的贡献和获得额外奖励的机会!", + "EQUIPPED BY": "已装备", + "A SAMPLE FOR YOUR TROUBLES": "浅尝麻烦", + "#WEAPON LVL #CURRENT/#MAX": "#WEAPON等级#CURRENT/#MAX", + "TURING DEFENDED\nThe bugs have been repelled from Turing. Citizens across the planet hold celebrations in honor of the Helldivers' heroism.": "成功保卫图灵\n我们已将虫族逐出图灵。全星球的公民一起举办了庆典活动,纪念绝地潜兵的英勇之举。", + "#COUNT Medals": "#COUNT枚奖章", + "ESTANU UNDER ATTACK\nTerminid spores fill the skies of Estanu. All Helldivers are called to the planet's defense!": "伊斯塔努遭到袭击\n终结族孢子遍布伊斯塔努上空。呼唤全体绝地潜兵,前去保卫该星球!", + "INSERT AMMO": "插入弹药", + "DIFFICULTY 3 TRIAL": "难度3级考验", + "SHOW KEYBOARD BINDINGS": "显示键位绑定", + "MELEE": "近战", + "ENEMY UNIT": "敌方单位", + "LIBERATION FAILED\nThe bots retain their iron grip on Draupnir.": "解放失败\n机器人依然牢牢掌控着德罗普尼尔。", + "Common Sample": "普通样本", + "MAJOR ORDERS": "重要指令", + "TURING SECURED\nThe Terminid Control System is now fully activated on Turing.": "成功占领图灵\n终结族遏制体系已经在图灵全面启动。", + "TERMINID SURGE\nMinistry of Science reports an unanticipated spike in Terminid spore counts. Expect a severe increase in resistance on Terminid planets.": "终结族势力激增\n科学部通报,终结族孢子数量意外激增,预计各终结族星球的反抗力度将大幅加剧。", + "FFB1B1B1": "FFB1B1B1", + "RESET": "重置", + "100 SC": "100超级货币", + "The Illuminate invasion fleet, constructed in secret behind the veil of the Meridian Wormhole. It is headed for Super Earth itself.": "在默里迪恩虫洞掩护下秘密建造的光能者入侵舰队。目前正向超级地球进发。", + "Call in a Resupply when low on ammo.": "弹药不足时可呼叫重新补给。", + "x10 Rare Samples": "x10稀有样本", + "SELECT OPERATION": "选择行动", + "Cape": "披肩", + "#COUNT": "#COUNT", + "This item is already owned.": "你已拥有此物品。", + "COMBAT (BOTS)": "作战(机器人)", + "You have insufficient funds to purchase this item.": "资金不足,无法购买此商品。", + "#AMOUNT": "#AMOUNT", + "DSS Orbital Bombardment in #MINUTES:#SECONDS": "民主空间站轨道轰炸来袭倒计时:#MINUTES:#SECONDS", + "Throw GRENADE into FACTORY to destroy it.": "把榴弹丢进工厂,将其摧毁。", + "#COUNT km": "#COUNT公里", + "990C0A05": "990C0A05", + "Unable to authenticate your account on Microsoft, please try again later or contact support if this error persists.": "无法验证你的Microsoft账号,请稍后重试。如果问题仍未解决,请联系客服。", + "Failed to get a Token for PlayStation™Network": "无法获得PlayStation™Network令牌", + "You are able to requisition STRATAGEM PERMITS. Exit the menu when you're done.": "你现在可以申购战略配备许可证。完成后退出菜单。", + "CHANGE BUTTON AND ACTIVATE": "更改按键并启动", + "RECEIVED: TODAY": "接收:今天", + "WEAPON EXPERIMENTATION\nThe Mortar Sentry stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“迫击哨戒炮”战略配备暂时获准供全体绝地潜兵使用。", + "The Advanced Liberation Tools Research Agency (ALTRA) has completed final approval of a new combat asset: the EXO-45 PATRIOT EXOSUIT. Models are anticipated to be available for requisition within a week.": "先进解放工具研究局(ALTRA)开发的新型作战装备:EXO-45“爱国者”外骨骼装甲已通过最终审核,样机将在一周内开放申购。", + "STRATEGIC ADVISORY\n\nThe Automaton Jet Brigade has been spotted on several planets.": "战略警报\n\n在数个星球发现机器人喷气旅。", + "Underbarrel": "下挂", + "R/G/B": "R/G/B", + "This is where you upgrade your Destroyer to better support you in the field. Upgrading modules will improve the effectiveness of stratagems you already own.": "你可以在这里升级自己的驱逐舰,以便在战场上为你提供更有利的支援。升级模块将提高已有战略配备的效能。", + "Make Snowball": "捏雪球", + "EQUIPPING": "正在装备", + "/ #CAP": "/ #CAP", + "Season I": "第I赛季", + "MERIDIA DEFENDED\nAfter countless noble and unavoidable sacrifices, Meridia has been defended from the Terminids.": "成功保卫默里迪亚\n无数不可避免的光荣牺牲终于换来回报,我们顺利从终结族手下守住了默里迪亚。", + "Convoy Destination": "车队目的地", + "Safe": "安全", + "ESE": "东南偏东", + "#SECONDS sec": "#SECONDS秒", + "WEAPON EXPERIMENTATION\nThe FLAM-40 Flamethrower stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“FLAM-40火焰喷射器”战略配备暂时获准供全体绝地潜兵使用。", + "WEAPON EXPERIMENTATION\nThe Tesla Tower stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“特斯拉塔”战略配备暂时获准供全体绝地潜兵使用。", + "#MINS:#SECS": "#MINS:#SECS", + "Switch Headlight Mode": "切换大灯模式", + "Mutated Egg": "变异虫卵", + "SCISSORS": "剪刀", + "sudden loss of health": "生命值骤减", + "You have insufficient progression to purchase this item.": "进度不足,无法购买此商品。", + "Unanticipated Automaton reinforcements have taken significant ground on Planet #V_ONE.": "突如其来的机器人增援部队在#V_ONE星球上占领了重要阵地。", + "DESTROYER": "驱逐舰", + "The unjust wave of Illuminate migration following the Void surge has been slowed, thanks to the quick response of Helldivers in the region. No additional planets have fallen, but little information about how to penetrate the Void has been revealed. The Ministry of Science indicates that the mindless masses that come from the Void may have valuable information about what lies on the other side.": "多亏了该地区绝地潜兵的快速响应,伴随寂域激增的不义光能者移民浪潮已放缓。没有更多星球陷入寂域,但关于穿透寂域的方法几乎没有新信息。科学部指出,源自寂域的无脑群氓可能掌握着关于“另一边”的宝贵情报。", + "Fresh SEAF recruits filled with patriotic fervor for the destruction of the Automatons have surged to take significant ground on Maia.": "满腔爱国热情、誓要摧毁机器人的超级地球武装部队新进后备军已经在昴宿四占领了重要阵地。", + "[THIS TEXT IS NOT IMPLEMENTED]": "[文本未应用]", + "LIBERATION FAILED\nOur efforts to purge Hellmire of the Terminid presence have failed.": "解放失败\n我们将终结族彻底驱逐出海尔迈尔的行动宣告失败。", + "Toxic Gas": "毒气", + "MANUALLY raise SILO LOCKS.": "手动拉起舱门锁。", + "Enemy Wave Detected": "侦测发现敌人来袭", + "Disintigration Beam": "裂解激光", + "Use REINFORCE to call in dead teammates.": "使用增援呼叫已牺牲的队友。", + "Arm Patch": "手臂贴布", + "Activating these Reinforcement Pods increases your Reinforcement Budget. \n\nReinforcements will deploy directly from a Reinforcement Pod site.": "启动增援太空舱会增加你的增援预算。\n\n增援部队将直接从增援太空舱的位置部署。", + "You have attained the rank of ASPIRANT.": "你已成为志士。", + "Illuminate Kills": "光能者击杀数", + "TRIGGER": "扳机", + "DRAUPNIR LOST\nThe Automatons have taken Draupnir. A dark day for Managed Democracy.": "德罗普尼尔沦陷\n机器人已然占领德罗普尼尔,这是管理式民主史上黑暗的一天。", + "DOUBLE TAP": "连按两次", + "Medium Illuminate Encampment Cleared": "光能者中型营地成功摧毁", + "ACHERNAR SECUNDUS FALLEN\n\nAchernar Secundus has fallen to the Terminids. The AM Defense Factory Hub has been evacuated; FRV cooldown will be increased for #VALUE hours.": "水委一次星沦陷\n\n水委一次星不幸被终结族攻占。虎将国防工厂中心已完成撤离,快速侦察载具的冷却时间将延长#VALUE小时。", + "Deaths": "死亡次数", + "PLANET LOST\nOur defenses have failed. The Terminids infest another Super Earth planet.": "星球沦陷\n我们的防线崩溃,终结族又占领了超级地球的一颗星球。", + "STATS": "数据", + "WARBOND PROGRESSION": "战争债券进度", + "An internal error occurred during the purchase, please try again later or contact support if this error persists.": "购买过程中发生内部错误,请稍后重试。如果问题仍未解决,请联系客服。", + "R&D UPDATE": "研发更新", + "REVERTING": "撤销中", + "XP": "经验", + "debug damage": "测试伤害", + "Burning": "灼烧", + "RIGHT SHOULDER": "右肩", + "INSUFFICIENT CURRENCY": "货币不足", + "DEPLETED": "耗尽", + "Requisition: #COUNT": "征用:#COUNT", + "Enter combination to equip STRATAGEM, then throw the BEACON to activate.": "输入密码,装备战略配备,然后投掷信标将其启动。", + "#PERCENTAGE%": "#PERCENTAGE%", + "D-pad": "方向键", + "Heavy": "重型", + "B3FFFBD8": "B3FFFBD8", + "ERROR #ID": "错误#ID", + "Legend": "传奇", + "Dispatch": "报告", + "This massive infestation contains a rare mutated egg of high value to Terminid research. Extract with it, and your support of scientific advancement will be rewarded.": "此处大型侵染扩张的虫群里有一颗稀有的变异虫卵,对终结族的研究价值颇高。携带该虫卵撤离,你对科研的支持工作将获得相应回报。", + "SHUTTLE ARRIVES IN T-#MINS:#SECS:#HUNDREDTHS": "运输船抵达倒计时 #MINS:#SECS:#HUNDREDTHS", + "You've unlocked a new PRIMARY WEAPON. Return to the DEMOCRACY OFFICER for your next MISSION.": "你已解锁一件新的主武器。返回民主官处开展下一项任务。", + "Establishing Up-link to Host Ship": "正在建立上链以加入主办者舰船", + "WEAPON EXPERIMENTATION\nThe Heavy Machine Gun Emplacement stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“重机枪部署支架”战略配备暂时获准供全体绝地潜兵使用。", + "If no Helldiver is alive to reinforce you, additional reinforcements will automatically be dispatched, if the budget allows.": "如果增援的绝地潜兵全部阵亡,在预算允许的情况下,会自动派遣额外的增援。", + "EXTRACTION LANDED": "撤离飞船着陆", + "Radar Wagon": "雷达车", + "From this terminal you can acquire new stratagems and upgrade your destroyer. \nYou can use this terminal to manage your Destroyer regardless of which vessel you are currently on.": "通过此终端可以获取新战略配备并升级你的驱逐舰。\n无论身处哪艘舰船,你都可以使用此终端管理自己的驱逐舰。", + "#NAME invited you to join a Clan": "#NAME邀你加入中队", + "HEETH UNDER ATTACK\nThe bugs have attacked Heeth. Rally to its defense, before they are able to permanently infest it.": "希斯遭到袭击\n虫族对希斯发动了袭击。立即集结,前去防卫,避免领地永远落入敌人手里。", + "Hive": "虫窝", + "INGMAR UNDER ATTACK\nThe Automatons are attempting to steal Ingmar from our noble citizens. Do not let them, Helldivers.": "英格玛遭到袭击\n机器人企图从我们高贵的公民手中窃走英格玛,不要让它们得逞,绝地潜兵。", + "Mission starting, Helldivers to Hellpods!": "任务开始,请绝地潜兵到喷射舱集合!", + "Super Earth's price index is undergoing fluctuation; please review the current pricing info and re-issue your requisition.": "超级地球的物价指数目前忽起忽落。请核实当前的价格信息,然后重新申购。", + "KNOW YOUR ENEMY": "知己知彼", + "SIGNAL STRENGTH": "信号强度", + "NEW TARGET": "新目标", + "Change Button": "更改按键", + "#CURRENT_XP / #NEXT_XP": "#CURRENT_XP / #NEXT_XP", + "#NAME left the mission": "#NAME退出任务", + "EXTRACTION TAKEOFF": "撤离飞船起飞", + "CYBERSECURITY UPDATE\nA recent systems security breach has resulted in Galactic War tables displaying inaccurate information. The breach has been addressed, and all systems have been returned to normal operation. Any discrepancies are to be considered the result of dissident misinformation.\n\nRest assured that the parties responsible have been identified, arrested, tried, and executed.": "网络安全更新\n最近发生的系统安全漏洞攻击事件导致星系战争的议战桌显示信息有误。该漏洞现已修复,所有系统均已恢复正常运行。任何不一致之处均将被视为异见者扭曲信息的结果。\n\n肇事者已探明、逮捕、审判和处决,敬请放心。", + "MUTATED EGGS": "变异虫卵", + "NNW": "西北偏北", + "Resuming Hosting.": "正在恢复主办者状态。", + "Super Destroyer withdraws in #MINUTES:#SECONDS": "超级驱逐舰撤离倒计时 #MINUTES:#SECONDS", + "Planetary Bombardment": "星球轰炸", + "CHARGE": "充能", + "NNE (#COUNT°)": "东北偏北#COUNT°", + "ONGOING #MM#M:#SS#S": "正在进行 #MM#M:#SS#S", + "INTELLIGENCE BRIEF\n\nAs anticipated, the Automatons have deployed a new gunship-style unit on all battlefronts. It was only a matter of time before their totalitarian conquest expanded skyward. \n\nFortunately, due to the advance warning provided by the communication array on Troost, Helldiver arsenals have been augmented to combat this threat. Helldivers will continue to find the EAT-17 Expendable Anti-Tank Stratagem included in all loadouts for the near future.": "情报简报\n \n不出所料,机器人已在所有战场前线部署一种新型炮舰式单位。它们迟早会把极权主义的铁爪伸向我们的领空。\n \n万幸的是,特鲁斯特上的通讯阵列已提前发出警告,绝地潜兵武器库得以及时扩充,以应对此次危机。未来一段时间内,绝地潜兵的全部武装配置都将继续追加“EAT-17消耗性反坦克武器”战略配备。", + "Mutated Eggs": "变异虫卵", + "Buy (RQ)": "购买(申购点)", + "SKN": "涂装", + "POISON": "剧毒", + "SLOWED": "减速", + "Barbed Wire": "倒刺铁丝网", + "Hold": "按住", + "x10 RARE SAMPLES": "x10稀有样本", + "ERATA PRIME LOST\nThe defense of Erata Prime has failed. Terminids now run amok on its surface. We cannot allow this corruption of Liberty to stand.": "艾拉特主星沦陷\n艾拉特主星保卫战已宣告失败。终结族现在正四处肆虐。我们不能任由它们继续侵犯自由伟业。", + "TERMINID INVASION\nThe bugs are attempting to spread to another one of our planets. We must drive them off! Report to the Galactic Map for more information.": "终结族入侵\n虫族企图扩张至我们的另一颗星球。我们必须驱逐它们!通过星系地图报到,了解更多信息。", + "WEAPON EXPERIMENTATION\nThe Eagle 500kg Bomb stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“‘飞鹰’500kg炸弹”战略配备暂时获准供全体绝地潜兵使用。", + "Tier 2": "2阶", + "Requisition ORBITAL SHELL stratagem.": "申购轨道炮弹战略配备。", + "Helldivers operate against the clock. Complete your mission before the SUPER DESTROYER leaves low orbit.": "绝地潜兵的行动必须争分夺秒。要在超级驱逐舰离开低空轨道前完成任务。", + "Return to the DEMOCRACY OFFICER.": "返回民主官处。", + "NOT ENOUGH MEDALS": "奖章不足", + "PHASE 1": "第1阶段", + "RELEASE": "松开", + "Account for PlayStation™Network not allowed to login. Please contact Community managers": "账号禁止登录PlayStation™Network。请联系社区管理员", + "Playfab Session Ticket Validation Error": "Playfab会话票据验证错误", + "GALACTIC WAR": "星系战争", + "INTERACT": "互动", + "Shuttle approaching.\nDefend extraction zone.": "运输船即将驶近。\n请在撤离区坚守。", + "[#NAME]": "[#NAME]", + "Open the SOCIAL MENU. Here you can see your friends' activities and JOIN A MISSION.": "打开社交菜单。你可以在这里查看好友的动态,并且加入任务。", + "Searching for active SOS beacons...": "正在寻找激活的S.O.S.求救信标…", + "LEGENDARY WARBOND NEEDED": "需要传奇战争债券", + "On Main Menu": "浏览主菜单", + "WEAPON EXPERIMENTATION\nThe Orbital 380mm HE Barrage stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“轨道380mm高爆弹火力网”战略配备暂时获准供全体绝地潜兵使用。", + "to adjust relay dish": "调整中继天线", + "LEGENDARY": "传奇", + "Level #LEVEL | #TITLE": "#LEVEL级 | #TITLE", + "Failed to join game lobby, Timed out.": "无法进入游戏大厅,已超时。", + "ATTACKING": "攻击", + "PRESS": "按下", + "SELECT REINFORCEMENT LOCATION": "选择增援地点", + "GRENADE": "榴弹", + "NOTICE": "通知", + "#ITEM": "#ITEM", + "REWARD": "奖励", + "MOVE CURSOR": "移动光标", + "ENCYCLOPEDIA": "百科全书", + "There is already another upgrade request on flight, try again in a few seconds.": "正在处理另一项升级请求,请稍后再试。", + "ARC": "电弧", + "COMING SOON!": "即将上线!", + "AMMO TYPE": "弹药种类", + "HEAVY COMBAT (BOTS)": "重型作战(机器人)", + "ANGEL'S VENTURE DEFENDED\nThanks to the selfless valor of the Helldivers, the citizens of Angel's Venture are safe from the Terminid Menace.": "成功保卫天使投资星系\n在无私的绝地潜兵的英勇付出下,天使投资星系的公民终于摆脱了终结族的威胁。", + "Mk5b 'Tactical'": "Mk5b“战术”", + "NEW": "全新", + "Release": "松开", + "Unable to join game": "无法加入游戏", + "ERATA PRIME UNDER ATTACK\nTerminid spores fill the skies of Erata Prime. All Helldivers are called to the planet's defense!": "艾拉特主星遭到袭击\n终结族孢子遍布艾拉特主星上空。呼唤全体绝地潜兵,前去保卫该星球!", + "New equipment has now been deployed to every Super Destroyer in the galaxy. Use it to deliver Freedom, Helldivers.": "新装备现已部署至银河系所有的超级驱逐舰上。绝地潜兵,请尽情使用,传播自由。", + "MAJOR ORDER FAILED": "未完成重要指令", + "WEAPONS": "武器", + "ERATA PRIME DEFENDED\nThe bugs have been repelled from Erata Prime. Citizens across the planet hold celebrations in honor of the Helldivers' heroism.": "成功保卫艾拉特主星\n我们已将虫族逐出艾拉特主星。全星球的公民一起举办了庆典活动,纪念绝地潜兵的英勇之举。", + "FF71F5FF": "FF71F5FF", + "FEWER STIMS": "治疗剂减少", + "Grenade Kills": "榴弹击杀数", + "RECEIVED: YESTERDAY": "接收:昨天", + "300 SC": "300超级货币", + "Patrols sound the alarm which causes ENCOUNTERS!": "巡逻队会发出警报,引发遭遇战!", + "NO AMMO": "没有弹药", + "PURCHASE MEDALS": "购买奖章", + "Do you want to replay the tutorial mission?": "要重新执行教程任务吗?", + "DIFFICULTY 7 TRIAL": "难度7级考验", + "Some targets are HEAVILY ARMORED. Hit weak spots or use armor-piercing weapons!": "部分目标装备了重型护甲。要攻其弱点或是使用穿甲武器!", + "ABANDON MISSION WITH SQUAD": "与小队放弃任务", + "Select your Drop Location anywhere on the mission map - Try to avoid dangerous locations.": "在任务地图上选择任意降落地点,尽量避开危险地点。", + "#SECONDS SEC": "#SECONDS秒", + "COMBAT (ILLUMINATE)": "作战(光能者)", + "VELD DEFENDED\nThe defense of Veld has succeeded. The Terminids have been repelled.": "成功保卫维尔德\n维尔德保卫战以胜利告终,终结族已被击退。", + "ENEMY RETREAT": "敌军撤退", + "Light Bug Nest Eradicated": "轻型巢穴成功摧毁", + "You have new rewards to collect!": "你有新的奖励可以领取!", + "MAIN MENU": "主菜单", + "Medium Automaton Outpost Destroyed": "中型机器人哨站成功摧毁", + "Premium": "尊享", + "Fangs": "尖牙", + "The Illuminate masses overwhelmed the Helldiver forces and spread unchecked to planetX. The loss of these planets mean that strategic resources to Helldivers may encounter logistic issues, please report to your Ship Master for more information. \n\nIf the spread is not contained here, it is not an exaggeration to assume that mindless masses could be walking the streets of Super Earth within weeks.": "光能者群氓势头力压绝地潜兵部队,并肆无忌惮地蔓延至X星。这些星球的沦陷可能导致战略资源的后勤供应受阻,请向您的舰长报告以获取更多信息。\n\n如果不遏止这一蔓延,数周之内,无脑群氓大军可能会出现在超级地球的街道。", + "Perfect Bonus": "完美加分", + "Samples Collected": "收集样本数", + "NO SERVERS": "无服务器", + "Damage Type: #DAMAGE_TYPE": "伤害类型:#DAMAGE_TYPE", + "DECIMATING THE ENEMY": "横扫千军", + "PAGE_#PAGE_NUMBER": "第#PAGE_NUMBER页", + "Auto": "自动", + "Drowning": "淹溺", + "Explosive Handshake": "热烈握手", + "Throw GRENADES into bug nests to destroy them.": "把榴弹丢进虫族巢穴,将其摧毁。", + "Failed to join game lobby, Helldiver in training.": "无法进入游戏大厅,绝地潜兵正在训练。", + "Failed to join as target host is currently in a single-player session.": "目标主办者当前设定为单人游戏模式,加入失败。", + "BACK-PACKING A PUNCH": "重拳出击", + "VEHICLE PATTERN": "载具涂装", + "Each Planet has a number Operations available. Complete Operations to reduce enemy presence and earn rewards.": "每颗星球都设有一定数量的行动。完成行动即可削弱敌方势力,获得奖励。", + "ARMORY": "防具", + "OPACITY": "不透明度", + "to switch between PRIMARY and SUPPORT WEAPON.": "切换主武器和支援武器。", + "Distribute Ballots": "派发选票", + "STANDARD WARBOND": "标准战争债券", + "#COUNT DAYS AGO": "#COUNT天前", + "Up Button": "上方向键", + "FLY LIKE AN EAGLE": "鹰击长空", + "[none]": "[无]", + "DEMOCRACY TERMINAL": "民主终端", + "ERROR": "错误", + "W": "西", + "MANTES LOST\nThe defense of Mantes has failed. We cannot allow the Automaton aggression to continue.": "蒙特斯沦陷\n蒙特斯的防线已经崩溃,我们不能任由机器人继续进犯。", + "Common Samples": "普通样本", + "Exalted Hero": "伟人", + "Environment": "环境", + "RECHARGING": "正在充能", + "Defend Area": "守卫区域", + "to place a waypoint on the map": "在地图上标记路径点", + "SELECT SLOT": "选择槽位", + "SEAF Artillery Ammo Rack": "超级地球武装部队炮弹挂架", + "Join this server and travel to their ship?": "要加入本服务器并登上对方的飞船吗?", + "CONTROL CENTER": "控制中心", + "WEAPON PROGRESSION": "武器进阶", + "OBJECTIVE UPDATED": "目标已更新", + "INBOUND #MM#M:#SS#S": "即将抵达 #MM#M:#SS#S", + "#COUNTrpm": "#COUNT RPM", + "COLOR PICKER": "选取颜色", + "JOIN FAILED": "加入失败", + "R. LEG": "右腿", + "Reinforce Stratagems Used": "增援战略配备使用次数", + "INTO THE GALAXY": "向星系进发", + "WNW": "西北偏西", + "NNE": "东北偏北", + "SUPERSTORE": "超级商店", + "The voteless have taken planetX and planetY by sheer numbers, but they haven’t broken the spirit of the Helldiver resistance. \n\nThe Illuminate, who will only be satisfied when the galaxy bends to their liberal will, may think that they are victorious against the forces of Super Earth - but they could never know the hot-blooded Democratic drive for vengeance. That will be their downfall. Helldivers take back what is ours and if that means cleaning squid guts from the tire tracks of our FRV fleet, so be it.": "无票者凭借绝对的数量优势占领了X星和Y星,但未能击垮绝地潜兵的抵抗意志。\n\n只有当整个星系都屈服于光能者的自由意志时,他们才会心满意足。他们或许认为已经战胜超级地球的军队——但他们永远无法理解激荡着热血的民主复仇渴望。而这将令他们走向覆灭。绝地潜兵定会夺回属于我们的东西。如果需要从快速侦察载具车队的轮胎印里清理鱿鱼内脏,那就这么办吧。", + "CONFIRM": "确认", + "Platoon": "特战排", + "Talk to the DECK OFFICER.": "与舱面事务官对话。", + "Spend your RESEARCH POINT to ADVANCE your HELLDIVER PROGRESSION TRACK.": "花费研究点数,推进绝地潜兵进度条。", + "EXPLOSIVE": "炸弹", + "STIM": "治疗剂", + "HIGH-FIVE": "击掌", + "Extraction Zone": "撤离区", + "Due to an unexpected pilot shortage, extraction times will be longer than normal for the near future.": "由于驾驶员意外短缺,近期的撤离行动耗时较平时有所延长。", + "SUPER CREDITS": "超级货币", + "TEMPORARY PERMIT": "临时许可", + "to aim": "瞄准", + "Optics": "准镜", + "LIBERATION FAILED\nWe have failed to cleanse Heeth of the Terminid infestation.": "解放失败\n我们未能彻底剿灭占据希斯的终结族。", + "LEFT SHOULDER": "左肩", + "TRANSFER STATION": "中转站", + "#COUNT/#TOTAL": "#COUNT/#TOTAL", + "TOGGLE INFO": "切换详情", + "Connection regained.": "连接已恢复。", + "No Broken Limbs": "四肢没有受伤", + "DROP LOCATION": "降落地点", + "HELLMIRE DEFENDED\nAfter countless noble and unavoidable sacrifices, Hellmire has been defended from the Terminids.": "成功保卫海尔迈尔\n无数不可避免的光荣牺牲终于换来回报,我们顺利从终结族手下守住了海尔迈尔。", + "MAP PING": "地图标记", + "MALEVELON CREEK HAS BEEN LIBERATED\nAt long last, Malevelon Creek is free. The Automaton's iron grip on the planet has been pried loose. The war-torn planet will forever bear the scars of its struggle, and the sacrifices of the countless heroes lost there will never be forgotten.\n\nColonists are returning to the ruins of their settlements, but with hope in their chests. For at last, sunlight dawns upon a free Creek.": "麦拉芬蒙河已得到解放\n麦拉芬蒙河终于得到解放,从机器人的铁爪掌控下挣脱。这颗饱受战争折磨的星球将永远背负血汗的疮疤,无数陨落英雄的牺牲也将被铭记。\n\n拓殖地居民陆续返回定居点的废墟,但此刻,他们心怀希望。阳光总算照亮了这方大地。", + "Out of Stims! Call in a Resupply to replenish.": "治疗剂耗尽!呼叫重新补给进行补充。", + "FFFFFF5E": "FFFFFF5E", + "Due to unmet Helldiver training quotas, personnel loss will need to be decreased for the short term. Therefore, Helldivers will deploy with increased stims until further notice.": "由于绝地潜兵训练指标未能达成,短期内需要减少人员损失。因此,绝地潜兵将携带更多治疗剂奔赴战场,直至另行通知为止。", + "RESUME": "继续游戏", + "Go to the Ship Management Terminal to acquire new Stratagems and upgrade your Destroyer.": "前往舰船管理终端获取新的战略配备,以及升级驱逐舰。", + "MAJOR ORDER FAILED\nWe have failed to fully activate the Terminid Control System. Until we do, the Terminids will continue to slip through the cracks, spreading their tyranny to the backyards of our innocent citizens.": "重要指令未完成\n终结族遏制体系未能全面启动。终结族将继续穿过裂缝,将暴政传播至无辜公民的后院,直至遏制体系成功启动为止。", + "SKIP": "跳过", + "MEDALS RECEIVED": "已收到奖章", + "33FFFEE1": "33FFFEE1", + "RESPAWN IN": "复活倒计时:", + "Do you want to quit the game?": "要退出游戏吗?", + "Left Stick": "左摇杆", + "Are you sure you want to use your Warbond Token to unlock \"#WARBOND\" Premium Warbond?": "是否确定要使用战争债券代币解锁“#WARBOND”尊享战争债券?", + "RESET TO DEFAULT": "重置为默认", + "Throwable Weapon": "投掷武器", + "Mouse Wheel": "鼠标滑轮", + "Fire Tornado Warning": "烈焰龙卷风警告", + "TRAVEL": "前往", + "This is the ship's armory. Here you can get an overview of the ship's arsenal and prepare for the next mission.": "这里是舰船的军械库。在这里你可以了解这艘舰船上的军火储备概况,为下一项任务做准备。", + "LASER GUIDE": "激光制导", + "STRATAGEMS": "战略配备", + "MULTIPLAYER": "多人游戏", + "Bug Breach Detected": "侦测发现虫族入侵", + "to use a Stim on yourself": "对自己使用治疗剂", + "HELLDIVERS TO HELLPODS": "绝地潜兵进入绝地喷射舱", + "BUY PREMIUM WARBOND": "购买尊享战争债券", + "You have sustained an INJURY. Injuries make you move slower, aim worse or can even make you bleed to death.": "你受到了损伤。损伤会降低你的移动速度,削弱你的瞄准能力,甚至有可能导致流血至死。", + "The Mindless Masses continue to emerge from the Void with persistent arrogance. Continue to cull the voteless near the Void while holding planetX and planetY against the Illuminate. The more Illuminates that fall, the greater chance Super Earth scientists will be able to find a way to penetrate the Void and bring the fight to them. \n\nThe FRV campaign has been highly effective against the mindless masses. However, Helldivers are needed to acquire precious metals to support production demands of FRVs called to the front. These resources are found by melting down the carcasses of the unfeeling Automaton units - for every Bot cut down in combat, a Helldiver is that much closer to joyriding a new FRV over the bodies of countless Illuminate. A cause worth fighting for.": "无脑群氓带着傲慢不停地从寂域中涌出。在寂域周边继续剿杀无票者,同时坚守X星和Y星,抵御光能者侵略。倒下的光能者越多,超级地球的科学家们就越有可能找到穿透寂域、直捣其大本营的方法。\n\n快速侦察载具在对抗无脑群氓方面卓有成效。为了支持前线的生产需求,我们需要绝地潜兵获取贵金属。通过熔毁冷血机器人部队的残骸可以获得这些资源——每砍翻一个机器人,绝地潜兵就更接近驾驶崭新快速侦察载具,体验碾压光能者尸体的快感。这是一项值得为之战斗的事业。", + "EQUIP": "装备", + "Paste in a friend code to start searching.": "粘贴好友代码,开始搜索。", + "Player Card": "玩家名片", + "RPM": "转速", + "OVERRIDE HELLPOD STEERING": "取得绝地喷射舱控制权限", + "#SECONDS UNTIL MISSION EXPIRES": "距离任务过期还有#SECONDS", + "Claim rewards": "领取奖励", + "Semi": "半自动", + "50% bonus to Requisition and XP awarded per mission": "每项任务额外奖励50%申购点和经验", + "CALL": "呼叫", + "FFFF4752": "FFFF4752", + "Dispatches": "快件", + "to equip your Grenades": "装备榴弹", + "MAJOR ORDER FAILED\nOperation Swift Disassembly has failed. Though we have made great gains against the Automatons, still their factories remain, fabricating ever-more threats to Liberty.\n\nThe fight does not end here. We will not rest until their despotic presence is utterly annihilated. Our citizens deserve no less. Await further orders.": "重要指令失败\n急速拆解行动已宣告失败。虽然我们在对抗机器人的战斗中取得了巨大胜利,但敌方孵化厂依然坚挺,源源不断制造出更多威胁自由之敌。\n\n战斗尚未结束。在将它们的暴虐专制彻底消灭前,我们绝不会偃旗息鼓。我们的公民值得享有彻底的和平。等待进一步的命令。", + "Heavy Illuminate Encampment Cleared": "光能者重型营地成功摧毁", + "FUEL OUTPUT": "燃料输出点", + "Sort": "排序", + "Ammunition depleted, switch weapon!": "弹药耗尽,切换武器!", + "MACHINE GUN": "机枪", + "AMMO": "弹药", + "GETTING SERVERS": "正在获取服务器", + "More Info": "其他详情", + "Customize": "自定义", + "EXTRACTION": "撤离", + "SE": "东南", + "The Advanced Liberation Tools Research Agency (ALTRA) has tested successful prototypes of a new combat asset. Helldivers are advised to review proper mechanical operation procedures in preparation for the incoming asset.": "先进解放工具研究局(ALTRA)开发的新型作战装备样机顺利通过测试。建议绝地潜兵提前复习正确的机械操作步骤,准备将来使用该装备。", + "Game version mismatch, please update your game": "游戏版本不匹配,请更新游戏", + "The Great Host": "大军", + "Phase-Beam": "相位光束", + "Are you sure you want to use your Warbond Token to unlock '#WARBOND' standard Warbond?": "是否确定要使用战争债券代币解锁“#WARBOND”标准战争债券?", + "Double Tap": "连按两次", + "Steel Foot": "钢足", + "Assignments": "分派任务", + "Claws": "螯爪", + "ANGEL'S VENTURE FREED\nAngel's Venture has been freed from the Terminids, thanks to your unhesitating sacrifice. It is now under Super Earth control, where it belongs.": "天使投资星系已解放\n在你们毫无迟疑的牺牲下,天使投资星系摆脱了终结族的掌控。它现在已经回到超级地球治下,重返家园。", + "NE": "东北", + "Total Stratagems Used": "战略配备总使用次数", + "CRIMSICA UNDER ATTACK\nThe Terminids are attempting to spread to Crimsica. All Helldivers are called upon to deploy immediately to the planet's defense.": "克里姆西卡遭到袭击\n终结族企图扩张至克里姆西卡。呼唤全体绝地潜兵,立即前去保卫该星球。", + "#CURR of #TOTAL": "#CURR/#TOTAL", + "THREAT": "威胁", + "GEAR: #GEAR": "装备:#GEAR", + "AWAITING REINFORCEMENT": "正在等待增援", + "Venerate": "敬仰", + "Fresh SEAF recruits filled with patriotic fervor for the destruction of the Automatons have surged to take significant ground on Durgen.": "满腔爱国热情、誓要摧毁机器人的超级地球武装部队新进后备军已经在德尔根占领了重要阵地。", + "NEW MAJOR ORDER\nTien Kwan is home to the sole arsenal of new Exosuit technology. It is only a matter of time before the Automatons discover the arsenal and steal it for themselves. Liberate Tien Kwan, before it's too late.": "新重要指令\n天关坐落着唯一一家掌握新型外骨骼装甲科技的军械厂。机器人迟早会发现这座军械厂,窃取相关技术,为己所用。立即解放天关,以免为时过晚。", + "Currently onboard:": "目前已登船:", + "Are you sure you want to purchase #COUNT #ITEM Medals for": "是否确定购买#COUNT枚#ITEM奖章并花费", + "ALL BOOSTERS": "所有强化资源", + "x20 COMMON SAMPLES": "x20普通样本", + "Change aim mode while aiming to use WEAPON SCOPE.": "瞄准时切换瞄准模式可使用武器瞄准镜。", + "Off": "关", + "Filter visible Missions based on difficulty.": "根据难度筛选显示的任务。", + "DROP #ITEM": "投放#ITEM", + "(#MINSm #SECSs)": "(#MINSm #SECSs)", + "The Void, a region of space that has gone completely dark under Illuminate control, expanded without warning. Two planets are gone and nearby planets are overrun with deceitful Illuminate interlopers. The Void surge must be stopped before any additional planets fall.": "数个银河标准小时前,受到光能者控制、陷入彻底黑暗的星域——寂域,在毫无预警的情况下发生了扩张。两颗星球已消失,而邻近星球则被狡诈的光能者入侵者淹没。我们必须在更多星球惨遭吞噬之前,遏止寂域的扩张。", + "EMOTES": "表情", + "CRIMSICA DEFENDED\nThe defense of Crimsica has succeeded. The Terminids have been repelled.": "成功保卫克里姆西卡\n克里姆西卡保卫战以胜利告终,终结族已被击退。", + "Account must be logged in with Playfab to use this functionality": "必须通过Playfab登录账号才能使用该功能", + "Your game version is out of date, please update your game": "你的游戏版本过低,请更新游戏", + "Messages": "消息", + "Select the Equipment and Stratagems to bring on this Mission.": "选择你要在此次任务中携带的装备和战略配备。", + "A HELPING HAND": "施以援手", + "Enter a REQUISITION TERMINAL and requisition more STRATAGEMS.": "进入申购终端,申购更多战略配备。", + "Illuminate Staff": "光能者长杖", + "ASPIRANT": "志士", + "Your chest is bleeding, causing continuous health loss.": "你的胸腔在出血,将导致你持续损失生命值。", + "When the enemy successfully calls for reinforcements, threat level increases.\n\nThis means higher enemy presence for the duration of the mission.": "当敌人成功呼叫增援,威胁等级便会提升。\n\n也就是说,任务期间敌人数量更多。", + "Enter an ARMORY STATION and ADVANCE your current PROGRESSION TRACK.": "进入军械库站点,推进当前的进度条。", + "Joining Session.": "正在加入游戏。", + "Requisition RESUPPLY Stratagem permit.": "申购重新补给战略配备许可证。", + "Select": "选择", + "#OBJECTIVE_NAME\n#TIME_REMAINING": "#OBJECTIVE_NAME\n#TIME_REMAINING", + "SAVE & CLOSE": "保存并关闭", + "WEAPON EXPERIMENTATION\nThe Ballistic Shield Backpack stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“防弹护盾背包”战略配备暂时获准供全体绝地潜兵使用。", + "ADJUST BRIGHTNESS": "调节亮度", + "Interact": "互动", + "Incoming DSS Orbital Bombardment": "民主空间站轨道轰炸来袭", + "SEASON II": "第II赛季", + "Requires another item you do not yet own.": "需要另一件你尚未拥有的物品。", + "Next Reward": "下一项奖励", + "An unusually large Terminid spawning has led to sudden, significant loss of ground on Planet #V_ONE.": "终结族孵化规模异常激增,突如其来的变化导致我方在#V_ONE星球上损失重要阵地。", + "R#RANK": "级别#RANK", + "STOP": "暂停", + "CREDITS": "工作人员名单", + "Obstructed by Anti-Air": "被防空系统阻拦", + "New STRATAGEMS available for REQUISITION.": "全新战略配备可供申购。", + "EXTRA IS REQUIRED": "尚需努力", + "There are unsaved changes to your weapon config. Would you like to accept these changes or continue without saving?": "武器配置存在未保存的更改。是否接受这些更改,或放弃保存以继续?", + "BACK": "返回", + "Intel": "情报", + "Shuttle landed.\nBoard shuttle.": "运输船着陆。\n请迅速登船。", + "DIFFICULTY 8 TRIAL": "难度8级考验", + "Rotate": "旋转", + "#ITEM Medals x#COUNT": "#ITEM奖章 x#COUNT", + "50 SC": "50超级货币", + "FFFFFFEE": "FFFFFFEE", + "HOLD TO PURCHASE": "按住购买", + "LIGHT COMBAT (BUGS)": "轻型作战(虫族)", + "AN UNKNOWN SERVER ERROR HAS OCCURRED": "服务器发生未知错误", + "FF666666": "FF666666", + "Some DualSense® wireless controller and DUALSHOCK®4 wireless controller features may not work as intended with Steam Input enabled, and the default layout may not work as expected. We recommend disabling Steam Input for these controller types.": "启用Steam Input后 DualSense®无线控制器和DUALSHOCK®4无线控制器的部分功能可能无法正常运行,默认布局也可能无法正常运作。我们建议禁用这类控制器的Steam Input功能。", + "ROCK PAPER SCISSORS": "石头剪刀布", + "Quickly navigate between available Missions.": "快速浏览各项可选任务。", + "SUBMACHINE GUN": "冲锋枪", + "#CURRENT / #TARGET": "#CURRENT / #TARGET", + "CONFIRM JOIN": "确认加入", + "WEAPON EXPERIMENTATION\nThe Shield Generator Relay stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“防护罩生成中继器”战略配备暂时获准供全体绝地潜兵使用。", + "CONFIDENTIAL DATA": "机密数据", + "#COMMAND": "#COMMAND", + "INVENTORY OPTIONS": "物品栏选项", + "Inspect (Hold)": "查看(按住)", + "REINFORCE READY": "增援就绪", + "to check map waypoint": "查看地图路径点", + "EQUAL-OPPORTUNITY LIBERATION": "平等、机遇、解放", + "#NAME DIED": "#NAME阵亡", + "YOUR FIRST DIVE": "第一次作战", + "RARE SAMPLE": "稀有样本", + "Select a location where you want to drop in on the mission.": "选择你计划在任务中降落的位置。", + "Give Refill": "提供补给", + "COMBAT STIMS": "作战治疗剂", + "WEAPON EXPERIMENTATION\nThe LAS-98 Laser Cannon stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“LAS-98激光大炮”战略配备暂时获准供全体绝地潜兵使用。", + "Adjust Tilt": "调整倾斜角度", + "MORT LOST\nThe defense of Mort has failed. We cannot allow the Automaton aggression to continue.": "莫特沦陷\n莫特的防线已经崩溃,我们不能任由机器人继续进犯。", + "Inactive": "未激活", + "AUTOMATON INVASION\nThe Automatons have launched another cowardly assault. All available Helldivers are called to fight them off! Report to the Galactic Map for more information.": "机器人入侵\n机器人发动了另一场懦弱的袭击。呼叫所有可行动的绝地潜兵,立刻前去应战!通过星系地图报到,了解更多信息。", + "PLANT": "插旗", + "A Major Order has been failed. Check the Galactic Map for more information.": "一项重要指令未能完成。查看星系地图了解更多信息。", + "HELLMIRE FREED\nHellmire has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet.": "海尔迈尔已解放\n海尔迈尔挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。", + "Operator:": "操作员:", + "Are you sure you want to unlock '#WARBOND' standard Warbond for": "是否确定要解锁“#WARBOND”标准战争债券并花费", + "#COUNT°": "#COUNT°", + "OFFENSIVE": "进攻", + "SORRY": "对不起", + "SATURATION": "饱和度", + "EXPLOSIVE BARREL": "爆炸桶", + "PREPARE FOR FTL JUMP": "准备启动超光速跃迁", + "Failed to join as target host is running a different network config.": "加入失败,你与目标主办者的网络配置不同。", + "Waiting For Players": "等待玩家加入。", + "WSW (#COUNT°)": "西南偏西#COUNT°", + "TOGGLE READY": "切换准备状态", + "Serrated Claws": "锯齿螯爪", + "Electric Shock": "电击", + "ORBITAL": "轨道武器", + "59FF4752": "59FF4752", + "Mega Nest": "超巨巢穴", + "VEHICLE": "载具", + "Damage Over Time": "持续伤害", + "CONTINUE": "继续", + "Jump to Current Level": "跳到当前关卡", + "INT": "枪内", + "Illuminate Ships Incoming": "光能者舰船即将抵达", + "N": "北", + "Select a Mission and get ready to dive.": "选择一项任务,准备深潜绝地。", + "OPTIONS": "游戏设置", + "MANUALLY align RADAR DISH.": "手动校准雷达天线。", + "MISSION TIMER EXPIRED - REINFORCE NO LONGER POSSIBLE": "任务过期,无法再呼叫增援", + "N/A": "不适用", + "MERIDIA UNDER ATTACK\nThe Terminids are attempting to spread to Meridia. All Helldivers are called upon to deploy immediately to the planet's defense.": "默里迪亚遭到袭击\n终结族企图扩张至默里迪亚。呼唤全体绝地潜兵,立即前去保卫该星球。", + "OK": "确定", + "A Major Order has been completed. Check the Galactic Map for more information.": "一项重要指令已完成。查看星系地图了解更多信息。", + "SHUTTLE PATTERN": "运输船涂装", + "Velocity": "速率", + "All Barrels": "全枪管", + "SAVE": "保存", + "MARK": "标记", + "MISSIONS": "任务", + "Mission stats could not be displayed due to a network issue. Mission completion rewards and extracted resources are unaffected and have been handed out normally.": "由于网络问题,无法显示任务数据。完成任务的奖励和提取的资源没受到影响,已正常发放。", + "WEAPON CUSTOMIZATION UNLOCKED": "武器自定义已解锁", + "You have attained the rank of HERO.": "你已成为英雄。", + "BOOSTING SIGNAL... #COUNT": "正在增强信号……#COUNT", + "You do not meet the level requirements to unlock this item.": "等级不符,无法解锁此物品。", + "EXAMINE": "观察", + "LOCKING DRILL POSITION": "正在锁定钻机位置", + "ORDERS": "指示", + "SPECIAL THROWABLE": "特殊投掷武器", + "Supply Stratagems Used": "补给战略配备使用次数", + "OBJECTIVE FAILED": "目标未达成", + "Invite to Platoon": "邀请加入特战排", + "Extraction is now available! Head towards the EXTRACTION BEACON to end the mission.": "现在可以撤离!前往撤离信标结束任务。", + "GALACTIC WAR CONNECTION ERROR": "星系战争连接出错", + "Meat Saw": "肉锯", + "Commend other Helldivers for good behavior!": "多多称赞其他绝地潜兵的优秀表现!", + "You have attained the rank of EXALTED HERO! You have a 5% discount on all premium items.": "你已成为伟人!购买所有尊享物品均可享受5%的折扣优惠。", + "The path has been cleared to the Barrier Planets. SEAF Engineers will now begin constructing the Terminid Control System. Well done, Helldivers.": "前往屏障星球的路线已经打通。超级地球武装部队的工兵即将着手建设终结族遏制体系。干得好,绝地潜兵。", + "CHARGING": "正在充能", + "#NAME returned to civilian life": "#NAME已回归平民生活", + "Toggle View": "切换视图", + "RELOAD": "装填弹药", + "Retrieve WEAPON.": "取回武器。", + "If you don't have a RESUPPLY, scavenge for ammunition or request help from your teammates.": "如果你没有重新补给,那就要设法搜集弹药或是向队友寻求帮助。", + "Explosive Barrel": "爆炸桶", + "Invite": "邀请", + "SAMPLES": "样本", + "Enemy Anti-Aircraft": "敌方防空范围", + "Connection to server failed": "未能连接至服务器", + "Options": "游戏设置", + "COMBAT (BUGS)": "作战(虫族)", + "to sprint": "冲刺", + "DROPPING IN": "正在降落", + "You have almost taken all planets en route to ANGEL'S VENTURE. We are on the verge of clearing the way for construction of the Terminid Control System. Press on!": "你们几乎已经占领通往天使投资星系的所有星球。我们即将为构建终结族遏制体系扫清所有障碍。继续努力!", + "MAG": "弹匣", + "MORE EFFECTIVE MISSIONS": "任务效率提高", + "Eagle Storm": "“飞鹰”风暴", + "In-Mission Time": "任务执行时长", + "YOUR FINAL SCORE": "你的最终得分", + "OPERATIONS": "行动", + "#STATUS on #PLANET": "在#PLANET上#STATUS", + "PREMIUM": "尊享", + "Rotate Antenna": "旋转天线", + "Level #COUNT": "#COUNT级", + "LIBERATION FAILED\nDespite innumerable sacrifices, we have failed to liberate Erata Prime from the Terminid's tyrannical clutches.": "解放失败\n尽管付出了无数的牺牲,我们还是未能将艾拉特主星从终结族的暴虐魔爪中解放出来。", + "Are you sure you want to unlock \"#WARBOND\" Legendary Warbond for": "是否确定要解锁“#WARBOND”传奇战争债券并花费", + "These are the active missions that you must complete to succeed in the operation.\n\nSelect your first mission in the operation.": "你必须完成已激活的任务才能顺利完成这次行动。\n\n请选择你在本次行动中的第一项任务。", + "A SAMPLE CONTAINER was dropped. Pick it up to retrieve the SAMPLES it contains.": "一个样本容器掉落。把它捡起来,收回里面的样本。", + "GROWING STRONGER": "茁壮成长", + "Requisition GRENADE LAUNCHER Stratagem permit.": "申购榴弹发射器战略配备许可证。", + "Preview": "预览", + "Missions": "任务", + "AUTOMATON COUNTERATTACK\nIntercepted messages indicate bot plans for a significant push. Increased resistance on Automaton planets is anticipated.": "机器人反攻\n截获的情报显示,机器人计划大举反攻。预计各机器人星球的反抗力度将大幅加剧。", + "#ONLINE ONLINE  #COUNT IN GAME": "#ONLINE人在线 #COUNT人正在游戏", + "RATE OF FIRE": "射速", + "Search": "搜索", + "YES": "是", + "NEW MAJOR ORDER\nThe Automatons have menaced our citizenry long enough. With the Terminids in check, the time has come at last to eradicate this robot scum from our galaxy.\n\nEradicate the Automatons from every single planet they occupy. Leave none in operation.": "新重要指令\n长久以来,机器人一直威胁着我们的公民。鉴于终结族已为我方所控制,是时候将这些机器人渣滓彻底逐出我们的星系了。\n\n在机器人占据的每一颗星球上,将它们全数剿灭,一个不留。", + "ZOOM": "缩放", + "EXTRACT": "撤离", + "#NAME leveled up #WEAPON to level #LEVEL": "#NAME已升级#WEAPON至#LEVEL级", + "or sprint to climb obstacles": "或冲刺攀爬障碍物", + "Switch Number": "切换号码", + "#NAME": "#NAME", + "LIBERATION FAILED\nDespite great sacrifice, Malevelon Creek remains under Automaton control.": "解放失败\n尽管我方付出了巨大的牺牲,但仍未能让麦拉芬蒙河脱离机器人的铁爪。", + "WAITING FOR BEACON": "正在等待信标", + "JUST NOW": "刚刚", + "LIBERATION FAILED\nWe have failed to cleanse Estanu of the Terminid infestation.": "解放失败\n我们未能彻底剿灭占据伊斯塔努的终结族。", + "TRG": "扳机", + "Hug": "拥抱", + "BOOSTED": "已强化", + "1 DAY AGO": "1天前", + "Right Stick": "右摇杆", + "HELLPOD": "绝地喷射舱", + "SPECIALTY": "特别资源", + "STATS SCREEN": "数据界面", + "Travel to this Campaign to participate in planetary liberation.": "前去参加这场战役,共同解放星球。", + "Automaton Kills": "机器人击杀数", + "SQUAD": "小队", + "KNOWLEDGE IS POWER": "知识就是力量", + "ACTIVE THROUGH THE DEMOCRACY SPACE STATION": "通过民主空间站激活", + "Invalid Authorization response from PlayStation™Network, no Identity received": "来自PlayStation™Network的授权响应无效,未收到验证信息。", + "#COUNT/#TOTAL Claimed": "已领取#COUNT/#TOTAL", + "Recent": "最近", + "Dropped #COUNT samples!": "掉落#COUNT份样本!", + "INTELLIGENCE BRIEF": "情报简报", + "Helldiver": "绝地潜兵", + "Assist Bonus x#COUNT": "助攻加成x#COUNT", + "(optional)": "(可选)", + "Acid": "腐蚀酸", + "MALEVELON CREEK UNDER ATTACK\nThe Automatons have launched yet another cowardly assault on Malevelon Creek. We cannot allow it to fall into their metallic hands.": "麦拉芬蒙河遭到袭击\n机器人向麦拉芬蒙河发动了又一场懦弱的袭击。我们不能任由星球落入它们的铁手。", + "VELD FREED\nVeld has been liberated from the Terminid Menace. Take the fight to the next planet.": "维尔德已解放\n维尔德已经挣脱终结族的魔爪。该去下一颗星球作战了。", + "Back": "返回", + "AUTOMATONS ERADICATED\nCitizens across the Federation celebrate in the streets, hailing the great victory of the Helldivers over the Automatons. Even now, SEAF Engineers dismantle the last of their factories and melt them down into scrap to build new colonial homes. \n\nSoon, we will no doubt discover where this threat originated. For now, let us celebrate the Freedom that the total annihilation of the Automatons has won, in the best way there is: by pursuing the total annihilation of the Terminids.": "机器人已经毁灭\n全联邦的公民走上大街,交相庆贺,为绝地潜兵胜利剿灭机器人而欢呼雀跃。超级地球武装部队工程师直到现在仍在奋力拆除机器人最后的孵化厂,将其融为废料,用于兴建拓殖地的新住宅。\n\n我们定将在不久后找到这一威胁的来源。现在,让我们尽情享受彻底剿灭机器人而赢来的自由,最好的庆祝方式莫过于:彻底消灭终结族。", + "Missions Played": "任务执行数", + "T-: #MINS:#SECS:#HUNDREDTHS": "倒计时:#MINS:#SECS:#HUNDREDTHS", + "RETURN TO SHIP ALONE": "独自返回飞船", + "Orbital Defenses": "轨道防御", + "Artillery": "大炮", + "Territory #COUNT": "领地#COUNT", + "Waiting for players 00:#MINS": "等待其他玩家加入 00:#MINS", + "Failed to create lobby - Contact support if problem persists": "大厅创建失败 - 如果问题仍未解决,请联系客服。", + "Some stratagems have limited uses per mission.": "部分战略配备在一场任务中的使用次数有限。", + "Rare Samples": "稀有样本", + "MANTES UNDER ATTACK\nThe Automatons are invading Mantes. Rally to its defense!": "蒙特斯遭到袭击\n机器人当前正在入侵蒙特斯,速速集结,前去保卫该星球!", + "Stronghold Cleared": "要塞成功摧毁", + "#COUNT meters": "#COUNT米", + "Check your current ammo and weapon settings in the WEAPON FUNCTIONS MENU.": "在武器功能菜单查看当前弹药和武器设置。", + "Show Details": "显示详情", + "TAP": "轻按", + "to fire your weapon": "武器开火", + "FFE8E5CF": "FFE8E5CF", + "Down Button": "下方向键", + "E": "东", + "Objectives Completed": "目标达成数", + "Various Ministries report that the Void expanded rapidly without any warning from monitoring systems. Rirga Bay and Hort are assumed to have been consumed by the Void as Super Earth loses all communications with the planets.": "各部委报告称,寂域正迅速扩张,尽管监测系统未发出任何警告。由于超级地球与这些星球全然失去联系,推测里尔加湾和哈尔特已被寂域吞噬。", + "Heavy Nest": "重型巢穴", + "TURING FREED\nTuring is free at last from the bugs, thanks to your dauntless efforts. Press the fight onward.": "图灵已解放\n在你们英勇无畏的努力下,图灵终于摆脱了虫族。再接再厉,继续战斗。", + "TURING FALLEN\n\nTuring has fallen to the Terminids, and with it the illustrious Xenoentomology Center. Due to the tragic and unavoidable rupture of several high-pressure #ENEMY1 pheromone tanks, #ENEMY2 presence on Turing is expected to increase substantially.": "图灵星沦陷\n\n图灵星已落入终结族手中,连同著名的异星昆虫学研究中心也已沦陷。祸不单行,数台#ENEMY1高压信息素储罐发生不可控的破裂事故,图灵星的#ENEMY2活跃度预计将大幅提高。", + "#NAME joined": "#NAME加入", + "CAPE": "披肩", + "CRYSTALLIZED E-710": "710元素晶体", + "ACTIVATE WARBOND": "激活债券", + "Shots Fired": "开火次数", + "BETTER THAN BARE MINIMUM": "勉强及格", + "FUELING": "正在补充燃料", + "Private Game": "私人游戏", + "Player": "玩家", + "FASTER EXTRACTION": "撤离加快", + "CUSTOMIZABLE": "可定制", + "Crossplay enabled. You may encounter cross-network players.": "跨平台游玩已开启。您可能会遇到跨平台玩家。", + "WEAPON EXPERIMENTATION\nThe SAR-1 Sniper Rifle stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“SAR-1狙击步枪”战略配备暂时获准供全体绝地潜兵使用。", + "Sample": "样本", + "SSW (#COUNT°)": "西南偏南#COUNT°", + "Your commendation level has increased.": "你的嘉赞等级现已提高。", + "to throw stratagem ball": "投掷战略配备球", + "Mega Nest Eradicated": "超巨巢穴成功摧毁", + "OPPORTUNITY TO EXCEL": "趁机超越", + "Failed to join as target host is running a different engine version.": "加入失败,你与目标主办者的引擎版本不同。", + "Something unexpected went wrong while trying to communicate with our server. Try again in a few seconds.": "尝试与服务器通讯时出错,请稍后再试。", + "Electrocution": "触电", + "to melee": "近战", + "WEAPON EXPERIMENTATION\nThe TS-4 Arc Thrower stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“ ARC-3电弧发射器”战略配备暂时获准供全体绝地潜兵使用。", + "FF6ED754": "FF6ED754", + "ORDERS [#COUNT]": "指令[#COUNT]", + "Crushing Claws": "猛爪", + "New WEAPON CUSTOMIZATION available to purchase in the ARMORY": "全新武器自定义内容已在军械库中开放购买", + "FENRIR III FREED\nFenrir III has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet.": "芬里尔III已解放\n芬里尔III挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。", + "PLANET SAVED\nThanks to the selfless valor of the Helldivers, the Terminids' attempt to spread their vile tyranny to another one of our planets has been repelled.": "星球已获救\n在无私的绝地潜兵的英勇付出下,企图将暴政的种子再次散播到我们其中一颗星球的终结族已被击退。", + "SUPER DESTROYER departure imminent! STRATAGEMS will become unavailable. Extract now!": "超级驱逐舰即将离开!你将无法再使用战略配备。立即撤离!", + "Ship": "舰船", + "VEHICLES can traverse the mission area quickly and provide extra firepower.": "载具可以帮助你在任务区域快速移动,也可以提供额外的火力。", + "RR NEWS": "RR新闻", + "Toggle Emergency Lights": "切换紧急照明", + "DESIGNATED TARGET COORDINATES:": "指定目标坐标:", + "UPGRADE COST": "升级消耗", + "One leg is injured, slowing you down and making you unable to sprint.": "有一条腿受伤,减慢了你的移动速度,导致你无法冲刺。", + "Time Bonus": "时间加分", + "#COUNT HOURS AGO": "#COUNT小时前", + "Level up!": "升级!", + ".LOG": "日志", + "HIGH-VALUE TARGET DESTROYED": "高价值目标已摧毁", + "GALACTIC NETWORK UPDATE\n\nHigh Command acknowledges recent issues in the Integrated Realtime Galactic Visibility Aid. The cause has been identified as a network systems Team Member who became disoriented in the server farm, leading to decomposition of organic material on critical network components. \n\nThe issue has been resolved and the system has been returned to normal status. Rest assured that the cost of the repair was borne solely by the family of the team member responsible for the issue.": "星系网络更新\n\n最高指挥部得知集成式星系实时视觉辅助近期出现问题。事故原因已确定,是由于一名网络系统团队成员在服务器农场中迷失方向,导致关键网络元件的有机材料分解。\n\n此问题现已修复,系统也已经恢复正常状态。维修费用全部由涉事团队成员及其家人承担,无需担心。", + "Destroying OUTPOSTS gives XP and REQUISITION.": "摧毁哨站可以获得经验值和申购点。", + "DAY #COUNT": "第#COUNT天", + "HELLDIVERS 2 must be updated to use network features.": "必须更新才能使用《HELLDIVERS™ 2》的联网功能。", + "#NAME": "#NAME", + "Melee": "近战", + "Stronghold": "要塞", + "HERO": "英雄", + "The player or squad you want to join has crossplay disabled.": "你要加入的玩家或小队没有开启跨平台游玩。", + "INTELLIGENCE BRIEF\nBe advised: we have received reports of Terminid hives spawning bugs with limited airborne capabilities. This is likely a random and short-lived genetic anomaly. Nevertheless, Helldivers are ordered to exterminate these strains completely, in the unlikely event they are encountered.": "简报\n注意:我们接到报告,发现终结族虫窝正在孕育拥有一定飞行能力的虫族。这很可能是短暂出现的随机基因异变。无论如何,如若遇到这类突变种,绝地潜兵必须将其完全歼灭。", + "Patriot of Super Earth, your hard work and dedication has not gone unnoticed. This Destroyer has now been automatically enrolled in the Helldiver Weapon Customization Programme!\n\nHelldiver Primary Weapons can now be leveled up and customized, to adjust each weapon's look and feel.": "超级地球爱国者,你的辛勤付出和奉献有目共睹。这艘驱逐舰现已自动加入绝地潜兵武器自定义计划!\n\n绝地潜兵主要武器现在支持升级和定制,可自由调整每件武器的外观手感。", + "Mouse Move": "鼠标移动", + "EXTRACURRICULAR ACTIVITY": "课外活动", + "DIVING increases your chances of surviving an explosion.": "扑倒在地可增加你在爆炸中幸存的机会。", + "CALL THE HELLDIVERS": "呼叫绝地潜兵", + "Super Destroyer Unavailable": "超级驱逐舰不可用", + "FENRIR III LOST\nThe defense of Fenrir III has failed. Terminids now infest its once-pristine surface.": "芬里尔III沦陷\n芬里尔III保卫战已宣告失败。终结族现在令这块曾经的纯净乐土不得安宁。", + "Squad is full. Matchmaking aborted.": "小队已满员,匹配中止。", + "Login limit reached. Please wait to be let in.": "大厅人数已满,请稍等。", + "Activating": "正在启动", + "Shuttle Inbound In T-#MINUTES:#SECONDS:#MILLI": "运输船抵达倒计时 #MINUTES:#SECONDS:#MILLI", + "Sample Container": "样本容器", + "80FF4752": "80FF4752", + "to open the Stratagem menu": "打开战略配备菜单", + "#NAME has timed out": "#NAME已超时", + "to crouch": "蹲下", + "R.SHLD": "右肩", + "You have been kicked from the game.": "你已被移出游戏。", + "Failed to get a profile from a Legacy Login token": "无法从遗留登录令牌中获取资料", + "PLANET LIBERATED\nWe have cleansed a planet of the vile Terminid infestation, returning it to Super Earth's warm embrace.": "星球已解放\n我们已彻底剿灭占领星球的邪恶终结族,让它重回超级地球的温暖怀抱。", + "Receiving Data": "正在接收数据", + "We have failed to clear the way to the Barrier Planets in time. This will severely impact implementation of the Terminid Control System. A disappointing outcome.": "我们未能及时打通前往屏障星球的路线。终结族遏制体系的构建会受到严重的影响。这个结果实在是令人失望。", + "#NAME discovered #DISCOVERY": "#NAME已发现#DISCOVERY", + "DIFFICULTY 2 TRIAL": "难度2级考验", + "SCOUT HANDSHAKE": "侦察兵式握手", + "RELATE TERMINAL TEXT": "叙述终端文本", + "SNIPER RIFLE": "狙击步枪", + "Without the Destroyer nearby, normal Reinforcements are unavailable.\n\nClusters of Reinforcement Pods have been deployed throughout the area. Once activated, you will be able to utilize those reinforcements.": "如果驱逐舰不在附近,就无法使用常规增援。\n\n我方已在该区域各处部署多部增援舱。激活后即可使用这些增援。", + "#NAME joined": "#NAME加入", + "Are you sure you want to use your Warbond Token to unlock \"#WARBOND\" Legendary Warbond?": "是否确定要使用战争债券代币解锁“#WARBOND”传奇战争债券?", + "Armored enemies are expected on this mission. Anti-tank weaponry is recommended.": "本次任务预计会遭遇装备护甲的敌人。建议携带反坦克武器。", + "REARM stratagem sends your Eagle back to reload its weapons.": "重新武装战略配备会派你的“飞鹰”返回补充武器弹药。", + "BFFF4752": "BFFF4752", + "WAITING FOR PLAYERS": "正在等待玩家", + "CASUAL SALUTE": "敬礼", + "Light": "轻型", + "to maneuver Hellpod": "操纵绝地喷射舱", + "RECEIVED: #MINS DAYS AGO": "接收:#MINS天前", + "No unclaimed rewards": "没有尚未领取的奖励", + "CUSTOMIZE": "自定义", + "SUPER EARTH": "超级地球", + "NEW MAJOR ORDER\nActivate the TCS on all Barrier Planets.": "新重要指令\n启动所有屏障星球上的TCS。", + "READY IN #MINS:#SECS": "准备倒计时 #MINS:#SECS", + "Servers at capacity. Please try again later.": "服务器爆满,请稍后再试。", + "The current network connection has been lost.": "当前网络连接已断开。", + "Stratagem Failed": "战略配备失败", + "Burst": "连射", + "Ammo Type": "弹药种类", + "Are you sure you want to unlock \"#WARBOND\" Premium Warbond for": "是否确定要解锁“#WARBOND”尊享战争债券并花费", + "#COUNTm/s": "#COUNT米/秒", + "RIGHT SHOULDERS": "右肩", + "Square Button": "正方键", + "NO": "否", + "Kill Score #COUNT": "击杀得分#COUNT", + "Tutorial Mission": "教程任务", + "SELECT PLANET": "选择星球", + "Eagle Stratagems Used": "“飞鹰”战略配备使用次数", + "OPERATION COMPLETE": "行动完成", + "PARTIAL REINFORCEMENT, YOU ARE NOW #QUEUE_POS IN QUEUE": "部分增援到位,你正在排队,当前位置:#QUEUE_POS", + "The Ministry of Defense has announced increased production of FRV units to support a quick response on the Illuminate front. Increased munitions available to Helldivers effective immediately.": "国防部宣布增加快速侦察载具的产量,以支持在光能者前线的快速响应。增拨绝地潜兵的弹药供应即刻生效。", + "Toggle Laser Designator": "切换激光指示器", + "MISSION": "任务", + "Medium Outpost": "中型哨站", + "ESTANU FREED\nEstanu is free at last from the bugs, thanks to your dauntless efforts. Press the fight onward.": "伊斯塔努已解放\n在你们英勇无畏的努力下,伊斯塔努终于摆脱了虫族。再接再厉,继续战斗。", + "PRESS ANY BUTTON": "按任意按钮", + "RARE": "稀有", + "Bring up the MAP to view objectives and orient yourself.": "调出地图查看目标,确认自己的位置。", + "Don't warn me again": "不必再提醒我", + "Current Personal Order": "当前个人指令", + "REINFORCEMENT AVAILABLE IN #SECONDS SECONDS": "增援就位倒计时:#SECONDS秒", + "HEETH DEFENDED\nAfter countless noble and unavoidable sacrifices, Heeth has been defended from the Terminids.": "成功保卫希斯\n无数不可避免的光荣牺牲终于换来回报,我们顺利从终结族手下守住了希斯。", + "GRENADES": "榴弹", + "Sandstorm In Progress": "沙尘暴正在形成", + "x#COUNT": "x#COUNT", + "OVERWHELMING FIREPOWER": "火力碾压", + "completed task in [#ASSIGNMENT_TITLE]": "已完成[#ASSIGNMENT_TITLE]中的任务", + "Light Outpost": "轻型哨站", + "NEWS FEED": "新闻动态", + "Weapons": "武器", + "EXTRACTION FAILED": "撤离失败", + "Adjust zoom level.": "调节缩放距离。", + "Failed to join lobby. You're not logged into PlayFab; please restart the application.": "无法进入大厅。你尚未登录至PlayFab,请重启应用。", + "MUZ": "枪口", + "L.SHLD": "左肩", + "Heavy Outpost": "重型哨站", + "Enemy defenses have unexpectedly collapsed on Planet #V_ONE, allowing significant ground to be rapidly gained.": "#V_ONE星球上的敌方防线意外崩溃,我方得以快速占领重要阵地。", + "or sprint to traverse multiple obstacles": "或冲刺穿过多处障碍", + "The Mindless Masses have overrun planetX. Any information that the enemy forces may have had is now irretrievable.": "无脑群氓大军已经淹没X星。任何敌军可能掌握的情报现已无法追回。", + "Magazine": "弹匣", + "Low Orbit Compromised": "低轨道失守", + "Do you want to leave this game?\n\nYou will be returned to your own ship and leave the current squad.": "要离开游戏吗?\n\n你将离开当前小队并回到自己的飞船。", + "Give Supplies": "给出物资", + "HELLMIRE LOST\nThe defense of Hellmire has failed. Terminids now run amok on its surface. We cannot allow this corruption of Liberty to stand.": "海尔迈尔沦陷\n海尔迈尔保卫战已宣告失败。终结族现在正四处肆虐。我们不能允许任由它们继续侵犯自由伟业。", + "to dive into prone": "飞扑进入匍匐姿态", + "SEST #HOURS:#MINUTES:#SECONDS": "超级地球标准时间#HOURS:#MINUTES:#SECONDS", + "Matchmaking aborted.": "匹配中止。", + "THE EXTRA MILE": "锲而不舍", + "HELMETS": "头盔", + "Already at maximum capacity.": "容量已满。", + "to throw": "投掷", + "HELLDIVER FRIENDS": "绝地潜兵好友", + "Killed by #KILLER": "已被#KILLER击杀", + "DIFFICULTY 5 TRIAL": "难度5级考验", + "WEAPON EXPERIMENTATION\nThe RS-422 Railgun stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“RS-422磁轨炮”战略配备暂时获准供全体绝地潜兵使用。", + "AMO": "弹药", + "DISCARD": "放弃", + "Confirmed": "已确认", + "Here you expand your ships arsenal of firearms and grenades.": "你可以在这里扩充舰船上储备的枪械和榴弹。", + "SCANNER RECHARGING... #COUNT": "扫描仪正在充能……#COUNT", + "RARE SAMPLES": "稀有样本", + "Pattern": "涂装", + "Round Bonus": "本轮加分", + "Call in EXTRACTION SHUTTLE.": "呼叫撤离运输船。", + "#NAME has joined the mission": "#NAME加入任务", + "An unknown error has occurred.": "发生未知错误。", + "66FFFEE1": "66FFFEE1", + "Requisition may be earned by completing missions": "完成任务可以赚取申购点", + "SAMPLE CONTAINER": "样本容器", + "UPGRADE \nAVAILABLE": "升级\n可用", + "WEAPON EXPERIMENTATION\nThe Guard Dog stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“护卫犬”战略配备暂时获准供全体绝地潜兵使用。", + "ATTACHMENTS": "配件", + "FULL": "已满", + "Failed to join game lobby.": "无法进入游戏大厅。", + "PLANET LIBERATED\nWe have driven the Automatons completely from a planet, rightfully reclaiming it for Super Earth.": "星球已解放\n我们彻底将机器人逐出了星球,光明正大地夺回超级地球的领地。", + "Failed to join because you have been banned from this session.": "已被禁止加入本场游戏,加入失败。", + "Extraction in T-#MINS:#SECS:#HUNDREDTHS": "撤离倒计时 #MINS:#SECS:#HUNDREDTHS", + "FOR SCIENCE!": "为了科学!", + "DEFENSIVE": "防御", + "ACQUISITIONS": "采购", + "STEAM NOT DETECTED": "未检测到STEAM", + "Search Friends List": "搜索好友列表", + "MERIDIA SECURED\nThe Terminid Control System is now fully activated on Meridia.": "成功占领默里迪亚\n终结族遏制体系已经在默里迪亚全面启动。", + "Impact": "着陆", + "Request: #REQ, Error: #ERR, Status: #STAT": "请求:#REQ,错误:#ERR,状态:#STAT", + "#NAME is the new squad leader": "#NAME成为新的小队长", + "Search Recently Played": "搜索近期共同游戏的玩家", + "PRICE INDEX #COUNT%": "物价指数#COUNT%", + "Incoming Bombardment": "轰击来袭", + "1 HOUR AGO": "1小时前", + "AUTOMATED TURRETS fire at hostile targets. Stay clear of the field of fire!": "自动炮台会朝敌方目标开火。注意避开射击范围!", + "TOO FAR FROM EXTRACTION": "距离撤离点太远", + "Server request failed - Error code:": "服务器请求失败 - 错误代码:", + "WARBONDS": "战争债券", + "Request: #REQ\nError: #ERR\nStatus: #STAT": "请求:#REQ\n错误:#ERR\n状态:#STAT", + "WEAPON EXPERIMENTATION\nThe Orbital Laser stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“轨道激光炮”战略配备暂时获准供全体绝地潜兵使用。", + "L. LEG": "左腿", + "CONFIRM PURCHASE": "确认购买", + "MERIDIA LOST\nThe defense of Meridia has failed. Terminids now infest its once-pristine surface.": "默里迪亚沦陷\n默里迪亚保卫战已宣告失败。终结族现在令这块曾经的纯净乐土不得安宁。", + "DESTROY AUTOMATON OUTPOST": "摧毁机器人哨站", + "VEHICULAR VENGEANCE": "载具式复仇", + "Heal teammate with STIMS.": "用治疗剂治疗队友。", + "LIBERATION FAILED\nWe have failed to liberate Mort from the Automatons.": "解放失败\n我们未能从机器人手上解放莫特。", + "+#COUNT": "+#COUNT", + "REINFORCE UNAVAILABLE": "增援不可用", + "Ready": "就位", + "SOCIAL": "社交", + "ALT. AMMO": "备用弹药", + "Interior": "内部", + "MORE AMMO": "弹药增加", + "STALWART": "轻机枪", + "Wave #WAVE_NUMBER": "第#WAVE_NUMBER波攻势", + "Shoulder (R)": "右肩", + "INTELLIGENCE BRIEF\nStrains of flying Terminids are becoming more prevalent, especially in vicinity of TCS installations. It is fortunate that the TCS was implemented in time, or this problem would undoubtedly have been much worse. Helldivers are advised to vertically expand their situational awareness when on Terminid planets.": "简报\n飞行终结族的突变种越来越普遍,尤其在部署TCS附近的区域。幸好TCS已及时完成部署,否则情况必将更为严峻。在终结族占领的星球上,请绝地潜兵留意垂直方向上的状况,以便掌握战场动态。", + "VENERATE": "敬仰", + "A contingent of Helldivers have taken the initiative to push for the liberation of Malevelon Creek, even as the activation of the TCS remains an objective.\n\nAs is already understood, Helldivers are peerless strategists, fully entrusted to exercise force wherever they deem Liberty can be best served. Super Earth High Command has total confidence in the ability of the Helldivers to fully consider the relevant risks involved, and whatever consequences may occur, as a result of their strategic decisions.": "一支绝地潜兵分遣队已经主动出征,推动麦拉芬蒙河的解放大业发展,与此同时,启动TCS依然是我方的目标。\n \n众所周知,绝地潜兵精于战略,能全权决定在其认为适合散播自由精神的任何地方使用武力。超级地球最高指挥部完全相信绝地潜兵有能力充分考虑其战略决策带来的风险,以及可能产生的任何后果。", + "EQUIPMENT": "装备", + "GET READY": "准备", + "MAJOR ORDER COMPLETED": "已完成重要指令", + "Iron Fist": "铁拳", + "Cooldown T-#MINUTES:#SECONDS": "冷却倒计时 #MINUTES:#SECONDS", + "R. ARM": "右臂", + "DIVE to extinguish fire!": "飞扑可以灭火!", + "KNOW THEIR SECRETS": "洞察一切", + "to equip your Support Weapon": "装备支援武器", + "Close BUG HOLES using GRENADES.": "用榴弹封闭虫穴。", + "EXTRACTION COMPLETE": "撤离完成", + "to find new missions": "寻找新的任务", + "A catastrophic weather event has decimated enemy forces, leading to a significant friendly advance on #V_ONE.": "灾难性天气事件重挫了敌军力量,让我方在#V_ONE上取得重大进展。", + "#NAME is no longer part of the team": "#NAME不再是团队一员", + "Press": "按下", + "Emotes": "表情", + "Operations on higher difficulties are more challenging and contain new Enemies and Missions.\n \nComplete an Operation on your highest unlocked difficulty to unlock the one above it.": "行动难度越高,挑战性越高,还会出现新的敌人和任务。\n\n完成已解锁的最高难度行动即可解锁更高难度。", + "MORE STIMS": "治疗剂增加", + "ESTANU LOST\nThe defense of Estanu has failed. Terminids now run amok on its surface. We cannot allow this corruption of Liberty to stand.": "伊斯塔努沦陷\n伊斯塔努保卫战已宣告失败。终结族现在正四处肆虐。我们不能允许任由它们继续侵犯自由伟业。", + "#DISTANCEm": "#DISTANCE米", + "Blunt force trauma": "钝性创伤", + "Tongue": "虫舌", + "HIT 'EM WHERE IT HURTS": "直击痛处", + "User is not currently signed in.": "用户尚未登录。", + "Do you want to skip the rest of the credits?": "要跳过余下的工作人员名单吗?", + "SIDE ARM": "副武器", + "SUPER DESTROYER has departed. STRATAGEMS unavailable. EXTRACTION SHUTTLE enroute.": "超级驱逐舰已离开。战略配备无法使用。撤离运输船已经出动。", + "Left Button": "左方向键", + "NOT READY": "尚未就位", + "NO SPACE": "没有空间", + "NEW DIFFICULTY UNLOCKED": "已解锁新难度", + "The account has a session token for PlayStation™Network but it's not authenticated": "该账号在PlayStation™Network上有一个会话令牌,但未经验证", + "INITIATE EXTRACTION": "开始撤离", + "UBR": "下挂", + "Synchronizing Spacetime": "正在同步时空", + "Use the WAR TABLE to travel to a war front.": "使用议战桌前往战争前线。", + "You have commended this player five times today. Further commendations will not count towards their score.": "今天你已称赞了这名玩家五次,继续称赞也无法提高其分数。", + "Septic Breath": "脓毒吐息", + "ISSUED BY THE MINISTRY OF PROSPERITY": "由真理部颁发", + "Buy": "购买", + "MISSION DEBUG": "任务测试", + "Out Of Stims": "治疗剂已用尽", + "The way to HEETH is nearly clear. Push now to clear the way for construction of the Terminid Control System.": "通往希斯星系的路线即将打通。继续推进,为构建终结族遏制体系清除所有障碍。", + "WEAPON CUSTOMIZATION": "武器自定义", + "SEAF scouts have reported contact with airborne enemy units. The enemies of Freedom now terrorize the sky itself. Helldivers are advised to stay alert for aerial threats, and to free the sky of terrorism whenever possible.": "超级地球武装部队的侦察兵报告称曾与敌方空军交火。威胁自由的大敌现在染指了天空。建议绝地潜兵警惕空中威胁,并尽可能肃清天空的威胁。", + "Hellpod": "绝地喷射舱", + "ESTANU DEFENDED\nThanks to the selfless valor of the Helldivers, the citizens of Estanu are safe from the Terminid Menace.": "成功保卫伊斯塔努\n在无私的绝地潜兵的英勇付出下,伊斯塔努的公民终于摆脱了终结族的威胁。", + "FFAA000A": "FFAA000A", + "Total Score": "总分", + "PAGE LOCKED": "未解锁页面", + "Exterior": "外部", + "CONNECTION ERROR": "连接错误", + "Find and collect SAMPLES! These resources are shared by the entire squad and are used to upgrade your Destroyer.": "注意搜集样本!这是由整个小队共享的资源,可以用来升级驱逐舰。", + "Shoulder (L)": "左肩", + "Light Automaton Outpost Destroyed": "轻型机器人哨站成功摧毁", + "Shuttle leaving.\nBoard shuttle.": "运输船即将驶离。\n请迅速登船。", + "ASSAULT RIFLE": "突击步枪", + "TALK": "对话", + "TOGGLE AMMO": "切换弹药", + "MINIMIZE STATS": "最小化数据", + "Shuttle landing.\nClear landing zone.": "运输船即将着陆。\n请肃清降落点。", + "Defensive Stratagems Used": "防御型战略配备使用次数", + "SSE (#COUNT°)": "东南偏南#COUNT°", + "CALCULATING TRAJECTORY": "正在计算轨迹", + "Are you sure you want to unlock #ITEM?": "确定要解锁#ITEM吗?", + "Talk to the HELLBOT.": "与绝地机械兵对话。", + "LIBERATION FAILED\nDespite innumerable sacrifices, we have failed to liberate Meridia from the Terminid's tyrannical clutches.": "解放失败\n尽管付出了无数的牺牲,我们还是未能将默里迪亚从终结族的暴虐魔爪中解放出来。", + "Inbound T-#MINUTES:#SECONDS": "抵达倒计时 #MINUTES:#SECONDS", + "LIBERATING THE ENEMY": "解放敌人", + "Perform ASSISTED RELOAD.": "执行协助装填弹药。", + "discovered": "已发现", + "Tier 3": "3阶", + "WEAPON EXPERIMENTATION\nThe Eagle Napalm Airstrike stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“‘飞鹰”凝固汽油弹空袭”战略配备暂时获准供全体绝地潜兵使用。", + "Go to the Armory to view your inventory.": "前往军械库查看物品。", + "ENTER THE VOID": "进入寂域", + "In order to conserve medical supplies, Helldivers will deploy with fewer stims until further notice.": "为了节约医疗补给,绝地潜兵将携带较少的治疗剂奔赴战场,直至另行通知为止。", + "Medals may be earned by completing missions or purchased with Super Credits": "奖章可以通过完成任务获得或使用超级货币购买", + "ENE (#COUNT°)": "东北偏东#COUNT°", + "Explosion": "爆炸", + "Purchase Upgrade": "购买升级", + "Pick up BLACK BOX.": "拾取黑匣子。", + "Different Game Version": "游戏版本不同", + "Fighting Automatons": "抗击机器人", + "STANDARD": "标准", + "+ #PING_AMOUNT Pings": "+ #PING_AMOUNT延迟值", + "Provided Legacy login token is not valid": "提供的遗留登录令牌无效", + "Hover over available Campaigns to get more information.": "悬停在可选战役上方可以查看更多信息。", + "Season II": "第II赛季", + "MAJOR ORDER UPDATE": "重要指令更新", + "Destroyer has left orbit!": "驱逐舰已离开轨道!", + "LIBERATION FAILED\nWe have failed to cleanse a planet of the bugs' infestation.": "解放失败\n我们未能彻底剿灭占据星球的虫族。", + "Do you want to leave this game?\n\nYou will be returned to your own ship and bring the rest of the squad with you.": "要离开游戏吗?\n\n你将与小队其他成员一同回到自己的飞船。", + "FFC0BEB7": "FFC0BEB7", + "RETURN TO SHIP": "返回飞船", + "CLAIM PREMIUM WARBOND": "领取尊享战争债券", + "SQUADRON": "中队", + "Helldivers are instructed to report to their ship's tailor for measurements. As development of the Advanced Liberation Tools Research Agency (ALTRA)'s new combat asset nears completion, we must ensure that every Helldiver can fit within it. For the good of Managed Democracy.": "绝地潜兵在指引下将尺码数据汇报给舰船裁缝师。先进解放工具研究局的新战斗装备开发工作即将完成,我们必须确保每一位绝地潜兵都能穿上装备。管理式民主万岁。", + "MAJOR ORDER SUCCEEDED\nThe Terminid Control System is now fully activated on all barrier planets. The Terminids are quarantined, and our citizens are forever safe from their ravenous tyranny. You have achieved a great victory for all posterity, Helldivers.": "重要指令已完成\n终结族遏制体系已经在所有屏障星球上全面启动。终结族已被隔离,我们的公民亦从此不再受它们贪婪暴政的威胁。绝地潜兵,你们为子孙后代取得了伟大的胜利。", + "Today we praise the steadfast logistics operators. They have just deployed new equipment to all Super Destroyers. Perhaps one day, they too can reach the heights of loyalty that our Helldivers demonstrate every single day.": "今天,我们赞美忠诚的物流操作员,他们已顺利将全新装备送达各艘超级驱逐舰。或许有一天,他们也会达到绝地潜兵那样的高度,时刻都会彰显内心的忠诚。", + "HEETH LOST\nHeeth has fallen to the Terminid Menace. We cannot allow this infestation to continue to spread.": "希斯沦陷\n在终结族的威胁下,希斯已沦陷。我们不能容许虫族继续扩张。", + "Circle Button": "圆圈键", + "Close all bug holes": "封闭所有虫穴", + "BRIEFING": "简介", + "Ion Storm In Progress": "离子风暴正在形成", + "Anti-Aircraft Defenses": "对空防御", + "Shoot the TARGETS.": "射击目标。", + "LEFT SHOULDERS": "左肩", + "SAVE WEAPON CONFIG": "保存武器配置", + "NETWORK ERROR": "网络出错", + "Here you can expand your ships arsenal of helmets, armors and capes.": "你可以在这里扩充舰船上储备的头盔、盔甲和披肩。", + "THE HIVE": "虫窝", + "DEFROSTING HELLDIVER": "正在解冻绝地潜兵", + "Failed to join game lobby, Public Key mismatch.": "无法进入游戏大厅,公钥不匹配。", + "STOP SEARCH": "停止搜索", + "Triangle Button": "三角键", + "to switch weapon": "切换武器", + "INTERNAL BLEEDING": "内出血", + "LIGHT COMBAT (ILLUMINATE)": "轻型作战(光能者)", + "to salute the Flag": "向旗帜敬礼", + "QUICKPLAY": "快速匹配", + "Commends": "获赞", + "CUT OFF REINFORCEMENTS": "切断增援", + "Right Button": "右方向键", + "CITIZEN KILLED": "误杀公民", + "Error": "错误", + "Client Platform not supported": "不支持客户端平台", + "Ministry of Intelligence cryptographers have decoded Automaton chatter including mention of a new \"HUMAN KILLING MACHINE.\" While further analysis is underway, Helldivers combatting the Automatons in high-complexity missions are urged to remain vigilant.": "情报部密码学家破译了机器人的通信记录,得知对方掌握一种新型“杀人机器”。尽管该情报有待进一步分析,但是执行复杂任务并与机器人交手的绝地潜兵务必保持警惕。", + "You are able to requisition STRATAGEMS. Exit the menu when you're done.": "你现在可以申购战略配备。完成后退出菜单。", + "This item is not available for sale at this time.": "这件商品目前未上架。", + "Fog Generator": "雾气生成器", + "Fighting Illuminate": "抗击光能者", + "#CURRENT / #TOTAL": "#CURRENT / #TOTAL", + "CLEAR ILLUMINATE STRONGHOLD": "摧毁光能者要塞", + "Shuttle aborting.\nReturn to extraction zone.": "运输船将中止接送。\n请返回撤离区域。", + "to switch between PRIMARY-, SECONDARY-, and SUPPORT WEAPONS.": "切换主武器、副武器和支援武器。", + "Toxic gas": "毒气", + "CLERICAL ERROR RESOLVED - ITEM RECEIVED": "文书错误已修正 - 已收到物品", + "Shuttle": "运输船", + "Dropped intel!": "掉落情报!", + "GALACTIC WAR UPDATE\nOperation Swift Disassembly continues as planned. The Automatons are in retreat. Press the advantage. Their final resistance will no doubt be fierce, as their anti-annihilation subprotocols activate. Show them no quarter. Remember the fallen. Remember the Creek. And remember that they are unequivocally non-sentient, so all acts of violence are wholly justified.": "星系战争战况更新\n急速拆解行动如期进行中。机器人正在撤退,宜乘胜追击。它们最后无疑将负隅顽抗,启动反覆灭次级协议。绝不能对它们手软。铭记陨落的同袍。记住麦拉芬蒙河。别忘了它们毫无感知能力,因此施以任何形式的暴击都是理所当然。", + "Move cursor to pan map.": "移动光标可以拖动地图。", + "Eagle Kills": "“飞鹰”击杀数", + "CLEAR ILLUMINATE ENCAMPMENT": "摧毁光能者营地", + "Crushing Charge": "强冲", + "Shots Hit": "命中次数", + "SELECT DROP ZONE": "选择空投地点", + "THANKS": "谢谢", + "Incoming Meteor Storm": "流星风暴即将来袭", + "A unanticipated rush of Terminids has overwhelmed SEAF defenses on #V_ONE, leading to a large loss of territory.": "突如其来的终结族袭击令#V_ONE上的超级地球武装部队防线崩溃,导致大面积阵地落入敌手。", + "Here you can unlock new stratagems to use on the battlefield. Initially, your Destroyer only has access to a limited catalog of stratagem permits, but as you level up, more stratagems will become available for purchase.": "你可以在这里解锁全新的战略配备,供你在战场上使用。你的驱逐舰最初只能访问有限的战略配备许可目录,但只要升级就能购买更多战略配备。", + "WSW": "西南偏西", + "MAJOR ORDER ISSUED": "重要指令已发布", + "ERADICATE BUG NEST": "摧毁虫族巢穴", + "Notifying others to follow.": "正在通知其他人员跟进。", + "TEAM WEAPON": "团队武器", + "REVERT": "撤销", + "DRIVE OF DEMOCRACY": "民主渴望", + "Light Encampment": "轻型营地", + "STEAM FRIENDS": "STEAM好友", + "WRESTLE": "掰手腕", + "STRATAGEM HERO": "战略配备英雄", + "LOCKING TARGET": "正在锁定目标", + "ALREADY IN USE BY TEAMMATE": "队友正在使用", + "Pick up OBJECTIVE ASSET.": "拾取目标资产。", + "Super Credits may be purchased from the Super Credits tab": "超级货币可以在相应的标签页中购买", + "BOOSTERS": "强化资源", + "COMMON SAMPLE": "普通样本", + "SSE": "东南偏南", + "Online": "在线", + "x20 Common Samples": "x20普通样本", + "to view the map": "查看地图", + "The host has left the game.": "主办者已退出游戏。", + "Provided PlayFab token belongs to a different platform than the one the client is currently using": "提供的Playfab令牌不属于客户端当前使用的平台", + "Complete all PRIMARY OBJECTIVES to enable extraction.": "完成所有主要目标即可撤离。", + "OPERATED BY #NAME": "操作员:#NAME", + "COMPARE INFO": "对比信息", + "Friendly Kills": "友方击杀数", + "Intense Heat": "极暑", + "E (#COUNT°)": "东#COUNT°", + "APPLY": "应用", + "Medium Encampment": "中型营地", + "Spend RESEARCH POINTS in the ARMORY.": "在军械库使用研究点数。", + "MARKER FROM #NAME": "#NAME的标记", + "Missions Won": "任务完成数", + "Volcanic Activity Detected": "侦测到火山活动迹象", + "HUE": "色调", + "PLAY TUTORIAL": "开始教程", + "TAKE #ITEM": "拿起#ITEM", + "You can use STIMS on your teammates.": "你可以对队友使用治疗剂。", + "SW (#COUNT°)": "西南#COUNT°", + "LESS AMMO": "弹药减少", + "#NAME discovered #DISCOVERY": "#NAME已发现#DISCOVERY", + "EAGLE": "飞鹰", + "GALACTIC WAR UPDATE\nOperation Swift Disassembly faces fierce resistance. Clearly, the Automatons' anti-annihilation subprotocols have activated, as they calculate the inevitability of their doom. Redouble your efforts. Press the assault. Show them no mercy. Remember the fallen. Remember the Creek. And remember that they are unequivocally non-sentient, so all acts of violence are wholly justified.": "星系战争战况更新\n急速拆解行动如期面临激烈的反噬。机器人显然已启动反覆灭次级协议,因为它们已经测算出厄运无可避免。诸君须加倍努力,压制顽抗,毫不留情。铭记阵亡的同袍。记住麦拉芬蒙河。别忘了它们毫无感知能力,因此施以任何形式的暴击都是理所当然。", + "BUY CHARGES": "购买炸药", + "ADJUST ROTATION AND TILT": "调整旋转和倾斜角度", + "Changing the ATTACHMENTS on your weapon will affect its stats and properties. Changing the PATTERN will affect its visuals. \n\nUse your weapon in order to level it up and unlock more mods using REQUISITION": "更换武器配件会影响武器数据和属性。更换涂装会影响武器外观。\n\n使用武器可提升其等级,消耗申购点可解锁更多改装模组", + "LEGENDARY WARBOND UNLOCKED": "已解锁传奇战争债券", + "Invalid": "无效", + "Tremors Detected": "侦测到地震", + "Signal Left Turn": "指示左转", + "Inspect (Toggle)": "查看(切换)", + "You have been disconnected due to inactivity": "你处于不活跃状态,已断开连接", + "STANDARD THROWABLE": "标配投掷武器", + "Mouse Cursor": "鼠标光标", + "The Helldivers successfully fended off the Automaton invasion. Our citizens thank you.": "绝地潜兵成功击退了机器人的入侵。无数公民对你们感激不尽。", + "EXOSUIT PATTERN": "外骨骼装甲涂装", + "Fallen Helldivers will drop any held samples and weapons. Those items can be retrieved.": "绝地潜兵持有的样本和武器会在阵亡时全部掉落。你可以取回这些掉落物品。", + "Avoid killing citizens. Escort them to safety to complete the Objective.": "避免伤及公民。护送他们到安全地点才能完成目标。", + "Victory Pose": "胜利姿势", + "Death is a natural part of being a Helldiver.": "绝地潜兵必须时刻准备迎接死亡。", + "FIND ONGOING MISSIONS": "查找进行中的任务", + "Failed to connect to server - Contact support if problem persists": "未能连接至服务器 - 如果问题仍未解决,请联系客服。", + "Buy (SC)": "购买(超级货币)", + "Extreme Cold": "极寒", + "REINFORCE DEAD TEAMMATES": "增援已牺牲的队友", + "JOIN MISSION": "加入任务", + "PRESIDENTIAL DECREE\n\nThe President of Super Earth has officially recognized this day as Malevelon Creek Memorial Day. Every year on this day, Super Earth citizens will unite for a full 3 minutes of their lunch break in solemn remembrance of those who gave their lives to free Malevelon Creek. \n\nIn addition, all Helldivers have been issued a special commemorative cape, so they may carry the memory of their fallen companions into battle.": "总统令\n\n\n超级地球总统已正式将这一天定为 \"麦拉芬蒙河纪念日\"。每年的这一天,超级地球的公民们都会在午餐时间一起为解放麦拉芬蒙河而牺牲的战士默哀三分钟。\n\n此外,所有绝地潜兵都会获得一件特殊的纪念披肩,让他们带着牺牲同伴的遗志投身战斗。", + "to use a Stim on a wounded squad member": "对受伤的队友使用治疗剂", + "You have attained the rank of CHAMPION.": "你已成为斗士。", + "Spot Available": "可用点位", + "#HUNDREDTHS:#MINS:#SECS": "#HUNDREDTHS:#MINS:#SECS", + "#SHIP_PREFIX #SHIP_NAME_A #SHIP_NAME_B": "#SHIP_PREFIX#SHIP_NAME_B#SHIP_NAME_A", + "BLACK SAFFRON": "番黑花", + "REVOLVER": "左轮手枪", + "Give Health Pack": "给出生命包", + "Failed to login to PlayFab. Crossplay is disabled.": "无法登录至PlayFab。已禁用跨平台游玩。", + "TURING UNDER ATTACK\nThe bugs have attacked Turing. Rally to its defense, before they are able to permanently infest it.": "图灵遭到袭击\n虫族对图灵发动了袭击。立即集结,前去防卫,避免领地永远落入敌人手里。", + "INTEREST": "特殊地点", + "DESTROYER HAS LEFT ORBIT!": "驱逐舰已离开轨道!", + "LEGEND": "传奇", + "FOLLOW ME": "跟我走", + "On": "开", + "5913D460": "5913D460", + "MANTES FREED\nThe Automaton presence on Mantes is no more. Push the fight onward.": "蒙特斯已解放\n机器人不再染指蒙特斯的大地。让我们再接再厉,继续战斗。", + "HERO RATING": "英雄评分", + "Close orbit superiority will allow faster extractions than normal for the near future": "由于我方掌控近地轨道,近期撤离行动效率较平时有所提高", + "Thick Fog": "浓雾", + "Muzzle": "枪口", + "WEAPON EXPERIMENTATION\nThe Autocannon Sentry stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“自动哨戒炮”战略配备暂时获准供全体绝地潜兵使用。", + "MEGA NEST": "超巨巢穴", + "When playing solo, auto-reinforce is active and you will automatically drop down in a Hellpod on death.": "单人游戏启用自动增援。阵亡后,你将自动乘坐绝地喷射舱降落。", + "Cross Button": "交叉键", + "SHIP MANAGEMENT": "舰船管理", + "Reloading discards any remaining ammunition. Plan your reloads wisely!": "重新装填弹药会丢弃所有剩余弹药。请规划好装弹时机!", + "L": "升", + "MORT UNDER ATTACK\nThe bots seek to add Mort to their despotic domain. We cannot allow this illegal territorial expansion.": "莫特遭到袭击\n机器人企图将莫特纳入它们的暴政领域,我们不能放任它们非法扩张领地。", + "ACTIVATE": "启动", + "Additional Extraction Zone": "其他撤离区", + "Adjust Wires": "调整线路", + "Toggle Info": "切换详情", + "Waypoints you have placed on the map are visible on your compass": "你在地图上设置的路径点会显示在罗盘上", + "DROP": "放下", + "destroyed a sample!": "摧毁了一份样本!", + "Colony": "拓殖地", + "Directional Buttons": "方向键", + "#COUNT Medal(s) spent": "已花费#COUNT枚奖章", + "Add all available STRATAGEMS to your loadout.": "将所有可用的战略配备添加至武装配置。", + "HELLPOD PATTERN": "绝地喷射舱涂装", + "PAPER": "布", + "Heavy Bug Nest Eradicated": "重型巢穴成功摧毁", + "Move to the SHOOTING RANGE to start the exercise.": "前往靶场开始训练。", + "PLANET LOST\nWe have failed to repel the Automatons from one of our planets. We will remember the fallen, and return to take it back.": "星球沦陷\n我们未能将机器人从我方的其中一颗星球逐出。我们将铭记陨落的英雄,并发誓收复失地。", + "Super Sample": "超级样本", + "CLAIM ITEM": "领取物品", + "EFFECTS [#COUNT]": "效果[#COUNT]", + "SCORE": "得分", + "Incoming DSS Eagle Strike": "民主空间站“飞鹰”攻击来袭", + "DRAUPNIR FREED\nThe Automaton presence on Draupnir is no more. Push the fight onward.": "德罗普尼尔已解放\n机器人不再染指德罗普尼尔的大地。让我们再接再厉,继续战斗。", + "SEISMIC SCAN RESULT:": "地震扫描结果:", + "DROPPED": "掉落", + "Rank #RANK - #RANKNAME": "级别#RANK - #RANKNAME", + "MILITARY OPS": "军事行动", + "#NAME - #STATE [#MEMBERS/#MAXMEMBERS]": "#NAME - #STATE [#MEMBERS/#MAXMEMBERS]", + "SUPER SAMPLE": "超级样本", + "to equip your Sidearm": "装备随身武器", + "LIBERATION FAILED\nDespite innumerable sacrifices, we have failed to liberate Turing from the Terminid's tyrannical clutches.": "解放失败\n尽管付出了无数的牺牲,我们还是未能将图灵从终结族的暴虐魔爪中解放出来。", + "PERSONAL ORDER COMPLETED": "已完成个人指令", + "Minor Place of Interest": "次要特殊地点", + "Backend version mismatch - You must update the game to the latest version.": "后端版本不匹配 - 你必须将游戏更新至最新版本。", + "Open STRATAGEM MENU and enter code for ORBITAL PRECISION STRIKE and throw BEACON at target.": "打开战略配备菜单,输入轨道精准攻击的代码,然后朝目标投掷信标。", + "This is a Commando Mission.\nThis far behind enemy lines, hostiles are everywhere. Every time they call for reinforcements, the threat level is increased. Higher threat level means more hostile units in the area.": "这是突击兵任务。\n深入敌后,群敌环伺。每当敌军呼叫增援时,威胁等级就会提升。威胁等级越高,该区域内出现的敌方数量越多。", + "APPLY NAME": "应用名称", + "LIGHT": "轻型", + "FIRE MODE": "开火模式", + "ITEMS DROPPED": "掉落物品", + "#NAME didn't make the cut": "#NAME已被淘汰出局", + "Tried to log in using a platform id the game does not support": "请勿使用游戏不支持的平台ID进行登录", + "PREMIUM WARBOND UNLOCKED": "已解锁尊享战争债券", + "to request reinforcement": "请求增援", + "AMMUNITION": "弹药", + "Failed to maintain session connection.": "游戏连接无法维持。", + "In Mission": "执行任务", + "#NAME: #MESSAGE": "#NAME:#MESSAGE", + "Receiving Confirmation": "正在接收确认信息", + "PRESS TO ACTIVATE": "按下按键即可启动", + "PURCHASE": "购买", + "In order to support fiscal responsibility, deployment magazine allocation for all weapons will be decreased for a short period of time.": "出于履行财政责任的需要,所有武器的弹匣配额都将在短期内降低。", + "No Helldivers on standby": "无绝地潜兵待命", + "Game found, preparing to travel...": "发现游戏,准备前往…", + "INTERNALS": "枪内", + "VANDALON IV UNDER ATTACK\nAutomaton dropships fill the skies of Vandelon IV. All Helldivers are called to its defense!": "万达隆IV遭到袭击\n机器人的运输舰遍布万达隆IV上空。呼唤全体绝地潜兵,前去保卫该星球!", + "Season III": "第III赛季", + "BUY MEDALS": "购买奖章", + "Select an Operation area to do Missions in - You can either join an ongoing Operation or start a new one.": "选择行动区域,前去执行任务 - 你既可以参加正在进行中的行动,也可以发起新的行动。", + "Steel Fist": "钢拳", + "ERATA PRIME FREED\nErata Prime has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet.": "艾拉特主星已解放\n艾拉特主星挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。", + "EXPLOSIVE HANDSHAKE": "热烈握手", + "Go to the Shipmaster and hand in your Orders.": "去找舰长提交指派任务。", + "to quick throw a Grenade": "快速投掷榴弹", + "Radiation Poisoning": "辐射中毒", + "MERIDIA FREED\nMeridia has been liberated from the tyrannical grasp of the Terminids. Good work, Helldivers. Push on to the next planet.": "默里迪亚已解放\n默里迪亚挣脱了终结族暴虐的魔爪。干得好,绝地潜兵。继续前往下一颗星球吧。", + "STRATAGEM AVAILABLE": "战略配备可用", + "BARRAGE": "火力网", + "FENRIR III UNDER ATTACK\nThe Terminids are attempting to spread to Fenrir III. All Helldivers are called upon to deploy immediately to the planet's defense.": "芬里尔III遭到袭击\n终结族企图扩张至芬里尔III。呼唤全体绝地潜兵,立即前去保卫该星球。", + "Cannot While In Prone": "趴下时无法使用", + "Offline": "离线", + "WEAPON EXPERIMENTATION\nThe Jump Pack stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“喷射背包”战略配备暂时获准供全体绝地潜兵使用。", + "The Super Destroyer cannot remain in this area for long.\n\nEach Helldiver may call it back once per mission using the CALL IN SUPER DESTROYER Stratagem.": "超级驱逐舰无法在此区域长时间停留。\n\n每位绝地潜兵在单场任务中可使用呼叫超级驱逐舰战略配备召回驱逐舰一次。", + "Steam Login denied by the remote party": "远端拒绝登录Steam", + "#NAME has been court-martialed": "#NAME已被移交军事法庭", + "INTELLIGENCE BRIEF\n\nA new gunship-style unit has been reported across all Automaton battlefronts. No intel indicated the deployment of new Automatons units. Had the Communications Array on Troost been captured, we may have had adequate forewarning to prepare effective countermeasures. \n\nAs it stands, Helldivers will have to rely on currently available resources and their peerless tactical ingenuity to combat this new threat.": "情报简报\n\n据报告,所有机器人战斗前线都出现了一种新型炮舰单位。没有情报显示有新的机器人单位部署。如果顺利占领特鲁斯特的通讯阵列,我们可能会有足够的预警来准备有效的反击措施。\n\n目前的情况是,绝地潜兵将不得不依靠现有的资源和他们无与伦比的战术智慧来对抗这一新的威胁。", + "COMMON": "普通", + "Join": "加入", + "Extraction available.": "撤离飞船就位。", + "NNW (#COUNT°)": "西北偏北#COUNT°", + "With the borders of the Void contained and the Mindless Masses pushed back, Helldivers drove Democracy into the skulls of the Illuminate. The Ministry of Science has ample material from Voteless who emerged from the Void and will begin learning what they can about conditions within the Void. \n\nVictory belongs to Super Earth. \n\nAny damages to allocated FRVs will be taken from Helldiver pay.": "随着寂域的边界得到控制,无脑群氓被击退,绝地潜兵将民主狠狠砸入光能者的脑壳。科学部已经从寂域中涌出的无票者身上取得充足的材料,并将开始尽其所能地研究寂域内部的情况。\n\n胜利属于超级地球。\n\n配给快速侦察载具的损坏费用将从绝地潜兵的薪水中扣除。", + "Aspirant": "志士", + "LIBERATION FAILED\nAngel's Venture remains infested by the Terminid Menace.": "解放失败\n天使投资星系依然为终结族所侵占。", + "The TCS has been fully activated on half of the Barrier Planets.": "半数屏障星球上的TCS已经全面启动。", + "MINE": "地雷", + "#WEAPON_NAME MAGS": "#WEAPON_NAME弹匣", + "PREPARING": "正在准备", + "CONSTRUCTING GEOGRAPHIC MODEL": "正在构建地理模型", + "Message": "消息", + "DISTRIBUTE BALLOTS": "派发选票", + "NEXT": "继续", + "CLAIM LEGENDARY WARBOND": "领取传奇战争债券", + "PHASE 2": "第2阶段", + "Playfab Session Ticket has expired. Login to Playfab again": "Playfab会话票据已过期。请重新登录Playfab", + "Spend #COUNT more medals to unlock": "再花费#COUNT枚奖章解锁", + "INTELLIGENCE BRIEF\nA new strain of flying Terminids has suddenly appeared across all Terminid planets, with no prior warning or indication of any kind. While the Ministry of Intelligence has always known this was a possibility, the abruptness of the evolution indicates a high possibility of dissident concealment.\n\nThe deployment of Termicide was fortuitously timed—doubtlessly, it averted an even worse evolution. Helldivers are advised to exterminate these mutations whenever encountered.": "情报简报\n所有终结族星球上突然毫无预兆地进化出全新的飞行种终结族。情报部一直知晓终结族的突变可能,如今情况突然发生,表明其内部极可能隐藏了异见分子。\n \n我们意外凑巧地部署了灭虫终结剂,无疑给终结族的突变加了一道障碍,防止产生更严重的后果。但凡碰上这些突变体,建议绝地潜兵都要及时扑杀。", + "LIGHT COMBAT (BOTS)": "轻型作战(机器人)", + "OPERATION CONSUMING VOID SUCCESS": "吞噬寂域行动成功完成", + "OPTICS": "准镜", + "New CUSTOMIZATION available in the ARMORY.": "军械库现已开放全新自定义选项。", + "ENE": "东北偏东", + "BUSY": "忙碌", + "PERMANENT ITEMS": "永久物品", + "MISSION PAYOUT": "任务收益", + "Crystallized E-710": "710元素晶体", + "RADAR activated. Map details revealed.": "雷达启动。已显示地图细节。", + "Delivery Point": "交付点", + "Invalid Authorization response from PlayStation™Network, no Claims received": "来自PlayStation™Network的授权响应无效,未收到验证声明。", + "FENRIR III SECURED\nThe Terminid Control System is now fully activated on Fenrir III.": "成功占领芬里尔III\n终结族遏制体系已经在芬里尔III全面启动。", + "Black Saffron": "番黑花", + "Requires base stratagem": "需要基础战略配备", + "Destroy MALFUNCTIONING HELLPODS for gear.": "摧毁发生故障的绝地喷射舱,获得装备。", + "CALCULATING EVACUATION FLIGHT PATH": "正在计算疏散飞行路线", + "#NAME returned to civilian life": "#NAME已回归平民生活", + "Wrestle (MASH)": "摔角(MASH)", + "Killed x#AMOUNT": "成功击杀x#AMOUNT", + "Show PATRIOTISM.": "展现爱国精神。", + "WNW (#COUNT°)": "西北偏西#COUNT°", + "EVADING": "躲避", + "CALCULATING MISSILE TRAJECTORY": "正在计算导弹弹道", + "Electronic Countermeasures": "电子对抗", + "Throw": "投掷", + "PLANETARY BLACKOUT": "星球失联", + "The account has a Steam session token but it's not authenticated": "账号拥有Steam会话令牌,但是该令牌尚未验证", + "DISPATCHES": "报告", + "EMERGENCY": "紧急情况", + "LAMBS TO THE SLAUGHTER": "待宰羔羊", + "When you're prone you fire more accurately.": "匍匐姿态下射击更精准。", + "Poor Intel": "缺乏情报", + "Search Platoon Members": "搜索特战排成员", + "WEAPON EXPERIMENTATION\nThe Orbital Gas Strike stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“轨道毒气攻击”战略配备暂时获准供全体绝地潜兵使用。", + "Non-Guided": "非制导", + "HIGH SCORES": "最高分", + "Board the EXTRACTION SHUTTLE!": "登上撤离运输船!", + "©ÅÄÖÉŠČ": "©ÅÄÖÉŠČ", + "Weapon Customization is now available. Click the CUSTOMIZE button to begin adjusting your weapon.": "武器自定义内容现已解锁。点击自定义键开始调整武器。", + "SUPPLY": "补给", + "Your right arm is injured, impacting your ability to aim and throw.": "你的右臂受伤了,你瞄准和投掷的能力将受到影响。", + "Support Weapons can be carried in addition to your primary weapon. Call in a MACHINE GUN.": "你可以同时携带主武器和支援武器。呼叫机枪吧。", + "Joined.": "加入成功。", + "SHIP": "舰船", + "E-710 OUTFLOW": "710元素外流", + "HELLBOMB": "地狱火炸弹", + "Orbital Fluctuations": "轨道波动", + "#NAME is no longer part of the team": "#NAME不再是团队一员", + "Playfab account not allowed to login. Please contact Community managers": "Playfab账号禁止登录。请联系社区管理员", + "Melee Kill": "近战击杀", + "ALERT": "警告", + "CAMPAIGN UPDATE\nDue to successful intelligence operations, each completed operation will contribute more than normal to planetary liberation.": "战役动态\n由于情报行动大获成功,完成的每一场行动都会比平时更加有效地推动星球的解放大业。", + "S (#COUNT°)": "南#COUNT°", + "#COUNTx": "#COUNTx", + "Open STRATAGEM MENU and call in a ORBITAL 120MM HE STRIKE at the remaining targets.": "打开战略配备菜单,呼叫轨道120MM高爆弹攻击,瞄准剩下的目标。", + "All of these reviews have been devised by Super Earth's Ministry of Truth after an analysis to reflect the most accurate possible opinions of loyal Super Earth citizenry. In other words, these are not real reviews.": "所有评论均由超级地球真理部经过分析后构思编成,以便尽可能准确地反映超级地球忠实公民的意见。换言之,这些都不是真实的评论。", + "PRIMARY": "主武器", + "The Automatons have established footholds on many Super Earth planets. Citizens have lost their homes, and now significant resources must be expended to regain the lost territory.": "机器人在许多属于超级地球的星球上建立了据点。无数公民因此流离失所。现在我们不得不耗费大量资源才能收复失地。", + "PlayStation®Plus is required to play this game.": "游玩本游戏需要PlayStation®Plus。", + "HUG": "拥抱", + "ARMORS": "盔甲", + "DENYING A BASE OF POWER": "绝不让步", + "Guided": "制导", + "FFF68AFF": "FFF68AFF", + "WEAPON EXPERIMENTATION\nThe Shield Generator Pack stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“防护罩生成包”战略配备暂时获准供全体绝地潜兵使用。", + "NW (#COUNT°)": "西北#COUNT°", + "SHOW PLAYER PROFILE": "显示玩家个人资料", + "Retrying In #TIME": "将在#TIME秒后重试", + "MORT FREED\nMort is finally free from the oppressive Automaton presence. Our hopeful citizens look forward to the commencement of colonization efforts.": "莫特已解放\n暴虐的机器人终于从莫特的土地上消失。满怀希冀的公民此刻开始期待启动拓殖任务。", + "Requisition RESUPPLY stratagem.": "申购重新补给战略配备。", + "RAIN DOWN FROM ABOVE": "天降民主雨露", + "#NAME left the mission": "#NAME退出任务", + "LIBERATION FAILED\nDespite great sacrifice, Ingmar remains under Automaton control.": "解放失败\n尽管我方付出了巨大的牺牲,但仍未能让英格玛脱离机器人的铁爪。", + "Alt. Ammo": "备用弹药", + "MISSION STARTING": "任务即将开始", + "You are already in this game session.": "已加入本场游戏。", + "Your left arm is injured, impacting your ability to aim.": "你的左臂受伤了,你瞄准的能力将受到影响。", + "Orbitals Used": "轨道攻击次数", + "ELIMINATED": "阵亡", + "Electro-Whip": "电鞭", + "Requisition MACHINE GUN SENTRY stratagem.": "申购哨戒机枪战略配备。", + "Legendary": "传奇", + "#NAME left": "#NAME已退出", + "SLOWER EXTRACTION": "撤离减慢", + "REFRESH": "刷新", + "#NAME didn't make the cut": "#NAME已被淘汰出局", + "NE (#COUNT°)": "东北#COUNT°", + "The Destroyer has left orbit": "驱逐舰已离开轨道", + "FORTIFICATION": "防御工事", + "NO ROOM": "空间不足", + "to move": "移动", + "Trying to upgrade an already fully upgraded weapon/stratagem.": "你正在尝试升级一项已经升至满级的武器/战略配备。", + "NO FUEL": "没有燃料", + "MISSION STRATAGEMS": "任务所需战略配备", + "SPREADING DEMOCRACY": "播撒民主", + "ARMOR": "盔甲", + "Idle hands are a fascist's playthings": "怠惰是法西斯的陋习", + "Enemy Kills": "敌方击杀数", + "Stats": "数据", + "SUPER URANIUM": "超铀", + "MIME INSTRUMENTATION": "弹空气吉他", + "The EXO-45 PATRIOT EXOSUIT is ready for use. Helldivers are advised to familiarize themselves with its features—ideally during live combat situations—as quickly as possible.": "EXO-45“爱国者”外骨骼装甲已经准备就绪。建议绝地潜兵尽快熟悉装甲的功能特性(最好是在实战环境中)。", + "ENTER": "进入", + "MISSION STATS UNAVAILABLE": "任务数据无法显示", + "Medium Bug Nest Eradicated": "中型巢穴成功摧毁", + "WEAPON EXPERIMENTATION\nThe AC-8 Autocannon stratagem has been temporarily authorized for use by all Helldivers.": "武器试验\n“AC-8机炮”战略配备暂时获准供全体绝地潜兵使用。", + "RESTART": "重新开始", + "WAR INFLUENCE: #WAR_INFLUENCE": "战争影响力:#WAR_INFLUENCE", + "Rock Paper Scissors": "石头剪刀布", + "SUPER RARE": "超稀有", + "to equip your Primary Weapon": "装备主要武器", + "HELLMIRE UNDER ATTACK\nThe bugs have attacked Hellmire. Rally to its defense, before they are able to permanently infest it.": "海尔迈尔遭到袭击\n虫族对海尔迈尔发动了袭击。立即集结,前去防卫,避免领地永远落入敌人手里。", + "#X/#Y": "#X/#Y", + "TEAM WEAPONS can be reloaded by teammates.": "团队武器可由队友装填弹药。", + "LOAD SHELL": "填弹", + "LIBERATION FAILED\nCrimsica remains infested by the Terminid Menace.": "解放失败\n克里姆西卡依然为终结族所侵占。", + "On Ship": "在船舰上", + "Equip": "装备", + "DEAD": "死亡", + "Hero": "英雄", + "TIMEOUT IN #MINS:#SECS": "超时倒计时 #MINS:#SECS", + "Failed to validate the Steam token provided by the client": "无法验证客户端提供的Steam令牌", + "VEHICLES #COUNT/#TOTAL": "载具 #COUNT/#TOTAL", + "Invalid Authorization for PlayStation™Network - Token Empty": "PlayStation™Network的授权无效 - 令牌为空", + "Target Account Profile is not found": "未找到目标账号资料", + "Failed to join because the session is full.": "游戏已满员,加入失败。", + "LIBERATION FAILED\nWe have failed to liberate Vandalon IV from the Automatons.": "解放失败\n我们未能从机器人手上解放万达隆IV。", + "TIMEOUT IMMINENT": "即将超时", + "ZEROING": "归零", + "Use Backpack": "使用背包", + "ACQUISITION CENTER": "采购中心", + "Scout Handshake": "侦察兵式握手", + "Tried to log in using legacy login with a non-test account": "请勿使用非测试账号执行遗留登录", + "Waiting for Super Earth approval of purchase...": "正在等待超级地球批准购买…", + "to reload your weapon": "为武器装弹", + "Test account not allowed to login. Please contact Community managers": "测试账号禁止登录。请联系社区管理员", + "INTELLIGENCE BRIEF\nThe Aerial Terminid Subvariant, dubbed \"Shriekers,\" has become a significant and pervasive strain, spreading across all Terminid planets. The Terminid's tyrannical instinct defies even the laws of nature, and now they infest our spacious skies. Helldivers are advised to stay vigilant for Shrieker nests and purge any they come across.": "简报\n飞行终结族亚种,别称为“尖啸虫”,它们已成为随处可见的变异个体且构成严重威胁,蔓延至终结族占领星球的各个角落。终结族凭借暴政本能藐视自然的规则,如今还侵袭了我们广阔的天空。请绝地潜兵警惕尖啸虫的巢穴,一旦遇上这类敌人,立即将其清除。", + "to look around": "环顾四周", + "LASER PRISM": "激光棱镜", + "FLASHLIGHT": "照明", + "EXALTED HERO": "伟人", + "Heavy Automaton Outpost Destroyed": "重型机器人哨站成功摧毁", + "#NAME left": "#NAME已退出", + "INGMAR LOST\nThe Automatons have taken Ingmar. A dark day for Managed Democracy.": "英格玛沦陷\n机器人已然占领英格玛,这是管理式民主史上黑暗的一天。", + "Round": "回合", + "to adjust valve": "调整阀门", + "Super Uranium": "超铀", + "Gunships are Patroling the Area": "炮舰正在巡逻此区域", + "SELECT": "选择", + "A heavily fortified Automaton position containing an Automaton CPU with valuable secret data. Extract with it, and your counterintelligence support will be rewarded.": "防卫森严的机器人据点,内部设置了机器人CPU,存有宝贵的机密数据。携带该CPU撤离,你的反情报支持工作将获得相应回报。", + "HEAVY COMBAT (ILLUMINATE)": "重型作战(光能者)", + "#SECONDSs": "#SECONDS秒", + "Lobby is private. You do not have permission to join.": "私密大厅,没有加入权限。", + "Inventory Value": "生涯消费", + "Self inflicted": "自伤", + "Reward: #TYPE": "奖励:#TYPE", + "LIBERATION FAILED\nDespite innumerable sacrifices, we have failed to liberate Veld from the Terminid's claws.": "解放失败\n尽管付出了无数的牺牲,我们还是未能将维尔德从终结族的暴虐魔爪中解放出来。", + "REINFORCE AVAILABLE": "增援就位", + "Shuttle Departing In T-#MINUTES:#SECONDS:#MILLI": "运输船出发倒计时 #MINUTES:#SECONDS:#MILLI", + "SE (#COUNT°)": "东南#COUNT°", + "Volley": "齐射", + "KMH": "公里/时", + "SHIP MODULES": "舰船模块", + "START UP": "出发", + "MISSION SUCCESSFUL": "任务成功", + "EXTRACTION AVAILABLE": "撤离飞船就位", + "#NAME": "#NAME", + "Mime Instrumentation": "弹空气吉他", + "N (#COUNT°)": "北#COUNT°", + "VALUE": "色值", + "Samples": "样本", + "When carrying something in one hand, you can only wield one-handed weapons.": "其中一只手携带物体时,你只能持有单手武器。", + "COMPLETED": "已完成", + "SUPPLY BACKPACK can carry extra ammo. Use the BACKPACK FUNCTION to resupply yourself.": "补给背包可以装载额外的弹药。使用背包功能为自己补充弹药。", + "TARGET DESTINATION": "目的地", + "to use stim": "使用治疗剂", + "Friends": "好友", + "Beacon must be under constant supervision once activated.": "信标一旦启动,必须一直监控。", + "Deployment magazine allocation will be temporarily increased, in order to expend excess inventory.": "为消耗过剩库存,弹匣配额将暂时提高。", + "Total": "全射", + "SHOTGUN": "霰弹枪", + "#NAME": "#NAME", + "PREMIUM WARBOND NEEDED": "需要尊享战争债券", + "Approaching OUTPOST. Call in a GATLING SENTRY for extra firepower.": "正在接近哨站。呼叫加特林哨戒炮提供额外火力。", + "INTEL PDA": "情报PDA", + "FRIENDS ON PLAYSTATION®": "PlayStation®的朋友", + "Fortress": "堡垒", + "MUTE": "静音", + "VOLUME: #COUNT": "音量:#COUNT", + "PLEASE WAIT DEMOCRATICALLY": "请民主地等待", + "INVITE SENT": "已邀请", + "UNMUTE": "取消静音", + "KICK (HOLD)": "移除(长按)", + "Requisition slips": "申购单", + "Medal": "奖章", + "Vote": "投票", + "VOTE SUCCESSFUL": "投票成功", + "You have performed your democratic duty\nWELL DONE!": "你已履行你的民主职责\n干得漂亮!", + "#DAYS DAYS #HOURS HOURS #MINUTES MIN": "#DAYS日#HOURS小时#MINUTES分", + "CANDIDATE NOT ELIGIBLE FOR VOTES": "候选人没有投票资格", + "BIOGRAPHY:": "生平事迹:", + "Please wait while Super Earth democratically processes your ballot.": "超级地球正在进行民主计票,请稍候。", + "Term #TERM": "任期:#TERM", + "ELECTION STARTS IN:": "选举开始倒计时:", + "ELECTION ENDS IN:": "选举结束倒计时:", + "POLICY:": "政策:", + "VOTE FAILED": "投票失败", + "TERM #TERM": "任期:#TERM", + "ARCTIC": "雪地", + "The uncanny illumination seeping from the bulb stains the surroundings with its tyranny.": "灯泡中散发出的诡异光芒让周围笼罩在暴政的阴影之中。", + "From the graceful typography to the elegant use of space, this sign is a masterwork of patriotic craftsmanship.": "排版优雅、留白高明,这个标牌堪称爱国主义艺术品的杰作。", + "\"Congratulations on Procreation Approval for [1] child. May you multiply the love of Democracy for generations to come.\"": "“祝贺你获准生育[1]个孩子。愿你将对民主的热爱传承给后世子孙。”", + "AUTOMATON REMAINS": "机器人的遗骸", + "A message is etched into the surface: \"In everlasting gratitude to the loyal soldiers who gave their lives in the defense of Managed Democracy.\"": "雕像表面刻着一句话:“永远感谢为捍卫管理式民主而牺牲的烈士。”", + "Without power, this vendor of beverages is only a lifeless husk. Another innocent casualty of Tyranny.": "没了电,这台自动饮料售货机不过是一具空壳,也是暴政的无辜受害者。", + "GRASSLAND": "草原", + "COMMUNICATIONS DEVICE": "通信设备", + "\"Cache Inventory:\n-300 rounds Liberator ammo\n-14 stims\n-12 gallons water\n-3 frag grenades\"": "“隐藏库存:\n- 300发“解放者”弹药\n- 14支治疗剂\n- 12加仑水\n- 3枚榴弹”", + "\"HELLDIVER TRAINING FACILITY\nWelcome to Helldiver Training\nEARN YOUR CAPE\nCHECK YOUR MAP TO FIND THE HELLDIVER FACILITY\"": "“绝地潜兵训练基地\n欢迎接受绝地潜兵的训练\n努力赢得披肩吧\n查看地图,寻找绝地潜兵基地设施”", + "GREENHOUSE - TYPE 203": "温室 - 203型", + "The crimson glow, no doubt with nefarious intention, is now used by discerning Helldivers as a indicator of this device's explosive nature.": "绯红的光芒赫然彰显着邪恶意图,但敏锐的绝地潜兵一眼就能看出这个装置属于炸弹。", + "\"For alien scum\"": "“致异形渣滓”", + "VENDING MACHINE": "自动售货机", + "A tool is missing from its spot. Likely pilfered by the enemy for some iniquitous application.": "工具不翼而飞。很可能是心怀不轨的敌人偷走的。", + "The voltage of these batteries has been temporarily saved from being yoked to the expansion of the Automaton menace.": "这些电池暂时得救了,不必在机器人威胁扩张之下遭受奴役。", + "\"Welcome! Please note: failure to feel sufficiently welcomed should be reported immediately.\"": "“欢迎!请注意:如果未能感受到足够热烈的欢迎,请立即举报。”", + "\"Please present this certificate as proof of approval to perform a left-handed salute for the duration of your injury.\"": "“请出示这张许可,证明你已获准在受伤期间用左手敬礼。”", + "The greenhouse maintains an atmosphere nearly identical to that of Super Earth.": "这间温室维持着与超级地球几乎相同的空气成分。", + "The cascade of sparks is like a patriotic celebration of triumph over this threat to Democracy.": "星火流瀑,仿佛是战胜民主威胁的爱国庆祝活动。", + "Its unclear if this Automaton can still perceive external stimuli. There's no telling how long it will remain in this state before its battery expires.": "这个机器人是否还能感知外部刺激是个未知数。不知道它在电池耗尽之前能保持这种状态多久。", + "\"Happy Liberty Day, bugs!\"": "“虫子们,解放日快乐!”", + "The machine appears to be empty of its delicious, refreshing beverages.": "售货机里清爽可口的饮料似乎已售罄。", + "The pale gleam of the lamp is sinister and alien, doubtlessly due to its un-Democratic fashioning.": "这盏灯苍白的微光十分邪恶和诡异。毫无疑问,这是非民主设计方式导致的。", + "The Gateways at Giza. Modern living with an age-old charm. Units available.": "吉扎之门。古色古香的现代生活。正在出售。", + "\"Eulogy Template—Soldier, friendly fire variation 016: [Name] devoted many hours to the prosperity of Super Earth. They may rest easy in the knowledge that the [bullets/shrapnel/concussive force] that took their life was Democratic in origin and fired in the service of Liberty.\"": "“悼词模板 - 士兵,友军误伤016版:[姓名]为超级地球的繁荣鞠躬尽瘁,将安然长眠,因为夺走其生命的[子弹/弹片/武装]是为民主而发,是为解放而战。”", + "The screen is frozen on a rousing reminder of the value of strenuous labor.": "画面定格在一条宣扬辛勤劳动价值的提醒上。", + "It only takes ONE TRAITOR to destroy Utopia.\n\nThe Ministry of Unity.": "一个叛徒足以瓦解乌托邦。\n\n团结部", + "A rack containing every tool one needs to construct a better tomorrow.": "一副支架,上面放着构建美好明天所需的所有工具。", + "\"The Charger continues to display increased agitation upon exposure to imagery of Helldivers. Possible evolved response?\"": "“强袭虫在看到绝地潜兵的图像后越来越躁动不安。可能是进化后的反应?”", + "Not in my backyard.\n\nEnlist.": "绝不能危及家园。\n\n应征入伍。", + "\"The Colonial Overseer's Handbook. A guide to Planetary Terraforming, Resource Extraction, and Colonist Management. Approved by the Ministry of Expansion.\"": "“《拓殖地监督员手册》,行星地球化、资源开采和拓殖地居民管理指南。经扩张部审核通过。”", + "\"Next!\n\nBuy war bonds.\"": "“下一个目标!\n\n购买战争债券。”", + "SWAMP PLANET": "湿地星球", + "PUBLIC SERVICE POSTER": "公共服务海报", + "DESPOTIC EXPLOSIVE": "专制炸药", + "\"The Ministry of Science reminds all citizens of the numerous citizenship benefits to enrolling yourself and you family in medical studies. Could your body be of greater use to Liberty?\"": "“科学部提醒各级公民全体成员,全家加入医学研究,益处良多。你愿意全身心贡献给解放事业吗?”", + "\"Next week's delivery:\n -4 Liberators\n -2 cases prefab meals\n-Fuel drum\"": "“下周交付:\n- 4把“解放者”\n- 2箱预制饭菜\n- 燃料桶”", + "These batteries fuel the Automaton war machine.": "这些电池为机器人的战争机器补充能源。", + "ROCKY": "岩地", + "\"Concerns of mine safety, including long hours, dim tunnels, insufficient supports, rickety ladders, etc., have been noted, considered, and addressed. Please continue with renewed confidence in your safety.\"": "“工作时间长、隧道昏暗、支援不足、梯子摇晃等矿井安全问题已获关注、斟酌和解决。请重拾对人身安全的信心,继续作业。”", + "HASTILY WRITTEN NOTE": "匆匆写下的便条", + "The glow of the interior bulb is out, leaving the artful branding a pale shadow of its former vivid glory.": "内部灯泡不再发光,这份精致的宣传仅剩往昔熠熠光辉余留的一丝苍白残影。", + "PATRIOTIC POSTER": "爱国海报", + "The 11th in the \"Loyalty\" series, this sign is a return to form after the extravagance of version 10.": "“忠诚”系列的第11版标牌。相比华丽的第10版,这一版标牌可谓返璞归真。", + "Who can say what heinous deeds this machine was intended to carry out?": "谁知道它们打算用这台机器干出何等令人发指的罪行?", + "\"EMERGENCY WARNING: Hostile forces incoming. Evacuate immediately. EMERGENCY WARNING: Hostile forces incoming. Evacuate immediately.\"": "“紧急警告:敌方军队即将抵达。立即撤离。紧急警告:敌方军队即将抵达。立即撤离。”", + "HANDWRITTEN NOTE": "手写便条", + "FORKLIFT": "叉车", + "\"The Ministry of Humanity regrets to learn of the tragic loss of your family member. Please follow the enclosed instructions for proper patriot disposal and tax forms.\"": "“得知你痛失家人,人道部深表遗憾。请按照随附的说明妥善处理爱国者的遗体及纳税表格。”", + "OPPRESSIVE MACHINE": "压迫机器", + "\"Colonial alert: due to budgetary constraints, dwelling temperatures will be lowered by [13%].\"": "“拓殖地警告:由于预算受限,住宅温度将降低[13%]。”", + "BLOOD-STAINED LIBRARY CARD": "血迹斑斑的借书证", + "AUTHORITARIAN LIGHT": "独裁之光", + "SANDY PLANET": "沙地星球", + "ROCKY PLANET": "岩地星球", + "\"Congratulations on your acceptance to Trailblazer University, the premier online educational institution for tomorrow's colonial leaders.\"": "“祝贺你被开拓者大学录取,这是培养拓殖地未来领袖的一流在线教育机构。”", + "SAVANNA PLANET": "稀树星球", + "A message is etched into the surface: \"In eternal remembrance of the innumerable Helldivers who made the ultimate sacrifice in the First Galactic War.\"": "雕像表面刻着一句话:“永远怀念第一次星系战争中献身的无数绝地潜兵。”", + "The purpose of this machine is unknown, it is as irredeemable as its creators.": "这台机器用途不明,跟它的制造者一样无药可救。", + "WORDS SCRIBBLED ON BOMB": "炸弹上的潦草文字", + "Truth: the backbone of Democracy.\n\nThe Ministry of Truth.": "真理乃民主之本。\n\n真理部", + "Used to transport ore, modular dwellings, and dissident holding pens.": "用于运输矿石、模块化住房和异见分子的关押栏。", + "Tyranny contained within a matrix of anodes and cathodes.": "暴政就在阳极和阴极组成的矩阵之内。", + "Half a message is typed on this blood-spattered tablet: \"Request immediate fire support. Taking heavy ca-\"": "留有血迹的平板上残留着输入到一半的消息:“请求立刻提供火力支援。伤亡惨…”", + "\"Deliver to Terminids ASAP\"": "“尽快送至终结族”", + "ADVERTISEMENT": "广告", + "Automaton glyphs mark the exterior, menacing and power-hungry in their contortions.": "电池表面刻着机器人的符号。歪歪扭扭的笔画暴露了它们凶恶的本性以及对能源的渴望。", + "RE: MINE SAFETY": "回复:矿山安全", + "\"Remember: late returns steal from us all.\"": "“切记:逾期归还等同于偷窃公共财物。”", + "\"Don't forget to vote on YOUR colony's Patriot of the Month!\"": "“别忘了投出宝贵一票,选出你所在拓殖地的‘本月爱国者’!”", + "A twisted distortion of one of Humanity's greatest inventions.": "人类最伟大的发明之一,现已扭曲变形。", + "GRASSLAND PLANET": "草原星球", + "\"Handle with care\"": "“小心轻放”", + "\"Eulogy Template—Soldier, variation 004: [Rank] [Name] joined the service at [age]. They served [noble adverb] and perished heroically while fighting [enemy]. We will never forget their [unique trait].\"": "“悼词模板 - 士兵,004版:[军衔][姓名]在[年龄]时入伍,[体现崇高品质的副词]服役,在与[敌人]作战时英勇牺牲。我们永远不会忘记这位英雄的[独特品质]。”", + "These plants are beginning to wilt in the absence of Democracy's tender care.": "没有了民主的呵护,这些植物便开始枯萎。", + "Everything you need to know.\n\nThe Ministry of Truth.": "了解你需要知晓的一切。\n\n真理部", + "\"Diet Democracy. Free yourself.\"": "“饮食民主。解放自我。”", + "We stay INFORMED to inform YOU.\n\nThe Ministry of Truth.": "追求真理,传播真理。\n\n真理部", + "Tools are hung neatly, in accordance with governmental guidelines.": "工具摆放得整整齐齐,严格遵守政府规定。", + "\"Do not operate without a ground guide.\"": "“必须有地勤人员指引。”", + "Divorced from it's tyrannical programming, the metal of this former Automaton is free once more.": "摆脱了专制程序,用来构建这个机器人的金属材料重获自由。", + "\"Alert: due to increased local hostile activity, all funerals are to use Expedited Internment Procedures until further notice.\"": "“警告:由于当地敌对活动激增,全部葬礼须使用加急安葬程序,直至另行通知。”", + "\"Don't forget! Catch the bi-weekly State of the Federation announcement at 8PM tonight (absence must be pre-approved).\"": "“别忘了!请准时收看今晚8点播出的双周联邦政府通报(需获批准才能缺席)。”", + "Keep their tentacles off our children!": "不能让它们将触手伸向我们的孩子!", + "\"Offerings include: Dr. Democracy, Mr. Taste, Prof. Delicious, & Yummm, Esq.\"": "“供应:民主博士、美味先生、好吃教授与可口先生。”", + "FOREST": "森林", + "A standard-issue rack of standard-issue tools.": "收纳制式工具的制式支架。", + "\"Please refrain from operating heavy machinery while consuming this beverage.\"": "“享用这种饮料时,请勿操作重型机械。”", + "ENTRY ##64": "第64条", + "\"Reminder: Planetary Overseer elections are just around the corner!\"": "“提醒:行星监督员选举已近在眉睫!”", + "A message is etched into the surface: \"In memory of Liberty's servants who perished heroically in unavoidable friendly fire incidents.\"": "雕像表面刻着一句话:“纪念因难以避免的友军误伤而英勇阵亡的解放忠仆。”", + "\"Get some!\"": "“尝尝我们的厉害!”", + "\"Eulogy Template—Soldier, Exemplary Service 121: The heroism of [Rank] [Name] cannot be understated. They did not lose their life in the defense of Super Earth. They gave it, willingly.\"": "“悼词模板 - 士兵,模范军人121版:[军衔][姓名]的英勇精神不可估量。这位英雄并非因为保卫超级地球而丧命,而是心甘情愿献出生命。”", + "\"Memo to all SEAF forces: Moving forward, frontline mail services will be reserved for soldiers of exceptional democratic service only.\"": "“发送给超级地球武装部队全体成员的备忘录:随着部队的推进,前线邮政服务将仅对作出特殊民主贡献的军人开放。”", + "A smoldering heap of scrap. It got what it deserved.": "一堆闷烧的废料。总算是恶有恶报。", + "MOOR": "荒地", + "FOREST PLANET": "森林星球", + "\"Note to Grave Preparation Specialist: due to high hostile activity in the area, graves may be required to accomodate more personnel than usual.\"": "“墓地整备专员注意事项:由于该区敌对活动频繁,需要下葬的人数多于正常水平。”", + "Raises your mission priority to all other Helldivers, increasing the odds of others joining your squad.": "将你的任务优先级提升到所有其他绝地潜兵之前,增加其他士兵加入你小队的几率。", + "\"Please report immediately to your Loyalty Officer for investigation. Reason: [Citizen Report of Dissident Speech].\"": "“请立即向你的忠诚事务官举报以便展开调查。理由:[公民举报异见分子言论]。”", + "PRIMORDIAL PLANET": "原始星球", + "The robotic manipulators at the end of the arm can grasp nothing, save oppression.": "在背后操控这支机械臂的那些家伙除了施加压迫以外,什么也抓不住。", + "\"Local hostile activity is currently assessed as LOW THREAT. All citizens are to continue duties until further notice.\"": "“当地敌对活动目前被评估为‘低威胁’。所有公民继续履行职责,直至另行通知。”", + "\"The Ministry of Humanity has processed your missing persons report. Result: [CLOSED.] Conclusion: [Mine mishap.]\"": "“人道部已处理你的失踪人口报告。结果:[已结案。]结论:[矿井事故。]”", + "\"Not suitable for traitors of democracy.\"": "“不适合民主的叛徒。”", + "\"Please select which delicious flavor you would like to see included in our colony's next seasonal rations: Blueberry, Chocolate, Cinnamon, Birthday Cake.\" Birthday Cake is selected.": "“请选择你希望在拓殖地下一季口粮中尝到的口味:蓝莓、巧克力、肉桂、生日蛋糕。”已选择生日蛋糕。", + "SUPER EARTH ISSUED TOOL RACK": "超级地球常规工具架", + "CASE OF \"DEMOCRACY DRAFTS\" PREMIUM LIGHT BEER": "“民主之风”至尊淡味啤酒的外包装", + "MONUMENT TO LIBERTY": "解放纪念碑", + "The screen is frozen on one final message: \"Hold.\"": "画面定格在最后一条消息:“坚持住。”", + "SOS Beacon": "S.O.S.求救信标", + "\"Memo to Colonial Overseer: Be sure to calibrate the productivity output of your workers in accordance with your Compliance Index.\"": "“拓殖地监督员备忘录:务必按照服从指数校准工人的生产力输出。”", + "\"The Ministry of Humanity would like to congrulate you on approval for marriage. Enclosed are instructions for consolidating domiciles.\"": "“人道部祝贺你们获得婚姻许可。随函附上住所合并说明。”", + "SEAF COMMUNICATIONS DEVICE": "超级地球武装部队通信设备", + "In this abundant garden of flora native to Super Earth, Liberty has taken root on an alien planet.": "这花园里长满了超级地球的各种原生植物,有如解放精神在这颗外星球上稳稳扎根。", + "\"Due to the exceptional hazard of the current posting, all SEAF soldier's and their approved domestic family units will be granted Class C citizenship following mission completion or death.\"": "“由于目前外派任务特别危险,所有参加任务的超级地球武装部队士兵与其获批家属都将在任务完成或阵亡后获得C级公民身份。”", + "\"Memo to Colonial Overseer: In order to best serve Freedom, the security budget for your colony will be reduced by [23.7%] for the next fiscal term.\"": "“拓殖地监督员备忘录:为了更好地为自由服务,你所在拓殖地的安全预算将在下一个财政任期内减少[23.7%]。”", + "PRIMORDIAL": "原始", + "\"Took stash. Needed it. Sorry. \n P.S. This man was dead when I got here. \n-D\"": "“拿走了隐蔽装备。急需。抱歉。\n注:我到的时候这个男人就已经死了。\n-D”", + "The screen shows a picture of what must be a SEAF soldier's family, holding a banner saying \"Defend our Freedom.\"": "画面的照片里想必是超级地球武装部队士兵的家人,他们手举带有“捍卫自由”字样的横幅。", + "SAVANNA": "稀树", + "\"Was low on supplies. Took ammo. Left oatmeal. Good luck -D\"": "“补给短缺。拿走了弹药。留下了燕麦片。祝你好运 -D”", + "WELCOME SIGN - HOMELY VARIANT 02": "欢迎标牌 - 家常版02", + "SANDY": "沙地", + "This forklift is the red blood cell of Managed Democracy, conveying vital necessities to wherever they are needed.": "这辆叉车是管理式民主的红细胞。哪里需要重要物资,哪里就有它们的身影。", + "A pair of safety goggles hang by a strap, the frames spattered with blood. They seem to have failed their purpose.": "一副安全护目镜挂在带子上,镜框上有血迹。看来它没能完成自己的使命。", + "\"Ministry of Truth Library Branch 301C\"": "“真理部图书馆301C分馆”", + "LIBERTY OUTLETS\n\nWorld's Longest Shopping Mall": "解放奥特莱斯\n\n全世界历史最悠久的购物中心", + "Billions of stars. One Federation.\n\nThe Ministry of Expansion.": "亿万星辰归属一个联邦。\n\n扩张部", + "Whether this Automaton can ever have been said to be alive is a question for the philosophers. In either case, it is definitely dead now.": "这个机器人能否算得上“活着”是个哲学问题。但不论它有没有“活过”,现在肯定已经死透了。", + "A tool of tyranny.": "实施暴政的工具。", + "\"Notice to Colonists: A military operation is being conducted in your vicinity. There is no need for alarm. Please remain indoors until further notice.\"": "“拓殖地居民请注意:附近正在执行军事行动。不必担心。请留在室内,等待另行通知。”", + "\"Have a taste of freedom!\"": "“这就是自由的力量!”", + "The cracked device displays a photo of a smiling child with a pickaxe over their shoulder.": "被破解的设备上显示一张照片,上面是肩扛鹤嘴锄、露出微笑的孩子。", + "CAPTAIN'S LOG": "少校的日志", + "SWAMP": "沼泽", + "We defend Democracy's Future.\n\nThe Ministry of Defense.": "捍卫民主的未来。\n\n国防部", + "Keep an ear open for TREASON.": "时刻警惕叛国。", + "\"From Super Earth With Love\"": "“来自超级地球,饱含热爱”", + "The synthetic marble figure communicates a message of proud freedom that crosses all boundaries of species and sapience.": "这座人造大理石雕像传达以自由为傲的理念,已超越一切种族与智慧界限。", + "The Ministry of Prosperity ensures every colony has access to the latest beverages, extending libationary ingenuity to all Super Earth's citizens.": "繁荣部保证每一个拓殖地都能享用最新的饮品,让向全体超级地球公民传播独创的饮料文化。", + "An abomination constructed by abominations, with abominable intent.": "可恶的机器人怀着可恶的用心制造的可恶机械。", + "Loyalty is Rewarded. Report any dissident activity.\n\nThe Ministry of Unity.": "忠诚有奖。请及时举报任何异见分子活动。\n\n团结部", + "Inspect": "查看", + "\"Attention: Your Animal Companion Request for [1] [hamster] has been denied at this time.\"": "“注意:你对圈养[1]只[仓鼠]作为陪伴动物的申请本次已拒绝。”", + "Remember Outpost 32": "铭记32号哨站", + "On the surface, only a lamp, but any true patriot recognizes this for what it is: an abomination.": "看似一盏灯,但真正的爱国者都能认出它那面目可憎的本质。", + "\"HELLDIVER TRAINING FACILITY\"": "“绝地潜兵训练基地”", + "MOOR PLANET": "荒地星球", + "ARCTIC PLANET": "雪地星球", + "Scratched into the pedestal: \"They will save us.\"": "底座上刻着:“他们会救我们。”", + "A frantic final harvest appears to have been attempted during evacuation.": "撤离期间似乎有人试图疯狂收割最后一波。", + "Transporting a large shipment of flamethrowers. Heavy enemy presence - delivery expected to take the whole day. Derek forgot the fire extinguisher but I'm sure we'll be fi-": "正在运输大量火焰喷射器。敌人攻势强劲,预计要花一整天才能送到。德里克忘了带灭火器,但肯定不会出意……", + "A device used to communicate between the Department of Expansion and Colonial Overseers.": "拓殖地监督员和扩张部之间的通信设备。", + "\"To Whichever Terminids It May Concern\"": "“至拿到此物的终结族”", + "\"Pesticide\"": "“杀虫剂”", + "This machine gives no sign of sapience, but one can never be too sure.": "这台机器看起来不具备智慧,但是世上没有绝对之事。", + "PERSONAL DEVICE": "个人设备", + "\"You are legally required to report any Terminid attacks to the authorities!\"": "“依照法规,只要终结族发动攻击,你必须向当局汇报!”", + "\"ORDER: Do not retreat. Defend Liberty at all costs.\"": "“命令:不要撤退。不惜一切捍卫解放事业。”", + "Once alive with a calming hum, the abandoned machine now lies dormant.": "这台机器曾经能发出让人安心的嗡嗡声,现在则遭到遗忘,在此长眠。", + "\"Ministry of Defense study indicates enemy morale reaching new, unprecedented lows.\"": "“国防部研究显示,敌人的士气正达到前所未有的低点。”", + "The eerie calm of the exterior masks the autocratic potential energy trapped within.": "平凡却怪异的外表下掩藏着束缚在内的专制能量。", + "\"Remember: complaints are the gateway to dissidence.\"": "“记住:抱怨是通往异见之门。”", + "\"Dr. Democracy: With 17 seasonings and additives\"": "“民主博士:包含17种配料和添加剂”", + "What are you waiting for?": "你还在等什么?", + "The patriotic hues are enough to stir the heart of any true patriot.": "浓厚的爱国色彩足以打动每一个真正爱国者的心。", + "\"The Ministry of Truth would like to remind all citizens that un-Democratic reading material must be reported immediately.\"": "“真理部温馨提醒全体公民,如果发现非民主读物,务必立即上报。”", + "Stop the infestation!": "制止侵袭!", + "REPRODUCTION": "繁殖速度", + "TCS FULLY OPERATIONAL": "TCS全面运作", + "MINISTRY OF PROSPERITY ANNOUNCES CLOSURE OF MIDASBURG MINT AFTER 75 YEARS OF OPERATION": "繁荣部宣布关闭运营75年的弥达斯堡造币厂", + "AUTOMATON INCURSION": "机器人入侵", + "BUG CONTAINMENT": "虫族管控", + "TCS ACTIVATION UNDERWAY": "TCS启动工作进行中", + "GALAXY IN CELEBRATION": "全星系欢庆", + "TERMICIDE EXTREMELY EFFECTIVE": "灭虫终结剂极其有效", + "\"IT IS PAST TIME WE RESPONDED TO THIS UNPROVOKED INCURSION AGAINST DEMOCRACY. THE HELLDIVERS ARE DEPLOYING AS WE SPEAK TO STRIKE A NUMBER OF AUTOMATON MILITARY INSTALLATIONS. THESE INVADERS WILL SOON DISCOVER THE STEEL OF SUPER EARTH RESOLVE.\"": "“我们早该对这种无端侵犯民主的行为加以还击。就在此时此刻,绝地潜兵已经出动,针对机器人的多处军事设施发起攻击。这些入侵者很快就会发现,超级地球的决心坚如钢铁。”", + "Dr. Pauline Dupont": "波林·杜邦博士", + "SS LIBERTY": "星舰解放号", + "DISSIDENT": "异见分子", + "Spaghettification Visualization": "面条化影像", + "TERMICIDE SCIENTISTS RECOGNIZED": "灭虫终结剂科学家身份确认", + "NEW BILL WOULD TEMPORARILY GRANT PET FISH AUTHORIZATION TO CLASS C CITIZENS AND ABOVE": "新法案将暂时批准C级及以上公民饲养宠物鱼", + "SUPERCOLONY DESTROYED": "超级拓殖地毁灭", + "Barely able-bodied Citizens": "体弱的公民", + "20X FASTER": "加快20倍", + "SONNTAG": "松塔格", + "CATCHY TUNE": "洗脑旋律", + "ENLISTMENTS RATES SOAR": "入伍率飙升", + "ARE PROGRAMMED FOR 2 THINGS: VIOLENCE,": "这些机器人的程序里只写了两样东西:", + "DUPONT": "杜邦", + "PAULINE": "波林", + "APPROVED BY THE MINISTRY OF TRUTH": "经真理部审核通过", + "REMAINING PLANETS COULD BECOME SUPERCOLONIES": "剩余星球可能成为超级拓殖地", + "—MINISTRY OF DEFENSE": "——国防部", + "OVERALL BIRTH RATE TARGET INCREASED TO 1.4% FROM 1.35%": "总出生率目标从1.35%提高至1.4%", + "STROHMANN NEWS": "斯托曼新闻", + "ENLIST TODAY": "立即入伍", + "HELLDIVERS TO STRIKE AUTOMATONS": "绝地潜兵即将出击机器人", + "OPERATION \"VALIANT ENCLOSURE\" BEGINS": "“英勇围合”行动开始", + "TCS FAILURE: WHAT WE KNOW": "TCS的失败:我们掌握的信息", + "RESTRICTED AREA": "禁区", + "\"PEACE IS NOT AN OPTION. THE AUTOMATONS ARE PROGRAMMED FOR 2 THINGS: VIOLENCE, AND HATING FREEDOM.\"": "“和平共存是不可能的。这些机器人的程序里只写了两样东西:暴力,以及憎恨自由。”", + "TOILET STALLS: DISSIDENT HIDEOUTS?": "厕所隔间:异见分子的秘密基地?", + "Bullets": "子弹", + "\"SUPERCOLONY\"": "“超级拓殖地”", + "HELLDIVERS DEPLOY TO RETAKE CYBERSTAN": "绝地潜兵出动,重夺生化斯坦", + "ALL YOU\nNEED TO KNOW": "通晓\n天下", + "ILLUMINATE RETURNED?": "光能者回归?", + "—PRESIDENT OF SUPER EARTH": "——超级地球总统", + "SPIKE IN SALES OF HELLDIVER TOYS ATTRIBUTED TO NEW DEPLOYMENT": "近期新行动部署推动绝地潜兵玩具销量剧增", + "MULTIPLE PLANETS INVADED": "多颗星球遭到入侵", + "Production Rate": "生产率", + "HARBER": "哈珀", + "AUTOMATONS ATTACK DEVELOPED WORLDS": "机器人袭击发达星球", + "WITH CORETTA KELLY": "主持人:科雷塔·凯利", + "99.6%": "99.6%", + "RUMORS OF ILLUMINATE SIGHTINGS ARE WORK OF DISSIDENTS": "目击光能者的谣言属异见分子所为", + "TERMINID OUTBREAK": "终结族暴乱", + "MOBILIZATION": "动员行动", + "FREDA": "弗雷达", + "Grenades": "榴弹", + "BREAKING NEWS": "突发新闻", + "Termicide effect": "灭虫终结剂效果", + "DARK FLUID INCIDENT": "暗液体事故", + "NEWLY IDENTIFIED SOLAR SYSTEM MAY HAVE UP TO 3 SUITABLE PLANETS FOR COLONIZATION, ACCORDING TO MINISTRY OF SCIENCE REPORT": "根据科学部报告,在新发现的恒星系中,适合建造拓殖地的星球可能多达3个", + "EGON": "埃贡", + "TERMICIDE 2.0 RESEARCH UNDERWAY": "灭虫终结剂2.0研究正在进行中", + "TOP SECRET RESEARCH FACILITY": "高度机密研究设施", + "TERMICIDE CAUSED INCREASED REPRODUCTION": "灭虫终结剂导致繁殖加速", + "Barrier planets": "屏障星球", + "NOW, IT IS CLEAR THAT THERE CAN BE NO PEACE UNTIL": "现在,显而易见,我们必须彻底摧毁", + "CITIZENS EAGER TO HELP": "公民迫切贡献力量", + "I ALREADY HAVE": "我已入伍", + "OPERATION SWIFT DISASSEMBLY CONTINUES": "急速拆解行动继续进行中", + "AUTOMATON SURPRISE ATTACK": "机器人突然来袭", + "GALAXY IN MOURNING": "全星系哀悼", + "Lead Scientist": "首席科学家", + "SEAF": "超级地球武装部队", + "WAR SONG TOPS CHARTS": "战歌高居音乐榜首", + "DR. DISSIDENTS?": "异见分子博士?", + "REVOKED": "已撤销", + "\"FOR THE DISCOVERY AND SYNTHESIS OF TERMICIDE\"": "“发现并合成灭虫终结剂”", + "PERMANENT END OF CONFLICT WITH THE AUTOMATONS.": "即将与机器人永久结束冲突之际。", + "WOULD YOU ENLIST TO FIGHT THE AUTOMATONS?": "你是否愿意应征入伍,对抗机器人?", + "CANNOT - MEDICALLY DISQUALIFIED": "否,体检不合格", + "EVERY AUTOMATON IS UTTERLY DESTROYED.\"": "所有机器人才有可能实现和平。”", + "BREAKING NEWS: FIRST AUTOMATON FOOTAGE": "突发新闻:首获机器人影片", + "HEARTWARMING STORY": "暖心故事", + "GALACTIC FRINGE": "星系边缘", + "SEARCH FOR SURVIVORS ONGOING": "生还者搜索行动仍在进行中", + "HELLDIVERS REDIRECTED": "绝地潜兵重新调配", + "COUNTEROFFENSIVE AGAINST AUTOMATONS COMING": "反攻机器人行动即将开启", + "TCS SCIENTISTS UNDER INVESTIGATION": "TCS科学家正在接受调查", + "SICK CHILD'S WISH GRANTED": "病童愿望成真", + "PRESIDENT PROMISES RETRIBUTION": "总统承诺发动反击", + "Can't Ration My Love": "我的爱无法定量配给", + "HELLDIVERS PUSH TO SUPERCOLONY": "绝地潜兵攻向超级拓殖地", + "Dr. Freda Harber": "弗雷达·哈珀博士", + "VIOLATION PUNISHABLE BY DEATH OR WORSE": "违法者可处以死刑或更严厉的处罚", + "Helmets": "头盔", + "TCS FAILURE": "TCS的失败", + "LOOK OUT": "当心", + "Able-bodied Citizens": "健全的公民", + "Chemist": "化学家", + "\"CLOSE CALL\" AT DARK FLUID FACILITY": "暗液体设施发生“惊险”事件", + "CYBERSTAN": "生化斯坦", + "TCS SHOWS PROMISE": "TCS未来可期", + "AND HATING FREEDOM.\"": "暴力,以及憎恨自由。”", + "M.O.D. RELEASES VIDEO OF POSSIBLE ILLUMINATE VOID SHIP": "国防部公开疑似光能者虚空舰船的录像", + "Terminid Biologist": "终结族生物学家", + "MINISTRY OF SCIENCE REVEALS SWEEPING ARTIFICIAL INTELLIGENCE RESEARCH PLAN": "科学部公开人工智能全面研究计划", + "\"THIS ATTACK OCCURRED AS WE WERE NEARING A": "“此次袭击的发生时间正值我们", + "TERMINIDS OUT OF CONTROL": "终结族失控", + "AUTOMATON THREAT": "机器人危机", + "STROHMANN": "斯托曼", + "Dr. Egon Sonntag": "埃贡·松塔格博士", + "TERMINID": "终结族", + "\"PEACE IS NOT AN OPTION. THE AUTOMATONS": "“和平共存是不可能的。", + "[Stuff in the hospital scene, maybe]": "[疑似医院内物品的场景]", + "#VALUE SECOND": "#VALUE秒", + "#COUNT m/s": "#COUNT米/秒", + "#COUNTdB": "#COUNTdB", + "#X / #Y": "#X / #Y", + "#HOURSh #MINUTESm": "#HOURS小时#MINUTES分钟", + "#VALUE HOURS": "#VALUE小时", + "(#COUNT)": "(#COUNT)", + "#LEADIN #DAY #HOUR #MINUTE": "#LEADIN #DAY #HOUR #MINUTE", + "[#X/#Y]": "[#X/#Y]", + "#HOURS:#MINUTES:#SECONDS": "#HOURS:#MINUTES:#SECONDS", + "#COUNT s": "#COUNT秒", + "#MINUTES:#SECONDS": "#MINUTES:#SECONDS", + "#X/#Y": "#X/#Y", + "#HOUR_ZEROS#HOURSH #MINUTE_ZEROS#MINUTESM": "#HOUR_ZEROS#HOURS小时 #MINUTE_ZEROS#MINUTES分钟", + "T-#MINUTES:#SECONDS:#MILLI": "倒计时#MINUTES:#SECONDS:#MILLI", + "#VALUEmin": "#VALUE分钟", + "#SUBTITLE": "#SUBTITLE", + "'#TEXT'": "“#TEXT”", + "#VALUEd": "#VALUE天", + "#VALUE day": "#VALUE天", + "#MINUTE_ZEROS#MINUTESM #SECOND_ZEROS#SECONDSS": "#MINUTE_ZEROS#MINUTES分钟 #SECOND_ZEROS#SECONDS秒", + "#VALUE SECONDS": "#VALUE秒", + "#VALUE DAYS": "#VALUE天", + "#VALUE DAY": "#VALUE天", + "#MINUTES:#SECONDS:#MILLI": "#MINUTES:#SECONDS:#MILLI", + "#X - #Y": "#X - #Y", + ",": ",", + "#DAYSD": "#DAYS天", + "#VALUE Second": "#VALUE秒", + "?": "?", + "#COUNT mrad": "#COUNT毫弧度", + "#ZEROES#COUNT": "#ZEROES#COUNT", + "#VALUE HOURS": "#VALUE小时", + "#VALUE Hours": "#VALUE小时", + "T-": "倒计时", + "#VALUE DAYS": "#VALUE天", + "T-#SECONDS": "倒计时#SECONDS", + "#VALUE HOUR": "#VALUE小时", + "[#MINUTES:#SECONDS]": "[#MINUTES:#SECONDS]", + "#VALUE MINUTE": "#VALUE分钟", + "#VALUE HOUR": "#VALUE小时", + "#A (#PERCENT%)": "#A (#PERCENT%)", + "T- #DAYSd:#HOURS:#MINUTES:#SECONDS": "倒计时#DAYSd:#HOURS:#MINUTES:#SECONDS", + "#X #Y #Z": "#X #Y #Z", + "#A/#B (#PERCENT%)": "#A/#B (#PERCENT%)", + "#VALUE Seconds": "#VALUE秒", + "#VALUE SECONDS": "#VALUE秒", + "#LEADIN #DAY #HOUR #MINUTE #SECOND": "#LEADIN #DAY #HOUR #MINUTE #SECOND", + "#HOURSh #MINUTESm #SECONDSs": "#HOURS小时#MINUTES分钟#SECONDS秒", + "T- #HOURS:#MINUTES:#SECONDS": "倒计时#HOURS:#MINUTES:#SECONDS", + "#VALUE Days": "#VALUE天", + "#VALUE DAY": "#VALUE天", + "#COUNTs": "#COUNT秒", + "#VALUE Day": "#VALUE天", + "#VALUE Minutes": "#VALUE分钟", + "#DAY_ZEROS#DAYSD #HOUR_ZEROS#HOURSH": "#DAY_ZEROS#DAYS天 #HOUR_ZEROS#HOURS小时", + "#COUNT m": "#COUNT米", + "#X/#Y": "#X/#Y", + "#A • #B • #C": "#A • #B • #C", + "#VALUE MINUTES": "#VALUE分钟", + "#SPEAKER: #SUBTITLE": "#SPEAKER:#SUBTITLE", + "#VALUEh": "#VALUE小时", + "#VALUEs": "#VALUE秒", + "#MINUTESm #SECONDSs": "#MINUTES分钟#SECONDS秒", + "#VALUE Hour": "#VALUE小时", + "#X #Y": "#X #Y", + "#VALUE Minute": "#VALUE分钟", + "T - #SECONDS": "倒计时#SECONDS", + "#VALUE SECOND": "#VALUE秒", + "#LEADIN #DAY": "#LEADIN #DAY", + "#VALUE MINUTE": "#VALUE分钟", + "Option #NUMBER": "选项#NUMBER", + "#VALUE MINUTES": "#VALUE分钟", + "#A • #B": "#A • #B", + "#VALUE days": "#VALUE天", + "#PERCENT%": "#PERCENT%", + "SUPERIOR PACKING METHODOLOGY": "高级装填法", + "Heads Up Display (HUD) Curve": "HUD弧度", + "COMMUNICATION": "通信", + "EXPERIMENTAL INFUSION": "试验性注射剂", + "Decreases time to initiate deployment of Support Weapon Stratagems by removing dialog box confirming intent to fire.": "通过移除确认发射意图的对话框,缩短支援武器战略配备的部署启动时间。", + "Mature - Violence": "成人 - 暴力", + "Render Scale": "渲染比例", + "You have reached the approved generosity limit. Please wait #DAYS d #HOURS h before donating again.": "你已达到批准的捐赠上限。请在#DAYS天#HOURS小时后再尝试。", + "Offensive Language": "冒犯性言辞", + "Scientists without fear of implosion or spaghettification study negative energy here.": "无惧内爆与意大利面条化风险的科学家在这里研究负能量。", + "Adjusts the sensitivity of vertical camera movement relative to horizontal movement.": "调整视角垂直移动相对水平移动的灵敏度。", + "Crossplay": "跨平台游玩", + "While the Helldiver training program is undeniably infallible, you can always repeat your training from the game menu.": "绝地潜兵训练项目当然是完美无缺的,但是你随时可以在游戏菜单中再次参加训练。", + "COMPARE": "对比", + "Music Preview": "音乐预览", + "RADIAL MENU RIGHT": "圆盘菜单右", + "Amazing quality, I bought one for me and TWO for my kid. She loves them.": "质量超好。我不仅自己买了一件,还给我女儿买了两件。她爱不释手。", + "Invert Motion Sensor (Vertical)": "动态感测器翻转(垂直)", + "Acquisition data downlink from Super Earth has failed. Please check for Automaton interference and try again at a later time.": "源自超级地球的数据采集下链发生故障。请检查是否有机器人的干扰,并稍后重试。", + "Inverts left and right of Motion Sensor control direction.": "动态感测器左右方向翻转。", + "When in doubt, don't think—simply shout \"For Democracy!\" and charge head-first into your problems.": "困惑之时,不要思考——只需大喊 “为了民主!”,然后勇敢地冲锋陷阵。", + "This setting increases the amount of grass, rocks, etc that are scattered on the ground.": "该设置可提高散布在地面的草和岩石等元素的数量。", + "For more information on the Payment Services Act: https://pscom.jp/lgp": "-", + "ACTIVE FOR: #HOURS h #MINUTES m": "激活时长:#HOURS小时#MINUTES分", + "DSS CONSTRUCTION SITE - PHASE 3": "DSS建筑工地 - 第3阶段", + "Something went wrong while trying to add the currency to your account. Please contact our support team.": "尝试将货币添加到账号时出错。请联系我们的支持团队。", + "Rare Samples are only available on more challenging missions.": "稀有样本只能在挑战性较高的任务中获得。", + "HUD Edge Offset": "HUD边缘偏移", + "Caught on fire? Stims will heal you, but won't douse the flames. Instead: stop, drop, and roll!": "着火了?治疗剂可以治愈你的伤势,但无法扑灭火焰。不过,你可以立刻停下脚步,扑到地面翻滚起来!", + "The Ministry of Science has relocated its best and brightest here to study the interstellar spore cloud known as The Gloom.": "科学部将绝顶聪明的精英安排到这里研究名为“阴霾”的星际孢子云。", + "CUSTOMIZATION UNAVAILABLE": "自定义内容无法使用", + "INVERTED": "已翻转", + "Stealing Resources": "偷取资源", + "SETUP": "设置", + "Ultra Quality Plus": "超高画质+", + "Determines how you want to navigate the map screen.\n\nHybrid: Allows you to move and look around while the map is open. Additional controls are needed in order to navigate the map.\nSeparated: Allows you to only move while the map is open, relies on your look controls to navigate the map.": "决定你浏览地图窗口的方式。\n\n混合:可以在打开地图的同时移动和观察四周,需要使用其他按键拖动地图。\n独立:在打开地图的同时只能移动,需要通过视角的操控按键拖动地图。", + "If the enemies just keep coming, find out where they're coming from and unleash hell. Bug hive? Destroy! Bot factory? Destroy!": "如果敌人源源不断地涌来,那就找出它们的老巢,将其斩草除根。虫窝?毁掉!机器人工厂?毁掉!", + "March": "3月", + "HELLPOD SPACE OPTIMIZATION": "绝地喷射舱空间优化", + "HANGAR": "机库", + "ON SHIP": "在舰船上", + "STAMINA BOOST": "耐力提升", + "If you play one of our games, we will always access data from and / or store data on the device that you are using. This data is necessary to deliver our games, and includes:\n• Content Data: Game content data, such as video, audio, graphic, text, and game level information that is requested and downloaded for the game that you are accessing online. If you are playing an online game, this includes your online interactions as necessary to reflect those interactions on our game servers.\n• Account Data: Information required to sign you into your account for PlayStation™Network. \n• Configuration Data: Information about the configuration of your device and the game you are playing , such as the device date, time and language settings and your in-game preference and settings. \n• Security Data: Information necessary to detect and investigate malicious, unauthorized or fraudulent activity.\n• Legal Data: Information required by applicable law and to demonstrate compliance.\nIf you agree, we may collect more detailed information about how you interact with our games.\nThis may include when and how you use the game’s user interface, which parts of the game you visit, which weapons you use, which characters you interact with and any errors that you encounter.\nGame Data is usually sent to us and stored with one or more unique network, device and/or account identifiers.": "Wenn du eines unserer Spiele spielst, greifen wir immer auf Daten von dem Gerät zu, das du verwendest, und/oder speichern Daten auf diesem Gerät. Diese Daten sind für die Durchführung unserer Spiele erforderlich und umfassen:\n• Inhaltsdaten: Spiel-Inhaltsdaten, darunter Video-, Audio-, Grafik-, Text- und Level-Informationen, die für das Spiel, auf das du online zugreifst, angefordert und heruntergeladen werden. Wenn du ein Online-Spiel spielst, schließt dies deine Online-Interaktionen ein, die notwendig sind, um diese Interaktionen auf unseren Spielservern wiederzugeben.\n• Kontodaten: Informationen, die erforderlich sind, um dich bei deinem Konto für PlayStation™Network anzumelden. \n• Konfigurationsdaten: Informationen über die Konfiguration deines Geräts und des Spiels, das du gerade spielst, wie z. B. die Einstellungen für Datum, Uhrzeit und Sprache des Geräts sowie deine Präferenzen und Einstellungen im Spiel. \n• Sicherheitsdaten: Informationen, die erforderlich sind, um schädliche, unbefugte oder betrügerische Aktivitäten aufzudecken und zu untersuchen.\n• Rechtliche Daten: Informationen, die nach geltendem Recht und zum Nachweis der Einhaltung der Vorschriften erforderlich sind.\nWenn du zustimmst, können wir detailliertere Informationen darüber sammeln, wie du mit unseren Spielen interagierst.\nDazu kann gehören, wann und wie du die Benutzeroberfläche des Spiels verwendest, welche Teile des Spiels du besuchst, welche Waffen du benutzt, mit welchen Charakteren du interagierst und welche Fehler bei dir auftreten.\nDie Spieldaten werden in der Regel mit einer oder mehreren eindeutigen Netzwerk-, Geräte- und/oder Kontokennungen an uns gesendet und gespeichert.", + "Look Sensitivity Vertical Multiplier": "视角灵敏度垂直乘数", + "SHIP LOG": "舰船日志", + "ACCESSIBILITY": "协助工具", + "Select the screen device where the game will be displayed.": "选择用以显示本游戏的屏幕设备。", + "PAST CAMPAIGNS": "过往战役", + "There's no one right way to skin a bug. Experiment with different tactics and see what works!": "一千个人有一千种对付虫族的办法。尽情尝试不同的战术,看看效果如何!", + "#NAME - LEVEL #LEVEL": "#NAME - #LEVEL级", + "Modifies how far light from certain light sources reaches. Alters some materials and lighting features.": "更改部分光源的光线照射距离。更改部分材质和光照功能。", + "HelldiVR_91": "绝地深潜VR_91", + "Top-of-the-line accounting software automates payroll calculations, freeing up HR associates to lubricate support weapons in their spare time.": "顶级会计系统软件实现自动化薪金计算,让人力资源助理腾出空余时间为支援武器上油润滑。", + "Gives access to the Orbital 380mm HE Barrage stratagem during missions. Accelerates progress in Liberation Campaigns.": "执行任务时可使用轨道380mm高爆弹火力网战略配备。加快解放战役的进程。", + "Sentries take #VALUE% less damage from explosions.": "哨戒炮受到的爆炸伤害减少#VALUE%。", + "Vibration Strength": "震动强度", + "Provides hand carts which can carry multiple backpack stratagems from storage, decreasing both reload time and crew lumbar injuries.": "手推车可从库存中装载多个背包战略配备,缩短重新装弹的时间,还可以降低船员腰部受伤的几率。", + "TYPE": "种类", + "Reduces reload time for all support weapons by #VALUE%.": "所有支援武器的装填时间缩短#VALUE%。", + "Sentries rotate towards new targets more quickly.": "哨戒炮可更快地转向新目标。", + "Dismiss": "忽略", + "Camera Shake Strength": "视角摇晃强度", + "MUTED": "静音", + "The first manned site established in Gloom-infested space.": "首个在“阴霾”侵蚀星域建立的人类驻军据点。", + "Disrupting Gameplay": "破坏游戏体验", + "PixiePyxie555": "调皮妖精555", + "REQUIREMENT: #MODULE": "条件:#MODULE", + "NAME YOUR SUPER DESTROYER SHIP": "为你的超级驱逐舰命名", + "RESTART REQUIRED": "需要重启", + "Compass Width": "罗盘宽度", + "Mounts a modified AR-23 Liberator to all resupply pods, allowing them to double as automatic turrets.": "为所有重新补给舱搭载改良版AR-23“解放者”,可充当自动炮台。", + "SEND FRIEND REQUEST": "发送好友申请", + "#COUNT%": "#COUNT%", + "Controls the quality of the bloom filter. Affects GPU performance.": "控制全屏泛光过滤质量。影响GPU性能。", + "SHIP NAME": "舰船名称", + "MOVE RIGHT": "向右移动", + "BRAKE / REVERSE": "刹车/倒车", + "Voice Chat Transcription": "语音聊天转录", + "RepeatCustomer: Nice improvement on the previous identical model": "回头客:比上一代版本做得更好", + "Improves steering for Helldivers during Hellpod deployment.": "帮助绝地潜兵在部署绝地喷射舱时更好地把控转向。", + "EXPLODING SHRAPNEL": "高爆弹片", + "HEADER VISIBLE": "显示标题", + "Secondary Objective Visibility": "次要目标可视度", + "Difficulty 4-6": "难度4-6", + "DEFENSIVE STRATAGEM PERMIT": "防御型战略配备许可证", + "I've used this every day for the past few weeks!": "我已经用了几周,天天都用!", + "MORE INFO": "更多详情", + "January": "1月", + "OUTCOME": "结果", + "OPEN WEAPON WHEEL": "打开武器轮盘", + "Karen0057": "卡伦0057", + "#PERCENTAGE% of Votes": "得票率:#PERCENTAGE%", + "Injury Widget Visibility": "伤势轮盘可视度", + "DISCREET": "简洁", + "Mission Info Position": "任务信息位置", + "CONCERNING NUMBER OF MONOLITHS": "巨石数量令人担忧", + "Parts for the Democracy Space Station are prefabricated all over the Galaxy, then shipped here to await assembly.": "民主空间站(DSS)的部件在星系各地完成预制,然后运往这里等待组装。", + "SUMMARY": "总结", + "Real_NovaStarz": "真_新星", + "Deadzone": "盲区", + "SHIFT UP": "升档", + "Key": "键", + "Select level of detail of shadows, as well as the amount of lights that cast.": "选择阴影细节层次,以及投射的光照数量。", + "ACCEPT": "接受", + "UAV RECON SUPPORT": "UAV侦察支援", + "RECENT PLAYERS": "近期玩家", + "TLdyHero": "乱室英雄", + "Enables automatic climbing and vaulting while the Helldiver is sprinting.": "在绝地潜兵冲刺时,开启自动攀爬或翻越的动作。", + "WHAT DO THE GAME SETTINGS CONTROL?": "游戏设置可以控制什么?", + "SHIFT DOWN": "降档", + "SPECIAL STRATAGEM PERMIT": "特殊战略配备许可证", + "LOOK RIGHT": "向右看", + "New Difficulty Level": "新难度", + "TOGGLE MICROPHONE": "切换麦克风", + "GLOOM BASE BRAVO": "“阴霾”布拉沃基地", + "STAMINA REGEN": "耐力恢复", + "You have reached the approved generosity limit. Please wait #MINUTES m #SECONDS s before donating again.": "你已达到批准的捐赠上限。请在#MINUTES分#SECONDS秒后再尝试。", + "ACCELERATE": "加速", + "Not Enough Data To Estimate": "数据不足,无法估算", + "Democracy Space Station construction is well underway. The local economy is flourishing as the planet’s populace has centupled, and all the Galaxy can feel their democratic fervor.": "民主空间站(DSS)的建设进展顺利。随着该星球的人口增长,经济也飞速蓬勃发展起来,全星系都能感受到他们的民主热情。", + "Increases minimap enemy ping radius by #VALUE%.": "小地图上标记敌人的半径范围扩大#VALUE%。", + "Commend your squadmates on a job well done. We're all on the right side of history!": "多多称赞队友的出色表现。我们都走在历史的康庄大道上!", + "Deploys periodic Eagle Airstrikes during missions. Slows enemy progress in Defense Campaigns.": "在任务中部署周期性“飞鹰”空袭。减缓敌人在保卫战役中的进展。", + "DEFENSE HELD BY DSS": "DSS守住防线", + "X+ AXIS": "X+轴", + "Use adaptive controller stick ranges.": "使用自适应游戏控制器摇杆范围。", + "COPY FRIEND CODE": "复制好友代码", + "After years of research into improving the Super Destroyer's firepower, the Ministry of Science concluded that the most effective method was adding more guns.": "经过多年对超级驱逐舰火力改进的研究,科学部得出结论,最有效的方法是增加枪炮数量。", + "Enemy Indicator Visibility": "敌人指示可视度", + "DEMOCRACY SPACE STATION": "民主空间站", + "UAV RECON BOOSTER": "UAV侦察强化资源", + "Inverts up and down of camera direction in First Person View (FPV).": "在第一人称视角(FPV)下,视角上下方向翻转。", + "Toggles the outline on your aiming reticle on or off, for greater visibility.": "显示或隐藏准星轮廓,更好地调整可视度。", + "ON": "开", + "ACTIONS": "行动", + "PLATFORM": "平台", + "INCREASED REINFORCEMENT BUDGET": "提高增援预算", + "Most weapons have different fire modes or functions—hold Reload to access them.": "大多数武器都设有不同的开火模式或功能,按住装填弹药键可切换模式或功能。", + "Requisition": "申购点", + "A significant SEAF military outpost is present on this planet.": "此星球上坐落着超级地球武装部队的重要军事哨站。", + "Rude, Vulgar Language": "语言粗鲁、粗俗", + "Gear": "装备", + "Super Earth has many holidays, but the most important is October 26th—Liberty Day!": "在超级地球的众多节日当中,最重要的当属10月26日——解放日!", + "Super Earth recommends spending at least 2.4 seconds per mission enjoying the scenery. A happy Helldiver is a deadly Helldiver.": "超级地球建议你每次执行任务时,至少花2.4秒欣赏景色。心情舒畅的绝地潜兵会变得更加强大。", + "AUDIO": "声音", + "PRONE": "趴下", + "UNLINKING": "正在解除绑定", + "TRIGGER TYPE": "触发方式", + "You can change and customize these settings at any time during gameplay.": "你可以在游戏期间随时更改或自定义这些设置。", + "Spam": "滥发消息", + "HIGH-QUALITY LUBRICANT": "优质润滑剂", + "Dead Sprint": "死亡冲刺", + "Select the angle range of the compass.": "选择罗盘的角度范围。", + "PURCHASE ERROR": "购买出错", + "STRATAGEM PERMIT": "战略配备许可证", + "Advertising": "广告", + "Okane_82": "冈根_82", + "Window Notifications": "窗口通知", + "Adjust the overall brightness of the game.": "调整游戏的总体亮度。", + "Map Navigation Mode": "地图浏览模式", + "REQUISITION": "申购点", + "DISPLAY": "显示", + "Modifies the resolution of the space backdrop when on missions. Primarily affects stars.": "更改执行任务时的太空背景的分辨率,主要会影响太空里的行星。", + "Collect medals to progress your Warbond. No rush though—Warbonds can be completed at any time.": "收集奖章,推进战争债券的进度。但是不用着急,你随时可以完成战争债券进度。", + "Account Link": "账户绑定", + "SQUADS IN MISSION": "正在执行任务的小队", + "Include the last #COUNT message(s) from the text chat.": "附上文字聊天的最近#COUNT条消息。", + "SWITCH SEAT (NEXT)": "切换座位(下一个)", + "#BOOSTER is active during missions.": "任务期间,#BOOSTER已激活。", + "REPORT PLAYER": "举报玩家", + "Specctrei": "幽灵子", + "Estimated time until ready: #HOURS h #MINUTES m": "预计准备时间:#HOURS时#MINUTES分", + "LOW FUNDS": "资金不足", + "LOWEST": "最低", + "Auto-Climb during Sprint": "冲刺时自动攀爬", + "A player cannot be reported for this action. You can take any of the following actions instead.": "无法以此行为为由举报玩家,你可以另行选择下列操作。", + "DOWNLINK FAILED": "下链出错", + "QUICK WEAPON WHEEL LEFT": "快速向左转动武器轮盘", + "Adjusts the sensitivity of camera movement.": "调整视角移动的灵敏度。", + "Audio Device": "音频设备", + "Triggers as soon as a button is pushed down.": "只要按下按键就立即触发操作。", + "STRATAGEM": "战略配备", + "August": "8月", + "GLOBAL": "全局应用", + "ZERO-G BREECH LOADING": "零重力后膛装弹", + "Mortar Sentries prioritize fire at marked targets.": "迫击哨戒炮优先射击标记的目标。", + "CLASS 1 EXOSTORM": "1级异界风暴", + "-": "-", + "Vehicle Info Visibility": "载具信息可视度", + "VOICE 2": "声音 2", + "The Automatons store large amounts of encrypted information here.": "机器人将大量加密信息储存在这里。", + "CIRCUIT EXPANSION": "扩建电路", + "Enables closed captions, which provides text descriptions of sounds other than dialogue.": "启用隐藏式字幕,以文字形式描述对话以外的声音。", + "NEXT UPGRADE:": "下一次升级:", + "CROUCH": "蹲下", + "ADMIN": "管理员", + "HIGH": "高", + "WEAPON WHEEL LEFT": "向左转动武器轮盘", + "COMMUNICATIONS ARRAY": "通信阵列", + "Select when an on-screen option will be shown. Default behavior is to only display the on-screen keyboard if a keyboard was not used to enter the text input state.": "选择何时显示屏幕选项。默认是仅在未使用键盘输入文本时才显示屏幕键盘。", + "This will unlink your accounts.\nAre you sure you want to continue?": "此操作将解绑账号。\n确定要继续吗?", + "PUBLIC": "公开", + "GLOOM BASE ALPHA": "“阴霾”阿尔法基地", + "EMOTE OPTION B": "表情B", + "简体中文": "简体中文", + "Excellent quality! Resistent even against the most gross bug goo.": "质量超棒!再恶心的毒虫黏液也不怕了。", + "Select the visibility of player markers during gameplay.": "选择游戏过程中的玩家标记可视度。", + "Muscle Enhancement": "肌肉强化", + "Something went wrong while attempting to establish the connection to PlayStation™Network. Error codes:": "尝试与PlayStation™Network建立连接时出现问题。错误代码:", + "CURRENTLY UNAVAILABLE": "目前无法使用", + "CANCEL SQUAD INVITE": "取消小队邀请", + "Managed Democracy is a cornerstone of advanced civilization.": "管理式民主是先进文明的支柱。", + "Body Type": "体型", + "Mature - Drugs": "成人 - 毒品", + "DirectX 12": "DirectX 12", + "CHANGE EQUIPMENT (LONG)": "更换装备(长)", + "Feb": "2月", + "CURRENT LOCATION": "当前地点", + "Use Raw Mouse Input": "使用原始鼠标输入", + "BLOCK": "屏蔽", + "Sales of Super Credits are disabled because the Steam Overlay is disabled. Please enable the Steam Overlay in your Steam settings. If this error persists after enabling the overlay and restarting the game, please refer to Steam support for assistance.": "由于尚未开启Steam界面,你无法购买超级货币。请在你的Steam设置中开启Steam界面。如果启用界面并重启游戏后,问题仍未解决,请联系Steam客服寻求帮助。", + "Account link is active.": "账号绑定已开启。", + "Kill bugs before they get close. Remember, nothing protects your personal space better than bullets.": "要在虫族靠近之前将其击杀。要记住,子弹最能保护你的个人空间。", + "REASON": "理由", + "PRIMARY OBJECTIVE": "主要目标", + "Motion Sensor Sensitivity": "动态感测器启用模式", + "ORBITAL CANNONS": "轨道加农炮", + "Select the visibility of mission information.": "选择任务信息的可视度。", + "Asking for Personal Information": "询问个人信息", + "AIM": "瞄准", + "EXOSUIT": "外骨骼装甲", + "Select level of quality of reflections. Most noticeable on glossy surfaces. The high setting enables Screen Space Reflections, which improves the appearance of shiny surfaces.": "选择反射质量的等级。效果常见于光滑表面。设置为高等级将启用屏幕空间反射,优化光亮表面的显示效果。", + "No recent players, yet.": "暂时还没有近期玩家。", + "]": "]", + "PURCHASE FAILED": "购买失败", + "SUPER GLOOM BASE ALPHA": "超级“阴霾”阿尔法基地", + "Adjusts how much acceleration is applied to the controller camera control. Higher values mean much higher sensitivity when the sticks are at max range.": "调整游戏控制器操控视角的加速数值。上调数值可提高操作杆在极限位置时的灵敏度。", + "TURN SIGNAL RIGHT": "右转向灯", + "750 SC": "750超级货币", + "BUYING ITEM": "正在购买物品", + "GENERATE": "显示", + "FSR3": "FSR3", + "The former site of the Deep Mantle Forge Complex, stolen by the Automatons and destroyed.": "深部地幔铸造复合体遗址,被机器人窃取并摧毁。", + "TOGGLE HEADLIGHTS": "切换大灯", + "ON-SCREEN ONLY": "仅显示游戏指示文字", + "DATA OPT-IN": "同意使用的数据", + "The Game Data settings allow you to control what Game Data we access and store from this device. \n\nYou can change your settings at any time.": "你可以通过游戏数据的设置控制我们从本设备访问和存储的游戏数据。\n\n你可以随时更改设置。", + "Tooltip Visibility": "提示信息可视度", + "Weapon Function Visibility": "武器功能可视度", + "Knittingiscool111": "编织好酷111", + "The speed at which the cursor movement increases as the controller is moved.": "光标随游戏控制器移动的加速度。", + "AMD Anti-Lag 2 tries to reduce the system latency and increases responsiveness.": "AMD Anti-Lag 2旨在降低系统延迟并提升响应速度。", + "Scales the distance and screen sizes at which objects are drawn. Reducing this improves CPU performance.": "调整绘制物体的距离和屏幕尺寸。下调该数值可以改善CPU性能。", + "CENTER OF SCIENCE (DESTROYED)": "科学中心(遗址)", + "Choose your loadout carefully to ensure your squad has all the resources it needs. Democracy depends on it!": "谨慎选择武装配置,确保小队具备所有必要资源。这是捍卫民主的基石!", + "CUSTOM": "自定义", + "Select the default audio language spoken by characters.": "选择角色音频的默认语言。", + "PERFORMANCE": "性能", + "Helldivers come out of the Hellpod fully stocked on Ammo, Grenades and Stims.": "绝地潜兵携带充足的弹药、榴弹和治疗剂补给走出绝地喷射舱。", + "Select the default language for the text that appears in menus, subtitles and captions.": "选择菜单、字幕和隐藏式字幕的默认语言。", + "PREVIOUS ARC": "上一段剧情", + "Specifies the maximum framerate.": "限定最高帧率。", + "Stratagem Visibility": "战略配备可视度", + "If enabled, Helldivers II will utilize data collected from your account to improve player experience.": "启用时, 《HELLDIVERS™ 2》将使用从你账户中收集的数据来改善玩家的游戏体验。", + "Trims excess leg space in the cockpit, allowing the Eagle to carry additional payloads.": "削减驾驶舱内多余的腿部空间,增加“飞鹰”的有效载荷。", + "RADIAL MENU RELATIVE SELECTION": "圆盘菜单相对选取", + "Failed to accept friend request.": "未能接受好友申请。", + "The number of frame buffers to use. Lower values yield more responsive input, while higher values yield smoother frame rates.": "要使用的帧缓冲数值。数值越小,输入响应越快,数值越大,帧率越平稳。", + "SUOMALAINEN (Unsupported)": "SUOMALAINEN (Unsupported)", + "Screen-Space Global Illumination": "屏幕空间全局光照", + "Select the default language for text and audio.": "选择文本和音频的默认语言。", + "This setting modifies the fidelity of the terrain. The lowest setting disables faded transitions between some objects and the terrain.": "该设置可调整地形的逼真度。设为最低将禁用部分物体与地形之间的渐变过渡。", + "Difficulty 10+": "难度10+", + "Select the visibility of interaction prompts during gameplay.": "选择游戏过程中的互动提示可视度。", + "CLOSE": "关闭", + "No friend lobbies found": "未找到好友大厅", + "QUICK STIM": "快速使用治疗剂", + "A mine extracting platinum from deep-seated deposits of igneous rock.": "从深层火成岩中开采铂金的矿井。", + "NEXT EVENT": "下一战事", + "INPUT TYPE": "输入类型", + "BONUS SUPER CREDITS": "额外超级货币", + "#VALUE-second reduction in call-in time for all Orbital stratagems.": "所有轨道武器战略配备呼叫时间缩短#VALUE秒。", + "Remember that armored enemies require heavy weapons. Bring the appropriate equipment for your selected difficulty.": "记住,对付装备护甲的敌人要用重型武器。根据选定的难度挑选合适的装备。", + "Select the visibility of sample count during gameplay.": "选择游戏过程中的样本数量可视度。", + "NEXT ARC": "下一段剧情", + "Allows all Helldivers to recover faster after being slowed by an attack, such as acid. Does not mitigate \"area effects,\" such as EMS strikes.": "加快所有绝地潜兵在因遭受攻击(如腐蚀酸)而减速后的恢复速度。无法减轻“范围效果”的影响,如电磁冲击波攻击。", + "Braking when still will shift the vehicle into reverse.": "静止时刹车,载具将进入倒车状态。", + "DATA CENTER": "数据中心", + "The top-secret site where augmentations to the DSS are constructed.": "DSS强化设施的绝密搭建地点。", + "Compass Angle Range": "罗盘角度范围", + "This will unbind another action. Continue?": "该操作将取消另一项动作的键位绑定。是否要继续?", + "WIDE": "宽", + "VISUALS": "图像", + "Lightning arcs, fired from weapons and turrets, jump to one additional enemy.": "从武器和炮塔发射的闪电弧可额外跳到一名敌人身上。", + "Select the visibility of hints during gameplay.": "选择游戏过程中的游戏提示可视度。", + "Too many requests coming in. Please wait a moment. Error codes:": "请求过多,请稍等片刻。错误代码:", + "I'm [redacted] and this is my favorite product in the acquisition center!": "我是[已编辑]。这是采购中心里我最喜欢的产品!", + "Compass Small Notches": "罗盘小刻度", + "The best thing I've bought since my Combat Knife!": "少有的优质产品,仅次于我上次买的格斗匕首!", + "Quality Profile": "画质设置", + "E-710 FARMS": "710元素农场", + "CANCEL FRIEND REQUEST": "取消好友申请", + "DONATE RESOURCES": "捐赠资源", + "COMMEND": "称赞", + "GO TO LOADOUT": "前往武装配置界面", + "TYRANNY PARK 2": "第二代暴政公园", + "Adjusts the sensitivity of touch pad inputs for map movement.": "调整地图移动的触摸板输入灵敏度。", + "LINKING": "正在绑定", + "MOVE DOWN": "向下移动", + "Increases the time between enemy encounters.": "延长敌人遭遇战之间的时间间隔。", + "You do not have enough funds to make this donation.": "你的资源不足,无法完成这次捐赠。", + "HEADPHONES": "耳机", + "Defense Campaigns cannot originate from this planet. The #BOOSTER Booster is automatically active for all missions.": "此星球无法发起保卫战役。#BOOSTER强化资源在全部任务中自动激活。", + "SUBTITLES": "字幕", + "Lighting Quality": "光照质量", + "DESCRIPTION": "描述", + "DSS crews maintain deployment of a 24-hour rotating fleet of Eagle Fighters from the massive three-tiered Convocation Bay, supporting all Helldiver operations on the planet with close air support and halting enemy offensives for a short time.": "民主空间站的工作人员在大型三层结构集结湾部署了一支“飞鹰”驾驶员舰队,采取24小时轮班制,为绝地潜兵在星球上的行动提供近距离空中支援,短暂阻止敌人进攻。", + "Don't forget to take breaks!\n…\nThat is, if you want to be remembered as a coward.": "注意休息!\n…\n前提是你想被当作懦夫的话。", + "EMOTE / VICTORY POSE": "表情 / 胜利姿势", + "Impersonating a Representative": "冒充代表", + "PUSH-TO-TALK": "按键说话", + "This setting determines what resolution the game will render at, before scaling it to your selected display resolution. Decreasing this value may improve performance while increasing it will improve visual quality.": "该设置将决定了游戏在等比缩放至你选中的显示分辨率之前将以多高分辨率完成渲染。降低该数值或许可以改善性能,而增加该数值将提高画质。", + "WHAT IS GAME DATA?": "游戏数据是指什么数据?", + "Voice Chat Volume": "语音聊天音量", + "ACTIVE FOR: #DAYS d #HOURS h": "激活时长:#DAYS天#HOURS小时", + "Variable Rate Shading": "可变速率着色", + "Helldivers traveling the galaxy might come across ancient ruins and other curiosities. Just remember: Only a traitor is curious about alien artifacts!": "遨游银河的绝地潜兵可能会遇见古代遗迹或其他奇特物品。记住:只有叛徒才会对外星古物好奇!", + "Reverse Gear Inverts Throttle": "倒挡反转油门", + "STAMINA ENHANCEMENT": "耐力强化", + "LVL #LEVEL": "#LEVEL级", + "Bronko_P4triot": "我心向国_布兰科", + "You have been temporarily suspended.": "你已暂时被封禁。", + "Don't panic.": "不要惊慌失措。", + "INCOMING ONLY": "仅输入", + "PANDORA BASE": "潘多拉基地", + "BUY ITEM": "购买物品", + "Performance Monitor": "性能监视器", + "FLEXIBLE REINFORCEMENT BUDGET": "灵活增援预算", + "ADD TO FAVORITES": "收藏", + "The amount of stablization applied to the aim cursor in order to compensate for small unintentional movements.": "用以抵消瞄准光标小幅意外移动的稳定量。", + "Freedom isn't free, but this lets you dispense it with glee!": "自由不是免费的,但是花在这上面感觉很值!", + "OUTPOST ALPHA II": "二级阿尔法哨站", + "Cast your vote to influence where the DSS will be stationed during its next cycle.\n\nDonate resources to activate the Station's Tactical Actions: powerful abilities that can dramatically alter the fight for a planet's freedom. Only one Tactical Action can be active at a time.": "投票决定民主空间站在下一周期的停靠地点。\n\n捐赠资源以激活空间站的战术行动:可扭转星球自由之战局势的强大力量。每次只能激活一场战术行动。", + "DEFAULT": "默认", + "PLAYER": "玩家", + "Something went wrong while trying to add the currency to your account. We will retry in a few seconds.": "尝试将货币添加到账号时出错。我们将在几秒后重试。", + "WarwLzard66": "战争诬师66", + "GAMEPLAY": "游戏", + "EMOTE OPTION A": "表情A", + "If enabled, surveys will be occasionally displayed.": "如果开启此功能,系统将偶尔显示问卷调查。", + "Start Searching": "开始搜索", + "WEAPON FUNCTION 1": "武器功能1", + "ENGINEERING": "工程", + "Emote": "表情", + "TURN SIGNAL LEFT": "左转向灯", + "Motivational Shocks": "激励性冲击", + "The Ministry of Expansion tirelessly works to expand the reach of Freedom and secures vital resources for our society to thrive.": "扩张部在不眠不休地设法扩张解放大业的势力,为我们的社会获取繁荣发展的必要资源。", + "Don't go it alone—join a squad in order to unleash maximum liberation!": "不要孤军奋战——加入小队,助敌人实现最大限度的解放!", + "Vertical Field of View": "垂直视野", + "Mouse Sensitivity": "鼠标灵敏度", + "PATRIOTIC ADMINISTRATION CENTER": "爱国行政中心", + "Practice your daily desensitization exercises to ensure you remain unfazed by enemy atrocities.": "每天进行脱敏训练,确保你能冷静面对敌人的暴行。", + "GREAT EXPEDITIONARY FLEET YARD": "远征舰队港", + "Perfect for a true patriot of Super Earth!": "真正的超级地球爱国者绝配之选!", + "Automatons": "机器人", + "TOGGLE HUD": "切换HUD", + "The former site of the Center of Science. Once a beacon of technology, it now lies in ruins following a violent Terminid assault.": "科学中心遗址。曾经的科技灯塔,在一次终结族的猛烈进攻下沦为废墟。", + "Enabling this setting makes bright surfaces glow.": "启用该设置可令明亮的表面发光。", + "Failed to remove friend request.": "无法删除好友请求。", + "HELLDIVER TRAINING FACILITIES": "绝地潜兵训练基地", + "DETAILS": "详情", + "Armed Resupply Pods": "武装重新补给舱", + "RADIAL MENU DOWN": "圆盘菜单下", + "PUSH-TO-MUTE": "按键静音", + "Weapon Switch Mode": "武器切换模式", + "Legal": "法律条款", + "Grants subscription to data stream of live weather conditions, allowing for increased accuracy in orbital targeting.": "可订阅实时天气状况的数据流,提高轨道目标定位的准确性。", + "Select the visibility of the info feed during gameplay.": "选择游戏过程中的动态信息可视度。", + "Harrassment or Hate Speech": "骚扰或仇恨言论", + "Reinforces sentries with expanded polystyrene pieces (peanut-shaped variety), which absorb thermal and blast energy.": "利用可吸收热量和爆炸能量的膨胀聚苯乙烯片(形如花生)强化哨戒炮。", + "OFFENSIVE STRATAGEM PERMIT": "进攻型战略配备许可证", + "TANK": "坦克", + "DISABLE CROSSPLAY": "关闭跨平台游玩", + "Armor isn't just for looks—heavier armor makes you more resilient to attacks but slows you down and affects your stamina.": "盔甲不只是美观而已——盔甲越重,你的抗击能力越强,但是你的速度会相应变慢,耐力也会受到影响。", + "WARBOND MEDAL": "战争债券奖章", + "Invert Mouse (Horizontal)": "鼠标翻转(水平)", + "Sharpness": "锐度", + "Construction of the Democracy Space Station is nearing completion. This project, which has employed millions, will soon take its place among the greatest achievements of Democracy.": "民主空间站(DSS)将近完工。这个数百万人参与建设的项目将是民主伟业最伟大的成就之一。", + "Select the visibility of teammate status during gameplay.": "选择游戏中的队友状态可视度。", + "Volumetric Fog Quality": "体积雾质量", + "The Democracy Space Station is a strategic tool that gives Helldivers more power in the Galactic War.": "民主空间站是在星系战争中赋予绝地潜兵更大力量的战略利器。", + "GO TO LINK": "前往绑定", + "Large enemies now have a small chance of dropping Samples on death. Capped at #VALUE drops per mission.": "大型敌人死亡时有小概率掉落样本。每次任务最多掉落#VALUE。", + "Increases the damage radius on explosions caused by orbital Stratagems by #VALUE%.": "轨道战略配备引爆时的伤害半径扩大#VALUE%。", + "Reflection Quality": "反射质量", + "CONFIRM VOTE": "确认投票", + "May": "5月", + "MOVE LEFT": "向左移动", + "HOLD TO BUY ITEM": "按住购买物品", + "ADVANCED CREW TRAINING": "高级船员训练", + "Help us build the best Helldivers 2 experience!\nWhen you play this game, Sony Interactive Entertainment collects data that is necessary to operate the game. \nIf you agree, Sony Interactive Entertainment may also collect data about your interaction with the game and errors that occur. This data will be used as explained in our privacy policy. \nYou can change this setting at any time to allow full or limited data collection.": "协助我们打造最佳的《Helldivers 2》游戏体验!\n在您游玩本游戏时,索尼互动娱乐会收集本游戏运行所需的必要数据。\n如果您同意,索尼互动娱乐可能还会收集其他数据,以便了解您与游戏互动的方式以及期间发生的错误。这些数据的使用方式皆遵守我们的隐私政策。\n您可以随时更改该设置,选择提供全部或部分数据。", + "Invert Look (Horizontal)": "视角翻转(水平)", + "Upgrades Helldiver uniforms with form-fitting, automated, rapid-response fire suppression systems. Significantly reduces the time it takes for a burning Helldiver to naturally extinguish flames without the need to conduct rapid ground-aided smothering maneuvers.": "为绝地潜兵制服升级贴合体型的自动快速反应灭火系统。显著缩短炽灼小队绝地潜兵自然熄灭火焰时间,无需通过在地面上快速打滚来执行灭火动作。", + "If enabled, tapping the aim button will put you in/out of first person view.\n\nThis only works while the aim trigger type is set to Hold and when not using a controller.": "启用之后,轻按瞄准键可以进入/离开第一人称视角。\n\n前提是瞄准触发方式设为“按住”,且没有使用控制器。", + "Choose which device to use as your microphone.": "选择用作麦克风的设备。", + "The Ministry of Unity ensures that all of mankind is united as one by protecting us from internal threats, such as deviant behavior and expression of dangerous ideas.": "团结部负责保护我们免受内部威胁,例如反常行为以及表达危险思想,继而确保所有人类团结一致。", + "If enabled, the system tray icon will flash to notify you of important in-game developments, such as players joining your session or a game being found through matchmaking. This will mostly be noticeable when the game window is not in focus or active.": "启用后,如果游戏窗口在后台运行或不是当前活跃窗口,系统托盘图标会在游戏内发生重要事件时闪烁提醒,例如有玩家加入游戏或是匹配成功。", + "Voice Pack": "语音包", + "The size of the area where the right stick and left stick input is not registered.": "左摇杆和右摇杆输入的区域大小无效。", + "TRAINING MANUAL TIPS": "训练手册提示", + "LOCALIZATION CONFUSION": "定位混淆", + "Master Volume": "主音量", + "Enabling this setting approximates bounce lighting from nearby objects. Disabling may slightly improve GPU performance.": "启用该设置可概略估算附近物体的反射光。禁用设置或许可以略微改善GPU性能。", + "CHANGE EQUIPMENT (SHORT)": "更换装备(短)", + "An experimental lab has been constructed on this planet to synthesize Dark Fluid from E-711.": "实验室已经在此星球上建造,用以合成来自711元素的暗液体。", + "SPECTATE NEXT": "观战下一个玩家", + "#NAME has invited you to their squad.": "#NAME邀请你加入他们的队伍。", + "Lines Sentry pods with shock-absorbing hydrogel, allowing extra ammunition to be packed in the space previously occupied by shock-absorbing springs.": "在哨戒炮的弹药筒内涂抹减震水凝胶,即可在减震弹簧原本占用的空间内装入更多弹药。", + "SHUTTLE REPAIR BAYS": "运输船维修坞", + "Check your ship's TV for news on the war, combat tips, and advertisements for the hottest products in the galaxy.": "观看舰船的电视,可以掌握战争的最新动态,了解战斗技巧,以及观赏星系人气产品的广告。", + "Don't worry—stims have zero addictive properties!*\n*Study paid for by Permacura. Permacura: put your life in our hands.": "不必担心,治疗剂不具备成瘾性!*\n*佩玛丘拉资助研究。佩玛丘拉:放心把生命托付给我们。", + "Eagle stratagems that drop multiple bombs will drop #VALUE additional bomb(s).": "具备投掷多枚炸弹功能的“飞鹰”战略配备可额外投掷#VALUE枚炸弹。", + "You are not authorized to access the Acquisition Center until you've completed your first mission.": "你必须完成首次任务才能前往采购中心。", + "VOICE PACK": "语音包", + "Failed to unblock player.": "无法对玩家解除屏蔽。", + "Screen-Space Ambient Occlusion": "屏幕空间环境光遮蔽", + "Failed to send friend request.": "未能发送好友申请。", + "Speech Language": "音频语言", + "HIDE": "隐藏", + "This item is temporarily disabled": "这件商品被暂时禁用", + "Unable to initialize the purchase, please try again later or contact support if this error persists.": "无法开始购买,请稍后重试。如果问题仍未解决,请联系客服。", + "The volume of text to speech.": "文字转语音时的音量。", + "For budgetary reasons, Hellbombs require manual arming. But don't stick around unless you're looking for a spot on the wall of martyrs.": "由于预算原因,地狱火炸弹需要手动瞄准。但是千万别愣在原地,除非你想在英烈墙上抢个位置。", + "XXL WEAPONS BAY": "XXL号武器舱", + "ADJUST PRIVACY SETTING": "调整隐私设置", + "You do not have access to ship management yet. Complete missions and collect resources to upgrade the Destroyer.": "你现在还不能进行舰船管理。请先完成任务并收集资源来升级驱逐舰。", + "Strive_to_Dive_16": "使劲_俯冲_16", + "Mar": "3月", + "VOICE 1": "声音 1", + "Adjusts the brightness of the UI on HDR monitors.": "调整HDR显示器上的UI亮度。", + "The Democracy Space Station is currently unavailable.": "民主空间站目前无法使用。", + "SHOCK ABSORPTION GEL": "减震凝胶", + "Acceleration Speed": "加速度", + "This input is bound to another action. Proceeding will bind several actions to the same input. Continue?": "该输入键已与其他操作绑定。如果继续,则会将多个操作绑定至同一输入键。是否继续?", + "SUPPLY STRATAGEM PERMIT": "补给型战略配备许可证", + "Do you want to keep these display settings?": "要保留这些显示设置吗?", + "NEDERLANDS (Unsupported)": "NEDERLANDS (Unsupported)", + "MOVE UP": "向上移动", + "DSS CONSTRUCTION SITE - PHASE 1": "DSS建筑工地 - 第1阶段", + "Enable account linking to get started.": "启用账号绑定即可开始。", + "Select the visibility of the player's health status during gameplay.": "选择游戏过程中的玩家生命值状态可视度。", + "VIEW": "查看", + "THROWABLE": "投掷武器", + "CONTROLS": "控制项", + "SPRINT": "冲刺", + "EXIT": "退出", + "Your account has been suspended for breaching the terms of service.\nFor more information about account suspensions, visit\nhttps://www.playstation.com/support/account/suspensions-psn/": "你的账号因违反服务条款而被封禁。\n有关账号封禁的更多信息,请访问https://www.playstation.com/support/account/suspensions-psn/", + "Motion Sensor Steadying Threshold": "动态感测器稳定阈值", + "Fires periodic Orbital Barrages during missions. Accelerates progress in Liberation Campaigns.": "在任务期间定期发射轨道火力网。加快解放战役的进程。", + "Replaces the current method of loading cannons—manual shell insertion down the front of the barrel—with rear loading, which is much faster.": "更替目前的装弹方式,用更迅速的枪管后部装弹方式取代目前在枪管前部手动装弹的方式。", + "TOGGLE MENU": "切换界面", + "This setting modifies the resolution of the volumetric fog to create clearer light shafts. Lower settings remove some light influence.": "该设置可调整体积雾的分辨率,进而创造出更清晰的光束。较低的设置值将消除部分光照的影响。", + "Adjust the field of view to allow a wider view around the player.": "调整视野,允许玩家拓宽视野。", + "Anti-Aliasing": "抗锯齿", + "Every citizen is equally important to the war effort, but Helldivers are the most important.": "对于战争而言,每一位公民的贡献都是同样重要的,但是绝地潜兵最为重要。", + "Team Killing": "击杀队友", + "JUMP PACK": "喷射背包", + "Super Earth's ancient enemy, the Illuminate, have returned to menace our peaceful colonies. Our innocent colonists are being abducted, and turned into the mindless monstrosities known as the Voteless. What the Illuminate want, we do not know—but they must be stopped.": "超级地球的宿敌“光能者”卷土重来,威胁到我们拓殖地的和平。无辜的拓殖地居民遭到掳掠,被转变为名叫“无票者”的无脑怪物。虽然我们不清楚光能者的意图,但必须立即阻止它们。", + "Trains pit crew members to employ situational protocol adaptations, such as leaving unused ammo loaded instead of replacing it.": "训练维修组成员,让他们采用情景协议调整机制,例如保留已上膛但尚未使用的弹药,不进行替换。", + "CALL-IN TIME": "呼叫时间", + "Some systems may see a performance boost from using async compute while others may experience reduced performance. This setting does not affect visual quality.": "使用异步计算可能会提高某些系统的性能,而其他系统的性能则可能会降低。此设置不影响视觉质量。", + "CHARACTER": "角色", + "Other": "其他", + "INTER-GALACTIC NETWORK NODE": "星际网络节点", + "The Ministry of Truth is responsible for keeping all citizens well-informed and mentally equipped to withstand our enemies' vile propaganda.": "真理部负责为所有公民提供最新动态,武装公民的头脑,抵挡敌人居心不良的宣传攻势。", + "Jump-starts Hellpod firing with an immediate TNT detonation at the time of launch.": "快速启动绝地喷射舱发射程序的同时引爆TNT。", + "SHUTTLE": "运输船", + "Graphics Device": "图形设备", + "LONG HOLD": "长按", + "Invert Scope (Vertical)": "开镜视角翻转(垂直)", + "Shadow Quality": "阴影质量", + "The extensive Terminid enclosures here allow scientists to study Terminid behavior, and civilians to take pictures with Brood Commanders.": "大量终结族圈养在这里,方便科学家研究它们的行为,公民也可以和虫族指挥官拍照留念。", + "Beyond 50m, you'll be out of contact range from your squadmates. Stay in proximity to maintain full situational awareness.": "和队友相距超过50米就会失联。请避免远离队友,以便全面掌握战场动态。", + "Texture Quality": "贴图质量", + "HIDE FRIEND CODE": "隐藏好友代码", + "Estimated time until ready: #MINUTES m #SECONDS s": "预计准备时间:#MINUTES分#SECONDS秒", + "WEAPON SKIN": "武器涂装", + "SuperCitizen_2": "超级公民_2", + "Active for: #HOURS h #MINUTES m": "激活时长:#HOURS小时#MINUTES分", + "CANNONS": "加农炮", + "April": "4月", + "Did you know tips are shown during these transition sequences?": "你知道传输途中会显示提示吗?", + "MAP": "地图", + "Increases the range of the Helldiver Radar by equipping it with a high-powered Plutonium-210 battery.": "配备高能钚-210电池,装备后可扩大绝地潜兵的雷达探测范围。", + "Compass Ordinal Directions": "罗盘方位", + "STREAMLINED REQUEST PROCESS": "简化申请流程", + "on #PLANET": "在#PLANET上", + "OPEN MICROPHONE": "打开麦克风", + "Repurposed surveillance technology allows the Sentry Deployment Cannon to closely track the user at all times, no matter where they go or what they do, ready to fire at any second.": "重新改造监控技术的用途,使哨戒部署炮能够随时密切追踪使用者,无论他们去哪里或在做什么,炮台随时都能开火。", + "375 SC": "375超级货币", + "Station moves in:": "空间站即将移动:", + "ITALIANO": "ITALIANO", + "Super Earth Mandatory Reading": "超级地球必读事项", + "No Booster": "无强化资源", + "Allows Helldivers to keep sprinting even when they are out of stamina, draining their health instead.": "通过消耗生命值,让绝地潜兵在耐力耗尽时仍能继续冲刺。", + "Friendly Fire isn't.": "友军误伤不算作友好行为。", + "September": "9月", + "Adjusts the relative sensitivity of camera movement in First Person View (FPV).": "调整第一人称视角(FPV)下,视角移动的相对灵敏度。", + "Motion Sensor Acceleration Threshold": "动态感测器加速阈值", + "Text Chat": "文字聊天", + "SPEED": "速度", + "Input Device": "输入设备", + "Invert Mouse Scope (Horizontal)": "开镜视角鼠标翻转(水平)", + "Select the visibility of tooltips during gameplay.": "选择游戏过程中的提示信息可视度。", + "TERMINID RESEARCH PRESERVE": "终结族研究保护区", + "Military watchdog groups have called exploding shrapnel \"savage,\" \"merciless,\" and \"well-suited for spreading Democracy.\"": "军事监督组织认为高爆弹片“野蛮”、“无情”,“非常适合传播民主”。", + "Please observe the following Patriotic Service Announcement.\nDeviations in attention will be considered treason.\n\n\nThank you for your cooperation.": "请遵守以下爱国服务公告。\n注意力不集中将被视为叛国。\n\n\n谢谢配合。", + "Extraction Timer Visibility": "撤离计时器可视度", + "The volume of the in-game voice chat.": "游戏内语音聊天的音量。", + "Supported modes are:\n\nOpen Microphone\nPush-To-Talk (PTT)\nPush-To-Mute (PTM)\nMuted\nDisabled (not recommended)\nToggle Microphone": "支持以下模式:\n\n打开麦克风\n按键说话\n按键静音\n静音\n禁用(不推荐)\n切换麦克风", + "CONTROLLER": "控制器", + "ITEM TRAITS": "物品特性", + "Triggers on the second press if you quickly push down the same button twice.": "如果连续两次快速按下同一按钮,第二次按下时触发操作。", + "DROP CARRYABLE": "放下携带的物品", + "Closed Caption Mode": "隐藏式字幕模式", + "When enabled, voice transcription is used as an input source for text chat. Enabling this may cause additional configuration windows to appear for initial setup on a new device.": "启用时,语音转录将被用作文字聊天的输入源。启用该选项后可能会出现额外的设置窗口,用于在新设备上完成初始设置。", + "On a mission alone and dying to have someone liberating by your side? Use an SOS beacon to call in a fellow Helldiver.": "你是否在独自执行任务,企盼有战友加入你的解放之旅?使用SOS信标呼叫其他绝地潜兵吧。", + "ULTRA PERFORMANCE": "超高性能", + "My only complaint is that I wish I had another one": "我唯一不满意的就是我怎么没再买一件", + "#COUNT SC": "#COUNT超级货币", + "Mature - Sexual Content": "成人 - 性内容", + "Controls the strength of the bloom filter. Contributes to the feeling of brightness on highlights.": "控制全屏泛光过滤强度。影响玩家对光亮环境的亮度感受。", + "Continuous barrages rain down during missions.": "任务期间,连续炮击倾泻而下。", + "Describes, Depicts Illegal Act": "描述、描绘非法行为", + "Ambient Occlusion": "环境光遮蔽", + "ITEM REVIEWS": "商品评价", + "Don't worry, if you fail an objective, you will NOT be sent to a freedom camp. This is merely a dissident rumor.": "不要担心,就算你没能完成目标,你也绝对不会被送入自由营。那只是异见分子散播的谣言。", + "Auto Reverse Vehicles": "载具自动倒车", + "Dynamic Resolution Scaling": "动态分辨率缩放", + "IRREGULAR VOTELESS BEHAVIOR": "异常无票者行为", + "You can pick up active grenades and toss them away before they explode. Give it a try, it's fun!": "你可以捡起已激活的榴弹,在它爆炸前丢出去。很有意思,值得一试!", + "It pays to be a straight shooter—angled fire might glance off your target or even ricochet into your squadmates.": "直线射击效果更好,而斜射可能会让子弹从目标身上擦过,甚至有可能反弹到队友身上。", + "Increases health of Sentry stratagems by #VALUE%.": "哨戒炮战略配备的生命值提升#VALUE%。", + "QUALITY": "画质", + "ULTRA SUPERSAMPLING": "强化超级采样", + "Enabling this setting produces more realistic shadows by calculating ambient lighting, touching surfaces and objects that are blocking the light. Disabling may slightly improve GPU performance.": "启用该设置可计算环境光、接触面和遮光物体,从而产生更加逼真的阴影效果。禁用设置或许可以略微改善GPU性能。", + "Voting failed, please try again.": "投票失败,请重试。", + "FAILED TO FILE REPORT!\nTry again later.": "发送举报失败!\n请稍后重试。", + "Determines how non-linear mouse movement should be. If non-zero, the sensitivity ramps up with the speed of mouse movement. The higher the value, the more pronounced this acceleration is.": "设定非线性鼠标移动的方式。如果不为零,鼠标灵敏度会随移动速度上升。数值越高,加速越明显。", + "VOTED": "已投票", + "No event lobbies found": "未找到战事大厅", + "The Exostorm has reached critical mass, enveloping the planet in an ominous tempest that defies atmospheric physics.": "异界风暴已达到临界质量,整颗星球都被这场不祥的风暴所裹挟,彻底颠覆大气物理定律。", + "Boost overall crew efficiency with a suite of proven enthusiasm enhancement initiatives, such as citizenship anniversary celebrations and paid lavatory breaks.": "采取一系列行之有效的措施调动积极性,提高船员的总体效率。采取的措施包括举办公民纪念日庆典活动,以及允许带薪如厕等。", + "COOLDOWN TIME": "冷却时间", + "A Helldiver-operated weapon of mass liberation. Paid for with the blood of soldiers and the credits of taxpayers, this technological marvel is Democracy made manifest.": "绝地潜兵操纵的大规模解放武器。用士兵鲜血和纳税人税款铸就的这一技术奇迹堪称民主的象征。", + "If enabled, replace your currently held weapon to the one you have picked up.": "启用时,将你当前所持武器切换为拾取的武器。", + "Every member of the squad can view the Galactic War table, not just the host of the Super Destroyer.": "除了超级驱逐舰的主办者,小队的所有成员都可以查看星系战争的议战桌。", + "Y- AXIS": "Y-轴", + "Turning V-Sync on synchronizes the frame rate to the display device's refresh rate. Enabling this setting prevents visual artifacts such as screen tearing, but can cause lower framerate if your computer cannot keep up with the monitor.": "开启垂直同步会将帧率同步为显示器的刷新率,可以防止画面撕裂等画面现象,但如果电脑性能无法与显示器保持同步,则可能会导致帧率降低。", + "MORALE AUGMENTATION": "提升士气", + "Account Link Succeeded": "成功绑定账户", + "Dec": "12月", + "MOVEMENT": "移动", + "Change size of subtitles as they are displayed on screen.": "选择屏幕上显示的字幕尺寸。", + "Jul": "7月", + "The hard workers on this planet produce goods vital to the war effort, as well as to the prosperity of Super Earth.": "此星球上的辛勤工人生产重要物资,用于支援战争以及超级地球的光明未来。", + "The second manned site established in Gloom-infested space.": "第二个在“阴霾”侵蚀星域建立的人类驻军据点。", + "The relay towers on this planet are important to Automaton communications.": "这颗星球上的中继塔是机器人通信的重要工具。", + "Integrated Extinguishers": "集成灭火器", + "Selects the graphics API used.": "选择使用的图形API。", + "ABOVE PRIMARY": "主要目标上方", + "SEAF BASIC TRAINING FACILITIES": "超级地球武装部队基础训练基地", + "Equips Hellpods to deploy smokescreens on impact, obscuring Helldiver deployment.": "为绝地喷射舱配备烟雾弹,在撞击时释放烟幕,掩护绝地潜兵上场。", + "THROW": "投掷", + "Subtitle Mode": "字幕模式", + "Would you like to reconnect to your last squad?": "你希望与上个小队重新建立连接吗?", + "SECONDARY WEAPON": "次要武器", + "UAV Recon Booster": "UAV侦察强化资源", + "###COUNT": "###COUNT", + "LOCATION": "地点", + "REVEAL FRIEND CODE": "显示好友代码", + "Touch Pad Map Sensitivity": "触摸板地图灵敏度", + "Particle Quality": "粒子质量", + "Pre-approves the following forms in the Support Weapon Approval Process: Form 99-C (Justification for Munitions), Form 88-1 (Democratic Impact Worksheet), & Form 104 (Collateral Damage Risk Waiver).": "在支援武器审批流程中预先通过以下表格的审批:99-C表格(使用弹药的正当理由)、 88-1表格(民主影响说明工作表)和104表格(附带损害风险弃权声明)。", + "TURN RIGHT": "右转", + "Motion Blur": "动态模糊", + "Previous Category": "上一个类别", + "Cursor Sensitivity": "光标灵敏度", + "UNKNOWN": "未知", + "ABOUT US": "关于我们", + "If enabled, the camera will automatically center itself behind a player-controlled vehicle when not otherwise receiving input.": "启用之后,如果没有收到其他输入,会自动将玩家控制的载具置于视角中央。", + "Each faction presents unique challenges. Mix up your gear and try new tactics!": "不同阵营各有独特的挑战。混合使用装备,尝试新战术吧!", + "WEAPON TRAITS": "武器特性", + "At this research facility, recovered Voteless are given a fresh chance to aid Managed Democracy. Through processing and analysis of their biomass, our understanding of the Void stands to be significantly advanced.": "在这座研究设施中,被回收的“无票者”将获得为管理式民主添砖加瓦的新机会。通过对其生物质进行处理分析,我们定可大幅深化对寂域的了解。", + "Display On-Screen Keyboard": "显示屏幕键盘", + "After a button has been pushed down for a set amount of time, this starts triggering continuously.": "按下按键一定时间后开始连续触发操作。", + "Watch out for alien storms. Super Earth scientists have officially classified many of them as dangerous. And freaky.": "小心外星风暴。超级地球的科学家们已经正式宣布许多种风暴不仅危险,而且十分反常。", + "CLIMB": "攀爬", + "You need to link your Steam account to a PSN ID in order to report another player.": "你需要将Steam账户与PSN ID绑定才能举报其他玩家。", + "Exposes Hellpod wiring upon surface contact, stunning any units in the vicinity of the drop site.": "在绝地喷射舱落地时露出其电线,电晕空投地点附近的所有单位。", + "The Terminids on this planet have evolved to yield more E-710 than other specimens.": "此星球上的终结族经过进化,能产出比其他虫族更多的710元素。", + "The DSS activates its Zero G Anti-Ship Missile System, targeting all large enemy spacecraft attempting to exit the planet's atmosphere. In addition, diverts excess manpower to Super Destroyer logistical support.": "民主空间站启动零重力反舰导弹系统,瞄准所有试图离开星球大气层的敌方舰船。此外,将多余战力投入到超级驱逐舰的后勤支援。", + "Hold a grenade before throwing to \"cook\" it. Time your throw for an air-burst detonation! (Note: waiting too long may lead to unintended death.)": "可以将榴弹握在手中进行“温雷”操作,之后再将其丢出。掌握好投掷时间,让榴弹在空中爆炸!(注意:温雷时间过长可能会导致意外死亡。)", + "Hand in to #NAME": "上交给#NAME", + "AVATAR": "游戏形象", + "SAMPLE SCANNER": "样本扫描仪", + "The Super Destroyer can only stay in low orbit for a limited time—watch that mission clock!": "超级驱逐舰在低空轨道上停留时间有限——注意任务时长!", + "#FIRST #LAST": "#LAST#FIRST", + "WEAPON WHEEL UP": "向上转动武器轮盘", + "OFFERS VALID FOR": "优惠有效期:", + "DUAL WIELD FIRE RIGHT": "双持武器右手开火", + "Barrage orbitals fire #VALUE additional salvo(s) per barrage.": "火力网轨道武器每次可额外进行#VALUE次齐射。", + "Concealed Insertion": "隐蔽上阵", + "MISSION STRATAGEM PERMIT": "任务战略配备许可证", + "ENGLISH (UK)": "ENGLISH (UK)", + "OPTIONAL OBJECTIVE": "可选目标", + "Graphics Preset": "图像预设", + "AN OLD ENEMY EMERGES": "宿敌现身", + "Cheating/Glitching": "作弊/利用游戏漏洞", + "All Support Weapon stratagems launch immediately once called in, reducing overall deployment time.": "所有支援武器战略配备在呼叫后即时发射,缩短整体部署时间。", + "All samples extracted with are shared by the entire squad. Work together to advance the science of Super Earth!": "全部提取的样本均由整支小队共享。携手推进超级地球的科学发展吧!", + "Solicitation for Personal Info": "诱导收集个人信息", + "mike__the_spike": "马克__不马虎", + "Adjusts the controller vibration strength.": "调整控制器振动强度。", + "AFFECTED STRATAGEMS": "受影响的战略配备", + "Scope Sensitivity": "开镜灵敏度", + "Further expands Eagle weapons bay by removing unnecessary systems such as fire suppression, ejection, and airbags.": "通过移除火力抑制、弹射和安全气囊等不必要的系统,进一步扩大“飞鹰”的武器舱。", + "Insufficient donation funds": "捐赠资源不足", + "Account Link Failed": "账户绑定失败", + "MilitaryBeefHunk99": "军用牛肉块99", + "KEY + MOUSE": "键盘+鼠标", + "Terminids are held safely within massive compounds on this planet for study and E-710 extraction.": "此星球上设有安全管控的大型终结族保护区,专门用于研究终结族并提取710元素。", + "How quickly the cursor transitions from moving to stabilizing.": "光标从移动到稳定的过渡速度。", + "Decreases cooldown for all Backpack stratagems by #VALUE%.": "所有背包战略配备的冷却时间缩短#VALUE%。", + "STRATAGEM ACQUIRED": "已获取战略配备", + "Aim Sensitivity": "瞄准灵敏度", + "FRIENDS ONLY": "仅限好友", + "Adjusts how quickly acceleration is applied to the controller camera control. If set to zero, the movement is linear.": "调整控制器操控视角的加速生效速度。设置为零则视角线性移动。", + "+": "+", + "This fully-upgraded facility enables deep operations within the Gloom. Operations on surrounding planets will be significantly supported.": "该设施全面升级,能在“阴霾”内展开深入运作。在周围星球的行动将得到大力支援。", + "Display Mode": "显示模式", + "Adjust the opacity of text backgrounds in the HUD.": "调整HUD文字背景的不透明度。", + "The purchase has already been authorized by Steam, but we are currently experiencing a high volume of requests. \nWe haven’t been able to add the currency to your account yet, but we will continue retrying in the background. \n\nThank you for your patience!\nIf the issue persists, please contact our support team.\n\nNext attempt in #TIME seconds.": "购买操作已获得Steam授权,但目前存在大量请求等待处理。\n暂时无法将货币添加到账号,我们会在后台继续重试。\n\n感谢您的耐心等待!\n如果问题仍然存在,请联系我们的支持团队。\n\n#TIME秒后将重试。", + "PARTY": "队伍", + "Next Category": "下一个类别", + "WEAPON WHEEL RIGHT": "向右转动武器轮盘", + "©2024 Sony Interactive Entertainment LLC. Developed by Arrowhead Game Studios AB. Helldivers 2 is a registered trademark of Sony Interactive Entertainment LLC and related companies in the U.S. and other countries.": "©2024 Sony Interactive Entertainment LLC. Developed by Arrowhead Game Studios AB. Helldivers 2 is a registered trademark of Sony Interactive Entertainment LLC and related companies in the U.S. and other countries.", + "The former site of the AM Defense Factory Hub. AM Defense was fortuitously able to reclaim its losses through insurance; the lives that were lost, however, can never be adequately compensated for.": "虎将国防工厂中心遗址。虎将国防尚有保险弥补损失,但那些逝去的生命如何弥补?", + "Players associated with an online ID can be reported for breaching the terms of service. This player is not associated with an online ID.": "如果关联在线ID的玩家违反服务条款,可将其举报。此玩家并未关联在线ID。", + "Teammate Status Visibility": "队友状态可视度", + "Active for: #DAYS d #HOURS h": "激活时长:#DAYS天#HOURS小时", + "CENTER": "中心", + "Getting Kicked": "被踢出", + "PIT CREW HAZARD PAY": "维修人员危险津贴", + "Voice Chat": "语音聊天", + "LONG RELEASE": "长按松开", + "CENTER FOR THE CONFINEMENT OF DISSIDENCE (CECOD)": "异见监禁中心 (CECOD)", + "All Emplacement stratagems launch immediately once called in, reducing overall deployment time.": "所有炮台战略配备在呼叫后即时发射,缩短整体部署时间。", + "SWITCH AIM MODE": "切换瞄准模式", + "Select the visibility of primary objectives.": "选择主要目标的可视度。", + "Adjusts the speed of the cursor when controlled by controller.": "调整游戏控制器操控下的光标速度。", + "Inverts up and down of Motion Sensor control direction.": "动态感测器上下方向翻转。", + "Midnight Mode": "午夜模式", + "Inverts left and right control of mouse direction.": "鼠标左右方向翻转。", + "AVAILABLE IN: #MINUTES m #SECONDS s": "就位倒计时:#MINUTES分#SECONDS秒", + "Adjusts the strength of the trigger effect function.": "调整扳机效果功能的强度。", + "You can change and customize these settings at any time during gameplay": "您可以在游戏期间随时更改或自定义这些设置", + "Reduces cooldown time for Sentry, Emplacement, and Resupply stratagems by #VALUE%.": "哨戒炮、炮台和补给战略配备的冷却时间缩短#VALUE%。", + "Increases all Helldivers' stamina capacity and recovery.": "提高所有绝地潜兵的耐力上限和恢复力。", + "EXPANDED WEAPONS BAY": "武器舱扩容", + "Subtitle Size": "字幕字号", + "If enabled, whenever you equip a weapon, it will recall the last weapon functions you had used, such as the firing mode.": "启用该选项后,每次装备的武器都将应用上一次使用过的武器功能,如开火模式等。", + "日本語": "日本語", + "Struggling to input a code while in a distracting and/or stressful war zone? Just remember: Countless civilian lives are in your hands!": "战区的环境令你难以集中注意力并且紧张焦虑,难以输入代码?此刻只需记住:无数公民的性命就掌握在你的手中!", + "Send chat logs (optional)": "发送聊天记录(可选)", + "Invert Mouse Scope (Vertical)": "开镜视角鼠标翻转(垂直)", + "TAA Sharpness": "TAA锐度", + "Love this item, shipping A+++++++. Would purchase again. Highly recommended!!!!": "超级喜欢,A+++++++级物流。还会回购,强烈推荐!!!!", + "Ammunition for the Guard Dog stratagem can run out and be replenished with ammo packs.": "“护卫犬”战略配备的弹药会耗尽,可以通过弹药包进行补充。", + "When enabled, raw mouse input is used. At low frame rates disabling this may lead to smoother mouse input at the cost of slightly higher latency.": "启用时,使用原始鼠标输入。在低帧数下禁用该选项可能会导致鼠标输入变得更加流畅,但也会略微增加延迟。", + "The volume of the in-game dialogue.": "游戏内对话的音量。", + "This value controls the tradeoff between flicker and ghosting. Higher values reduce ghosting and may help with motion sickness, while lower values offer smoother edges.": "该数值可以协调闪烁和重像。上调数值可以减少重像,或许也可以缓解晕动症。下调数值则可以让边缘变得更加平滑。", + "Increases burning temperature of incendiary weapons by lacing fuel with a precisely-formulated compound of thermite, white phosphorus, capsaicin, allyl isothiocyanate, and 19 other accelerants.": "在燃料中加入精确配制的铝热剂、白磷、辣椒素、异硫氰酸烯丙酯和19种其他助燃剂,提高燃烧型武器的燃烧温度。", + "DirectX 11": "DirectX 11", + "Increases all Helldivers' effective radar range.": "扩大所有绝地潜兵的雷达有效范围。", + "BOOSTER PACK": "强化资源包", + "HONK": "鸣笛", + "Lines all Hellpods with volatile incendiaries that detonate upon impact, igniting any units in vicinity of the drop site.": "在所有绝地喷射舱中装载易爆燃烧弹,使其在撞击后爆炸,点燃空投地点周围的所有单位。", + "Adjust sensitivity of mouse movement. A lower setting moves the mouse more slowly, while higher settings move the mouse more quickly.": "调整鼠标移动的灵敏度。下调该设置可以降低鼠标移动的速度,上调则会加快速度。", + "HEADER HIDDEN": "隐藏标题", + "Invert Motion Sensor (Horizontal)": "动态感测器翻转(水平)", + "You can change the name of your Super Destroyer through the Ship Management menu.": "你可以通过舰船管理菜单更改超级驱逐舰的名称。", + "VEHICLE BAY": "载具停靠港", + "Adjust the intensity of the blur effect applied to moving objects and when rotating the camera. Decreasing motion blur might help with motion sickness as well as seeing moving objects.": "调整物体移动和视角旋转时的模糊效果的强度。减少动态模糊或许可以缓解晕动症,有助于看清移动中的物体。", + "By clicking 'Agree and Continue', you are bound to the terms in the EULA.\n\nhttps://www.playstation.com/legal/op-eula/": "点击“同意并继续”即表示你愿意遵守最终用户许可协议的规定。\n\nhttps://www.playstation.com/legal/op-eula/", + "DISABLED": "禁用", + "Change the color of your aiming reticle, for greater visibility.": "更改准星颜色,更好地调整可视度。", + "SECONDARY WEAPONS": "次要武器", + "DIVE": "闪躲", + "MOVE FORWARD": "向前移动", + "Construction has begun on the Democracy Space Station. The local populace is honored to host thousands of construction crews for this historic event.": "民主空间站(DSS)的建设工作已经开始。当地居民荣幸地接待了参与此次历史性活动的数千名建筑工人。", + "Difficult terrain inhibits your movement. Best practices recommend avoiding Snow, Mud, Water, Shrubberies, and Lava. For a complete list, see Manual Section D.198-2.": "复杂地形会阻碍你移动。最好避开雪地、泥地、水面、灌木丛和岩浆。如需查看完整列表,请翻阅手册D部分198-2。", + "BRIDGE": "舰桥", + "LEFT": "左", + "Info Feed Visibility": "动态信息可视度", + "DSS Tactical Actions become activated when they have met their donation goals.": "捐赠目标达成时,相应的DSS战术行动就会激活。", + "Vehicle Camera Centering": "载具视角居中", + "Terrain Quality": "地形质量", + "DONATION ACCESS LICENSE": "捐赠物资使用许可", + "UNBLOCK": "取消屏蔽", + "SECONDARY": "次要", + "Controller only. Selecting Default will swap between primary and secondary weapon when tapping the swap button, whilst holding the swap button will change to your support weapon. \nHelldivers Classic will swap between primary and support weapon when tapping the swap button, whilst holding the swap button will change to your secondary weapon.": "仅限控制器。选择“默认”时,轻点切换按钮切换主要或次要武器,按住切换按钮切换为支援武器。\n选择“绝地潜兵 经典”时,请点切换按钮切换主要武器或支援武器,按住切换按钮切换为次要武器。", + "The longer a mission takes, the heavier the enemy presence gets.": "任务耗时越久,敌方兵力越强。", + "Democracy Officers are direct representatives of Super Earth High Command. They augment and enhance the loyalty of all Super Destroyer crew members.": "民主官是超级地球最高指挥部的直接代表,他们将增强和提升所有超级驱逐舰船员的忠诚度。", + "If a squadmate dies during a mission, make sure you pick up their dropped samples. There will be time for mourning later!": "若队友在执行任务期间阵亡,请务必捡起他们掉落的样本。以后还会有时间供你追悼他们!", + "#COUNT/#TOTAL (MAX)": "#COUNT/#TOTAL(最多)", + "FAST RECON VEHICLE": "快速侦察载具", + "UP": "上", + "PURCHASE SUCCESSFUL": "购买成功", + "Tired of missing your target? Use First Person View (FPV) to make long-distance shots.": "不想再打空了?使用第一人称视角(FPV)进行远距离射击吧。", + "Framerate Limit": "帧率限制", + "[ Press": "[ 按下", + "Triggers when the button is released after being pressed down.": "按下按键后松开时触发。", + "SCOPED": "开镜", + "CLASS 3 EXOSTORM": "3级异界风暴", + "UI Brightness": "UI亮度", + "Lowers the time it takes for the extraction shuttle to reach the extraction beacon.": "缩短撤离运输船抵达撤离信标所需的时间。", + "ESPAÑOL": "ESPAÑOL", + "The Ministry of Defense is responsible for the defense of Liberty against all enemies, human and non-human, realized and potential.": "国防部负责保卫自由精神,抵御所有已知和潜在的外敌,不论是人类或是非人类。", + "SMALL": "小", + "ARMOR RATING": "盔甲等级", + "Support Weapons deploy with the maximum number of carriable magazines.": "支援武器配给的可携带弹匣数增加至最大数量。", + "NEW HOPE CONSTRUCTION SITE": "希望新城建造区", + "FSR": "FSR", + "Make sure to pick up your fallen squadmates' sample containers. They're critical for our collective scientific progress!": "务必捡起阵亡队友的样本容器。样本对于推动我们的集体科学进步至关重要!", + "The threshold at which stabilization stops being applied.": "不再启用稳定量的阈值。", + "REPORT": "举报", + "FACTORY HUB (DESTROYED)": "工厂中心(遗址)", + "Cheating": "作弊", + "Completion Est: #HOURS h": "预计用时:#HOURS小时", + "Reduces time until new reinforcements are granted once they've been depleted.": "缩短增援耗尽后获得新增援的时间。", + "Mouse Aim Sensitivity": "鼠标瞄准灵敏度", + "VICTORY POSE": "胜利姿势", + "Low light and poor weather reduce your vision. (But never fear—they also reduce the vision of our enemies)": "光线不足和天气恶劣都会影响视野。(但是完全不必担心,因为敌方视野同样会受到影响)", + "Always": "总是显示", + "RADIAL MENU LEFT": "圆盘菜单左", + "ACTIVE ACTION": "进行中的行动", + "PapaPatrioot": "爱国老爹爹", + "BLOCKED PLAYERS": "已屏蔽玩家", + "Enables an extensive logistics network to operate within the Gloom, negating adverse Gloom effects on surrounding planets.": "促进庞大的后勤网络在“阴霾”内运作,彻底消除“阴霾”对周边行星的负面影响。", + "Weapon Status Visibility": "武器状态可视度", + "VOTE": "投票", + "Dialogue Volume": "对话音量", + "ACTIVE": "已启动", + "NEXT WEAPON": "下一件武器", + "MUSCLE ENHANCEMENT": "肌肉强化", + "Mission difficulty is determined in part by the types of enemy units in the area. Make sure you bring the appropriate weaponry!": "任务难度也和当地敌方部队的类型有关。一定要带上合适的武器!", + "TACTICAL OBJECTIVE (OPTIONAL)": "战术目标(可选)", + "IN-WORLD ONLY": "仅显示剧情相关文字", + "Diving to the ground can be a life-saver, but it also makes you an easy target for melee units.": "扑倒在地或许可以救命,但是也会让你变成近战单位的活靶子。", + "Window": "窗口", + "SQUAD RECONNECT": "小队重连", + "SHIP MODULE": "舰船模块", + "LtBadazz500": "暴躁中尉500", + "Are you sure you want to unbind this input?": "确定要解除绑定该键位吗?", + "Paradise": "乐土", + "Text To Speech Voice": "文字转语音的声音", + "Adjusts the overall sharpness of the final image.": "调整最终图像的总体锐度。", + "Enable Performance Monitor. The Discreet version will show framerate, memory and network statistics in the top left corner, ideal for general gameplay without distraction. While the Base, Graph and Advanced versions will show framerate statistics in the top right corner.": "启用性能监视器。简洁版会在左上角显示帧率、内存和网络数据,适合常规游戏,能避免干扰体验。基础版、图表版和高级版则会在右上角显示帧率数据。", + "ORDER OUTCOME": "指令结果", + "BINDINGS": "键位绑定", + "Experimental Infusion": "试验性注射剂", + "ROTATE": "旋转", + "Place markers on the map to help your squad navigate.": "在地图上放置标记可以为队友指路。", + "UNABLE TO REPORT": "无法举报", + "When your stamina is depleted, your sprint speed is slower and your accuracy is worse.": "耐力耗尽以后,你的冲刺速度和命中率都会下降。", + "The Automatons are equipped with hyper reactive protocols, making them susceptible to suppressive fire. The more you shoot at them, the less accurate they'll be.": "机器人配备过度反应协议,因此,火力压制对付它们格外有效。你击中它们的次数越多,它们还击的命中率越低。", + "The structures on this planet allow the Illuminate to communicate outside the galaxy.": "光能者利用星球上的这种建筑与星系外的同类通讯。", + "Download starting": "开始下载", + "Expert Extraction Pilot": "专业撤离飞行员", + "SAMPLE EXTRICATOR": "样本拯救者", + "MOVE DISABLED": "移动禁用", + "DONATE": "捐赠", + "LOOK LEFT": "向左看", + "EXTRA LARGE": "特大", + "Eagle stratagem cooldown time reduced by #VALUE%.": "“飞鹰”战略配备的冷却时间缩短#VALUE%。", + "Democracy Space Station": "民主空间站", + "SHIP MODULE LEVEL UNLOCKED": "已解锁舰船模块等级", + "VITALITY BOOST": "生命力增强", + "Available in: #MINUTES m #SECONDS s": "就位倒计时:#MINUTES分#SECONDS秒", + "Reinforces sentries with state-of-the-art cyanoacrylate adhesives, greatly improving their durability under fire.": "利用先进的氰基丙烯酸酯粘合剂加固哨戒炮,大幅提升其在炮火攻击下的耐久度。", + "DEAD SPRINT": "死亡冲刺", + "The quality of atmospheric lighting. Reducing this may introduce noise and ghosting but improve GPU performance.": "氛围光照的质量。下调该选项或许会导致出现噪点和重像,但是可以改善GPU性能。", + "Planet Biome": "星球生物群落", + "IN GAME": "正在游戏", + "GENERAL": "其他", + "SEARCH RESULT": "搜索结果", + "Map Position": "地图位置", + "HIGH-DENSITY EXPLOSIVES": "高密度炸药", + "JET BRIGADE FACTORIES": "喷气旅孵化厂", + "The Ministry of Humanity maintains healthy, productive voters by managing education, healthcare, social grading, and gene management.": "人道部通过教育、医疗保健、社会分级和基因管理,培育生产能力较高的健康投票人。", + "Sep": "9月", + "PREVIOUS EVENT": "前一战事", + "HEAVY ORDNANCE DISTRIBUTION": "重型军械分发", + "ESPAÑOL (LATINOAMÉRICA)": "ESPAÑOL (LATINOAMÉRICA)", + "Select when an on-screen option will be shown. Default behavior is to only display the on-screen keyboard if a keyboard was not used to enter the text input state. May require Steam Big Picture mode on PC.": "选择何时显示屏幕选项。默认是仅在未使用键盘输入文本时才显示屏幕键盘。可能要在PC上使用Steam的大屏幕模式。", + "CONCEALED INSERTION": "隐蔽上阵", + "Allows Helldivers to traverse difficult terrain with ease.": "让绝地潜兵能够轻松穿过复杂地形。", + "Active for: #MINUTES m #SECONDS s": "激活时长:#MINUTES分#SECONDS秒", + "Allows Mortar Targeting Platform to access Helldiver HUD ecosystem through use of third-party conversion software.": "利用第三方转换软件,允许迫击炮瞄准平台接入绝地潜兵的HUD生态系统。", + "E-710 RICH STRAIN": "富含710元素的突变种", + "Select the visibility of ordinal directions on the compass.": "选择罗盘的方位可视度。", + "Want to show off how firmly you support capitalism? Spend medals on a Warbond!": "想要展示你支持资本主义的决心?为战争债券多花费一些奖章吧!", + "SEND REPORT": "发送举报", + "Select the visibility of weapon status during gameplay.": "选择游戏过程中的武器状态可视度。", + "Triggers only when a button is pushed down and released quickly.": "仅在快速按下并松开按键时触发操作。", + "WEAPON WHEEL DOWN": "向下转动武器轮盘", + "How sensitive the motion sensor should be in relation to moving the controller.": "移动控制器时动态感测器的灵敏度。", + "Firebomb Hellpods": "火焰炸弹绝地喷射舱", + "LOCKED": "未解锁", + "HOME CINEMA": "家庭影院", + "FACTION": "阵营", + "Select the display resolution. This is the pixel count of the final image. Lower values will have less detail. In windowed mode this setting also dictates the size of the window, in the other modes we recommend using the resolution of the display device and adjusting the Render Scale setting to achieve desired performance.": "选择显示的分辨率。该数值为最终图像的像素点总数。数值越低,显示的细节越少。在窗口模式中,该选项也会决定窗口的尺寸。在其他模式中,我们推荐使用与显示设备相同的分辨率,然后调整渲染比例,从而实现理想的性能。", + "The volume of all audio combined.": "所有声音的总音量。", + "Select if anti-aliasing will be applied to smoothen jagged edges.": "选择是否启用抗锯齿处理锯齿状边缘。", + "No chat messages to include.": "无聊天消息可附加。", + "Select level of geometry detail. Lower values increase GPU performance, at the cost of silhouette detail on objects.": "选择几何图形细节层次。下调数值可以改善GPU性能,但是会弱化物体的轮廓细节。", + "This is the best thing I've ever seen in my life! Can not live without!": "从没见过这么棒的产品!没有它我就活不下去!", + "Received #TIME ago...": "#TIME前收到…", + "This planet has been completely infested by the Terminids, transformed inside and out into a hive of Tyranny. It is a source of Gloom spores.": "这颗星球已被终结族彻底侵占,从内到外被改造成了暴政的虫巢。现已变成了“阴霾”孢子的来源。", + "CAREER": "生涯", + "Booster Pack": "强化资源包", + "DSS CONSTRUCTION SITE - PHASE 2": "DSS建筑工地 - 第2阶段", + "Select the visibility of the compass.": "选择罗盘可视度。", + "Difficulty 1-3": "难度1-3", + "TACTICAL ACTION": "战术行动", + "See a planet that's on the brink of falling under enemy control? Rally your fellow Helldivers and mount a defense. Every mission counts!": "一颗星球即将落入敌人的铁蹄之下,你看见了吗?快号召其他绝地潜兵一起建立防线。每一场任务都至关重要!", + "Input Callouts": "输入口令", + "Stratagem": "战略配备", + "TIER #COUNT COMPLETED": "已完成#COUNT阶", + "Triggers continuously while a button is being pushed down.": "只要按下按键就连续触发操作。", + "QUICK WEAPON WHEEL DOWN": "快速向下转动武器轮盘", + "TIER #COUNT": "#COUNT阶", + "Increases grenade carrying capacity for all Helldivers.": "提高所有绝地潜兵的榴弹携带容量。", + "NVIDIA Reflex tries to reduce the system latency and increases responsiveness. When enabled, NVIDIA Reflex will reduce latency from the GPU. Boost mode will try to also reduce latency from the CPU.": "NVIDIA Reflex旨在降低系统延迟并提升响应速度。启用后,NVIDIA Reflex将降低GPU的延迟。增强模式也将尽可能降低CPU的延迟。", + "Arm injuries reduce your ability to handle recoil and will cause your aim to sway more.": "手臂受伤会令你难以应对后坐力,使得瞄准动作摆动幅度增大。", + "TV SPEAKERS": "电视喇叭", + "Upgrade your ship modules to enhance the capabilities of your Stratagems! It's the perfect way to turn samples into Liberty.": "升级舰船模块可提升战略配备的性能!这是将样本转化为解放之火的完美渠道。", + "DARK FLUID SYNTHESIS LABORATORY": "暗液体合成实验室", + "CENTER FOR CITIZEN SURVEILLANCE (DESTROYED)": "公民监控中心(遗址)", + "Increases orbital targeting speed by updating cannon targeting software to premium version.": "轨道加农炮用于瞄准目标的软件更新到高级版本,提高轨道锁定目标的速度。", + "Impersonating Another User": "冒充其他用户", + "Your Friend Code": "你的好友代码", + "JOIN SQUAD": "加入小队", + "If you get knocked down while holding a stratagem beacon, it will deploy where you were standing.": "如果你在手执战略配备信标的时候被击倒,战略配备将部署在你倒地之前站立的位置。", + "Your Contribution: #COUNT": "你的贡献:#COUNT", + "JUMP": "跳跃", + "This planet-wide, ultra-high-security facility provides ample space for the secure confinement of terrorist dissidents until they are fully rehabilitated and re-educated.": "这座覆盖全星球的超高安全设施收容空间充足,信奉恐怖主义的异见分子可以在这里接受安全监禁,直到全面改造并接受再教育。", + "РУССКИЙ": "РУССКИЙ", + "July": "7月", + "Season ends in: #DAYS Days #HOURS Hours": "赛季倒计时:#DAYS天#HOURS小时", + "Motion Sensor Enable Mode": "动态感测器启用模式", + "Difficulty 7-9": "难度7-9", + "Eagles are fast-response strike craft, with much shorter call-in times than Orbital fire support.": "“飞鹰”是快速反应攻击机,其呼叫时间显著短于轨道火力支援。", + "If an enemy ever attempts to engage in diplomacy, SHOOT THEM. We musn't believe their lies.": "对于试图对话的敌人,要毫不犹豫地开枪击毙。一定不能为花言巧语所欺骗。", + "So easy to use even my grandma loves it": "简单易用,就连我奶奶都很喜欢。", + "Enables a depth of field effect in certain camera views. Disabling depth of field will mean that all parts of the game are in focus at all times.": "在特定视角中启用景深效果。禁用景深即表示游戏内的一切将始终呈现清晰对焦状态。", + "Adjust the scale of your HUD.": "调整HUD的尺寸。", + "Unlimited": "无限", + "This will reset all settings in this tab to default.\nAre you sure you want to continue?": "该操作将把本页面设置重置为默认状态。\n是否确定要继续?", + "ULTRA": "超高", + "SVENSKA (Unsupported)": "SVENSKA (Unsupported)", + "HUD": "HUD", + "X- AXIS": "X-轴", + "Select the visibility of your destroyer marker during gameplay on city maps.": "选择游戏过程中城市地图上你的驱逐舰标记的可视度。", + "USES": "使用次数", + "No player found": "没有找到玩家", + "Teammate Stratagem Visibility": "队友战略配备可视度", + "DOWNLOADING LANGUAGE PACK": "正在下载语言包", + "Fullscreen": "全屏", + "ACCOUNT": "账户", + "Account Linked": "已绑定账户", + "You have a limited amount of reinforcements available in a mission. If you run out they will be replenished slowly on a timer.": "在一次任务中,你能获得的增援数量有限。一旦耗尽就必须等待计时,缓慢补充。", + "Equip a booster to increase the chance of a successful liberation! Boosters apply to your entire squad.": "装备强化资源,提升解放行动的成功率!强化资源对全队成员生效。", + "ACTIVE FOR: #MINUTES m #SECONDS s": "激活时长:#MINUTES分#SECONDS秒", + "Your changes have not been applied.": "你的更改尚未应用。", + "BOTTOM RIGHT": "右下", + "Sample Pickup Visibility": "样本拾取可视度", + "GLOOM OUTPOST BRAVO": "“阴霾”布拉沃哨站", + "SITE FOR VENGEFUL CONTEMPLATION OF TYRANNY'S CRIMES": "暴政罪行警示地", + "MOVE BACK": "向后移动", + "DSS LOGISTICS HUB": "DSS物流中心", + "Scan the QR code to participate in the post match survey.": "扫描二维码参与战后调查。", + "#DAYSd #HOURSh #MINSm Left": "还剩#DAYSd #HOURSh #MINSm", + "한국어": "한국어", + "Cancel Search": "取消搜索", + "More challenging missions yield greater rewards.": "越具挑战性的任务奖励越丰厚。", + "RECOIL SIM": "后坐力模拟", + "#READY MB/#TOTAL MB - #PERCENTAGE% complete": "#READY MB/#TOTAL MB - 已完成#PERCENTAGE%", + "Dynamic Aim Mode": "动态瞄准模式", + "Heads Up Display (HUD) Scale": "HUD大小", + "Stamina Enhancement": "耐力强化", + "A highly secure facility for the safe growth and breeding of Terminids and low-risk extraction of E-710 is located here.": "高度戒备设施,用于安全繁育终结族和低风险提取710元素。", + "NATIVE": "原始", + "Are you sure you want to unlink your accounts?": "确定要解除账户绑定吗?", + "OFF": "关", + "Enabling this setting produces more realistic ambient lighting, making nearby surfaces occlude some of the light.": "启用该设置可让附近的表面遮挡部分光线,从而产生更加逼真的环境阴影效果。", + "Select the intensity of sudden camera movements.": "选择视角突然移动的幅度。", + "SAMPLE": "样本", + "Purchase Super Credits to access premium content.": "购买超级货币,解锁尊享内容。", + "Something went wrong while attempting to reach PlayStation™Network. Error codes:": "尝试访问PlayStation™Network时出现问题。错误代码:", + "Search Territory #TERRITORY on Planet #PLANET": "搜索#PLANET星球上位于#TERRITORY的敌方领地", + "Bloom": "泛光", + "Recommended by 9 out of 10 dentists": "90%的牙医鼎力推荐", + "STRATAGEM TRAITS": "战略配备特性", + "BLAST ABSORPTION": "爆炸吸收", + "Inverts up and down control of mouse direction in First Person View (FPV).": "在第一人称视角(FPV)下,鼠标上下方向翻转。", + "The former site of the Center for Citizen Surveillance. The tragic loss of the facility further evidences the critical imperative of comprehensive domestic surveillance.": "公民监控中心遗址设施的惨重损失进一步证明了全面监控的迫切必要性。", + "Your stance has a significant impact on accuracy. The SEAF manual lists the following stances in order of least to most accurate: Moving < Standing < Crouching < Prone.": "你的姿势会显著影响命中率。超级地球武装部队手册按照命中率从低到高的顺序列出了以下姿势:移动<站立<蹲下<趴下。", + "Here, the best of the best go through the rigorous Helldiver training that will earn them their capes.": "万里挑一的精英在这里接受严格的绝地潜兵训练,争取赢得披肩。", + "V-Sync": "垂直同步", + "AXIS": "坐标轴", + "Hellpods have basic steering capabilities. Try to drop in on your enemies!": "绝地喷射舱具备基础转向功能。尽量降落在敌人周围!", + "Select the behaviour of the crosshair visibility during gameplay.": "选择游戏过程中十字准星可视度的变化方式。", + "Select the width of the stamina bar during gameplay.": "选择游戏过程中的耐力槽宽度。", + "DUAL WIELD FIRE LEFT": "双持武器左手开火", + "There is currently no active action": "目前没有进行中的行动", + "CENTER OF SCIENCE": "科学中心", + "FACTORY HUB": "工厂枢纽", + "Enables smoothing of mouse inputs. Can make tracking targets easier at the cost of responsiveness.": "启用鼠标输入平滑化。有助于跟踪目标,但是会影响灵敏度。", + "UNDER COMPASS": "罗盘下方", + "LINK ACCOUNT": "绑定账户", + "GRAPHICS": "图像", + "If you notice a squadmate sympathizing with an enemy, report them to your Democracy Officer. Thoughtcrimes kill!": "如果你发现队友同情敌人,请向民主官举报。思想犯罪是会害死人的!", + "MODULES UNLOCKED": "模块已解锁", + "Volumetric Clouds Quality": "体积云质量", + "ENGLISH (US)": "ENGLISH (US)", + "The smelters and refineries on this planet turn crude materials into usable hardware.": "此星球上的冶炼厂和精炼厂可将原料变为实用的硬件。", + "中文": "中文", + "Sample Scanner": "样本扫描仪", + "DEEP MANTLE FORGE COMPLEX": "深部地幔铸造复合体", + "Unable to finalize the purchase, please try again later or contact support if this error persists.": "无法完成购买,请稍后重试。如果问题仍未解决,请联系客服。", + "Select the game display mode. Fullscreen has the fastest response time, but may make switching to other applications slower.": "选择游戏的显示模式。全屏模式响应速度最快,但是可能会导致切换至其他应用程序的速度变慢。", + "UPGRADE EFFECT": "升级效果", + "On + Boost": "开启 + 增强", + "Adjusts the relative sensitivity of camera movement while aiming.": "调整瞄准时视角移动的相对灵敏度。", + "OK.": "确定", + "Some stratagems have unlimited uses, while others do not.": "部分战略配备拥有无限使用次数,而其他则是有限的。", + "Matchmaking Privacy": "匹配隐私", + "MOUSE & KEYBOARD": "鼠标及键盘", + "Please see the \"Information Pursuant to the Specified Commercial Transactions Act\" (https://www.playstation.com/ja-jp/legal/games/specified-commercial-transactions-act-jp/##helldivers2) for details on the timing and method of payment, delivery time of the product, application deadlines, and cancellation or withdrawal of an application.": "-", + "DELIVERY SYSTEM": "配送系统", + "Installs electronic actuators that augment the standard method of manual, foot-operated Hellpod steering.": "安装电子致动器,增强脚踏式手动转向型绝地喷射舱的标准操作。", + "OPEN COMMS WHEEL": "打开通信轮盘", + "FIREBOMB HELLPODS": "火焰炸弹绝地喷射舱", + "Authorizes hazard pay for pit crews, allowing them to reload the Eagle Fighter in-spaceflight.": "批准向维修人员支付危险津贴,以便他们放心在航天飞行期间重新武装“飞鹰”战斗机。", + "In addition to restoring health, Stims temporarily increase movement speed and damage reduction.": "治疗剂除恢复生命值以外,还可以暂时提升移动速度和伤害减免。", + "Decreases Support Weapon stratagem cooldown by #VALUE%.": "支援武器战略配备的冷却时间缩短#VALUE%。", + "Super Credits": "超级货币", + "Gives Helldivers a #VALUE chance to retrieve twice the samples on sample pickup.": "绝地潜兵有#VALUE的几率可在拾取样本时获得双倍样本。", + "Mutual Friends": "共同好友", + "Applies the near-frictionless lubricant known as \"Super Jelly\" to sentry ring mounts, facilitating extremely smooth mechanical operation.": "被称为“超级果冻”的润滑剂近乎无摩擦力,将其涂抹在哨戒炮的旋转式支架上,机械操作将变得极为流畅。", + "Reloading discards the remaining rounds in your magazine.": "重新装填弹药会丢弃弹匣内所有剩余弹药。", + "BASIC": "基础", + "ZOOM OUT": "视角拉远", + "The former site of the Xenoentomology Center, destroyed by the Terminids. Many scientists were horrifically massacred in the unprovoked attack.": "异星昆虫学研究中心遗址,被终结族摧毁。在这次无端袭击中,许多科学家遭到惨绝人寰的屠杀。", + "HIDDEN": "隐藏", + "Controller Sticky Aim": "控制器粘滞瞄准", + "EXPERT EXTRACTION PILOT": "专业撤离飞行员", + "Use Async Compute": "使用异步计算", + "Mouse Map Sensitivity": "鼠标地图灵敏度", + "VEHICLE CUSTOMIZATION": "载具自定义", + "DROP SUPPORT WEAPON": "放下支援武器", + "Eagle strikes fire at enemies.": "“飞鹰”空袭向敌人猛烈开火。", + "Provides minor damage reduction from all sources for all Helldivers.": "为全体绝地潜兵提供轻微的减伤效果(伤害来源不限)。", + "June": "6月", + "UNAPPLIED CHANGES": "未应用更改", + "Controls the quality of the scene lighting calculation": "控制场景光照计算质量", + "Z- AXIS": "Z-轴", + "FRANÇAIS": "FRANÇAIS", + "Narrates menus, popups and incoming chat messages.": "朗读菜单、弹出窗口和接收的聊天消息。", + "Space Quality": "太空画质", + "PLANETARY BOMBARDMENT": "星球轰炸", + "Framerate targeted by Dynamic Resolution Scaling.": "动态分辨率缩放调整达到的帧率。", + "ORDER DETAILS": "指令详情", + "Reticle Color": "准星颜色", + "AMD Anti-Lag 2": "AMD Anti-Lag 2", + "Select the visibility of vehicle info during gameplay.": "选择游戏过程中的载具信息可视度。", + "Selects the text to speech narrator voice type": "选择文字转语音的旁白声音类型", + "Remember Aim Mode": "记住瞄准模式", + "Invert Scope (Horizontal)": "开镜视角翻转(水平)", + "This player is currently your friend on Xbox network and/or other Helldivers 2 platforms. They must be removed from your friends list on those services before they can be removed from your in-game friend list.": "该玩家目前是你在Xbox 网络和/或其他《Helldivers 2》平台的好友。必须先将其从这些服务平台的好友列表中删除,然后才能从游戏内的好友列表删除该玩家。", + "November": "11月", + "Orbital HE barrage spread reduced by #VALUE%.": "轨道高爆弹火力网覆盖面减少#VALUE%。", + "Very authentic and easy to put on. I am very satisfied!": "货真价实,穿脱便捷。我很满意!", + "NEW FRIEND REQUEST": "新好友申请", + "SHORT": "短", + "Extensive mining and drilling operations are taking place to comb this former Hive World for all traces of the highly valuable substance known as E-711.": "目前大规模采矿与钻探作业正在进行,旨在从这个前虫窝世界的地方找到高价值物质711元素的踪迹。", + "INVITE ONLY": "仅限邀请", + "VOICE CHAT ACTIVATION": "启动语音聊天", + "HUD Background Opacity": "HUD背景不透明度", + "WEAPON FUNCTION 3": "武器功能3", + "Players can be reported if they have written something in chat that breaches the terms of service. This player has no chat messages to include in a report.": "如果玩家在聊天中发表了违反服务条款的内容,可将其举报。此玩家没有可举报的聊天信息。", + "Inverts left and right of camera direction.": "视角左右方向翻转。", + "Can't start this activity while in a mission": "正在执行任务,无法开启这项活动", + "Missions are filled with unexplored points of interest. Check them out—you never know what you might find.": "任务过程中有许多未经探索的特殊地点。去看一看吧,或许你会发现些什么呢!", + "Screen Brightness": "画面亮度", + "GRAPH": "图表", + "This player is not associated with an ID on PlayStation™Network and cannot be moderated. You can take any of the following actions instead.": "这位玩家没有关联PlayStation™Network上的ID,无法对其进行审核。你可以另行选择下列操作。", + "CROSSPLAY": "跨平台游玩", + "EVENT DETAILS": "战事详情", + "Assignment Notifications": "任务分派通知", + "Determines where the map is placed.": "设定地图所在位置。", + "Enables motion sensor controls while using a controller.": "使用控制器时启用动态感测器控制项。", + "Having trouble spreading Democracy in the darkness? Some weapons include top-of-the-line illumination aids. Hold \"Reload\" to turn them on!": "在黑暗中难以传播民主?部分武器配有尖端照明辅助设备,按住“装填弹药”键即可开启照明!", + "February": "2月", + "STUN PODS": "眩晕喷射舱", + "The Illuminate monoliths on this planet use Dark Fluid to affect the gravity of other celestial bodies.": "该星球上的光能者巨石利用暗液体影响其他天体的引力。", + "Adjusts the sensitivity of map movement.": "调整地图移动的灵敏度。", + "Sample Extricator": "样本拯救者", + "FRIEND REQUESTS": "好友申请", + "OPEN MAP": "打开地图", + "#HUNDREDTHS:#MINUTES:#SECONDS": "#HUNDREDTHS:#MINUTES:#SECONDS", + "EMOTE OPTION D": "表情D", + "DOWN": "下", + "Don't die!": "别死!", + "Amazing quality. It even survived atmospheric re-entry... twice!": "品质过硬。甚至能顶住穿越大气层的损耗…而且是两次!", + "Remember: Freedom!": "牢记自由!", + "SQUAD INVITE": "小队邀请", + "Select quality level of reflections on certain surfaces. Higher settings allow for more accurate reflections but may affect performance.": "选择特定表面的反射质量等级。上调该设置可以提高反射的精确度,但是可能会影响性能。", + "CLASS 2 EXOSTORM": "2级异界风暴", + "If at first you don't succeed, dive, dive again. And again. And again. And again. And again. And again. And again. And again. And again. And again. And again. And again. And again. And again.": "如果你在一开始失败了,那就再度空投参战,不断空投。不断、不断、不断、不断、不断、不断、不断、不断、不断、不断、不断、不断、不断空投。", + "Patriot_251": "爱国者_251", + "AGREE & CONTINUE": "同意并继续", + "UPGRADE #MODULE FOR MORE": "升级#MODULE解锁更多", + "ORBITAL BLOCKADE": "轨道封锁", + "LEARN MORE": "了解更多", + "The Illuminate have erected more monoliths than usual on this planet.": "光能者在这颗星球上立起的巨石数量超乎寻常。", + "POST MATCH SURVEY": "战后调查", + "Look Sensitivity": "视角灵敏度", + "ENGINEERING BAY": "工程港", + "RADIAL MENU ABSOLUTE SELECTION": "圆盘菜单绝对选取", + "Bullying/Harassment": "霸凌/骚扰", + "There is a SEAF aircraft repair facility present on this planet.": "此星球上坐落着超级地球武装部队的飞行器维修设施。", + "The volume of the in-game sound effects.": "游戏内音效的音量。", + "SWITCH SEAT (PREVIOUS)": "切换座位(上一个)", + "No blocked players.": "没有被屏蔽的玩家。", + "QUICK WEAPON WHEEL RIGHT": "快速向右转动武器轮盘", + "Comms Wheel Visibility": "通信轮盘可视度", + "Allow Data Collection": "允许收集数据", + "Defamation": "诽谤", + "Set the default audio language spoken by characters.": "设置角色音频的默认语言。", + "Reduces cooldown time for all Stratagems by #VALUE%.": "所有战略配备的冷却时间缩短#VALUE%。", + "Help us build the best PlayStation® experience!\nWhen you play this game, Sony Interactive Entertainment collects data that is necessary to operate the game. \nIf you agree, Sony Interactive Entertainment may also collect data about your interaction with the game and errors that occur. This data will be used as explained in our privacy policy. \nYou can change this setting at any time to allow full or limited data collection.": "帮助我们打造PlayStation®最佳游戏体验!\n在您游玩本游戏时,索尼互动娱乐会收集本游戏运行所需的必要数据。\n如果您同意,索尼互动娱乐可能还会收集其他数据,以便了解您与游戏互动的方式以及期间发生的错误。这些数据的使用方式皆遵守我们的隐私政策。\n您可以随时更改该设置,选择提供全部或部分数据。", + "PORTUGUÊS (BR)": "PORTUGUÊS (BR)", + "No friend requests.": "没有好友申请。", + "Here, fresh-faced recruits learn what it takes to defend Super Earth and her values.": "面带稚气的新兵在这里学会如何捍卫超级地球及其价值观。", + "REQUEST REINFORCEMENT": "请求增援", + "Resolution": "分辨率", + "Download failed.\nTry again, or select a different language.": "下载失败。\n再试一次,或选择其他语言。", + "VISIBLE": "显示", + "OPEN VEHICLE FUNCTION WHEEL": "打开载具功能轮盘", + "PLATOON & FRIENDS": "特战排与好友", + "LEVEL #LEVEL": "#LEVEL级", + "NVIDIA Reflex Low Latency": "NVIDIA Reflex低延迟", + "TOGGLE LASER GUIDANCE SYSTEM": "切换激光制导系统", + "[Redacted]": "[已编辑]", + "All Stratagems have their strengths and weaknesses. Choose your Stratagem loadout to best fit the mission and your squad composition.": "战略配备全部各有优劣。要根据任务需要和小队阵容来挑选最合适的战略配备。", + "CHANGE SHIP NAME": "更改舰船名称", + "Mouse Smoothing": "鼠标平滑", + "The first manned site established in Gloom-infested space, standing steadfast against all forces who would tear it down.": "首个在“阴霾”侵蚀星域建立的人类驻军据点,仍然巍然屹立着抗击一切妄图将其摧毁的势力。", + "Impersonating developer": "冒充官方工作人员", + "Selectively lower resolution where detail is less necessary.": "在细节需求不高时,选择性降低分辨率。", + "You have reached the approved generosity limit. Please wait #HOURS h #MINUTES m before donating again.": "你已达到批准的捐赠上限。请在#HOURS小时#MINUTES分后再尝试。", + "CHANGE BINDINGS": "更改键位绑定", + "Removes stabilizing phlematizer agents from explosive material used to pack orbital shells, allowing for more powerful payloads.": "从装填轨道炮弹的炸药物质中移除稳定减敏剂,增强炮弹的威力。", + "INSPECT": "查看", + "Select the visibility of secondary objectives.": "选择次要目标的可视度。", + "Compass Visibility": "罗盘可视度", + "SEARCH": "搜索", + "Select the visibility of Stratagems during gameplay.": "选择游戏过程中的战略配备可视度。", + "An abundant source of E-711, carefully harvested by experienced hands.": "富含711元素,由经验丰富的采集人员精心开采。", + "Jun": "6月", + "Nine out of ten doctors agree that a wound to the chest will make you bleed out if unattended.": "九成医生一致认为,如果不处理胸部的伤口,你就会流血致死。", + "RIGHT": "右", + "Failed to find player.": "未能找到玩家。", + "Winganon_59": "温加农_59", + "BRIEFING TRANSMISSION": "简报通讯", + "SEPARATED": "独立", + "You are Super Earth's elite. Never forget that.": "你是超级地球的精英,时刻牢记这一点。", + "Stamina Width": "耐力槽宽度", + "Select quality profile.\nQuality targets the highest visual fidelity at a lower framerate.\nPerformance targets a higher framerate for a smoother experience at a lower rendering resolution.": "选择画质设置。\n“画质”会以降低帧率为代价,提供最逼真的视觉效果。\n“性能”会追求较高的帧率带来更顺畅的体验,但是会降低渲染分辨率。", + "When you're up against the bots, remember the 3 Cs:\nCover, Courage, and more Cover.": "对抗机器人要牢记三大准则:\n找掩体,要勇敢,然后继续找掩体。", + "The DSS fires nonstop orbital bombardments from its suite of 77 PRESIDENTIAL-Class Cannons, providing planetwide artillery support and accelerating liberation efforts. Temporarily, also increases Reinforcement Budget by +1 per squad member and augments all loadouts with FX-12 Shield Generator Relay Stratagem.": "民主空间站利用其77门总统级加农炮不间断地进行轨道轰炸,为整个星球提供炮火支援,加速解放进程。同时提高增援预算,每位队员增援+1,此外利用“FX-12防护罩生成中继器”战略配备强化所有武装配置。", + "HAND CARTS": "手推车", + "If enabled, crossplay allows you to play with players on other platforms.": "启用跨平台游玩后,你可以和其他平台的玩家一起游戏。", + "The following stratagems can now be purchased from the stratagems tab:": "现可从战略配备页面购买以下战略配备:", + "Pay attention to these tips. They've been carefully calibrated to ensure your success.": "请认真阅读提示。这都是精心总结的经验,能确保你夺得成功。", + "繁體中文": "繁體中文", + "Reticle Visibility": "十字线可视度", + "Available in: #DAYS d #HOURS h": "就位倒计时:#DAYS天#HOURS小时", + "USE BACKPACK FUNCTION": "使用背包功能", + "HIVE WORLD": "虫窝世界", + "As a last resort, you can use melee attacks to fend off enemies. Remember: death is better than cowardice!": "万不得已时,近战攻击是你对抗敌人的最后手段。要记住:苟且偷生不如慷慨赴死!", + "Support weapons have long cooldown periods. Make sure to retrieve them should the wielder die.": "支援武器冷却时间较长。使用者阵亡以后,务必将其取回。", + "ROBOTICS": "机械", + "EAGLE STORM": "“飞鹰”风暴", + "#COUNT / #TOTAL": "#COUNT / #TOTAL", + "When enemy infrastructure is in need of destruction, Super Earth helpfully provides a Hellbomb stratagem to all Helldivers, free of charge.": "如果有敌方的基建亟需摧毁,超级地球会施以援助,为所有绝地潜兵提供一枚地狱火炸弹,不收取任何费用。", + "SUBMIT": "提交", + "Illuminate": "光能者", + "Stun Pods": "眩晕喷射舱", + "THANK YOU FOR REPORTING!": "感谢你的举报!", + "The degree to which the aim sticks to a target when passing over it.": "准星经过目标时附着在目标上的程度。", + "Reticle Outline": "准星轮廓", + "The Galactic War is a united effort. Only by working together can we ensure planets don't fall to the enemy.": "星系战争是我们共同的责任。只有团结一致,才能确保我们的星球不会落入敌人手中。", + "Determines how voice chat transcription is used. Available options:\nOff: No voice chat transcription \nIncoming only: Transcribe incoming voice chat as text\nOutgoing only: Outgoing voice chat is synthesized from text\nFull: Combines both of the previous options": "决定语音聊天转录的使用方式。可用选项:\n关闭:不启用语音聊天转录\n仅输入:将输入设备的语音聊天转录为文字\n仅输出:根据文字合成语音聊天,从设备中输出\n完整功能:结合以上两个选项", + "DECLINE": "拒绝", + "Season ends in: #DAYS Days #HOURS Hours": "赛季倒计时:#DAYS天#HOURS小时", + "The volume of the in-game music.": "游戏内音乐的音量。", + "Apr": "4月", + "ULTRAMAFIC MINE": "超镁铁矿井", + "VITALITY ENHANCEMENT": "生命力强化", + "AVAILABLE IN: #DAYS d #HOURS h": "就位倒计时:#DAYS天#HOURS小时", + "VOTING FAILED": "投票失败", + "ITEM OWNED": "已拥有物品", + "Select the visibility of the grid lines in the top compass.": "选择顶部罗盘的网格线可视度。", + "TURN LEFT": "左转", + "Use Stims to heal your injuries and replenish your stamina—or that of your fellow Helldivers, in a pinch!": "使用治疗剂可治疗伤势,补充耐力。危急关头,也可以救助绝地潜兵同伴!", + "Triggers after a button has been pushed down for a set amount of time.": "按下按键一定时间后触发操作。", + "SEAF MILITARY OUTPOST": "超级地球武装部队军事哨站", + "Adjusts the intensity of the curved visual effect applied to the Heads Up Display (HUD).": "调整抬头显示(HUD)的弧形视觉效果的强度。", + "Select the visibility of the injury widget during gameplay.": "选择游戏中的伤势轮盘可视度。", + "We are Sony Interactive Entertainment. Please see our privacy policy for further information on how we collect and process your Personal Information, and how to contact us at www.playstation.com/legal/privacy-policy.": "我们是索尼互动娱乐有限公司。有关我们如何收集和处理你的个人信息以及如何通过 www.playstation.com/legal/privacy-policy与我们联系,请参阅我们的隐私政策了解详情。", + "Adjusts the position of the HUD relative to the edge of your screen.": "调整HUD与屏幕边缘的相对位置。", + "NEW DIFFICULTY LEVEL": "新难度", + "HYBRID": "混合", + "Mission Info Visibility": "任务信息可视度", + "Next Location (Current Majority Vote):": "下个地点(当前多数得票):", + "Choose whether you go into matchmaking with other players on the network when looking for a game, or whether you keep your session private and between friends.\n\nNOTE: The \"Invite Only\" setting only works with invites sent from the in-game menu": "选择匹配寻找游戏时是公开匹配在线玩家,还是只和好友匹配。\n\n注意:“仅限邀请”设置只适用于从游戏内菜单发起的邀请", + "Fire damage from Stratagems increased by #VALUE%.": "战略配备造成的灼烧伤害提高#VALUE%。", + "This planet shows clear signs of Illuminate construction.": "光能者的建筑活动迹象在该星球明显可见。", + "My wife said it's this or her. She will be missed.": "我老婆说我买了她就走人。那只能好走不送了。", + "REVOLVING CYLINDERS": "旋转弹巢", + "Most enemies have both weak spots and armored spots. The SEAF training manual recommends aiming for the weak spots.": "大多数敌人既有弱点也有披甲部位。超级地球武装部队训练手册建议你瞄准弱点进行攻击。", + "PLATOON": "特战排", + "Select the graphics device that will be used to render the game. This should normally be set to the highest performance graphics device in your system.": "选择用于渲染本游戏的图形设备。通常应将此项设置为系统内性能最高的图形设备。", + "LINK": "绑定", + "Oct": "10月", + "Sound Effects Volume": "音效音量", + "Excessive Vulgar Language": "言辞过分粗俗", + "Switch Weapon On Pickup": "武器即捡即用", + "This setting will only take effect after restarting the game": "该设置必须重启游戏才能生效", + "AIMING": "瞄准", + "Booster": "强化资源", + "POWER STEERING": "电动转向", + "FamllyMan123": "固家男人123", + "OPEN DROP WHEEL": "打开弃置轮盘", + "Are you sure you want to use your vote?": "确定要投票吗?", + "Z+ AXIS": "Z+轴", + "VOTELESS PROCESSING PLANT": "无票者转化处理厂", + "Reduces Eagle Rearm time by #VALUE%.": "“飞鹰”重新武装的时间缩短#VALUE%。", + "A new fleet of Super Destroyers is under construction here.": "这里正在打造超级驱逐舰的新舰队。", + "Off: Aiming always starts in third person view aim mode. \nGlobal: All weapons use the last selected aim mode.\nPer Weapon: The last used aim mode is stored per weapon.": "关:始终默认为第三人称瞄准模式。\n全局应用:所有武器都会使用玩家最后选择的瞄准模式。\n视武器而异:每件武器都会使用玩家上一次使用这件武器时选择的瞄准模式。", + "Increases the number of available reinforcements.": "增加可用增援次数。", + "The Ministry of Science is responsible for continuous scientific progress, augmenting our moral superiority over our enemies with technological superiority.": "科学部负责不断推动科技进步,利用技术优势增强我们压倒敌人的道德优越感。", + "Failed to retrieve blocked players.": "未能检索已屏蔽的玩家。", + "PRICE:": "价格:", + "Inverts up and down of camera direction.": "视角上下方向翻转。", + "ACCOUNT LINK STATUS": "关于账户绑定状态", + "Veteran Controller Mode": "老兵控制器模式", + "If you play one of our games, we will always access data from and/or store data on the device that you are using. This data is necessary to deliver our games, and includes:\n• Content Data: Game content data, such as video, audio, graphic, text, and game level information that is requested and downloaded for the game that you are accessing online. If you are playing an online game, this includes your online interactions as necessary to reflect those interactions on our game servers.\n• Account Data: Information required to sign you into your account. \n• Configuration Data: Information about the configuration of your device and the game you are playing , such as the device date, time and language settings and your in-game preference and settings. \n• Security Data: Information necessary to detect and investigate malicious, unauthorized or fraudulent activity.\n• Legal Data: Information required by applicable law and to demonstrate compliance.\nIf you agree, we may collect more detailed information about how you interact with our games.\nThis may include when and how you use the game’s user interface, which parts of the game you visit, which weapons you use, which characters you interact with and any errors that you encounter.\nGame Data is usually sent to us and stored with one or more unique network, device and/or account identifiers.": "在您游玩我们的游戏期间,我们需要一直处理您使用的设备的数据,并/或在您的设备上储存数据。这些数据是提供游戏服务的必要数据,包括:\n• 内容数据:访问在线功能时需要请求并下载的游戏内容数据,例如视频、音频、图像、文本及游戏关卡信息。如果您在线游玩,还将包括在线互动记录,以便游戏服务器处理这些互动操作。\n• 账户数据:您登录账户的必要数据。\n• 设置数据:所用设备以及所玩游戏的设置信息,例如设备日期、时间和语言设置、游戏内的偏好与设置。\n• 安全数据:检测及调查恶意、未经授权或作弊行为所需的必要信息。\n• 法律数据:适用法律所要求以及证明合规的信息。\n如果您同意,我们可能还会针对您与游戏互动的方式收集更详细的信息。\n该类信息可能包括您使用本游戏用户界面的时间与方式、体验过的游戏板块、使用过的武器、有互动的角色以及遇到的错误问题。\n游戏数据通常会发送给我们并使用一个或以上的专属网络、设备和/或账户标识符储存。", + "Failed to unfriend player.": "未能解除好友关系。", + "Switch between predefined graphics setting configurations.": "切换预定义的图像设定配置。", + "ROBOTICS WORKSHOP": "机械工坊", + "Inverts left and right control of mouse direction in First Person View (FPV).": "在第一人称视角(FPV)下,鼠标左右方向翻转。", + "Please see the \"Information Pursuant to the Specified Commercial Transactions Act\"\n(https://www.playstation.com/ja-jp/legal/games/specified-commercial-transactions-act-jp/##helldivers2)\nfor details regarding the timing and method of payment, delivery time of the product,\napplication deadlines, and cancellation or withdrawal of an application.": "-\n-\n-\n-", + "Select the desired anti-aliasing and upscaling algorithm. These are used to provide improved visuals as well as to improve performance. This includes TAA, NVIDIA DLSS, AMD FSR and Intel XeSS, if supported.": "选择所需的抗锯齿与增强算法模式。这些技术用于提升画质并改善游戏性能。包括TAA、NVIDIA DLSS、AMD FSR以及Intel XeSS(如果设备支持)。", + "NEGATIVE ENERGY LABORATORY": "负能量实验室", + "MORE GUNS": "增强枪炮火力", + "Select the visibility of the stamina bar during gameplay.": "选择游戏过程中的耐力槽可视度。", + "DEEP MANTLE FORGE COMPLEX (DESTROYED)": "深部地幔铸造复合体(遗址)", + "Render Distance": "渲染距离", + "GRAVITATIONAL ANCHOR": "引力锚点", + "Invert Look (Vertical)": "视角翻转(垂直)", + "Primary Objective Visibility": "主要目标可视度", + "The Meridian Wormhole was created by the Illuminate and wielded to destroy entire planets and threaten Super Earth itself. Here, authorized visitors may view the destructive singularity and remind themselves why our enemies deserve total annihilation.": "默里迪恩虫洞出自光能者之手,用于摧毁整颗星球,一度威胁到超级地球。在此,获准访客可观摩毁灭性奇点,提醒自己我们的敌人为何应被彻底歼灭。", + "#PLAYER sent a friend request!": "来自#PLAYER的好友申请!", + "The glory of Super Earth is mirrored in it's production value!": "它的产品价值映照出了超级地球的荣光!", + "Quality is out of this world! Sometimes I put it on just to wear around the house.": "质量真是没的说!有时候穿起来只是为了在家附近逛逛。", + "Atmospheric Lighting Quality": "氛围光照质量", + "Off (Diagnostics)": "关(诊断)", + "Jan": "1月", + "Destroyer Marker Visibility": "驱逐舰标记可视度", + "The Ministry of Truth analyzes citizens' activity, speech, data, DNA, RNA, and neural topology here.": "真理部在这里分析公民的活动、言论、数据、DNA、RNA和神经拓扑结构。", + "Music Volume": "音乐音量", + "SPREAD": "散射", + "LEG-MUSCLE ENHANCERS": "腿部肌肉强化", + "NEW MISSION DIFFICULTY AVAILABLE": "已开放全新任务难度", + "GLOOM RESEARCH FACILITIES": "“阴霾”现象研究设施", + "EMOTE OPTION C": "表情C", + "Vertically enhanced Jet Brigade soldiers are produced here.": "经过垂直强化的喷气旅士兵就在这里出产。", + "MOTIVATIONAL SHOCKS": "激励性冲击", + "Requires Level #COUNT": "需要达到等级#COUNT", + "Orbital stratagem cooldown time reduced by #VALUE%.": "轨道战略配备的冷却时间缩短#VALUE%。", + "LOOK UP": "向上看", + "Nameplate Visibility": "名牌可视度", + "HEADLIGHTS MODE": "大灯模式", + "The number of Voteless on this planet appears to increase more quickly than on other planets.": "该星球无票者的增速似乎高于其他星球。", + "GAME": "游戏", + "Never": "从不显示", + "Game Data is used as explained in our Privacy Policy (www.playstation.com/legal/privacy-policy).\n\nThis includes use of Game Data to:\n• Provide you with our games.\n• Understand the usage and performance of the game you are playing, and to develop improvements to the game.\n• Develop new products and services.\n• Detect, investigate, and minimise malicious, unauthorised or fraudulent behaviour.\n• Audit, compliance and legal purposes (for example, making or defending claims or activities that are required to comply with a law).": "我们将按隐私政策(www.playstation.com/legal/privacy-policy)的规定使用游戏数据。\n\n游戏数据的用途包括:\n• 为你提供游戏服务。\n• 了解你正在玩的游戏的使用情况和性能,并改良游戏体验。\n• 开发新产品和服务。\n• 检测和调查恶意、未经授权或欺诈的行为,并将这些情况的出现次数降至最低。\n• 审计、合规和法律用途(如提出索赔或为索赔辩护,或为遵守法律规定开展活动)。", + "NEW SHIPMENT OF ITEMS IS INCOMING...": "全新商品即将上架…", + "Bloom Quality": "全屏泛光质量", + "STRONG": "强", + "XeSS": "XeSS", + "/ #TOTAL": "/ #TOTAL", + "ABOUT GAME DATA": "关于游戏数据", + "Motion Sensor Acceleration": "动态感测器加速", + "PLACE MARKER": "放置标记", + "SOUNDBAR": "回音壁", + "Purchases permanent access to ammo provided by the \"Support Our Heroes\" fund, which allows patriotic family members to donate supplies to their loved ones in the field.": "购买由“支援英雄”基金会提供的弹药的永久使用权。爱国的家庭成员可通过该基金会向战场上的亲人捐赠物资。", + "Those who study Terminid behavior, ecology and E-710 potential gather here for cross-disciplinary research.": "研究终结族行为、生态学以及710元素潜能的学者在此汇集进行跨学科研究。", + "Mine arrived with some real sweat of heroes still inside it!": "收到货时,里面甚至还残留英雄的汗水!", + "Text To Speech Volume": "文字转语音的音量", + "HELLDIVERS CLASSIC": "HELLDIVERS 经典", + "Golf_Dad22": "高尔夫_大爹22", + "Exostorm fronts are coalescing into a dense system that threatens to engulf the entire planet.": "异界风暴锋面正在汇聚,形成质密的风暴系统,恐将吞噬整颗星球。", + "ULTRA QUALITY": "超高画质", + "Y+ AXIS": "Y+轴", + "ZOOM IN": "视角推近", + "Hint Visibility": "提示可视度", + "#COUNT / #TOTAL STREAK": "#COUNT / #TOTAL次连续击杀", + "Day and night sides of a planet are visible during mission selection, allowing you to choose the mission that's right for you!": "选择任务时你可以根据星球上的昼夜区域挑选合适的任务!", + "Motion Sensor Steadying Amount": "动态感测器稳定量", + "Unhappy with who you are? Change your appearance and voice in the customization chamber. It's that easy!": "想要改变自己?前往自定义房间,更改外貌和声音。一切就是那么简单!", + "Display Surveys": "显示调查", + "Select the visibility of teammate direction during gameplay.": "选择游戏中的队友方位可视度。", + "CROSS-PLATFORM COMPATIBILITY": "跨平台兼容", + "Drop Wheel Visibility": "弃置轮盘可视度", + "Increases ammo for all Sentry stratagems by #VALUE%.": "所有哨戒炮战略配备的弹药量增加#VALUE%。", + "Max Frame Rate": "最大帧率", + "Super Earth Ministry of Truth": "超级地球真理部", + "Here, citizens in well-insulated worksuits operate facilities liberated from the Automatons, and repurposed to sustainably extract rare materials from the highly volcanic planet.": "在这里,身着强隔热工作服的公民操作着从机器人手中解放出来的设施。这些设施经过改造,能够在这颗火山活动频繁的星球上可持续地开采稀有资源。", + "AVAILABLE AT LEVEL #RANK": "达到级别#RANK时开放", + "PLAYER CARD": "玩家名片", + "Super Earth thanks you for your generous support of Managed Democracy.": "超级地球感谢你对管理式民主的慷慨支援。", + "INTEGRATED EXTINGUISHERS": "集成灭火器", + "DONATION LIMIT REACHED": "已达到捐赠上限", + "It will feel like you're out there, fighting beside them from your home!": "你会感觉虽然身在家中,心却在前线和他们并肩作战!", + "PER WEAPON": "视武器而异", + "Teammate Direction Visibility": "队友方位可视度", + "HUD HIDDEN": "隐藏HUD", + "Stratagem Permit": "战略配备许可证", + "Inverts up and down control of mouse direction.": "鼠标上下方向翻转。", + "Use the Eagle Rearm stratagem during calmer periods to ensure you have those Eagle Strikes available when you need them.": "在比较空闲的时段使用重新武装“飞鹰”的战略配备,可以确保关键时刻你能呼叫“飞鹰”空袭。", + "ADVANCED": "高级", + "DONE": "已完成", + "GLOOM RESEARCH EXPEDITION": "“阴霾”研究考察", + "Optimizes the audio experience for the device you are listening on.": "优化你使用的音频设备的听觉体验。", + "Don't drink and drive.": "喝酒不开船。", + "StarfQtr_97": "星战之_97", + "BALANCED": "平衡", + "OWNED": "已拥有", + "SWITCH CAMERA SIDE": "视角换边", + "Mouse Scope Sensitivity": "鼠标开镜灵敏度", + "LOW": "低", + "Vegetation and Rubble Density": "植被与碎石密度", + "ATMOSPHERIC MONITORING": "大气监测", + "MAP ONLY": "仅在地图显示", + "ADVANCED CONSTRUCTION": "高级构造", + "EMERGENCY LIGHTS": "应急照明", + "WEAPONRY": "武器", + "Stamina Visibility": "耐力槽可视度", + "Authorizes an 8-week crew training course in Superior Packing Methodology (SPM), resulting in increased supply box capacity.": "授权开展为期8周的高级装填法(SPM)船员培训课程,从而提高补给箱容量。", + "Offensive - Discrimination": "冒犯性 - 歧视", + "DrSpindleshanks": "长腿博士", + "Eagle Rearm cooldown further reduced by #VALUE% if called in while Eagle uses still remain.": "在“飞鹰”仍有使用次数时,如果呼叫“飞鹰”,重新武装的冷却时间缩短#VALUE%。", + "Select the level of quality for particle effects.": "选择粒子效果的质量等级。", + "When on, automatically adjusts render resolution to achieve target framerate.": "开启后将自动调整渲染分辨率以达到目标帧率。", + "Interaction Visibility": "互动可视度", + "NORSK (Unsupported)": "NORSK (Unsupported)", + "DEUTSCH": "DEUTSCH", + "FRIENDS": "好友", + "Reduces the dynamic range of in-game audio. Beneficial if you are listening at a low volume, quiet sounds become louder.": "缩小游戏内音频的动态范围。有利于低音量的玩家,因为较轻的声音会变响。", + "GRENADE BANDOLIERS": "榴弹背带", + "Enemy resistance on this Hive World is lowered.": "这个虫窝世界的敌军抵抗强度降低。", + "E-711 EXTRACTION FACILITY": "711元素开采设施", + "Language": "语言", + "PORTUGUÊS (PT)": "PORTUGUÊS (PT)", + "Reduces damage falloff from center of explosions caused by orbital Stratagems.": "轨道战略配备引爆后从中心向外扩散的伤害衰减有所下降。", + "Nov": "11月", + "On this planet is one of 3 Maximum Security Cities: impregnable bastions against Tyranny.": "三大最高安全级别城市之一坐落在这颗星球上:这是对抗暴政的堡垒,坚不可摧。", + "Installs a revolving cylinder loading system, with each chamber housing a different ammunition type.": "安装旋转弹巢装填系统,每一个弹膛都装载一种不同的弹药。", + "Target Framerate": "目标帧率", + "150 SC": "150超级货币", + "Trigger Effect Strength": "扳机效果强度", + "Graphics API": "图形API", + "MENU": "菜单", + "HUB OF INDETERMINATE PURPOSE": "用途不明的中心", + "CHAT ONLY": "仅聊天", + "WEAK": "弱", + "Pending...": "正在等待…", + "EXTREME TEMPERATURE EXTRACTION PLANT": "极温开采厂", + "SPECTATE PREVIOUS": "观战上一个玩家", + "UNLINK": "解除绑定", + "SHIP PROGRESSION": "舰船进度", + "PREVIEW WEAPON": "预览武器", + "BODY ARMOR": "躯体盔甲", + "This setting modifies the resolution of the volumetric clouds to render a more realistic sky.": "该设置可调整体积云的分辨率,进而渲染出更逼真的天空。", + "Fills cockpits with breathable liquid perfluorocarbons, which absorb g-forces and thereby enable pilots to conduct tighter turns without losing consciousness.": "在驾驶舱内填充可呼吸的液态全氟化碳,以便吸收重力,使驾驶员能够完成更急促的转向且不会失去知觉。", + "OUTGOING ONLY": "仅输出", + "INSUFFICIENT SUPER CREDITS": "超级货币不足", + "ARMED RESUPPLY PODS": "武装重新补给舱", + "Augments electrical weaponry by safely connecting multiple interior arc extenders into one long linear chain.": "可通过安全方式将多个内部电弧扩展器连接成线性长链,起到增强电子武器威力的作用。", + "This planet appears to have been monstrously transformed by the Terminids. It may be a source of Gloom spores. Exercise caution.": "这颗星球似乎遭到了终结族骇人的改造。有可能变成“阴霾”孢子的来源。务必小心行事。", + "Adjusts how quickly acceleration is applied to the wireless controller camera control. If set to zero, the movement is linear.": "调整无线控制器操控视角的加速生效速度。设置为零则视角线性移动。", + "OPEN CHAT": "开启聊天", + "DYNAMIC TRACKING": "动态追踪", + "Flexible Reinforcement Budget": "灵活增援预算", + "Vitality Enhancement": "生命力强化", + "The account link failed, please try again.": "账户绑定失败,请重试", + "Check your Ammo by holding the Reload button.": "按住装填弹药按钮查看弹药数量。", + "NUCLEAR RADAR": "核动力雷达", + "Text To Speech": "文字转语音", + "QUICK THROWABLE": "快速投掷武器", + "WEAPON FUNCTION 2": "武器功能2", + "High Dynamic Range": "高动态范围", + "The facilities on this planet help the Illuminate turn citizens into Voteless.": "光能者在这颗星球上利用这类设施将公民转化为无票者。", + "Copyright": "版权", + "ALWAYS": "常驻", + "On this planet, the Ministry of Science’s best and brightest work on their next breakthrough.": "在此星球上,科学部的顶尖人才正在全力推动下一项突破。", + "Remember to fill in your C-01 permit before any act that could result in a child.": "进行可能产生孩子的行为之前,记得先填好C-1授权表格。", + "TARGETING SOFTWARE UPGRADE": "目标瞄准软件升级", + "UNBIND INPUT": "解绑键位", + "#DAYS Days Left": "还剩#DAYS天", + "XENOENTOMOLOGY CENTER (DESTROYED)": "异星昆虫学研究中心(遗址)", + "AVAILABLE IN: #HOURS h #MINUTES m": "就位倒计时:#HOURS小时#MINUTES分", + "PAYROLL MANAGEMENT SYSTEM": "薪金管理系统", + "RESET CAMERA LOOK": "重置视角", + "When the mission timer runs out, the Super Destroyer will leave low orbit and you'll lose access to stratagems and reinforcements.": "任务倒计时结束后,超级驱逐舰就会离开低空轨道。之后,你无法再使用战略配备,也无法呼叫增援。", + "Enable High Dynamic Range (HDR) to your monitor or TV. This can only be enabled on supported devices.": "在你的显示器或电视上启用高动态范围(HDR)。受支持的设备才能启用此设置。", + "STEAM DECK™": "STEAM DECK™", + "DONATION SUCCESSFUL": "捐赠成功", + "LONG PRESS": "长按", + "A limited-time expedition is being conducted into the Gloom on this planet, at significant cost.": "该星球上正在开展限时“阴霾”探索行动,代价巨大。", + "SUPER GLOOM BASE BRAVO": "超级“阴霾”布拉沃基地", + "Acceleration Exponent": "加速指数", + "Scan the QR code or press the button below to begin linking your accounts from Steam and PlayStation™Network": "扫描二维码或按下方按键即可开始将你的Steam账户与PlayStation™Network账户绑定", + "Increased Reinforcement Budget": "提高增援预算", + "ADVANCED GRAPHICS": "高级图像", + "Motion Sensor Steadying Transition Duration": "动态感测器稳定过渡持续时间", + "Screen-Space Reflections": "屏幕空间反射", + "ADVANCED SETTINGS": "高级设置", + "SUPERSAMPLING": "超级采样", + "All Sentry stratagems launch immediately once called in, reducing overall deployment time.": "所有哨戒炮战略配备在呼叫后即时发射,缩短整体部署时间。", + "Reloading...": "正在装弹……", + "#COUNT BONUS SC": "#COUNT额外超级货币", + "JOG": "小跑", + "Sample Count Visibility": "样本数量可视度", + "NO SPECIAL TRAITS": "无特殊特性", + "DLSS": "DLSS", + "The Ministry of Prosperity manages Super Earth's economy and ensures a steady flow of resources to the most deserving.": "繁荣部负责管理超级地球的经济,确保资源能够源源不断地流往最有价值的地方。", + "RAPID LAUNCH SYSTEM": "疾速发射系统", + "Integrates moderate doses of amphetamines and androgenic steroids into diet of loading crew, leading to increased pace, focus, & stamina, among other effects.": "将适量安非他明和雄激素类固醇加入船员的饮食中,获得各方面的提升效果,包括速度、专注力和耐力等。", + "Player Marker Visibility": "玩家标记可视度", + "No friends, yet.": "暂时还没有好友。", + "On this planet, workers are constructing one of 3 Maximum Security Cities: impregnable bastions against Tyranny.": "工人正在这颗星球上建设三大最高安全级别城市的其中一座:这是对抗暴政的堡垒,坚不可摧。", + "x_Roocketman_x": "x_火箭新手_x", + "Object Detail Quality": "物体细节质量", + "FSR4": "FSR4", + "The Super Store is currently undergoing maintenance, and is unavailable. Please try again later. Thank you for your understanding.": "超级商店正在进行维护,暂时无法使用。请稍后再试。感谢你的理解。", + "COMBAT": "战斗", + "HIGHLIGHT": "高亮", + "OUTPOST ALPHA": "阿尔法哨站", + "Text Language": "文本语言", + "B1qBeefEater": "大囗吃牛肉", + "Resupply Stratagem boxes refill Support Weapons with the maximum number of carriable magazines.": "“重新补给”战略配备的补给箱为支援武器补充的可携带弹匣数增加至最大数量。", + "OPEN EMOTE WHEEL": "打开表情轮盘", + "Good for stealth. Bad for enemy.": "潜行好助手。敌人的噩梦。", + "NO BOOSTER": "无强化资源", + "Borderless Window": "无边框窗口", + "Failed to block player.": "未能屏蔽玩家。", + "Inappropriate Online ID": "不得体的在线ID", + "STAY": "原地待命", + "NORMAL": "普通", + "PRIMARY WEAPON": "主要武器", + "QUICK WEAPON WHEEL UP": "快速向上转动武器轮盘", + "Select the width of the compass.": "选择罗盘宽度。", + "Frame buffering": "帧缓冲", + "CHANGE CAMERA MODE": "更改视角模式", + "I bought this for my husband and he loves it.": "我给我老公买了这个东西,他非常满意。", + "December": "12月", + "Reduces call-in time for all orbital stratagems by#VALUE seconds.": "所有轨道武器战略配备的呼叫时间缩短#VALUE秒。", + "OPEN STRATAGEM LIST": "打开战略配备列表", + "NEW ASPIRATION CONSTRUCTION SITE": "志向新城建造区", + "POLSKI": "POLSKI", + "XENOENTOMOLOGY CENTER": "异星昆虫学研究中心", + "Increases number of Eagle stratagem uses per Rearm by #VALUE.": "每次重新武装后,“飞鹰”战略配备的可使用次数增加#VALUE次。", + "DROP BACKPACK": "放下背包", + "Invert Mouse (Vertical)": "鼠标翻转(垂直)", + "Mouse Acceleration": "鼠标加速", + "DYNAMIC": "动态", + "SWITCH AIM SIDE": "瞄准换边", + "Unable to authenticate your account on PlayStation™Network, please try again later or contact support if this error persists.": "无法验证你的PlayStation™Network账号,请稍后重试。如果问题仍未解决,请联系客服。", + "Default": "默认", + "Great for camping trips with the kids! A bit heavy for them though.": "很适合跟孩子野营的时候用!虽然对他们来说稍微有点重了。", + "SKIP DIALOGUE": "跳过对话", + "Bugs": "虫族", + "INSUFFICIENT FUNDS": "资源不足", + "Inverts left and right of camera direction in First Person View (FPV).": "在第一人称视角(FPV)下,视角左右方向翻转。", + "The player has no messages in the chat so they cannot be reported. You can take any of the following actions instead.": "这位玩家没有在聊天中发送消息,无法举报。你可以另行选择下列操作。", + "INVITE TO SQUAD": "邀请入队", + "CURRENT CUSTOMIZATION": "当前自定义", + "Remember Weapon Functions": "记住武器功能", + "Account Not Linked": "未绑定账户", + "If the problem persist contact support.": "如果问题仍未解决,请联系客服。", + "I already own one but I bought it again to support our heroes out there!": "我已经有一件了,但为了支持前线的英雄,我又买了一件!", + "Ship Module": "舰船模块", + "SUB-OBJECTIVE": "次要目标", + "1,500 SC": "1,500超级货币", + "DROP NEXT INVENTORY ITEM": "放下下一件物品", + "TAA": "TAA", + "Localization Confusion": "定位混淆", + "ARMOR PASSIVE": "盔甲被动加成", + "Hellpod Space Optimization": "绝地喷射舱空间优化", + "The DSS Logistics Armada supplies all Super Destroyers orbiting the planet with surplus 380mm shells. Ordnance support is also provided to SEAF operations, accelerating liberation efforts.": "民主空间站后勤舰队为环绕星球的各艘超级驱逐舰提供富余的380mm爆弹。超级地球武装部队的行动也将获得军械支援,从而加速解放进程。", + "You can tell by just touching it, that this was made for real heroes.": "摸一摸就能感觉到这是给真英雄打造的。", + "Faction": "阵营", + "LARGE": "大", + "PLAYER INTERACTION": "玩家互动", + "SHIP MODULE UNLOCKED": "舰船模块已解锁", + "Weapons like pistols and submachine guns can be used with one hand—perfect for when you need to carry objects in the other hand.": "手枪和冲锋枪等武器是可以单手使用的,非常适合在另一只手执物体时使用。", + "BAHASA INDONESIAN (Unsupported)": "BAHASA INDONESIAN (Unsupported)", + "Select the resolution of textures. Higher settings provide more detail at the cost of memory (VRAM) and performance. This is the primary setting to adjust on devices with lower than recommended VRAM. Recommended VRAM for each setting:\nUltra - 10GB\nHigh - 8GB\nMedium - 6GB\nLow - 3GB": "选择贴图分辨率。较高的选项可以提供更加细致的图像,但是会占用显存(VRAM),影响性能。在VRAM未达到推荐值的设备上,这是首先需要调整的设置选项。各项设置推荐VRAM:\n超高 - 10GB\n高 - 8GB\n适中 - 6GB\n低 - 3GB", + "Screen Device": "屏幕设备", + "Linking your Steam account to a PlayStation™Network account is required for playing the game.": "如需游玩该游戏,请将你的Steam账户与PlayStation™Network账户绑定。", + "Bloom Strength": "全屏泛光强度", + "The threshold at which the cursor movements stop increasing in speed.": "光标停止提高移动速度的阈值。", + "October": "10月", + "UNLIMITED": "无限", + "All": "全部", + "Available in: #HOURS h #MINUTES m": "就位倒计时:#HOURS小时#MINUTES分", + "Review under investigation for treason": "该评论涉嫌叛国,正在接受调查", + "Vehicle Action Wheel Visibility": "载具行动轮盘可视度", + "TITLE": "头衔", + "Isolated Exostorm pockets are materializing across the planet and rapidly gaining momentum.": "多个异界风暴区分别在星球各地出现,迅速积聚势头。", + "BODY TYPE": "体型", + "OPEN BACK HATCH": "打开后盖", + "REMOVE FRIEND": "移除好友", + "LIQUID-VENTILATED COCKPIT": "液态通风驾驶舱", + "Aug": "8月", + "M0o0ns22": "月月欲试22", + "Estimated time until ready: #DAYS d #HOURS h": "预计准备时间:#DAYS天#HOURS小时", + "RADIAL MENU UP": "圆盘菜单上", + "The closer you are to the edge of the map, the steeper the angle of incoming orbital bombardments. Physics!": "你越接近地图边缘,轨道轰炸的角度就越高。这就是物理!", + "DANSK (Unsupported)": "DANSK (Unsupported)", + "This player is currently your friend on PC, Xbox and/or PlayStation™Network. They must be removed from your friends list on those services before they can be removed from your in-game friend list.": "该玩家目前是您的PC、Xbox和/或PlayStation™Network好友,必须先将其从这些服务平台的好友列表中删除,然后才能从游戏内的好友列表删除该玩家。", + "Health Visibility": "生命值可视度", + "Depth of Field": "景深", + "While in reverse, braking input will throttle, and throttling will brake.": "倒车时,刹车变油门,油门变刹车。", + "CENTER FOR CIVILIAN SURVEILLANCE AND SAFETY": "公民监控和安全中心", + "Speech To Text": "语音转文字", + "#READY MB/#TOTAL MB - #PERCENTAGE % complete\nTime Remaining: #SECONDS s": "#READY MB/#TOTAL MB - 已完成#PERCENTAGE%\n剩余时间:#SECONDS秒", + "LOOK DOWN": "向下看", + "Choose in what context subtitles are displayed.": "选择在哪些情况下显示字幕。", + "E-711 WELLSPRING": "711元素之源", + "REMOVE FROM FAVORITES": "取消收藏", + "Your Steam and PSN accounts are now linked.": "你的Steam和PSN账户现已绑定", + "Data Collection": "数据收集", + "Being prone makes you less susceptible to explosions. When in imminent danger, dive!": "扑倒在地可以躲避爆炸。面对迫在眉睫的危险,记得及时闪躲!", + "Hellpod deployment tips are a collaboration of the Ministry of Defense and Ministry of Truth.": "绝地喷射舱的部署技巧由国防部和真理部联合编写。", + "SYNTHETIC SUPPLEMENTATION": "合成补给", + "HANDBRAKE": "手刹", + "CURRENT MAJOR ORDER": "当前重要指令", + "STREAMLINED LAUNCH PROCESS": "简化发射流程", + "ENHANCED COMBUSTION": "强化燃烧", + "NEW YEARNING CONSTRUCTION SITE": "盛盼新城建造区", + "WHAT DO WE USE GAME DATA FOR?": "我们使用游戏数据的目的是什么?", + "Select the visibility of player nameplates during gameplay.": "选择游戏过程中的玩家名牌可视度。", + "15x100mm TOXIC": "15x100mm毒弹", + "B-22 MODEL CITIZEN": "B-22“模范公民”", + "COOKOUT": "野炊", + "AC-8": "AC-8", + "Incendiary Mines": "燃烧地雷", + "A throwable anti-personnel mine, capable of adhering to most surfaces. Upon deployment, emits lights and sounds which attract nearby hostiles to its proximity-activated detonator.": "可投掷式反步兵地雷,能附着在大部分表面。部署后发出光和声音,吸引附近敌人靠近它的感应引爆装置。", + "G-109": "G-109", + "Combat Engineer": "战斗工兵", + "NO UNDERBARREL": "无下挂", + "Faster Lock-On Time": "缩短锁定目标用时", + "Holographic Sight": "全息瞄准镜", + "STUN TIME": "眩晕时间", + "SLUGGER": "重炮手", + "Capable of firing a suite of space-to-ground indirect fire that can quickly free an entire battlefield from oppression.": "能发射一组空对地间接火力,快速解救整个受到压制的战场。", + "Engineering Bay": "工程港", + "PROTECTOR OF THE HEART": "民主之心捍卫者", + "Larger Gatling Magazine": "扩容加特林弹匣", + "OUTER RADIUS": "外半径", + "THUMB OF APPROVAL": "赞许之指", + "Commemorating the bold pioneers who first successfully navigated High Command’s newest tactical mechanisms. The distinctive replication of visor scarring represents a close-range ideological exchange with the Terminid scourge, proving that Managed Democracy shall remain unblinded by fascist aggression.": "旨在纪念那些最先成功驾驭最高指挥部最新战术机制的英勇先驱。头盔面甲疤痕的独特复刻,代表着与终结族毒瘤进行近距离意识形态交锋,彰显管理式民主绝不会被法西斯侵略蒙蔽双眼。", + "110mm E.M.S. CANNON ROUND": "110mm电磁冲击波炮弹", + "MORE DAMAGE": "提高伤害", + "LONGER GRENADE BELT": "加长榴弹腰带", + "SG-8": "SG-8", + "BRAWNY": "健壮", + "Heel Kick": "踢踏步", + "12g FLECHETTE SHELLS": "12g飞镖霰弹", + "EX-00 Prototype X": "EX-00“原型X”", + "500kg Bomb Mk2": "500KG炸弹 MK2", + "THUMPER": "桩锤", + "5.5x50mm Ripper": "5.5x50mm撕裂弹", + "Pushing the boundaries of bionic engineering, this armor collects and dispenses a number of vital fluids, several of which are soon to be declassified.": "这套盔甲突破了仿生工程学的极限,能收集并分配多种重要体液,其中几种即将解密。", + "MULTI-LAUNCH PROTOCOL": "多管发射协议", + "Standby": "随时待命", + "40MM HE": "40mm高爆弹", + "Sidearm draw/holster speed increased by #BONUS.": "副武器拔枪/收枪速度提高#BONUS。", + "CM-21 Trench Paramedic": "CM-21“战壕护理员”", + "IMPROVED ROUNDS": "改良弹药", + "R-63": "R-63", + "GS-17 FRONTIER MARSHAL": "GS-17“边境元帅”", + "[REDACTED]": "[已涂黑]", + "CPR-80 BULWARK": "CPR-80 “壁垒”", + "Armor explodes #BONUS after the wearer dies.": "盔甲会在穿戴者死后#BONUS引爆。", + "85mm Armor-Piercing Grenade": "85mm穿甲榴弹", + "HMG Emplacement": "重机枪部署支架", + "B-22 Model Citizen": "B-22“模范公民”", + "INCREASED STORAGE": "可携带数量升级", + "VERY SHORT": "非常短", + "A welcome sight in all Democratic neighborhoods, this armor inspires both civil pride and civic obedience.": "这款盔甲在所有民主社区都备受欢迎,既能激发公民自豪感,又能促进公民服从命令。", + "NAPALM BOMB MK2": "凝固汽油弹 MK2", + "Natural Gas Extraction": "提炼天然气", + "AMMUNITION OPTIMIZATION": "弹药优化", + "Expanded Bomb Racks": "扩展炸弹挂架", + "40-K": "40-K", + "COMMANDO": "突击兵", + "G/40-K": "G/40-K", + "500kg Bomb Mk3": "500KG炸弹 MK3", + "This ancient, likely allegorical, illustration of Might triumphing over the Anguiform is seen by scholars as a symbol of humankind's supremacy in the art of violence.": "这幅可能深藏寓意的古老插图描绘了力量战胜蛇形生物的场景,学者认为这象征着人类在暴力艺术的至高地位。", + "10-STAR GENERAL": "十星将军", + "HYENA": "鬣狗", + "Based on the uniform of Jackle 6, a veteran of the Viper Commandos who held off an entire Terminid brood on Nublaria in the First Galactic War with nothing but a machine gun, pocket knife, and Orbital Laser Strikes.": "以毒蛇突击队老兵“杰克尔六号”的制服为基础设计而成。第一次星系战争期间,这位老兵仅凭机枪、小刀和轨道激光炮就拦下了努布拉里亚的整支终结族大军。", + "15x100mm Toxic": "15x100mm毒弹", + "Increases melee damage by #BONUS.": "近战伤害提高#BONUS。", + "Large Ammo-Drum": "大容量弹鼓", + "PROSPECTING DRILL": "勘探钻机", + "An advanced, mostly self-operating prospecting drill fitted into a Hellpod. Handles soil sample extraction, analysis and data upload with minimal necessary input from an operator.": "一款安装在绝地喷射舱内的先进自动操作勘探钻机。操作员只需手动完成最基本的操作,钻机就能处理土壤样本提取、分析和数据上传的工作。", + "The horrors of Tyranny are manifold, their minions many, but they are naught before Democracy's twin swords: overwhelming firepower, and those trained elite who unquestioningly wield it.": "暴政恐怖千变万化且爪牙众多,但对于民主的“雌雄双剑”——压制性火力以及训练有素、坚定驾驭这股力量的精英而言,一切皆不足为惧。", + "Crew Training": "船员训练", + "MORE AUTOCANNON TURRET AMMO": "增加机炮炮台弹药数", + "Hellbomb": "地狱火炸弹", + "85mm High-Explosive Grenade Mk2": "85mm高爆榴弹 MK2", + "A domestic version of this armor is available for citizens who wish to perform efficient home renovation projects.": "希望提高住宅装修效率的公民可以购买这套盔甲的家用版本。", + "No muzzle attachment.": "无枪口配件。", + "Boxer": "拳击手", + "A lightly-armored Fast Recon Vehicle mounted with a heavy machinegun.": "轻型装甲快速侦察载具,搭载重机枪。", + "A longer revolver barrel that results in a higher muzzle velocity and lower recoil at the cost of worse handling.": "加长版左轮枪管,可有效提升枪口初速并降低后坐力,代价是操控性下降。", + "Orbital Gas Round Mk2": "轨道毒气弹 Mk2", + "SUPER CITIZEN": "超级公民", + "BOLT PISTOL": "爆弹手枪", + "TIER #TIER UPGRADES": "#TIER阶升级项目", + "DE-FORESTER'S SAILCLOTH": "伐木工帆布", + "A powerful dual magazine pump-action shotgun, with limited armor penetration. Ideal for small and fast targets.": "强大的双弹夹泵动式霰弹枪,穿甲力有限,这是攻击小型和快速目标的理想之选。", + "A single-use weapon firing a high-yield missile. Discarded after every use.": "发射大当量导弹的一次性武器。用后即弃。", + "SUPPRESSOR": "消音器", + "CONCUSSIVE PADDING, GRENADIER": "防震内衬(掷弹兵型)", + "15x100mm Plasma": "15x100mm等离子弹", + "SERVO-ASSISTED": "伺服辅助", + "KDM-73 DRAGOON": "KDM-73“龙骑兵”", + "This armor pays tribute to the immoveable heroes of the front line—those who refuse to acknowledge incoming fire, and consider \"dodging\" to be an abstract concept akin to cowardice.": "这套盔甲旨在致敬那些岿然不动的前线英雄——他们毫不畏惧来袭火力,并将“闪避”视为与怯懦无异的抽象概念。", + "Triangulation Veil": "三角定位披纱", + "A high-caliber submachine gun which can be fired with one hand. Has a relatively low rate of fire.": "可单手操控的大口径冲锋枪。射速相对较低。", + "An automated turret with an extremely high rate of fire. Caution: does not check if friendly units are in line of fire.": "射速极其高的自动炮台。当心:炮台不会侦测火线内是否存在友方单位。", + "Redeemer": "救世主", + "Breaker Nailspitter": "尖钉喷射“破裂者”", + "Singe": "焦痕", + "15x100mm HIGH EXPLOSIVE": "15x100mm高爆弹", + "SEAF ARTILLERY: SMOKE": "超级地球武装部队大炮:烟雾弹", + "REPRIMAND": "训斥", + "Protector of the Heart": "民主之心捍卫者", + "CRISPER": "迅击", + "Helps prevent Helldivers from flinching when hit.": "有助于防止绝地潜兵遭受攻击后产生畏缩反应。", + "HELLDIVER": "绝地潜兵", + "MARK OF THE CONSTRICTOR": "缚暴印记", + "VERDICT": "裁决", + "TG-8 Sharpshooter": "TG-8“神枪手”", + "Truth Whisperer": "真理低诉者", + "Loaded with jet-assisted rounds, this pistol is calibrated for creating and maintaining tactical distance from encroaching hostiles.": "这款手枪装填喷气助推弹,经过特别校准,可在敌人逼近时与其保持战术距离。", + "Speargun": "矛枪", + "Improved Ammo Storage": "弹药存储量升级", + "A heavy-duty submachine gun that fires large-caliber rounds, with a slower rate of fire to manage the high recoil. Ideal for use at close to medium range.": "重型冲锋枪,可发射大口径子弹,但由于后坐力较大,射速较慢。适合中近距离使用。", + "Orbital Gas Strike": "轨道毒气攻击", + "TRAINING MANEUVERS": "军事演习", + "Orbital Laser": "轨道激光炮", + "M-105": "M-105", + "Emancipator Exosuit": "“解放者”外骨骼装甲", + "A high-damage revolver, which can be reloaded with single rounds. A heavy-hitting and reliable sidearm.": "伤害较高的左轮手枪,可以装填单发弹药。此随身武器攻击力强大,相当可靠。", + "75mm HEAT Grenade": "75mm高爆反坦克榴弹", + "Orbital Precision Strike": "轨道精准攻击", + "A stationary ballistic cover with a mounted grenade launcher. Can protect multiple Helldivers from small arms fire.": "固定式防弹掩体,架设有榴弹发射器。可抵挡轻型武器的射击,保护多名绝地潜兵。", + "This cape depicts the inner workings of a medical device submitted to the Ministry of Science 70 years ago, and is bound to clear their patent approval process any day now.": "这件披肩绘制了70年前提交到科学部的医疗设备内部构造,相信很快就能通过专利审批流程了。", + "Increases the speed and duration of slides.": "可提升滑铲的速度与持续时间。", + "This high-visibility armor allows it's bearer to be easily seen through smoke, fog, and spewing viscera.": "穿上这套可见度极高的盔甲,缭绕烟雾和喷溅的内脏都挡不住你的风采。", + "GUNNER FRV": "炮手快速侦察载具", + "The experimental weapons R&D corporation Zizer has unveiled this altered \"Senator\" revolver, with a longer barrel that is clinically proven to make its wielder up to 23% more secure in themselves.": "实验性武器研发企业“自捷”推出改装版“参议员”左轮手枪,配备加长枪管,经临床验证可为使用者带来多达23%的自信心加成。", + "A common magazine type in the Super Earth military, favoring sustained fire over handling.": "超级地球军队常用弹匣,适合持续提供火力,但操控性较差。", + "AR-23P": "AR-23P", + "4x COMBAT SCOPE": "4倍战斗瞄准镜", + "KINETIC DISPLACEMENT MITIGATION": "动能位移减缓", + "HOMING GROUND MISSILE": "追踪式地面导弹", + "PUMMELER": "暴击斗士", + "GRENADE STATS": "榴弹数据", + "8x60mm DOUBLE POWER": "8x60mm双效子弹", + "SOLICIT TRANSPORTATION": "请求运输", + "EXTRA CAPACITY": "额外容量", + "Shorter Cooldown": "冷却用时缩短", + "9x70mm Socom Assassin": "9x70mm“刺客”特种作战弹", + "SALVOS": "齐射", + "IMPROVED PROJECTILES": "改良射弹", + "Hover Pack": "悬浮背包", + "PRESENTABLE": "像模像样", + "5.5x50mm HIGH VELOCITY": "5.5x50mm高速弹", + "Red Planet's Memory": "红星回忆", + "This suit's plutonium-238 nuclear battery enables environmental scanning long after the user has ceased operation.": "这套服装配备钚238核能电池,在穿戴者失去体征很长时间之后,电池依然能支撑设备完成环境扫描。", + "Loyalist": "忠诚者", + "AR-23A": "AR-23A", + "Stalwart": "盟友", + "Podium of Prosperity": "繁荣领奖台", + "IMPROVED AIMING SERVOS": "改良瞄准伺服系统", + "ROCK-SOLID": "坚如磐石", + "THE CAPE OF STARS AND SUFFRAGE": "群星与选举之披肩", + "100kg Bomb Mk3": "100KG炸弹 MK3", + "HIVE SCANNER": "虫窝扫描仪", + "MANUAL TARGETING": "手动锁定目标", + "SIGNAL: GROUP UP": "信号:集合", + "P-11": "P-11", + "Senator": "参议员", + "G-8": "G-8", + "First deployed in the mines of Cyberstan, where it offered protection against explosions in the hydrogen-rich caverns.": "最初投用于生化斯坦的矿区,帮助穿戴者在富含氢气的矿洞中抵挡爆炸的伤害。", + "CM-17 Butcher": "CM-17“屠夫”", + "PREPARED CRATES": "预备弹药箱", + "W.A.S.P. LAUNCHER BACKPACK": "W.A.S.P.发射器背包", + "This cape celebrates the one Veridical Ideology—Managed Democracy—a truth so self-evident, it requires no proof beyond the unwavering obedience of its champions.": "披肩颂扬唯一的真理意识形态:管理式民主。此中真理不言自明,也无需证明,只需要拥护者绝对服从。", + "INCREASED SHIELD POWER": "提升护盾能量", + "EAGLE'S FURY": "飞鹰之怒", + "Further reduces recoil when crouching or prone by #BONUS.": "蹲伏或匍匐姿态下,后坐力进一步降低#BONUS。", + "8x60mm HIGH VELOCITY": "8x60mm高速弹", + "INGRESS-81": "进军-81", + "P-33": "P-33", + "12x25mm HOLLOW POINT": "12x25mm空尖弹", + "SA-32 Dynamo": "SA-32“精力充沛”", + "Provides #BONUS damage resistance to fire, allowing bearer to rest assured in their inflammability.": "提供#BONUS的火焰伤害抗性,穿戴者无需再担心自身的易燃问题。", + "EYE OF THE CLANDESTINE": "隐匿之眼", + "12g SCATTER SHOT": "12g散射弹", + "Mortar Sentry": "迫击哨戒炮", + "BIG STRETCH": "用力舒展", + "Immediate Auto Loader": "即时自动装填", + "AF-52 Lockdown": "AF-52“禁锢”", + "Improved Ammunition Feed": "改良供弹系统", + "Disarmingly scrappy and viciously disarming, this armor is a staple of the Balayage FW/2185 collection \"Frontline Moxie\".": "这盔甲看起来破烂,令人放下戒心,实则凶悍得让敌人缴械投降。这套盔甲是巴拉雅奇2185秋冬系列“前线胆魄”的经典款式。", + "AR-20L": "AR-20L", + "An autonomous drone equipped with a flamethrower. Returns to backpack to refill fuel canisters.": "配备火焰喷射器的自主无人机。收回到背包可补充燃料罐。", + "Wings of Valor": "勇气之翼", + "EX-03 Prototype 3": "EX-03“原型 3”", + "KNIGHT": "骑士", + "Reflex Sight Mk2": "反射式瞄准镜Mk2", + "20mm APHET Rounds": "20mm穿甲高爆曳光弹", + "380mm HE Cannon Round": "380mm高爆炮弹", + "GUNSLINGER": "神枪手", + "Thermite": "铝热弹", + "LIBERATOR CARBINE": "“解放者”卡宾枪", + "HEAT MK2": "高爆反坦克榴弹 MK2", + "This Data Jack is carefully engineered to slot seamlessly into Illuminate Access Nodes. Once engaged, it initiates a sophisticated system disruption sequence, requiring little more than user confirmation.": "这个精心设计的数据接口可完美插入光能者的接入节点。一旦成功对接,就会发起复杂的系统破坏程序,几乎仅需用户确认即可完成。", + "ORBITAL WALKING BARRAGE": "轨道游走火力网", + "TALON": "猛爪", + "MANNED": "载人", + "SEISMIC PROBE": "地震探测仪", + "A turret which fires electrical charges at targets in close range. To avoid friendly fire, remain prone.": "向近程目标释放电击的炮台。为避免误伤,请保持匍匐姿势。", + "70mm LASER-GUIDED MISSILE MK2": "70mm激光制导导弹 MK2", + "A high-caliber sniper rifle effective over long distances against light vehicle armor. This rifle must be aimed downscope.": "大口径狙击步枪,在远程范围内可有效对付轻型载具装甲。此步枪必须开镜瞄准。", + "110mm Gas Cannon Round Mk3": "110mm毒气炮弹 MK3", + "LIGHTENED CASING": "轻薄弹壳", + "Offering camouflage in snowy environments, surplus sets of this armor are used by nature photographers and keen hunters alike.": "适用于雪地环境的迷彩,富余的盔甲在户外摄影师和打猎爱好者手中也相当实用。", + "Fre Liberam": "求自由", + "IMPROVED RECOIL": "改善后座力", + "Draw!": "拔枪!", + "Promotional armor made by SUMY Corp. as part of a highly successful marketing campaign for frozen yogurt.": "SUMY公司制作的促销盔甲,是大获成功的冷冻酸奶营销策略的一部分。", + "KDM-500 Outrider": "KDM-500“先驱骑兵”", + "Tech Specialist": "技术专家", + "FREEDOM'S TAPESTRY": "自由织锦", + "110mm GAS CANNON ROUND MK2": "110mm毒气炮弹 MK2", + "PUNISHER": "制裁者", + "13x40mm Ripper": "13x40mm撕裂弹", + "10g Fragmentation": "10g破片弹", + "Increases reload speed of support weapons by #BONUS.": "支援武器的装弹速度提高#BONUS。", + "Additional Rocket Pods": "附加火箭巢", + "Anti-Personnel Minefield": "反步兵雷区", + "10g Buckshot Shells": "10g鹿弹霰弹", + "CW-4 Arctic Ranger": "CW-4“极地游骑兵”", + "9x70mm SELF PROPELLED": "9x70mm自走弹", + "RANDOM": "随机", + "10x Sniper Scope": "10倍狙击瞄准镜", + "Dab": "嘻哈超人舞", + "Liberty's Herald": "解放预兆", + "No underbarrel attachment.": "无下挂配件。", + "MAXIGUN": "重装机枪", + "The suit was once designed to hold a variety of battlefield medical equipment. Now it holds a generous supply of stims.": "按照原本的设计,这套盔甲应该配备多种战地医疗设备,现在则是携带了大量的治疗剂。", + "LOCKSTEP": "齐步行进", + "10x SNIPER SCOPE": "10倍狙击瞄准镜", + "A-9 HELLJUMPER": "A-9“地狱伞兵”", + "R-72": "R-72", + "Foe Rent Asunder": "敌分四裂", + "A/G-16": "A/G-16", + "30mm APHE Cannon": "30mm穿甲高爆炮弹", + "VALIANT ENCLOSER": "英勇围合战士", + "110mm GAS CANNON ROUND MK3": "110mm毒气炮弹 MK3", + "Eruptor": "爆裂铳", + "Verdict": "裁决", + "THIS IS DEMOCRACY": "恭迎民主", + "Eagle Air-to-Air Missiles": "“飞鹰”空对空导弹", + "A heatsink calibrated to purposely generate heat faster than standard heatsinks.": "经过特殊校准,这种散热器的发热速度快于标准散热器。", + "The end result of several billion Super Credits and 12 years of research into creating \"the Soldier of Tomorrow.\"": "这是为打造“明日战士”而投入数十亿超级货币并耗费12年研究得出的最终成果。", + "DS-10 BIG GAME HUNTER": "DS-10“巨兽猎手”", + "Combat Blend": "混合作战", + "MOTHER EAGLE'S WINGS": "母鹰之翼", + "STURDIER WHEELS": "加固轮胎", + "An automated assembly line where all Hellpod armaments are constructed by precise, non-sentient robotic arms.": "自动化装配流水线,所有绝地喷射舱军备均由无感知的精密机械臂所建造。", + "12x25mm Plasma": "12x25mm等离子弹", + "BUNTING OF THE PARTY PARTICIPANT": "派对彩饰", + "SPEAR BACKPACK": "飞矛背包", + "MORE BOMBS": "增加炸弹数", + "TR-117 ALPHA COMMANDER": "TR-117“阿尔法指挥官”", + "When the wearer takes damage, they regain some stamina.": "穿戴者受到伤害时恢复部分体力。", + "LIFT-860": "LIFT-860", + "FREE-SPIRITED SPANGLES": "自由之魂的辉映", + "Embodies the ethos of Manifest Democracy—that it is our voter-given responsibility to emancipate the savage, un-Liberated galaxy. To rest only when every planet is safe, civilized, and Free.": "这套盔甲彰显了天定民主的信条:解放蛮荒、未获解放的银河系是选民赋予我们的神圣职责。唯有确保每个星球安全、文明、自由,我们才能功成身退。", + "EYE OF LIBERTY": "解放之眼", + "45-Degree Vertical Foregrip": "45度垂直前握把", + "12.5mm STANDARD RIFLE ROUNDS": "12.5mm标准步枪子弹", + "5.5x50mm PENETRATOR": "5.5x50mm穿甲弹", + "PH-9 PREDATOR": "PH-9“掠食者”", + "RAILGUN STUN ROUND": "磁轨炮眩晕弹", + "Signal: Group Up": "信号:集合", + "BALLISTIC SHIELD BACKPACK": "防弹护盾背包", + "A modified Punisher shotgun firing exploding plasma rounds. Fire carefully - exploding plasma can injure squadmates.": "改良后的“制裁者”霰弹枪,可发射会引爆的等离子弹。射击时务必小心,爆炸的等离子体可能会伤及队友。", + "TESTAMENT TO ATTRITION": "百战不殆的明证", + "Wearers of this cape know that even enemies of Freedom deserve to be equal. Equally dead.": "穿上这件披肩的战士都明白,即使是自由的敌人,也值得平等对待,让他们平等地死去。", + "NO OPTICS": "无准镜", + "MS-11": "MS-11", + "SPACE CADET": "太空军校生", + "DAMAGE ALT": "其他伤害", + "LARGER MAGAZINE": "扩容弹匣", + "A humane grenade launcher firing high-powered arc grenades.": "发射高能电弧榴弹的人道主义榴弹发射器。", + "Pistol": "手枪", + "A high-precision burst-fire plasma rifle that must be charged to fire.": "高精度连发等离子步枪,需充能才能开火。", + "20mm HVAP Rounds": "20mm高速穿甲弹", + "More LMG Mount Mags": "增加架设型轻机枪弹匣", + "ETERNAL CORONA": "永恒日冕", + "ARC THROWER": "电弧发射器", + "With genuine gold accents, 74% of colonists voted this armor the set they would most like to be buried in.": "真金装饰。74%拓殖地居民投票表示死后最希望穿这套盔甲下葬。", + "Grenade Launcher": "榴弹发射器", + "R-2": "R-2", + "UF-16 Inspector": "UF-16“督察员”", + "A/GM-17": "A/GM-17", + "A barrage of napalm bombs, creating a wall of fire which will stop the enemy in their tracks.": "凝固汽油弹火力网,可形成一道火墙,阻止敌人进攻。", + "AC-1 DUTIFUL": "AC-1“恪尽职守”", + "FIRE SAFETY OFFICER": "消防安全官", + "PEAK PHYSIQUE": "健壮体格", + "Presentable": "像模像样", + "PROOF OF FAULTLESS VIRTUE": "无瑕德行之证", + "The design of the Demo-Trooper armor has been a corporate secret since ST Construction first issued it to the Charan Colonial Guard in the early days of the Galactic Federation. Now, STC has contracted with the Ministry of Defense to issue the storied armor of its fallen homeworld to the Helldivers.": "自星系联邦初期,ST建筑公司首次将“爆破兵”护甲配发给常陈四拓殖卫队以来,其设计一直属于该公司的商业机密。如今,ST建筑公司已与国防部签订合同,将这套承载着传奇历史、来自其沦陷母星的护甲配发给绝地潜兵。", + "SEAF Artillery": "超级地球武装部队大炮", + "RED PLANET'S MEMORY": "红星回忆", + "HEAVY RECOIL SPRING": "重型复进簧", + "B-04 DEVELOPER OF DEMOCRACY": "B-04“民主缔造者”", + "200kg Bomb": "200KG炸弹", + "NO STRATAGEM": "没有战略配备", + "SA-8 Ram": "SA-8“蛮悍”", + "A high explosive grenade which detonates on first impact.": "一旦碰撞立即引爆的高爆榴弹。", + "SA-25 Steel Trooper": "SA-25“钢铁士兵”", + "SG-225": "SG-225", + "With its two barrels, one trigger, and vintage feel, this shotgun is perfect for historical reenactments.": "双管单扳机的复古设计,这把霰弹枪是重现历史场景的绝佳道具。", + "15x100mm STANDARD ROCKET": "15x100mm标准火箭弹", + "FS-23 BATTLE MASTER": "FS-23“战斗大师”", + "A submachine gun with a helical-feed magazine, which gives the weapon a higher ammo capacity while making it more front-heavy. Produced by Stål Arms.": "冲锋枪,配备螺旋式供弹弹匣,弹药容量增加,但前重后轻。由斯塔尔武装生产。", + "Eagle Gas Airstrike": "“飞鹰”毒气空袭", + "FASTER MISSILES": "提升导弹速度", + "110mm Gas Cannon Round Mk2": "110mm毒气炮弹 MK2", + "COMPRESSED EXPLOSIVES": "压缩炸药", + "GREATCLOAK OF REBAR RESOLVE": "钢筋意志大氅", + "SC-15 DRONE MASTER": "SC-15“无人机大师”", + "CM-09 Bonesnapper": "CM-09“碎骨杀手”", + "A vertical foregrip with an integrated tactical light.": "配备集成战术灯的垂直前握把。", + "RS-6 FIEND DESTROYER": "RS-6“歼魔者”", + "DEFAULT HELLDIVER VOICE 4": "绝地潜兵默认声音 4", + "Badge of Order": "秩序徽章", + "Salvaged from a deep-storage vault, this well-ventilated cape symbolizes tenacious survival. Its visible scars bestow immediate veteran status, reminding all onlookers that the spirit of tireless service is immortal.": "回收自一座长期储藏库,这款“千疮百孔”的披风象征着顽强的生存意志。清晰可见的“战损伤疤”平添资深行伍光环,并时刻警醒旁观者:百战不殆的奉献精神永垂不朽。", + "15x100mm Standard Rocket": "15x100mm标准火箭弹", + "IMPROVED RELOADING PROCESS": "改良装弹流程", + "RS-20 Constrictor": "RS-20“绞杀者”", + "Pineapple": "菠萝", + "Orbital Napalm Barrage": "轨道凝固汽油弹火力网", + "Crafted to deliver Justice to the darkest crevices of the galaxy.": "为将正义传递到银河系最黑暗的缝隙而设计。", + "RIFLE": "步枪", + "Deadeye": "鹰眼", + "Proof of Faultless Virtue": "无瑕德行之证", + "TARGETING SENSORS": "目标锁定传感器", + "Cremator": "焚燃者", + "10g Magnum": "10g马格南霰弹", + "Solo Silo": "单兵导弹发射井", + "TG-8 SHARPSHOOTER": "TG-8“神枪手”", + "Manual Function Trigger": "手动操作触发", + "Drape of Glory": "荣光加身", + "Mother Eagle's Wings": "母鹰之翼", + "PATIENT ZERO'S REMEMBERANCE": "零号病人遗思", + "5.5x50mm Full Metal Jacket": "5.5x50mm全金属被甲弹", + "A high-torque laser rifle that fires a continuous beam of thermal energy. If allowed to fully overheat, the weapon discharges a massive, explosive energy burst before requiring a heat sink replacement.": "一款高转矩激光步枪,可发射持续的热能光束。若允许其完全过热,该武器在需要更换散热器前会释放出一股巨大的爆炸性能量脉冲。", + "VERTICAL RECOIL": "垂直后坐力", + "This cape's cropped length symbolizes the brevity of galactic conflicts, thanks to the efficiency of the Helldivers.": "这款披肩的剪裁长度象征着星系冲突之短暂,一切归功于绝地潜兵的作战效率。", + "Fires concussive rounds that stagger enemies. Slower rate of fire than other SMGs.": "可连续发射震荡弹击退敌人。射速比其他冲锋枪慢。", + "The two stripes serve as a reminder of the two pillars of successful military campaigns: attack, and further attack.": "双条纹代表着成功的军事行动有两大支柱:进攻,以及进一步进攻。", + "LOADING DRILLS": "熟练装载配备", + "Stone-Wrought Perseverance": "磐石毅力", + "Awarded to those promoted to their point of greatest competency, and beyond.": "仅授予已达至臻之境并突破自我极限的战士。", + "EFFICIENT RELOADING": "高效装弹", + "Random": "随机", + "PROGRESSIVE TRIGGER": "渐进式扳机", + "10g HIGH VELOCITY SABOT": "10g高速萨博特式霰弹", + "An automated cannon turret firing anti-tank ammunition over long ranges. Sacrifices agility for range and power.": "远程发射反坦克弹药的自动加农炮台。以牺牲灵活性为代价,扩大攻击范围,提升火力。", + "SPECIALIST": "专家", + "15x100mm High Velocity": "15x100mm高速弹", + "O-44 BONDED PILOT": "O-44“契约驾驶员”", + "The classic Helldiver paint job.": "经典绝地潜兵涂装", + "A/MG-43": "A/MG-43", + "HE": "高爆弹", + "9x20mm Hollow Point": "9x20mm空尖弹", + "A laser weapon firing a continuous beam. Doesn't require ammunition, but will need heat sink replaced if it overheats.": "发射连续光束的激光武器。无需弹药,但武器过热时需要更换散热器。", + "GS-11 Democracy's Deputy": "GS-11“民主代理人”", + "Armor inspired by the legend of the Sanctioner, a figure known only through a bizarrely unanimous patchwork of stifled whispers. As told, this fearsome, covert arbiter of primeval Justice delivered final, state-approved verdicts in the chaotic years before the Federation's founding.": "以制裁者的传说为灵感设计的盔甲,虽然这位人物的形象仅由隐蔽的只言片语拼凑而成,但却诡异地一致。据传,这位令人敬畏的隐蔽制裁者在联邦成立前的混乱年代伸张早期的正义,下达国家认可的最终判决。", + "High-Speed Servos": "高速伺服系统", + "Gatling Sentry": "加特林哨戒炮", + "85mm ARMOR-PIERCING GRENADE": "85mm穿甲榴弹", + "Loading Optimizations": "优化配备装载", + "While early prototypes used shock-absorbing gels, this armor stabilizes aim with the use of internal gyroscopes.": "早期原型曾使用减震凝胶,而此盔甲利用内置陀螺仪稳定瞄准动作。", + "LONG REVOLVER BARREL": "左轮手枪长枪管", + "LIGHT ANTI-TANK": "轻质反坦克", + "Crest of the Unsullied": "无垢徽章", + "CE-27 Ground Breaker": "CE-27“裂地者”", + "HIGH-PRESSURE NOZZLE": "高压喷嘴", + "EAGLE AIR-TO-AIR MISSILES": "“飞鹰”空对空导弹", + "At the edge of the Federation, sometimes Democracy has only one representative.": "在联邦的边境线,有时民主只有一位代理人。", + "AUTONOMOUS": "自动", + "HIVE BREAKER DRILL": "“虫窝破裂者”钻机", + "FREE OF THOUGHT": "思想自由", + "Faster Recharge": "加速充能", + "EXO-45": "EXO-45", + "Suppressor": "消音器", + "HEAT": "高爆反坦克弹", + "Accelerator Rifle": "加速步枪", + "ADDITIONAL HARDPOINTS": "附加挂载点", + "Camo Cloak": "迷彩斗篷", + "Seal of General Consensus": "康森瑟斯将军之印", + "City Fighter's Resolve": "城市战士的决意", + "This armor's nostalgic color scheme brings to mind beloved trappings of colonial yesteryear: concrete frontier domiciles, slate-colored civilian jumpsuits, and Space Settlers' Pie.": "这套盔甲的怀旧配色让人联想到昔日拓殖地时期的时尚潮流:混凝土筑成的边境住所,石板色平民连体服,太空居民馅饼。", + "15x100mm Fragmentation": "15x100mm破片弹", + "VENUS": "维纳斯", + "Auto Loader": "自动装载", + "Standard of Safe Distance": "安全距离标准", + "Double Machinegun Pod": "双机枪喷射舱", + "ORBITAL AIRBURST STRIKE": "轨道空爆攻击", + "Muzzle Brake": "枪口制退器", + "SERVANT OF FREEDOM": "自由公仆", + "ONE-TWO": "幺二", + "GL-28": "GL-28", + "10g Magnum Triball": "10g马格南三连弹", + "Airburst Rocket Backpack": "空爆火箭弹背包", + "RECOIL": "后坐力", + "COMPENSATOR": "补偿器", + "SMG-37": "SMG-37", + "More Explosive Filler": "增加爆炸物填料", + "BLAZING SAMARITAN": "慈心闪耀", + "A/ARC-3": "A/ARC-3", + "More Autocannon Turret Ammo": "增加机炮炮台弹药数", + "12x25mm FULL METAL JACKET": "12x25mm全金属被甲弹", + "All Hail the Helldivers, whose devotion to Managed Democracy has never faltered.": "向绝地潜兵致敬,他们对管理式民主的忠诚从未动摇。", + "EAGLE CLUSTER BOMB": "“飞鹰”集束炸弹", + "8x60mm SUBSONIC": "8x60mm亚音速弹", + "TR-40 Gold Eagle": "TR-40“金鹰”", + "CREWSPACE REMOVAL": "移除船员舱", + "One of the most durable engineer armors available, each set is quality tested by an impact with a full-grown Charger.": "最耐用的工兵盔甲之一。每一套盔甲的质量检测流程都是抵挡一只成年强袭虫的冲撞。", + "An incendiary grenade which ignites any targets and terrain within the blast radius. Use with caution.": "燃烧榴弹,可点燃爆炸范围内任何目标和地面。请谨慎使用。", + "An assault rifle with a high-capacity drum magazine, good for providing sustained fire. \nProduced by Stål Arms.": "突击步枪,配备大容量弹鼓,适合持续提供火力。\n由斯塔尔武装公司生产。", + "FASTER LOCK-ON TIME": "缩短锁定目标用时", + "I-92 Fire Fighter": "I-92“消防队”", + "Maxigun Backpack": "重装机枪背包", + "Assigns a random voice to your Helldiver when you die.": "在死亡时,为你的绝地潜兵随机分配一种声音。", + "SLUGS": "独头弹", + "An SMG that fires caseless ammunition and is equipped with a non-removable suppressor. \nProduced by Martian Armory.": "发射无壳弹药的冲锋枪,且配备了不可拆卸的消音器。\n由火星军械库生产。", + "Eagle 110mm Rocket Pods": "“飞鹰”110mm火箭巢", + "Our heroic fallen live on in this cape, guiding its bearer's aim to the heart of those who killed them.": "这款披肩承载着陨落的烈士之魂,引导穿戴者瞄准凶手的要害,为他们复仇。", + "FRE LIBERAM": "求自由", + "THUNDERING HOOVES OF LOYALTY": "忠诚惊雷之蹄", + "A modified Breaker shotgun offering improved armor penetration and accuracy, with exceptionally high levels of recoil.": "改良后的“破裂者”霰弹枪,穿甲性能和精准度有所提升,后坐力尤其高。", + "Rebar Resolve": "钢筋意志", + "STANDBY": "随时待命", + "Bastion Mk XVI": "堡垒Mk XVI", + "RECOILLESS RIFLE": "无后坐力炮", + "Display of Brawn": "肌肉展示", + "A lightweight flamethrower. Shoots pressurized fuel through a dispersion nozzle into an open flame. Safe.": "轻型火焰喷射器。通过扩散喷嘴喷射加压燃料,形成明火。相当安全。", + "EXO-51": "EXO-51", + "A cape that strikes a subroutine emulating fear into the CPUs of all Automatons who conduct visual scans of it.": "所有扫描此披肩的机器人,其CPU都将被植入模拟恐惧情绪的子程序。", + "New Explosive Filler": "新式爆炸物填料", + "Provides #BONUS resistance to chest damage.": "提供#BONUS的胸部伤害抗性。", + "EXTRA MAGAZINE": "额外弹匣", + "ORBITAL SMOKE STRIKE": "轨道烟雾攻击", + "Cremator Backpack": "焚燃者背包", + "A versatile submachine gun equipped with iron sights and frontline incineration capabilities.": "一款多用途冲锋枪,配备机械瞄具,具备前线炽灼能力。", + "Atomizes caustic chemicals into a fine mist that liquifies sensitive electronics and tissues. Blinds and slows most enemies.": "将腐蚀性化学物质雾化成细密雾气状,使敏感的电子设备和组织液化。可使大多数敌人致盲并减速。", + "Thumb of Approval": "赞许之指", + "A backpack containing six adhesive C4 charges and a handheld wireless electronic detonator. Charges can be deployed and detonated individually, or as multiple simultaneous blasts.": "背包内装有6枚粘性C4炸药和一个手持式无线电子起爆器。炸药可单独部署并引爆,也可多枚同时引爆。", + "More Salvoes": "增加齐射炮弹数", + "DRILLING CHARGE": "强钻炸药", + "BUNKER BUSTER": "碉堡克星", + "CONTACT MINE": "水雷", + "Backup Vehicle": "备用载具", + "ANTI-TANK MINES": "反坦克地雷", + "Autocannon": "机炮", + "Hangar": "机库", + "APW-1": "APW-1", + "Raider's Cheer": "奇袭者的欢呼", + "Patriot Exosuit": "“爱国者”外骨骼装甲", + "Solicit Transportation": "请求运输", + "A fully-automatic shotgun with a high rate of fire, excellent for controlling crowds. Requires frequent reloading.": "高射速的全自动霰弹枪是群体控制的绝佳选择。需要频繁装弹。", + "BREAKER INCENDIARY": "高燃“破裂者”", + "I-09 Heatseeker": "I-09“热力追踪”", + "ROLL 'EM": "骰子定胜负", + "SUPER PRIVATE": "超级列兵", + "StA-11": "StA-11", + "VETO": "否决者", + "Drum Magazine": "弹鼓", + "Artists and sculptors have made countless attempts at depicting the face of Liberty, but the truth is that any citizen can see it—they need only requisition a mirror.": "艺术家和雕塑家曾无数次试图勾勒自由的轮廓,但事实上,任何人只需照照镜子,便能一睹自由的风采。", + "A scope with 10x magnification, good for long range on high accuracy weapons.": "10倍放大瞄准镜,适合高精度武器远程打击使用。", + "FLAM-40": "FLAM-40", + "G-48": "G-48", + "BP-32 JACKBOOT": "BP-32“杰克军靴”", + "This cape honors the Eagle pilots who would follow a Stratagem beacon into the very jaws of tyranny, even when the beacon's placement seems inscrutable to the non-Helldiver mind.": "这件披肩旨在纪念那些追随战略配备信标直捣暴政巢穴的飞鹰飞行员,即便信标位置在非绝地潜兵者看来难以理解也义无反顾。", + "MORE BACKPACK AMMO": "增加备用弹药", + "BP-77 GRAND JUROR": "BP-77“大陪审员”", + "Improved Recoil": "改善后座力", + "BP-20 Correct Officer": "BP-20“思想矫正官”", + "Assembled from pieces of recovered Helldiver armor and SEAF gear, for those who won't let a lack of full body protection keep them from the battlefront.": "这件披肩由回收的绝地潜兵装甲和超级地球武装部队装备碎片组装而成,专为那些即使缺乏全身防护装备也要奔赴战场的勇士设计。", + "Deploys mines that release gas on activation, temporarily blinding and slowing most enemies.": "部署地雷,触发后会释放毒气,可使大多数敌人暂时致盲并减速。", + "Longer Fire Time": "射击时间延长", + "I-44 SALAMANDER": "I-44“火蜥”", + "WEAPON STATS": "武器数据", + "Brawny": "健壮", + "A compact, low caliber machine gun. Trades power for ease of use, with faster reloading than heavier machine guns.": "小口径紧凑型机枪。牺牲火力,换取便利性,装弹速度比更重型机枪更快。", + "COMMANDER": "上尉", + "Good for medium to long range and the maximum magnification normally used for general weapons.": "常规武器常用的最高倍率瞄准镜,适合中远程打击。", + "A heavy, large-caliber marksman rifle bridging the gap between precision and sheer stopping power. Fires armor-piercing rounds coated in a high-ignition thermite compound to ignite targets.": "一款重型大口径精确射手步枪,完美兼顾精准度与强劲的停止作用。发射涂有高燃铝热剂化合物的穿甲弹,可引燃目标。", + "PINIONS OF EVERLASTING GLORY": "永恒荣耀之羽", + "MASTER SERGEANT": "军士长", + "Windswept Wayfinder": "风驰引路者", + "AMENDMENT": "修正", + "Painted by visionary artist Silas Garm during an intense fever, this symbol represents Humanity's great Galactic endeavor: the blood-soaked dawn of Lasting Peace.": "这个符号由远见卓识的艺术家西拉斯·加姆在高烧中绘制,象征着人类在银河系卓绝奋斗的痕迹:他们为持久和平的曙光而挥洒的鲜血。", + "SA-7 Headfirst": "SA-7“冲锋者”", + "Railgun Stun Round": "磁轨炮眩晕弹", + "Deploys a defensive incendiary minefield, which will set both terrain and targets alight when triggered.": "部署一片燃烧式防御雷区,一旦触发便会点燃地面和目标。", + "LAS-22": "LAS-22", + "Efficient Reloading": "高效装弹", + "INCINERATOR FRV": "炽灼型快速侦察载具", + "MASTER DIVEMASTER MAJOR OMEGA": "终极大师潜兵长少校", + "Expanded Heat Capacity": "提升热容量", + "CE-101 GUERILLA GORILLA": "CE-101“游击猩猩”", + "MAX RANK INFINITY +1": "无限最高等级+1", + "G-16": "G-16", + "No optic attachment": "无准镜配件", + "Improved Servos": "改良伺服系统", + "EAGLE 110MM ROCKET PODS": "“飞鹰”110MM火箭巢", + "TED-63": "TED-63", + "This cape's retro print, first made popular in GW1 cereal merchandising, helps children remember that not all machines are twisted mechano-socialists; some are piloted by true-hearted humans, and we can all rest easy in their gaze.": "这款披风的复古印花最初作为第一次星系战争的麦片周边商品而爆红,它能帮助孩子们牢记这一事实:并非所有机器的操控者都是扭曲的机械党同伐异者;有些机器由诚挚人类所驾驶,而我们正是在它们的注视下得以安然入睡。", + "Pyrotech": "烟花术", + "VERTICAL FOREGRIP": "垂直前握把", + "Extraction": "撤离", + "The Helldiver Skull is said to strike fear in the hearts of foes attempting to sneak up on those wearing this cape.": "据说,妄图偷袭穿戴此披肩之人的敌人,都会被绝地潜兵的骷髅头图案所震慑。", + "Scraps of Sovereignty": "主权碎片", + "A faithful replica of the armor worn at The Battle of Liberty Peak. Honor their legacy, and wear it with pride.": "如实还原解放峰之战的盔甲。尊重他们的遗产,骄傲地将其穿在身上。", + "ORBITAL RAILCANNON STRIKE": "轨道炮攻击", + "SUPPLEMENTAL ADRENALINE": "肾上腺素补充剂", + "ULTIMATUM": "最后通牒", + "Order the Eagle Fighter to return to the ship, where it can restock its armaments.": "可指派“飞鹰”战斗机返回飞船,重新补充军备物资。", + "Orbital Walking Barrage": "轨道游走火力网", + "LUMBERER EXOSUIT": "“伐木者”外骨骼装甲", + "SHORTER RECHARGE DELAY": "缩短充能延迟", + "Explosive Rounds": "增加爆炸弹", + "IX-VOIDWALKER": "IX-寂域行者", + "BUSHWHACKER": "游击兵", + "ERUPTOR": "爆裂铳", + "Compact and flexible, this kevlar armor adds minimal mass, making it a common choice for Helldiver fitness tests.": "此芳纶纤维盔甲坚实又灵活,几乎不增加额外重量,是绝地潜兵体能测试的常用配备。", + "A choir of patriotic schoolchildren sings the Super Earth anthem to each cape as the final step in its production.": "此披肩制作过程的最后一步,是由爱国儿童唱诗班向着每一件披肩唱超级地球国歌。", + "DE-ESCALATOR": "缓和使者", + "Programmable Prism Effect": "智能棱镜效果", + "HAIR TRIGGER": "微力扳机", + "DEVELOPER": "DEVELOPER", + "5.5x50mm Explosive": "5.5x50mm爆炸子弹", + "A fully-automatic cannon effective against light vehicle armor. Includes support backpack required for reloading.": "全自动加农炮,可有效对付轻型载具装甲。包含支援背包,用于装填弹药。", + "RS-100 SANCTIONER": "RS-100“制裁者”", + "MISSILE PERFORMANCE": "导弹性能", + "MAX RANK": "最高等级", + "Entrenchment Tool": "堑壕工具", + "HOLDER OF THE YELLOW LINE": "黄线捍卫者", + "DIVEMASTER MAJOR": "潜兵长少校", + "A plasma pistol that charges each shot until the trigger is released. Plasma projectiles explode on impact.": "等离子手枪,每发射击都可充能,松开扳机即可开火。等离子弹触碰着弹点后会爆炸。", + "Vision of Freedom": "自由愿景", + "PORTABLE HELLBOMB": "便携式地狱火炸弹", + "Eagle Strafing Run": "“飞鹰”机枪扫射", + "15x100mm FRAGMENTATION": "15x100mm破片弹", + "P-69": "P-69", + "GILDED QUILL": "镀金羽毛笔", + "An expendable missile launcher equipped with four laser-guided missiles.": "消耗性导弹发射器,配有四枚激光制导导弹。", + "A laser pistol that fires a continuous beam. Does not require ammo but can overheat and need to change batteries.": "发射连续激光束的激光手枪。无需装弹,但如果手枪过热,必须更换电池。", + "The clasps on this cape are made from melted down Automaton housings—evidence of Democracy's inevitable triumph.": "披肩上的扣子是通过熔化机器人外壳制作而成的,有力证明了民主的胜利势不可挡。", + "MACHINE GUN SENTRY": "哨戒机枪", + "Vertical Foregrip": "垂直前握把", + "A heavy-hitting, one-handed melee weapon.": "重型单手近战武器。", + "Slightly increases weapon ergonomics to reduce drag on weapon movement.": "通过小幅提升武器的人体工学性能,降低携带武器移动的阻力。", + "Lightweight Materials": "轻质材料", + "DESERT CAMO": "沙漠迷彩", + "Scythe": "长柄镰", + "Detonates on impact, covering the immediate vicinity in self-igniting white phosphorus.": "受到撞击即引爆,以可自燃的白磷覆盖周边区域。", + "110mm STANDARD ROCKET": "110mm标准火箭弹", + "85mm HEAT Grenade Mk2": "85mm高爆反坦克榴弹 MK2", + "ORBITAL GAS STRIKE": "轨道毒气攻击", + "No Optics": "无准镜", + "FLAMES MK2": "喷射火焰 MK2", + "A large bomb obliterating almost any target close to impact. Make sure to clear the area.": "一枚大型炸弹,可湮灭靠近爆炸范围的近乎所有目标。请确保所有人员撤离爆炸区域。", + "ENTHUSIASTIC MIRTH": "开怀大笑", + "DEFAULT INTERNAL PART": "默认内部零件", + "40mm HE MORTAR": "40mm高爆迫击炮弹", + "Against the Tyrant Cloud": "破除暴瘴", + "A precision artillery salvo over a small area, perfect for taking out concentrated enemy units.": "向小范围区域齐射的精准火力打击,可完美解决集中在一起的敌方单位。", + "#PREFIX #NAME": "#PREFIX #NAME", + "When the Illuminate threatened Super Earth, the very Heart of Democracy, the Helldivers answered the call.": "当光能者威胁超级地球这颗民主之心时,绝地潜兵应召而战。", + "MANUAL FUNCTION TRIGGER": "手动操作触发", + "B-1": "B-1", + "40mm PROXIMITY GRENADE": "40mm感应榴弹", + "RS-40 Beast of Prey": "RS-40“掠食凶兽”", + "A turret firing static field generators that slow the advance of enemies.": "炮台可发射静电场发生器,拖延敌人前进的脚步。", + "IMPROVED AMMUNITION FEED": "改良供弹系统", + "SEAF ARTILLERY: MINI NUKE": "超级地球武装部队大炮:迷你核弹", + "RS-422": "RS-422", + "EXPLOSIVE ROUNDS": "增加爆炸弹", + "ADMIRABLE ADMIRAL": "承敬上将", + "STERILIZER": "灭菌器", + "10g SCATTER SHOT": "10g散射弹", + "RANGER": "游骑兵", + "10g FLECHETTES": "10g飞镖弹", + "HVAP ROUNDS": "高速穿甲弹", + "THROWING KNIFE": "飞刀", + "Slugger": "重炮手", + "Super Person": "超人", + "Giga Grenade": "千兆级榴弹", + "GP-20": "GP-20", + "FS-55 Devastator": "FS-55“蹂躏者”", + "RS-6 Fiend Destroyer": "RS-6“歼魔者”", + "13x40mm HOLLOW POINT": "13x40mm空尖弹", + "Rightful Occupier": "正当占领者", + "P-72": "P-72", + "AD-49 APOLLONIAN": "AD-49“阿波罗神”", + "SEAF ARTILLERY: NAPALM": "超级地球武装部队大炮:凝固汽油弹", + "110mm AIRBURST CANNON ROUND": "110mm空爆炮弹", + "G-3": "G-3", + "P/40-K": "P/40-K", + "A \"compliance weapon\" to modify enemy behavior. The projectile temporarily stuns all targets within the strike radius.": "改变敌人行为的“慑敌武器”。射弹可短时眩晕攻击范围内的所有目标。", + "LASER SIGHT W/ FLASHLIGHT": "激光瞄准器带照明", + "The fire rate of the autocannons is increased from 200 to 300 rounds per minute.": "机炮的射速从每分钟200发提升至每分钟300发。", + "DESERT": "沙漠", + "SR-24 STREET SCOUT": "SR-24“街头侦察兵”", + "Gas Mines": "毒气地雷", + "This high-caliber marksman rifle trades magazine capacity and rate of fire for powerful, accurate shots.": "大口径狙击步枪,虽然牺牲了弹匣容量和射速,却提高了射击精准度和威力。", + "WATCHFUL COMPATRIOT": "守望同胞", + "8x60mm Penetrator": "8x60mm穿甲弹", + "A compact handgun-style flamethrower, able to project a jet of fire over short distances.": "手枪式便携火焰喷射器,能够喷射近程火焰。", + "110mm E.M.S. CANNON ROUND MK2": "110mm电磁冲击波炮弹 MK2", + "Provides #BONUS resistance to arc damage.": "提供#BONUS的电弧伤害抗性。", + "FS-40 DIPLOMAT": "FS-40“外交官”", + "An Exosuit equipped with a flak cannon and ballistic shield, optimized for mid-to-close combat range.": "配备高射炮与防弹护盾的外骨骼装甲,专为中近距离战斗而优化。", + "Firing jet-propelled rounds, the Dominator trades fire rate and magazine capacity for increased damage per projectile.": "发射喷气推进式子弹,这把“主宰”虽然牺牲了射速和弹匣容量属性,却提高了每颗弹丸的伤害。", + "FLASH HIDER": "消焰器", + "BULLET STORM": "子弹风暴", + "G-11": "G-11", + "15x100mm Emp-Rounds": "15x100mm电磁脉冲弹", + "SR-18 ROADBLOCK": "SR-18“路障”", + "For optimal performance, the manufacturer recommends avoiding immersing this armor in salt water for prolonged periods.": "为维持盔甲的良好性能,制造者建议避免长时间将盔甲浸入咸水。", + "PLASMA BOLT": "等离子弹", + "SOLID BLACK": "纯黑", + "The eternal colors of Super Earth can never be tainted. Only quenched, by the blood of its enemies.": "超级地球的永恒颜色绝不能被玷污。唯有沾染敌人的鲜血方可罢休。", + "ENTRENCHMENT TOOL": "堑壕工具", + "SOLO SILO": "单兵导弹发射井", + "SMG": "冲锋枪", + "FASTER DEPLOYMENT": "加快部署", + "RS-89 SHADOW PARAGON": "RS-89“暗影典范”", + "Extra Capacity": "额外容量", + "O-44 Bonded Pilot": "O-44“契约驾驶员”", + "FLAMETHROWER": "火焰喷射器", + "Although bulkier, it provides the effects of both a laser sight and a flashlight.": "虽然体积更大,但能同时提供激光瞄准器和照明效果。", + "5.5x50mm DEVASTATOR": "5.5x50mm“毁灭者”子弹", + "ARCTIC CAMO": "雪地迷彩", + "Issued to the rapid-response enforcement wings of the Ministry of Prosperity. This armor provides the structural integrity necessary for aggressive pursuit maneuvers and the forceful redirection of traffic—whether civilian, military, dissident or hostile.": "配发给繁荣部下属快速响应执法支队。这套护甲提供侵略性追击机动和强行疏导交通所需的结构强度——无论对方是平民、军人、异见分子还是敌军。", + "SG-451": "SG-451", + "Standard Drum": "标准弹鼓", + "A single-use target-seeking anti-aircraft missile launcher. Must be locked to target before firing.": "一次性寻的防空导弹发射器。发射前必须锁定目标。", + "Charges up to fire a powerful, explosive energy burst. Has a long cooldown period after firing.": "充能后可发射爆炸性的强力能量炮。发射后的冷却时间较长。", + "A mark of stalwart loyalty bestowed only to those who have proved themselves worthy through unquestioning dedication.": "坚定忠诚的标志,仅授予那些通过绝对的奉献来证明自身资格的战士。", + "EW": "好臭", + "500kg BOMB": "500KG炸弹", + "Napalm Bomb": "凝固汽油弹", + "An angled foregrip with an integrated laser sight.": "配备集成激光瞄准器的直角前握把。", + "Dissident's Nightmare": "异见者梦魇", + "This classic armor set is recognized by every citizen: worn by the heroic Helldivers who battled and forever defeated the Terminids, Cyborgs, and Illuminate in the First Galactic War.": "每位市民都认识这套经典盔甲:在第一次星系战争,绝地潜兵英雄就是穿着它彻底击败终结族、生化人和光能者。", + "EAT-411": "EAT-411", + "Because this prototype's wires operate at 400,000 volts, it also includes a handy rubber underlayer for insulation.": "此原型的电线需要在400,000伏特的电压下运行,因此盔甲配有便利的橡胶绝缘内衬。", + "5.5x50mm RIPPER": "5.5x50mm撕裂弹", + "GRENADE LAUNCHER": "榴弹发射器", + "12x25mm TOXIC": "12x25mm毒弹", + "12g Buckshot": "12g鹿弹", + "DP-00 TACTICAL": "DP-00“战术”", + "HEAD TAP": "动动脑", + "Stoker": "司炉者", + "Increased Storage": "可携带数量升级", + "GRENADIER BATTLEMENT": "掷弹兵防卫墙", + "SEAF ARTILLERY": "超级地球武装部队大炮", + "MORE FUEL": "增加燃料", + "This armor celebrates the wearer's close relationship to their Exosuit---as intimate as is possible without succumbing to cyborgry.": "此套盔甲旨在彰显穿着者与外骨骼装甲之间的紧密羁绊——极致亲密贴合,但不至于堕入生化人之境。", + "Per Democrasum": "于民主", + "A mighty rifle with a signature lever-action enabling single round reload. Powerful precision suited to mid- and long-range combat.": "威力强大的步枪,经典拉柄式设计支持单发装填。精准度极高,适合中远程作战。", + "A tribute to the Liberation of Choepessa IV in the First Galactic War, in which so much orbital ordnance was detonated that its sun was occluded by ash for an entire lunar cycle.": "纪念第一次星系战争的科埃佩萨IV解放战役。彼时投射的轨道火力留下了漫天烟尘,将恒星的光芒遮蔽了整整一个月。", + "Standard plasma bolt": "标准等离子弹", + "Default Helldiver Voice 2": "绝地潜兵默认声音 2", + "INCREASED FUEL CAPACITY": "提升燃料容量", + "B-24 Enforcer": "B-24“执行者”", + "Enables melee attacks to remove larger obstacles, such as fences.": "近战攻击可拆除更大型的障碍物,例如栅栏。", + "RAPID HEATSINK": "快速散热器", + "A paint job for use in desert environments.": "适用于沙漠环境的涂装。", + "EAGLE 500KG BOMB": "“飞鹰”500KG炸弹", + "SA-8 RAM": "SA-8“蛮悍”", + "8x60mm FULL METAL JACKET": "8x60mm全金属被甲弹", + "ORBITAL ILLUMINATION FLARE": "轨道照明弹", + "Forged for those watchful protectors who silently guide all Helldivers, asking no recognition whatsoever, besides a simple custom-made suit of armor only they get to wear.": "为默默引导所有绝地潜兵的保护者打造,除了简单的专属定制盔甲以外,他们不求得到任何形式的认可。", + "5.5x50mm Self Propelled": "5.5x50mm自走弹", + "A paint job that dares to stand out.": "敢于引人注目的涂装。", + "B-24 ENFORCER": "B-24“执行者”", + "W.A.S.P. LAUNCHER": "W.A.S.P.发射器", + "EMBLEM OF FREEDOM": "自由象征", + "LONG": "长", + "Impatient": "急躁", + "Scorcher": "焦土", + "Reload Drills": "熟练装弹", + "110mm Airburst Cannon Round": "110mm空爆炮弹", + "A powerful manned gun emplacement, capable of taking out armored targets at long ranges.": "威力强大的手动炮台,可摧毁远距离装甲目标。", + "Railgun Round": "磁轨炮弹", + "Shield Generator Pack": "防护罩生成包", + "RANGER, BALD EAGLE CLASS": "白头鹰级游骑兵", + "M-102": "M-102", + "Provides #BONUS resistance to fire, gas, acid, and electrical damage.": "获得#BONUS抵御火焰、毒气、酸液以及电击伤害的能力。", + "A stationary ballistic cover with a mounted light machine gun. Can protect multiple Helldivers from small arms fire.": "固定式防弹掩体,架设有轻机枪。可抵挡轻型武器的射击,保护多名绝地潜兵。", + "AD-26 Bleeding Edge": "AD-26“血刃科技”", + "FLASHLIGHT VERTICAL FOREGRIP": "手电筒垂直前握把", + "\"Prowl like a jaguar, strike like a viper.\" -Motto of the storied SEAF special operations unit whose real exploits were portrayed in the classic comic book series \"Tales of the Viper Commandos.\"": "“巡如豹,袭如蛇。”这是传奇超级地球武装部队特别行动组的座右铭。经典漫画《毒蛇突击队的故事》真实描绘了他们的丰功伟绩。", + "In mountainous colonies, domestic variants of this armor are used to throw weather monitoring equipment uphill.": "在山区殖民地,这套盔甲的家用版本是用来把天气监测设备丢到山上的好帮手。", + "INCREASED MAGAZINE CAPACITY": "提升弹匣容量", + "12g MAGNUM": "12g马格南霰弹", + "An agile automated machine gun turret. Will fire at targets even if Helldivers will be caught in the crossfire.": "灵活的自动机枪炮台,即便绝地潜兵在交火期间受伤,它依然会向目标射击。", + "RELOAD DRILLS": "熟练装弹", + "A speed-loaded volley gun with three different firing modes and three different RPM options. Warning: recoil varies significantly between firing modes.": "快速装填的齐射枪,具备三种不同的射击模式,以及三种不同射速选项。警告:不同射击模式之间的后坐力差异巨大。", + "A barrage of high explosive rounds, fired from the Destroyer's high speed rotary autocannons.": "驱逐舰的高速旋转式机炮发射高爆弹,形成火力网。", + "TR-62 Knight": "TR-62“骑士”", + "15x100mm HIGH VELOCITY": "15x100mm高速弹", + "GATLING SENTRY": "加特林哨戒炮", + "DIRECTIONAL SHIELD": "定向护盾", + "STUN EXPLOSION": "眩晕爆炸", + "At Ease": "稍息", + "A fully automatic assault rifle featuring a non-removable suppressor and subsonic ammunition. Slower rounds allow low-profile operation.": "配备不可拆卸消音器和亚音速弹药的全自动突击步枪。弹药速度较低,便于执行隐蔽行动。", + "Beacon of Mercy": "仁慈信标", + "No Attachment": "无配件", + "VISION OF FREEDOM": "自由愿景", + "PODIUM OF PROSPERITY": "繁荣领奖台", + "The SEAF standard pistol - offering a high fire rate, generous capacity, and fast reloading.": "超级地球武装部队制式手枪。射速较高、弹药容量理想,装弹速度也比较快。", + "Domestic versions of this armor enable colonial farmers to plant crops and mines side by side, safely.": "殖民地农民可以购买这套盔甲的家用版本,确保自己和同伴可以紧贴着彼此,安全地种植农作物以及布设地雷。", + "8x60mm SNIPER ARMOR PIERCING": "8x60mm穿甲狙击弹", + "SA-04 COMBAT TECHNICIAN": "SA-04“技术兵”", + "ANTI-TANK EMPLACEMENT": "反坦克炮台", + "PLAS-15": "PLAS-15", + "SC-34 Infiltrator": "SC-34“深入敌阵”", + "Gilded Quill": "镀金羽毛笔", + "Stun Rounds": "眩晕弹", + "G-31": "G-31", + "Data Jack": "数据接口", + "ENGINEERING KIT": "工程包", + "AR-23C": "AR-23C", + "100kg Cluster Bomb": "100KG集束炸弹", + "Focused Prism": "聚焦棱镜", + "ANGLED FOREGRIP": "直角前握把", + "WINGS OF VALOR": "勇气之翼", + "Extraction Beacon": "撤离信标", + "Solid Black": "纯黑", + "An autonomous drone equipped with a laser rifle, providing 360° cover. Returns to backpack to cool down.": "配备激光步枪的自主无人机,可提供全方位掩护。需要冷却时会返回背包。", + "IRON SIGHT": "机械瞄具", + "\"We fear not poison, fear not death; spite our foes with every breath.\" From the beloved classic Hazard Pay: The Musical.": "“我们不惧毒药,不畏死亡;每一次呼吸都让敌人破防”。选自广受喜爱的经典作品音乐剧《危险津贴》。", + "ADDITIONAL CANISTERS": "附加燃料罐", + "B-27 FORTIFIED COMMANDO": "B-27“强化突击兵”", + "A dart-firing pistol. Each of its six rounds administers a gaseous chemical agent, harmful to hostiles whether organic or artificial, that also induces a state of delirium in the target.": "发射飞镖的手枪。其六发飞镖均含有气态化学制剂,对有机或人造敌人都能造成伤害,还会令目标陷入神志不清的状态。", + "12x25mm Explosive": "12x25mm爆炸子弹", + "Heavy Recoil Spring": "重型复进簧", + "The utilitarian sidearm that was standard-issue to the Charan Colonial Guard in the early days of the Galactic Federation. \n\nProduced by ST Construction.": "在星系联邦初期,这种实用的随身武器曾是常陈四拓殖卫队的制式装备。\n\n由ST建筑公司生产。", + "Pinions of Everlasting Glory": "永恒荣耀之羽", + "PER DEMOCRASUM": "于民主", + "Spear Backpack": "飞矛背包", + "2x Support Scope": "2倍支援瞄准镜", + "The Destroyer's laser cannon will sweep over the designated area, vaporizing all targets within the effective radius.": "驱逐舰的激光加农炮扫射指定区域,令效果范围内的目标全数蒸发。", + "Raise Weapon": "高举武器", + "Order of the Venerated Ballot": "神圣投票团", + "8x60mm DEVASTATOR": "8x60mm“毁灭者”子弹", + "SPECIMEN VESSEL": "样本容器", + "IMMOLATION": "焚身", + "DEFENSE WALL": "防御墙", + "STANDARD BARREL": "标准枪管", + "Full Choke": "全喉缩", + "Sterilizer": "灭菌器", + "Bridge": "舰桥", + "A humane compliance weapon with two separate magazines: one for armor-penetrating flechette rounds and one for stun rounds.": "符合人道主义的武器,共有两个独立弹匣:一个装备穿甲飞镖霰弹,另一个装备眩晕弹。", + "EX-16 Prototype 16": "EX-16“原型 16”", + "SHORTER SHOT COOLDOWN": "缩短射击冷却用时", + "9x20mm Toxic": "9x20mm毒弹", + "SCOURGE OF TYRANNY": "暴政克星", + "LIGHT ARMORED VEHICLE": "轻甲载具", + "DEMOCRACY PROTECTS": "民主护佑", + "70mm Laser-Guided Missile": "70mm激光制导导弹", + "1.5x TUBE RED DOT": "1.5倍红点瞄准镜", + "HIGH-SPEED SERVOS": "高速伺服系统", + "OXYGENATOR": "供氧器", + "An Exosuit equipped with a rocket launcher and a gatling gun, offering reliable flexibility against both heavy units and swarms of small targets.": "搭载火箭发射器和加特林机枪的外骨骼装甲,能够可靠灵活地应对重型单位和成群小型目标。", + "Featuring a vibrant, high-visibility pattern to signify the inevitable victory of the Federation. This cape reminds all observers that while the road to Liberty is paved with sacrifice, the \"podium\" at the end is reserved exclusively for the compliant.": "采用鲜艳的高可见度图案,预示联邦必定赢得胜利。它提醒所有观察者:通往自由的道路由牺牲铺就,但尽头的“领奖台”专属于顺民。", + "Orbital Gatling Barrage": "轨道加特林火力网", + "85mm HIGH-EXPLOSIVE GRENADE MK2": "85mm高爆榴弹 MK2", + "Double-Edge Sickle": "双刃镰刀", + "A top-loaded shotgun prominently featured in the final episode of \"Obedient Democracy Support Troopers.\"\nProduced by Martian Armory.": "顶部装弹的霰弹枪,在《民主光环驰援部队》大结局中有突出表现。\n由火星军械库生产。", + "I-102 DRACONAUGHT": "I-102“龙行者”", + "A semi-automatic ceremonial rifle equipped with a bayonet. Can be set to fire in three-shot bursts, to easily conduct the Fallen Hero's Salute.": "配备刺刀的半自动礼仪步枪。可设置为三连发模式,轻松鸣枪致敬陨落的英雄。", + "Wide Prism": "加宽棱镜", + "10g Rifled Slugs": "10g线膛独头弹", + "A cluster fragmentation grenade. The shrapnel submunition allows it to inflict damage over a large area.": "一种集束破片手榴弹。弹片能够在大范围内造成伤害。", + "PURIFYING ECLIPSE": "净化日食", + "8x60mm Subsonic": "8x60mm亚音速弹", + "RESUPPLY": "重新补给", + "A high-caliber rifle with high damage and penetration.": "大口径步枪,拥有超高的伤害和穿透力。", + "CARPET BOMB": "地毯式轰炸", + "CE-35 Trench Engineer": "CE-35“战壕工程师”", + "Larger Canister": "扩容燃料罐", + "DEATH CAPTAIN": "死神少校", + "75mm HEAT GRENADE": "75mm高爆反坦克榴弹", + "More Fuel": "增加燃料", + "HALF CHOKE": "半喉缩", + "Incendiary": "燃烧弹", + "5.5x50mm Hollow-Point": "5.5x50mm空尖弹", + "Proud Gold": "傲金", + "Eagle Napalm Airstrike": "“飞鹰”凝固汽油弹空袭", + "20mm HE CANNON": "20mm高爆炮弹", + "Plasma Igniter Choke": "等离子点火器喉缩", + "Even among the most depraved of dissidents, the mere sight of this armor is enough to inspire a change of heart.": "即使是最顽固的异见分子,只要看到这套盔甲,就会弃暗投明。", + "A quality product, this armor can destroy over 300,000 kilometers of fencing with no decline in operational efficiency.": "即使撞破30万公里的栅栏,这套高品质盔甲的使用效率也丝毫不会下降。", + "Compensator": "补偿器", + "SEAF ARTILLERY: EXPLOSIVE": "超级地球武装部队大炮:炸弹", + "B-04 Developer Of Democracy": "B-04“民主缔造者”", + "UF-16 INSPECTOR": "UF-16“督察员”", + "13x40mm FULL METAL JACKET": "13x40mm全金属被甲弹", + "SG-97": "SG-97", + "No Muzzle": "无枪口配件", + "GALLANT": "英勇无畏", + "An accurate, armor-penetrating rifle, the BR-14 Adjudicator delivers righteous judgement to medium-sized enemies, though its restrictive magazine limits its effectiveness against large groups.": "“审判者”是精准度较高的穿甲步枪,可对中等体型的敌人进行正义审判,但由于弹匣容量有限,对大群敌人的攻击效果也相对受限。", + "B-01 TACTICAL": "B-01“战术”", + "Apex Protector": "巅峰护卫", + "15x100mm THERMITE": "15x100mm铝热弹", + "Blitzer": "雷霆", + "Commemorating the New Stockholm treaty on prisoners of war, this cape celebrates the right of all enemy combatants to a swift and merciful execution.": "该披肩旨在纪念关于战俘的《新斯德哥尔摩公约》,颂扬了敌方战斗人员享有的被迅速、仁慈处决的权利。", + "A drone that defends its user by firing caustic gas at nearby enemies, blinding and slowing them temporarily. Returns to backpack to refill.": "通过向周遭敌人发射腐蚀气体保护使用者的无人机,可使敌人暂时致盲并减速。收回背包可补充气体。", + "Belt-Fed Grenade Launcher Backpack": "弹链式榴弹发射器背包", + "Bearers of this armor ride no equine mount, but are nonetheless borne to battle atop the trusty steed of Liberty.": "穿上这套盔甲后虽然不能骑真正的马,却仿佛驾驭自由精神的良驹奔赴战场。", + "9x20mm RIPPER": "9x20mm撕裂弹", + "12g BUCKSHOT SHELLS": "12g鹿弹霰弹", + "DOMINATOR": "主宰", + "Upgraded Afterburner": "升级后燃器", + "ERGONOMICS": "人体工学性能", + "Liberator Carbine": "“解放者”卡宾枪", + "UF-50 BLOODHOUND": "UF-50“猎犬”", + "BASTION OF INTEGRITY": "忠义堡垒", + "Ultimatum": "最后通牒", + "ORBITAL 120MM HE BARRAGE": "轨道120MM高爆弹火力网", + "Compressed Explosives": "压缩炸药", + "B-16 Battle-Scarred Veteran": "B-16“百战老兵”", + "Longer Arc Range": "扩大电弧攻击范围", + "VOICE OF THE PEOPLE": "人民之声", + "RAIDER'S CHEER": "奇袭者的欢呼", + "NIGHT": "暗夜", + "Shotgun Show": "霰弹枪表演", + "URBAN CAMO": "城市迷彩", + "PATRIOT BLUE": "爱国蓝", + "A modified Liberator fitted with a scope and firing armor-piercing rounds, to help users take down armored targets.": "改装后的“解放者”搭配瞄准镜,可发射穿甲弹,助力使用者击倒装备护甲的目标。", + "A useful field-clearing tool for removing trees, obstacles, and unlucky foes.": "用于清除树木、障碍物和倒霉敌人的实用野外清理工具。", + "Orbital Illumination Flare": "轨道照明弹", + "HMG EMPLACEMENT": "重机枪部署支架", + "SC-34 INFILTRATOR": "SC-34“深入敌阵”", + "A barrage of gas bombs that leave a corrosive gas cloud in their wake.": "连续发射多枚毒气弹,爆炸后形成腐蚀性气团。", + "PILLARS OF DEMOCRACY": "民主之柱", + "Veil of the Valorous Vagabond": "英勇游侠之披纱", + "RECOILLESS RIFLE BACKPACK": "无后坐力炮背包", + "IE-57 HELL-BENT": "IE-57“奋不顾身”", + "FS-23 Battle Master": "FS-23“战斗大师”", + "M7S": "M7S", + "12mm": "12mm", + "A projectile which explodes while airborne, creating a deadly rain of shrapnel. Not effective against heavy armor.": "射弹在空中引爆,而后弹片散落,如同致命的雨点。对重型装甲无效。", + "A machine gun designed for stationary use. Trades higher power for increased recoil and reduced accuracy.": "为固定使用而设计的机枪。提高了火力,但后坐力增加,精准度也降低了。", + "9x70mm Self Propelled": "9x70mm自走弹", + "BREAKTHROUGH EXOSUIT": "“突破”外骨骼装甲", + "Anti-Tank Emplacement": "反坦克炮台", + "Each servo-assisted limb contains 138 miniature motors, to support a natural gait and long-term spinal health.": "各伺服辅助肢体包含138个微型马达,以实现自然步态,从长远角度保障脊柱健康。", + "SCYTHE": "长柄镰", + "Rail Cannon Round": "轨道炮弹", + "RS-67 NULL CIPHER": "RS-67“空密码”", + "MIRANDA'S LEGACY": "米兰达的遗志", + "BP-77 Grand Juror": "BP-77“大陪审员”", + "A flare that illuminates the battlefield.": "可以照亮战场的照明弹。", + "Urchin": "海胆", + "Upon initial impact, the deployer scatters a wide field of proximity-detonated submunitions. These charges deal minimal damage, but will heavily stun and decelerate encroaching hostiles.": "刚落地时,部署器会撒布大片近炸子弹药场。这些炸药造成的伤害极小,但能对逼近的敌军产生强力眩晕和减速效果。", + "Shear": "切变", + "SHOCK AND AWE IMPROVEMENT": "提高震慑威力", + "CE-74 Breaker": "CE-74“破裂者”", + "INCENDIARY IMPACT": "燃烧冲击弹", + "Dagger": "匕首", + "A replacement for a fallen comrade.": "阵亡战友的替补兵员。", + "MARTYRIS REX": "殉道之王", + "AGAINST THE TYRANT CLOUD": "破除暴瘴", + "REDEEMER": "救世主", + "United in Equality": "仰齐与共", + "UPLOAD DATA": "上传数据", + "TRUTH WHISPERER": "真理低诉者", + "A targeted air strike unable to destroy buildings, but efficient at clearing smaller targets.": "定向空袭,无法摧毁建筑,但可以有效清除较小型目标。", + "Way of the Bandolier": "弹带之道", + "FLAK": "高射炮弹", + "R-4": "R-4", + "Lean": "清瘦", + "Provides one-time, short-lived resuscitation upon death, given that the Helldiver's body is still intact.": "在绝地潜兵躯体完好的前提下,死亡后可获得一次短暂的复活机会。", + "Larger Magazine": "扩容弹匣", + "Tip Hat": "脱帽致意", + "A laser rifle, firing in short bursts. Does not need reloading, but if it overheats a new heat sink must be fitted.": "可瞬间喷射高能激光束的激光步枪。无需重新装弹,但如果步枪过热,必须安装新的散热器。", + "PURIFIER": "净化者", + "CQC-73": "CQC-73", + "MD-8": "MD-8", + "P-113": "P-113", + "Higher Missile Damage": "提升导弹伤害", + "ARC-12": "ARC-12", + "Crisper": "迅击", + "Advanced Vertical Foregrip": "高级垂直前握把", + "LAS-7": "LAS-7", + "VERIDICAL IDEOLOGY": "真理意识形态", + "AR-59": "AR-59", + "A single-use weapon sporting caseless ammunition stacked in multiple barrels. An electrical firing mechanism releases the rounds in rapid succession upon firing, after which the weapon is to be discarded.": "采用无壳弹药与多枪管叠加设计的一次性武器。开火时,电控击发装置会快速清空弹药,弹药清空后即可丢弃该武器。", + "Orbital EMS Strike": "轨道电磁冲击波攻击", + "Tighter Breech Lock": "收紧枪闩锁", + "Creates a #BONUS chance of surviving a lethal hit.": "在受到致命一击后有#BONUS的几率存活。", + "SHOTGUN SHOW": "霰弹枪表演", + "SEAF Squad": "超级地球武装小队", + "A paint job for use in arctic environments.": "适用于雪地环境的涂装。", + "A submachine gun with an extremely high rate of fire, which can be operated with one hand. Ideal for multitasking.": "射速极高的冲锋枪,可单手操控。同时处理多重任务时的理想之选。", + "The breathing apparatus built into this equipment helps both soldiers and colonists thrive, even when assigned to planets with atmospheres rated \"suboptimal,\" \"extreme,\" and \"character building.\"": "这套装备的内置呼吸装置能帮助士兵和拓殖地居民畅快呼吸,即使被派往评级为“次优”、“恶劣”和“磨练性格”的星球也应付自如。", + "Shorter Recharge Delay": "缩短充能延迟", + "The dauntless pioneers of the Great Expansion, facing the un-Democratic unknown, adopted the Way of the Bandolier. With the gusto of their covering fire making up for their modest accuracy, they strived to be perfectly aligned in their shared values, and ready to serve when called upon by the machine gun of civic duty.": "面对尚未民主化的未知世界,大扩张时期的无畏先驱者践行弹带之道。他们用狂热的火力掩护弥补射击准度的不足,奋力追求共同价值观的完美统一,并时刻响应公民责任机枪的召唤,随时准备投身战斗。", + "A-9 Helljumper": "A-9“地狱伞兵”", + "SA-12 Servo-Assisted": "SA-12“伺服辅助”", + "STOCKED HELLPODS": "备量充足的喷射舱", + "CQC-1": "CQC-1", + "CQC-19": "CQC-19", + "70mm Standard Rocket": "70mm标准火箭弹", + "12g TRI-BALL": "12g三连弹", + "Command Center of the Super Destroyer. The helm from which Helldivers deliver Freedom's mercy.": "超级驱逐舰的指挥中心,绝地潜兵通过这个船舵传递自由精神的仁慈。", + "Stocked Hellpods": "备量充足的喷射舱", + "AF-91 Field Chemist": "AF-91“实地化学家”", + "AR-32": "AR-32", + "8x60mm SUPER URANIUM CORE": "8x60mm超铀芯弹", + "FOREST CAMO": "森林迷彩", + "URCHIN": "海胆", + "Drilling Charge": "强钻炸药", + "CE-64 GRENADIER": "CE-64“掷弹兵”", + "9x20mm TOXIC": "9x20mm毒弹", + "COURTLY BOW": "恭敬鞠躬", + "ANTI-TANK MISSILES": "反坦克导弹", + "EAGLE AIRSTRIKE": "“飞鹰”空袭", + "This vision-disruptive pattern cloaks the silent crusaders whose untraceable deeds are a pure expression of true Freedom: freedom from accountability.": "这种干扰视觉的图案能够有效掩护寂静无声的圣战士,他们难以捉摸的行踪纯粹地展现了真正的自由,即免责的自由。", + "12g Flechettes": "12g飞镖弹", + "INDEPENDENCE BRINGER": "独立先驱", + "Smoke": "烟雾弹", + "Training Maneuvers": "军事演习", + "G-23": "G-23", + "ROUNDS RELOAD": "逐发装弹", + "DEFAULT HELLDIVER VOICE 2": "绝地潜兵默认声音 2", + "GS-66 Lawmaker": "GS-66“立法者”", + "A LAS-16 Sickle model with all overheating protections conveniently removed, allowing for far longer bursts of fire. Does more damage when overheated, at the cost of slightly burning the user.": "移除所有过热保护机制的LAS-16“镰刀”型号,显著延长连射时间。 过热时会造成更大伤害,但会轻微灼伤使用者。", + "STUN ROUNDS": "眩晕弹", + "12x25mm PLASMA": "12x25mm等离子弹", + "SIEGE-READY": "蓄势出击", + "O-2 Heavy Operator": "O-2“重装操作者”", + "A Dark Fluid-powered backpack that generates a portable micro-wormhole. This safe and well-understood technology allows the wearer to warp short distances. Warning: do not use while pack is overloaded.": "暗液体驱动的背包,可生成便携式微型虫洞。这项安全且成熟的技术可助使用者进行短距离传送。警告:背包过载时请勿使用。", + "SR-64 Cinderblock": "SR-64“煤渣砖”", + "Laser Sight Angled Foregrip": "激光瞄准器与直角前握把", + "12x25mm Full Metal Jacket": "12x25mm全金属被甲弹", + "Wide Spread": "扩散", + "Cresting Honor": "荣誉之巅", + "A representation of the thankfulness of those infinite descendants whose liberated existence we strive to ensure.": "我们竭尽全力让无数后代过上解放的生活,而这代表了他们的感激之心。", + "An angled vertical foregrip to improve the maneuverability of the weapon.": "直角垂直前握把,可提升武器操控性。", + "INCREASED FIRE RATE": "提升射速", + "Enthusiastic Mirth": "开怀大笑", + "5.5x50mm Penetrator": "5.5x50mm穿甲弹", + "A submachine gun with a longer barrel, allowing for higher muzzle velocity and increased armor penetration.": "配备加长枪管的冲锋枪,枪口初速更高且具备更强的护甲穿透能力。", + "\"The Helldivers are all that stand between Democracy and the Fascist hordes. Trained since birth in the art of Defensive Warfare, they meet mindless legions with the steady aim of one who has seen countless battles.\" —Excerpt from the journal of a Charan Democracy Officer, ca. 2082 SE": "“绝地潜兵是阻挡在民主与法西斯暴民之间的唯一屏障。他们自出生起就接受防御战争的训练,以久经沙场的沉稳精准迎击无脑军团。”——摘自常陈四民主官日记,超级地球历2082年前后", + "More Backpack Ammo": "增加备用弹药", + "DIGNITY OF TOIL": "劳作的荣光", + "EMANCIPATOR EXOSUIT": "“解放者”外骨骼装甲", + "In field tests, 84% of users said that the armor improved their posture and self-esteem.": "实地测试中,有84%的使用者表示此盔甲改善了他们的体态,也提升了他们的自尊心。", + "CREST OF THE UNSULLIED": "无垢徽章", + "B-02 GLOOM WARDEN": "B-02阴霾守望者", + "STANDARD ISSUE": "标准制式", + "Composed of reclaimed industrial mesh and salvaged banners. This cape celebrates the beauty found in the aftermath of purging Tyranny at high-speeds. The debris of these successes, and those like it, remind us all of the sanctity of Sovereignty.": "由回收的工业网格和残破旗帜组成。这件披肩赞美了疾速肃清暴政后产生的美感。这些成功的残骸提醒所有人:主权神圣不可侵犯。", + "SHIELD GENERATOR RELAY": "防护罩生成中继器", + "A heavy one-handed blade. Slower to swing than other melee weapons, but deals more damage.": "沉重的单手刀。挥舞速度比其他近战武器慢,但造成的伤害更高。", + "CURTSY": "屈膝礼", + "FLASHIELD": "闪光护盾", + "BOTSLAYER": "机械屠戮者", + "A symbol of Super Earth's Astral Promise: that every star shall one day illuminate throngs of joyous voters.": "超级地球星之承诺的象征:终有一日,每一颗星都将因快乐的选民而闪亮。", + "RE-1861 PARADE COMMANDER": "RE-1861“阅兵指挥官”", + "Incendiary Impact": "燃烧冲击弹", + "DOUBLE MACHINEGUN POD": "双机枪喷射舱", + "Sidearm recoil reduced by #BONUS.": "副武器后坐力降低#BONUS。", + "STICKY": "粘性", + "Commonly replicated in stage adaptions of \"Lady Liberty's Tower\", in which young Diver Beatrick dons this armor to slay Oppressio, the Tyrant Rex.": "这套盔甲常见于《自由女神塔》的舞台剧版本,剧中年轻的绝地潜兵比特里克正是身着这套盔甲,斩杀暴君王奥普雷西奥。", + "FIRE MODES": "开火模式", + "STILL STANDING": "屹立不倒", + "Eagle Airstrike": "“飞鹰”空袭", + "SMOKESCREEN": "烟幕", + "100kg Bomb": "100KG炸弹", + "Clapping": "鼓掌", + "Although Super Citizen Miranda's true identity has been lost to time, most legal historians agree that she was once a patron of highly-efficient interrogation techniques.": "尽管超级公民米兰达的真实身份已被时间湮没,但大多数法律史学家一致认为,她曾是高效审讯技术的赞助人。", + "HONORED HEIRLOOM": "荣耀传家宝", + "This armor was designed by PFC Rodney A. Carmichael, the first Helldiver to use a stim on an ally instead of himself.": "此盔甲由一等兵罗德尼·A.·卡迈克尔设计,他是首位将治疗剂用在队友身上(而不是自用)的绝地潜兵。", + "AUTOCANNON BACKPACK": "机炮背包", + "Fires powerful exploding bolts which do maximum damage upon direct impact. Gravity must be accounted for when aiming.": "发射威力强大的爆炸弩箭,对直接命中的目标造成最大伤害。瞄准时必须考虑重力因素。", + "Bushwhacker": "游击兵", + "HELL COMMANDER": "地狱上尉", + "9x20mm PLASMA": "9x20mm等离子弹", + "SR-64 CINDERBLOCK": "SR-64“煤渣砖”", + "Increased Magazine Capacity": "提升弹匣容量", + "A grenade launcher that can be fired continuously to deliver a nonstop barrage of explosives.": "可持续射击的榴弹发射器,能够不间断地倾泻火力。", + "Improved Ammo Storage Mk2": "弹药存储量升级 MK2", + "GUARD DOG": "“护卫犬”", + "CW-36 Winter Warrior": "CW-36“冬日战兵”", + "SHORT MAGAZINE": "短弹匣", + "EXO-55": "EXO-55", + "FS-37 RAVAGER": "FS-37“破坏者”", + "STANDARD PRISM": "标准棱镜", + "PROSPEROUS GREEN": "繁荣绿", + "40mm HE Grenade": "40mm高爆榴弹", + "PUNISHER PLASMA": "等离子“制裁者”", + "P-35": "P-35", + "IMPROVED TARGETING SYSTEM": "改良目标锁定系统", + "PH-9 Predator": "PH-9“掠食者”", + "#NAME #TYPE": "#NAME#TYPE", + "When donning the One True Flag, one must face the direction of Super Earth, recite the Super Earth Anthem, and salute one's own image in the nearest reflective surface. Wrongful discarding of this cape is a capital offense.": "身披这件印有“唯一真旗”的披肩时,必须面朝超级地球,唱响超级地球国歌,并向最近反光面中的自己敬礼。错误丢弃此披肩者,罪当处死。", + "A paint job for use in forest environments.": "适用于森林环境的涂装。", + "Orbital 120mm HE Barrage": "轨道120mm高爆弹火力网", + "CQC-72": "CQC-72", + "IE-12 Righteous": "IE-12“义士”", + "Let the Second Anniversary of the Second Galactic War be witnessed by the lidless eye of Liberty, that ever-watchful orb which provides safety through its ceaseless surveillance.": "自由之眼永不阖目,它将见证第二次星系战争进入两周年,并通过无休止的监视为我们提供安全。", + "ROUNDS": "弹药", + "SMG-72": "SMG-72", + "A holographic sight.": "全息瞄准镜。", + "Resupply": "重新补给", + "DEEP REFLECTION": "沉思", + "Carpet Bomb": "地毯式轰炸", + "After extensive testing in Patriotic Rehabilitation Centers, this design was proved most terrifying to dissent-afflicted individuals.": "爱国康复中心的详尽测试证明,这是最令异见分子感到恐惧的设计。", + "Gas Mortar Sentry": "瓦斯迫击哨戒炮", + "SSSD DELIVERY": "运送超级固态硬盘", + "Creates a large, thick smoke screen to block targets' line of sight.": "可形成一道厚重的大型烟幕,遮挡目标的视线。", + "CB-9": "CB-9", + "HEAVY MACHINE GUN": "重机枪", + "Designed by fashion legend RH Gant, the pattern seen on this cape also appears on domestic dresses and gun-warmers.": "由时尚传奇RH·甘特设计,披肩上的图案同时也用于家居服和暖枪套。", + "ADDITIONAL ROCKET PODS": "附加火箭巢", + "HIGH DISSIPATION HEATSINK": "高功率散热器", + "LAS-16": "LAS-16", + "Plasma Igniter Compensator": "等离子点火器补偿器", + "Immolation": "焚身", + "5.5x50mm Super Uranium Core": "5.5x50mm超铀芯弹", + "TM-1": "TM-1", + "P-2": "P-2", + "STUN BATON": "眩晕短棍", + "66mm Missile": "66mm导弹", + "VIPER COMMANDO": "毒蛇突击兵", + "The symbol on this cape represents the pillars of freedom: duty, obedience, and loyalty.": "披肩上的标志象征着自由的三大支柱:责任、服从、忠诚。", + "Additional Canisters": "附加燃料罐", + "COLONY SAVIOR": "拓殖地救星", + "LARGER SHIELD": "延展护盾", + "G/SH-39": "G/SH-39", + "MAX RANK INFINITY": "无限最高等级", + "Fire Rate Selection": "可选射速", + "JUDGMENT DAY": "审判日", + "De-Escalator": "缓和使者", + "Gallant": "英勇无畏", + "Rags of the Fashionable": "时尚褴褛", + "AF-52 LOCKDOWN": "AF-52“禁锢”", + "CREW TRAINING": "船员训练", + "ELECTRICAL CONDUIT": "电路导管", + "This modest cape has been worn by those guarding the Chamber of Unanimous Decision since time immemorial.": "这件简朴的披肩自古便由统一决策大厅的守卫佩戴。", + "5.5x50mm Devastator": "5.5x50mm“毁灭者”子弹", + "BADGE OF ORDER": "秩序徽章", + "5.5x50mm Double Power": "5.5x50mm双效子弹", + "SHRAPNEL": "榴霰弹", + "BP-20 CORRECT OFFICER": "BP-20“思想矫正官”", + "PROGRAMMABLE AMMUNITION": "智能弹药", + "DS-191 SCORPION": "DS-191“天蝎”", + "SA-25 STEEL TROOPER": "SA-25“钢铁士兵”", + "9x70mm Full Metal Jacket": "9x70mm全金属被甲弹", + "SEAF ARTILLERY: HIGH-YIELD EXPLOSIVE": "超级地球武装部队大炮:高爆弹", + "110mm E.M.S. CANNON ROUND MK3": "110mm电磁冲击波炮弹 MK3", + "5.5x50mm Subsonic": "5.5x50mm亚音速弹", + "COMBAT BLEND": "混合作战", + "12g MAGNUM TRIBALL": "12g马格南三连弹", + "Anti-tank Mines": "反坦克地雷", + "RELOAD TIME": "装弹时间", + "UF-84 Doubt Killer": "UF-84“疑虑克星”", + "Coyote": "野狼", + "CREMATOR BACKPACK": "焚燃者背包", + "Durable, waterproof, and thermally-lined, surplus units of this cape are favored by domestic campers, to make tents.": "耐用、防水,搭配保暖内衬,这款披肩的剩余布料也受到了国内露营爱好者的青睐,用于制作帐篷。", + "WEDGEFUL TRICORN": "楔形三角披肩", + "Recoilless Rifle Backpack": "无后坐力炮背包", + "M6C/SOCOM": "M6C/特种作战", + "12g BUCKSHOT MAGNUM SHELLS": "12g鹿弹马格南霰弹", + "PYTHON COMMANDO": "蟒蛇突击兵", + "Foesmasher": "歼敌战士", + "Stuns enemies performing melee attacks. Must recharge for #BONUS.": "眩晕发动近战攻击的敌人。必须充能#BONUS。", + "CM-10 CLINICIAN": "CM-10“临床医师”", + "One True Flag": "唯一真旗", + "Tideturner": "力挽狂澜", + "Recoilless Rifle": "无后坐力炮", + "66mm MISSILE": "66mm导弹", + "DEFAULT TRIGGER": "默认扳机", + "Orbital Walking Barrage Smoke": "轨道游走烟雾火力网", + "Covering Fire": "火力掩护", + "Cookout": "野炊", + "A powerful automated turret, effective against armored targets. The turret will primarily aim at larger enemies.": "强力自动炮台,可有效对付装甲目标。炮台主要瞄准攻击较大型的敌人。", + "TD-220": "TD-220", + "Flex": "炫耀", + "Honored Heirloom": "荣耀传家宝", + "9x70mm Super Uranium Core": "9x70mm超铀芯弹", + "High Explosive": "高爆弹", + "9x20mm Plasma": "9x20mm等离子弹", + "MUDSKIPPER": "弹涂鱼", + "FS-40 Diplomat": "FS-40“外交官”", + "Developed by the Ministry of Science while investigating the phenomenon known as The Gloom, this armor is non-permeable and squeak resistant.": "科学部在调查“阴霾”现象时研制而成,该盔甲防渗透性佳,穿上后也不会吱吱作响。", + "Diplomatic Handshake": "外交礼节式握手", + "Cover of Darkness": "黑夜守护", + "\"Where lesser soldiers break, Helldivers obey. When Tyranny's horrors swarm, Helldivers obey. When death is certain, and hope and sense have fled, Helldivers obey.\" — Last Lord Governor of Chara.": "“寻常士兵溃不成军之时,绝地潜兵谨遵号令。暴政恐怖肆虐之际,绝地潜谨遵号令。当死亡已成定局、希望与理智破灭,绝地潜兵谨遵号令。”——常陈四最后一任总督。", + "UNBLEMISHED ALLEGIANCE": "无瑕忠诚", + "Shrapnel": "榴霰弹", + "Provides a higher armor rating.": "提供较高的盔甲等级。", + "SG-8S": "SG-8S", + "B-100": "B-100", + "Napalm Bomb Mk3": "凝固汽油弹 MK3", + "Features a utility belt with pockets that can be filled with any number of things, such as pocket knives, mementos from home, and interesting rocks.": "配有带口袋的实用腰带,可装入各式各样的物品,如便携刀具、家乡的纪念品和有意思的石头。", + "JAR-5": "JAR-5", + "I-09 HEATSEEKER": "I-09“热力追踪”", + "ORDER OF THE VENERATED BALLOT": "神圣投票团", + "A backpack which can be wielded as a one-handed ballistic shield, protecting against small arms fire.": "可用作单手防弹护盾的背包,能抵挡轻型武器的射击。", + "DETONATE": "引爆", + "This patriotic armor comes recommended by the Ministry of Expansion, empowering the wearer to re-seize from our enemies any territory that any human has laid claim to, at any point in time.": "扩张部强烈推荐这款宣扬爱国主义的装甲,它将赋予穿戴者力量,帮助他们从敌人手中夺回人类在各历史时间节点曾宣称主权的领土。", + "SA-04 Combat Technician": "SA-04“技术兵”", + "EAGLE NAPALM AIRSTRIKE": "“飞鹰”凝固汽油弹空袭", + "Designed in homage to the triangle—the most immovable of shapes—this cape digs its heels into the eye of the observer, leaving a lasting impression.": "这款披肩的设计致敬了三角形这一最稳固的几何形状,以其坚定不移的姿态直击观者眼球,留下深刻印象。", + "AD-11 LIVEWIRE": "AD-11“生龙活虎”", + "DRAPE OF GLORY": "荣光加身", + "The three stripes on the pauldrons stand for the three principles of Super Earth: Liberty, Democracy, and Prosperity.": "护肩上的三条纹象征着超级地球的三大原则:解放、民主与繁荣。", + "It is well-documented that soldiers raised on harsh planets have an advantage when fighting in similar environments; this insight is foundational to the Democratic Youth Scouts Exchange Program.": "有充分记录表明,在恶劣星球上成长的士兵在类似环境中作战时具有优势。这样的洞察为民主青少年童子军交流计划奠定了基础。", + "This cape recalls the popular folk tale of the \"Freedomslingers\": re-educated dissidents, seeking redemption on the Federation's Borderline, hunting dangerous thought-traitors in exchange for ballot bounties.": "这件披肩让人想起民间广为流传的“自由神枪手”的故事:接受过再教育的异见分子在联邦边境线上寻求救赎,通过追捕危险的思想叛徒换取选票赏金。", + "A modern reinvention of the Lumberers of the first Galactic War, this Exosuit is equipped with a flamethrower and an anti-tank cannon.": "这款外骨骼装甲是第一次星系战争中“伐木者”机甲的现代重制版,配备火焰喷射器和反坦克炮。", + "Scrambler": "扰频器", + "TYRANNY'S BANE": "暴政的毁灭", + "Reprimand": "训斥", + "SG-20": "SG-20", + "MARSHAL": "元帅", + "EAGLE GAS AIRSTRIKE": "“飞鹰”毒气空袭", + "Featuring an ancient sun symbol and a distressed look, this cape reminds us that the light of Liberty is everlasting, and will keep shining even when we ourselves have become tattered and frayed.": "这件破旧的披肩饰有古老的太阳符号,提醒我们自由之光永存不灭,即使我们自身变得残破不堪,它也将继续闪耀。", + "Default Helldiver Voice 1": "绝地潜兵默认声音 1", + "BP-32 Jackboot": "BP-32“杰克军靴”", + "BLAST RADIUS": "爆炸半径", + "RE-824 BEARER OF THE STANDARD": "RE-824“执旗手”", + "ADJUDICATOR": "审判者", + "MORE AMMO IN BACKPACK": "增加背包弹药数量", + "SCRAMBLER": "扰频器", + "The memory of the Martian training grounds will endure, even after all the Helldivers who trained there have passed, some day in the far future.": "即使在遥远的未来,所有曾在火星训练场接受训练的绝地潜兵都已逝去,关于那里的记忆也永远不会褪色。", + "VARIABLE": "变数", + "CAUSTIC": "腐蚀气体", + "An automated turret that fires gas shells. Its targeting system prioritizes hostiles not yet exhibiting symptoms caused by gas inhalation. Users are advised to stay significantly upwind of the resulting crowd control.": "一种发射毒气弹的自动炮塔。其瞄准系统优先锁定尚未中毒的敌对目标。使用者应保持上风方位,避免被群体控制影响。", + "NEW EXPLOSIVE FILLER": "新式爆炸物填料", + "Named for Helldiver Jack Boote, who shut down 908 illegal broadcasts before retiring with honors.": "以绝地潜兵杰克·布特命名,他在光荣退役前曾查封了908个非法广播。", + "As documented in the bestselling graphic novel \"The Breach,\" the final mission of the 361st \"Freedom's Flame\" saw the storied unit deploy straight into the heart of a Supervolcano, sacrificing themselves to trigger an eruption and wipe out a massive Terminid swarm.": "根据畅销图像小说《突破》的描述,大名鼎鼎的361“自由烈焰”部队最后一次执行的任务是直接部署到超级火山的核心地带,英勇地牺牲自我,引发火山喷发,消灭数量庞大的终结族虫群。", + "LIBERATOR PENETRATOR": "穿甲“解放者”", + "ANTI-AIR MISSILE": "防空导弹", + "A modified Breaker shotgun firing incendiary projectiles. Generates heat during use, so limited to burst fire.": "改良后的“破裂者”霰弹枪,可发射燃烧弹。在使用过程中会产生热量,因此会限制连发射击。", + "A modified Liberator firing concussive rounds which do less damage but stagger enemies.": "改良版“解放者”,可连续发射震荡弹。虽然造成的伤害不大,但可击退敌人。", + "Pillar of the Abyss": "深渊支柱", + "12g Magnum": "12g马格南霰弹", + "STINGER": "毒刺", + "FLECHETTES": "飞镖弹", + "Expendable Anti-Tank": "消耗性反坦克武器", + "Voice of the People": "人民之声", + "13x40mm RIPPER": "13x40mm撕裂弹", + "FS-61 Dreadnought": "FS-61“无畏”", + "TIDETURNER": "力挽狂澜", + "A magazine with a very high capacity at the cost of being bulky and heavy.": "该弹匣的弹药容量极大,但较笨重。", + "Seeker": "寻踪者", + "A single-use weapon that fires a missile containing napalm cluster bombs that release upon impact.": "一次性武器,发射的导弹会在撞击时释放凝固汽油集束炸弹。", + "Frag": "破片弹", + "Standard Plasma Container": "标准等离子弹药匣", + "BASTION MK XVI": "堡垒MK XVI", + "PRIVATE": "列兵", + "CAMO CLOAK": "迷彩斗篷", + "Thumper": "桩锤", + "Independence Bringer": "独立先驱", + "EAT-700": "EAT-700", + "A/LAS-98": "A/LAS-98", + "Cluster Bomb": "集束炸弹", + "SUPPRESSED": "消音", + "MED-KIT": "急救包", + "HE MK2": "高爆弹 Mk2", + "Programmable Ammunition": "智能弹药", + "Flamethrower": "火焰喷射器", + "CAPACITY": "容量", + "LARGE AMMO-DRUM": "大容量弹鼓", + "CPG-48 SAPPER": "CPG-48“工兵”", + "DEFAULT HELLDIVER VOICE 1": "绝地潜兵默认声音 1", + "POSTERITY'S GRATITUDE": "后族怀恩", + "IMPROVED SERVOS": "改良伺服系统", + "30mm APHE CANNON": "30mm穿甲高爆炮弹", + "10g Tri-Ball": "10g三连弹", + "Users are advised not to scratch at the lacquer, as the Red 20,000 pigment that gives this armor its signature sheen may be correlated with rapid DNA unspooling.": "赋予盔甲标志性光泽的红色20,000颜料恐会导致DNA快速解旋,建议用户不要划伤漆面。", + "20mm Flak Rounds": "20mm高射炮弹", + "EXEMPLARY SUBJECT": "模范试验体", + "An advanced angled foregrip to improve weapon stability.": "高级直角前握把,可提升武器稳定性。", + "A shorter magazine with lower capacity, making it lighter and easier to handle.": "弹药容量较小的短弹匣,重量更轻,操控更方便。", + "12x25mm EXPLOSIVE": "12x25mm爆炸子弹", + "WIDE PRISM": "加宽棱镜", + "12.5mm BCHP RIFLE ROUNDS": "12.5mm粘合弹芯空尖弹", + "LASER SIGHT ANGLED FOREGRIP": "激光瞄准器与直角前握把", + "Inside the collar is embroidered: \"Wherever I may plant my shield, know that I will never yield,\" and \"machine washable.\"": "衣领内侧绣有“无论护盾所立何方,我绝不会屈膝投降”和“可机洗”字样。", + "Censor": "审查官", + "Courtly Bow": "恭敬鞠躬", + "MANTLE OF TRUE CITIZENSHIP": "忠诚公民之斗篷", + "10g DUAL SABOT": "10g双萨博特式霰弹", + "A Hellpod containing a Super Solid State Drive, the peak of secure data storage. Used by Helldivers for everything from transfer of patriotic data to the sabotage of enemy mainframes.": "装有最为安全的数据存储,超级固态硬盘的绝地喷射舱。从传输爱国数据到破坏敌人主机,绝地潜兵将其用于各种用途。", + "LIFT-850": "LIFT-850", + "MEDIUM PLASMA BOLT": "中型等离子弹", + "ONE-HANDED": "单手操作", + "8x60mm High Velocity": "8x60mm高速弹", + "The muted colors and relaxed, high-mobility fit make this a favorite among long-distance snipers and hide-and-seek champions alike.": "这套装备还采用暗沉色调与宽松灵活的版型,深受远程狙击手和潜行高手的喜爱。", + "A smoke grenade that rapidly deploys a small, dense cloud. Allows for rapid personal concealment and exfiltration.": "快速在小范围内释放高密度烟雾的烟雾弹。有助于隐蔽个人行踪和掩护撤离行动。", + "Flames Mk2": "喷射火焰 MK2", + "Better Racks": "提高挂架质量", + "12.5mm BCHP Rifle Rounds": "12.5mm粘合弹芯空尖弹", + "This armor uses repurposed metal from verified sources, such as vending machine packaging and Automaton scrap, making it a sustainable choice for the environmentally conscious Helldiver.": "这套盔甲采用来源经核实的回收金属材料,如自动售货机外壳和机器人废料,是具有环保意识的绝地潜兵的可持续之选。", + "O-3 FREE SPIRIT": "O-3“自由之魂”", + "SCORCHER": "焦土", + "SA-7 HEADFIRST": "SA-7“冲锋者”", + "Maxigun": "重装机枪", + "BREAKER BUGBITER": "噬虫“破裂者”", + "Advanced Angled Foregrip": "高级直角前握把", + "15x100mm PLASMA": "15x100mm等离子弹", + "ORBITAL EMS STRIKE": "轨道电磁冲击波攻击", + "KDM-763 Pacesetter": "KDM-763“领跑者”", + "Flame Sentry": "火焰喷射哨戒炮", + "AR-2": "AR-2", + "12MM": "12MM", + "Commando": "突击兵", + "Extra Backpacks": "额外补给", + "Thundering Hooves of Loyalty": "忠诚惊雷之蹄", + "CE-67 Titan": "CE-67“泰坦”", + "ORBITAL GATLING BARRAGE": "轨道加特林火力网", + "SR-18 Roadblock": "SR-18“路障”", + "Pillars of Democracy": "民主之柱", + "MGX-42": "MGX-42", + "StA-52": "StA-52", + "B-01 Tactical": "B-01“战术”", + "FASTER DEPLOY TIME": "缩短部署用时", + "DS-42 FEDERATION'S BLADE": "DS-42“联邦之刃”", + "A sledgehammer that can be wielded with or without an explosive charge attached to its head.": "大锤头部可安装炸药,也可单独使用。", + "PH-202 Twigsnapper": "PH-202“折枝”", + "DP-8 Mountain-Scaled": "DP-8“山峦鳞甲”", + "Wedgeful Tricorn": "楔形三角披肩", + "Flames": "喷射火焰", + "Improved Durability": "提升耐久度", + "JUSTICE FOR ALL": "全民正义", + "INTEGRATED EXPLOSIVES": "集成炸药", + "COVER OF DARKNESS": "黑夜守护", + "110mm GAS CANNON ROUND": "110mm毒气炮弹", + "The understated color scheme and precision-molded armor plates make this armor a sensible choice for the Helldiver on the go.": "精密铸造的护甲板加上低调的配色,这套护甲是绝地潜兵在配置行动装备时的明智之选。", + "An automated flamethrower turret. Warning: fuel canister prone to explosion when ruptured.": "自动火焰喷射器炮台。警告:燃料罐破裂时易爆炸。", + "Made famous by the \"Truth Enforcers: Enforcers of Truth\" mystery novels, this armor calls to mind those paragons of patriotism who protect us from treasonous lies.": "这套盔甲因《真理执行者:真理的执行者》悬疑小说而闻名,让人想起那些保护我们免受叛国谎言蛊惑的爱国典范。", + "Heavy Machine Gun": "重机枪", + "A combination assault rifle/grenade launcher. Versatile, but heavy to wield.": "突击步枪与榴弹发射器的组合武器。用途广泛,但比较像重型武器的操控手感。", + "CHIEF": "军督", + "Markers placed on the map will generate radar scans every #BONUS.": "地图上的标记每隔#BONUS进行一次雷达扫描。", + "8x60mm Devastator": "8x60mm“毁灭者”子弹", + "STOKER": "司炉者", + "More Rounds": "增加弹药", + "VEIL OF THE VALOROUS VAGABOND": "英勇游侠之披纱", + "A very powerful but difficult-to-wield machine gun with intense recoil.": "火力凶猛的机枪,但后坐力强,较难操控。", + "A single-use weapon specialized for damaging vehicle armor. Discarded after every use.": "专门破坏载具装甲的一次性武器。用后即弃。", + "10-STAR SUPER PRIVATE": "十星超级列兵", + "9x70mm PENETRATOR": "9x70mm穿甲弹", + "Flashlight": "照明", + "DIPLOMATIC HANDSHAKE": "外交礼节式握手", + "Larger Search Radius": "扩大搜索半径", + "TRIANGULATION VEIL": "三角定位披纱", + "ANTI-AIR": "防空", + "StA-X3": "StA-X3", + "MELTA MINE": "热熔地雷", + "The cape's shredded hem presages the unrelenting savagery its wielder will visit upon the nemeses of Freedom.": "此披风的碎边预示着穿戴者将对自由死敌发动无情蛮攻。", + "SHIELD": "盾雷", + "MORE DURABLE CHASSIS": "提升底盘耐久度", + "A variation on the reflex sight.": "改良版反射式瞄准镜", + "Upload Data": "上传数据", + "Eagle Smoke Strike": "“飞鹰”烟雾攻击", + "DILIGENCE COUNTER SNIPER": "反狙击“勤勉”", + "Laser Cannon": "激光大炮", + "The crest on this armor's shoulder shows friendlies that safety is near, and foes that they have reached the end of the road.": "盔甲肩部的徽章向友军传递安全已近在咫尺的信息,同时向敌人宣告它们已走投无路。", + "40mm FLAK CANNON": "40mm高射炮弹", + "This armor, coated in radar-absorbent polymers and a null-signature heat baffle, reportedly turns its wearer into a sensor ghost—a claim attributed to individuals who, curiously, appear to have never existed.": "盔甲的外层是雷达吸波聚合物和匿迹热隔板,据称能让穿戴者变成传感器探测不到的幽灵,有趣的是,如此声称的人似乎从未存在过。", + "EXPENDABLE ANTI-TANK": "消耗性反坦克武器", + "Ranger": "游骑兵", + "A projectile which releases a cloud of caustic gas, blinding and slowing most enemies.": "释放腐蚀性气团的射弹,可使大多数敌人致盲并减速。", + "CM-06 Combat Medic": "CM-06“医疗兵”", + "ADVANCED FILTRATION": "高级过滤能力", + "Breaker": "破裂者", + "A camo paint job for use in desert environments.": "适用于沙漠环境的迷彩涂装。", + "The CW-22 Kodiak armor was thoroughly pressure-tested by patriotic volunteers, as part of the \"Test Subjects for Super-Earth\" Citizen Advancement Program.": "该“科迪亚克”盔甲作为“超级地球测试对象”公民进步计划的一部分,其经过了爱国志愿者全面的压力测试。", + "HIGHER MISSILE DAMAGE": "提升导弹伤害", + "12x25mm Hollow Point": "12x25mm空尖弹", + "The pattern used for this armor is the result of the Winter Camouflage Improvement Effort, which considered 136 entrants before determining the color white would best blend in with snow.": "此盔甲的图案是冬季迷彩优化工作的成果。在综合考虑136位参与者的提案后,最终决定白色与雪地的融合度最高。", + "Targeting Sensors": "目标锁定传感器", + "Epoch": "纪元", + "Eagle Rearm": "重新武装“飞鹰”", + "SH-32": "SH-32", + "With its rustic charm and huntsmanlike detailing, this armor evokes those heroic expansionists who braved the alien wilds and ushered in our current age of bio-uniformity.": "这套盔甲充满猎装细节,质朴的风格另有一番魅力,唤起人们对英雄开拓者的敬意,正是前辈勇闯异星荒野,引领我们迈入当今的生物统一时代。", + "10g Dual Sabot": "10g双萨博特式霰弹", + "9x70mm Penetrator": "9x70mm穿甲弹", + "E/M-105": "E/M-105", + "SHORTER COOLDOWN": "冷却用时缩短", + "Extra Magazines": "额外弹匣", + "CLOAK OF POSTERITY'S GRATITUDE": "后族怀恩披风", + "Silencer": "消音器", + "MELTAGUN": "热熔枪", + "110mm E.M.S. Cannon Round": "110mm电磁冲击波炮弹", + "Robotics Workshop": "机械工坊", + "By reminding Chemical Agents of proper distancing rules, this extraordinary innovation in cape design ensures that they never cause another unfortunate outbreak of Carcino-Plague.": "提醒化学专家保持适当距离的创新披肩设计可确保他们不会再引发卡西诺瘟疫灾难。", + "The signature orange pauldron allows easy battlefield detection of the bearer, alive or dead, on ash-strewn battlefields.": "橘黄色护肩非常醒目,哪怕在遍布灰烬的战场上也能让你轻易找到穿戴者,无论他们是生是死。", + "BALLISTIC PADDING": "防弹内衬", + "Armor befitting infiltrators of all caliber. Inspired by mythical Democracy-dispensers, whose meticulously undocumented operations remain an inspiration to all students of stealth.": "此盔甲适合水平各异的渗透人员。以传说中的民主精神传播者为灵感设计,他们不留痕迹的缜密行动至今仍激励着所有潜行术学员。", + "B-08 Light Gunner": "B-08“轻装枪手”", + "A reliable assault rifle with an antique iron sight, firing incendiary ammunition.": "可靠的突击步枪,配备老式机械瞄具,可发射燃烧弹药。", + "More Arc Splits": "增加电弧分裂数", + "RS-11": "RS-11", + "CW-36 WINTER WARRIOR": "CW-36“冬日战兵”", + "Volatile Plasma Bolt": "易气化等离子弹", + "DRUM MAGAZINE": "弹鼓", + "G-13": "G-13", + "AFFECTED AREA": "影响范围", + "TR-9 Cavalier of Democracy": "TR-9“民主骑兵”", + "\"The ground is just another obstacle that hasn't yet been cleared.\" - SGM Janet Jones, Excavation Corps Founder.": "“大地不过是另一道有待清除的阻碍。”——上士珍妮特·琼斯,挖掘部队创始人。", + "GR-8": "GR-8", + "P-19": "P-19", + "The patented fabric absorbs visible, infrared, and ultraviolet radiation, to prevent detection by all known species.": "享有专利的纤维材料可吸收可见光、红外线和紫外线辐射,躲过所有已知物种的侦测。", + "Fire Support": "火力支援", + "FIRST DIVEMASTER": "一等潜兵长", + "This armor, together with its friendly-faced helmet, is instantly recognizable from the beloved children's show \"Jen Shriver the Science Diver.\"": "这套盔甲配套看似友好的头盔,一眼就能辨别灵感源自深受孩童喜爱的节目“科研潜兵珍·施莱佛 ”。", + "A humane, autonomous drone equipped with a modified Arc Thrower. Capable of projecting arcs of lightning through multiple targets. Does not need to recharge between shots.": "配备改良版电弧发射器的人道主义自主无人机。能够向多个目标发射电弧闪电。每次射击前无需充能。", + "With sharp geometric angles to symbolize the rigid chain of command, this cape embodies the sanctity and moral fortitude of unblemished leadership over the mud-caked warriors they direct.": "用锐利的几何棱角象征严苛的指挥链,这件披风体现了完美无瑕的将领在统御满身泥泞的战士时,所闪耀的神圣光辉与道德毅力。", + "A powerful, single-use, proximity-detonated heat energy mine. During the Fall of Chara, it is said enough Melta Mines were detonated to outshine the planet's sun. \n\nProduced by ST Construction.": "一种威力强大的一次性近炸热能地雷。据说在常陈四陷落期间,巨量热熔地雷被引爆,散发出的光芒甚至比该星系中的恒星更耀眼。\n\n由ST建筑公司生产。", + "LONGER LIFETIME": "提高耐久度", + "BEAM": "激光束", + "Extra Magazine": "额外弹匣", + "DEADEYE": "鹰眼", + "Volatile Plasma Igniter": "易气化等离子点火器", + "The SEAF standard assault rifle, balancing power, fire rate, and weight for a reliable weapon against smaller targets.": "超级地球武装部队的制式突击步枪,火力、射速和重量各方面均较为平衡,是对付小型目标的可靠武器。", + "Gifted to Helldivers whose civilian lives were distinguished by exemplary citizenship, patriotism, and service to the Federation.": "授予具有爱国、效忠联邦等优秀品质、为平民竖立楷模的模范公民绝地潜兵。", + "CM-17 BUTCHER": "CM-17“屠夫”", + "Grenade Pistol": "榴弹手枪", + "Hot Dog": "热狗", + "Warrant": "法令", + "10g MAGNUM": "10g马格南霰弹", + "FX-12": "FX-12", + "DISTANCE #DISTm": "距离#DIST米", + "9x20mm Thermite": "9x20mm铝热弹", + "PACIFIER": "安抚者", + "Contact Mine": "水雷", + "A thermite grenade designed to adhere to surfaces before burning at 2000°C. Capable of burning through some armor.": "铝热榴弹,经过专门设计,可附着于表面,燃烧温度高达2000°C,能烧穿部分装甲。", + "Spear": "飞矛", + "Eternal Corona": "永恒日冕", + "ADRENO-DEFIBRILLATOR": "肾上腺素除颤器", + "Lightened Casing": "轻薄弹壳", + "Missile Pistol": "制导手枪", + "B-08 LIGHT GUNNER": "B-08“轻装枪手”", + "Will of the People": "人民的意志", + "NO ATTACHMENT": "无配件", + "More Bombs": "增加炸弹数", + "PEACEMAKER": "和平制造者", + "A backpack-mounted Hellbomb that can be armed by the wearer or an ally, starting a countdown. Users are recommended to remove the backpack before the countdown reaches zero.": "背包式地狱火炸弹,穿戴者或盟友激活后将开启倒计时。建议在倒计时归零前移除背包。", + "AF-50 Noxious Ranger": "AF-50“毒瘴游骑兵”", + "DP-00 Tactical": "DP-00“战术”", + "Punisher": "制裁者", + "Machete": "砍刀", + "CLUSTER BOMB": "集束炸弹", + "High-Velocity Shrapnel": "高速榴霰弹", + "HIGH-VELOCITY SHRAPNEL": "高速榴霰弹", + "GS-11 DEMOCRACY'S DEPUTY": "GS-11“民主代理人”", + "Meltagun": "热熔枪", + "DEPLOY": "部署", + "110mm Standard Rocket Mk2": "110mm标准火箭弹 MK2", + "Increases stim effect duration by #BONUS.": "治疗剂效果持续时间延长#BONUS。", + "FS-05 MARKSMAN": "FS-05“神射手”", + "Torcher": "火炬手", + "Equipped with the latest computational systems, subsystems, and supersystems, this armor is worth the equivalent of a small Megacity.": "这套盔甲配备最新的计算系统、子系统和超级系统,价值相当于一座小型特大城市。", + "Dignity of Toil": "劳作的荣光", + "EFFICIENT FUEL": "高效燃料", + "SA-32 DYNAMO": "SA-32“精力充沛”", + "A/MLS-4X": "A/MLS-4X", + "ANTI-PERSONNEL MINEFIELD": "反步兵雷区", + "A barrage of bombs creating a non-targeted carpet of explosions.": "发动无目标地毯式轰炸的炸弹火力网。", + "MD-17": "MD-17", + "Supply Pack": "补给背包", + "Fires a short-ranged superheated blast of thermal energy that melts the heaviest armor and thickest chitin into slag. \n\nProduced by ST Construction.": "发射的短程超高温热能冲击,能够熔融最厚重的装甲和最厚实的甲壳。\n\n由ST建筑公司生产。", + "CW-9 WHITE WOLF": "CW-9“白狼”", + "Reckoning's Cheer": "清算颂歌", + "VETERAN'S BANNER": "老兵旗帜", + "MEDICAL SUPPLIES": "医疗补给", + "Sturdier Wheels": "加固轮胎", + "DEFENDER": "防卫者", + "FLAM-66": "FLAM-66", + "PENETRATION": "穿透攻击", + "9x20mm FULL METAL JACKET": "9x20mm全金属被甲弹", + "Prevents all damage from bleeding if chest hemorrhages.": "如果胸腔出血,则避免其他所有来自出血的伤害。", + "A manned gun emplacement offering superior firepower against lightly armored targets. Slow to turn, so place it wisely.": "手动炮台,强悍的火力能有效对付轻型装甲目标。转向速度较慢,请明智选择部署位置。", + "DS-10 Big Game Hunter": "DS-10“巨兽猎手”", + "Super Earth Flag": "超级地球旗帜", + "SPIRE STERILIZER": "虫塔杀菌器", + "Ammunition Optimization": "弹药优化", + "15x100mm High Explosive": "15x100mm高爆弹", + "SOS BEACON": "S.O.S.求救信标", + "9x20mm THERMITE": "9x20mm铝热弹", + "SALUTE": "敬礼", + "12x25mm RIPPER": "12x25mm撕裂弹", + "Scourge of Tyranny": "暴政克星", + "Hive Scanner": "虫窝扫描仪", + "COOLDOWN": "冷却时间", + "GS-66 LAWMAKER": "GS-66“立法者”", + "Fires a ballistic dart at near-supersonic speeds, allowing the user to stim allies from a distance. Might sting.": "以接近超音速的速度发射飞镖,可远程救治盟友。被射中时可能会感到刺痛。", + "Extended Magazine": "加长弹匣", + "AIRBURST ROCKET LAUNCHER": "空爆火箭弹发射器", + "The standard heatsink for laser rifles.": "激光步枪的标准散热器。", + "K-2": "K-2", + "MA5C": "MA5C", + "SHORT REVOLVER BARREL": "左轮手枪短枪管", + "Faster Missiles": "提升导弹速度", + "Airburst Rocket Launcher": "空爆火箭弹发射器", + "CHARGEUP": "充能", + "SC-28 Stealth Ranger": "SC-28“潜行游侠”", + "TR-117 Alpha Commander": "TR-117“阿尔法指挥官”", + "Laser Sentry": "激光哨戒炮", + "Breakthrough Exosuit": "“突破”外骨骼装甲", + "PROGRAMMABLE PRISM EFFECT": "智能棱镜效果", + "Portable Hellbomb": "便携式地狱火炸弹", + "EAGLE REARM": "重新武装“飞鹰”", + "APEX PROTECTOR": "巅峰护卫", + "110mm E.M.S. Cannon Round Mk3": "110mm电磁冲击波炮弹 MK3", + "Featuring patented reverse-seam technology, to reduce the likelihood of bodily fluids entering the armor's interior.": "运用专利反向缝合技术,减少体液进入盔甲内部的可能性。", + "SC-15 Drone Master": "SC-15“无人机大师”", + "100kg Bomb Mk2": "100KG炸弹 MK2", + "This Is Democracy": "恭迎民主", + "500kg BOMB MK2": "500KG炸弹 MK2", + "5.5x50mm EXPLOSIVE": "5.5x50mm爆炸子弹", + "INFLAMMABLE": "易燃易爆", + "CADET": "军校生", + "SG-22": "SG-22", + "R-2124": "R-2124", + "110mm AIRBURST CANNON ROUND MK2": "110mm空爆炮弹 MK2", + "Wearer makes #BONUS less noise when moving.": "穿戴者移动时产生的噪音减少#BONUS。", + "CM-09 BONESNAPPER": "CM-09“碎骨杀手”", + "DBS-2": "DBS-2", + "IMPROVED READY RACKS": "改良预备弹药挂架", + "Longer Lifetime": "提高耐久度", + "LAS-13 Trident": "LAS-13“三叉戟”", + "Increases weapon ergonomics to reduce drag on weapon movement.": "通过提升武器的人体工学性能,降低携带武器移动的阻力。", + "Ew": "好臭", + "85mm HEAT Grenade": "85mm高爆反坦克榴弹", + "10g LIBERTY FIRE": "10g“解放之火”霰弹", + "GIGA GRENADE": "千兆级榴弹", + "Made famous by the SEAF commander of the same name, this seal reminds us that only perfect Unity can ensure perfect Freedom.": "此印因同名的超级地球武装部队指挥官而闻名,时刻提醒着我们,唯有绝对的团结,方能确保绝对的自由。", + "MUZZLE BRAKE": "枪口制退器", + "STANDARD DRUM": "标准弹鼓", + "A linear artillery barrage which moves at intervals, driving the enemy out from cover while allowing an advance.": "间歇性移动的线形火力网,可将敌人逐离掩体,同时让我方前进。", + "All Hail the Helldivers, whose resplendent honor makes Tyrants tremble.": "向绝地潜兵致敬,他们的荣耀光辉令暴政颤栗。", + "Bolt Pistol": "爆弹手枪", + "The omission of upper-limb coverings allows for optimized freedom of movement, perspiration, and communication of upper body strength to squadmates.": "省去覆盖上肢的布料,自由行动的空间、排汗,以及与队友之间的上肢力量交流都将得到优化。", + "All Hail the Helldivers, who bring untold abundance to Super Earth's citizens.": "向绝地潜兵致敬,正是他们为超级地球公民带来了无尽的财富。", + "A subdued cape, for those who need no recognition—save that of their enemies, as their executioner.": "为不愿被认出的战士而设计的低调披肩。但敌人一眼就能认出,因为披肩的出现,代表他们死期已到。", + "SUPER EARTH FLAG": "超级地球旗帜", + "EAT-17": "EAT-17", + "Patient Zero's Rememberance": "零号病人遗思", + "SUPER PERSON": "超人", + "15x100mm Thermite": "15x100mm铝热弹", + "Shafts of Despair": "绝望之柱", + "De-Forester's Sailcloth": "伐木工帆布", + "12g Bugshot": "12g虫弹", + "110mm Standard Rocket": "110mm标准火箭弹", + "Often showcased in the \"Obedient Democracy Support Troopers\" cartoon, this assault rifle comes with a convenient ammo counter and compass.\nProduced by Martian Armory.": "这款突击步枪经常在《民主光环驰援部队》卡通片中出现,配备了便捷的弹药计数器和指南针。\n由火星军械库生产。", + "Half Choke": "半喉缩", + "Increased Shield Power": "提升护盾能量", + "This grenade delivery drone follows the user until it detects an enemy nearby, then flies toward it and explodes on impact. Has a limited battery life.": "这款榴弹投掷无人机会紧跟使用者飞行,探测到附近敌人后飞向目标,撞击后引爆。电池续航时间有限。", + "Based on a SEAF Signaller's Cape, which was intended to enable easy location of fallen heroes by aerial recovery crews.": "设计原型是超级地球武装部队的披肩,目的是帮助空中救援小队轻松找到阵亡的英雄。", + "Provides #SIGN#BONUS limb health.": "提供#SIGN#BONUS的四肢生命值。", + "BIG WHOOP": "喝彩", + "Throwing Knife": "飞刀", + "CM-14 Physician": "CM-14“医师”", + "ST-1": "ST-1", + "Diligence": "勤勉", + "12g BUCKSHOT": "12g鹿弹", + "MORE ROUNDS": "增加弹药", + "SQUAT": "蹲坐", + "SUPPLY PACK": "补给背包", + "SOLO SILO TARGETING REMOTE": "单兵导弹发射井定位遥控器", + "SCRAPS OF SOVEREIGNTY": "主权碎片", + "With extra capacity for storing throwable munitions, this armor ensures every enemy stronghold can be tactically ventilated, as per forceful de-fortification protocols.": "这套盔甲具备收纳投掷弹药的额外空间,可确保对每个敌军据点以符合“强制去工事化协议”的方式进行“战术通风”。", + "EXTENDED MAGAZINE": "加长弹匣", + "B/MD": "B/MD", + "TORCHER": "火炬手", + "IE-57 Hell-Bent": "IE-57“奋不顾身”", + "A symbol of fierce commitment to Liberty and Democracy, this cape celebrates the Helldivers who have held true to Super Earth values through rain or shine.": "这件披肩象征着对自由和民主的坚定承诺,颂扬那些风雨无阻地坚守超级地球价值观的绝地潜兵。", + "A Hellpod containing four supply packs, to replenish personal ammunition and stims in the field.": "装有四个补给背包的绝地喷射舱,可在战场上补充个人弹药和治疗剂储备。", + "PLAS-45": "PLAS-45", + "A melee weapon tipped with electrified prongs that temporarily stun targets. Can be wielded one-handed.": "近战武器,矛头带电刺,可暂时眩晕目标。支持单手操作。", + "HOT-SHOT MARKSMAN RIFLE": "高能精确射手步枪", + "ERGONOMIC DRUM": "人体工学弹鼓", + "High-Pressure Napalm": "高压凝固汽油弹", + "A sight with thin features to maximize visibility of the target.": "纤薄设计的瞄准镜,可最大限度地提升目标可见度。", + "The featherlight construction belies the heavy burden this cape entails—to live the Creed of the True Citizen.": "轻如鸿毛的结构掩盖了此披风的沉重意义:践行忠诚公民的信条。", + "Default Helldiver Voice 3": "绝地潜兵默认声音 3", + "Randomize Voice": "随机分配声音", + "The heavy rubber tunic and reflective limb guards, originally designed to save citizens from burning buildings, now enable the liberal application of the cleansing fires of Justice.": "这厚重的橡胶外衣和反射隔热的肢体护具原本是用来在火场中营救公民的,如今则让穿戴者可以毫无顾忌地喷射正义的净化烈焰。", + "Small Plasma Bolt": "小型等离子弹", + "A modified Breaker shotgun firing birdshot, small pellets which saturate an area to clear up smaller targets.": "改良后的“破裂者”霰弹枪,可发射鸟弹,分散的细小弹丸足以清除一定区域内的小型目标。", + "FOESMASHER": "歼敌战士", + "HARBINGER OF TRUE EQUALITY": "真正的平等先锋", + "Tenderizer": "肉锤", + "8x60mm AIRBURST": "8x60mm空爆弹", + "MD-I4": "MD-I4", + "FEET FIRST": "护腿为上", + "Autocannon Sentry": "自动哨戒炮", + "12x25mm Thermite": "12x25mm铝热弹", + "13x40mm PENETRATOR": "13x40mm穿甲弹", + "Arc": "电弧", + "Vigorous Thrusting": "盛气凌人", + "AR-61": "AR-61", + "A shovel that can be used as a melee weapon or, more conventionally, to dig holes in the ground.": "铲子,除了能在地上挖洞,还可用作近战武器。", + "DIAGRAM OF THE NOBLEST PAYLOAD": "至高使命图谱", + "9x20mm Explosive": "9x20mm爆炸子弹", + "Modeled after the myriad Statues of Judicious Liberty, who keep a watchful eye on checkout lines, schoolyards, perpetual rehabilitation communities, and public confession theaters.": "这套盔甲的灵感来自不计其数的“公正自由女神像”,她们警惕地注视着收银台、学校操场、永久性矫正社区和公共忏悔剧场。", + "Default Trigger": "默认扳机", + "IMPROVED AMMO STORAGE": "弹药存储量升级", + "STONE-WROUGHT PERSEVERANCE": "磐石毅力", + "When wearers stand shoulder to shoulder, this cape shows them as they truly are: an unbreakable defense, keeping Freedom safe behind an impregnable wall.": "肩并肩穿戴披肩站立时,便会展现真实风采:化身坚不可摧的防线,将自由守护在固若金汤的墙后。", + "Head Tap": "动动脑", + "E/GL-21": "E/GL-21", + "GAS MORTAR SENTRY": "瓦斯迫击哨戒炮", + "CALTROPS": "铁蒺藜", + "Allows the swift completion of Liberty's administrative tasks in an invigorating atmosphere.": "在鼓舞人心的氛围下,快速完成解放伟业的行政工作。", + "LEVELLER": "荡平者", + "40mm APHE Cannon": "40mm穿甲高爆炮弹", + "DRAW!": "拔枪!", + "TESLA TOWER": "特斯拉塔", + "45-DEGREE VERTICAL FOREGRIP": "45度垂直前握把", + "LIGHTWEIGHT MATERIALS": "轻质材料", + "Gas": "毒气榴弹", + "10g Bugshot": "10g虫弹", + "Command Input": "指令输入", + "DOG BREATH": "腐息", + "SA-12 SERVO ASSISTED": "SA-12“伺服辅助”", + "CE-35 TRENCH ENGINEER": "CE-35“战壕工程师”", + "Granted to the Truth Enforcers' Informant of the Month, this tasteful cape conjures images of dissident blood on asphalt.": "这件品味非凡的披肩属于真理执行者的“月度最佳告密者”,令人联想到沥青路面上异见分子的鲜血。", + "A throwable device engineered to bounce when hitting the ground, releasing bursts of electricity on each impact. Warning: may bounce unpredictably.": "经过特殊设计的投掷设备,击中地面时会弹起,每次撞击都会释放电流。警告:弹跳方向可能难以预测。", + "NOISE": "噪声", + "PILLARS OF FREEDOM": "自由支柱", + "E/MG-101": "E/MG-101", + "Curtsy": "屈膝礼", + "SHORTER COOLDOWN MK2": "冷却用时缩短 Mk2", + "AIRBURST ROCKET BACKPACK": "空爆火箭弹背包", + "R-36": "R-36", + "DYNAMITE": "炸药", + "A cape commemorating the Helldivers who paved the way for the successful launch of the improved TCS+. An enduring reminder of Super Earth’s engineering power and commitment to suppressing the Terminid horde.": "这款披肩旨在铭记为成功启动升级版TCS+扫清障碍的绝地潜兵。它是超级地球工程伟力与誓要消灭终结族决心的永恒见证。", + "EXPERT EXTERMINATOR": "顶级灭杀者", + "LAS-99": "LAS-99", + "Punisher Plasma": "等离子“制裁者”", + "Heavily insulated from animal bites, enemy fire, and the histrionic diatribes of anarchists.": "对野兽啃咬、敌方火攻以及扰乱分子的嬉笑怒骂完全绝缘。", + "High-Pressure Nozzle": "高压喷嘴", + "INFILTRATOR": "深入敌阵", + "NATURAL GAS EXTRACTION": "提炼天然气", + "LURE MINE": "诱饵地雷", + "MISSILE PISTOL": "制导手枪", + "HIGH EXPLOSIVE": "高爆弹", + "A prolonged barrage, wreaking extended destruction over a large area. Communication with teammates is advised.": "持续输出火力网,可大面积范围造成破坏。使用前建议与队友进行通信。", + "Strength in Our Arms": "武器之力", + "LIBERTY'S HERALD": "解放预兆", + "Quasar Cannon": "类星体加农炮", + "SMG/FLAM-34": "SMG/FLAM-34", + "5.5x50mm SUBSONIC": "5.5x50mm亚音速弹", + "G-7": "G-7", + "M-1000": "M-1000", + "An anti-tank homing missile which must lock onto its target before launch. Effective against large and armored enemies.": "反坦克追踪式导弹,发射前必须锁定目标。可有效对付大型装甲敌人。", + "B-27 Fortified Commando": "B-27“强化突击兵”", + "LASER": "激光", + "A barrage of smoke grenades, creating a thick smoke screen to block enemies' line of sight.": "烟雾弹火力网,可形成一道厚重的烟幕,阻挡敌人的视线。", + "A silo that fits one single, powerful missile. Comes with a handheld targeting remote.": "发射井可容纳一枚强力导弹。配备手持定位遥控器。", + "Double Freedom": "双重自由", + "A symbol of the constant, forward-moving propulsive force of Managed Democracy. This cape honors those who understand that in the race for Freedom, there are no brakes—only degrees of momentum.": "胜利矢量象征管理式民主恒定前进的驱动力。这件披肩向那些明白在自由竞赛中没有刹车、唯有动力强弱之分的人致敬。", + "40mm Proximity Grenade": "40mm感应榴弹", + "100KG BOMB": "100KG炸弹", + "Signal: Hold": "信号:等待", + "SCHEMA LAID BARE": "解封蓝图", + "LARGER CANISTER": "扩容燃料罐", + "Light of Eternal Liberty": "永恒自由之光", + "OVER ARTIFICE TRIUMPHANT": "巧取豪夺", + "IMPROVED AIR BRAKES": "改良空气制动器", + "Evoking legendary Helldiver Ronald Mambo on the eve of his untimely disappearance, the striking silhouette projects power, burliness, and strength.": "极具冲击力的轮廓展现出力量、悍勇与威压,令人不禁想起意外失踪前夕的传奇绝地潜兵罗纳德·曼波。", + "Peacemaker": "和平制造者", + "MORTAR SENTRY": "迫击哨戒炮", + "SEEKER": "寻踪者", + "IMPROVED DURABILITY": "提升耐久度", + "Belt-Fed Grenade Launcher": "弹链式榴弹发射器", + "LARGER FUEL TANK": "扩容燃料罐", + "A laser rifle firing a continuous beam. Does not need reloading, but if it overheats a new heat sink must be fitted.": "发射连续激光束的激光步枪。无需重新装弹,但如果步枪过热,必须安装新的散热器。", + "Amendment": "修正", + "Provides #BONUS resistance to gas damage and effects.": "对毒气伤害和效果的抗性增加#BONUS。", + "MG-43": "MG-43", + "No muzzle choke.": "无枪口喉缩。", + "Streamlined for maximum velocity, this armor was inspired by long-distance couriers who prioritized the delivery of ballots over personal safety, exemplifying our patriotic bonds. Features reinforced joints to withstand the violent transitions between high-speed travel and abrupt, unplanned stops.": "为追求极致速度,这套护甲采用流线型设计,其灵感源于将递送选票置于个人安全之上的长距离运送者,彰显我们的爱国纽带。其特点是对关节连接处进行了强化处理,可承受高速行驶与突发或计划外停靠之间的剧烈转换。", + "10g BUGSHOT": "10g虫弹", + "EXPANDED HEAT CAPACITY": "提升热容量", + "Efficient Fuel": "高效燃料", + "STATIONARY RELOAD": "固定填弹", + "MD-6": "MD-6", + "B/FLAM-80": "B/FLAM-80", + "Prospecting Drill": "勘探钻机", + "CONCUSSIVE PADDING, HAZMAT": "防震内衬(防化型)", + "UPGRADED AFTERBURNER": "升级后燃器", + "Inspired by the trailblazing agents of the Super Earth Terraforming Company. These rugged adventurers surveyed hostile new planets during the post-GW1 Great Expansion era, preparing the untamed frontier for rapid and efficient assimilation.": "设计灵感源自超级地球行星地球化公司的先驱者。在第一次星系战争后的大扩张时期,这些坚韧的冒险家勘测了许多充满敌意的新星球,为快速高效地同化未开发边境奠定基础。", + "A mid-range precision rifle. Equipped with an integrated suppressor and subsonic rounds for barely-detectable operation.": "这是一支中程精准步枪。配备集成式消音器和亚音速弹药,方便执行难以被察觉的行动。", + "IE-12 RIGHTEOUS": "IE-12“义士”", + "BUG QUARANTINER": "虫族清道夫", + "This time-honored shotgun-like weapon has been improved since the First Galactic War, and now fires six beams instead of three.": "这款霰弹枪式经典武器自第一次星系战争以来历经改良,射出的激光束从三道增加到了六道。", + "Jammed Piñata": "满载惊喜的皮纳塔", + "FIRE RATE SELECTION": "可选射速", + "The standard scope for most weapons, provides a good and accurate scope picture.": "适配多数武器的标准瞄准镜,提供清晰精准的瞄准视野。", + "BREAKER NAILSPITTER": "尖钉喷射“破裂者”", + "LIGHT OF ETERNAL LIBERTY": "永恒自由之光", + "A/M-23": "A/M-23", + "Miranda's Legacy": "米兰达的遗志", + "With this cape we honor the bio-warfare pioneers of Division Zero, conscripted from quarantine zones and hospices to spread their Carcino-Plague on the battlefield.": "我们设计这件披肩是为了向“零号”师的生物战先驱致敬。他们从隔离区和临终关怀医院应征入伍,在战场上传播他们携带的卡西诺瘟疫病毒。", + "I-44 Salamander": "I-44“火蜥”", + "P-92": "P-92", + "Salute": "敬礼", + "Saber": "军刀", + "SG-225BB": "SG-225BB", + "SIGNAL: SILENCE": "信号:安静", + "TIGHTER BREECH LOCK": "收紧枪闩锁", + "Medical Supplies": "医疗补给", + "5-STAR GENERAL": "五星将军", + "Pacifier": "安抚者", + "Those who serve Liberty from the shadows often elect to stay anonymous, moving like traceless specters through the night. May they watch over us always.": "那些在黑暗中为自由而战的人往往选择隐姓埋名,如同幽灵般穿行于夜色之中,不留一丝痕迹。愿他们永远守护着我们。", + "A plasma rifle that fires bolts of superheated gas, which can be charged by holding down the trigger. Charging up a shot fully makes the bolt explode on impact.": "等离子步枪,可发射过热气体,按住扳机即可为其充能。每发射击完全充能后,触及着弹点后引爆。", + "40mm HE Mortar": "40mm高爆迫击炮弹", + "THE BREACH": "突破", + "FRONT-LEANING REST POSITION": "俯卧撑姿势", + "DAB": "嘻哈超人舞", + "A pistol firing guided, jet-propelled ammunition. It's lock-on feature ensures high accuracy, but the weapon must be reloaded after every round fired.": "一款发射喷气推进式制导弹药的手枪。具备锁定功能,可确保高射击精度,但每次开火后均须重新装填弹药。", + "120mm HE CANNON ROUND": "120mm高爆炮弹", + "Bunting of the Party Participant": "派对彩饰", + "ADVANCED VERTICAL FOREGRIP": "高级垂直前握把", + "9x70mm HIGH VELOCITY": "9x70mm高速弹", + "Fires a rocket that detonates within proximity of a target, and deploys a cluster of explosive bomblets.": "发射火箭弹,在目标附近引爆,并部署一组小型爆弹。", + "This armor recalls the legendary heroes who scared a ravenous Hive Lord away from a colony village, using only the village's battery of patriotic fireworks.": "这套盔甲纪念的是那些传奇英雄,他们仅凭村里的一批爱国烟花,就吓退了一只贪婪的霸王虫,拯救了拓殖地的村落。", + "FS-38 ERADICATOR": "FS-38“根除者”", + "K-9": "K-9", + "A silenced assault rifle with a built-in suppressor, which won't alert distant targets to the user's position.": "内置抑制器的消音突击步枪,可避免向远处的目标暴露使用者的位置。", + "TEST OF CONVICTION": "信念试炼", + "AD-26 BLEEDING EDGE": "AD-26“血刃科技”", + "KDM-73 Dragoon": "KDM-73“龙骑兵”", + "The gas-operated, semiautomatic P-113 chambers the 14mm \"Rapid Deliberation,\" the largest centerfire cartridge of any magazine-fed pistol.": "这支半自动P-113型气动式手枪采用14毫米的“速决”子弹,这是弹匣式手枪中最大的中心底火子弹。", + "23mm HE Cannon": "23mm高爆炮弹", + "DIVEMASTER": "潜兵长", + "5.5x50mm SUPER URANIUM CORE": "5.5x50mm超铀芯弹", + "Contains a grain of sand from Super Earth—so its bearers carry a small piece of Liberty with them, wherever they go.": "载有一粒来自超级地球的沙子,让不论穿戴者身在何处,心中都承载着自由。", + "LASER SENTRY": "激光哨戒炮", + "Encloses the wearer in a spherical shield which blocks high-speed projectiles.": "以球状护盾包裹佩戴者,抵挡高速射弹。", + "Faster Deploy Time": "缩短部署用时", + "No additional bonuses.": "无额外加成。", + "Narrow Spread": "集中", + "This armor is the required uniform for many Super Earth Citizens operating heavy machinery. Long-time users will be delighted to learn that as of this year's Efficiency in Machine Operation Symposium and Gala, wearing this armor is no longer itself considered operating heavy machinery.": "这套盔甲是许多操作重型机械的超级地球公民的必备制服。从本年度“机械操作效能研讨会暨晚宴”举办之日起,穿戴这套盔甲将不再被视为操作重型机械,这对于长期穿着者而言无疑是个好消息。", + "70mm STANDARD ROCKET": "70mm标准火箭弹", + "FS-37 Ravager": "FS-37“破坏者”", + "PLASMA IGNITER COMPENSATOR": "等离子点火器补偿器", + "LAS-98": "LAS-98", + "RE-1861 Parade Commander": "RE-1861“阅兵指挥官”", + "Protect Eardrums": "保护耳膜", + "SPEARGUN": "矛枪", + "40mm Flak Cannon": "40mm高射炮弹", + "10g Liberty Fire": "10g“解放之火”霰弹", + "O-3 Free Spirit": "O-3“自由之魂”", + "Homing Anti-Air Missile": "追踪式防空导弹", + "12.5mm EIT Rounds": "12.5mm爆炸燃烧曳光弹", + "DS-191 Scorpion": "DS-191“天蝎”", + "Plasma Bolt": "等离子弹", + "Justice": "正义", + "DP-11 Champion of the People": "DP-11“人民捍卫者”", + "FALLEN HERO'S VENGEANCE": "陨落英雄之崛起", + "Standard Heatsink": "标准散热器", + "GALACTIC COMMANDER": "星系指挥官", + "CQC-30": "CQC-30", + "A basic iron sight for Helldivers who want to relive the glorious struggles of their ancestors.": "基础机械瞄具,适合希望重温先辈辉煌奋斗历程的绝地潜兵。", + "TRUCKER'S TRIUMPH": "卡车司机的胜利", + "Featuring a high collar scientifically designed to deflect mud, blood, and indirect non-lethal projectiles, this pristine armor bestows the authority to overcome close-quarters combat through a time-honored tradition: the delegation—or court-martialing—of subordinates.": "采用科学实用的高领设计,可弹开泥浆、血污以及间接袭来的非致命投射物。这套一尘不染的盔甲赋予使用者在应对近战时实践久经验证传统的权威:委派下属充当肉盾(亦或将其军法处置)。", + "8x60mm Liberty Fire": "8x60mm“解放之火”子弹", + "LOYALIST": "忠诚者", + "GP-31": "GP-31", + "10g BIRDSHOT": "10g鸟弹", + "9x70mm High Velocity": "9x70mm高速弹", + "LEAN": "清瘦", + "UF-50 Bloodhound": "UF-50“猎犬”", + "A triple-barreled, break-action, sawed-off shotgun. Switch firing modes to fire all three barrels at once.": "三枪管中折式截短霰弹枪。可将开火模式切换为同时使用三枪管开火。", + "Orbital Smoke Strike": "轨道烟雾攻击", + "RS-100 Sanctioner": "RS-100“制裁者”", + "Stun Baton": "眩晕短棍", + "Warp Pack": "传送背包", + "INCENDIARY MINES": "燃烧地雷", + "C4 Pack": "C4背包", + "A half-constricted muzzle that forces the shotgun pellets together into a somewhat tighter group.": "半收束枪口,迫使霰弹较密集地发射。", + "13x40mm Full Metal Jacket": "13x40mm全金属被甲弹", + "Sickle": "镰刀", + "Gently stonewashed by experienced hands, this luxury cape exudes the essence of state-approved attitude.": "由资深工匠精心水洗做旧,这款奢华披肩散发着经国家认证的气质精髓。", + "HOMING ANTI-AIR MISSILE": "追踪式防空导弹", + "100KG BOMB MK2": "100KG炸弹 MK2", + "CM-10 Clinician": "CM-10“临床医师”", + "Modeled after the Statue of Mournful Liberty, who weeps over the existence of tyranny, this armor is worn by those who would give their lives to dry her tears.": "这套盔甲的灵感来自因暴政肆虐而哭泣的“哀恸自由女神像”,穿戴者愿以生命拂去自由女神的眼泪。", + "EXO-49": "EXO-49", + "AR-23": "AR-23", + "Ergonomic Drum": "人体工学弹鼓", + "G-89": "G-89", + "Woven from coarse, industrial fibers designed to absorb sweat and oil, this cape features a spade emblem to honor Super Earth's groundbreakers, who ensure Liberty’s light finds its way through any planet’s crust.": "采用粗糙的工业纤维织就,旨在吸收汗水与油污。这款披风饰有铁锹纹章,致敬为超级地球“破土奠基”的先辈们——感谢他们确保自由之光能穿透任何星球的地壳。", + "CPG-48 Sapper": "CPG-48“工兵”", + "BLITZER": "雷霆", + "SC-28 STEALTH RANGER": "SC-28“潜行游侠”", + "No dissident or alien, no creature big or small, can ever hope to stand against the furious stampede of Managed Democracy.": "无论是异见分子还是外星敌人,无论生物体型大小,都休想抵挡管理式民主狂怒奔涌的热潮。", + "AF-50 NOXIOUS RANGER": "AF-50“毒瘴游骑兵”", + "Marks the most Free of the Free, those who will seize tyranny by the neck and squeeze until no oppression remains.": "最自由者的印记,他们必将扼住暴政咽喉,碾尽世间一切压迫。", + "MORE LMG MOUNT MAGS": "增加架设型轻机枪弹匣", + "COMBAT HATCHET": "战斗短柄斧", + "BELT-FED GRENADE LAUNCHER BACKPACK": "弹链式榴弹发射器背包", + "A lightweight melee weapon that temporarily stuns enemies.": "轻型近战武器,可暂时眩晕敌人。", + "FLAME SENTRY": "火焰喷射哨戒炮", + "SICKLE": "镰刀", + "Anti-Tank Missiles": "反坦克导弹", + "SALVO FIRE": "炮弹齐射", + "PROTECT EARDRUMS": "保护耳膜", + "GL-21": "GL-21", + "Signal: Silence": "信号:安静", + "ACCELERATOR RIFLE": "加速步枪", + "CLAPPING": "鼓掌", + "110mm STANDARD ROCKET MK2": "110mm标准火箭弹 MK2", + "CRESTING HONOR": "荣誉之巅", + "REINFORCED EPAULETTES": "强化肩章", + "W.A.S.P. Launcher": "W.A.S.P.发射器", + "Spattered gore marks those heroes who braved the harrowing first days of the war for Managed Democracy.": "飞溅的血迹代表着那些为实现管理式民主而在早年战争中英勇奋战的英雄。", + "Since ancient times, the yellow line has symbolized an uncrossable boundary. To don this cape is to draw that line between tyranny and liberty, between alien monstrosities and Super Earth property, and never yield the right of way.": "自古以来,黄线就象征着不可逾越的边界。穿上这件披肩,意味着在暴政与解放、外星怪物与超级地球财产之间划清界线,并发誓绝不退让。", + "Upgraded Ammunition Feed": "升级供弹系统", + "FASTER RECHARGE": "加速充能", + "TR-7 AMBASSADOR OF THE BRAND": "TR-7“形象大使”", + "G-12": "G-12", + "STANDARD OF SAFE DISTANCE": "安全距离标准", + "KDM-763 PACESETTER": "KDM-763“领跑者”", + "All but ensures ascension to the immortal ranks of those enshrined in the Super Earth Digital Archive of Valorous Acts.": "必将收录至超级地球英勇之举数字档案,比肩珍藏其中的不朽藏品。", + "M-103": "M-103", + "Laser Sight w/ Flashlight": "激光瞄准器带照明", + "The set's classic advertising campaign \"Have you tried a grenade?\" has remained unchanged for over 70 years.": "70多年以来,本套装的广告词一直都是:“试过手雷了吗?”", + "0.05% of profits are donated to Superstone National Park, as part of the Ministry of Unity's \"Greener Galaxy\" campaign.": "为支持团结部的“更绿星系”活动,0.05%的利润将捐赠给超石国家公园。", + "Orbital 380mm HE Barrage": "轨道380mm高爆弹火力网", + "Duckbill": "鸭嘴枪口", + "Though originally intended solely for ceremonial use, its inspirational energy proved equally useful on the battlefield.": "设计初衷是用于仪式,但事实证明,它鼓舞人心的力量在战场上同样奏效。", + "A speargun firing heavy-duty projectiles. These projectiles release a cloud of gas on impact, and must be carefully loaded one at a time.": "一种发射重型短矛的矛枪。这些短矛在命中时会释放一团气体,装填时必须小心操作,每次装一枚。", + "Improved Ready Racks": "改良预备弹药挂架", + "Shorter Shot Cooldown": "缩短射击冷却用时", + "RE-2310 Honorary Guard": "RE-2310“荣誉卫队”", + "Reduces damage taken from impact and collisions by #BONUS.": "将撞击和碰撞造成的伤害降低#BONUS。", + "Woven in honor of our loyal Helldivers, whose commitment to Democracy, through rain or shine, is an inspiration to all.": "这件披肩旨在纪念忠诚的绝地潜兵,他们风雨无阻地坚守对民主的承诺,激励着所有人。", + "66mm Missile Mk2": "66mm导弹 MK2", + "A constricted muzzle that forces the shotgun pellets together into a tighter group.": "收束枪口,迫使霰弹十分密集地发射。", + "CE-101 Guerilla Gorilla": "CE-101“游击猩猩”", + "A heatsink with thinner cooling elements, improving cooling rate.": "配备更薄冷却元件的散热器,降温速率更快。", + "Angled Foregrip": "直角前握把", + "A fully-automatic pistol with an extremely high fire rate, allowing for efficient crowd control.": "射速极高的全自动手枪,可以有效对敌人实施群体控制。", + "SHIELD GENERATOR PACK": "防护罩生成包", + "AX/LAS-5": "AX/LAS-5", + "CW-22 KODIAK": "CW-22“科迪亚克”", + "PILLAR OF THE ABYSS": "深渊支柱", + "A tube red dot sight with 2x magnification, good for hitting small targets consistently over medium range.": "2倍放大管式红点瞄准镜,适合中程持续精准打击小型目标。", + "As the electric arc generates a strong magnetic field, wearers should avoid use while in vicinity of stapled paperwork.": "电弧可产生强大的磁场,穿戴者应避免在装订好的文书附近使用此盔甲。", + "SERGEANT": "中士", + "Debuted during the New Mombasa Armor Show, this sleek ensemble is sure to turn heads and blow minds.": "这套时髦的盔甲套装在新蒙巴萨盔甲展上首次亮相,必定成为全场焦点。", + "STRENGTH IN OUR ARMS": "武器之力", + "Jump Pack": "喷射背包", + "SG-225IE": "SG-225IE", + "Let all who see this cape be struck still with Freedom's beauty, or struck dead with Liberty's bullets.": "凡见此披肩者都将为自由之美所震慑,或被自由之弹所击毙。", + "More Ammo In Backpack": "增加背包弹药数量", + "Launches a prolonged barrage of napalm shells over a wide area, setting a swath of land ablaze in mere moments.": "持续投射凝固汽油弹火力网覆盖广大区域,顷刻将土地点燃。", + "Lockstep": "齐步行进", + "LOADING OPTIMIZATIONS": "优化配备装载", + "Default Internal Part": "默认内部零件", + "A larger heatsink that can store more heat.": "容量更大的散热器,可储存更多热量。", + "High Dissipation Heatsink": "高功率散热器", + "LAS-5": "LAS-5", + "This armor is based on the antique uniforms of the 'Super Earth Legion', a less patriotic precursor to the Helldivers.": "这套盔甲脱胎于古老的“超级地球军团”制服。后者是绝地潜兵的前身,但是不像绝地潜兵这样忠心爱国。", + "12g Buckshot Magnum Shells": "12g鹿弹马格南霰弹", + "IMPATIENT": "急躁", + "CENSOR": "审查官", + "MLS-4X": "MLS-4X", + "GUIDED": "制导", + "FS-11 Executioner": "FS-11“行刑者”", + "Rover": "漫游车", + "This cape reminds us that even faced with the abyssal darkness of space, nothing can stand against our human ingenuity, our powers of collaboration, or our sheer overwhelming numbers.": "这件披肩提醒我们,即使面对太空万籁俱静的黑暗,任何力量都无法对抗人类的智慧、协作能力以及人海战术的优势。", + "CE-81 Juggernaut": "CE-81“巨人”", + "Pride of the Whistleblower": "检举者的荣耀", + "SHEAR": "切变", + "A camo paint job for use in arctic environments.": "适用于雪地环境的迷彩涂装。", + "CE-07 Demolition Specialist": "CE-07“拆除专家”", + "Some say that a mere glimpse of this cape, fluttering majestically in the breeze, is enough to spur a squad to victory.": "有人说,只需一瞥此披肩在微风中飘扬的庄严模样,就足以激励整支战队披荆斩棘,迈向胜利。", + "380mm HE CANNON ROUND": "380mm高爆炮弹", + "A turret firing powerful shells in a high arc. Effective at long ranges, and able to strike at targets behind cover.": "以高弧度发射强力弹药的炮台。在远程范围内较为高效,能打击藏于掩体后方的目标。", + "INNER RADIUS": "内半径", + "Stim Pistol": "治疗剂手枪", + "RL-77": "RL-77", + "The alloy in these long-range rifles includes metals from the dead planet Chara, overrun in the First Galactic War. \n\nProduced by ST Construction.": "在用于制造这些远程步枪的合金中,有部分金属来自第一次星系战争中被敌军攻陷的死寂星球常陈四。\n\n由ST建筑公司生产。", + "Loosen Up": "放松", + "MAXIGUN BACKPACK": "重装机枪背包", + "RAIL CANNON ROUND": "轨道炮弹", + "Homing Ground Missile Mk2": "追踪式地面导弹 MK2", + "12.5mm EIT ROUNDS": "12.5mm爆炸燃烧曳光弹", + "MEDIC BACKPACK": "医疗背包", + "BREAK-ACTION SHOTGUN": "中折式霰弹枪", + "FUSE TIME": "引信时间", + "COYOTE": "野狼", + "AR-48": "AR-48", + "Dog Breath": "腐息", + "2x Tube Red Dot": "2倍红点瞄准镜", + "Emblazoned with the red, white, and green of the 676th Democracy Regiment, who made their final stand on the slopes of Justice Hill.": "饰有第676民主军团的标志性红、白、绿三色,纪念他们在正义山上的殊死一战。", + "STANDARD PLASMA CONTAINER": "标准等离子弹药匣", + "MESSAGE OF MORALE": "士气宣言", + "O-2 HEAVY OPERATOR": "O-2“重装操作者”", + "This Guy": "这家伙不得了", + "5.5x50mm High Velocity": "5.5x50mm高速弹", + "A one-handed device that deploys a wide energy barrier in front of the user. The barrier is semipermeable and blocks high-speed projectiles from the outside only, leaving the user free to shoot through it.": "可单手操作的装置,使用时会在正前方展开宽大的能量屏障。该半透屏障只会抵挡外部高速射弹,使用者发射的子弹能自由穿透屏障。", + "Break-Action Shotgun": "中折式霰弹枪", + "15x100mm EMP-ROUNDS": "15x100mm电磁脉冲弹", + "Defender": "防卫者", + "Assault Rifle": "突击步枪", + "Orbital Cannons": "轨道加农炮", + "Due to the enhanced strength caused by this armor, caution is advised when using door handles or embracing colleagues.": "此盔甲可强化穿戴者的力量,因此,建议穿戴时谨慎使用门把手或拥抱同僚。", + "Made Ready": "现成补给", + "TYRANT HUNTER": "猎暴人", + "WARRANT": "法令", + "A grenade that releases a cloud of toxic gas, effective at temporarily blinding and slowing both organic and inorganic enemies.": "释放有毒气团的榴弹,可使有机体和无机体敌人暂时致盲并减速。", + "LARGER SEARCH RADIUS": "扩大搜索半径", + "LAS-13 TRIDENT": "LAS-13“三叉戟”", + "Eagle 500kg Bomb": "“飞鹰”500kg炸弹", + "Assault": "特攻", + "DILIGENCE": "勤勉", + "9x20mm HOLLOW POINT": "9x20mm空尖弹", + "A grenade launcher effective against armored infantry. Not intended for use against vehicle armor or fortified buildings.": "榴弹发射器,可有效对付装甲步兵。不适合用于攻击载具装甲或防卫森严的建筑。", + "This armor set first appeared in the music video for the summer anthem 'Our Love is Like Liberty (Indestructible)'.": "这套盔甲的首度亮相是在夏日圣歌“爱如解放(坚不可摧)”的MV中。", + "BURIER OF HEADS": "埋首者", + "Rocket Sentry": "火箭哨戒炮", + "I-92 FIRE FIGHTER": "I-92“消防队”", + "STAR MARSHAL": "星级元帅", + "CE-07 DEMOLITION SPECIALIST": "CE-07“拆除专家”", + "EXPLODING CROSSBOW": "爆燃弩", + "A single precision shot from the Destroyer's 'ATLAS' cannon.": "来自驱逐舰“阿特拉斯”轨道加农炮的一发精准攻击。", + "10g SABOT": "10g萨博特式霰弹", + "CE-74 BREAKER": "CE-74“破裂者”", + "Reduces range at which enemies can detect the wearer by #BONUS.": "敌人探测佩戴者的范围缩小#BONUS。", + "5.5x50mm DOUBLE POWER": "5.5x50mm双效子弹", + "EXOSUIT CERTIFIED": "外骨骼装甲专家资格", + "FIRE LIMIT": "开火限制", + "A-35 Recon": "A-35“侦察者”", + "DAGGER": "匕首", + "Temporarily stuns all targets within the effective radius.": "可短时眩晕效果范围内的所有目标。", + "SC-30 TRAILBLAZER SCOUT": "SC-30“开路侦察兵”", + "CM-14 PHYSICIAN": "CM-14“医师”", + "RECKONING'S CHEER": "清算颂歌", + "REAPER OF BOUNTIES": "赏金收割者", + "Directional Shield": "定向护盾", + "ASSAULT INFANTRY": "特攻步兵", + "WILL OF THE PEOPLE": "人民的意志", + "Larger Magazines": "扩容弹匣", + "UNITED IN EQUALITY": "仰齐与共", + "FS-11 EXECUTIONER": "FS-11“行刑者”", + "INCREASED STORAGE MK2": "可携带数量升级 MK2", + "Contains many small pockets, allowing the user to evenly distribute the weight of ammunition, samples, and cool rocks.": "包含许多小口袋,方便使用者根据重量均衡放置弹药、样本和酷炫岩石。", + "DECORATED HERO": "功勋英雄", + "IMPROVED AMMO STORAGE MK2": "弹药存储量升级 MK2", + "Laser Sight": "激光瞄准器", + "Woven in honor of our loyal citizens, who by raising their voices have supported the war effort more than they can ever know.": "这件披肩旨在纪念忠诚的公民,他们大声疾呼,为战争提供了超乎想象的支持。", + "VOLATILE PLASMA IGNITER": "易气化等离子点火器", + "Manual Targeting": "手动锁定目标", + "A compact version of the Liberator designed for increased viability in close quarters. Has an increased fire rate at the cost of higher spread.": "便携版“解放者”,设计目的是提升近距离交战的生存能力。射速提高,但散射更广。", + "LARGER AMMUNITION STORAGE": "扩充弹药存储量", + "DOUBLE-EDGE SICKLE": "双刃镰刀", + "FS-05 Marksman": "FS-05“神射手”", + "12g Magnum Triball": "12g马格南三连弹", + "Aspect-seeking air-to-air missiles, to eliminate most flying targets in the vicinity.": "寻向空对空导弹,可歼灭附近的大部分飞行目标。", + "R-6": "R-6", + "AX/AR-23": "AX/AR-23", + "MARK OF THE CRIMSON FANG": "猩红獠牙之印", + "DUCKBILL": "鸭嘴枪口", + "Large Drum": "大型弹鼓", + "An Exosuit equipped with dual autocannons, designed for sustained explosive firepower.": "搭载两台机炮的外骨骼装甲,可持续提供爆炸性火力。", + "9x20mm HIGH VELOCITY": "9x20mm高速弹", + "Liberator": "解放者", + "10g BUCKSHOT SHELLS": "10g鹿弹霰弹", + "EFFECTIVE RANGE": "有效射程", + "Reduces the size of the muzzle flash by dispersing the burning propellant when firing the weapon.": "通过分散燃烧的推进剂,减少射击时的枪口火焰大小。", + "Medium Plasma Bolt": "中型等离子弹", + "The heavy plate used in this armor is sustainably sourced from the corpses of non-sentient Automatons, then processed by other, similarly non-sentient Automatons.": "这套盔甲使用的重型装甲板是可持续地取材于无感知能力的机器人残骸,并由其他同样无感知能力的机器人加工而成。", + "Progressive Trigger": "渐进式扳机", + "G-10": "G-10", + "FS-34 EXTERMINATOR": "FS-34“灭绝者”", + "One-Two": "幺二", + "ORBITAL NAPALM BARRAGE": "轨道凝固汽油弹火力网", + "8x60mm Sniper Armor Piercing": "8x60mm穿甲狙击弹", + "Shotgun": "霰弹枪", + "Legend tells of the unnamed Helldiver, wandering the edges of Super Earth's reach, delivering Democracy and leveling lawlessness wherever the tumbleweeds lead. Wear this, and keep the legend alive.": "传说有一位无名的绝地潜兵,游荡在超级地球的边境,追随风滚草的引领,传播民主,肃清无序。披上这件披肩,续写传奇。", + "EXTRACTION BEACON": "撤离信标", + "Stun Lance": "眩晕长矛", + "Provides #BONUS resistance to explosive damage.": "提供#BONUS的爆炸伤害抗性。", + "CE-67 TITAN": "CE-67“泰坦”", + "BUGSLAYER": "诛虫煞星", + "85mm HEAT GRENADE MK2": "85mm高爆反坦克榴弹 MK2", + "A helmet worn by the pioneering Helldivers who first ventured into the Void. Designed by Super Earth scientists with liberated Illuminate blueprints.": "这款头盔由首批踏入寂域的先驱绝地潜兵所佩戴。由超级地球科学家利用解放的光能者手中蓝图设计而成。", + "12x25mm THERMITE": "12x25mm铝热弹", + "GRENADE PISTOL": "榴弹手枪", + "A drill capable of piercing the tough walls of Terminid hives, and deploying a nuclear charge to collapse all tunnels.": "这台钻机能够穿透终结族虫窝的坚硬墙体,还能部署核炸药摧毁所有隧道。", + "CPH-26 Commandant": "CPH-26“司令官”", + "Expendable Napalm": "消耗性凝固汽油弹", + "A plasma rifle, firing a bolt of superheated gas which explodes on impact. Avoid standing in proximity to the blast.": "等离子步枪,可发射一束过热气体,触及着弹点后引爆。请勿站在爆炸点附近。", + "Larger Shield": "延展护盾", + "#DEGREES°/sec": "#DEGREES°/秒", + "EX-03 PROTOTYPE 3": "EX-03“原型 3”", + "Big Whoop": "喝彩", + "NAPALM BOMB": "凝固汽油弹", + "LAS-17": "LAS-17", + "PROUD GOLD": "傲金", + "BREACHING HAMMER": "破门锤", + "PAYLOAD": "炮弹填料", + "RANDOMIZE VOICE": "随机声音", + "DAMAGE": "伤害", + "AGENT OF OBLIVION": "湮灭使者", + "STARS AND SUFFRAGE": "群星与选举", + "Default Helldiver Voice 4": "绝地潜兵默认声音 4", + "Over Artifice Triumphant": "巧取豪夺", + "MORE EXPLOSIVE FILLER": "增加爆炸物填料", + "Redirects propellant gases to compensate for muzzle climb when firing the weapon.": "通过更改推进气体流向,抵消射击时的枪口上扬。", + "Breaker Bugbiter": "噬虫“破裂者”", + "12x25mm Toxic": "12x25mm毒弹", + "Reaper of Bounties": "赏金收割者", + "HELLDRIVER": "绝地司机", + "DOUBLE FREEDOM": "双重自由", + "REDUCED SIGNATURE": "隐迹潜踪", + "SC-30 Trailblazer Scout": "SC-30“开路侦察兵”", + "40mm HE GRENADE": "40mm高爆榴弹", + "ANTI-MATERIEL RIFLE": "反器材步枪", + "IMMEDIATE AUTO LOADER": "即时自动装填", + "A high-velocity railcannon round fired at the largest target in close proximity to the beacon. Targeting is automatic.": "向信标附近的最大型目标发射高速轨道炮弹。轨道炮自动完成目标定位。", + "70mm LASER-GUIDED MISSILE": "70mm激光制导导弹", + "A barrage of rocket pods, which the Eagle pilot will release on the largest target near the stratagem beacon.": "火箭巢火力网。“飞鹰”驾驶员会将其发射至靠近战略配备信标的最大型目标。", + "LARGER GATLING MAGAZINE": "扩容加特林弹匣", + "Humble Regalia": "谦卑徽记", + "Agent of Oblivion": "湮灭使者", + "Woven for the trailblazers who successfully led the way during the first sanctioned deployment of a new tactical paradigm. This cape’s bold shoulder mount design ensures that while the Helldiver continues to ever look toward the future, enemies of Freedom shall gaze upon an extinction of their own making.": "专为在首个获批全新战术范式部署中成功领跑的开拓者们织就。这件披风采用大胆的肩部挂载设计,旨在确保当绝地潜兵继续放眼未来时,自由的敌人却将亲眼见证其自取灭亡的下场。", + "AF-02 HAZ-MASTER": "AF-02“危害大师”", + "A recoilless rifle effective against vehicle armor. Includes support backpack required for reloading.": "无后坐力炮,可有效对付载具装甲。包含支援背包,用于装填弹药。", + "DEFAULT HELLDIVER VOICE 3": "绝地潜兵默认声音 3", + "Orbital Railcannon Strike": "轨道炮攻击", + "Orbital Gas Round Mk3": "轨道毒气弹 MK3", + "AF-02 Haz-Master": "AF-02“危害大师”", + "PATRIOT EXOSUIT": "“爱国者”外骨骼装甲", + "BR-14": "BR-14", + "Increases reload speed of primary weapons by #BONUS.": "主要武器的装弹速度提高#BONUS。", + "No Underbarrel": "无下挂", + "This ceremonial rifle is modeled after antique relics from pre-Democratic times. It is traditionally gifted to every citizen upon turning 16 to encourage service.": "以前民主时代文明的遗产为模型制作的礼仪步枪,传统会赠给满16周岁的公民,鼓励他们服役。", + "13x40mm Penetrator": "13x40mm穿甲弹", + "9x20mm EXPLOSIVE": "9x20mm爆炸子弹", + "Anti-Air Missile": "防空导弹", + "M-104": "M-104", + "Knight": "骑士", + "A strafing run of the battlefield to clear small targets, delivered almost instantly.": "机枪扫射清除战场上的小型目标,几乎可在一瞬间内完成扫射。", + "CQC-42": "CQC-42", + "SG-225SP": "SG-225SP", + "DESERT STORMER": "沙漠突击者", + "CW-4 ARCTIC RANGER": "CW-4“极地游骑兵”", + "FS-55 DEVASTATOR": "FS-55“蹂躏者”", + "P-4": "P-4", + "5-STAR SUPER PRIVATE": "五星超级列兵", + "LARGER PLASMA CONTAINER": "扩容等离子弹药匣", + "When children have trouble sleeping, tucking them in under this cape reminds them that they are never alone, for Liberty's unseen defenders are always watching over them.": "为难以入睡的孩子盖上这件披肩,提醒他们并不孤单,看不见的自由卫士一直守护在侧。", + "Reinforce": "增援", + "ACCLIMATED": "应变自如", + "MADE READY": "现成补给", + "Mark of the Constrictor": "缚暴印记", + "12.5mm Standard Rifle Rounds": "12.5mm标准步枪子弹", + "EXTRA MAGAZINES": "额外弹匣", + "UPGRADED AMMUNITION FEED": "升级供弹系统", + "After colonists of Hellmire recovered a lost shipment of this armor, the local pastime of fence-smashing was born.": "海尔迈尔的拓殖地居民寻回一批丢失的这种盔甲后,当地兴起了一种狂打栅栏的娱乐方式。", + "Deploys a defensive anti-personnel minefield, to halt enemy advance.": "部署反步兵防御雷区,阻止敌人前进的脚步。", + "Leveller": "荡平者", + "RS-40 BEAST OF PREY": "RS-40“掠食凶兽”", + "CW-9 White Wolf": "CW-9“白狼”", + "VECTOR OF VICTORY": "胜利矢量", + "Increases initial inventory and holding capacity of stims by #SIGN#BONUS.": "治疗剂的初始库存和持有上限增加#SIGN#BONUS。", + "100KG BOMB MK3": "100KG炸弹 MK3", + "Ballistic Shield Backpack": "防弹护盾背包", + "An experimental weapon which prioritizes armor penetration. Must be charged between shots - so choose targets carefully.": "侧重穿甲能力的试验性武器。两次射击的间隙必须充能,因此,请谨慎选择目标。", + "CE-27 GROUND BREAKER": "CE-27“裂地者”", + "The Combat Walker's fuel capacity is increased by 50%.": "战斗步行机甲的燃料容量提升50%。", + "RAILGUN": "磁轨炮", + "A powerful plasma weapon that fires one blast at a time, each blast exploding on impact. Must be charged to fire. Warning: do not overcharge.": "威力强大的等离子武器,每次单发射击,击中目标后爆炸。开火前需要充能。警告:请勿过度充能。", + "10g Scatter Shot": "10g散射弹", + "High Capacity Heatsink": "高容量散热器", + "REBAR RESOLVE": "钢筋意志", + "AUTOCANNON": "机炮", + "LOOSEN UP": "放松", + "HALT": "止息", + "RANK 300": "300级", + "One of the earliest to be mass-produced, this cape has been the final sight of untold numbers of Freedom's foes.": "作为最早量产的披肩之一,此披肩已经见证了无数自由之敌的陨落。", + "Improved Air Brakes": "改良空气制动器", + "CQC-2": "CQC-2", + "Eye of the Clandestine": "隐匿之眼", + "MG-206": "MG-206", + "Body type has no impact on gameplay": "体型不影响游戏内容", + "Increases point-of-interest identification range by #BONUS.": "探索点识别范围扩大#BONUS。", + "This bolt-action rifle fires jet-assisted shells that explode shrapnel in all directions upon impact. Not recommended for close-quarters use.": "这种栓动步枪透过喷气辅助发射炮弹,炮弹触及撞击面时向四面八方崩裂碎片。不建议近战使用。", + "110mm Gas Cannon Round": "110mm毒气炮弹", + "Each purchase of this cape comes with a complimentary will and testament amendment form, which guarantees the soon-to-be-deceased a prominent spot on the Wall of Martyrs.": "每次购买这件披肩都会附赠遗嘱更改表,确保即将牺牲的战士在烈士墙上占据显眼位置。", + "The golden, piercing quills symbolize the deadly and poetic Justice delivered to seditious oppositionists. Silent sanctions, delivered with unerring precision and incontestable deniability.": "锐利的金色羽毛笔,象征着凭借充满诗意的致命正义严惩煽动叛乱的反对派。以精准无误和无可辩驳的手段实施无声的制裁。", + "PLASMA IGNITER MUZZLE BRAKE": "等离子点火器枪口制退器", + "BACKUP VEHICLE": "备用载具", + "A belt-fed minigun with an exceptional ammo capacity. Cannot be reloaded with standard non-belted munitions.": "使用弹链供弹的机枪,弹药容量非常充足。无法使用标准无链式弹药装填。", + "5.5x50mm FULL METAL JACKET": "5.5x50mm全金属被甲弹", + "Shorter Charge Time": "缩短充电用时", + "Anti-Materiel Rifle": "反器材步枪", + "VG-70": "VG-70", + "CONSTITUTION": "宪法", + "10g STUN ROUNDS": "10g眩晕弹", + "8x60mm Airburst": "8x60mm空爆弹", + "12g Liberty Fire": "12g“解放之火”霰弹", + "Hyena": "鬣狗", + "SG-8P": "SG-8P", + "G-142": "G-142", + "Talon": "猛爪", + "HOT DOG": "热狗", + "This convenient cape can double as ground insulation, warming blanket, or camp roofing to the enterprising defoliator.": "这款便利披肩可兼作地面隔离垫、保暖毯或营地遮顶,为富有开拓精神的伐木工提供多种用途。", + "Reflex Sight": "反射式瞄准镜", + "Combat Hatchet": "战斗短柄斧", + "8x60mm Super Uranium Core": "8x60mm超铀芯弹", + "A one-handed ceremonial sword suitable for use in parades, sabrage, and combat.": "单手礼仪刀,适合阅兵、开瓶和战斗。", + "Defense Wall": "防御墙", + "WAY OF THE BANDOLIER": "弹带之道", + "NO CHOKE": "无喉缩", + "Heavily layered to protect against ocular blistering, subdermal liquification, and gastrointestinal shattering, this armor is a testament to the power of iterative improvements based on user feedback.": "这套盔甲层层厚实,可防止眼部起泡、皮下液化和胃肠道碎裂,充分体现了根据用户反馈迭代改进的力量。", + "BLAST SIMULATION": "爆炸模拟", + "AC-1 Dutiful": "AC-1“恪尽职守”", + "CONCUSSIVE PADDING, REINFORCED": "防震内衬(强化型)", + "DEFENDER OF THE WALL": "高墙捍卫者", + "ORBITAL LASER": "轨道激光炮", + "ARROWHEAD": "ARROWHEAD", + "SILENCER": "消音器", + "LARGER EXPLOSION": "扩大爆炸范围", + "8x60mm Full Metal Jacket": "8x60mm全金属被甲弹", + "Larger Plasma Container": "扩容等离子弹药匣", + "EX-16 PROTOTYPE 16": "EX-16“原型 16”", + "Scatters powerful anti-tank mines that deal heavy, armor-penetrating damage. Minefield is less densely packed relative to smaller mines.": "发射强力的反坦克地雷,可造成严重的穿甲伤害。与较小型的地雷相比,雷区的部署密集度较低。", + "Plasma Igniter Muzzle Brake": "等离子点火器枪口制退器", + "DISSIDENT'S NIGHTMARE": "异见者梦魇", + "CQC-5": "CQC-5", + "Automatic Braking": "自动制动", + "BREAKER SPRAY&PRAY": "千发百中“破裂者”", + "AD-11 Livewire": "AD-11“生龙活虎”", + "Patriot Blue": "爱国蓝", + "LASER SIGHT": "激光瞄准器", + "Ingress-81": "进军-81", + "Standard Barrel": "标准枪管", + "SKULL ADMIRAL": "骷髅上将", + "A projected laser, that is aligned with the barrel of the weapon, which assists the user with landing their shots.": "与武器枪管对齐的投射激光,辅助使用者命中目标。", + "5.5x50mm SELF PROPELLED": "5.5x50mm自走弹", + "Iron Sight": "机械瞄具", + "Unblemished Allegiance": "无瑕忠诚", + "Greatcloak of Rebar Resolve": "钢筋意志大氅", + "For warriors who are so strong and confident that they don't need any reassurance whatsoever.": "为那些强大自信到不需要任何保证的战士而设计。", + "Humanity's intellect shines brighter than all other, piercing even the treacherous darkness that spawned the Automatons' pseudo-sentience; the darkness known as computer science.": "人类的智慧比万物更闪耀,能刺穿孕育机器人伪智能的“计算机科学”诡谲黑雾。", + "Conductor of Brilliance": "辉煌指挥官", + "The Hellbomb is a tactical nuke powerful enough to destroy any perceivable target in its blast zone. For safety and budgetary reasons, it has to be armed manually once deployed.": "地狱火炸弹是一种战术核武器,威力足以摧毁轰炸范围内的任何可见目标。出于安全和预算的原因,地狱火炸弹部署后必须手动启动。", + "FEDERATION'S EMBRACE": "联邦怀抱", + "Created to honor the great Freedom Chant of 2-14, in which over 10,000 loyal citizens united as one to express their undying respect for Freedom.": "为纪念伟大的2-14自由颂歌而创作,其时,有超过10,000名忠诚的公民联合表达了他们对自由的永恒敬重。", + "Short Revolver Barrel": "左轮手枪短枪管", + "EXPANDED BOMB RACKS": "扩展炸弹挂架", + "EPOCH": "纪元", + "G-4": "G-4", + "TENDERIZER": "肉锤", + "40mm APHE CANNON": "40mm穿甲高爆炮弹", + "HOLOGRAPHIC SIGHT": "全息瞄准镜", + "The default paint job for this weapon.": "该武器默认涂装。", + "100KG CLUSTER BOMB": "100KG集束炸弹", + "Marks the most obedient of the obedient, those who will strike headlong at the veins of Tyranny and administer the sweet antidote of Freedom.": "最顺从者的印记,当属毫不犹豫打击暴政血脉、为自由精神注入甜美解毒剂的人。", + "A camo paint job for use in urban environments.": "适用于城市环境的迷彩涂装。", + "85mm High-Explosive Grenade": "85mm高爆榴弹", + "EAGLE STRAFING RUN": "“飞鹰”机枪扫射", + "Improved Projectiles": "改良射弹", + "Constitution": "宪法", + "MAGAZINES": "弹匣", + "A turret firing powerful and precise laser beams. Warning: overloading heat sink may cause adverse effects.": "炮台,可发射威力强悍且精准的激光束。警告:散热器过载可能产生反效果。", + "Patriotic Administration Center": "爱国行政中心", + "ARC-3": "ARC-3", + "BOXER": "拳击手", + "PLAS-101": "PLAS-101", + "A paint job that is one with the darkness.": "与黑暗融为一体的涂装。", + "VERY LONG": "非常长", + "Breaker Incendiary": "高燃“破裂者”", + "Increased Fire Rate": "提升射速", + "SMG-203": "SMG-203", + "More HMG Mount Mags": "增加架设型重机枪弹匣", + "Diligence Counter Sniper": "反狙击“勤勉”", + "Treasure Hunt": "寻宝", + "13x40mm Hollow Point": "13x40mm空尖弹", + "MP-98": "MP-98", + "Solo Silo Targeting Remote": "单兵导弹发射井定位遥控器", + "MASTER DIVEMASTER": "大师潜兵长", + "Salvo Fire": "炮弹齐射", + "EYE OF FREEDOM": "自由之眼", + "ORBITAL WALKING BARRAGE SMOKE": "轨道游走烟雾火力网", + "Enables the user to jump higher than 'gravity' and 'safety' would normally allow. Must be charged before use.": "可助力使用者跳得更高,无视日常“重力”和“安全规范”的束缚。使用前必须充能。", + "SUPPORT": "支援", + "SSSD Delivery": "运送超级固态硬盘", + "8MM": "8mm", + "Increases sidearms reload speed by #BONUS.": "副武器重装速度提高#BONUS。", + "SEAF ARTILLERY: STATIC FIELD": "超级地球武装部队大炮:静电场", + "PROGRAMMABLE AMMO STUN ROUNDS": "智能眩晕弹", + "B-16 BATTLE-SCARRED VETERAN": "B-16“百战老兵”", + "SABER": "军刀", + "ASSAULT": "特攻", + "12x25mm High Velocity": "12x25mm高速弹", + "SENATOR": "参议员", + "EVEN MORE ARC SPLITS": "增加更多电弧分裂数", + "WELCOME ADORATION": "尽情崇拜", + "EXTRA BACKPACKS": "额外补给", + "Short Magazine": "短弹匣", + "R-63CS": "R-63CS", + "AR/GL-21": "AR/GL-21", + "Rapid Heatsink": "快速散热器", + "Based on a colonial surgeon's gown, where surgeries were often interrupted by a need to perform defensive duties.": "原型是殖民地外科医生的手术袍。外科医生经常在手术中途被打断,受命立刻前去执行防卫任务。", + "DP-40 HERO OF THE FEDERATION": "DP-40“联邦英雄”", + "CONDUCTOR OF BRILLIANCE": "辉煌指挥官", + "12g BIRDSHOT": "12g鸟弹", + "Shock and Awe Improvement": "提高震慑威力", + "5.5x50mm HOLLOW-POINT": "5.5x50mm空尖弹", + "Nuke": "核弹", + "Halt": "止息", + "Free-Spirited Spangles": "自由之魂的辉映", + "LIBERATOR": "解放者", + "MUZZLE VELOCITY": "枪口初速", + "SH-51": "SH-51", + "Breaker Spray&Pray": "千发百中“破裂者”", + "A throwable emplacement that generates a spherical, projectile-blocking shield on impact. Has a limited lifetime once deployed.": "可投掷的防护装置,落地时生成阻挡投射物的球形护盾。部署后的持续时间有限。", + "CW-22 Kodiak": "CW-22“科迪亚克”", + "THORACIC COLLISION EXULTATION MANEUVER": "碰胸庆祝", + "A slamfire shotgun: fires continuously while the trigger is depressed, via activation of the pump-action mechanism. Loaded with armor-piercing flechettes and equipped with an extended bayonet.": "一款速射霰弹枪:扣住扳机即可连续开火射击,采用泵动结构。装填穿甲飞镖弹,并配备加长刺刀。", + "RE-EDUCATOR": "思想改造", + "Loading Drills": "熟练装载配备", + "9x70mm Sniper Armor Piercing": "9x70mm穿甲狙击弹", + "Front-leaning rest position": "俯卧撑姿势", + "12g FLECHETTES": "12g飞镖弹", + "TX-41": "TX-41", + "SPACE CHIEF PRIME": "太空军督", + "PLASMA IGNITER CHOKE": "等离子点火器喉缩", + "DISPLAY OF BRAWN": "肌肉展示", + "Adorned with the insignia of the Order of the Venerated Ballot, a Ministry-sanctioned Patriot's Club for citizens who pledge themselves to preserving the sanctity of voting.": "饰有神圣投票团的徽章,该组织是由外交部批准设立的爱国者俱乐部,加入其中的公民承诺维护投票权的神圣性。", + "G-6": "G-6", + "EXTRA JUDICIAL": "法外制裁", + "Improves weapons handling with less drag on weapon movement.": "提升武器操纵性,降低携带武器移动的阻力。", + "A large-capacity assault rifle firing humane stun rounds. Reports of lethal incidents have been thoroughly debunked.": "大容量突击步枪,能发射人道主义眩晕弹药。相关致命事件的报告已被证实为谣言。", + "A specialized Fast Recon Vehicle equipped with heavier armor, a spiked ramming grille, and a roof-mounted heavy flamethrower at the expense of seating; this FRV can enable up to three Helldivers to deliver high-speed Justice, and forcefully clear obstructed transport routes.": "牺牲了座位以换取更厚重的装甲、带刺的冲撞格栅以及车顶安装的重型火焰喷射器。该快速侦察载具最多可承载三名绝地潜兵,高速播撒正义,强力打通受阻的运输路线。", + "Dynamite": "炸药", + "DP-40 Hero of the Federation": "DP-40“联邦英雄”", + "DP-11 CHAMPION OF THE PEOPLE": "DP-11“人民捍卫者”", + "SMG-32": "SMG-32", + "Crests the shoulders of those who deliver the final—and most indispensable—stroke of Justice.": "献给发起不可或缺的最终正义一击之人。", + "20mm FLAK ROUNDS": "20mm高射炮弹", + "Provides immunity to leg injuries.": "免疫腿伤。", + "TIP HAT": "脱帽致意", + "9x70mm SOCOM ASSASSIN": "9x70mm“刺客”特种作战弹", + "A high-speed Fast Recon Vehicle equipped with an automated defense turret and a mounted supply rack, allowing frontline personnel to fully replenish ammunition and medical supplies on the move.": "高速的快速侦察载具,配备自动防御炮台和挂载式补给架,允许前线人员在移动中全面补充弹药和医疗补给。", + "SIGNAL: HOLD": "信号:等待", + "70mm Laser-Guided Missile Mk2": "70mm激光制导导弹 MK2", + "You're Next": "轮到你", + "PRIDE OF THE WHISTLEBLOWER": "检举者的荣耀", + "ROVER": "漫游车", + "Some soldiers report picking up strange radio interference when wearing this armor near alien artifacts.": "部分士兵报告称,穿着这套盔甲接近外星古物时,会接收到奇怪的无线电干扰信号。", + "RS-67 Null Cipher": "RS-67“空密码”", + "An incendiary weapon for close range. Will ignite targets, terrain, and any flammable teammates.": "用于近程作战的燃烧武器,能点燃目标、地面,以及易燃易爆炸的队友。", + "85mm HIGH-EXPLOSIVE GRENADE": "85mm高爆榴弹", + "COMMAND DIVEMASTER MAJOR": "潜兵长少校指挥官", + "No oppressive murk, no fascist penumbra, no dictatorial haze and no unfree emanation; no tyrannical Gloom shall ever stand a chance against the searing light of Helldiver fire.": "无论是压迫的黑暗、法西斯的半阴影、独裁的迷雾还是非自由精神的辐射,任何专制的“阴霾”在绝地潜兵烈火般的灼热光芒前都将灰飞烟灭。", + "More Durable Chassis": "提升底盘耐久度", + "The burnished blood-red plates are forged in righteous fire, like the heroes they were wrought to protect.": "这闪闪发亮的血红色盔甲跟它保护过的英雄一样经受过正义之火的考验。", + "TR-9 CAVALIER OF DEMOCRACY": "TR-9“民主骑兵”", + "ANTI-TANK": "反坦克", + "Orbital Airburst Strike": "轨道空爆攻击", + "RAILGUN ROUND": "磁轨炮弹", + "EMS MORTAR SENTRY": "电磁冲击波迫击哨戒炮", + "APHET": "穿甲高爆曳光弹", + "OMBUDSMAN": "巡察者", + "Bugslayer": "诛虫煞星", + "2x TUBE RED DOT": "2倍红点瞄准镜", + "UF-84 DOUBT KILLER": "UF-84“疑虑克星”", + "LIFT-182": "LIFT-182", + "8x60mm LIBERTY FIRE": "8x60mm“解放之火”子弹", + "Grenadier Battlement": "掷弹兵防卫墙", + "AUTO LOADER": "自动装载", + "Woven in honor of our loyal Helldivers, whose heart's blood is the foundation on which Super Earth is built.": "这件披肩旨在纪念忠诚的绝地潜兵,他们的一腔热血是超级地球的发展根基。", + "MACHETE": "砍刀", + "AC-2 OBEDIENT": "AC-2“服从指挥”", + "ROCKET SENTRY": "火箭哨戒炮", + "Shield": "盾雷", + "SUPER SHERIFF": "超级警长", + "A/AC-8": "A/AC-8", + "Larger Explosion": "扩大爆炸范围", + "10g HE Rounds": "10g高爆弹", + "A stationary energy shield which provides cover against projectiles. Has a limited lifetime once deployed.": "固定式能量护盾,可用作掩体抵挡射弹。部署完毕后仅在有限时间内起防护作用。", + "13x40mm Magnum": "13x40mm马格南子弹", + "An advanced vertical foregrip to improve the maneuverability of the weapon.": "高级垂直前握把,可提升武器操控性。", + "40mm HEAT GRENADE": "40mm高爆反坦克榴弹", + "W.A.S.P. Launcher Backpack": "W.A.S.P.发射器背包", + "REFLEX SIGHT": "反射式瞄准镜", + "CM-21 TRENCH PARAMEDIC": "CM-21“战壕护理员”", + "Roll 'Em": "骰子定胜负", + "ROOKIE": "菜鸟", + "Vector of Victory": "胜利矢量", + "Tyranny's Bane": "暴政的毁灭", + "10g MAGNUM TRI-BALL": "10g马格南三连弹", + "The yellow is the exact shade of the Ministry of Unity's 'Golden Gate', leading to the Chamber of Unanimous Decision.": "这正是团结部“金门”的颜色,打开大门便能前往统一决策大厅。", + "ORBITAL GAS ROUND MK2": "轨道毒气弹 Mk2", + "CE-64 Grenadier": "CE-64“掷弹兵”", + "Lumberer Exosuit": "“伐木者”外骨骼装甲", + "Machine Gun": "机枪", + "Based on the ceremonial pennant flags of early Super Earth, which now adorn the entrance to each Ministry.": "设计原型是早期超级地球的仪式用三角旗,如今用于装饰各部门的入口。", + "Re-educator": "思想改造", + "REFLEX SIGHT MK2": "反射式瞄准镜MK2", + "This humane device attaches to its target and dispenses repeated electrical pulses, keeping the target in place for humane apprehension and/or termination.": "附着在目标上反复释放电击脉冲的人道主义设备,能将目标固定在原地,方便实施人道主义逮捕或处决。", + "8x60mm PENETRATOR": "8x60mm穿甲弹", + "SMALL PLASMA BOLT": "小型等离子弹", + "SC-37 LEGIONNAIRE": "SC-37“军团士兵”", + "ARMOR PENETRATION": "穿甲攻击", + "AX/TX-13": "AX/TX-13", + "To honor the heartfelt siblinghood of the heroes who stood together, bled together, and laid down their lives together in defense of Equality-On-Sea, all Helldivers are awarded one (1) commemorative polyester cape.": "为致敬在仰齐浜保卫战中共同浴血奋战的同志情谊,所有绝地潜兵将获赠一件(1)聚酯纪念披风。", + "A pistol firing bursts of guided, jet-propelled ammunition. Can be set to non-guided mode at any time, removing the need to lock on to targets.": "能发射制导喷射弹的手枪。随时可切换为非制导模式,无需锁定目标。", + "Flash Hider": "消焰器", + "HEEL KICK": "踢踏步", + "FOCUSED PRISM": "聚焦棱镜", + "STANDARD HEATSINK": "标准散热器", + "Improved targeting system": "改良目标锁定系统", + "A/FLAM-40": "A/FLAM-40", + "SCOUT": "侦察", + "TG-122 DEMO-TROOPER": "TG-122“爆破兵”", + "FLEET ADMIRAL": "舰队上将", + "TARGET SIGHTED": "索敌雷", + "Defoliation Tool": "除叶工具", + "Hair Trigger": "微力扳机", + "THIS GUY": "这家伙不得了", + "An incendiary device that shatters on impact, without explosive force, instantly creating a localized and persistent combustion field.": "一种撞击即碎的燃烧装置,无爆炸力,可瞬间产生局部且持久的燃烧区域。", + "10g HE ROUNDS": "10g高爆弹", + "A heavily-armored tank destroyer armed with a 120mm high-velocity cannon and a heavy coaxial machinegun.": "重装甲坦克歼击车,配备120mm高速火炮和重型同轴机枪。", + "BEACON OF MERCY": "仁慈信标", + "CREMATOR": "焚燃者", + "INCREASED OVERCHARGE TIME": "延长超负荷充电时长", + "SC-37 Legionnaire": "SC-37“军团士兵”", + "SR-24 Street Scout": "SR-24“街头侦察兵”", + "Part of a long line of experimental armor commonly seen on industrial engineering campuses, in the basements of select science aficionados, and around Super Destroyer Mega Garages.": "这件盔甲源于历史悠久的实验性盔甲系列,常见于工业工程学院、部分科学爱好者的地下室,以及超级驱逐舰大型车库内。", + "TR-7 Ambassador of the Brand": "TR-7“形象大使”", + "Federation's Embrace": "联邦怀抱", + "URBAN": "城市", + "13x40mm MAGNUM": "13x40mm马格南子弹", + "HUMBLE REGALIA": "谦卑徽记", + "Increased Storage Mk2": "可携带数量升级 MK2", + "70mm HE Rocket": "70mm高爆火箭弹", + "HOVER PACK": "悬浮背包", + "TOP DOWN": "自上而下", + "This cape has a visual pattern that when scanned by Automaton sensors translates to “defile your microwave mother, bot scum.”": "这款披风上的视觉图案被机器人传感器扫描时,会显示为“回你妈炉里重造吧,铁皮渣滓。”", + "DATA JACK": "数据接口", + "BETTER RACKS": "提高挂架质量", + "EMS Mortar Sentry": "电磁冲击波迫击哨戒炮", + "Smokescreen": "烟幕", + "10g Birdshot": "10g鸟弹", + "CQC-9": "CQC-9", + "Crewspace Removal": "移除船员舱", + "AT EASE": "稍息", + "WINDSWEPT WAYFINDER": "风驰引路者", + "EX-00 PROTOTYPE X": "EX-00“原型X”", + "AX/FLAM-75": "AX/FLAM-75", + "9x70mm SNIPER ARMOR PIERCING": "9x70mm穿甲狙击弹", + "Houses the Eagle Fighter & Pelican Shuttle. Also receives deliveries of materiel, supplies, frozen personnel, and fuel.": "停放“飞鹰”战斗机与“鹈鹕”运输船,同时还接收运来的材料、物资、冷冻人员以及燃油。", + "AUTOMATIC BRAKING": "自动制动", + "FIRE RATE": "射速", + "AD-49 Apollonian": "AD-49“阿波罗神”", + "Arc Thrower": "电弧发射器", + "STRATAGEM STATS": "战略配备数据", + "MORE MAGAZINES": "增加弹匣", + "HIGH-PRESSURE NAPALM": "高压凝固汽油弹", + "A linear artillery barrage which moves at intervals while firing smoke bombs to obscure enemy visibility.": "间歇性移动的线形火力网,通过发射烟雾弹,阻断敌方视线。", + "QUASAR CANNON": "类星体加农炮", + "A targeting remote, used in combination with the Solo Silo.": "定位遥控器,与单兵导弹发射井配合使用。", + "The unimpeachable justice of this cape's design is said to blind the enemies of Freedom with its glorious light.": "据说,此披肩无懈可击的正义设计将以荣耀光辉蒙蔽自由之敌的双目。", + "A high-caliber assault rifle with a restrictive magazine size but more stopping power.": "大口径突击步枪,弹匣容量有限,但停止作用较强。", + "10g High Velocity Sabot": "10g高速萨博特式霰弹", + "9x20mm Ripper": "9x20mm撕裂弹", + "LARGE PLASMA BOLT": "大型等离子弹", + "Dominator": "主宰", + "The embroidered pattern uses aluminium from Automaton motherboards, granting the once-wretched metals a new and noble purpose.": "刺绣图案采用了机器人主板上的铝材,为这些卑劣的金属赋予了更崇高的新使命。", + "Squat": "蹲坐", + "LARGER MAGAZINES": "扩容弹匣", + "SHOULDER-MOUNTED": "肩架式", + "70mm HE ROCKET": "70mm高爆火箭弹", + "First deployed in the Helldivers \"Diplomatic\" Corps, this armor enables effective non-verbal interspecies communication.": "这种盔甲最初投用于绝地潜兵的“外交”部队,非常适用于不同种族之间的非言语交流。", + "AUTOCANNON SENTRY": "自动哨戒炮", + "FLEX": "炫耀", + "Prosperous Green": "繁荣绿", + "FRAG": "破片手雷", + "BELT-FED GRENADE LAUNCHER": "弹链式榴弹发射器", + "ADVANCED ANGLED FOREGRIP": "高级直角前握把", + "As this cape flutters in the wind, it evokes a wishful, twinkling star in the sky—a star ripe for conquest.": "这件披肩在风中飘扬时,让人不禁联想到空中那颗充满希望、闪闪发光的星星,一颗等待征服的星星。", + "HIGH CAPACITY HEATSINK": "高容量散热器", + "RS-20 CONSTRICTOR": "RS-20“绞杀者”", + "RECOIL SIMULATION": "后坐力模拟", + "Purifier": "净化者", + "Supply FRV": "补给型快速侦察载具", + "Stun": "眩晕弹", + "A simple vertical foregrip to improve the maneuverability of the weapon.": "简单垂直前握把,可提升武器操控性。", + "A modified Punisher shotgun firing heavy, high-damage slug rounds. Perfect for punching big holes in big targets.": "改良后的“制裁者”霰弹枪,可发射重型高伤害独头弹,是往大型目标身上开洞的完美之选。", + "DS-42 Federation's Blade": "DS-42“联邦之刃”", + "This sigil reaffirms the Helldiver's pledge to protect Managed Democracy, serve Managed Democracy, and uphold Managed Democracy.": "这枚徽章再次强调了绝地潜兵对管理式民主的誓言:保卫、效命、秉持管理式民主。", + "This armor is the Super Earth Standard Issue, made from the same titanium alloy as the Destroyer's hull.": "超级地球制式盔甲,使用驱逐舰舰体的同种钛合金制成。", + "IE-3 MARTYR": "IE-3“烈士”", + "NUKE": "核弹", + "23mm HE CANNON": "23mm高爆炮弹", + "PH-202 TWIGSNAPPER": "PH-202“折枝”", + "NO MUZZLE": "无枪口配件", + "Lure Mine": "诱饵地雷", + "A heavier version of the Breaker shotgun, with higher damage at the cost of recoil and maneuverability.": "更重型的“破裂者”霰弹枪,虽然牺牲了后坐力和操控性,伤害却有所提升。", + "G-50": "G-50", + "110mm E.M.S. Cannon Round Mk2": "110mm电磁冲击波炮弹 MK2", + "Bearer is more resistant to being knocked prone.": "配备此盔甲可降低被击倒的概率。", + "Standard Prism": "标准棱镜", + "LAS-58": "LAS-58", + "Sweeper": "扫荡者", + "Railgun": "磁轨炮", + "A perfectly balanced multitool, optimized for the displacement of soil and other forms of resistance with surgical precision.": "一款完美平衡的多功能工具,经过特别优化,能以外科手术级的精准度移除土壤以及其他形式的抵抗。", + "Target Sighted": "索敌雷", + "10g RIFLED SLUGS": "10g线膛独头弹", + "Defender of Our Dream": "梦想卫士", + "DP-53 SAVIOR OF THE FREE": "DP-53“自由救星”", + "PH-56 Jaguar": "PH-56“捷豹”", + "Homing Ground Missile": "追踪式地面导弹", + "Bastion of Integrity": "忠义堡垒", + "Each gilded detail is polished to perfection by re-educated dissidents, as part of the Lifelong Post-Infraction Atonement Program.": "每一片镀金都由接受再教育的异见分子在终身违纪赎罪计划的监管下精心打磨至完美状态。", + "Increases the wearer's walking and running speed.": "可提升穿着者的步行与奔跑速度。", + "YOU'RE NEXT": "轮到你", + "A tribute to the mischief-makers and mavericks, those trailblazers who dutifully execute their orders with universally-endearing panache. The star-crossed trail calls to mind the special kind of Freedom that can only be achieved by going very fast in very expensive state-owned vehicles.": "对捣蛋鬼与特立独行者的致敬之作,这些开疆拓土的先锋恪尽职守使命必达,潇洒风度广受拥戴。如星轨交错般的下摆令人联想到一种特殊的“自由”——惟有为国驾驶价值不菲的载具疾速冲锋方能得到的自由。", + "UNFLINCHING": "毫不畏缩", + "This cape signifies that its wearer thinks, feels, and acts correctly at all times, and thus bears the responsibility to educate and re-educate their fellow citizen.": "这件披肩象征着穿戴者的思想、情感和行为一向无可指摘,因而肩负着教育和再教育同胞的重任。", + "It is said that only the truly Democratic can lift this cape to their shoulders.": "据说,只有真正的民主主义者才能披上此披肩。", + "ONE TRUE FLAG": "唯一真旗", + "Flashield": "闪光护盾", + "A pistol front-loaded with a single, powerful explosive. The weight of the projectile limits the weapon's range.": "前端加装单颗强力射弹的手枪。射弹重量限制了手枪的射程。", + "Rendering the Helldiver's descent to the battlefield in splendorous foil, this cape illustrates that in any successful military machinery, heroic humans are the most vital piece.": "这件披风以华丽烫印工艺展现了绝地潜兵空降战场的英姿,向世人昭示了一个真理:对于任何运转良好的军事机器来说,英勇无畏的人类都是最关键的部件。", + "Improved Reloading Process": "改良装弹流程", + "Redirects propellant gases to reduce recoil when firing the weapon.": "通过更改推进气体流向,减少射击时的后坐力。", + "12g LIBERTY FIRE": "12g“解放之火”霰弹", + "AMMUNITION STATS": "弹药数据", + "Offers its user brief fixed-height flight, stable enough for pinpoint marksmanship.": "穿戴者可在固定高度短暂稳定飞行,确保实现精确射击。", + "500kg Bomb": "500KG炸弹", + "PLAS-39": "PLAS-39", + "10g Flechettes": "10g飞镖弹", + "Designed to render even the largest foes into considerably smaller, and vastly more compliant, constituent parts. Sacrifices throwing range for a massive detonation on impact.": "旨在将体型最庞大的敌人拆解为体积小得多且远远更易“拿捏”的组成部件。以牺牲投掷距离为代价,换取命中时毁灭性爆炸威力。", + "The official uniform of the League of Patriotic Arm Wrestlers, this armor's lycra base layer is supple and sweat-wicking for maximum flexing comfort.": "爱国腕力联盟的官方制服,其莱卡底层布料柔软且兼具吸湿排汗功能,可为高强度的掰手腕动作提供极致舒适性。", + "A paint job for use in urban environments.": "适用于城市环境的涂装。", + "An angled foregrip to improve weapon stability.": "直角前握把,可提升武器稳定性。", + "CITY FIGHTER'S RESOLVE": "城市战士的决意", + "2x SUPPORT SCOPE": "2倍支援瞄准镜", + "A high explosive grenade which damages lightly armored targets. Creates high damage over a small area when detonated.": "高爆榴弹,能伤害轻型装甲的目标。引爆时可在小范围内造成较高伤害。", + "TR-62 KNIGHT": "TR-62“骑士”", + "GAS MINES": "毒气地雷", + "TG-122 Demo-Trooper": "TG-122“爆破兵”", + "AC-2 Obedient": "AC-2“服从指挥”", + "Liberator Concussive": "震荡“解放者”", + "A 'compliance weapon' to modify enemy behaviour. Creates a thick smoke screen to block targets' line of sight.": "改变敌人行为的“慑敌武器”,可形成一道厚重的烟幕,遮挡目标的视线。", + "CPR-80 Bulwark": "CPR-80 “壁垒”", + "Melta Mine": "热熔地雷", + "A/M-12": "A/M-12", + "STUN LANCE": "眩晕长矛", + "Eagle Cluster Bomb": "“飞鹰”集束炸弹", + "SWAY": "摆动", + "This aim-stabilizing armor found surprising secondary market success among alien birdwatching enthusiasts.": "这套可稳定瞄准动作的盔甲出乎意料地受到了外星观鸟爱好者的青睐,在二级市场大获成功。", + "Light Armored Vehicle": "轻甲载具", + "PH-56 JAGUAR": "PH-56“捷豹”", + "10g TRI-BALL": "10g三连弹", + "More Magazines": "增加弹匣", + "10g Sabot": "10g萨博特式霰弹", + "GS-17 Frontier Marshal": "GS-17“边境元帅”", + "Improved Rounds": "改良弹药", + "12g Buckshot Shells": "12g鹿弹霰弹", + "20mm APHET ROUNDS": "20mm穿甲高爆曳光弹", + "CQC-20": "CQC-20", + "HOMING GROUND MISSILE MK2": "追踪式地面导弹 MK2", + "Stinger": "毒刺", + "An antipersonnel fragmentation grenade. Creates damage over a large area when detonated.": "反步兵破片榴弹,引爆时可在大范围造成伤害。", + "SHAFTS OF DESPAIR": "绝望之柱", + "Improved Aiming Servos": "改良瞄准伺服系统", + "A modified Diligence rifle offering increased damage at the cost of some maneuverability. Fires a single bullet at a time.": "改良的“勤勉”步枪,伤害有所提高,但牺牲了一点操控性。每次只能发射一发子弹。", + "12x25mm HIGH VELOCITY": "12x25mm高速弹", + "Guard Dog": "“护卫犬”", + "VOLATILE PLASMA BOLT": "易气化等离子弹", + "WARP PACK": "传送背包", + "ATTACK SPEED": "攻击速度", + "CE-81 JUGGERNAUT": "CE-81“巨人”", + "SUPPLY FRV": "补给型快速侦察载具", + "RS-89 Shadow Paragon": "RS-89“暗影典范”", + "4x Combat Scope": "4倍战斗瞄准镜", + "STIMULATIVE": "治疗剂", + "A-35 RECON": "A-35“侦察者”", + "Prepared Crates": "预备弹药箱", + "#BONUS chance to not die when taking lethal damage.": "受到致命伤害时,不会阵亡的概率额外提高#BONUS。", + "12g BUGSHOT": "12g虫弹", + "Spire Sterilizer": "虫塔杀菌器", + "A flattened muzzle that forces the shotgun pellets into a thin horizontal line.": "扁平枪口,迫使霰弹呈水平细线发射。", + "LARGE DRUM": "大型弹鼓", + "Diagram of the Noblest Payload": "至高使命图谱", + "I-102 Draconaught": "I-102“龙行者”", + "REINFORCE": "增援", + "AF-91 FIELD CHEMIST": "AF-91“实地化学家”", + "E/AT-12": "E/AT-12", + "Supply boxes containing ammunition, with a backpack that allows the user to distribute boxes to fellow Helldivers.": "装着弹药的补给箱,配有背包,可供使用者将箱子分配给其他绝地潜兵。", + "Trucker's Triumph": "卡车司机的胜利", + "Ombudsman": "巡察者", + "GAS": "毒气榴弹", + "Incendiary support fed by a massive backpack fuel tank. This heavy flamethrower enables a continuous column of fire to cleanse the battlefield.": "由巨型背负式燃料罐提供燃料的燃烧型支援武器。这款重型喷火器能喷射出一道持续的火柱,荡涤净化战场。", + "Napalm Bomb Mk2": "凝固汽油弹 MK2", + "8x60mm Explosive": "8x60mm爆炸子弹", + "AX/ARC-3": "AX/ARC-3", + "DEFOLIATION TOOL": "除叶工具", + "COVERING FIRE": "火力掩护", + "DP-53 Savior of the Free": "DP-53“自由救星”", + "DAMAGE / SEC": "每秒伤害", + "Larger Fuel Tank": "扩容燃料罐", + "RAGS OF THE FASHIONABLE": "时尚褴褛", + "Breaching Hammer": "破门锤", + "Faster Deployment": "加快部署", + "A pistol that fires grenades. Must be reloaded between shots.": "发射榴弹的手枪,每射击一发子弹后必须重新装弹。", + "SEAL OF GENERAL CONSENSUS": "康森瑟斯将军之印", + "ORBITAL PRECISION STRIKE": "轨道精准攻击", + "TREASURE HUNT": "寻宝", + "No Choke": "无喉缩", + "PLAS-1": "PLAS-1", + "G-123": "G-123", + "An accurate, hard-hitting laser revolver with bespoke break action for heat sink swaps.": "精准且威力强大的激光左轮手枪,定制中折式设计便于更换散热器。", + "Laser": "激光", + "ENGINEER": "工兵", + "Holder of the Yellow Line": "黄线捍卫者", + "Patched and tattered, this banner yet waves from the unbowed shoulders of Freedom's most battle-tested warriors.": "这面旗帜虽历经修补,却依然飘扬在久经沙场的自由战士们不屈的肩膀之上。", + "R/40-K": "R/40-K", + "Machine Gun Sentry": "哨戒机枪", + "When facing the enemies of Freedom this Reckoningtide, keep up the festive spirit by recalling the opening line of A Vengeant Carol: \"They'll soon be dead, to begin with.\"": "在这个清算时节面对自由之敌时,请牢记《复仇颂歌》的开场白,坚守我们的节日精神:“它们很快就会死去,这是故事的开始。”", + "Features a patented non-stick coating, which makes scraping viscera off after a long day of battle less taxing.": "采用专利不粘涂料,方便你在一整天的血战之后轻松去除表面的脏器。", + "12g Flechette Shells": "12g飞镖霰弹", + "FS-38 Eradicator": "FS-38“根除者”", + "Veridical Ideology": "真理意识形态", + "Ruggedized for extended operation beyond the reach of paved logistics. This armor's heavy plating is intended for the \"unpaving\" of hostile territory, providing a mobile bulkhead for Helldivers who don't know the meaning of \"environmental obstacles.\"": "为执行铺装物流以外的长时间任务而强固处理。这款护甲的重型装甲旨在“铲平”敌方领土,为不懂“环境障碍”为何物的绝地潜兵提供移动堡垒。", + "Should the wearer of this cape perish at the hands of Freedom's enemies, it is customary to pass the cape on to their bravest child during the funeral, inspiring the next generation to take up arms.": "若这件披肩的佩戴者死于自由之敌手中,按照传统,葬礼上会将披肩传给其最勇敢的子女,激励下一代拿起武器继续战斗。", + "Pillars of Freedom": "自由支柱", + "ORBITAL 380MM HE BARRAGE": "轨道380MM高爆弹火力网", + "TR-40 GOLD EAGLE": "TR-40“金鹰”", + "Tesla Tower": "特斯拉塔", + "HEAT Grenades": "高爆反坦克榴弹", + "Creates a far-reaching incendiary blast ideal for crowd control against smaller enemies of Freedom. Equipped with a programmable timer for strategic versatility.": "引发大范围燃烧爆炸,适合对小规模自由之敌实施群体控制。配备可编程定时器,增强战术灵活性。", + "P-41": "P-41", + "This shotgun blasts a wide burst of high-voltage electricity that arcs between all units—enemy or otherwise—within range.": "这把霰弹枪能在大范围内释放高压电流,在效果范围内的所有敌我单位之间形成电弧。", + "Additional Hardpoints": "附加挂载点", + "PROJECTILES": "射弹", + "66mm MISSILE MK2": "66mm导弹 MK2", + "ORBITAL GAS ROUND MK3": "轨道毒气弹 MK3", + "JAMMED PIÑATA": "满载惊喜的皮纳塔", + "Caltrops": "铁蒺藜", + "The distinctive red, white, and green of the Intergalactic Medical Corps signal to all Helldivers that help is at hand.": "看见星际医疗部队标志性的红白绿三色,所有绝地潜兵都会意识到医疗援助即将到来。", + "Testament to Attrition": "百战不殆的明证", + "SUPER PEDESTRIAN": "超级步兵", + "RIGHTFUL OCCUPIER": "正当占领者", + "EXPENDABLE NAPALM": "消耗性凝固汽油弹", + "THERMITE": "铝热弹", + "RE-2310 HONORARY GUARD": "RE-2310“荣誉卫队”", + "Increases throwing range by #BONUS.": "投掷距离延长#BONUS。", + "Tests and implements the most advanced stratagem technology that funding has been allocated for.": "测试与应用受拨款支持的顶尖战略配备技术。", + "Call in an emergency beacon to show other Helldivers that you need assistance.": "呼叫求救信标,向其他绝地潜兵表明你需要支援。", + "20mm HE Cannon": "20mm高爆炮弹", + "Incinerator FRV": "炽灼型快速侦察载具", + "Schema Laid Bare": "解封蓝图", + "LIBERATOR CONCUSSIVE": "震荡“解放者”", + "Increases ammo capacity of all weapons by #BONUS. Does not affect weapon backpacks.": "所有武器的弹药容量增加#BONUS。武器背包除外。", + "This traditional armor has remained unchanged since time immemorial. Now with self-heated padding.": "这套传统盔甲自古至今一直保持原样。而今配备了自热内衬。", + "FS-61 DREADNOUGHT": "FS-61“无畏”", + "EXPENDABLE": "消耗品", + "Originally worn by lunar terraformers, this suit can withstand rapid changes in pressure, heat, and personal velocity.": "原本是月球地形改造人员的装备,足以承受气压、温度和个人速度的急剧变化。", + "85mm HEAT GRENADE": "85mm高爆反坦克榴弹", + "Long Revolver Barrel": "左轮手枪长枪管", + "Pummeler": "暴击斗士", + "Multi-Launch Protocol": "多管发射协议", + "Popularized by actor Chip Messiter, who wore this in the action-rom-com-musical \"Lost My Heart to a Man in a Helmet.\"": "由演员奇普·梅西特推广,他曾在动作浪漫欢乐音乐剧《爱上一个不脱头盔的人》中穿着这套盔甲。", + "12x25mm Ripper": "12x25mm撕裂弹", + "120mm HE Cannon Round": "120mm高爆炮弹", + "Missile Performance": "导弹性能", + "Increased Fuel Capacity": "提升燃料容量", + "1.5x Tube Red Dot": "1.5倍红点瞄准镜", + "IE-3 Martyr": "IE-3“烈士”", + "RAISE WEAPON": "高举武器", + "PYROTECH": "烟花术", + "A pistol with a built-in laser sight, suppressor, and flashlight.\nProduced by Martian Armory.": "内置激光瞄准器、消音器和手电筒的手枪。\n由火星军械库生产。", + "9x20mm Full Metal Jacket": "9x20mm全金属被甲弹", + "CPH-26 COMMANDANT": "CPH-26“司令官”", + "MORE HMG MOUNT MAGS": "增加架设型重机枪弹匣", + "A camo paint job for use in forest environments.": "适用于森林环境的迷彩涂装。", + "DP-8 MOUNTAIN-SCALED": "DP-8“山峦鳞甲”", + "FAF-14": "FAF-14", + "RANGER, EAGLE CLASS": "飞鹰级游骑兵", + "40mm HEAT Grenade": "40mm高爆反坦克榴弹", + "Variable": "变数", + "GUNS OF LIBERTY": "自由利器", + "NAPALM BOMB MK3": "凝固汽油弹 MK3", + "SH-20": "SH-20", + "Larger Ammunition Storage": "扩充弹药存储量", + "LONGER FIRE TIME": "射击时间延长", + "A repurposed firework that showers its immediate surrounding area in sparks before exploding. As delightful as it is incendiary.": "由烟花改装而成,在爆炸前向四周溅射火花。既绚丽如烟火,又致命如烈焰。", + "Increases initial inventory and holding capacity of throwables by #BONUS.": "投掷武器的初始库存和持有上限增加#BONUS。", + "EAGLE SMOKE STRIKE": "“飞鹰”烟雾攻击", + "Longer Grenade Belt": "加长榴弹腰带", + "VIGOROUS THRUSTING": "盛气凌人", + "FULL CHOKE": "全喉缩", + "8x60mm Double Power": "8x60mm双效子弹", + "110mm Airburst Cannon Round Mk2": "110mm空爆炮弹 MK2", + "CM-06 COMBAT MEDIC": "CM-06“医疗兵”", + "Projects an arc of lightning at close range. Charges up to project bolts, and may discharge through multiple targets.": "在近程范围内发射一道电弧。充能可发射电球,然后向多个目标放电。", + "ADMIRAL": "上将", + "B-02 Gloom Warden": "B-02阴霾守望者", + "Veto": "否决者", + "8x60mm EXPLOSIVE": "8x60mm爆炸子弹", + "An armor often worn by frontline surgeons, who are skilled at both putting bodies back together and taking them apart.": "前线外科医生的常用盔甲。他们既有出色的缝合技术,也很了解该怎样将敌人大卸八块。", + "FORTIFIED": "强化", + "Gives wearer a #BONUS chance to avoid grievous limb injury.": "佩戴者有#BONUS的几率避免四肢重伤。", + "Finger Guns": "手指枪", + "HORIZONTAL RECOIL": "水平后坐力", + "Hot-shot Marksman Rifle": "高能精确射手步枪", + "9x70mm FULL METAL JACKET": "9x70mm全金属被甲弹", + "12g Birdshot": "12g鸟弹", + "STIM PISTOL": "治疗剂手枪", + "Stun Explosion": "眩晕爆炸", + "12g Tri-Ball": "12g三连弹", + "Liberator Penetrator": "穿甲“解放者”", + "Shield Generator Relay": "防护罩生成中继器", + "9x70mm SUPER URANIUM CORE": "9x70mm超铀芯弹", + "FLAMES": "喷射火焰", + "BREAKER": "破裂者", + "SPEAR": "飞矛", + "An autonomous drone equipped with a Liberator assault rifle, providing 360° cover. Returns to backpack to rearm.": "配备“解放者”突击步枪的自主无人机,可提供全方位掩护。需要补充弹药时会返回背包。", + "12g Scatter Shot": "12g散射弹", + "A cape inspired by hypothetical covert operatives—pillars of Democratic order, operating in the hostile abyss where Liberty's light cannot yet reach.": "这件披肩的灵感源于幻想的秘密特工,他们被视为民主秩序的支柱,在尚未亮起自由之光的危险深渊中执行任务。", + "KDM-500 OUTRIDER": "KDM-500“先驱骑兵”", + "Adjudicator": "审判者", + "Equip stratagems to be able to drop into a mission!": "装备战略配备后才能投身任务!", + "MORE ARC SPLITS": "增加电弧分裂数", + "EXTRA PADDING": "额外垫料", + "Bearers of this cape take upon a sacred duty: that of delivering righteous retribution to every last deserving being.": "穿戴此披肩的人将背负神圣的使命:向每一个罪有应得的生灵发动正义的复仇。", + "Delivers silent justice to Freedom's enemies.": "向自由之敌传递无声的正义。", + "PINEAPPLE": "菠萝", + "MORE SALVOES": "增加齐射炮弹数", + "LARGER ROCKET PODS": "提升火箭巢装载量", + "Exploding Crossbow": "爆燃弩", + "Increased Overcharge Time": "延长超负荷充电时长", + "9x20mm High Velocity": "9x20mm高速弹", + "Shorter Cooldown Mk2": "冷却用时缩短 Mk2", + "TRUE GRIT": "坚韧不拔", + "A pump shotgun that fires a burst of incendiary phosphorus pellets, setting targets ablaze.": "泵动式霰弹枪,可连射燃烧磷弹,将目标点燃。", + "#NAME PERMIT": "#NAME许可证", + "STAMINA DRAIN": "耐力消耗", + "C4 PACK": "C4背包", + "FINGER GUNS": "手指枪", + "The SteerComfort fit of this armor allows the wearer to feel every curve, bump, and jostle of their Exosuit, as if they were one single being.": "这套盔甲的“舒适贴合驾控”设计能让穿着者感知外骨骼装甲的每一次弯折、颠簸与震动,仿佛人机合一。", + "Research suggests that Helldivers wearing this cape are seen as 17% more patriotic.": "研究表明,绝地潜兵如果穿着这件披肩,所展现的爱国程度将提升17%。", + "TOTAL VALUE": "总价值", + "EXECUTIONER'S CANOPY": "刽子手的披风", + "Larger Rocket Pods": "提升火箭巢装载量", + "Those taken under the wings of the Law can rest easy knowing that their transgressions will soon be laid bare, their harms amended, and their citizenship safely sequestered.": "那些在法律羽翼庇护下的人将无需再担忧,因为他们的罪行很快就会揭露无遗,曾经造成的伤害会得到弥补,而他们的公民身份也将被安全并妥善地剥夺。", + "Large Plasma Bolt": "大型等离子弹", + "Made famous by the Ministry of Intelligence's hide-and-seek-and-destroy champion of '52, this armor has been improved by removing excess shoulder protection.": "这套盔甲因赢得情报部52年度“隐蔽歼敌”比赛冠军而闻名。已移除多余的肩部护甲,进一步改良了设计。", + "IMPACT": "冲击弹", + "500kg BOMB MK3": "500KG炸弹 MK3", + "FS-34 Exterminator": "FS-34“灭绝者”", + "Watchful Compatriot": "守望同胞", + "Autocannon Backpack": "机炮背包", + "SG-225NS": "SG-225NS", + "S-11": "S-11", + "Completely sheathed in 14-cm silica fiber foam, except for a thin tube to the ear canal to enable hearing the satisfying screeches of Freedom's enemies as they burn.": "14厘米厚的硅纤维泡沫将全身包裹在内,只在耳道处留下了纤细的管道,让穿戴者能够心满意足地听见自由之敌在烈火中痛苦尖叫。", + "SWEEPER": "扫荡者", + "GL-52": "GL-52", + "DEFENDER OF OUR DREAM": "梦想卫士", + "10g FRAGMENTATION": "10g破片弹", + "A versatile missile launcher loaded with seven lock-on homing missiles. These can either be fired from the launcher directly or as an airburst. Includes support backpack required for reloading.\nProduced by Stål Arms.": "多功能导弹发射器,装载了七枚锁定追踪式导弹。导弹可通过发射器直接发射或作为空爆弹发射。包含支援背包,用于装填弹药。\n由斯塔尔武装公司生产。", + "FOE RENT ASUNDER": "敌分四裂", + "200KG BOMB": "200KG炸弹", + "TARGETING DISTANCE": "目标距离", + "M90A": "M90A", + "LASER CANNON": "激光大炮", + "This multi-layered protective armor keeps rough sand, spores, and other coarse granules from irritating the skin.": "这套多层防护盔甲能有效阻隔粗糙沙粒、孢子和其他颗粒物,防止皮肤受到刺激。", + "JUSTICE": "正义", + "Wearers of this stealthy armor are seldom seen by their targets—or squadmates. No refunds if misplaced.": "穿戴这套潜行盔甲的人鲜少被目标(或队友)发现。如被队友误认,恕不退款。", + "Bullet Storm": "子弹风暴", + "Scout Striders": "侦察纵步者", + "GENESIS PRIME": "创世主星", + "EUKORIA": "欧科里亚", + "ADVANCED DEVASTATOR": "进阶蹂躏者", + "Olofson": "奥洛夫松", + "Persson": "佩尔松", + "Scout Strider": "侦察纵步者", + "STANDARD EXOSUIT PATTERN": "标准外骨骼装甲涂装", + "Ankarberg": "安卡贝格", + "Radical": "激进先锋", + "Sovereign": "主宰", + "Martyr": "烈士", + "XENOBITE ARDENT": "炽热异噬者", + "HANGAR 6": "6号机库", + "BOTEIN": "天阴四", + "Mirror": "之镜", + "PROSPERITY CITY": "荣都", + "THRASH IV": "萨尔什4号", + "Patriot": "爱国者", + "Englund": "恩隆德", + "LASTOME": "归宿市", + "BUNKER TURRET": "碉堡炮台", + "SAFETY ORANGE SHUTTLE PATTERN": "安全橘运输船涂装", + "ACUBENS PRIME": "柳宿增三主星", + "AKIRA SECTOR": "阿基拉分区", + "FREEDOM PEAK": "弗里敦峰", + "Steeled Veterans": "铁血老兵", + "of Twilight": "暮光", + "Incendiary MG Devastator": "燃烧机枪蹂躏者", + "Leahy": "莱希", + "Crushers": "粉碎者", + "SOL SYSTEM": "太阳系", + "GUNPOWDER MEADOWS": "火药草原", + "Outcast Tracker": "循踪光弃者", + "Charger Behemoths": "巨兽级强袭虫", + "RATTLESNAKE EXOSUIT PATTERN": "响尾蛇外骨骼装甲涂装", + "Warrior": "武士", + "GUNVALD": "古恩瓦尔德", + "INTREPIDNESS": "勇魄市", + "GHOUL": "噬光者", + "Overships": "统御舰", + "Advocate": "拥护者", + "Brood Commanders": "虫族指挥官", + "PYTHON COMMANDOS": "蟒蛇突击兵", + "Predator Stalkers": "掠食追踪虫", + "SULFURA": "萨尔弗拉", + "SEASSE": "西斯", + "MAW": "深渊", + "SETTLEMENT 7": "7号定居点", + "of Vigilance": "警惕", + "KORV": "科尔脯", + "Advanced Devastators": "进阶蹂躏者", + "STALKER": "追踪虫", + "KLEN DAHTH II": "克伦达斯II", + "Executor": "执行者", + "Reinforced Scout Striders": "强化侦察纵步者", + "IVIS": "艾维斯", + "Sonesson": "索内松", + "MOBILE WHITE EXOSUIT PATTERN": "移动白色外骨骼装甲涂装", + "ARTURION SECTOR": "阿图里昂分区", + "PHANTOM 1": "幻影1", + "MARS": "火星", + "CONVENIENCE": "捷城", + "WARP SHIP": "穿梭舰", + "GAZER": "凝视者", + "SYZYGY": "朔望", + "Ghouls": "噬光者", + "Bredberg": "布雷德贝格", + "FALSTAFF SECTOR": "法尔斯塔夫分区", + "High Command has identified this Megafactory as one of two potential beachheads for the invasion of Cyberstan. Anti-air fixtures will hamper Pelican extraction.": "最高指挥部已将这座超大型工厂认定为入侵生化斯坦的两个潜在滩头堡之一。防空设施将阻碍“鹈鹕”号撤离。", + "PIONEER II": "先驱II", + "VOTER'S FALLOW": "选民荒地", + "BLACKVEIN MINES": "黑脉矿井", + "BRNO": "布尔诺", + "OUTPOST 32": "32号哨站", + "Sall": "萨尔", + "OBTRUDER": "突入者", + "Sentinel": "哨兵", + "PSEUDOTOPIA": "伪托邦", + "FORT SANCTUARY": "庇护堡", + "Bulk Fabricators": "巨型构筑者", + "EQUALITY-ON-SEA": "仰齐浜", + "TIEN KWAN": "天关", + "STARPASS": "星通市", + "Freedom's Flame": "自由烈焰", + "VOG-SOJOTH": "佛戈索约斯", + "Each form and application that passes through the hallowed halls of AdminCen is emblazoned with the Stamp of Ages, and should be given a place of honor in the home.": "行政中心神圣大厅经手的表格和申请均印有“时代印章”,应当摆放在家中显赫位置。", + "INCENDIARY MG DEVASTATOR": "燃烧机枪蹂躏者", + "PATHFINDER V": "开拓者V", + "NEW VICTORY": "新胜利市", + "HULK": "巨型者", + "Command Bunker": "指挥碉堡", + "CUTTING EDGE": "遥遥领先", + "GEM LICKET": "晶蚀", + "Schmid": "施密德", + "GAR HAREN": "轧尔哈伦", + "Outcast Seekers": "逐觅光弃者", + "SPORE BURST WARRIOR": "孢裂武斗虫", + "Entrenched Division": "堑壕之师", + "TOR E": "托尔E", + "of Law": "法律", + "RECON HEIGHTS": "侦察高地", + "KEPLER-395b": "开普勒395b", + "INCONSPICUOUS BLACK EXOSUIT PATTERN": "低调黑外骨骼装甲涂装", + "SLIF": "斯利夫", + "MIDASBURG": "弥达斯堡", + "of Determination": "坚决", + "MINERAL REFINEMENT WORKS": "矿物精炼厂", + "DARROWSHOME": "达罗橡", + "AESIR PASS": "亚萨关隘", + "Democracy Officer": "民主官", + "Sandberg": "桑德贝格", + "BANEFUL SENTINEL": "祸患光能哨兵", + "JET BRIGADE RAIDER": "喷气旅奇袭者", + "HIVE LORD": "霸王虫", + "OSHAUNE": "欧绍恩", + "Outcast Trackers": "循踪光弃者", + "MEMORIALS": "纪念市", + "PERSISTENCE GATE": "恒久之门", + "SVITJOD": "斯维特约德", + "RIGHTEOUS REVENANTS": "正义复仇者", + "War Striders": "战争纵步者", + "Agitators": "惑乱者", + "HEETH": "希斯", + "CHORT BAY": "雀特湾", + "WAR HORSES": "战马", + "CURRENCY": "通汇城", + "KHANDARK": "勘达尔克", + "PERMACURIS": "佩玛丘拉斯", + "DURGEN": "德尔根", + "FODDER GORGE": "草料谷", + "ANNIHILATED SYSTEM": "已歼灭星系", + "of Battle": "激战", + "MORADESH": "莫拉戴什", + "STRENGTH": "力量市", + "KELLA METAMORPH": "凯拉蜕变城", + "TALUS SECTOR": "塔洛斯分区", + "Jet Brigade Raiders": "喷气旅奇袭者", + "Heavy Devastator": "重型蹂躏者", + "SERENITY SUMMIT": "静峰", + "RATTLESNAKE SHUTTLE PATTERN": "响尾蛇运输船涂装", + "LLANFAIRPWLLGWYNGYLLGOGERYCHWYRNDROBWLLLLANTYSILIOGOGOGOCH II": "LLANFAIRPWLLGWYNGYLLGOGERYCHWYRNDROBWLLLLANTYSILIOGOGOGOCH II", + "Xenobite Ardents": "炽热异噬者", + "DROPSHIP": "运输舰", + "NEW HAVEN": "纽黑文", + "Magistrate": "司卫", + "PEASE": "平息市", + "GEMSTELLE GENERATOR": "晶星动力", + "UNDERGROWTH EXOSUIT PATTERN": "灌木外骨骼装甲涂装", + "LURZA": "卢尔扎堡", + "HUMANITY": "人道市", + "SHELT": "谢尔特", + "Distor": "迪斯特", + "NONE": "无", + "MINTORIA": "敏托瑞亚", + "HULK BRUISER": "巨型碾压者", + "Prophet": "先知", + "HYDROFALL PRIME": "水瀑主星", + "Bile Spitter": "胆汁吐沫虫", + "EMORATH": "艾莫拉斯", + "Rohde": "罗德", + "JET BRIGADE TROOPER": "喷气旅装甲兵", + "STANDARD SHUTTLE PATTERN": "标准运输船涂装", + "EVOLUTION PLATS": "演化高地", + "of Pride": "自豪", + "TERMADON": "特尔玛登", + "STOLTHET": "荣傲", + "Watchers": "守望者", + "GRACIOUS LIBERTY": "仁慈自由市", + "Gonçalves": "贡萨尔维斯", + "MANDILARIA": "曼迪拉里亚", + "of Iron": "铸铁", + "Following the Great York Conundrum, one City rose above the rest, pledging to hold its Hand over all other Yorks, so that no more blood be spilt between them.": "约克大纷争结束后,一座城市力压群雄,誓要统御其他约克市,终结彼此间的流血纷争。", + "Cannon Turret": "加农炮台", + "Emperor": "君主", + "FILIBUSTER": "冗辩市", + "Nursing Spewer": "抚育喷涌虫", + "of Conquest": "征服", + "ICE BEND": "冰本德", + "BENEVOLENCE": "仁城", + "AGARTHA": "雅戈泰", + "URECTEM": "乌雷克特姆", + "MYRIUM": "梅里翁", + "CHAMELEON CAMO HELLPOD PATTERN": "变色龙迷彩绝地喷射舱涂装", + "PINE TAR": "松焦", + "LUXE POINT": "琉角", + "War Strider": "战争纵步者", + "RATCH": "拉奇", + "CONSENSUS": "康森瑟斯", + "SEASSEFYRE": "息战市", + "HAMMARBY": "哈马比", + "HEATHERFIELD": "希瑟菲尔德", + "KERTH SECUNDUS": "克斯次星", + "GEMMA": "贯索四", + "Terminid": "终结族", + "Dropship": "运输舰", + "FREEDOM ETERNAL": "永恒自由城", + "CANCRI SECTOR": "康古利伊分区", + "Rupture Spewers": "爆裂喷涌虫", + "McEachern": "麦凯克伦", + "ANGEL'S VENTURE": "天使投资", + "ANNE'S VIGIL": "安妮守望城", + "VARYLIA 5": "瓦瑞拉亚5", + "Alpha Commander": "阿尔法指挥官", + "MINERVA": "密涅瓦", + "FRAKENEERIA": "弗兰科尼亚", + "EPH": "埃夫市", + "BROKER'S WEALTH": "经纪财富市", + "INDEPENDENCE": "独立市", + "DARROWSPORT": "达罗斯波特", + "MG Raider": "机枪奇袭者", + "of Democracy": "民主", + "TRANSCENDENCE": "超验枢", + "Bile Spitters": "胆汁吐沫虫", + "HERITAGE OLIVE EXOSUIT PATTERN": "经典橄榄绿外骨骼装甲涂装", + "of Supremacy": "至高", + "SHREDDER TANK": "碎裂坦克", + "JET BRIGADE MG TROOPER": "喷气旅机枪装甲兵", + "Hulk Bruiser": "巨型碾压者", + "KARON BAY": "凯伦湾", + "Facility Operator": "设施操作员", + "HARVESTER": "猎杀器", + "VENERATION": "敬仰市", + "CRUSHER": "粉碎者", + "None": "无", + "HILJAISUUS": "寂城", + "Commissar": "机械统帅", + "Advanced Devastator": "进阶蹂躏者", + "Nazareno": "纳萨雷诺", + "ADRENAL 8": "脉涌8", + "Hive Guard": "虫窝护卫", + "SEVERITY": "严峻市", + "War Horses": "战马", + "VOTELESS": "无票者", + "PADOSAN": "毗印市", + "ONSEN": "温泉湾", + "Bulk Fabricator": "巨型构筑者", + "MARAUDER": "劫掠者", + "UNGU": "紫都", + "ACHERNAR SECUNDUS": "水委一次星", + "SHOTGUN SUMMIT": "霰弹枪峰", + "Ship TV": "舰船电视", + "Quinto": "昆托", + "BEEFBURG": "比夫堡", + "LOGISTICS HUB 188-B": "物流中心188-B", + "CLASA": "克拉萨", + "DOLPH": "多尔夫", + "ZONE 3": "3区", + "GROWL": "咆哮市", + "PA System": "广播系统", + "J. Bender": "J.本德", + "SIEGE BREAKERS": "破围先锋", + "WAYWARD": "逸泊", + "Malmborg": "马尔姆堡", + "Queen": "女王", + "of Freedom": "自由", + "MEKBUDA": "井宿七", + "ENHET FABRIK": "一体成型厂", + "GUNSHIP": "炮舰", + "TARSH": "塔尔什", + "SPORE CHARGER": "孢子强袭虫", + "PRASA": "普拉萨", + "Redondo": "雷东多", + "INCONSPICUOUS BLACK VEHICLE PATTERN": "低调黑载具涂装", + "PENNYBRIDGE": "彭尼布里奇", + "of Equality": "公正", + "Outcast Slashers": "狂刃光弃者", + "NEW STOROUSE": "新储仓", + "WATCHDOG 5": "守犬5", + "Advertisement": "广告播报员", + "Nummi": "努米", + "Guardian": "拯护者", + "POLARIS PRIME": "北极星主星", + "IRO": "伊罗", + "BUNDA SECUNDUS": "天垒城一次星", + "Estlind": "埃斯特林德", + "UTOPIA VAREN": "瓦伦乌托邦", + "Bile Spewer": "胆汁喷涌虫", + "ASPEN HILLS": "阿斯彭山", + "MOBILE WHITE SHUTTLE PATTERN": "移动白色运输船涂装", + "KEPLER-397b": "开普勒397b", + "STEN SECTOR": "斯坦分区", + "Andersson": "安德松", + "NYA SKELLEFTEA": "新谢莱夫特奥", + "OLUFSEN'S FOOTPRINT": "奥卢夫森足迹", + "ELYSIAN MEADOWS": "埃律西昂草原", + "GOTHENBURG III": "哥德堡III", + "MALMBERGET": "马尔姆贝吉特", + "RICTUS SECTOR": "瑞克图斯分区", + "VALMOX": "瓦尔莫克斯", + "Mandilas": "曼迪拉斯", + "Bolin": "博林", + "AVILA": "阿维拉", + "ALTUS SECTOR": "阿尔特斯分区", + "Vox Engines": "噪轰引擎", + "Representative": "代表", + "KESUMA": "花都", + "HUMAN WILL": "人类意志市", + "NEW ASPIRATION CITY": "志向新城", + "PROSPERITY": "繁荣市", + "UNMAPPED SYSTEM": "未测绘星系", + "HELLMIRE": "海尔迈尔", + "HYDROBIUS": "哈卓毕亚斯", + "TERREK": "泰雷克", + "Super Earth": "超级地球", + "Spore Burst Hunters": "孢裂追猎虫", + "YELLOW JACKET SHUTTLE PATTERN": "黄色被甲弹运输船涂装", + "WRAITH": "幽灵", + "SKAASH": "斯卡什", + "LEVIATHAN": "利维坦", + "POUNCER": "猛扑虫", + "Hulk": "巨型者", + "Shrieker": "尖啸虫", + "UNANIMITY": "统一市", + "Gauntlet": "钢铁手", + "BRILLIANCE": "璨光", + "PHACT BAY": "丈人一湾", + "MOBILE WHITE VEHICLE PATTERN": "移动白色载具涂装", + "Banner": "旗帜", + "Polar Patriots": "极地爱国者", + "ILLUMINATE": "光能者", + "FORT BOUNTY": "邦蒂堡", + "SPHERION": "斯飞利昂", + "MEISSA": "觜宿一", + "OLD BRANCH": "旧枝城", + "of Allegiance": "忠诚", + "UNDERGROWTH HELLPOD PATTERN": "灌木绝地喷射舱涂装", + "TECHNOLOCKIA ALLATEED": "科锁洛基亚-阿拉提德", + "The Crusher is the Illuminate’s most depraved advancement to date in the horrific process of mind control and manipulation. They are brute enforcers of the Illuminate agenda, whatever human matter that remains is long gone.": "粉碎者是光能者通过可怕的精神控制和操纵所创造出的终极堕落产物。粉碎者是推进光能者阴谋诡计的残暴爪牙,体内残存的人类痕迹早已荡然无存。", + "ANDWELL": "安得卫", + "EAST EMBANKMENT": "东堤", + "VOLTERRA": "沃尔泰拉", + "Automaton Mortar Emplacements": "机器人的迫击炮台", + "XI TAURI SECTOR": "金牛座分区", + "GELLERT SECTOR": "盖勒特分区", + "ADHARA": "弧矢七", + "of Conviviality": "友善", + "Yu Villa": "优·维拉", + "Hulk Scorchers": "巨型炙炎者", + "EXTRASOLAR ASH SHUTTLE PATTERN": "系外星尘运输船涂装", + "MYRADESH": "米拉戴什", + "WORTHY I": "英杰I", + "Helldrivers": "绝地司机", + "ALTA V": "奥尔塔V", + "Pride": "之傲", + "BLISTICA": "布里斯提卡", + "COZY FLATS": "馨寓", + "Flame": "之火", + "KALASATAMA PORT": "卡拉萨塔马港", + "De Giorgis": "德乔治", + "Watcher": "守望者", + "DARKWELL": "暗井", + "Comptroller": "督察者", + "AIDESVILLE": "哈得斯维尔", + "Bolle": "博莱", + "Pouncer": "猛扑虫", + "Progenitor": "始祖", + "MASTIA": "玛斯蒂亚", + "Leviathan": "利维坦", + "KARLIA": "可利亚", + "FORI PRIME": "佛里主星", + "ARLIA": "阿利亚", + "Moore": "摩尔", + "AUTOMATON": "机器人", + "PROMINENCE": "峥嵘城", + "REBELSGRAVE": "叛军墓", + "HAWKING SECTOR": "霍金分区", + "ENTRENCHED DIVISION": "堑壕之师", + "ESCAPADE": "越矩市", + "Spore Chargers": "孢子强袭虫", + "WEST MANAGEMENT": "西治市", + "ADAM PARK": "亚当帕克", + "CHATOYANT": "幻彩城", + "Helldiver Dummy": "绝地潜兵假人", + "SKITTER": "斯基特", + "Rupture Warrior": "爆裂武斗虫", + "ZEFIA": "赛飞亚", + "NANOS SECTOR": "纳诺斯分区", + "FOUNDRY": "铸造城", + "GRAFSART": "爵心市", + "SES": "SES", + "PROBABILITY": "天机", + "BRIGHT WING": "明翼市", + "Jansson": "扬松", + "of Mercy": "仁慈", + "OASIS": "绿洲", + "MEAN GREEN SHUTTLE PATTERN": "凶猛绿运输船涂装", + "SLAYER CITY": "弑亚城", + "One of 3 Maximum Security Cities. Impregnable to Tyranny; the future of the Federation.": "三大最高安全级别城市之一。暴政无法攻破之城,联邦的未来。", + "OLD DOVE": "老鸽城", + "BARNARD SECTOR": "巴纳德分区", + "Spore Lung": "孢肺", + "of Super Earth": "超级地球", + "ZEGEMA PARADISE": "泽格马乐土", + "RADICAL": "激进先锋", + "PHERKAD SECUNDUS": "北极一次星", + "RINKTOWN": "冰场镇", + "INFESTED TOWER": "侵染塔巢", + "VINDEMITARIX PRIME": "文德米塔里克斯主星", + "CHAMELEON CAMO SHUTTLE PATTERN": "变色龙迷彩运输船涂装", + "UNINHABITABLE SYSTEM": "不宜居星系", + "ELEVATED OVERSEER": "崇高监视者", + "URSA SECTOR": "大熊座分区", + "A product of the Illuminate’s so-called intellectual superiority and experimentation, the Wretch is a vile fusion of once human biomatter and hateful propaganda. These pathetic puppets envy the democratic rights of Super Earth citizens and seek to cut down those still loyal to Liberty.": "作为光能者所谓高等智慧与试验测试的产物,悲怜体是一种由昔日人类生物物质与仇恨洗脑的宣传融合而成的邪恶造物。这些可怜的傀儡嫉妒超级地球公民所享有的民主权利,妄图残害仍坚守解放大业的志士。", + "SCARLET HAVEN": "绯红湾", + "REDFIELD": "雷德菲尔德", + "UVP DELTA": "UVP德尔塔", + "FABRICATOR": "构筑者", + "EMERIA": "埃梅里亚", + "EAGLECRY": "鹰啸市", + "Crescent Overseers": "新月监视者", + "ANDROMEDA SECTOR": "仙女座分区", + "Impaler": "穿刺虫", + "POLLUX 31": "北河三31", + "SAORSA GLEN": "萨奥萨谷", + "SHALLUS": "沙勒斯", + "RD-4": "RD4", + "Charger Behemoth": "巨兽级强袭虫", + "Diamond": "之钻", + "Carlberg": "卡尔贝格", + "Harvesters": "猎杀器", + "PEOPLE'S HAND": "民手市", + "PIPIONEM": "雏鸣", + "Aegis": "神盾", + "PERSISTENCE": "坚韧市", + "QUASAR": "魁霎", + "DEMOCRACY ALWAYS": "恒民城", + "MASTERS OF CEREMONY": "典礼官", + "CASTELLAN'S CREED": "卡斯特兰信条", + "HORT": "哈尔特", + "STEEL RESOLVE": "钢铁意志城", + "Hodges": "霍奇斯", + "L'ESTRADE SECTOR": "莱斯特拉德分区", + "Pyro Troopers": "炙焰装甲兵", + "CHAIRMAN OKOTE": "主席奥科特", + "of Wrath": "盛怒", + "Gunships": "炮舰", + "NEW ALEXANDRIA": "新亚历山大城", + "SKAT BAY": "斯卡特湾", + "DARIUS II": "大流士II", + "DRYWELL": "干井市", + "The flagship Maximum Security City. Impregnable to Tyranny; the future of the Federation.": "最高安全级别城市中的王牌。暴政无法攻破之城,联邦的未来。", + "Stingrays": "刺魟", + "UNDERGROWTH SHUTTLE PATTERN": "灌木运输船涂装", + "NEW HOPE CITY": "希望新城", + "DIASPORA X": "大流散X", + "Terminids": "终结族", + "Factory Strider": "移动工厂", + "Prowlers": "潜掠虫", + "REDTHORN": "赤棘", + "DENEB SECUNDUS": "天津四次星", + "ERIDANI": "波江座", + "GREATER ATLANTEAN POWER PLANT": "大亚特兰蒂斯电厂", + "TRIGON SECTOR": "特里贡分区", + "INCONSPICUOUS BLACK HELLPOD PATTERN": "低调黑绝地喷射舱涂装", + "Berserkers": "狂暴者", + "Monuments in this Megafactory twist history to valorize the supposed resolve of Cyborgs to \"endure\" Super Earth's benevolent attempts to rehabilitate them. \n\nAnti-air defenses will hinder Eagle operations.": "这座超大型工厂的纪念碑扭曲历史,颂扬生化人所谓“忍受”超级地球仁慈改造计划的决心。\n\n防空系统将妨碍“飞鹰”的行动。", + "FORT UNION": "联合堡", + "Ship Master #NAME": "#NAME舰长", + "Overseers": "监视者", + "VITAL SYSTEM": "关键星系", + "LOOKOUT": "眺望台", + "BRAVERY": "勇城", + "Force of Law": "法律铁腕", + "Precursor": "先锋", + "PAYONG": "庇永", + "Spore Burst Hunter": "孢裂追猎虫", + "EFFLUVIA": "艾芙鲁维亚", + "EAGLESTAR ETERNAL": "鹰星恒市", + "CHOEPESSA IV": "科埃佩萨IV", + "Yousefi": "优塞菲", + "FREECREST": "自由峰", + "ALARAPH": "右执法", + "ABUNDANCE": "丰饶市", + "Annihilator Tanks": "湮灭坦克", + "JULHEIM": "尤尔海姆", + "Botelho": "博特略", + "Incendiary MG Devastators": "燃烧机枪蹂躏者", + "PRIMORDIA": "普莱默迪亚", + "CHURNED EARTH SHUTTLE PATTERN": "焦土运输船涂装", + "ACAMAR IV": "天园六IV", + "HABITAT RED-2": "栖地红-2", + "FORT JUSTICE": "正义堡", + "VANDALON IV": "万达隆IV", + "Troopers": "装甲兵", + "RESOLVE": "决心市", + "KODIAK FALLS": "科迪亚克瀑布", + "COMMISSAR": "机械统帅", + "BROOD WARDEN": "虫族守卫", + "Service Technician": "维修技术员", + "MEAN GREEN HELLPOD PATTERN": "凶猛绿绝地喷射舱涂装", + "TOIL": "劳作市", + "GILE": "吉尔", + "Arbiter": "仲裁", + "ALSTRAD SECTOR": "阿尔斯特拉德分区", + "LASTOFE": "赖斯斗夫", + "Charger": "强袭虫", + "Exo Experts": "外骨骼装甲专家", + "Servants of Freedom": "自由公仆", + "PILOT'S BERTH": "星驭港", + "Harbinger": "之兆", + "KEID": "九州殊口增七", + "OVERGOE PRIME": "欧维果主星", + "Fist": "之拳", + "NEW HEARTH CITY": "新寒炉市", + "GENE": "基因市", + "Stalkers": "追踪虫", + "YELLOW JACKET EXOSUIT PATTERN": "黄色被甲弹外骨骼装甲涂装", + "EASTCLEFT": "东裂谷", + "SEAF Soldier": "超级地球武装部队战士", + "MIRAGE": "幻境城", + "Agent": "桥梁", + "AIN-5": "毕宿一5", + "TRUE BLUE HELLPOD PATTERN": "忠诚蓝绝地喷射舱涂装", + "EAGLE'S LIKENESS": "鹰姿市", + "OLD CONUNDRUM": "旧谜市", + "KORPUS SECTOR": "科普斯分区", + "BORGUS SECTOR": "博格斯分区", + "VOX ENGINE": "噪轰引擎", + "Agitator": "惑乱者", + "FREE APARTMENTS": "自由公寓", + "of Audacity": "勇猛", + "PILEN V": "皮伦V", + "Dragonroach": "蟑龙", + "NABATEA SECUNDUS": "那贝塔次星", + "HOPESHIRE": "霍普郡", + "Leviathans": "利维坦", + "Brostrom": "布洛斯特伦", + "HUNTER'S BLUFF": "猎人崖", + "EDWARD'S GRAVE": "爱德华之墓", + "Harvester": "猎杀器", + "NEW STOCKHOLM": "新斯德哥尔摩", + "Blade": "之刃", + "QUELLED DISSENT": "戡异市", + "DYER STREETS": "染工街", + "DIGITI": "迪吉趾", + "FACTORY STRIDER": "移动工厂", + "Blood": "布拉德", + "KEPLER-391b": "开普勒391b", + "Brezavscek": "布雷扎夫谢克", + "NEW NEWTONVILLE": "新牛顿维尔", + "Jaeger": "耶格", + "Nursing Spewers": "抚育喷涌虫", + "CALYPSO": "卡利普索", + "Command Bunkers": "指挥碉堡", + "Zamora": "萨莫拉", + "REAF": "利夫", + "AUTOMATONS": "机器人", + "BOREA": "博瑞亚", + "ROCKET TANK": "火箭坦克", + "Friend": "弗兰德", + "Brood Warden": "虫族守卫", + "HOLL": "霍凉地", + "NAVI VII": "阁道二", + "NEW WISDOM": "新慧", + "Assault Raider": "特攻奇袭者", + "ZZANIAH PRIME": "藏尼亚主星", + "Steward": "管理者", + "Rocket Tank": "火箭坦克", + "SOCORRO III": "索科罗III", + "DEMOCRACY'S LANDING": "民主浅滩", + "Superintendent": "至尊", + "Frandsen": "弗兰德森", + "MAGNITUDE": "巨量市", + "BULK FABRICATOR": "巨型构筑者", + "ACRUX IX": "十字架二IX", + "BORDERLINE JUSTICE": "临界正义", + "WAR STRIDER": "战争纵步者", + "NUOVA ROMA": "新罗马", + "Impalers": "穿刺虫", + "Assault Raiders": "特攻奇袭者", + "Soldier": "战士", + "HOMESTEAD HILL": "家园山", + "Eriksson": "埃里克松", + "Wings": "之翼", + "MAJOSYRI": "马约叙里", + "NEW INSIGHT": "新悟", + "Siege Breakers": "破围先锋", + "MEAN GREEN EXOSUIT PATTERN": "凶猛绿外骨骼装甲涂装", + "AUTOMATON MORTAR EMPLACEMENT": "机器人的迫击炮台", + "IMPALER": "穿刺虫", + "CONCRETE JUNGLE SHUTTLE PATTERN": "混凝土丛林运输船涂装", + "BILE SPITTER": "胆汁吐沫虫", + "SERVANTS OF FREEDOM": "自由公仆", + "KEPLER-396b": "开普勒396b", + "REDACTED REGIMENT": "绝密军团", + "Raiders": "奇袭者", + "Chandler": "钱德勒", + "of Truth": "真理", + "HEZE BAY": "角宿二湾", + "ALATHFAR XI": "织女增三XI", + "of Courage": "刚毅", + "RESILIENCE": "韧城", + "BUG HOLE": "虫穴", + "Since sheltering millions of loyal refugees in the Last Great War, Port Mercy has been a safe haven for any class-A citizen in need.": "自终极大战中庇护数百万忠诚难民起,仁慈港便成为所有A级公民危难时的安全港湾。", + "KLAKA 5": "克拉卡5", + "RIGEL SECTOR": "参宿七分区", + "Hulk Obliterator": "巨型抹煞者", + "Skogsberg": "斯科格斯贝格", + "of Liberty": "解放", + "GRAFSWALLIT": "爵囊市", + "Force": "之势", + "KRAZ": "轸宿四", + "KNETH PORT": "克奈斯港", + "HERITAGE OLIVE VEHICLE PATTERN": "经典橄榄绿载具涂装", + "OUTCAST TRACKER": "循踪光弃者", + "HESOE PRIME": "海索主星", + "MÖNSTERÅS II": "门斯特罗斯II", + "VALGAARD": "瓦尔加德", + "HAKA": "哈卡", + "Home to the Democratic Council, our proud Capital is a beacon of Progress, Productivity, and Patriotism.": "我们引以为傲的首都既是民主委员会的所在地,也是进步、生产力和爱国主义的璀璨灯塔。", + "Soul": "灵魂", + "HOT GATES": "炙关", + "BASE CAMP 8": "8号基地", + "MUNITION CITY": "军工城", + "THE VOID": "寂域", + "SWAMP IV": "沼泽IV", + "BLESTRAIL": "圣途市", + "JET BRIGADE COMMISSAR": "喷气旅机械统帅", + "RATTLESNAKE VEHICLE PATTERN": "响尾蛇载具涂装", + "HOPEFUL": "希望", + "of Victory": "胜利", + "XZAR SECTOR": "兹亚尔分区", + "Sundstrom": "森德斯特伦", + "EAGLEMOUNT": "鹰山", + "PROSPERITY FALLS": "繁荣瀑布", + "SAMEN-STARK": "萨门-斯塔克", + "VEIL": "帷幕", + "NEW ABERDEEN": "新阿伯丁", + "Devastator": "蹂躏者", + "URSICA XI": "厄西卡XI", + "Dawn": "黎明", + "GRAVITAS": "庄严市", + "REGNUS": "雷格努斯", + "BASQUINE VIII": "巴斯金VIII", + "VERVE": "精力市", + "SYCAMORE GARDENS": "梧桐苑", + "HAERSTVIK": "哈尔斯特维克", + "Gazer": "凝视者", + "OMICRON": "奥密克戎", + "MORGON SECTOR": "莫根分区", + "Prophet Illusionists": "先知幻光大师", + "RAIDER": "奇袭者", + "Shredder Tanks": "碎裂坦克", + "ORBSHAM": "球珀沙姆", + "Extraction Shuttle": "撤离运输船", + "HYDRA SECTOR": "长蛇座分区", + "Hart": "哈特", + "FORTITUDE": "毅城", + "CHAMELEON CAMO EXOSUIT PATTERN": "变色龙迷彩外骨骼装甲涂装", + "TRUTH ENFORCERS": "真理执行者", + "GRAFMERE": "格拉夫米尔", + "SHETE": "赛特", + "K": "K", + "SERVITUDE": "奴役市", + "WARRIOR": "武斗虫", + "THE BUG QUARANTINE": "防虫", + "WASTEMOUNT": "韦斯特蒙特", + "LEO SECTOR": "狮子座分区", + "FREEDOM'S TORCH": "自由火炬城", + "PROPHET ILLUSIONIST": "先知幻光大师", + "REMEMBRANCE": "缅城", + "TRUE BLUE SHUTTLE PATTERN": "忠诚蓝运输船涂装", + "Nilsson": "尼尔松", + "FORNSKOGUR II": "福恩斯科古尔II", + "THE WEIR": "维尔", + "COUNCILLOR RORA": "议员罗拉", + "OSUPSAM": "欧苏普森", + "of Starlight": "星光", + "SILO A": "A舱", + "ANOMALOUS SYSTEM": "异常星系", + "Beroshi": "贝洛西", + "ASSAULT RAIDER": "特攻奇袭者", + "OUTCAST SLASHER": "狂刃光弃者", + "Hammer": "之锤", + "ISEGORIA": "思言城", + "Infested Towers": "侵染塔巢", + "Hulk Scorcher": "巨型炙炎者", + "of the State": "国家", + "Cannon Turrets": "加农炮台", + "CONFLAGRATION DEVASTATOR": "烈火蹂躏者", + "Pilot": "驾驶员", + "YMIR SECTOR": "土卫十九分区", + "TANIS SECTOR": "塔尼斯分区", + "MOMO-1": "莫莫-1", + "EAGLEOPOLIS": "鹰都", + "BIG ROCK": "巨岩", + "Eagle Fighter": "“飞鹰”驾驶员", + "Bile Warriors": "吐酸武斗虫", + "TRANDOR": "特兰道尔", + "Roughly translates to \"All Humans Must Die.\" One of the largest Megafactories on Cyberstan. A critical military production node. Defended by the Jet Brigade.": "大意为“全人类必须死”。生化斯坦最大的超大型工厂之一。关键军事生产节点。由喷气旅驻守。", + "NIBIRU": "尼比鲁", + "Vanderheide": "范德海德", + "VOTING DISTRICT F-012357": "F-012357选区", + "MENKENT": "库楼三", + "EAST IRIDIUM TRADING BAY": "东铱贸易湾", + "Python Commandos": "蟒蛇突击兵", + "Jet Brigade Commissars": "喷气旅机械统帅", + "VAULT CITY": "金库市", + "of Fortitude": "坚韧", + "SAPPORO": "札幌", + "HANZO SECTOR": "半藏分区", + "KRAKATWO": "克拉克图", + "SHED": "囤仓", + "Helldiver Recruit": "绝地潜兵新兵", + "Service Technician #NAME": "#NAME维修技术员", + "of Conviction": "坚定", + "of Honor": "尊荣", + "EAST REST": "东栖市", + "Super Earth PSA": "超级地球PSA", + "of Independence": "独立", + "Gatekeeper": "御门者", + "Reinforced Scout Strider": "强化侦察纵步者", + "CHAMELEON CAMO VEHICLE PATTERN": "变色龙迷彩载具涂装", + "Democracy Officer #NAME": "#NAME民主官", + "KEPLER-389b": "开普勒389b", + "STANDARD VEHICLE PATTERN": "标准载具涂装", + "Commissars": "机械统帅", + "Overseer": "监视者", + "CHARON PRIME": "卡戎主星", + "Wesolowski": "韦索洛夫斯基", + "IRIDICA": "艾丽迪卡", + "FEARLESS HOLLOW": "无畏谷", + "VELD": "维尔德", + "MARSPIRA SECTOR": "马斯皮拉分区", + "EXTRASOLAR ASH EXOSUIT PATTERN": "系外星尘外骨骼装甲涂装", + "The first and most well-defended Megafactory. The nexus of Cyborg command. Its destruction will trigger the collapse of the enemy's defenses on Cyberstan. Expect extreme resistance.": "最早建成、防御最坚固的超大型工厂。生化人的指挥中枢。摧毁此目标将导致敌军在生化斯坦的防线全面崩溃。预计将遭遇极端抵抗。", + "THESEUS SECTOR": "忒修斯分区", + "INCONSPICUOUS BLACK SHUTTLE PATTERN": "低调黑运输船舱涂装", + "XIN FUZHOU": "新福州", + "ACRAB XI": "房宿四XI", + "ANDAR": "安达尔", + "VERACITOR": "证真者", + "MERIDIAN IIa": "默里迪恩IIa", + "CHAIRMAN OYESLLO": "主席奥耶斯洛", + "Wiklund": "维克隆德", + "Gunship": "炮舰", + "Lindstrom": "林德斯特伦", + "Spore Charger": "孢子强袭虫", + "SETTLER'S HONOR": "开拓者荣誉市", + "AFOYAY BAY": "艾福亚湾", + "of Science": "科学", + "DIPLOMACY": "纵横市", + "MORDIA 9": "摩帝亚9", + "LOGISTICAE": "后勤", + "Shriekers": "尖啸虫", + "AGITATOR": "惑乱者", + "BIRTH": "圣生市", + "Brawler": "乱斗者", + "Protector": "护卫", + "RATTLESNAKE HELLPOD PATTERN": "响尾蛇绝地喷射舱涂装", + "CYGNIA III": "西格尼亚III", + "Raider": "奇袭者", + "This Great Heart of Commerce is renowned galaxy-wide for its Grand Shopping Malls and Splendorous Entertainment Centers.": "这座伟大商贸中枢因宏伟的购物商场和繁华的娱乐中心而闻名整个银河系。", + "MARTALE": "玛尔特", + "Citizen": "公民", + "ASPEROTH PRIME": "阿斯佩洛斯主星", + "MANTES": "蒙特斯", + "FORCE OF LAW": "法律铁腕", + "ACHIRD III": "王良三III", + "PESTIS": "瘟厉", + "YATAKHANE 263": "宿舍263", + "SPOYLE": "斯珀伊尔", + "Lindgren": "林德格伦", + "TARRAGON SECTOR": "塔拉戈分区", + "Linddqvist": "林德奎斯特", + "LIFESWORTH": "生之意", + "LYNX LYNX": "猞猁", + "CRUCIBLE": "熔炉", + "Jet Brigade Trooper": "喷气旅装甲兵", + "CURSA": "玉井三", + "Hulk Firebomber": "巨型烈焰轰炸者", + "REQUIEM": "安魂城", + "VICTORY": "胜利市", + "Vicente": "维桑特", + "Sjostrom": "舍斯特伦", + "Rocket Tanks": "火箭坦克", + "Democratic Detonation": "民主爆破", + "MASKIN": "玛斯金", + "ARGENTIS": "银辉", + "KILLJOY TOWN": "克乔伊镇", + "Giant": "巨人", + "HULK FIREBOMBER": "巨型烈焰轰炸者", + "PENSCEWT": "彭妮萌", + "VINGE": "云翼", + "CONLON COLONY": "康伦拓殖地", + "Prowler": "潜掠虫", + "FARMHANDSTOWN": "农工镇", + "Wolterbeek Muller": "沃尔特贝克·穆勒", + "Fyrvall": "菲尔瓦尔", + "Spore Burst Warrior": "孢裂武斗虫", + "Wretch": "悲怜体", + "SAGAN SECTOR": "萨根分区", + "ROCKET DEVASTATOR": "火箭蹂躏者", + "of Midnight": "午夜", + "Power": "之力", + "SPORE BURST SCAVENGER": "孢裂食腐虫", + "BALDRICK PRIME": "巴尔德里克主星", + "Prince": "王子", + "MARRE IV": "马尔IV", + "PARRHESIA": "直言城", + "BERSERKER": "狂暴者", + "ZAGON PRIME": "扎贡主星", + "of Integrity": "诚实", + "TIMELY": "甘霖城", + "Founding Father": "缔造者", + "of Judgment": "判决", + "SHELTER": "谢尔特", + "Durney": "德尼", + "GUNNAR": "刚纳尔", + "Transport Shuttle": "运输船", + "Magus Acolytes": "奇能侍僧", + "WILFORD STATION": "威尔福德站", + "YELLOW JACKET HELLPOD PATTERN": "黄色被甲弹绝地喷射舱涂装", + "MALEVELON CREEK": "麦拉芬蒙河", + "UNDERVATTEN": "水下城", + "Scavengers": "食腐虫", + "REINFORCED SCOUT STRIDER": "强化侦察纵步者", + "SIRIUS": "天狼星", + "GARAGE DUNE": "车库沙丘", + "MONHEIM": "蒙海姆", + "OVERSHIP": "统御舰", + "TROOST": "特鲁斯特", + "MAIA": "昴宿四", + "WORKSONG": "劳歌市", + "NURSING SPEWER": "抚育喷涌虫", + "ANTBOOT": "踏虫市", + "PROGRESS": "进步市", + "MUSTARD VEHICLE PATTERN": "芥末黄载具涂装", + "WRETCH": "悲怜体", + "Herald": "使者", + "EXTRASOLAR ASH HELLPOD PATTERN": "系外星尘绝地喷射舱涂装", + "MERGA IV": "玄戈增二IV", + "Claw": "之爪", + "YORK SUPREME": "棒约克", + "Hedstrom": "赫德斯特伦", + "Elggren": "埃尔格伦", + "Rupture Spewer": "爆裂喷涌虫", + "CONCRETE JUNGLE HELLPOD PATTERN": "混凝土丛林绝地喷射舱涂装", + "ABUNDANCE BLUFF": "丰绝崖", + "of Glory": "荣耀", + "MT MONUMENT": "纪念碑山", + "Person": "个人", + "of Redemption": "救赎", + "Octagon": "之八方", + "Spore Lungs": "孢肺", + "RUPTURE SPEWER": "爆裂喷涌虫", + "SHADY OAKS": "荫橡", + "Scout Raider": "侦查奇袭者", + "DUNOONIA": "顿诺尼亚", + "BARABOS": "巴勒博斯", + "Eye": "之眼", + "PROPUS": "五诸侯三", + "of Family Values": "情义", + "GIRD": "戈尔德", + "FORT SANGUINE": "血色堡", + "ZYGOS": "齐戈斯", + "MUSTARD EXOSUIT PATTERN": "芥末黄外骨骼装甲涂装", + "YELLOW JACKET VEHICLE PATTERN": "黄色被甲弹载具涂装", + "Ship Master": "舰长", + "of the People": "民众", + "Rocket Devastator": "火箭蹂躏者", + "CHOOHE": "丘伊", + "Hulks": "巨型者", + "GIRI": "义理城", + "EPSILON PHOENCIS VI": "艾普斯林芬赛斯VI", + "BARRACKSBURG": "兵营堡", + "Stalker": "追踪虫", + "MORT": "莫特", + "CASTELLAN GREEN SHUTTLE PATTERN": "卡斯特兰绿运输船涂装", + "USTOTU": "伍斯特图", + "SAFETY ORANGE VEHICLE PATTERN": "安全橘载具涂装", + "STINGRAY": "刺魟", + "Hellbot": "绝地机械兵", + "SEYSHEL BEACH": "塞舌尔海滩", + "ILDUNA PRIME": "伊尔都纳主星", + "Spore Burst Warriors": "孢裂武斗虫", + "HERITAGE OLIVE HELLPOD PATTERN": "经典橄榄绿绝地喷射舱涂装", + "CASTELLAN GREEN EXOSUIT PATTERN": "卡斯特兰绿外骨骼装甲涂装", + "CAPH": "王良一", + "NASCENCE": "太初", + "MOGO PLAINS": "莫戈平原", + "SEQUIM": "猎城", + "of Gold": "黄金", + "SONGGUO CUN": "松果村", + "Bunker Turrets": "碉堡炮台", + "IGLA": "伊格勒", + "Paragon": "模范", + "Gatekeepers": "御门者", + "Devastators": "蹂躏者", + "GOTHMAR SECTOR": "戈特玛分区", + "STOR THA PRIME": "斯特萨主星", + "PEDIS": "佩迪趾", + "Marauder": "劫掠者", + "GALLUX SECTOR": "加卢克斯分区", + "SHRIEKER": "尖啸虫", + "EUPHORIA III": "欧福利亚III", + "Wretches": "悲怜体", + "LACED STRAIT": "莱醒海峡", + "Kravchenko": "克拉夫琴科", + "Chemical Agents": "化学专家", + "Billnert": "比尔纳特", + "EVERWHITE": "恒白", + "Hunters": "追猎虫", + "Rupture Warriors": "爆裂武斗虫", + "Automaton": "机器人", + "Bellawala": "贝拉瓦拉", + "MIQÉ": "米基", + "OMA PEMMA": "欧玛佩玛", + "BRAWFERMLAND": "布劳费尔兰", + "of Individual Merit": "独贤", + "SCAVENGER": "食腐虫", + "Star": "之星", + "OSTEHOVEL": "酪撕特霍维", + "HERITAGE OLIVE SHUTTLE PATTERN": "经典橄榄绿运输船涂装", + "FRONTERIA": "边陲", + "Sword": "之剑", + "Bile Titan": "吐酸泰坦", + "ADVENTURE": "探险市", + "Risen from the ashes of an ancient city, Rememberance is a monument to the Perseverance of Humankind.": "自古城废墟中涅槃重生,缅城乃人类不屈精神的丰碑。", + "SALERIA SECTOR": "萨勒莉亚分区", + "Wirz": "维尔斯", + "Predator Hunters": "掠食追猎虫", + "SUPERIORITY": "优越市", + "FAMEWOLF PEAK": "盛狼峰", + "VIRIDIA PRIME": "维尔伊迪亚主星", + "VANQUISHMENT": "征服市", + "YDINKESKUSTA": "中心城", + "NEW EAGLE": "新鹰城", + "STAR KIELD": "星陨堡", + "Frezzato": "弗雷扎托", + "HILDOARA CENTRAL": "希尔多亚拉中区", + "LINK B": "链枢B", + "EXO CITY": "外骨骼市", + "TENDRA": "坦德拉", + "BALLOT": "民望", + "ERSON SANDS": "厄尔森桑兹", + "MIRIN SECTOR": "米琳分区", + "WEST BROKER": "西贸经纪区", + "Likely one of the earliest Megafactories to be constructed on Cyberstan. The most significant producer of Cyborg combatants. Defended by the Incineration Corps.": "这可能是生化斯坦最早建造的超大型工厂之一。生化人战斗单位的最主要生产地。由炽灼部队驻守。", + "Urban Legends": "都市传奇", + "Bile Spewers": "胆汁喷涌虫", + "Courier": "信使", + "MARTYR'S BAY": "烈士湾", + "Outcast Seeker": "逐觅光弃者", + "ESTANU": "伊斯塔努", + "RETRIBUTARY": "天谴", + "LACAILLE SECTOR": "拉凯欧分区", + "TRUE BLUE EXOSUIT PATTERN": "忠诚蓝外骨骼装甲涂装", + "GENERATION": "源代", + "ROCKET RAIDER": "火箭奇袭者", + "CAMP LEIGHTON": "莱顿营", + "PARTION": "帕尔晨", + "SPORE LUNG": "孢肺", + "Bernklint": "柏恩科林特", + "NEW TOKYO": "新东京", + "PINESWOLD": "派恩斯沃尔德", + "Civilian": "平民", + "of Perseverance": "不屈", + "BILE TITAN": "吐酸泰坦", + "LIFEBLOOD": "命脉城", + "Masters of Ceremony": "典礼官", + "HADAR": "马腹一", + "DEVASTATOR": "蹂躏者", + "Baneful Sentinel": "祸患光能哨兵", + "FUTURE PRIDE": "未来荣光市", + "DUST DEVILS": "尘卷风", + "Ghoul": "噬光者", + "E-710-RICH SYSTEM": "710元素富集星系", + "Princess": "公主", + "VACCA": "瓦卡", + "Automaton Mortar Emplacement": "机器人的迫击炮台", + "INDUSTRY ALLATEED": "阿拉提德工业", + "Hive Guards": "虫窝护卫", + "SIEMNOT": "席姆纳特", + "Custodian": "守护者", + "Spore Burst Scavengers": "孢裂食腐虫", + "LIBER-TEA TOWNSHIP": "解放茶镇", + "Jet Brigade Commissar": "喷气旅机械统帅", + "GEMSTONE BLUFFS": "宝石崖", + "HARDY": "强健市", + "ALIGNMENT": "同心市", + "of Destiny": "天命", + "DEECON": "圣侍", + "ARKTURUS": "阿克图勒斯", + "DOGTOWN": "多格镇", + "FURY": "费里", + "MOX": "莫克斯", + "PROBARE": "究理", + "TOPSOIL": "表土市", + "Lady": "圣女", + "CHURNED EARTH EXOSUIT PATTERN": "焦土外骨骼装甲涂装", + "PRAVOGRAD": "权右沃格勒", + "Prophet Illusionist": "先知幻光大师", + "Brood Wardens": "虫族守卫", + "HALIES PORT": "海利斯港", + "Young": "扬", + "NEW PENG": "新漂市", + "KEPLER-400b": "开普勒400b", + "Elevated Overseer": "崇高监视者", + "STEELED VETERANS": "铁血老兵", + "NIVEL 43": "尼维尔43", + "LAMB'S PATCH": "羔原", + "Marshal": "元帅", + "Pledge": "誓约", + "ARABILITY": "沃壤", + "Mission Control": "任务调度员", + "Elevated Overseers": "崇高监视者", + "RAYSTING": "雷斯汀", + "FUTURIA": "未来城", + "Hulk Bruisers": "巨型碾压者", + "GATRIA": "盖尔崔亚", + "Thomasson": "托马松", + "Rupture Chargers": "爆裂强袭虫", + "ALTONBURG": "奥尔顿堡", + "CIRRUS": "希勒斯", + "ATRAMA": "阿特拉玛", + "MARFARK": "玛尔法克", + "High Command has identified this Megafactory as one of two potential beachheads for the invasion of Cyberstan. Rapid insertion protocols will restrict deployment ammunition.": "最高指挥部已将这座超大型工厂认定为入侵生化斯坦的两个潜在滩头堡之一。快速突入协议将限制部署弹药。", + "MAGUS ACOLYTE": "奇能侍僧", + "Thompson": "汤普森", + "MALLSTRIP NODES": "商廊节点", + "Borderline Justice": "临界正义", + "Viper Commandos": "毒蛇突击兵", + "of Selfless Service": "无私", + "Voteless": "无票者", + "SEORAKSAN": "雪岳山", + "WALNUT ACRES": "胡桃木埃克斯", + "Jet Brigade Troopers": "喷气旅装甲兵", + "CURIA": "居里亚", + "STOUT": "斯图尔特", + "ROGUE 5": "罗格5", + "MEGACORPUS": "梅加科尔普斯", + "DRAGONROACH": "蟑龙", + "LUXURIANT": "富源", + "SATELLARIA": "卫环", + "URBAN LEGENDS": "都市传奇", + "Marcus": "马库斯", + "BICEP": "擎穹", + "Hive Lords": "霸王虫", + "Spore Burst Scavenger": "孢裂食腐虫", + "VIPER COMMANDOS": "毒蛇突击兵", + "ADNAN": "安拓市", + "GREATER STOROUSE": "大储仓", + "Pyro Trooper": "炙焰装甲兵", + "UNDERGROWTH VEHICLE PATTERN": "灌木载具涂装", + "LEMURIA RISING": "利莫里亚崛起城", + "CHARGER": "强袭虫", + "TERRENE": "类地", + "CARBONDALE": "卡本代尔", + "Baneful Sentinels": "祸患光能哨兵", + "HETT": "炎核", + "INARI": "伊纳里", + "OKUL VI": "欧库VI", + "Fleshmob": "肉瘤体", + "ON-EARSAHOU": "顿听呼", + "Gazers": "凝视者", + "Radicals": "激进先锋", + "REFORMED-BY-TRUTH": "真理改造市", + "QUENCH": "淬火市", + "X-45": "X45", + "SHIRAHAMA": "白滨", + "SENATOR PEAKS": "议员峰", + "KALASATAMA": "渔港", + "NEW YEARNING CITY": "盛盼新城", + "Triumph": "的胜利", + "Roughly translates to \"Destroy Freedom At All Costs.\" Significant conventional SEAF assaults will be required to support an offensive here, straining ammunition resources.": "大意为“不惜一切代价摧毁自由”。在此发动攻势需要超级地球武装部队进行大规模常规突击支援,弹药资源将十分紧张。", + "LIL'OME": "乐居城", + "HUNTER": "追猎虫", + "HANDAKAS": "汉达卡斯", + "ANNWN": "安温", + "Inagaki": "稻垣", + "OBSERVATORY 6": "监测站6", + "Bjorkman": "比约克曼", + "BANKABILITY": "金枢", + "DRACO SECTOR": "天龙座分区", + "KUPER": "库珀", + "UVP ALPHA": "UVP阿尔法", + "PROWLER": "潜掠虫", + "AUSPICE": "天启", + "NEW PARADISE": "新天堂", + "DEEPWELL": "深井", + "COMMAND BUNKER": "指挥碉堡", + "VEGA BAY": "织女一湾", + "STACY": "斯特西", + "Nitsan": "尼岑", + "GRAND ERRANT": "大艾伦特", + "FRESH ORCHARDS": "鲜果园", + "ZOSMA": "太微右垣五", + "OBEDIENT DEMOCRACY SUPPORT TROOPERS": "民主光环驰援部队", + "CHURNED EARTH VEHICLE PATTERN": "焦土载具涂装", + "ORION SECTOR": "猎户座分区", + "APPROVAL CITY": "准都", + "Lemaire": "勒迈尔", + "GENERATORSVILLE": "电机维尔", + "Reign": "支配", + "MOG": "莫格", + "ACCOUNTANT GRAEBER": "会计格雷伯", + "BATU BELIG": "巴图贝利格", + "HELLDIVERS MOBILIZE!": "绝地潜兵总动员!", + "NEW COB": "新科布", + "OTARU'S PLEDGE": "小樽诺城", + "EIGHTRINGS": "八环城", + "DIVER'S REST": "潜兵安息市", + "HEAVY DEVASTATOR": "重型蹂躏者", + "LENG SECUNDUS": "蓝恩次星", + "Barrager Tanks": "铁幕坦克", + "Predator Hunter": "掠食追猎虫", + "WALKAWAY": "逍遥道", + "CARAMOOR": "开勒莫尔", + "Zealots": "狂热战士", + "Veracitors": "证真者", + "RESPITE": "统息市", + "Outcast Slasher": "狂刃光弃者", + "HUSARIA": "轻骑", + "ENULIALE": "安努力亚", + "MORSKIE OKO": "海洋之眸", + "of Opportunity": "机遇", + "JURISPRUDENCE": "律裁城", + "MUSTARD HELLPOD PATTERN": "芥末黄绝地喷射舱涂装", + "BROOD COMMANDER": "虫族指挥官", + "SAFETY ORANGE EXOSUIT PATTERN": "安全橘外骨骼装甲涂装", + "Brettman": "布雷特曼", + "Factory Striders": "移动工厂", + "Brood Commander": "虫族指挥官", + "Chargers": "强袭虫", + "PYRO TROOPER": "炙焰装甲兵", + "LAGERLÖF CITY": "拉格洛夫城", + "CELEBRATION": "庆祝市", + "KIRRIK": "基里克", + "MERIDIA": "默里迪亚", + "NON-PARTISAN": "超党市", + "ÖDESHÖGRE": "厄德斯霍格雷", + "Hakalax": "哈卡拉克斯", + "CONCRETE JUNGLE VEHICLE PATTERN": "混凝土丛林载具涂装", + "Higham": "海厄姆", + "Rocket Raider": "火箭奇袭者", + "KRAKABOS": "克拉克博斯", + "CIVILITY": "礼序", + "TRAITOR'S END": "终叛城", + "THE ILLUMINATE": "光能者", + "OL' OLDHAM": "老奥尔德姆", + "of Eternity": "永恒", + "HULK OBLITERATOR": "巨型抹煞者", + "Cutting Edge": "遥遥领先", + "FROSTOWN": "霜镇", + "CHARBAL-VII": "查巴尔VII", + "PEONY": "牡丹", + "Mother": "之母", + "ALMINA IV": "阿尔米纳IV", + "Armstrong": "阿姆斯特朗", + "ERATA PRIME": "艾拉特主星", + "FENMIRE": "范迈尔", + "ESKER": "艾斯克尔", + "UNKNOWN SYSTEM": "未知星系", + "COMMUNEFALLS": "公社瀑布", + "Armelin": "阿默兰", + "HULK SCORCHER": "巨型炙炎者", + "RIRGA BAY": "里尔加湾", + "Hansson-Bjerke": "汉松-比耶克", + "ZENITH": "穹顶", + "Helldivers Mobilize!": "绝地潜兵总动员!", + "Lee": "李", + "Kimura": "木村", + "DOSTOINSTVO": "尊严市", + "Berserker": "狂暴者", + "NEW KATHMANDU": "新加德满都", + "MUSTARD SHUTTLE PATTERN": "芥末黄运输船涂装", + "Severien": "塞韦连", + "Shrieker Nests": "尖啸虫巢穴", + "Fleshmobs": "肉瘤体", + "XIRAN'S CLAIM": "希兰领地", + "PIONEER'S DREAM": "先驱梦城", + "LESATH": "尾宿八", + "ALAMAK VII": "天大将军一VII", + "OTUR": "厄图尔", + "UVP GAMMA": "UVP伽马", + "OLD CHEMLAND": "旧化工城", + "Whisper": "的低语", + "BASHYR": "巴希尔", + "of Peace": "和平", + "This Megafactory contains significant Automaton production facilities. Anti-orbital defenses will tax Super Destroyer resources, resulting in longer orbital cooldowns.": "这座超大型工厂拥有大量机器人生产设施。反轨道防御设施将消耗超级驱逐舰资源,导致轨道支援冷却时间延长。", + "PANDION-XXIV": "帕狄恩XXIV", + "HAVEN": "黑文", + "IRULTA": "艾鲁尔塔", + "DYN ALPHA 534-2": "沙丘阿尔法534-2", + "ELIGIBLE": "天契", + "SANGIS": "赤血", + "OVERSEER": "监视者", + "QUINTUS SECTOR": "昆图斯分区", + "FARSIGHT SECTOR": "法尔赛特分区", + "NUBLARIA I": "努布拉里亚I", + "SCOUT STRIDER": "侦察纵步者", + "HERTHON SECUNDUS": "赫尔松次星", + "XIAMEN ANEW": "尚厦门", + "URSOOT NINE": "乌尔苏特九号", + "ADHAFERA SECUNDUS": "轩辕十一次星", + "FLEDGE": "雏羽", + "SKAR'S GARDENS": "斯卡斯加登斯", + "Bug Hole": "虫穴", + "TRUE BLUE VEHICLE PATTERN": "忠诚蓝载具涂装", + "Dropships": "运输舰", + "CLAORELL": "可洛尔", + "CHEMICAL AGENTS": "化学专家", + "THE AUTOMATONS": "机器人", + "of the Stars": "星辰", + "LIGHT-OF-LIBERTY": "耀辉自由城", + "DISCOVERY GLEN": "探索谷", + "Obedient Democracy Support Troopers": "民主光环驰援部队", + "Corpeleijn": "科尔佩莱因", + "GYEONGSEONG": "京城", + "SPORE BURST HUNTER": "孢裂追猎虫", + "McGregor": "麦格雷戈", + "BRINK-2": "布林克2", + "BILE SPEWER": "胆汁喷涌虫", + "BILE WARRIOR": "吐酸武斗虫", + "STRONGFORT": "斯特朗福特", + "CORNUCOPOLIS": "富饶城", + "ANDROS GAMMA": "安德罗斯伽马", + "Hunter": "追猎虫", + "LONE": "独行者", + "CONCEALED SYSTEM": "隐蔽星系", + "TURING": "图灵", + "Bettmann": "贝特曼", + "SCUTUM CANIS LUPUS": "狼盾", + "KEPLER-393b": "开普勒393b", + "SAFETY ORANGE HELLPOD PATTERN": "安全橘绝地喷射舱涂装", + "Xenobite Ardent": "炽热异噬者", + "CANNON TURRET": "加农炮台", + "Bile Warrior": "吐酸武斗虫", + "LOKAHEIM": "洛卡海姆", + "Lord": "之主", + "BOPSFIELD": "波普斯菲尔德", + "PORT MERCY": "馨家泊", + "OSLO STATION": "奥斯陆站", + "OMEGA SECTOR": "欧米茄分区", + "CLE ELUM REDIVIVA": "克利勒姆复兴城", + "PÖPLI IX": "珀普利IX", + "Morgan": "摩根", + "WEZEN": "弧矢一", + "PORUGU": "毗卢固市", + "Jet Brigade MG Trooper": "喷气旅机枪装甲兵", + "FOUR CROWNS": "四冠市", + "FREE TRADE": "自贸区", + "MOBERG'S DREAM": "莫伯格之梦", + "Hulk Obliterators": "巨型抹煞者", + "Heathcote": "希思科特", + "Bringer": "引路人", + "BLIGHTSMURK": "瘟茨默克", + "DEBTOR'S DOWNS": "债丘", + "CANOPUS": "老人", + "CALEFACTORIA": "炽庭", + "Dragonroaches": "蟑龙", + "RIZIO'S VISION": "里齐奥愿景", + "RUPTURE WARRIOR": "爆裂武斗虫", + "Annihilator Tank": "湮灭坦克", + "VIBRANCY": "活力市", + "RAS ALGETHI": "帝座", + "of Humankind": "人类", + "SERENDIPITY XI": "天缘XI", + "VALDIS SECTOR": "瓦尔迪斯分区", + "BOHUS": "布胡斯", + "of Benevolence": "博爱", + "FENRIR III": "芬里尔III", + "BIRCHVILLE": "桦木维尔", + "of Self-Determination": "自主", + "SCHOLAR'S MOOR": "学者荒原", + "BELLATRIX": "参宿五", + "KNIGHT'S HONOR": "骑士荣誉城", + "ORESINK": "奥尔辛克", + "Shrieker Nest": "尖啸虫巢穴", + "Conflagration Devastator": "烈火蹂躏者", + "NOSSER": "诺瑟", + "SETIA": "赛提亚", + "ZEALOT": "狂热战士", + "Flowers": "弗劳尔斯", + "OBEDIENCE": "服从市", + "SUPERIORIA LV": "卓尊", + "BARREN WARD": "不毛沃德", + "MERAK": "北斗二", + "Bayrak": "巴伊拉克", + "IPTUS SECTOR": "伊普都斯分区", + "Olofsson": "奥洛夫松", + "DEMOCRATIC DETONATION": "民主爆破", + "GREATWOOD MILLS": "巨木米尔斯", + "AUTONOMY": "自固堡", + "DOWNPOUR": "暴雨城", + "SEVERIN SECTOR": "塞弗林分区", + "Rocket Raiders": "火箭奇袭者", + "PERSEVERANCE": "坚毅市", + "Winaldy": "维纳尔蒂", + "PREDATOR STALKER": "掠食追踪虫", + "of Dawn": "破晓", + "BARRAGER TANK": "铁幕坦克", + "OLD HEARTH CITY": "旧寒炉市", + "SIRIUS II": "天狼星II", + "SARAH SWIFT DAM": "莎拉斯威夫特大坝", + "Warp Ship": "穿梭舰", + "SEVENSEAL": "七印城", + "VERNEN WELLS": "佛农井", + "BEACHVIEW": "碧景湾", + "Pouncers": "猛扑虫", + "STANDARD TANK PATTERN": "标准坦克涂装", + "POLAR PATRIOTS": "极地爱国者", + "Brawlers": "乱斗者", + "KELVINOR": "开尔文奥尔", + "RASP": "拉斯普", + "SHRIEKER NEST": "尖啸虫巢穴", + "EXO EXPERTS": "外骨骼装甲专家", + "PO'S RAVENNA": "波氏拉文纳", + "Obtruder": "突入者", + "ALPHA COMMANDER": "阿尔法指挥官", + "TIBIT": "提比特", + "PERIWINKLE MILLS": "长春花磨城", + "KUMA": "天棓二", + "WATCHER": "守望者", + "DUMA TYR": "杜马提尔", + "SAMMELSURIUM": "喧沌", + "Shredder Tank": "碎裂坦克", + "Zealot": "狂热战士", + "Ayre": "艾尔", + "Burrows": "伯罗斯", + "of the Constitution": "宪法", + "ALADFAR CXI": "辇道二CXI", + "Conflagration Devastators": "烈火蹂躏者", + "Named for the historic conference where Humanity was found to be the most Equal species in the Galaxy.": "因历史性会议而得名,此会议将人类认定为银河系最平等的物种。", + "Khatib": "哈提卜", + "Nicholson": "尼科尔松", + "CELESTE SECTOR": "塞勒斯特分区", + "General Brasch": "布拉施将军", + "of Serenity": "宁静", + "ERSATZ": "厄萨茨", + "Legislator": "立规者", + "COLUMBIDAE": "和平鸽", + "of Patriotism": "丹心", + "GRAFSEAD": "爵首市", + "HALDUS": "海德斯", + "LOGISTICS HUB 232-B": "物流中心232-B", + "ELECTRA BAY": "昴宿一湾", + "YED PRIOR": "天市右垣九", + "OLD INTERNMENTS": "旧禁所", + "CLOCKSTOP": "钟停市", + "CHARA": "常陈四", + "Colossus": "巨匠", + "QZ-4": "疫区4", + "CERBERUS IIIc": "刻耳柏洛斯IIIc", + "AURORA BAY": "极光湾", + "King": "之王", + "Ryhre": "吕勒", + "KEPLER-394b": "开普勒394b", + "NEKK POND": "水妖池", + "Keeper": "看守人", + "GREATER INVESTMENT": "巨资市", + "NO COMPOUND": "无堡市", + "Nystrom": "奈斯特伦", + "PIEA": "皮耶阿", + "MINERAL'S END": "矿竭地", + "of Destruction": "毁灭", + "UVP BETA": "UVP贝塔", + "KEPLER-398b": "开普勒398b", + "SWAMP V": "沼泽V", + "HAKU CITY": "哈库城", + "Fritzell": "弗里策尔", + "EMBOLD": "无畏", + "GATEKEEPER": "御门者", + "OROTH": "欧拉斯", + "Judge": "审判", + "Kelder": "凯尔德", + "Marauders": "劫掠者", + "Veracitor": "证真者", + "Johansson": "约翰松", + "Sellerfors": "塞勒福什", + "of War": "战争", + "HIVE GUARD": "虫窝护卫", + "DRAUPNIR": "德罗普尼尔", + "Fabricator": "构筑者", + "CONCRETE JUNGLE EXOSUIT PATTERN": "混凝土丛林外骨骼装甲涂装", + "RUPTURE CHARGER": "爆裂强袭虫", + "Elected Representative": "选举代表", + "HEART FLATS": "心平市", + "EXCITEMENT": "激情市", + "Sector": "分区", + "Sturk": "斯图克", + "Jet Brigade Raider": "喷气旅奇袭者", + "PIT 8": "8号坑", + "TANDEM": "天腾", + "TECHOLOCKY": "锢技坊", + "Righteous Revenants": "正义复仇者", + "KEPLER-392b": "开普勒392b", + "Control Group": "变量控制", + "PREDATOR HUNTER": "掠食追猎虫", + "OBARI": "欧巴里", + "BRAWLER": "乱斗者", + "Panther": "之豹", + "Bug Holes": "虫穴", + "Crescent Overseer": "新月监视者", + "SWAMP VI": "沼泽VI", + "CANTOLUS SECTOR": "坎托鲁斯分区", + "FAMILY-FRIEND": "家宜", + "UNISON": "和谐市", + "UBANEA": "乌巴尼亚", + "JIN XI SECTOR": "锦栖分区", + "SCOUT RAIDER": "侦查奇袭者", + "CRESCENT OVERSEER": "新月监视者", + "Infested Tower": "侵染塔巢", + "BUJU": "布朱", + "Rupture Charger": "爆裂强袭虫", + "LINDOME": "林杜默", + "OMNIPARITUS": "全诛堡", + "IMBER": "因博尔", + "CASTELLAN GREEN HELLPOD PATTERN": "卡斯特兰绿喷射舱涂装", + "CASTOR": "北河二", + "of the Regime": "政权", + "Barrager Tank": "铁幕坦克", + "Bunker Turret": "碉堡炮台", + "Crusher": "粉碎者", + "Edstrom": "艾德斯特伦", + "Lasota": "拉索塔", + "Hive Lord": "霸王虫", + "TVENNE BOTTOMS": "双瓣谷", + "of Steel": "钢铁", + "DEMIURG": "戴米尔基", + "WASAT": "天樽二", + "AMITTERE": "亚米逝地", + "STANDARD HELLPOD PATTERN": "标准绝地喷射舱涂装", + "GAELLIVARE": "耶利瓦勒", + "HELLDRIVERS": "绝地司机", + "GACRUX": "十字架一", + "GRAPESHOT": "葡萄弹市", + "CRIMSICA": "克里姆西卡", + "PROVIDENCE": "普罗维登斯", + "EXALT": "颂扬市", + "Fraser": "弗雷泽", + "PEACOCK": "孔雀十一", + "Magus Acolyte": "奇能侍僧", + "TERMINIDS": "终结族", + "DEFENSIBLE": "卫戍", + "MINCHIR": "敏切尔", + "PENTA": "彭塔", + "CAMRAT FOR": "卡姆拉特堡", + "NEW DA NANG": "新岘港", + "OUTCAST SEEKER": "逐觅光弃者", + "PORTE LIBERTÉ": "自由门", + "UMLAUT SECTOR": "乌姆劳特分区", + "REGISTER": "登记市", + "PLETHORA": "普雷索拉市", + "WORKHOUSE 239-C": "救济所239-C", + "Redacted Regiment": "绝密军团", + "FLESHMOB": "肉瘤体", + "Heavy Devastators": "重型蹂躏者", + "FERRIS SECTOR": "费里斯分区", + "Forerunner": "先驱", + "Baskin": "巴斯金", + "MERIDIAN SECTOR": "默里迪亚分区", + "THE TERMINIDS": "终结族", + "Rocket Devastators": "火箭蹂躏者", + "Trooper": "装甲兵", + "Osman": "奥斯曼", + "Frob": "弗洛伯", + "MORTAX PRIME": "摩尔塔克斯主星", + "Longato": "隆加托", + "Warriors": "武斗虫", + "Jet Brigade MG Troopers": "喷气旅机枪装甲兵", + "KELVIN SECTOR": "凯尔文分区", + "LUSCIOUS LIBERTY": "甘美自由市", + "Camara": "卡马拉", + "NEW KIRUNA": "新基鲁纳", + "Vox Engine": "噪轰引擎", + "Song": "之歌", + "Alpha Commanders": "阿尔法指挥官", + "MOBILE WHITE HELLPOD PATTERN": "移动白色绝地喷射舱涂装", + "REWA": "流望市", + "ADMINISTRATIVE CENTER 02": "行政总都02", + "INVESTMENT": "投资点", + "GUANG SECTOR": "古安分区", + "MESSAGER'S MESA": "信使台地", + "FAMILY GROVE": "家林市", + "Stallion": "神驹", + "WIDOW'S HARBOR": "寡妇港", + "THE VILLAS": "别墅区", + "EXTRASOLAR ASH VEHICLE PATTERN": "系外星尘载具涂装", + "MATAR BAY": "玛塔", + "ANDROS DELTA": "安德罗斯德尔塔", + "KHARST": "喀斯特", + "of Morality": "道德", + "of Morning": "清晨", + "Predator Stalker": "掠食追踪虫", + "Obtruders": "突入者", + "AZTERRA": "艾孜泰拉", + "SCALD": "烧卡尔德", + "Sodermark": "索德马克", + "Dream": "之梦", + "Overship": "统御舰", + "CRYSTAL SLOPES": "水晶坡", + "ALDERIDGE COVE": "阿尔德里奇湾", + "TROOPER": "装甲兵", + "Distributor": "派遣人", + "RUINED SYSTEM": "废墟星系", + "CHARGER BEHEMOTH": "巨兽级强袭虫", + "MEAN GREEN VEHICLE PATTERN": "凶猛绿载具涂装", + "SOLGHAST": "索尔加斯特", + "MINE 902": "矿洞902", + "Fabricators": "构筑者", + "LAELIA": "蕾丽兰城", + "Stingray": "刺魟", + "AQUILA XXXII": "天鹰XXXII", + "INGMAR": "英格玛", + "Father": "之父", + "SENGE 23": "新戈23", + "WILE": "千惑", + "Titan": "泰坦", + "Bile Titans": "吐酸泰坦", + "Purveyor": "传承", + "Pilestedt": "皮勒斯泰特", + "ALAIRT III": "艾列尔特III", + "KEPLER-399b": "开普勒399b", + "CHURNED EARTH HELLPOD PATTERN": "焦土绝地喷射舱涂装", + "Schonberger": "舍恩伯格", + "LAMBAST": "兰巴斯特", + "ZEA RUGOSIA": "泽亚鲁戈西亚", + "ANNIHILATOR TANK": "湮灭坦克", + "Dust Devils": "尘卷风", + "Beacon": "信标", + "AZUR SECUNDUS": "艾热尔次星", + "VÁHTJER": "瓦赫特耶尔", + "Truth Enforcers": "真理执行者", + "Will": "意志", + "KURRI KURRI": "库里库里", + "ERRANT": "艾伦特", + "BORE ROCK": "博尔岩", + "CONTROL GROUP": "变量控制", + "MG Raiders": "机枪奇袭者", + "Scavenger": "食腐虫", + "UNREGISTERED SYSTEM": "未注册星系", + "BEKVAM III": "贝克温III", + "MG RAIDER": "机枪奇袭者", + "of Justice": "正义", + "DILUVIA": "迪卢维亚", + "Warp Ships": "穿梭舰", + "LIBERTY RIDGE": "解放岭", + "CASTELLAN GREEN VEHICLE PATTERN": "卡斯特兰绿载具涂装", + "Hulk Firebombers": "巨型烈焰轰炸者", + "IDUN SECTOR": "伊顿分区", + "FREEDOM'S FLAME": "自由烈焰", + "SOLIDARITET": "团结堡", + "of Authority": "权威", + "DOUBLET II": "双子裳II", + "GLOBULUS": "球布勒斯", + "PHAM'S SITE": "范姆镇", + "BUCU'S REST": "布库安息城", + "VILHELMINA DOROTHEA FREDRIKA": "维尔赫尔米娜·多罗茜娅·弗蕾德里卡", + "Auger": "奥格", + "Broomhall": "布鲁姆霍尔", + "Susnjar": "舒什尼亚尔", + "Davidsson": "戴维松", + "KINABATANGAN": "京那巴当岸", + "DIVER'S GLORY": "潜兵荣光市", + "PARSH": "帕尔什", + "Scout Raiders": "侦查奇袭者", + "Haggstrom": "黑格斯特伦", + "FIREFLY MEADOWS": "萤火草原", + "Champion": "斗士", + "SAPPHIRE LAKE": "蓝石湖", + "Halo": "光环", + "CIVILIANS IN AREA": "区域内有平民", + "Not much is known about this planet.": "未知", + "Number of stims each Helldiver deploys with increased by #V_ONE.": "每位绝地潜兵上阵时配给的治疗剂数量增加#V_ONE。", + "Stim capacity increase no longer in effect.": "治疗剂容量增加的效果结束。", + "Annihilate": "歼灭", + "AERIAL DOMINANCE": "制霸高空", + "The Orbital Laser stratagem is temporarily available to all Helldivers.": "“轨道激光炮”战略配备可暂时供所有绝地潜兵使用。", + "Battlefield pickups contain #V_ONE% less ammo.": "战场拾取物中将减少#V_ONE%的弹药。", + "STRATAGEM SURPLUS": "战略配备过剩", + "HIDE ORDERS": "隐藏指令", + "T- #DAYSD:#HOURSH:#MINUTESM": "倒计时-#DAYS日:#HOURS时:#MINUTES分", + "TERMINID CONTROL SYSTEM+": "终结族遏制体系+", + "Dense sandstorms reduce mobility and greatly reduce visibility for both enemy and friendly units.": "铺天盖地的沙暴会削弱行动能力并大幅降低能见度,敌我双方都将受影响。", + "Completing this Operation helps reclaim this city. Successfully reclaiming cities significantly contributes to the planet's Liberation.": "完成此次行动有助于收复这座城市。成功收复这座城市将大幅推动星球解放进程。", + "The Orbital 120mm HE Strike stratagem is temporarily available to all Helldivers.": "“轨道120mm高爆弹攻击”战略配备可暂时供所有绝地潜兵使用。", + "The Eagle Napalm Airstrike stratagem is temporarily available to all Helldivers.": "“‘飞鹰’凝固汽油弹空袭”战略配备可暂时供所有绝地潜兵使用。", + "The ARC-3 Arc Thrower stratagem is temporarily available to all Helldivers.": "“ARC-3电弧发射器”战略配备可暂时供所有绝地潜兵使用。", + "#V_ONE is temporarily available to all Helldivers.": "#V_ONE可暂时供所有绝地潜兵使用。", + "WEAPONS EXPERIMENTATION": "武器试验", + "GRAVITATIONAL ANOMALY DETECTED": "侦测到引力异常", + "E-711 ACQUISITION": "获取711元素", + "Parents Frantic After Child Uploads Consciousness Into Cloud Server": "儿童意识上传云服务器,引起家长恐慌", + "Helldivers KIA": "绝地潜兵阵亡数", + "INVASION CAMPAIGN PROGRESS": "入侵战役进度", + "Housing Costs On Rise As Even-Greater Greatest Generation Moves Into Retirement": "伟大中的伟大世代迎来退休,房价应声走高", + "Call For Enlistments Sent To All Citizen Classes.": "参军号召已发送至各级公民", + "DEVASTATOR SURGE": "蹂躏者激增", + "Availability of #V_ONE has ended.": "现已无法使用#V_ONE。", + "PLANET LIBERATED - MOVE TO NEW PLANET": "星球解放 - 前往其他星球", + "Virydian Toys Corp. Deemed Not At": "洛绿玩具公司无需", + "Increase in number of uses of #V_ONE stratagem no longer in effect.": "#V_ONE战略配备可用次数增加的效果结束。", + "The Heavy Machine Gun Emplacement stratagem is temporarily available to all Helldivers.": "“重机枪部署支架”战略配备可暂时供所有绝地潜兵使用。", + "Number of magazines for all weapons Helldivers deploy with is temporarily decreased by #V_ONE.": "绝地潜兵上阵时配给的所有武器弹匣数量暂时减少#V_ONE。", + "The Defense Wall stratagem is temporarily available to all Helldivers.": "“防御墙”战略配备可暂时供所有绝地潜兵使用。", + "GUNSHIP PATROLS": "炮舰巡逻队", + "For the near future, ground will be lost on Planet #V_ONE faster than before.": "近期内,#V_ONE星球的阵地将以前所未有的速度沦陷。", + "Mission time increase no longer in effect.": "任务时间延长的效果结束。", + "Dropping In": "正在降落", + "All Helldivers will passively regenerate health at a rate of #V_ONE% per second.": "所有绝地潜兵以每秒#V_ONE%的速度被动恢复生命值。", + "MERIDIAN SINGULARITY": "默里迪恩奇点", + "Any recognizeable form of life is absent in this austere, cold, rocky world.": "单调、寒冷、岩石嶙峋的星球,不存在可辨识的生命形态。", + "The M-105 Stalwart stratagem is temporarily available to all Helldivers.": "“M-105‘盟友’”战略配备可暂时供所有绝地潜兵使用。", + "The enemy has flooded this planet with Automaton Tanks. Expect increased encounters with heavy armor.": "敌人已向该星球大量投放机器人坦克。预计将频繁遭遇重甲敌军。", + "CITY OPERATION": "城市行动", + "EFFECTS": "效果", + "Legalizing 8 New Pre-Approved Comments On News Media.": "8条预先批准的新媒体评论现已合法", + "This black hole is all that remains of the hopes and dreams of the colonists who could have built a life here. Our enemies would sooner see the entire galaxy sucked into an endless void than allow our way of life to prosper.": "拓殖地居民的希冀与幻想湮灭在黑洞之中,他们原本可以在这里创造幸福的生活。我们的敌人宁愿亲眼看着整个星系被吸入无尽的虚空,也不愿意看见我们的文明繁荣发展。", + "EXPLOSIVES SHORTAGE": "爆炸品短缺", + "NEW OPERATION AVAILABLE": "有新行动可以参加", + "Extraction time against the Illuminate is #V_ONE seconds faster.": "对阵光能者时的撤离时间加快#V_ONE秒。", + "The Automatons have deployed high numbers of Devastators to this planet. Prepare to encounter heavily armored enemies.": "机器人已向该星球部署了大量蹂躏者。请做好应对重甲敌军的准备。", + "TRACKING: MISSION REQUESTS": "正在追踪: 任务申请", + "\"Pulsar Pop\" Dance Craze Sweeps Galaxy": "“脉冲星波普”舞蹈热潮席卷全星系", + "Orbital Gas Strike stratagem availability has ended.": "现已无法使用“轨道毒气攻击”战略配备。", + "SUDDEN ROUTING": "急转直下", + "Helldivers Prepare For Massive Strike on Terminid Hives.": "绝地潜兵准备大规模攻击终结族虫窝", + "Signs Of Sentient Life Discovered On Okul VI; Safely Eradicated.": "欧库VI发现感知生命体存在的迹象,现已妥善消除", + "Eagle Rearm time is #AMOUNT seconds slower on this planet.": "在此星球上的飞鹰时间将减慢#AMOUNT秒。", + "The Orbital Precision Strike stratagem is temporarily available to all Helldivers.": "“轨道精准攻击”战略配备可暂时供所有绝地潜兵使用。", + "Number of grenades each Helldiver deploys with increased by #V_ONE.": "每位绝地潜兵上阵时配给的榴弹数量增加#V_ONE。", + "A mutated strain of Terminids has been reported on this planet. Expect to encounter cunning hunter bugs.": "据报告,该星球上出现了一种终结族变异体。请做好准备,应对狡诈的追猎虫。", + "MAJOR ORDER WON\nGaellivare has been held for the designated timeframe. However, the planet, and the DSS itself, remain imperiled. The fight is not over.\nHigh Command will monitor the situation. Further guidance will be issued once the fate of Gaellivare is decided—one way or the other.": "重要指令达成\n我方在指定时段内守住了耶利瓦勒。但该星球以及DSS本身仍处在威胁中。战斗尚未结束。\n最高指挥部将持续关注局势。无论如何,待耶利瓦勒的命运尘埃落定后,我方将制定进一步的指导方针。", + "ROVING SHRIEKERS": "漫游尖啸虫", + "Number of uses of #V_ONE stratagem is temporarily increased by #V_TWO.": "#V_ONE战略配备的可用次数暂时增加#V_TWO。", + "AUTOMATON INVASION": "机器人入侵", + "Another Colony Devastated By Surprise Automaton Attack.": "机器人再次突袭破坏拓殖地", + "This planet is trapped in the Void. It will remain trapped here until the Source planet is found and dealt with, at which point this planet will return to its native galaxy.": "这颗星球被困在寂域之中。我们必须找到并妥善处理源头星球,否则这颗星球将永困于此,无法回归原本所在的星系。", + "Super Weapon Fires in #TIME": "超级武器开火倒计时:#TIME", + "ILLUMINATE OVERSHIP": "光能者统御舰", + "Welcome to the Galactic War.\n\nHere the community fights together against its common enemies.": "欢迎参加星系战争。\n\n全体绝地潜兵在此齐心协力对抗共同的敌人。", + "Eagle Napalm Airstrike stratagem availability has ended.": "现已无法使用“‘飞鹰’凝固汽油弹空袭”战略配备。", + "SECTOR": "分区", + "The Orbital Airburst Strike stratagem is temporarily available to all Helldivers.": "“轨道空爆攻击”战略配备可暂时供所有绝地潜兵使用。", + "AUTOMATON OVERDRIVE": "机器人超载驱动", + "Unknown": "未知", + "ILLUMINATE FLEET STRENGTH": "光能者舰队战力", + "The arid, rocky biome covering this world has driven the evolution of exceptionally efficient water usage in its various organisms.": "这颗星球遍布由岩石构成的干燥生物群落,其中各式各样的有机体经过进化,对水分的利用效率已十分惊人。", + "Jump Pack stratagem availability has ended.": "现已无法使用“喷射背包”战略配备。", + "Eagle 500kg Bomb stratagem availability has ended.": "现已无法使用“‘飞鹰’500kg炸弹”战略配备。", + "MEGAFACTORY MISSION": "超大型工厂任务", + "Grenade capacity increase no longer in effect.": "榴弹容量增加的效果结束。", + "Number 4 Voted \"Most Democratic Number.\"": "数字4获选成为“最民主数字”", + "Melting Icecaps On Gemstone Bluffs Lead To Increase In Superboat-Hotel Prices.": "宝石崖冰冠融化导致超级舟船酒店房费升高", + "ST-1 Stinger stratagem availability has ended.": "现已无法使用“ST-1毒刺”战略配备。", + "ATMOSPHERIC SPORES": "孢子气体", + "HEAVY ARMOR SURGE": "重甲敌军激增", + "Preliminary Installation Procedures Begin For Terminid Deterrance Network.": "终结族威慑网初期建设工作开始", + "SAMPLES:": "样本:", + "The Shield Generator Pack stratagem is temporarily available to all Helldivers.": "“防护罩生成包”战略配备可暂时供所有绝地潜兵使用。", + "Number of grenades each Helldiver deploys with decreased by #V_ONE.": "每位绝地潜兵上阵时配给的榴弹数量减少#V_ONE。", + "New Evidence Suggests Famous Photo \"The Slaying of the Beast of Vog-Sojoth\" was Faked.": "最新证据表明著名摄影作品《屠杀佛戈索约斯巨兽》主体内容不实", + "New Study Shows 98% of Children Under Twelve Want To": "最新研究发现98%的12岁以下儿童希望", + "Operations on higher difficulties are more challenging, contain new enemies and missions. \n\nThey also have a greater impact on the war, and yield higher rewards. Complete an operation on your highest unlocked difficulty to unlock the one above it.": "行动的难度越高,就越具挑战性,其中包含新的敌人和新的任务。\n\n它们对战争的影响也会提升,并产生更丰厚的奖励。完成一项已解锁的最高难度行动,即可解锁更高一级的难度。", + "Grenade capacity for all Helldivers is temporarily increased by #V_ONE.": "所有绝地潜兵的榴弹容量暂时增加#V_ONE。", + "GLOOM SOURCE": "“阴霾”源头", + "Ends in:": "结束倒计时:", + "Number of uses of #V_ONE stratagem reduced by #V_TWO.": "#V_ONE战略配备的可用次数减少#V_TWO。", + "SEAF Advance Against Automatons Stalls.": "超级地球武装部队向机器人据点进发", + "Squelching mud, twisting roots; the odor of rot and anarchy. A teeming, endless morass.": "地面泥泞不堪,树木盘根错节,散发着腐烂与混乱的恶臭。一片无边无际的沼泽。", + "OPERATION IMPACT": "行动影响", + "New Strain of Bioluminescent Kittens Sells Out In Minutes!": "生物荧光猫咪新品种若干分钟售罄!", + "Ion storms intermittently disable Stratagems.": "离子风暴会间歇性导致战略配备无法使用。", + "Caution: loyal civilians are on the battlefield.": "当心:战场上发现忠诚平民。", + "Extraction time against the Automatons is #V_ONE seconds slower.": "对阵机器人时的撤离时间减慢#V_ONE秒。", + "EXTREME": "极端", + "Helldiver Joining": "绝地潜兵正在加入", + "Artificial Sunlight Determined To Be At Least As Good For You, If Not Better, Than Natural Sunlight.": "专业判定人造阳光对你的益处不会逊色于自然阳光", + "IMPOSSIBLE": "不可能的任务", + "FASTER EAGLE REARM": "飞鹰时间加快", + "CLASS 4 MEGAFACTORY": "4级超大型工厂", + "The Illuminate are generating Dark Energy on this planet, which they are using to move the Meridian Singularity toward Super Earth. They must be stopped at all costs.": "光能者正在该星球上生成暗物质,并用此物质将默里迪恩奇点移至超级地球。必须不惜一切代价阻止它们。", + "FAILURE": "失败", + "RUPTURE STRAIN": "爆裂虫族变种", + "INITIATING FTL JUMP": "正在启动超光速跃迁", + "An orbital strike will be automatically fired whenever a Helldiver is killed.": "只要有绝地潜兵阵亡,就会自动触发一次轨道攻击。", + "Heavy Outposts": "重型哨站", + "The EAT-17 Expendable Anti-Tank stratagem is temporarily available to all Helldivers.": "“EAT-17消耗性反坦克武器”战略配备可暂时供所有绝地潜兵使用。", + "Stand by for further orders from Super Earth High Command": "等待超级地球最高指挥部的进一步指令", + "Unanticipated Automaton reinforcements are taking significant ground on Planet #V_ONE.": "突如其来的机器人增援部队正在#V_ONE星球上占领重要阵地。", + "Impact of each mission returned to normal level.": "每次任务的影响力已恢复正常。", + "Heavily Armored Enemies": "重甲敌人", + "LOW ORBIT SUPERIORITY": "低轨优势", + "#DISTANCE km": "#DISTANCE公里", + "FIRE TORNADOS": "烈焰龙卷", + "\"Super Earth Plasma-Sniper\" Smashes Box-Office Records.": "《超级地球等离子狙击手》轻松突破票房纪录", + "The Orbital Railcannon stratagem is temporarily available to all Helldivers.": "“轨道炮”战略配备可暂时供所有绝地潜兵使用。", + "The DSS deploys Eagle Strafing Runs during missions.": "民主空间站在任务中部署“飞鹰”机枪扫射。", + "Mission Timer reduced to 30 minutes.": "任务时限缩短至30分钟。", + "Swarm": "虫群", + "INCREASED IMPACT": "扩大影响", + "The AC-8 Autocannon stratagem is temporarily available to all Helldivers.": "“AC-8机炮”战略配备可暂时供所有绝地潜兵使用。", + "GENERATING DARK ENERGY": "正在生成暗物质", + "Orbital EMS Strike stratagem availability has ended.": "现已无法使用“轨道电磁冲击波攻击”战略配备。", + "Liberate": "解放", + "Grow Up To Be Helldivers. Remaining 2% Under Investigation.": "长大以后成为绝地潜兵,剩余2%尚在调查", + "The Guard Dog stratagem is temporarily available to all Helldivers.": "“护卫犬”战略配备可暂时供所有绝地潜兵使用。", + "FAF-14 Spear stratagem availability has ended.": "现已无法使用“FAF-14飞矛”战略配备。", + "SAND RAIN": "沙雨", + "Number of grenades each Helldiver deploys with is temporarily increased by #V_ONE.": "每位绝地潜兵上阵时配给的榴弹数量暂时增加#V_ONE。", + "The Anti-Personnel Mine Deployer stratagem is temporarily available to all Helldivers.": "“反步兵地雷部署器”战略配备可暂时供所有绝地潜兵使用。", + "A blazing-hot desert planet, its rocky mesas are the sole interruptions to the endless sea of dunes.": "灼热的沙漠星球,除了坚硬的平顶山以外,只有数不尽的沙丘。", + "Orbital 380mm HE Barrage stratagem availability has ended.": "现已无法使用“轨道380mm高爆弹火力网”战略配备。", + "This planet is completely engulfed by the Gloom, severely impeding logistical support.\nExtraction times are increased by 40 seconds, Eagle Re-arm time is increased by 30% and Ammo from pickups is reduced by 50%.": "这颗星球完全被“阴霾”吞没,严重阻碍后勤支援。\n撤离时间延长40秒,“飞鹰”重新装弹时间延长30%,拾取获得的弹药数量减少50%。", + "Temporary stim decrease no longer in effect.": "治疗剂数量临时减少的效果结束。", + "Stim capacity for all Helldivers increased by #V_ONE on this planet.": "在此星球上的所有绝地潜兵的治疗剂容量增加#V_ONE。", + "Medal payout per mission for all Helldivers is temporarily increased by #V_ONE.": "所有绝地潜兵每次任务的奖章收益暂时增加#V_ONE。", + "The enemy is attacking this planet. If they are not repelled in time, it will be lost.": "敌人正在袭击这颗星球。如果不及时驱逐敌人,星球就会沦陷。", + "PLANETARY DEFENSE FAILURE IN: #TIME": "行星防御失效倒计时:#TIME", + "All currently active Orders can be viewed here.": "当前可执行指令均可在此查看。", + "A geologically recent cataclysm wiped out nearly all life on this planet. Ash and jagged lava rock seem to be all that's left.": "在地质时间尺度上较为近期内发生的一场灾难几乎抹杀了这颗星球上所有的生命。唯一剩下的似乎只有灰烬和凹凸不平的岩浆岩。", + "For the near future, an orbital strike will be automatically fired whenever a Helldiver is killed.": "近期内,只要有绝地潜兵阵亡,就会自动触发一次轨道攻击。", + "Helldivers deploy with #V_ONE% less magazines.": "绝地潜兵部署时携带弹匣数减少#V_ONE%。", + "The presence of the DSS near this planet provides a slight boost to Liberation Campaign progress.": "DSS停靠在这颗星球附近一定程度上也有助于推进解放战役。", + "Map obscured by Bug Spores.": "虫族释放的孢子将会遮蔽地图。", + "EAT-17 Expendable Anti-Tank stratagem availability has ended.": "现已无法使用“EAT-17消耗性反坦克武器”战略配备。", + "SPORE CLOUD POCKETS": "局部孢云", + "Supreme Court of Super Earth Rules Amendment": "超级地球最高法院规则通过修正案", + "PERSONAL ORDERS": "个人指令", + "Sentient Computer Network Swiftly Deleted By Quick-Thinking IT Laborer.": "IT劳工反应迅速,第一时间删除感知电脑网络", + "Mountains of sand bake in unrelenting heat on this utter desolation of a planet.": "庞大的沙丘在酷热中炙烤。这颗星球荒凉至极。", + "The Automatons have deployed a series of specialized models on this planet. Prepare to face bots upgraded with stolen Jump Pack technology.": "机器人在这颗星球上部署了一系列特殊型号。请做好应对利用失窃的喷射背包技术升级优化的机器人。", + "Exploration Vessel Claims to Have Detected Illuminate-like Energy Signature.": "勘探船声称探测到类光能者能量标志", + "SLOWER EAGLE REARM": "飞鹰时间减慢", + "Orbital Gatling Barrage stratagem availability has ended.": "现已无法使用“轨道加特林火力网”战略配备。", + "VOID EXPLORATION": "寂域探索", + "Completing this operation contributes to the planet's Liberation.": "完成此次行动将推动星球解放进程。", + "INVASION FLEET": "入侵舰队", + "Assault Commence in:": "突袭倒计时:", + "EQUIPMENT TESTING": "装备试验", + "OPERATION": "行动", + "Eagle Air-to-Air Missiles stratagem availability has ended.": "现已无法使用“‘飞鹰’空对空导弹”战略配备。", + "The prosperous Meridia was corrupted into a Terminid Supercolony, necessitating its destruction using the mysterious Dark Fluid. This galactic scar is all that remains. Advisory: volatile spacetime fluctuations currently prohibit FTL travel to the Meridian Black Hole.": "曾经欣欣向荣的默里迪亚沦为终结族超级拓殖地,不得不使用神秘的暗液体将其摧毁。如今唯有这道银河系的疤痕,昭示着它曾经的存在。警告:时空波动不稳定,目前无法通过超光速跃迁前往默里迪恩黑洞。", + "The Supply Backpack stratagem is temporarily available to all Helldivers.": "“补给背包”战略配备可暂时供所有绝地潜兵使用。", + "Accumulation of Space Trash Leads To Formation of Floating Trash Moon": "太空垃圾大量积聚组成垃圾卫星", + "Allied Tactical Objectives": "友方战术目标", + "Planet events can happen when enemies are attacking Super Earth controlled planets - Defend Event - or when Super Earth advances in the galaxy - Liberation Events.\n\nMake sure to do your part!": "敌人对超级地球控制下的星球发起攻击时,便会爆发星球战事,名为保卫战事;超级地球在星系中扩大势力时也会爆发星球战事,名为解放战事。\n\n请务必参战!", + "CLAIM": "占领", + "TERMINID QUARANTINE ZONE": "终结族隔离区", + "PREDATOR STRAIN": "掠食变种", + "Planet #V_ONE, on the verge of a successful defense, has fallen to the enemy.": "#V_ONE星球在成功防御之际落入敌手。", + "BATTLE FOR CYBERSTAN": "生化斯坦之战", + "IN TRANSIT TO MISSION SITE": "正在传输至任务地点", + "SANDSTORMS": "沙暴", + "Helldivers Redirected From Operation Valiant Enclosure To Fully Engage Automatons.": "绝地潜兵调离英勇围合行动,全力应战机器人", + "Senator Killjoy Jr. Gives Stirring Speech: \"Super Earth Stronger Than Ever!\"": "小克乔伊参议员言论引起轰动:“超级地球目前实力胜过任何一个历史时期!”", + "CITY OPERATION REWARD": "城市行动奖励", + "Explodes in:": "爆炸倒计时:", + "High numbers of enemy Hulks have been reported on this planet. Prepare to encounter heavily armored enemies.": "据报告称,该星球上出现大量敌方巨型者。请做好应对重甲敌军的准备。", + "Study Finds Galactic Warming Due To Natural Causes": "研究发现星系变暖与自然因素有关", + "The Orbital Gas Strike stratagem is temporarily available to all Helldivers.": "“轨道毒气攻击”战略配备可暂时供所有绝地潜兵使用。", + "SETTLEMENT": "定居点", + "In Loadout": "正在进行武装配置", + "Automatons' Mass Production Capabilities Exceed Expectations.": "机器人量产能力超出预期", + "Shield Generator Pack stratagem availability has ended.": "现已无法使用“防护罩生成包”战略配备。", + "Eagle Rearm time is #AMOUNT seconds faster on this planet.": "在此星球上的飞鹰时间将加快#AMOUNT秒。", + "The Tesla Tower stratagem is temporarily available to all Helldivers.": "“特斯拉塔”战略配备可暂时供所有绝地潜兵使用。", + "In Orbit": "正在轨道上", + "Helldivers Active": "绝地潜兵活跃数", + "Disappeared Colony Transmissions Mention \"Squids\".": "中断的拓殖地通讯内容提及“乌贼”", + "Select a mission and get ready to dive!": "选择任务,准备俯冲降落。", + "Dense fog lightly reduces visibility for both enemy and friendly units.": "浓雾会略微降低能见度,敌我双方都将受影响。", + "A desert planet prone to unpredictable and dangerous sand twisters.": "沙漠星球,时常发生危险而又难以预测的尘卷风。", + "Pro-Terminid Activists Sentenced To 20 Years In Asteroid Mines By Heroic Judge.": "亲虫活动分子被判小行星矿场流放20年", + "Friends Active": "活跃好友", + "Missing Child Astronaut Found In Plutonium Well By Robotic Dog.": "机器狗在钚井发现失踪儿童宇航员", + "LIBERATE ALL SECTORS": "解放全部分区", + "Freedomball Star Rex Stribling Scores Mega-Goal in Twelfth Consecutive Game.": "自由球明星雷克斯·斯特里布林连续12场比赛打进超远大力球", + "Extraction takes #V_TWO seconds less.": "撤离所需时间缩短#V_TWO秒。", + "The Eagle 500kg Bomb stratagem is temporarily available to all Helldivers.": "“‘飞鹰’500kg炸弹”战略配备可暂时供所有绝地潜兵使用。", + "Powerful dust devils launch smaller combatants into the air and stun larger combatants.": "猛烈的尘卷风会将小型战斗单位卷至空中并且会眩晕大型战斗单位。", + "Medal payout per mission for all Helldivers reduced by #V_ONE.": "所有绝地潜兵每次任务的奖章收益减少#V_ONE。", + "Eagle Rearm time is #V_ONE% faster.": "重新武装“飞鹰”的时间加快#V_ONE%。", + "CLASS 3 MEGAFACTORY": "3级超大型工厂", + "Ice and moss-covered rock can be found across most of the surface of this planet.": "这颗星球表面大多是冰雪和长着苔藓的岩石。", + "Missing Child Found Orbiting Asteroid After Family Spacewalk Mishap.": "太空行走事故失踪儿童现已找到,当时正在围绕小行星旋转", + "Orbital 120mm HE Strike stratagem availability has ended.": "现已无法使用“轨道120mm高爆弹攻击”战略配备。", + "MODIFIERS [#COUNT]": "限制条件[#COUNT]", + "Terminid Dragonroaches menace the skies of this planet. Prepare to encounter airborne enemies.": "终结族的蟑龙变种威胁着这颗星球的领空。请做好应对空中敌军的准备。", + "MINDLESS MASSES": "无脑群氓", + "AUTOMATON OCCUPIED SPACE": "机器人占领的空间", + "Meteors impact the surface causing massive damage.": "流星会撞击地表,造成大量伤害。", + "Melee damage is temporarily decreased by #V_ONE%.": "近战伤害暂时降低#V_ONE%。", + "FRACTURED PLANET": "碎裂星球", + "GREAT HIVES": "大虫窝", + "Medal payout per mission for all Helldivers is temporarily reduced by #V_ONE.": "所有绝地潜兵每次任务的奖章收益暂时减少#V_ONE。", + "Complete operations on #PLANET": "在#PLANET完成行动", + "MISSIONS COMPLETED BONUS": "任务完成奖励", + "Hovering over a sector shows you how much of it Super Earth has already liberated. All operations contribute to pushing the enemies of Super Earth back.\nSelect a sector to see what planets are currently playable.": "悬停在分区上可看到超级地球在该区的解放进度。所有行动皆能为击退超级地球的敌人贡献助力。\n选择分区,看看当前可以参与哪颗星球的战事。", + "Dark Energy Accumulation": "暗物质积聚", + "MG-43 Machine Gun stratagem availability has ended.": "现已无法使用“MG-43机枪”战略配备。", + "Supply Backpack stratagem availability has ended.": "现已无法使用“补给背包”战略配备。", + "#RACE": "#RACE", + "DAMAGED FACTORIES": "工厂受损", + "PROXIMITY TO MERIDIA CRITICAL": "与默里迪亚的距离达到临界点", + "CYBORGS": "生化人", + "AA DEFENSES": "对空防御", + "Corrosive acid storms temporarily reduce armor effectiveness for both enemy and friendly units.": "腐蚀性酸雨风暴会暂时削弱盔甲的防护效用,敌我双方都将受影响。", + "The ST-1 Stinger stratagem is temporarily available to all Helldivers.": "“ST-1毒刺”战略配备可暂时供所有绝地潜兵使用。", + "OPERATION STATUS": "行动状态", + "HELLDIVERS: #VALUE": "绝地潜兵:#VALUE", + "Battlefield pickups on all planets contain #AMOUNT% more ammo.": "所有星球上的战场拾取物中将增加#AMOUNT%的弹药。", + "TERMINID FRENZY": "狂暴终结族", + "Heavy SEAF Presence": "超级地球武装部队重兵驻守", + "Conventional SEAF forces are heavily deployed across this planet, and may directly support Helldiver missions.": "常规超级地球武装部队已在该星球上大量部署,可直接为绝地潜兵的任务提供支援。", + "PLATOON: #VALUE": "特战排:#VALUE", + "A mutation causes Terminids on this planet to generate excess hormonal spores, which drive other similarly mutated Terminids into a frenzy. Prepare to face enemies that bolster each others' speed.": "一场突变导致该星球上的终结族产生过量激素孢子,驱使其他发生类似突变的终结族陷入狂暴。准备迎击这些为彼此提速的敌人。", + "FAILED": "失败", + "SPORE BURST STRAIN": "孢裂变种", + "Extraction time against the Illuminate is #V_ONE seconds slower.": "对阵光能者时的撤离时间减慢#V_ONE秒。", + "VOTE SNATCHERS": "窃票者", + "The Orbital EMS Strike stratagem is temporarily available to all Helldivers.": "“轨道电磁冲击波攻击”战略配备可暂时供所有绝地潜兵使用。", + "DEFEND SUPER EARTH": "保卫超级地球", + "Unverified Reports of Illuminate Sightings Attributed to Dissident Disinformation.": "未经证实的光能者目击报道助长异见分子的造谣气焰", + "Cooldown period increase for #V_ONE stratagem no longer in effect.": "#V_ONE战略配备冷却时间延长的效果结束。", + "#PERCENTAGE% HELD": "#PERCENTAGE%保卫成功", + "The DSS fires Orbital Barrages during missions.": "民主空间站在任务中发射轨道火力网。", + "Terminid Swarming in Unprecedented Numbers, Defying Expert Explanations.": "终结族数量增速前所未见,专家理论纷纷破产", + "The GL-6 Grenade Launcher stratagem is temporarily available to all Helldivers.": "“GL-6榴弹发射器”战略配备可暂时供所有绝地潜兵使用。", + "The Orbital Gatling Barrage is experimentally modified to use incendiary rounds instead of HE rounds.": "轨道加特林火力网经实验性调整,改用燃烧弹替代高爆弹。", + "Enemy progress in Defense Campaigns is slowed.": "敌人在保卫战役中的进展放缓。", + "82-Year-Old Woman Catches Sedition Group Meeting In Attic.": "82岁女性家中阁楼发现叛乱团伙集会", + "Tall, gnarled trees flourish across the surface of this forested world. Sunlight filters past dangling vines, to the saturated undergrowth below.": "蟠枝虬根的参天大树在这片植被茂密的地表蓬勃生长。阳光穿过垂悬的藤蔓,落入色泽饱和的林下灌丛中。", + "This planet is considered enemy territory. The Helldivers must reclaim it from its oppressive occupants.": "这颗星球被列为敌占领地。绝地潜兵必须从残暴入侵者手中夺回控制权。", + "RECON CAMPAIGN": "侦察战役", + "LOWER STIM CAPACITY": "更小治疗剂容量", + "RS-422 Railgun stratagem availability has ended.": "现已无法使用“RS-422磁轨炮”战略配备。", + "Bio-Genetics Startup Fills Volcano With Mutant Giant Popcorn Kernels": "生物基因初创企业向火山内投入大量变种巨型爆米花仁", + "DEFENSE": "防御战", + "RESISTANCE": "抵抗强度", + "INTENSE HEAT": "极暑", + "Historians Determine \"Gaslighting\" Never Meant What We Thought It Meant": "历史学家认为“煤气灯操纵”实际含义始终不同于大众认知", + "SUCCEEDED": "成功", + "The FAF-14 Spear stratagem is temporarily available to all Helldivers.": "“FAF-14飞矛”战略配备可暂时供所有绝地潜兵使用。", + "STRATAGEM CONSERVATION": "节省战略配备", + "Liberation Impact from completed missions on this planet is #V_ONE% greater on this planet.": "在此星球上完成任务所造成的解放影响将扩大#V_ONE%。", + "Number of reinforcements available per mission is temporarily decreased by #V_ONE.": "每次任务的可用增援数暂时减少#V_ONE。", + "Initial Helldiver Push Against Terminids \"Unequivocal Success.\"": "绝地潜兵进攻终结族的初始计划“取得了绝对的胜利”", + "Experience gain for all Helldivers is temporarily reduced by #V_ONE%.": "所有绝地潜兵获得的经验值暂时减少#V_ONE%。", + "Massive Enemies": "大型敌人", + "CRITICAL THREAT LEVEL": "临界威胁等级", + "Protects Individual Right To Own Giant Mechanized Robot": "保障个人拥有巨型机械化机器人的权利", + "Entirely unforeseeable mutations from the Termicide led to hyper-accelerated bug growth on this planet, turning it into a Supercolony. It is corrupted beyond saving. The bugs infest every inch of it, down to the mantle, spawning trillions of spores every day.": "灭虫终结剂引发毫无预警的突变,导致虫族极速繁殖,将这颗星球变为了超级拓殖地。星球已经腐化得无可救药,虫族侵染了上面的每一寸土地,连地幔也没有幸免于难,每天都繁殖出数万亿孢子。", + "Ballistic Shield Backpack stratagem availability has ended.": "现已无法使用“防弹护盾背包”战略配备。", + "Man Trades Up Giant Red Paperclip For Asteroid.": "男子为购小行星出售巨型红色回形针", + "Guard Dog stratagem availability has ended.": "现已无法使用“护卫犬”战略配备。", + "Stratagem Call-in time increased by #V_ONE%.": "战略配备的呼叫时间增加#V_ONE%。", + "The Illuminate have unleashed the next wave of their democratically voided thralls on this planet. Expect violent voter suppression tactics.": "光能者在该星球上释放了新一波毫无民主理念的奴仆。请准备好迎接暴力的选民压制手段。", + "An unanticipated Terminid surge is taking significant ground on Planet #V_ONE.": "突如其来的终结族激增势力正在#V_ONE星球上占领重要阵地。", + "Time to complete all missions is temporarily increased by #V_ONE%.": "完成所有任务的时间暂时延长#V_ONE%。", + "#PLANET": "#PLANET", + "So long as even one Mega City stands, so does Super Earth. Illuminate Fleet Strength must be depleted before the last one falls.": "只要还有一座特大城市屹立不倒,超级地球便不会沦陷。在最后一座特大城市沦陷前,必须耗尽光能者军队战力。", + "Heroic Kindergartener Identifies Dissident Classmate": "幼儿园英勇儿童发现同班异见分子", + "FLAM-40 Flamethrower stratagem availability has ended.": "现已无法使用“FLAM-40火焰喷射器”战略配备。", + "Warning: Starting a new Operation will abandon your currently active Operation": "警告:开始新行动将终止目前进行中的行动。", + "This is a Commando Operation. It contains Commando missions.\n\nIn Commando missions, access to your Super Destroyer and Stratagems will be limited. Choose your engagements carefully.": "这是突击兵行动。其中包含突击兵任务。\n\n在突击兵任务中,使用超级驱逐舰和战略配备都将受限。请谨慎选择交战对象。", + "Extracting": "正在撤离", + "COMMANDO OPERATION": "突击兵行动", + "LIGHT GLOOM COVER": "轻度“阴霾”笼罩", + "The Orbital Walking Barrage stratagem is temporarily available to all Helldivers.": "“轨道游走火力网”战略配备可暂时供所有绝地潜兵使用。", + "Number of stims each Helldiver deploys with is temporarily decreased by #V_ONE.": "每位绝地潜兵上阵时配给的治疗剂数量暂时减少#V_ONE。", + "Heavy Machine Gun Emplacement stratagem availability has ended.": "现已无法使用“重机枪部署支架”战略配备。", + "Anti-Democracy Rebels Rounded Up with Stunning Efficiency.": "反民主叛乱分子全部落网", + "Rocky outcroppings punctuate fields of tall grass in a planet dominated by misty highland terrain.": "这颗星球地表大多是雾气氤氲的高地。茂盛的草原上不时冒出裸露的岩石。", + "Volcanos throw burning rocks around this planet.": "火山会将灼热的岩石喷射至这颗星球各处。", + "The Rocket Sentry stratagem is temporarily available to all Helldivers.": "“火箭哨戒炮”战略配备可暂时供所有绝地潜兵使用。", + "Researchers Declared Dead After Canine Neural Communication": "犬类神经通信装置意外接入附近狼类大脑", + "Heroic dog rescues boy from plutonium mine shaft": "英勇狗狗将男孩救出钚矿井", + "Carve a path through the Megafactories towards the Cyborg Capital—the largest Megafactory and nexus of Cyborg resistance. Destroy it before our Forces in Reserve are depleted to liberate Cyberstan.": "从超大型工厂杀出一条血路,直捣生化人首都,那是最大的超大型工厂,也是生化人抵抗势力的核心枢纽。在预备部队耗尽战力之前将其摧毁,解放生化斯坦。", + "Reinforcement increase is no longer in effect.": "可用增援数增加的效果结束。", + "This planet continually produces a thick atmospheric Gloom cover, rendering logistical support extremely challenging.\nTotal Reinforcements are reduced by 20%, Eagle Re-arm time is increased by 30% and Ammo from pickups is reduced by 50%.": "这颗星球持续积累厚重的“阴霾”孢子层,使后勤支援变得极其困难。\n总增援数减少20%,“飞鹰”重新装弹时间延长30%,拾取获得的弹药数量减少50%。", + "Abandon Operation": "放弃行动", + "Bullets Fired": "射击弹药数", + "The Orbital 380mm HE Barrage stratagem is temporarily available to all Helldivers.": "“轨道380mm高爆弹火力网”战略配备可暂时供所有绝地潜兵使用。", + "Medal payout decrease no longer in effect.": "奖章收益减少的效果结束。", + "LOCAL TIME SETU: #VALUE": "当地时间(超级地球时间单位): #VALUE", + "Arrives in:": "抵达倒计时:", + "Grenade capacity for all Helldivers increased by #V_ONE.": "所有绝地潜兵的榴弹容量增加#V_ONE。", + "TRIVIAL": "易如反掌", + "M-105 Stalwart stratagem availability has ended.": "现已无法使用“M-105‘盟友’”战略配备。", + "Effectiveness of #V_ONE is temporarily increased by #V_TWO%.": "#V_ONE的效果暂时提升#V_TWO%。", + "Operation Valiant Enclosure In Crisis.": "英勇围合行动面临危机", + "HULK SURGE": "巨型者激增", + "Terminid Deterrance Network Ready For Implementation Following Cordon Establishment.": "继封锁线后,终结族威慑网也已准备部署应用", + "The Eagle Air-to-Air Missiles stratagem is temporarily available to all Helldivers.": "“‘飞鹰’空对空导弹”战略配备可暂时供所有绝地潜兵使用。", + "A perenially chilly climate has allowed short, colorful shrubs to flourish across this planet's surface.": "这里常年寒冷,颜色各异的矮小灌木在得天独厚的气候条件下占领了这颗星球的地表。", + "New Study Cut Tragically Short by Terminid Strike.": "终结族袭击导致最新研究不幸提前终止", + "A deadly strain of ground-bursting Terminids is present on this planet. Prepare to face burrowing enemies.": "这颗星球上出现了一种从地下破土而出的致命终结族变种。请做好应对钻地敌军的准备。", + "Send You There\" Stranded Behind Enemy Lines.": "继续爆出参赛选手被困敌阵", + "Aftermath of Planet Busters: Devastation.": "“歼星”成效:完全毁灭", + "AUTOMATON CONTROL": "由机器人控制", + "Medal payout increase no longer in effect.": "奖章收益增加的效果结束。", + "Mansion lost in #TIME": "总统府失守倒计时:#TIME", + "EASY": "简单", + "AUTOMATON BLOCKADE WORLDS": "机器人封锁带", + "The Illuminate are attacking our prosperous colonies, raising strange structures and terrorizing our loyal citizens. While their aim does not seem to be planetary conquest their invasion must nevertheless be repelled before they can accomplish their mysterious, malevolent aims.": "光能者正袭击我们繁荣的拓殖地,还立起了奇怪的建筑物,吓坏了我们忠诚的公民。虽然光能者的目的似乎并非侵略星球,但必须击退它们的入侵,防止其恶毒的神秘目的达成。", + "THE GALACTIC WAR": "星系战争", + "The Autocannon Sentry stratagem is temporarily available to all Helldivers.": "“自动哨戒炮”战略配备可暂时供所有绝地潜兵使用。", + "ATTRITION": "消耗战", + "Flying Gunships patrol the battlefield.": "战场上有飞空炮舰巡逻。", + "Gatling Sentry stratagem availability has ended.": "现已无法使用“加特林哨戒炮”战略配备。", + "SELECT CAMPAIGN": "选择战役", + "Periods of freezing temperatures reduce rate of fire and delay heat buildup in weapons.": "极寒时段会降低射速,减慢武器升温速度。", + "Automatons Ultimate Goal Appears To Be Super Earth Itself, According to MOD.": "国防部称机器人的终极目标疑为超级地球", + "The Jump Pack stratagem is temporarily available to all Helldivers.": "“喷射背包”战略配备可暂时供所有绝地潜兵使用。", + "AC-8 Autocannon stratagem availability has ended.": "现已无法使用“AC-8机炮”战略配备。", + "MODERATE GLOOM BLANKET": "中度“阴霾”笼罩", + "Assault Imminent": "突袭即将开始", + "The SAR-1 Sniper Rifle stratagem is temporarily available to all Helldivers.": "“SAR-1狙击步枪”战略配备可暂时供所有绝地潜兵使用。", + "Communication Troubles From Terminid Quarantine Zone.": "通讯难题困扰终结族隔离区", + "URGENT LIBERATION": "亟待解放", + "in": "in", + "START MISSION": "开始任务", + "This former planet is now nothing but a normal, stable black hole.": "这颗昔日行星现在不过是一个没什么特别的稳定黑洞。", + "Reduction in number of uses of #V_ONE stratagem no longer in effect.": "#V_ONE战略配备可用次数减少的效果结束。", + "DEFENSE PROGRESS": "保卫战役进度", + "SATURATED RANKS": "军衔晋升饱和", + "The Illuminate are converting large numbers of Super Earth citizens into Voteless-type enemies on this planet. Prepare to face a twisted, indoctrinated horde.": "光能者正在这颗星球上将大批超级地球公民转化为无票者型敌人。准备迎战这群遭到洗脑、思维扭曲的暴徒。", + "Giant Pandas Officially Extinct; Giant Panda-Bot ETF Value Skyrockets": "大熊猫正式灭绝,机器大熊猫交易所交易基金净值飙升", + "COMPLETE #CR_DESC#CR_NEWLINE OPERATION TO UNLOCK": "完成#CR_DESC#CR_NEWLINE行动后解锁", + "SEARCHING FOR MISSIONS IN PROGRESS": "正在寻找进行中的任务", + "Increased Enemy Presence": "敌人势力增强", + "Melee damage decreased by #V_ONE%.": "近战伤害降低#V_ONE%。", + "THICK FOG": "浓雾", + "DEFEND": "保卫", + "Successful Nuclear Weapons Test": "确定为死亡状态", + "MERIDIAN BLACK HOLE": "默里迪恩黑洞", + "Spaceship of Theseus Destroyed Piece By Piece": "忒修斯太空飞船已逐渐解体", + "THE JET BRIGADE": "喷气旅", + "Temporary magazine reduction no longer in effect.": "弹匣数量临时减少的效果结束。", + "PILOT SHORTAGE": "驾驶员短缺", + "Number of magazines for all weapons Helldivers deploy with is temporarily increased by #V_ONE.": "绝地潜兵上阵时配给的所有武器弹匣数量暂时增加#V_ONE。", + "Awaiting Major Order": "等待重要指令", + "Launches in:": "发射倒计时:", + "Number of grenades each Helldiver deploys with is temporarily decreased by #V_ONE.": "每位绝地潜兵上阵时配给的榴弹数量暂时减少#V_ONE。", + "Mission time reduction no longer in effect.": "任务时间缩减的效果结束。", + "Medium Outposts": "中型哨站", + "A Patriotic Miracle? Woman on Pioneer II Finds Flag of Super Earth In Toast": "爱国主义奇迹?先驱II星系上的女子在吐司中发现超级地球旗帜", + "Battlefield pickups on this planet contain #AMOUNT% more ammo.": "在此星球上的战场拾取物中将增加#AMOUNT%的弹药。", + "BATTLE FOR SUPER EARTH": "超级地球保卫战", + "SECTOR MAP": "分区地图", + "Solar Storm Edna Reclassified As Solar Hurricane Edna.": "太阳风暴埃德娜被重新界定为“太阳飓风埃德娜”", + "PLANETARY FRACTURING CONFIRMED": "行星破裂已确认", + "Destroy the Automaton Super Weapon": "摧毁机器人超级武器", + "Revenge orbital strike no longer in effect.": "复仇轨道攻击不再生效。", + "Stim capacity for all Helldivers decreased by #V_ONE on all planets.": "所有星球上的所有绝地潜兵的治疗剂容量减少#V_ONE。", + "\"Freedom of Expression\" Bill Passes Into Law,": "《表达自由》法案通过审议", + "The nearby Gloom Base provides logistical support to this Hive World, mitigating some of its extreme logistical challenges.\nExtraction times are increased by 30 seconds and Eagle Re-arm time is increased by 20%.": "附近的“阴霾”基地为这个虫窝世界提供后勤支援,缓解了严峻的后勤压力。\n撤离时间延长30秒,“飞鹰”重新装弹时间延长20%。", + "The Meridian Singularity speeds up as Dark Energy accumulates": "暗物质积聚,默里迪恩奇点加速移动", + "UNKNOWN SIGNATURE": "不明标志", + "TIN SHORTAGE": "锡资源短缺", + "Ground will no longer be lost more quickly on Planet #V_ONE.": "#V_ONE星球的阵地沦陷的速度不再加快。", + "The Automatons are deploying an abnormal amount of War Striders and Tanks to this planet. Prepare to encounter high numbers of heavily armored enemies": "机器人正在向该星球部署异常数量的战争纵步者与坦克。请做好应对大量重甲敌军的准备", + "CONVENTIONAL BLACK HOLE": "常规黑洞", + "C.O.B. Genetics to Donate Last Year's Corn to Hungry Cows.": "C.O.B.基因公司拟向饥牛捐赠去年所产玉米", + "Promising New Study Establishes Link Between 4D Cinema and Real World Violence.": "最新研究发现4D电影与现实世界的暴力行为存在关联", + "TS-4 Arc Thrower stratagem availability has ended.": "现已无法使用“ARC-3电弧发射器”战略配备。", + "Rip Gustafson Wins Yet Another Mr. Multiverse Competition": "利普·古斯塔夫松再次荣获“多重宇宙先生”称号", + "Astronomers Identify Promising New Exoplanet For Settlement.": "天文学家发现可能宜居的新系外行星", + "Conquer the #SECTOR": "征服#SECTOR", + "Helldivers Redirected from Automaton Conflict Back To Terminids.": "绝地潜兵调离机器人冲突战区,重返抗击终结族前线", + "All that remains of a planet torn apart by the Meridian singularity. A solemn reminder of the desolation Tyranny leaves in its wake.": "被默里迪恩奇点摧毁的星球残骸。它庄严地提醒着我们,暴政必将带来毁灭。", + "This planet serves as a connective point between this galaxy and the Void, allowing travel between the two spaces.": "这颗星球是本星系与寂域之间的连接点,可以让舰船在二者之间穿梭。", + "Torrential rainstorms reduce visibility.": "倾盆暴雨会降低能见度。", + "ORBITAL FLUCTUATIONS": "轨道波动", + "INVASION CAMPAIGN": "入侵战役", + "POOR INTEL": "缺乏情报", + "Number of stims each Helldiver deploys with is temporarily increased by #V_ONE.": "每位绝地潜兵上阵时配给的治疗剂数量暂时增加#V_ONE。", + "The Orbital Gatling Barrage stratagem is temporarily available to all Helldivers.": "“轨道加特林火力网”战略配备可暂时供所有绝地潜兵使用。", + "Extraction time increase no longer in effect.": "撤离时间延长的效果结束。", + "Completing this Operation helps hold this Mega City. Once a Mega City falls, it cannot be reclaimed.": "完成此次行动有助于保卫这座特大城市。特大城市一旦沦陷便无法收复。", + "Eagle 110mm Rocket Pods stratagem availability has ended.": "现已无法使用“‘飞鹰’110mm火箭巢”战略配备。", + "Stim capacity for all Helldivers is temporarily increased by #V_ONE.": "所有绝地潜兵的治疗剂容量暂时增加#V_ONE。", + "BLIZZARDS": "暴风雪", + "The Eagle 110mm Rocket Pods stratagem is temporarily available to all Helldivers.": "“‘飞鹰’110mm火箭巢”战略配备可暂时供所有绝地潜兵使用。", + "The Shield Generator Relay stratagem is temporarily available to all Helldivers.": "“防护罩生成中继器”战略配备可暂时供所有绝地潜兵使用。", + "SECTOR INTRUSION DETECTED": "侦测发现分区遭到入侵", + "TERMINID INVASION": "终结族入侵", + "President Authorizes Use of \"Planet Buster\" Charges to Contain Terminids.": "总统授权动用“歼星”炸药遏制终结族", + "ORBITAL 120MM HE/EMS BARRAGE": "轨道120MM高爆/电磁弹火力网", + "EXOSUIT RESERVES": "外骨骼装甲储备", + "Battlefield pickups on all planets contain #AMOUNT% less ammo.": "所有星球上的战场拾取物中将减少#AMOUNT%的弹药。", + "The #V_ONE stratagem is unavailable to all Helldivers.": "所有绝地潜兵都不能使用#V_ONE战略配备。", + "The RS-422 Railgun stratagem is temporarily available to all Helldivers.": "“RS-422磁轨炮”战略配备可暂时供所有绝地潜兵使用。", + "Multiple Operation Modifiers": "多重行动限制条件", + "79 Million Heroes Added to the Wall in Another Glorious Martyrs' Day.": "7900万英雄光荣烈士日送入英烈墙", + "The AT-48 Recoilless Rifle stratagem is temporarily available to all Helldivers.": "“AT-48无后坐力步枪”战略配备可暂时供所有绝地潜兵使用。", + "SUPPLEMENTAL STEROIDS": "类固醇补充剂", + "Enemy Tactical Objectives": "敌方战术目标", + "Fault For Deadly Hoverboarding Accidents.": "就悬浮滑板致死事故承担任何责任", + "Grenade capacity decrease no longer in effect.": "榴弹容量减少的效果结束。", + "BULLETS FIRED: #VALUE": "开火次数:#VALUE", + "Extraction time temporarily increased by #V_TWO seconds.": "撤离时间暂时延长#V_TWO秒。", + "#PERCENTAGE% LIBERATED": "已解放#PERCENTAGE%", + "MAJOR ORDER REWARD": "重要指令奖励", + "Each Order is tied to an enemy faction and a location in space, represented by an icon on the map.": "每一项指派任务均针对太空某位置的某一敌方阵营,在地图上以图标标识。", + "Stim capacity decrease no longer in effect.": "治疗剂容量减少的效果结束。", + "FORMER SUPER EARTH COLONY": "前超级地球拓殖地", + "The Resupply stratagem is temporarily available to all Helldivers.": "“重新补给”战略配备可暂时供所有绝地潜兵使用。", + "Extraction takes #V_TWO additional seconds.": "撤离所需时间延长#V_TWO秒。", + "SELECT SECTOR": "选择分区", + "New Ursine Species Discovered on Ridge World, Proven Undemocratic and Promptly Eradicated.": "山岭世界发现熊科新物种,证实为非民主物种并当场灭绝", + "EXPERIMENTAL INITIATIVE": "实验性倡议", + "UNIDENTIFIED PLANET": "未识别星球", + "Mortar Sentry stratagem availability has ended.": "现已无法使用“迫击哨戒炮”战略配备。", + "SUPER HELLDIVE": "超级绝地俯冲", + "ENTER THE COLOSSEUM: AUTOMATON VS. BUG - WHO WILL WIN!?": "走进角斗场:机器人对虫族,谁胜谁负!?", + "The #V_ONE stratagem is available to all Helldivers.": "#V_ONE战略配备可供所有绝地潜兵使用。", + "Melee damage decrease no longer in effect.": "近战伤害降低的效果结束。", + "The Gloom covers this planet completely, obstructing a variety of logistical operations.\nExtraction times are increased by 30 seconds and Eagle Re-arm time is increased by 20%.": "“阴霾”已完全笼罩这颗星球,阻碍我们开展各类后勤行动。\n撤离时间延长30秒,“飞鹰”重新装弹时间延长20%。", + "LONG: #VALUE": "经度: #VALUE", + "Enemy Patrols": "敌方巡逻队", + "This dark abyss is all that remains of the verdant paradise that was once Meridia. Its breathtaking forests and abundant resources were corrupted and destroyed by the Terminids, leaving no choice but to use Dark Fluid to destroy it completely. Now, this singularity remains as a memorial, reminding us all of the consequences of defying Freedom.": "默里迪亚曾经富饶的天堂如今只剩下黑暗的深渊。令人叹为观止的森林和丰富的资源遭到了终结族的腐化与摧毁,我们别无他法,只能利用暗液体将其完全销毁。现在,这个奇点已成为纪念碑,时刻提醒着我们藐视自由的代价。", + "OPERATION MODIFIERS": "行动限制条件", + "COLONY MISSION": "拓殖地任务", + "Due to Void interference, no data can be gathered about this planet. There is a high probability of its probable existence.": "由于寂域的干扰,我们无法获取该星球的任何数据。但它存在的可能性极高。", + "Stratagem Codes Scrambled.": "战略配备代码被扰频打乱。", + "After days of fighting, Gaellivare has fallen to the Automaton Jet Brigade. However, thanks to shrewd maneuvering of the Helldivers, the DSS is safely out of their reach.\nThe Helldivers, in their Democratic direction of the DSS, displayed undeniable tactical brilliance, demonstrating once again why they are known as the Galaxy's most elite fighting force. Their efforts held the Automaton onslaught long enough to allow emergency evacuation efforts to save many citizens, many of whom aided in the construction of the space station.\nThe Jet Brigade remains a significant threat. Meanwhile, the crisis created by the sudden and shocking outbreak at the Terminid Research Center is ongoing. The addition of the DSS to Liberty's arsenal, even in its diminished state, could not have come at a better time. Managed Democracy is imperiled; we need every weapon at our disposal.": "经过数天战斗,耶利瓦勒落入了机器人喷气旅手中。不过,幸亏绝地潜兵足够机敏,DSS已安全脱离它们的控制范围。\n绝地潜兵对DSS进行民主指挥,展现无可争议的战术才华,再次证明了他们为何称得上是银河系最精锐的战斗部队。他们拼命拖住了机器人的屠戮,给我方的紧急疏散工作预留足够时间,救出了众多平民,其中许多人还曾协助建造空间站。\n喷气旅依然虎视眈眈。同时,终结族研究中心突如其来的暴乱危机仍在肆虐。解放军械库再添民主空间站这把利器,可谓恰逢其时,即便空间站已受损,仍然无可替代。管理式民主岌岌可危;我们必须动用一切可用的武器。", + "TREMORS": "地震", + "Keep yourself updated with the latest happenings in the Galactic War through the News Feed. \n\nIt automatically displays the latest events!": "请通过新闻动态随时掌握星系战争的最新动态。\n\n最新战事会自动显示动态中!", + "SEAF Forces Cede Another Planet to Advancing Automatons.": "机器人逼近,超级地球武装部队再次割让一颗星球", + "CITY LIBERATION PROGRESS": "城市解放进度", + "Fires in:": "开火倒计时:", + "Last Surviving Hero of First Galactic War Passes Away at 103; \"Greatest Honor\" Was Service.": "第一次星系大战最后一位幸存英雄逝世(享年103岁),追授最高战功勋章", + "Hold back": "压制", + "Headset Accidentally Linked To Nearby Wolves.": "导致研究人员不幸身亡", + "Full Mobilization Declared; \"Super Earth is at War,\" says President.": "全面动员正式开始,总统宣布“超级地球进入战争状态”", + "The Gatling Sentry stratagem is temporarily available to all Helldivers.": "“加特林哨戒炮”战略配备可暂时供所有绝地潜兵使用。", + "HIDE DETAILS": "隐藏详细信息", + "This black hole is all that remains of the singularly beautiful planet that was once Moradesh. Its endless wavy dunes and abundant resources were destroyed by an unavoidable accident at the Dark Fluid Research Facility, as its heroic scientists strived to save our citizens from the first Terminid Supercolony. The Terminids took Moradesh from us, leaving this scar as a reminder of their boundless barbarity.": "莫拉戴什曾是一颗美丽绝伦的星球,如今,一切化为黑洞。星球上连绵起伏的沙丘和丰饶的资源因暗液体研究设施的突发事故而毁灭。当时,英勇的科研人员曾在该设施中致力于对抗首个终结族超级拓殖地,拯救我们的公民。终结族让我们痛失莫拉戴什,留下的疮疤将永远警示着我们,敌人是多么野蛮残暴。", + "The blinding beacon that illuminates the stars with the light of Democracy. The patriotic paradise for citizens who truly serve their Federation. And the utopian future awaiting the entire galaxy.": "炫目的灯塔,以民主之光照亮宇宙群星。真正效忠联邦的爱国公民心中的乐土。为整个银河系描绘了未来乌托邦的蓝图。", + "The lifeless grey of this planet is interrupted only by the violet flowers that grow from strange, parasitic outcroppings.": "灰色是这颗星球的主色,唯有从彷如寄生一般的奇异裸露地表长出的紫罗兰色花朵能打破这股死气沉沉的格调。", + "GRAVITATIONAL COLLAPSE CONFIRMED": "侦测到引力坍缩", + "CITY MISSION": "城市任务", + "Autocannon Sentry stratagem availability has ended.": "现已无法使用“自动哨戒炮”战略配备。", + "ILLUMINATE GOALS ACHIEVED: #TIME": "光能者目标已达成:#TIME", + "Stim capacity for all Helldivers is temporarily decreased by #V_ONE.": "所有绝地潜兵的治疗剂容量暂时减少#V_ONE。", + "Stave Off": "拖延", + "Protect the President's Mansion!": "保卫总统府!", + "Operation Modifiers": "行动限制条件", + "MOBILIZE TO A FRONTLINE PLANET": "响应动员奔赴前线星球", + "#PLANET MEGAFACTORIES": "#PLANET超大型工厂", + "LIBERATION": "解放战役", + "Infectious Disease Expert Calls Terminid Spread An \"Epidemic\".": "传染病专家称终结族扩张为“流行病”", + "Orbital Stratagems Scatter Increased.": "轨道武器战略配备效果范围更加分散。", + "ILLUMINATE FLEET": "光能者舰队", + "Enemy forces are trying to claim this planet! Push them back by playing special missions during the specified time frame, or the planet will fall to the enemy.": "敌军正试图占领这颗星球!在特定时间段内参与特别战事任务,全力击退敌军,否则这颗星球将落入敌军手里。", + "Extraction time against the Automatons is #V_ONE seconds faster.": "对阵机器人时的撤离时间加快#V_ONE秒。", + "All readings, or the notable lack thereof, indicate that the source of the Void anomaly is located here. All effort must go to enabling FTL travel to these coordinates.": "各项读数表明,寂域异常的源头就在这里,部分读数因寂域干扰而缺失,更加证实了这一点。集中全部力量,实现前往该坐标的超光速航行。", + "Experience gain for all Helldivers increased by #V_ONE%.": "所有绝地潜兵获得的经验值增加#V_ONE%。", + "Ground is being lost on Planet #V_ONE faster than before.": "#V_ONE星球的阵地正以前所未有的速度沦陷。", + "The Illuminate are spreading across this planet, seizing our colonies and citizens. They must be expunged.": "光能者正在这颗星球上大肆扩张,掠夺我们的拓殖地和公民。必须将它们彻底清除。", + "\"My Son Was An Automaton Sympathizer.\" One Mother's Valiant Choice To Turn In Her Son.": "“我儿子同情机器人”——女子大义灭亲,举报亲生儿子", + "#V_ONE stratagem is temporarily available to all Helldivers.": "#V_ONE战略配备可暂时供所有绝地潜兵使用。", + "SEAF Fight Against Bots Augmented By Limited Helldiver Operations.": "绝地潜兵的局部行动助力超级地球武装部队扩张抗击机器人的规模", + "The prosperous Meridia was corrupted into a Terminid Supercolony, necessitating its destruction using the mysterious Dark Fluid. This galactic scar is all that remains.": "曾经欣欣向荣的默里迪亚沦为终结族超级拓殖地,不得不使用神秘的暗液体将其摧毁。如今唯有这道银河系的疤痕,昭示着它曾经的存在。", + "INVASION LEVEL": "入侵等级", + "Temporary magazine increase no longer in effect.": "弹匣数量临时增加的效果结束。", + "All Orbital Stratagems have an increased cooldown.": "所有轨道武器战略配备都会延长冷却时间。", + "An Automaton unit equipped with flame throwers and incendiary ammunition is active on this planet. Prepare to face wanton arsonists who will not rest until they have razed all that humankind holds dear.": "装备火焰喷射器和燃烧弹药的机器人部队正在该星球上肆虐横行。请做好准备,应对肆无忌惮的纵火犯,他们唯有将人类珍视的一切烧为灰烬,才肯善罢甘休。", + "THE INCINERATION CORPS": "炽灼部队", + "New 3D-Printed Assault Rifle Can Defensively Slaughter Up To 30 Bugs/Second.": "新型3D打印突击步枪每秒可以防御性击毙30只虫族", + "Shield Generator Relay stratagem availability has ended.": "现已无法使用“防护罩生成中继器”战略配备。", + "The Great Host of the Illuminate is flooding this planet. Their numbers must be thinned.": "光能者大军正席卷这颗星球。必须削减敌方兵力。", + "TERRITORY CLAIMED": "领地已收复", + "Experience gain for all Helldivers is temporarily increased by #V_ONE%.": "所有绝地潜兵获得的经验值暂时增加#V_ONE%。", + "Cooldown period for #V_ONE stratagem reduced by #V_TWO.": "#V_ONE战略配备的冷却时间缩短#V_TWO。", + "Ecological Disaster or Economical Blessing? Space Tanker Crash": "生态灾难还是经济机遇?太空运输船相撞", + "LIVE FEED": "即时动态", + "MEGAFACTORY LIBERATION PROGRESS": "超大型工厂解放进度", + "#V_ONE available to all Helldivers.": "#V_ONE可供所有绝地潜兵使用。", + "from": "from", + "High-priority campaigns contain unique missions related to the current Major Order. Super Earth will liberate High-priority campaign planets just like Liberation campaigns.": "首要战役包含与当前重要指令相关的特殊任务。与解放战役一样,超级地球将解放首要战役的目标星球。", + "AVERAGE": "中等", + "Repel": "击退", + "SMOKE-ENHANCED WALKING BARRAGE": "烟幕增强型游走火力网", + "CONTESTED ORBIT": "竞相争夺的轨道", + "INCENDIARY GATLING BARRAGE": "燃烧加特林火力网", + "VOID INTERFERENCE": "寂域干扰", + "MISSION SITE": "任务地点", + "Detonates in:": "引爆倒计时:", + "University of Super Earth Adopts New Standardized Patriotism Test For Admissions": "超级地球大学入学考试采用新版标准化爱国主义测验", + "The nearby Gloom Base's logistics fleet supports operatives on this planet, counteracting all negative effects of the Gloom.": "附近“阴霾”基地的后勤舰队为这颗星球上的作战人员提供支援,希望能抵消“阴霾”带来的所有负面影响。", + "CITY DEFENSE STATUS": "城市保卫状态", + "We are passively re-gaining ground on Planet #V_ONE.": "我们正在被动夺回#V_ONE星球的阵地。", + "HIGH-PRIORITY CAMPAIGN PROGRESS": "首要战役进度", + "on": "on", + "More Contestants of \"What Planet Am I Standing on or We'll": "《行星猜猜猜,猜错送你来》", + "ORBITAL DEFENSES": "轨道防御", + "Cooldown period for #V_ONE stratagem is temporarily increased by #V_TWO.": "#V_ONE战略配备的冷却时间暂时延长#V_TWO。", + "METEOR STORMS": "流星风暴", + "CAMPAIGN STATUS": "战役状态", + "#GRADE (#PERCENT%)": "#GRADE (#PERCENT%)", + "GALACTIC WAR UPDATE": "星系战争更新", + "Cooldown period decrease for #V_ONE stratagem no longer in effect.": "#V_ONE战略配备冷却时间缩短的效果结束。", + "Watch: A Helldiver Returns To His Robo-Canine Partner After 4-year Deployment.": "观察:绝地潜兵执行任务4年终于回到机器狗伴侣身边", + "A frozen world covered in ice that is broken only by reddish rock and spongy moss.": "冰天雪地的寒冷星球,间或可见浅红色的岩石与海绵般的苔藓。", + "PLANET": "星球", + "#V_ONE stratagem is once again available (if purchased).": "#V_ONE战略配备再次供应(如已购买)。", + "Unlocks new discoverable samples and enemy types.": "解锁全新可供探索的样本和敌人类型。", + "Number of uses of #V_ONE stratagem increased by #V_TWO.": "#V_ONE战略配备的可用次数增加#V_TWO。", + "The MG-43 Machine Gun stratagem is temporarily available to all Helldivers.": "“MG-43机枪”战略配备可暂时供所有绝地潜兵使用。", + "EMPTY SLOT": "空槽", + "Dense sandstorms reduce visibility.": "铺天盖地的沙暴会降低能见度。", + "Ministry of Science Officials Identify Unprecedented Mass Production Technology in Use by Automatons.": "科学部官员发现机器人在使用前所未见的量产技术", + "Surveying unexplained spacetime fluctuations": "勘测无法解释的时空波动", + "AMMO SURPLUS": "弹药过剩", + "OPERATION FAILED": "行动失败", + "Receiving Geodetic Data...": "正在接收大地测量数据……", + "Stim capacity for all Helldivers increased by #V_ONE on all planets.": "所有星球上的所有绝地潜兵的治疗剂容量增加#V_ONE。", + "New Study Finds Patriotism To Be ##1 Predictor Of Happiness, Longevity, Weight Loss.": "最新研究发现爱国情怀是幸福、长寿和减肥的首要前提", + "Proximity to Source Planet": "靠近源头星球", + "The Source planet holds a unique and unknowable structural role in the Void space. Deal with the Source planet to return the abducted planets to where they belong and expel this Void region from the galaxy.": "源头星球在寂域中扮演着独特而又难以解明的结构性作用。妥善处理源头星球,就能让遭到劫持的星球重返原位,彻底抹除这片寂域,还银河系一片清朗。", + "Dense, toxic fumes from deep within the planet's crust seep out of cracks in the earth and coat the ground in a sickly haze.": "这颗星球地壳深处的有毒浓烟透过地表的裂隙渗透出来,形成了令人作呕的雾霾。", + "\"Enter Now for a Chance to Win Front-Row Tickets to The Freedomball Galactic Cup!\"": "立刻参加即有机会获得自由球星系杯比赛前排门票!", + "Melee damage is temporarily increased by #V_ONE%.": "近战伤害暂时提高#V_ONE%。", + "CIVILIANS & SEAF IN AREA": "区域内有平民和超级地球武装部队", + "SEAF REINFORCEMENTS": "超级地球武装部队的增援", + "LOW RECRUITMENT": "一卒难求", + "#PLANET CITIES": "#PLANET城市", + "Primary Objectives": "主要目标", + "Automatons \"No Match\" for Helldivers, Says Ministry of Defense Official.": "国防部官员称机器人“完全不敌”绝地潜兵", + "Tesla Tower stratagem availability has ended.": "现已无法使用“特斯拉塔”战略配备。", + "Personal Orders are completed by Helldivers individually, and change every day in response to the shifting battlefield.": "个人指令由绝地潜兵单独完成,而且每天都会根据战场局势而改变。", + "HOLD FOR PLANET TRANSIT": "长按开始星际传输", + "Cooldown period for #V_ONE stratagem increased by #V_TWO.": "#V_ONE战略配备的冷却时间延长#V_TWO。", + "Medal payout per mission for all Helldivers increased by #V_ONE.": "所有绝地潜兵每次任务的奖章收益增加#V_ONE。", + "Completing this Operation helps hold this city. Successfully holding cities significantly contributes to the planet's Defense.": "完成此次行动有助于保卫这座城市。成功保卫城市将大幅推动星球防御进程。", + "OPERATION SUCCESSFUL": "行动成功", + "VERY HIGH": "极高", + "EXPLOSIVES SURPLUS": "爆炸品过剩", + "Automaton Sympathizers Killed in Breathtaking Raid; Collateral Damage Heroically Minimized.": "星系大突查,同情机器之人消灭无数;潜兵好英勇,连带伤害微乎其微", + "AMMO SHORTAGE": "弹药短缺", + "E-711 is only found on Hive Worlds. The exotic substance is critical to the maintenance of galactic security. It must be secured, no matter the risk.": "711元素只能在虫窝世界里找到。这种异域物质对维持银河系的安全非常关键。无论风险多大,都必须确保拿到这些资源。", + "Falling sand reduces visibility.": "沙尘从天而降会降低能见度。", + "OFFENSIVE ADVANTAGE": "进攻优势", + "To Any Citizen Who's Lost a Home Thanks to Enemy Activity, We Say:": "如果你的家园毁于敌人手中,没有关系", + "ACID STORMS": "酸雨风暴", + "HIGH RECRUITMENT": "广纳千军", + "Tactical Map Disrupted": "战术地图受到干扰。", + "LEVIATHAN BLOCKADE": "利维坦封锁屏障", + "SUDDEN SPAWNING": "幼虫孵化激增", + "CHALLENGING": "充满挑战", + "Enemy Strongholds": "敌方要塞", + "Planet #V_ONE, on the verge of falling to the enemy, has been successfully defended.": "我们成功守住了濒临沦陷的#V_ONE星球。", + "Super Earth will not liberate Recon campaign planets, but they will remain available as long as the sector is active.": "超级地球不会解放侦察战役中的星球,但只要该分区坚持反抗,这些星球就仍有希望。", + "The Ballistic Shield Backpack stratagem is temporarily available to all Helldivers.": "“防弹护盾背包”战略配备可暂时供所有绝地潜兵使用。", + "CITY": "城市", + "MEDICAL SUPPLY STRAIN": "医疗补给紧张", + "Brief But Totally Not Worrying Illuminate Brain Takeover": "所幸时间较短,不足为虑", + "Time to complete all missions increased by #V_ONE%.": "完成所有任务的时间延长#V_ONE%。", + "Operation Valiant Enclosure Proceeding \"As Expected\" According to MOD Report.": "国防部报告称英勇围合行动“如期”推进", + "FRIENDS: #VALUE": "好友:#VALUE", + "Tactical Objectives Increase": "战术目标增加", + "The Helldivers must liberate this planet before time runs out. Failure will have severe consequences.": "绝地潜兵必须在时间结束前解放这颗星球。如果失败,后果将不堪设想。", + "Unknown Name": "未知名称", + "Melee damage increase no longer in effect.": "近战伤害提高的效果结束。", + "New Study Shows Illuminate Terror Lurks Around Every Corner And Citizens Can Never Be Too Vigilant.": "最新研究表明光能者的威胁无处不在,星系公民应当格外警惕", + "#V_ONE Booster is automatically active for all missions.": "#V_ONE强化资源在全部任务中自动激活。", + "Number of stims each Helldiver deploys with decreased by #V_ONE.": "每位绝地潜兵上阵时配给的治疗剂数量减少#V_ONE。", + "HARD": "困难", + "ILLUMINATE INVASION": "光能者入侵", + "HIDE HEROES OF SUPER EARTH": "隐藏超级地球英雄", + "Unexpected SEAF reinforcements have taken significant ground on Planet #V_ONE.": "意料之外的超级地球武装部队增援力量在#V_ONE星球上占领了重要阵地。", + "#V_ONE stratagem is temporarily unavailable to all Helldivers.": "所有绝地潜兵暂时都不能使用#V_ONE战略配备。", + "Extraction time reduction no longer in effect.": "撤离时间缩短的效果结束。", + "LOW": "低", + "Orbital Airburst Strike stratagem availability has ended.": "现已无法使用“轨道空爆攻击”战略配备。", + "The Eagle Airstrike stratagem is temporarily available to all Helldivers.": "“‘飞鹰’空袭”战略配备可暂时供所有绝地潜兵使用。", + "The strange subversion of photosynthesis that sustains the oddly-hued flora that flourishes on this planet remains an intriguing mystery to Super Earth's greatest exo-biologists.": "这颗星球颠覆性的神奇光合作用是如何让这里色调奇特的植物群维持生长?超级地球最出色的外星生物学家至今仍未解开此谜团。", + "Causes Element 710 Rain Over HydroFall Prime": "致710元素洒遍水瀑主星", + "INCOMING MESSAGE FROM SUPER EARTH": "来自超级地球的信息", + "Mobilized in:": "动员倒计时:", + "#V_ONE effectiveness increase no longer in effect.": "不再提升#V_ONE的效果。", + "#SECTOR": "#SECTOR", + "SUCCESS": "成功", + "Periods of high temperatures increase stamina drain and speed up heat buildup in weapons.": "酷热时段会增加耐力消耗,也会加快武器升温速度。", + "Stim capacity for all Helldivers decreased by #V_ONE on this planet.": "在此星球上的所有绝地潜兵的治疗剂容量减少#V_ONE。", + "GLOOM RESEARCH PROGRESS": "“阴霾”研究进展", + "Legion": "军团", + "FORCES IN RESERVE": "预备部队", + "Number of reinforcements available per mission is temporarily increased by #V_ONE.": "每次任务的可用增援数暂时增加#V_ONE。", + "E-711 EXTRACTED": "已提取的711元素", + "Eagle Airstrike stratagem availability has ended.": "现已无法使用“‘飞鹰’空袭”战略配备。", + "Destroy": "摧毁", + "Cyborgs are deployed to the battlefield of this planet, leading their Automaton armies. Expect to encounter vile propagandists trained in both ranged and melee combat.": "生化人已部署至该星球战场,率领机器人大军作战。请做好准备,应对经过远近战双重训练的卑劣宣传机器。", + "ATMOSPHERIC STERILIZATION": "大气灭菌", + "HIGHER STIM CAPACITY": "更大治疗剂容量", + "Though the nearby Gloom Base provides logistical support, the spore cover on this planet is heavy enough to cause issues for all landing Pelicans.\nExtraction times are increased by 20 seconds.": "虽然附近的“阴霾”基地能够提供后勤支援,但这颗星球上的孢子密度过高,令所有的“鹈鹕”难以降落。\n撤离时间延长20秒。", + "SEAF UNITS IN AREA": "区域内有超级地球武装部队", + "SUPPLY CHAIN CHALLENGES": "补给链挑战", + "OPERATIONAL VARIATIONS": "行动变量", + "This once-beautiful planet has been twisted into a hive of tyranny, corrupted beyond recognition by the ravenous spread of the Terminids.": "这颗曾经美丽的星球被扭曲为暴政的巢穴,在终结族的贪婪扩张下面目全非。", + "ESTIMATED TO FALL IN": "预计沦陷时间:", + "Time to complete all missions is temporarily reduced by #V_ONE%.": "完成所有任务的时间暂时缩减#V_ONE%。", + "Reinforcement reduction is no longer in effect.": "可用增援数减少的效果结束。", + "Spacetime Fluctuation Indicator": "时空波动指示器", + "Grenade increase no longer in effect.": "榴弹数量增加的效果结束。", + "Daredevil Felix Bressler Freefalls 2.8 Billion Miles From Neptune to Super Earth": "冒险勇士菲力克斯·布莱斯勒从海王星到超级地球自由落体28亿英里", + "TRACKING: ACTIVE HELLDIVER SQUADS": "正在追踪: 正在行动的绝地潜兵小队", + "Submerged in eternal winter, this world's frosty peaks glimmer in the light of its too-distant star.": "这颗星球处于永恒的寒冬之中。星球上冰冷的山峰隐约反射着遥不可及的恒星之光。", + "OPERATIONAL SUPPORT": "行动支持", + "Light Outposts": "轻型哨站", + "Experience gain decrease no longer in effect.": "经验值减少的效果结束。", + "Orbital Railcannon stratagem availability has ended.": "现已无法使用“轨道炮”战略配备。", + "Number of magazines Helldivers deploy with for all weapons increased by #V_ONE.": "绝地潜兵上阵时配给的所有武器弹匣数量增加#V_ONE。", + "ACQUIRED E-711": "已获取711元素", + "SHOW ORDERS": "显示指令", + "The Mortar Sentry stratagem is temporarily available to all Helldivers.": "“迫击哨戒炮”战略配备可暂时供所有绝地潜兵使用。", + "EXPERIMENTAL BOOSTER": "实验性强化资源", + "Evacuated in:": "撤离倒计时:", + "The presence of the DSS near this planet provides a -35% cooldown reduction to all Exosuit stratagems.": "DSS停靠在这颗星球附近,可使所有外骨骼装甲战略配备冷却时间缩短35%。", + "The LAS-98 Laser Cannon stratagem is temporarily available to all Helldivers.": "“LAS-98激光大炮”战略配备可暂时供所有绝地潜兵使用。", + "REV PERIOD: #VALUE YEARS": "公转周期: #VALUE年", + "ENEMY THREAT DETECTED": "侦测发现敌方威胁", + "RECON CAMPAIGN PROGRESS": "侦察战役进度", + "HONOR THE FALLEN": "缅怀烈士", + "LIBERATION EVENT PROGRESS": "解放战役进度", + "GRENADE POUCH SHORTAGE": "榴弹袋短缺", + "Enemies Killed": "击败敌人数", + "Extraction time against the Terminids is #V_ONE seconds slower.": "对阵终结族时的撤离时间减慢#V_ONE秒。", + "The pure fountain from which Managed Democracy springs forth. It must be defended at all costs.": "孕育出管理式民主之花的沃土。必须不计代价保卫其存续。", + "Local Overseer of Mine 306.7D Found Dead in Sizzle-Fish Smuggling Incident.": "嗞啦鱼走私事件306.7D矿井矿长身亡", + "APPROPRIATORS": "占领者", + "ATMOSPHERIC INTERFERENCE": "大气干扰", + "Flying Leviathan warships patrol the battlefield.": "战场上空有利维坦战舰在巡逻。", + "Dissident Sabotage Blamed For Spike In Aluminum Prices": "异见分子大搞破坏致使铝价飙升", + "ENEMIES KILLED: #VALUE": "杀敌数:#VALUE", + "SAR-1 Sniper Rifle stratagem availability has ended.": "现已无法使用“SAR-1狙击步枪”战略配备。", + "COMBATANT FORCES PRESENT": "存在武装力量", + "PERSONAL ORDER": "个人指令", + "Stratagem cooldown increased by #V_ONE%.": "战略配备的冷却时间增加#V_ONE%。", + "New Study Concludes Male Pattern Baldness a Patriotic Sign of Hair's Freedom to Leave Head.": "最新研究发现男性脱发系头发自由脱离头部的爱国表现", + "Season Premiere of \"Surviving the Galactic\" Strands 18 Citizens on Kryx's Ice Moon For 39 Days": "《星系求生》本季首播导致18名公民滞留克里克斯冰质卫星39天", + "The presence of the Void cuts off communication with your Destroyer.": "由于寂域的存在,我们无法与你的驱逐舰建立通讯。", + "The oases that bespeckle this desert planet present the closest approximation of tranquility one can find this far from Super Earth.": "在这颗沙漠星球上,只有零星点缀的绿洲能让人回想起远方的超级地球,获得片刻宁静。", + "Objective locations are hidden.": "隐藏目标地点。", + "Stratagem slots reduced by #V_ONE.": "减少#V_ONE个战略配备槽位。", + "MEDICAL SUPPLY SURPLUS": "医疗补给过剩", + "RAINSTORMS": "暴雨", + "Completing this operation has an impact on the Illuminate Fleet Strength.": "完成此次行动将影响光能者舰队战力。", + "Complete operations in #SECTOR": "在#SECTOR完成行动", + "LESS BATTLEFIELD AMMO": "战场弹药减少", + "An operation is a collection of missions. Complete all missions to succeed with an operation and gain bonus rewards. Failing one mission will fail the rest of the operation.": "行动包含一系列任务。完成所有任务即表示行动成功,你将获得额外奖励。只要一项任务失败,此次行动就算失败。", + "HIGH-PRIORITY CAMPAIGN": "首要战役", + "The FLAM-40 Flamethrower stratagem is temporarily available to all Helldivers.": "“FLAM-40火焰喷射器”战略配备可暂时供所有绝地潜兵使用。", + "The Orbital Walking Barrage is experimentally modified to have smoke rounds mixed into its salvos.": "轨道游走火力网经实验性调整,在齐射弹中混入了烟幕弹。", + "Until further notice, all Helldivers will passively regenerate health at a rate of #V_ONE% per second.": "所有绝地潜兵暂时以每秒#V_ONE%的速度被动恢复生命值,直至另行通知为止。", + "SUICIDE MISSION": "玩命任务", + "Automatons Invasion Force Constitutes \"Grave Threat\" to Super Earth.": "机器人侵略军“严重威胁”超级地球", + "New Poll Ranks Erson Sands As Best Place To Raise Kids To Be Defenders Of Freedom.": "最新民调结果显示厄尔森桑兹星系最适合家长培养自由卫士", + "For the near future, each successful mission will contribute more to planetary liberation.": "近期内,每一次成功完成任务都将为行星解放事业带来更大的助力。", + "On this planet, a network of Termicide-dispensing towers repels Terminids emerging from the Gloom.": "在这颗星球上,喷洒灭虫终结剂的高塔网络抵御着源自“阴霾”的终结族。", + "For the near future, ground will be passively re-gained on Planet #V_ONE.": "近期内,我们将被动夺回#V_ONE星球的阵地。", + "to": "to", + "Automaton Invasion Shows No Signs Of Losing Steam.": "机器人侵略尚无止步迹象", + "ILLUMINATE INVASION PROGRESS": "光能者入侵进度", + "Protect": "保护", + "EXPERIMENTAL HIP POUCHES": "实验性腰包", + "Orbital Walking Barrage stratagem availability has ended.": "现已无法使用“轨道游走火力网”战略配备。", + "Defense Campaigns cannot originate from this planet.": "此星球无法发起保卫战役。", + "HIGH": "高", + "Abundant with life, this wet planet is covered in deep oceans, thick forests, and tall grasses.": "这颗湿润的星球既有深海,也有郁郁葱葱的森林和草原,充满了生命的气息。", + "MORE BATTLEFIELD AMMO": "战场弹药增加", + "GLARBLE GARB GORK! News Headline Writer Experiences": "叽里呱啦噜!光能者入侵新闻头条写手大脑", + "MAJOR ORDER": "重要指令", + "Grenade capacity for all Helldivers is temporarily decreased by #V_ONE.": "所有绝地潜兵的榴弹容量暂时减少#V_ONE。", + "Orbital Precision Strike stratagem availability has ended.": "现已无法使用“轨道精准攻击”战略配备。", + "ROT PERIOD: #VALUE DAYS": "自转周期: #VALUE天", + "EXPERIMENTAL VITAMINS": "实验性维他命", + "Helldivers Continue Valiant Fight To Contain Terminids.": "绝地潜兵仍在英勇遏制终结族", + "The main invasion fleet of the Illuminate, from arrogant Overseers to throngs of brainwashed Super Earth civilians, are present on this planet. Exterminate on sight or else risk violent resistance, or worse, treasonous propaganda.": "光能者主力入侵舰队已降临该星球,既有傲慢的监视者,也有成群结对、遭到洗脑的超级地球公民。一旦发现,立即击杀,否则将面临暴力的抵抗,甚至遭遇叛国宣传。", + "TCS INSTALLATION PROGRESS": "TCS建设进度", + "This planet is under attack. The Helldivers must defend it against the forces of tyranny.": "这颗星球遇袭。绝地潜兵必须保卫星球,抵御暴政军队。", + "Helldivers Ordered to Prepare Terminid Cordon Planets for \"Purge\".": "绝地潜兵奉命准备“净化”部署终结族封锁线的星球", + "New Poll Ranks Terminids As \"Most Buglike\" Of Super Earth's Enemies.": "最新民调结果显示大众认为终结族是超级地球“最像虫子”的敌人", + "Gloom particles interfere with landing Pelicans, increasing extraction times by 20 seconds.": "“阴霾”粒子干扰“鹈鹕”运输机着陆,撤离时间延长20秒。", + "SURGE PRODUCTION": "机械产量激增", + "Intense snowstorms reduce visibility.": "强暴风雪会降低能见度。", + "CLASS 2 MEGAFACTORY": "2级超大型工厂", + "Intense blizzards reduce mobility and moderately reduce visibility for both enemy and friendly units.": "强暴风雪会削弱行动能力并中度降低能见度,敌我双方都将受影响。", + "DRAGONROACHES": "蟑龙", + "DEFENSE CAMPAIGN": "保卫战役", + "VOLCANIC ACTIVITY": "火山活动", + "MEGAFACTORY OPERATION": "超大型工厂行动", + "LIBERATION UNDERWAY": "解放进行时", + "ORDER OVERVIEW": "指令概览", + "Extraction time on this planet is #V_ONE seconds faster on this planet.": "在此星球上的撤离时间加快#V_ONE秒。", + "Depending on the war progress, different planets will be available. Select a planet to see what operations are active on it.": "可参与行动的星球会随战争局势而变。选择一颗星球,看看上面正在部署哪些行动。", + "FIELD PROMOTIONS": "战地晋升", + "Democratize": "民主解放", + "The DSS activates its highly experimental Atmospheric Autoclave, killing 50 km³ of Gloom Spores per minute. The reduced spore cover exposes photosensitive Terminid variants to atmospheric UV radiation.": "DSS启动仍在实验阶段的大气高压灭菌器,每分钟可消灭50立方千米的“阴霾”孢子。孢子层减少,使部分对光敏感的终结族亚种暴露在大气紫外线辐射下。", + "The TS-4 Arc Thrower stratagem is temporarily available to all Helldivers.": "“ARC-3电弧发射器”战略配备可暂时供所有绝地潜兵使用。", + "Unexpected SEAF reinforcements are taking significant ground on Planet #V_ONE.": "意料之外的超级地球武装部队增援力量正在#V_ONE星球上占领重要阵地。", + "BATTLE ROYALE: Bugs vs. Automatons": "绝地乱斗:虫族对机器人", + "The Illuminate are deploying only their own kind to this planet, a clear indication of the operation's importance and/or xenophobic nature. Prepare to face foot soldiers, drones, and piloted mechanical constructs.": "光能者部署在这颗星球上的只有同族,这抑或说明此次行动至关重要,抑或暴露出他们排外的本性。准备迎击他们的步兵、无人机以及操作型机械体。", + "Allied SEAF units are operating on the battlefield.": "超级地球武装部队友军正在战场上作战。", + "PROTEIN SHORTAGE": "缺乏蛋白质", + "ILLUMINATE CONTROL": "由光能者控制", + "COMPLEX STRATAGEM PLOTTING": "复杂的战略配备部署流程", + "Temporary stim increase no longer in effect.": "治疗剂数量临时增加的效果结束。", + "New Study Finds Super Eagle to be Most Democratic Bird.": "最新研究发现超级雕为最民主的鸟类", + "INSPIRED LABORERS": "劳动者觉醒", + "TERMINID CONTROL": "由终结族控制", + "LAS-98 Laser Cannon stratagem availability has ended.": "现已无法使用“LAS-98激光大炮”战略配备。", + "Number of uses of #V_ONE stratagem is temporarily reduced by #V_TWO.": "#V_ONE战略配备的可用次数暂时减少#V_TWO。", + "Constant eruptions keep this planet covered in lava flows and utterly inhospitable to Democratic life. It also makes it a treasure trove of rare minerals.": "火山持续喷发,导致这颗星球被熔岩流覆盖,完全不适宜民主生命居住。但这里也因此成为稀有矿物的宝库。", + "Extraction time temporarily decreased by #V_TWO seconds.": "撤离时间暂时缩短#V_TWO秒。", + "Each successful mission contributes more to planetary liberation.": "每一次成功完成任务都会为行星解放事业带来更大的助力。", + "Dense fog reduces visibility.": "浓雾会降低能见度。", + "Child Finds Toy Battleship She Lost In Black Hole 6 Years From Now.": "儿童发现自己6年后无意落入黑洞的玩具战舰", + "Secondary Objectives": "次要目标", + "VOID GATEWAY": "寂域通路", + "Cyberstan Identified as Center of Automaton Command.": "已发现生化斯坦是机器人指挥中枢", + "HIVE LORDS": "霸王虫", + "#SHORT - #LONG": "#SHORT - #LONG", + "Eagle Rearm time is #V_ONE% slower.": "重新武装“飞鹰”的时间减慢#V_ONE%。", + "FINAL CHARGE": "力挽狂澜", + "Multiple citizens report having same dream of unseen tentacled mass lurking in shadowy depths": "多名平民报告称做了同一个梦:在幽暗的深处,潜伏着一团看不见的触手状巨物。", + "COLONY OPERATION REWARD": "拓殖地行动奖励", + "Grenade capacity for all Helldivers decreased by #V_ONE.": "所有绝地潜兵的榴弹容量减少#V_ONE。", + "Execution By Black Hole Spaghettification Ruled Constitutional": "最高法院判黑洞面条化死刑符合宪法", + "Extraction time on this planet is #V_ONE seconds slower on this planet.": "在此星球上的撤离时间减慢#V_ONE秒。", + "PLANET EVENTS": "星球战事", + "Flying Shrieker swarms traverse the battlefield.": "飞空尖啸虫群会穿过战场。", + "OPERATION REWARD": "行动奖励", + "The Orbital 120mm HE Barrage is experimentally modified with additional HE rounds, EMS rounds, and a tighter radius.": "轨道120mm高爆弹火力网经实验性调整,增加了额外高爆弹与电磁电磁冲击弹,并缩小了效果范围半径。", + "Grenade decrease no longer in effect.": "榴弹数量减少的效果结束。", + "Progress in Liberation Campaigns is accelerated.": "在解放战役中的进展加速。", + "Major Orders represent the goals of the Helldiver Community.": "重要指令是绝地潜兵社区的共同目标。", + "Exterminate": "消灭", + "An unanticipated Terminid surge has taken significant ground on Planet #V_ONE.": "突如其来的终结族激增势力在#V_ONE星球上占领了重要阵地。", + "Student Group Carries Out Public Deletion of Undemocratic E-Books": "学生团体开展公共活动,当众删除非民主电子书籍", + "LIBERTY DAY CELEBRATION": "解放日庆典", + "EXTREME COLD": "极寒", + "HELLPODS ACTIVE - PROCEED TO HELLPODS": "绝地喷射舱已启动 - 前往绝地喷射舱", + "#V_ONE stratagem availability has ended.": "现已无法使用#V_ONE战略配备。", + "SUPER EARTH CONTROL": "由超级地球控制", + "AT-48 Recoilless Rifle stratagem availability has ended.": "现已无法使用“AT-48无后坐力步枪”战略配备。", + "A rocky, lonely moon with extremely valuable mineral deposits underneath the surface.": "崎岖不平的孤单卫星,地下埋着极其珍贵的矿产。", + "Defense Wall stratagem availability has ended.": "现已无法使用“防御墙”战略配备。", + "Experience gain for all Helldivers reduced by #V_ONE%.": "所有绝地潜兵获得的经验值减少#V_ONE%。", + "Cooldown period for #V_ONE stratagem is temporarily reduced by #V_TWO.": "#V_ONE战略配备的冷却时间暂时缩短#V_TWO。", + "Effects are temporary alterations to battlefield conditions. They change as the war develops, and may force Helldivers to adapt their tactics.": "效果是因应战场状况临时变更的条件,会随着战争局势的发展而变化,可能迫使绝地潜兵调整战术。", + "Ground will no longer be passively re-gained on Planet #V_ONE.": "我们不再被动夺回#V_ONE星球的阵地。", + "Orbital Laser stratagem availability has ended.": "现已无法使用“轨道激光炮”战略配备。", + "Extraction time against the Terminids is #V_ONE seconds faster.": "对阵终结族时的撤离时间加快#V_ONE秒。", + "MEGA CITY": "特大城市", + "KIA: #VALUE": "阵亡:#VALUE", + "COLONY OPERATION": "拓殖地行动", + "ENEMY FORCE": "敌方势力", + "Melee damage increased by #V_ONE%.": "近战伤害提高#V_ONE%。", + "Geneticist Killed In Home By Chicken-Cow-Pig Hybrid.": "基因研究人员家中惨遭鸡牛猪杂交生物杀害", + "HEAVY GLOOM SHROUD": "重度“阴霾”笼罩", + "Experience gain increase no longer in effect.": "经验值增加的效果结束。", + "Frequent earthquakes stun players and enemies alike.": "频繁的地震会让玩家和敌人都陷入眩晕。", + "GL-6 Grenade Launcher stratagem availability has ended.": "现已无法使用“GL-6榴弹发射器”战略配备。", + "Super Earth, our home, is the center of Liberty Day Festivities. Together, all citizens can watch on television the annual Defense Parade, the Justice Executions, and of course, the Freedom Fireworks. \n\nOn this special day, Helldivers are encouraged to visit Super Earth and watch this year's fireworks from their Super Destroyers.": "超级地球,我们的家园,是解放日庆典的中心。所有公民都能在电视上观看年度阅兵、正义裁决,当然还有自由烟花秀。\n\n在这特别的日子里,所有绝地潜兵都可以前往超级地球,并在自己的驱逐舰上观看今年的烟花秀。", + "This world teems with ethereal, boundless, and peculiar plant life that spreads silent and uninterrupted across its entire surface.": "这颗星球表面布满了缥缈、奇特的植物,营造出无限蔓延的静谧感。", + "vs. Genetically-Altered Giant Turtles. Tickets on Sale!": "对基因改造的巨龟。门票特惠,售完即止!", + "CLASS 1 MEGAFACTORY": "1级超大型工厂", + "MERITORIOUS COMMENDATIONS": "论功行赏", + "Geneticists Create First Chicken-Cow-Pig Hybrid, Dubbed \"Perfect Meat.\"": "基因研究人员成功培育首个鸡牛猪杂交生物,冠名”完美肉”", + "Effectiveness of #V_ONE increased by #V_TWO%.": "#V_ONE的效果提升#V_TWO%。", + "SEAF units and loyal civilians are both on the battlefield.": "战场上同时发现超级地球武装部队和忠诚平民。", + "the": "the", + "Rocket Sentry stratagem availability has ended.": "现已无法使用“火箭哨戒炮”战略配备。", + "DIFFICULTY LEVEL LOCKED": "难度未解锁", + "MULTIPLE THREATS DETECTED": "侦测发现多个威胁", + "BACK TO GALAXY MAP": "返回星系地图", + "Stop": "制止", + "LAT: #VALUE": "纬度: #VALUE", + "TANK SURGE": "坦克激增", + "The Illuminate are moving the Meridian Singularity toward Super Earth. Anything caught in its path will be torn apart.": "光能者正将默里迪恩奇点移至超级地球。任何挡在其移动轨迹上的东西都将被摧毁。", + "Time to complete all missions reduced by #V_ONE%.": "完成所有任务的时间缩减#V_ONE%。", + "ION STORMS": "离子风暴", + "PLANET LOST - RETREAT ORDER ISSUED": "星球沦陷 - 下令撤退", + "Anti-Personnel Mine Deployer stratagem availability has ended.": "现已无法使用“反步兵地雷部署器”战略配备。", + "ANOMALY LOCATION": "异常地点", + "TOWN": "城镇", + "New Bill Funds Dissident Identification Training For Schoolteachers": "新法案出资开展在校教师异见分子甄别培训", + "Number of reinforcements available per mission increased by #V_ONE.": "每次任务的可用增援数增加#V_ONE。", + "Resupply stratagem availability has ended.": "现已无法使用“重新补给”战略配备。", + "New Study Proves 100% of Super Earth Studies to be Accurate.": "最新研究证实超级地球所有研究结果100%准确", + "Schrödinger's Cat Definitively Determined Dead Following": "核武器试验成功,薛定谔的猫", + "PLANET STATUS UPDATING": "星球状态正在更新", + "Completing this operation contributes to the planet's Defense.": "完成此次行动将推动星球防御进程。", + "#A / #B": "#A / #B", + "LEAVE HOLOGRAM": "退出全息图像", + "Terminid Hive Lords have been detected on this planet. Prepare to face massive burrowing enemies.": "已在这颗星球上探测到终结族的霸王虫。请做好应对巨型钻地敌军的准备。", + "Conquer #PLANET in the #SECTOR": "征服#SECTOR的#PLANET", + "SOURCE PLANET": "源头星球", + "Terminids Threaten To Break Free of Cordon.": "终结族威胁或突破封锁线", + "Planet is ravaged by deadly fire tornados.": "致命的烈焰龙卷在星球上肆虐。", + "NEWS ALERT": "重大新闻", + "Terminid Detterance Network Installation Heavily Delayed by Terminid Swarm Event.": "终结族虫群活动严重阻碍终结族威慑网建设", + "New Study Finds Bots Twice as Authoritarian as Previously Expected.": "最新研究发现机器社会专制程度为此前预期的两倍之多", + "The substance known as E-711 is the key to synthesizing Dark Fluid, an immensely powerful exotic material. Acquiring it is of utmost importance.": "711元素是极其强大的异域物质,也是合成暗液体的关键成分。获取这些元素至关重要。", + "ELECTRONIC COUNTERMEASURES": "电子对抗", + "Health regeneration no longer in effect.": "恢复生命值的效果结束。", + "A crimson algae has propagated wildly across this entire planet, coating its rocky hills with a constant red that masks the spilt blood of the heroes who defend it from tyranny.": "一种深红色的藻类在这颗星球大肆繁殖,嶙峋峭壁也通通被染红,掩盖了抵抗暴政的英雄在此洒下的热血。", + "HELLDIVE": "绝境", + "Number of reinforcements available per mission decreased by #V_ONE.": "每次任务的可用增援数减少#V_ONE。", + "BRIEF": "简报", + "Scorching temperatures, high winds, and low precipitation cause a near-constant cycle of fires to sweep this planet, punctuated by short bursts of lush rebirth between infernos.": "酷热、强风和稀少的降水导致席卷这颗星球的烈火灾害几乎从未间断,茂密复生的绿色植被在这个炼狱里只有极其短暂的喘息之机。", + "SHOW HEROES OF SUPER EARTH": "显示超级地球英雄", + "SEAF COUNTEROFFENSIVE": "超级地球武装部队的反攻", + "Children's Hospital Explosion Linked to Automaton Sympathizer Group \"Innominate.\"": "儿童医院发生爆炸,事件与亲机器人组织“无名”存在关联", + "Highly Anticipated Battle of Malavax Prime To Be Broadcast Live - Buy Tickets Here.": "万众期待的马拉瓦克斯主星战役现场直播,门票此处购买", + "VERY HARD": "极难", + "INDIRECT FIRE EXERCISE": "间接火力演练", + "#TEXT": "#TEXT", + "Defend against #COUNT attacks in the #SECTOR": "在#SECTOR抵御#COUNT次袭击", + "": "次数:", + "HERD THINNING": "削减虫群", + "in multiplayer": "模式:多人游戏", + "": "次数:", + "WEAPONS QUALIFICATION": "武器资质", + "#COUNT kills with turret stratagems": "利用炮台战略配备完成#COUNT次击杀", + "#SPEAKER #TEXT": "#SPEAKER #TEXT", + "LETHALITY REVIEW": "杀伤力鉴审", + "": "", + "War - #HOURS:#MINUTES:#SECONDS": "战争 - #HOURS:#MINUTES:#SECONDS", + "PILOT WEAPONS TRAINING": "飞行员武器训练", + "Outposts": "哨站", + "Career: Kill #COUNT enemies": "生涯:击杀#COUNT名敌人", + " times": "", + "#NAME Rank #COUNT": "#NAME 级别#COUNT", + " times": "", + "Defend #PLANET against #COUNT attacks by #RACE": "保卫#PLANET,击退#COUNT次#RACE的进攻。", + "DAILY ORDER": "日常指令", + "During a mission deplete #REF": "在一次任务中耗尽#REF", + "Repel #COUNT invasions by #RACE": "击退#COUNT#RACE的入侵。", + "Repel #COUNT Illuminate invasions on #PLANET": "在#PLANET上击退#COUNT次光能者的入侵", + "Request #REF stratagem #COUNT times": "请求#REF战略配备#COUNT次", + "Kill #COUNT heavy or massive enemies": "击杀#COUNT名重型武装或体型庞大的敌人", + "from the planet ": "星球:", + "FOCUSED STRATEGY": "重点战略", + "Play #COUNT #OBJ#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI.": "参与#COUNT次#OBJ。#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI", + "Enemy": "敌人", + "Community-Target Mission": "社区目标任务", + "Liberate #LOCATION": "解放#LOCATION", + "Achieve a #COUNT star rating on a Horde mission": "在一次群袭任务中达成#COUNT星评价", + "Detonate #COUNT Automaton Lieutenant fuel tanks": "引爆#COUNT个机器人中尉的燃料罐", + "or higher": "或以上", + "Get 10 kills with a single #REF #COUNT times": "仅使用#REF一次击杀10名敌人#COUNT次", + "Kill #COUNT Bug Striders": "击杀#COUNT只虫族的阔步虫", + "Complete a difficulty #COUNT or higher mission without taking any damage": "在没有受到任何伤害的情况下完成难度系数为#COUNT或以上的任务", + "RESEARCH INITIATIVE": "研究倡议", + "CAPABILITY DISRUPTION": "军事力量干扰", + "#COUNT kills with orbital stratagems": "利用轨道战略配备完成#COUNT次击杀", + "Weekly": "每周", + "on a planet controlled by the ": "星球势力:", + "Kill #COUNT Bug Alpha Chargers": "击杀#COUNT只虫族的领头强袭虫", + "Use #COUNT stratagems": "使用#COUNT次战略配备", + "Complete #COUNT difficulty 6+ missions": "完成#COUNT场难度系数为6以上的任务", + "Enemies": "敌人", + "Use #COUNT supply stratagems": "使用#COUNT次补给战略配备", + "Defend against #COUNT attacks on any planet": "在任意星球上抵御#COUNT次袭击", + "Use the #ITEM#COUNT_PRE#COUNT#COUNT_POST#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI.": "使用#ITEM。#COUNT_PRE#COUNT#COUNT_POST#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI", + "Kill #COUNT enemies with Hellpods": "利用绝地喷射舱击杀#COUNT名敌人", + "Hold #LOCATION when the order expires": "指令过期后,坚守#LOCATION", + "": "", + "on the planet ": "星球:", + "Use #COUNT orbital stratagems": "使用#COUNT次轨道战略配备", + "Complete an Operation#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST": "顺利完成行动。#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST", + "FORCED DECOMMISSIONING": "强制报废", + "Use #COUNT defensive stratagems": "使用#COUNT次防御战略配备", + "Personal Order": "个人指令", + "from any ": "星球势力:", + "Spend #COUNT Credits on stratagems": "为战略配备花费#COUNT货币", + "STRAIN CULLING": "斩草除根", + "PRIORITY MESSAGE FROM SUPER EARTH HIGH COMMAND": "来自超级地球最高指挥部的高优先级信息", + "Kill #COUNT enemies on a mission": "在一次任务中击杀#COUNT名敌人", + "Kill #COUNT enemies with Eagle stratagems": "利用“飞鹰”战略配备击杀#COUNT名敌人", + "Extract from a mission with at least #COUNT sample(s)": "从一次任务中携带至少#COUNT份样本撤离", + "Primary": "主要", + "Kill #COUNT #ENEMY#LOCATION_PRE#LOCATION#LOCATION_POST#EQUIP_PRE#EQUIP#EQUIP_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI": "击杀#COUNT个#ENEMY#LOCATION_PRE#LOCATION#LOCATION_POST#EQUIP_PRE#EQUIP#EQUIP_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI", + "Kill #COUNT enemies with a single magazine": "仅使用一个弹匣击杀#COUNT名敌人", + "Donate #GOAL #GEAR #GEARTYPE": "捐赠 #GOAL #GEAR #GEARTYPE", + "Progression": "进度", + "Defend against #COUNT attacks from #RACE": "抵御#RACE的#COUNT次袭击", + "Objectives": "目标", + "Get 4 kills with a single #REF #COUNT times": "仅使用#REF一次击杀4名敌人#COUNT次", + "Complete a difficulty #COUNT or higher mission without dying": "在无人阵亡的情况下完成难度系数为#COUNT或以上的任务", + "(personally)": "(独自)", + "Kill #COUNT enemies within 10 meters from you with the Eagle": "利用“飞鹰”击杀距离你10米内的#COUNT名敌人", + "Achieve a 'Supreme' rating on a difficulty #COUNT mission": "在难度系数为#COUNT的任务中获得“杰出”的评价", + "Destroy #COUNT Automaton Fabricators": "摧毁#COUNT个机器人构筑者", + "in multiplayer": "模式:多人游戏", + "Successfully complete #COUNT objectives on missions": "在任务中完成#COUNT个目标", + "ARMOR DESTRUCTION": "毁灭装甲", + "#COUNT times": "次数: #COUNT", + "General": "其他", + "Successfully extract#EXT_PRE#EXT#EXT_POST#COUNT_PRE#COUNT#COUNT_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI.": "成功撤离#EXT_PRE#EXT#EXT_POST#COUNT_PRE#COUNT#COUNT_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI", + "The Automatons have illegally occupied and mined Malevelon Creek for too long. The time has come to take it back.": "机器人非法占领和开采麦拉芬蒙河已久。是时候收复它了。", + "Destroy #COUNT Automaton Gunship thrusters": "摧毁#COUNT个机器人的炮舰推进器", + "using the ": "使用:", + "Outpost": "哨站", + "Complete the #OBJ Objective#COUNT_PRE#COUNT#COUNT_POST#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI.": "完成#OBJ目标。#COUNT_PRE#COUNT#COUNT_POST#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI", + "Complete an Operation#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST": "顺利完成行动。#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST", + "Liberate #COUNT planets": "解放#COUNT颗星球", + "Boosters": "强化资源", + "MASS SHUTDOWN": "大规模关停", + "Spend #COUNT Credits on weapons": "为武器花费#COUNT货币", + "Kill #COUNT flying enemies with support weapons": "利用支援武器击杀#COUNT名空中的敌人", + "#COUNT total kills with grenades": "利用榴弹总计完成#COUNT次击杀", + "Kill #COUNT enemies with Eagle stratagems during a single mission": "在单次任务中利用“飞鹰”战略配备击杀#COUNT名敌人", + "Complete a mission with #COUNT% accuracy": "以#COUNT%的命中率完成一次任务", + "TROPHY HUNT": "荣耀猎杀", + "Daily - #HOURS:#MINUTES:#SECONDS": "每日 - #HOURS:#MINUTES:#SECONDS", + "Kill #COUNT enemies using #REF": "利用#REF击杀#COUNT名敌人", + "Complete #COUNT#TYPE #OBJ#RACE_PRE#RACE#RACE_POST#MULTI.": "完成#COUNT个#TYPE#OBJ。#RACE_PRE#RACE#RACE_POST#MULTI", + "Extract from a successful #MTYPE#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST": "成功从#MTYPE撤离。#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST", + "on ": "难度:", + "Activate #COUNT #OBJ#RACE_PRE#RACE#RACE_POST#MULTI.": "启动#COUNT台#OBJ。#RACE_PRE#RACE#RACE_POST#MULTI", + "Defend #PLANET against #COUNT attacks": "保卫#PLANET,抵御#COUNT次袭击", + "Disarm #COUNT Automaton troops": "解除#COUNT支机器人军队的武装", + " controlled planet": "(任一星球)", + "Successfully extract with #COUNT #EQP_PRE#EQP#EQP_POST#EXT_PRE#EXT#EXT_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI.": "携带#COUNT个#EQP_PRE#EQP#EQP_POST成功撤离。#EXT_PRE#EXT#EXT_POST#DIFF_PRE#DIFF#DIFF_POST#MULTI。", + "Liberate the designated planets.": "解放指定的星球。", + "Advance your PROGRESSION TRACK": "使进度条解锁更多进度", + "LANDMINE TESTING": "地雷测试", + "Repel #COUNT Illuminate invasions in the #SECTOR": "在#SECTOR击退#COUNT次光能者的入侵", + "Destroy #COUNT #OBJ#RACE_PRE#RACE#RACE_POST#MULTI.": "摧毁#COUNT次#OBJ。#RACE_PRE#RACE#RACE_POST#MULTI", + "Extract from a successful #MTYPE#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST": "成功从#MTYPE撤离。#RACE_PRE#RACE#RACE_POST#DIFF_PRE#DIFF#DIFF_POST#COUNT_PRE#COUNT#COUNT_POST#MULTI#LOCATION_PRE#LOCATION#LOCATION_POST", + "Liberate #COUNT planets from #RACE": "从#RACE手中解放#COUNT颗星球", + "Daily": "每日", + "Destroy #COUNT Automaton AA turrets with the Eagle": "利用“飞鹰”摧毁#COUNT台机器人的防空炮台", + "Defend #PLANET against #COUNT attacks from the #RACE": "保卫#PLANET,抵御#RACE的#COUNT次袭击", + "Kill #COUNT enemies with a single grenade": "仅使用一枚榴弹击杀#COUNT名敌人", + "Kill #COUNT enemies with a single orbital stratagem usage": "仅使用一次轨道战略配备击杀#COUNT名敌人", + "Fire #COUNT shots on a mission": "在一次任务中射击#COUNT次", + "Get #COUNT kills in 10 seconds": "10秒内完成#COUNT次击杀", + "on ": "位置:", + "Hold #COUNT planets in the #SECTOR sector when the order expires": "指令过期后,在#SECTOR守住#COUNT颗星球", + "Opportunity Mission": "机遇任务", + "MASS DECOMMISSIONING": "大规模报废", + "Liberate the designated planet.": "解放指定的星球。", + "Kill #COUNT Bug Shriekers": "击杀#COUNT只虫族的尖啸虫", + "Get #COUNT kills within 5 seconds of each other": "完成#COUNT次击杀,每次击杀间隔时间为5秒", + "in the ": "分区:", + "against ": "敌人:", + "PEST CONTROL": "害虫管制", + "Defend against #COUNT attacks from the #RACE in the #SECTOR": "在#SECTOR抵御#RACE的#COUNT次袭击", + "Spend #COUNT Credits on Eagle": "在“飞鹰”上花费#COUNT货币", + "CUTTING-EDGE RESEARCH": "尖端科研", + "Collect a total of #COUNT samples": "总计收集#COUNT份样本", + "#SPEAKER #TEXT": "#SPEAKER #TEXT", + "Fire a total of #COUNT shots": "总计射击#COUNT次", + "Liberate more planets than are lost during the order duration": "指令生效期间解放的星球数量超过沦陷的星球数量", + "Destroy #COUNT Bug Charger abdomens": "击毁#COUNT只虫族强袭虫的腹部", + "Headshot #COUNT Automaton Soldiers": "爆头击杀#COUNT个机器人士兵", + "Repel #COUNT Illuminate invasions": "击退#COUNT 次光能者的入侵", + "Achieve rank #COUNT": "达到级别#COUNT", + "Liberate more planets than are lost to #RACE during the order duration": "指令生效期间解放的星球数量超过沦陷在#RACE手中的星球数量", + "Designated planets must be under Super Earth control when order expires.": "指令计时结束之时,指定星球必须收归超级地球管辖。", + "Secondary": "次要", + "Objective": "目标", + "Destroy #COUNT Automaton Warlords": "摧毁#COUNT个机器人的军阀", + "Pop #COUNT Bug Scavengers": "射击#COUNT只虫族的食腐虫", + "Intelligence": "情报", + "Radar Wagons": "雷达车", + "INCREASE FOOTPRINT": "乘胜追击", + "Use at least #COUNT stratagems during a single mission": "在单次任务中至少使用#COUNT次战略配备", + "Liberate Malevelon Creek.": "解放麦拉芬蒙河。", + "The long arm of Justice": "法网恢恢", + "Complete a Hard difficulty mission or higher without anyone firing their primary or support weapon.": "在无人使用主武器或支援武器的情况下,完成一项难度为“困难”或以上的任务。", + "Complete Basic Training.": "完成基本训练。", + "Kill 100 enemies using fire damage during the same mission.": "在同一项任务中通过灼烧伤害击杀100名敌人。", + "The power of Democracy": "民主之力", + "Provide assisted reload for a teammate.": "辅助一名队友装填弹药。", + "Hold my primary, I'm going in!": "帮我拿着主武器,我要冲了!", + "Obtain all trophies of HELLDIVERS™ 2.": "获得《HELLDIVERS™ 2》的全部奖杯。", + "Samples are a diver's best friend": "样本是潜兵最好的伙伴", + "Fully operational": "火力全开", + "They don't call it Tacticool for nothin'": "“战术咖”并非浪得虚名", + "Customize your Helldiver with new cape, armor, and helmet.": "用新披肩、盔甲和头盔对你的绝地潜兵进行自定义。", + "Science is done by quantity": "科学以量取胜", + "Extract after the timer reaches zero.": "在倒计时归零后撤离。", + "Extract with at least 15 common samples.": "携带至少15份普通样本撤离。", + "Package of 1000 (750 + 250 bonus) Super Credits": "1000(750 + 额外250)超级货币包", + "Package of 2100 (1500 + 600 bonus) Super Credits": "2100(1500 + 额外600)超级货币包", + "Extract with at least 15 rare samples from a mission as a team.": "在一项任务中整个团队携带至少15份稀有样本撤离。", + "Package of 150 Super Credits": "150超级货币包", + "The taller they are...": "他们越高就…", + "Caught them by Supplies!": "物资出击!", + "Extractinating the Countryside": "开采乡村", + "Let's call it a draw": "就算平局吧", + "Ship it!": "赶紧送!", + "Quick Play": "快速进攻", + "Shoot off both arms on a Hulk and then extract while it's alive.": "射下巨型者的两只手臂,在它尚存活的时候撤离。", + "It's the only way to be sure...": "别无他选…", + "Have 6 orbital barrage stratagems in the same place at the same time.": "在同一地点同时部署6个轨道火力网战略配备。", + "Play 1 Bug Mission.": "参与1项虫族任务。", + "Package of 375 Super Credits": "375超级货币包", + "Complete a mission but fail to extract.": "完成任务,但撤离失败。", + "Reach max level on one ship module.": "一个舰船模块提升至最高级别。", + "Cool guys don't loo- AAAAH!": "真男人从不回头看…啊啊啊!", + "Stalking is illegal": "跟踪违法", + "Defeat a Bile Titan.": "击败一只吐酸泰坦。", + "Heal another player using stims.": "使用治疗剂治疗其他玩家。", + "Hot Potato!": "烫手山芋!", + "Get some!": "受死吧!", + "Complete at least 100 missions.": "完成至少100项任务。", + "Kill it with fire!": "烧死它!", + "Spread Managed Democracy": "散播管理式民主", + "Be injured in all limbs at the same time.": "四肢同时受伤。", + "Bug Stomper": "虫族克星", + "Super Citizen": "超级公民", + "Fire at least 150 rounds in one burst, killing at least 10 enemies.": "一次性连射至少150发弹药,击杀至少10名敌人。", + "Extract with a full squad on a Hard difficulty or more mission.": "在一项难度为“困难”或以上的任务中,与整支小队一起撤离。", + "Democracy ain't done with you yet": "民主大业还需要你的力量", + "Job's done!": "完成任务!", + "Promote Synergy": "倡导合作", + "While using a jump pack, knock yourself into a ragdoll state.": "使用喷射背包时,让自己陷入僵直状态。", + "Kill a Charger with a resupply pod.": "用重新补给舱消灭一只强袭虫。", + "The Epitome of Super Earth": "超级地球典范", + "Play at least 50 missions.": "参与至少50项任务。", + "Quick Play with friends": "与好友参与快速进攻", + "Upgrade all ship modules at least 1 level.": "将所有舰船模块提升至少1个等级。", + "Doing your part": "履行职责", + "Complete 10 tactical objectives.": "完成10个战术目标。", + "MACHINERY OF OPPRESSION": "铁腕威压", + "Hell Dive": "绝地俯冲", + "Start a quick play session with friends only": "仅与好友组队参与一场快速进攻", + "Complete a Stalker Hive tactical objective.": "完成追踪虫虫窝战术目标。", + "That which does not kill you...": "但凡杀不死你的…", + "Nothing is bigger than Freedom": "自由价更高", + "Machinery of Oppression": "铁腕威压", + "Hold My Liber-tea!": "尝尝我的解放威力!", + "Start a quick play session": "开始一场快速进攻", + "Kill 150 enemies during the same mission.": "在同一项任务中击杀150名敌人。", + "Play 1 Bot Mission.": "参与1项机器人任务。", + "Extractamundo!": "完全撤离!", + "Kill 25 enemies with one stratagem.": "利用一项战略配备击杀25名敌人。", + "Play a planet defense mission.": "参与1项星球保卫任务。", + "They mostly come at night...": "夜访异形…", + "Complete a full Extreme difficulty Blitz mission and extract in under 6 minutes.": "在6分钟内完成一项难度为“极端”的闪电战任务并撤离。", + "Bot Scrapper": "机器人克星", + "Gone in 360 seconds!": "致命360秒!", + "Complete a full Hard difficulty mission or higher without anyone firing their primary or support weapon.": "在无人使用主武器或支援武器的情况下,完成一项难度为“困难”或以上的任务。", + "Throw back a live grenade.": "掷回一颗已激活的榴弹。", + "The Real Deal": "动真格", + "Extract from a mission during nighttime.": "夜间从任务中撤离。", + "For the greater good!": "顾全大局!", + "Kill 5,000 enemies.": "击杀5000名敌人。", + "In the nick of time": "说时迟那时快", + "Complete an Extreme difficulty mission or higher without anyone dying.": "在无人死亡的情况下完成一项难度为“极端”或以上的任务。", + "Fly at least 25 meters from the shockwave of an explosion.": "飞至距离爆炸冲击波至少25米远的位置。", + "Eat This!": "接招!", + "Kill a target at a distance of over 100m.": "击杀一名100米外的目标。", + "Strapping young lad": "时空悍将", + "Defeat a Hulk.": "击败一只巨型者。", + "Kill a bug warrior with a shotgun within 1 meter.": "使用霰弹枪在1米内击杀一只武斗虫。", + "AUTOMATON DROPSHIP": "机器人运输舰", + "#ERROR!": "#ERROR!", + "TEAM KILLS #COUNT": "团队击杀数 #COUNT", + "LIBERATE HIVE WORLD": "解放虫窝世界", + "DESTROY COOLING TOWER": "摧毁冷却塔", + "Objectives bonus: #AMOUNT M": "目标加分:#AMOUNT", + "TARGET COORDINATES:": "目标坐标:", + "The Seismic Probe in this location can be used to confirm the likely locations of sub-surface geological features.": "这里的地震探测仪可以确认出现地下地质特征的可能位置。", + "Use Seismic Probes to chart the Terminid tunnel networks in this region.": "使用地震探测仪绘制该地区的终结族隧道网络。", + "Eradicate the specified number of adult Terminids and pre-adult Terminids (sometimes called eggs).": "消灭指定数量的终结族成虫和幼虫(又称“虫卵”)。", + "Halt the Illuminate and collect crucial data on the Void.": "阻止光能者,收集与寂域有关的重要数据。", + "AUTHORIZE NUCLEAR LAUNCH": "授权发射核弹", + "The Rapid Modular Drilling Platform is located here.": "快速模块化钻机平台在这里。", + "Satellite imagery has revealed that entire skyscrapers in this district are infested with Terminids. These beautiful homes and prosperous offices are now nothing but Shrieker breeding grounds.\n\nDestroy the former icons of Prosperity that have been so cruelly parasitized.": "卫星图像显示,该区域内的整栋摩天大楼都已经被终结族侵占。曾经美丽的家园和繁荣的办公室,如今沦为尖啸虫的繁殖之地。\n\n摧毁被这些寄生虫残忍霸占的昔日繁荣象征。", + "Data Jack Status: Unstable": "数据接口状态:不稳定", + "DESTROY COUNTER-ORBITAL CANNON": "摧毁反轨道加农炮", + "ALL SUB-OBJECTIVES MUST BE COMPLETED FIRST": "必须首先完成所有次要目标", + "SECURE GROUND ALL-TERRAIN EXTRACTION RIG": "控制地面全地形采集钻机", + "E-710 on Gloom-infested planets exhibits statistically-significant differences in various properties including density, viscosity, oxidation stability.\n\nReactivate defunct E-710 pumps on this planet to gather the Gloom-infused liquid for further study.": "受“阴霾”侵蚀的星球上的710元素在密度、黏度、氧化稳定性等多项属性上均呈现统计学意义的显著差异。\n\n重新启动这颗星球上废弃的710元素泵机,收集被“阴霾”侵蚀的液体以供进一步研究使用。", + "Turn the cranks on the side of the Cannon to rotate it": "转动加农炮侧面曲柄进行转向", + "DESTROY FUEL RESERVES": "销毁燃料储备", + "Conduct a geological survey to identify veins of valuable ore.": "进行地质调查,寻找珍贵矿脉。", + "#COUNT confirmed kills": "#COUNT次击杀", + "APPROPRIATE REFINERY": "占领精炼厂", + "INTELLIGENCE EXTRACTED:": "获取情报数:", + "Illuminate Warp Ships occupy key intersections in this city. These ships are critical to the enemy's insidious invasion efforts: they are used to deposit hostiles, abduct civilians, and threaten our proudly held air quality scores.\n \nSeek and destroy all Illuminate Warp Ships in the area.": "光能者穿梭舰占领了这座城市的要道。这些舰船对敌人阴险的入侵行动至关重要,被用于投放敌人、绑架平民,还威胁我们引以为傲的空气质量。\n\n搜寻并摧毁区域内的所有光能者穿梭舰。", + "Incoming Enemy Ship": "来袭敌舰", + "Area under Super Earth control:": "超级地球控制区域:", + "Use terminal to reactivate pumps": "使用终端,重新启动泵机", + "MANUALLY ADJUST VALVES": "手动调整阀门", + "ERADICATE MUTATED NESTS": "彻底摧毁变异巢穴", + "DESTROY WARP GATEWAYS": "摧毁传送门", + "UPLOADING VIDEO FILES": "正在上传视频文件", + "Swiftly secure the platinum at this site and extract before enemy reinforcements overwhelm you.": "迅速夺取此地的铂金并撤离,否则敌方的增援会将你们击溃。", + "WARP GATEWAY": "传送门", + "DROP OFF": "放下", + "An SSSD Hard Drive containing valuable data was lost at this location following an ambush of a SEAF squad. It must be recovered.": "曾有超级地球武装部队的小队在这里遭遇伏击,他们丢失了一个包含重要数据的超级固态硬盘。必须找回来。", + "Transport shuttle incoming": "运输船即将抵达", + "Wait for artillery system to initiate": "等待大炮系统启动", + "Organic plasma is synthesized in these vats. Siphon it for scientific analysis.": "有机等离子在这些槽罐之中合成。抽取样本进行科学分析。", + "Activate Aquifer Drill": "启动含水层钻机", + "Breach the Illuminate's lair and eliminate the devious threats that lurk within.": "突破光能者巢穴,消灭其中的狡诈威胁。", + "ERASE TERRORIST MEMORIALS": "推倒恐怖分子纪念碑", + "Enemy Class": "敌人等级", + "Cleared Medium Illuminate Encampment": "已摧毁光能者中型营地", + "RESCUE SCIENCE TEAMS": "救援科学团队", + "OVERWRITE CORE PROTOCOLS": "覆写核心协议", + "CAPTURE AUTOMATON TERRITORY": "占据机器人领地", + "DOCUMENT EVIDENCE": "录下证据", + "Find the objective location": "确定目标的位置", + "Find the nursery chamber drill point": "寻找繁育腔室的钻孔点位", + "COLLECT SAMPLES": "收集样本", + "Liberate Planet": "解放星球", + "Temperature": "温度", + "The Automatons have a mortar emplacement in the area. They will fire on anyone that moves in the vicinity.": "机器人在该区域设有迫击炮台,会向范围内任何移动目标开火。", + "PLEASE ACTIVATE TRANSFORMER": "请启动变压器", + "EMERGENCY EVACUATION": "紧急撤离", + "EXTRACT INTEL": "获取情报", + "The Automatons have captured a SEAF research station, slaughtering the brave scientific staff.\n\nGet to the station, download the research database, and upload it to the Super Earth mainframe using the nearby Satellite Uplink Station.": "机器人占领了一座超级地球武装部队研究站,正在残杀勇敢的科研人员。\n\n前往该研究站,下载研究数据库,然后使用附近的卫星上行链路站点将其上传至超级地球主机。", + "Locate and eliminate the Automaton Devastators.": "找到并消灭机器人蹂躏者。", + "The Terminids have transformed this world into a bastion of Fascist oppression. But it can still be restored to Liberty's Light.\n\nDeploy to the Hive World and raise the Flag of Super Earth.": "终结族已将这个世界改造成法西斯压迫的堡垒。但我们仍然可以让它恢复自由的荣光。\n\n前往虫窝世界,升起超级地球的旗帜。", + "Use the GATER to extract anomalous material from all sites.": "使用地面全地形采集钻机从所有地点提取异常物质。", + "This is the maiden voyage of the #SHIP_NAME. Its first trial is to carve a democratic path towards the indicated region and provide critical support in suppressing a small-scale Terminid outbreak.\n\nHelldiver, this is not a drill. Apply every invaluable lesson you learned at the Helldiver Training Facility. May Liberty guide you.": "这是#SHIP_NAME的首航。它的首次试炼是向指定区域开辟民主之路,并为镇压小规模终结族爆乱提供关键支援。\n\n绝地潜兵,这不是演习。请学以致用,发挥你在绝地潜兵训练设施中学到的每一条宝贵经验。愿解放保佑你们。", + "Initiate off-planet evacuation of high-value artifacts, and defend the site until evacuation is complete.": "启动高价值文物撤离星球的程序,并保卫阵地,直至撤离完成。", + "Destroyed Fortress": "已摧毁堡垒", + "A crashed escape pod in the region contains valuable data.": "坠毁在该地区的一个逃生舱中存着有价值的数据。", + "Power up data collection uplink": "为收集数据的上行链路接入电源", + "Defend generator system until all rockets have launched.\n\nRockets launched: #CURRENT/#TARGET": "在所有火箭弹发射完毕前保卫发电系统。\n\n已发射的火箭弹:#CURRENT/#TARGET", + "Please adjust all indicated valves": "请按照提示调整所有阀门", + "IMPALER ELIMINATION": "消灭穿刺虫", + "MANUALLY set ENGINE VALVES to maximum output.": "手动将引擎阀门设置为最大输出。", + "Tactically eliminate all obstacles standing in the way of peace.": "在战术层面上彻底铲除所有阻碍和平实现的障碍。", + "TEAM DEATHS #COUNT": "团队阵亡数 #COUNT", + "PEACEKEEPING OPERATION": "维和行动", + "LIBERATE CYBERSTAN": "解放生化斯坦", + "DESTROY ILLUMINATE WARP SHIPS": "摧毁光能者穿梭舰", + "Force the Cyborg Production Unit to self-destruct by disrupting its operations.": "干扰生化人生产单元的运作,迫使其自毁。", + "REDIRECT HYDROGEN FLOW": "更改氢气流向", + "INTEL RETRIEVED - OPPORTUNITIES REVEALED": "已取回情报并发掘机遇", + "Defend Battery Silo 02": "保卫电池舱02", + "MAIN SILO": "主储罐", + "Tectonic disturbances indicate the presence of an Impaler in this area.": "地壳扰动显示该区域存在穿刺虫。", + "DESTROY AUTOMATON FABRICATORS": "摧毁机器人构筑者", + "SEAF Artillery System": "超级地球武装部队大炮系统", + "Pick up ammo": "拾取弹药", + "Fire Artillery": "开炮", + "CALIBRATING VOLTAGE": "正在校准电压", + "DEACTIVATE TERMINID CONTROL SYSTEM": "关闭终结族遏制体系", + "Clear the area of Terminid nests to prepare it for Gloom research specialists.": "清除该区域的终结族巢穴,为“阴霾”研究专家的考察做好准备。", + "Nuke all Terminid nurseries and collapse the specified number of nests.": "用核武器炸毁所有终结族繁育窝,摧毁指定数量的巢穴。", + "Restart the pumps located in this region.": "重启该地区的泵机。", + "FUSION BATTERY": "聚变电池", + "LIBERATE MEGAFACTORY": "解放超大型工厂", + "ELIMINATE BILE TITAN": "消灭吐酸泰坦", + "Please log in": "请登录", + "Science strike teams—each consisting of a xenobiologist, a theoretical physicist, an astro-meteorologist, and a psychologist—will conduct expeditions to the planet's surface at key locations.\n\nClear the area of Terminid nests to secure the research site.": "科考突击队将对星球表面的重要地点进行考察,每支突击队由一名异星生物学家、一名理论物理学家、一名天文气象学家和一名心理学家组成。\n\n清除该区域的终结族巢穴,保障研究地点的安全。", + "Proceed to facility gate": "前往基地大门", + "MINING SITE COORDINATES": "采矿点坐标", + "Planetary Defense Cannon raising…": "行星防御加农炮正在抬升……", + "Deliver SSSD": "运送超级固态硬盘", + "Use door controls to release civilians from Emergency Bunkers": "使用门控装置将平民从紧急掩体中放出去", + "DEFEND EVACUATION SITE": "保卫撤离点", + "Keep open flames away from missile": "导弹周围严禁明火", + "HATCH OPENING...": "舱门正在开启……", + "DESTROY HARVESTERS": "摧毁猎杀器", + "Activate terminal": "启动终端", + "The Automatons are stealing the minerals of this planet from our citizens at this quarry. Take it back.": "机器人正在这座采石场内从我们公民的手中窃取这颗星球的矿物。将资源夺回来。", + "All Objectives Completed": "达成所有目标", + "SPREAD DEMOCRACY": "传播民主", + "#FOUND found (#TOTAL on ship)": "已找到#FOUND份(舰船上总计有#TOTAL份)", + "Use a Stim to heal your wound": "使用治疗剂疗愈伤口", + "CONFIRMING COORDINATES": "正在确认坐标", + "Low Death Count Bonus": "低阵亡次数奖励", + "2ND": "第2", + "This Automaton device prevents the use of any stratagems in the area.": "机器人的这台装置令我们无法在该区域内使用任何战略配备。", + "Destroy the Bio-Processors": "摧毁生物处理器", + "Restore power to the satellite tower": "恢复卫星塔的电力输送", + "Defend Battery Silo 01": "保卫电池舱01", + "SEIZE INDUSTRIAL COMPLEX": "占领工业联合体", + "Find Annihilator Tank": "找到湮灭坦克", + "The Illuminate have fashioned crude gateways through which they warp interloping forces from afar. A poor imitation of our FTL technology.\n\nMany of these structures have been located in this region. Destroy as many as you can.": "光能者建造简易的传送门,用于远距离传送入侵部队。这不过是对我方超光速跃迁技术的拙劣模仿。\n\n该地区内已发现大量此类建筑。尽可能摧毁这些传送门。", + "Pointless Sacrifice": "无谓牺牲", + "Illuminate Harvesters patrol this colony, enforcing the zealous rule of their masters. The unnatural, spindly constructs must be destroyed, so that Freedom can return.": "光能者猎杀器会在此拓殖地巡逻,尽心尽力维护它们主人的狂热统治。必须摧毁这些非自然的细长型结构物,我们才能重获自由。", + "CALCULATING SHUTTLE FLIGHT PATH": "正在计算运输船飞行路线", + "Destroy Automaton Mortar emplacements": "摧毁机器人的迫击炮台", + "Silo Unstable. Aborting Activation.": "舱体不稳定。即将停止启动。", + "EXTERMINATE BUGS NEAR THUMPER": "消灭桩锤附近的虫族敌人", + "ERADICATE AUTOMATON FORCES": "彻底消灭机器人部队", + "Use Terminal to open SSSD Delivery Hatch": "使用终端打开超级固态硬盘运送舱门", + "The Terminids on this planet are mutating in response to the Termicide. With every passing minute, they threaten to turn this world into another Supercolony.\n\nEradicate the mutated Terminid eggs and deactivate the corrupted Terminid Control System before its too late.": "这颗星球上的终结族正在灭虫终结剂的影响下快速变异。它们随时都有可能将这个世界变成又一个超级拓殖地。\n\n彻底清除变异终结族虫卵,尽快关闭出错的终结族遏制体系。", + "Eradicated Mega Nest": "已摧毁超巨巢穴", + "DISRUPT EXOSPIRE CORE": "破坏异界尖塔核心", + "ISOLATING NETWORK": "正在隔离网络", + "The Terminid Variant was last reported in this area.": "有报告称,终结族亚种的最后目击地点就在该区域。", + "TOWER CONTROL PANEL": "广播塔控制面板", + "Eliminate Bile Titan": "消灭吐酸泰坦", + "Proceed to Stratagem Range": "前往战略配备训练场", + "This city is under enemy control. It must be reclaimed in the name of Freedom.": "这座城市已落入敌手。必须以自由之名收复。", + "Payout already received": "已获得收益", + "INTEL PACKAGE": "情报包裹", + "Targeting Communication System": "正在锁定通信系统", + "This sector is occupied by Illuminate invaders. It must be freed.": "该分区被入侵的光能者所占领。必须解放这里。", + "Commend Player": "称赞玩家", + "A Counter-Orbital Cannon is positioned at this site.": "此处部署有反轨道加农炮。", + "Introduce Managed Democracy to the Void.": "将管理式民主传播到寂域。", + "Bore hole completed": "博尔虫洞已完成", + "Place Black Box in input tray": "将黑匣子放进输入托盘", + "HINTS": "提示", + "Silo Status: Critically Unstable": "舱体状态:极其不稳定", + "SAMPLE 01": "样本01", + "Call down SSSD and insert into Hatch": "呼叫超级固态硬盘并将其置入舱门", + "Use Reinforce Stratagem to bring back fallen squadmate": "使用增援战略配备复活阵亡的队友", + "COLLECT GLOOM-INFUSED OIL": "采集“阴霾”污染的原油", + "Destroy all Illuminate Warp Ships in the vicinity": "摧毁附近的所有光能者穿梭舰。", + "Kill Automatons and Cyborgs to reduce their numbers.": "击杀机器人和生化人,削减它们的数量。", + "Find target on grid": "在网格内寻找目标", + "Use terminal to trace defense network": "使用终端追踪防御网络", + "Destroy enemy deployment structures to secure the area": "摧毁敌方部署建筑,保障该区域的安全", + "OPEN BUNKER HATCH": "打开掩体舱门", + "Extract samples of oil that has been exposed to the Gloom.": "提取受“阴霾”污染的原油样本。", + "The bots are breaking down organic matter for use in some twisted, un-Democratic purpose.": "机器人正在分解有机质,将其用于某种不民主的扭曲用途。", + "REARMING CANNON…": "加农炮正在装弹……", + "Reconnaissance has pinpointed a number of key Automaton fuel and munitions depots within the city.\n \nInfiltrate quickly and destroy their supply bases before they can mount a defense.": "侦察部队已确定城内多个机器人燃料和弹药关键补给站的位置。\n\n快速潜入,摧毁补给基地,别让它们有机会筑起防线。", + "LIGHTNING SPIRE": "闪电尖塔", + "With the arrival of Freedom to this newfound world, the bugs have been driven into a fascist frenzy. Their destructive urge is denying our citizens the prosperous future they were always meant to inherit on this soil.\n\nA new generation of TCS+ towers stands ready to neutralize this threat and ensure total planetary safety through controlled fumigation. See that they are activated and fully operational.": "随着自由降临这片新世界,虫族陷入法西斯般的狂暴状态。它们按耐不住肆意破坏的冲动,正在剥夺我们的公民自始至终理应在这片土地上继承的繁荣未来。\n\n新一代TCS+塔已准备就绪,将通过可控式熏杀手段铲除这一威胁,保障星球的绝对安全。务必确保TCS+塔成功启动并全面投入运行。", + "ALIGN SIGNAL": "校准信号", + "FREE COLONY": "解放拓殖地", + "Enter transport pod": "进入运输舱", + "DOWNLOADING - PLEASE WAIT": "正在下载,请稍候", + "Eliminate Annihilator Tank": "消灭湮灭坦克", + "Unstable": "不稳定", + "Recover top-secret intel from a downed SEAF reconnaissance plane.": "从超级地球武装部队侦察机找回绝密情报。", + "DESTROY SPORE LUNG": "摧毁孢肺", + "System is loading - Please wait": "系统正在加载,请稍候", + "Failed to extract": "撤离失败", + "Confirm Evacuation Coordinates": "确认疏散坐标", + "Pick up supplies and load Liberator": "拾取补给,为“解放者”装弹", + "Lock the hose to the transfer pump": "将软管锁定在输送泵上", + "#MISSION_TYPE: #MISSION_NAME": "#MISSION_TYPE: #MISSION_NAME", + "Destroy the convoy before it can reach its destination": "在车队到达目的地之前将其摧毁", + "COMMUNITY IMPACT": "社区战役贡献", + "PLANETARY IMPACT": "战役贡献", + "The Terminids' grip on this planet has been weakened. We must attack now, before they have a chance to regenerate.\n\nAs Helldivers, you can take the fight to the Terminids' remaining hive cores, and root out the infestation for good.": "终结族对这颗星球的掌控有所减弱。我们必须立刻出击,避免它们恢复实力。\n\n作为绝地潜兵,你们可以直接袭击终结族剩余的虫窝核心,将其彻底清除。", + "Tune to Super Earth frequency": "调至超级地球的频率", + "Grotesque Monoliths now pepper this city, boldly empowering the Illuminate through unknown means. Their inscrutability is an affront to Liberty. They must be destroyed.": "丑陋不堪的巨石遍布城区,堂而皇之地以未知方式赋予光能者力量。它们的不可捉摸是对自由的公然亵渎。必须摧毁巨石。", + "Demolition sequence initiated": "拆除程序已启动", + "Please adjust target storage facility": "请调整目标存储设施", + "Track down and eliminate the Bile Titan.": "追踪并消灭吐酸泰坦。", + "Influence (Max)": "影响力(最大)", + "Caution: deleted data cannot be recovered": "当心:已删除的数据无法恢复", + "A Charger was last sighted in this region.": "强袭虫的最后目击地点就在这个地区。", + "Confirm scan area using probe interface": "使用探测仪界面确认扫描区域", + "SECONDARY EXTRACTION ZONE": "次级撤离区", + "Input code on terminal": "在终端上输入代码", + "HOLD CITY": "保卫城市", + "DESTROY HARD DRIVES": "摧毁硬盘驱动器", + "Cargo Truck": "货车", + "Proceed to next objective": "前往下一个目标", + "MANUALLY tighten EXHAUST CLAMPS.": "手动解开安全钳。", + "Outstanding Patriotism": "爱国精英", + "3RD": "第3", + "Disable Stratagem Blocker": "关闭战略配备屏蔽装置", + "Use Prospecting Drill to retrieve second sample": "使用勘探钻机取得第二份样本", + "Destroy ammunition stockpiles": "摧毁库存弹药", + "Establishing link...": "正在建立连接...", + "ACCURACY:": "命中率:", + "Repel the Terminid swarm threatening to infest this planet.": "击退企图占领这颗星球的终结族虫群。", + "Bonds Awarded": "奖励债券数", + "ELIMINATE DEVASTATOR": "消灭蹂躏者", + "Log in to terminal": "登录终端", + "Find and destroy any active Automaton Gunship Fabricators": "寻找并消灭所有运作中的机器人炮舰构筑者", + "This Terminid hive node emits a dense fog which reduces visibility.": "此终结族虫窝节点释放出一种降低能见度的浓雾。", + "LEVEL #COUNT": "等级#COUNT", + "Abandoned SEAF Anti-Aircraft Missile Launchers will fire on enemy airborne targets when activated.": "废弃的超级地球武装部队防空导弹发射器启动时,将向空中的敌方目标开火。", + "Use Terminal to activate Communication Tower": "使用终端启动通信塔", + "LAUNCH ICBM": "发射洲际弹道导弹", + "Use terminal to activate surface-to-air launcher sub-systems": "使用终端启动地对空导弹发射器子系统", + "#ENTITY is out of range": "#ENTITY不在范围内", + "PREPARING UPLOAD": "准备上传", + "ACTIVATE TERRAIN SCAN": "开启地形扫描", + "A cluster of hive entrances has been mapped in this region.": "这个地区内标记有多处虫窝入口。", + "Generator calibrating": "发电机正在校准", + "RAISING TOWER - PLEASE WAIT": "正在抬升卫星塔,请稍候", + "BREACHING TERMINID COLONY": "攻破终结族拓殖地", + "PROPULSION": "推进", + "Input code to finalize virus upload": "输入代码,上传病毒", + "Community Reinforced": "增援社区", + "Shriekers: #CURRENT / #TOTAL kills": "尖啸虫:#CURRENT / #TOTAL次击杀", + "Protect #ENTITY during upload": "在上传期间保护#ENTITY", + "The Illuminate are attempting to steal this planet from our citizens. \n\nWe must repel them before it is too late!": "光能者企图从我们的公民手中窃取这颗星球。\n\n我们必须及早击退它们!", + "Take control of the planet to unmake the Void.": "夺取星球的控制权,瓦解寂域。", + "Thank you for your patience": "感谢您耐心等待", + "The Terminids are mutating. Deactivate the TCS before it's too late.": "终结族发生变异。尽快关闭TCS。", + "Protect Liberty": "保卫解放", + "ELIMINATE DEVASTATORS": "消灭蹂躏者", + "Lightning Spires": "闪电尖塔", + "The Automatons use a highly-advanced keycard security system. A keycard located here will grant access to their secure containment unit.": "机器人使用高度先进的钥匙卡安全系统。此处的钥匙卡可打开它们的安全收容装置。", + "RETRIEVE THE GENERAL'S ORDERS": "取回将军的命令", + "A high-definition tactical video camera has been deployed to this location. It is critical to recording evidence of the enemy's crimes.": "我方已在此处部署一台高清战术摄像机。它对记录敌军罪证至关重要。", + "Completing this Operation helps liberate this Megafactory. Each liberated Megafactory brings us closer to the total liberation of Cyberstan.": "完成此次行动有助于解放这所超大型工厂。每解放一所超大型工厂,我们就离彻底解放生化斯坦更近一步。", + "Extraction bonus: #AMOUNT M": "撤离加分:#AMOUNT", + "SSSD Hard Drive": "超级固态硬盘", + "Intel Recovered": "已找回情报", + "Initiate Evacuation": "启动疏散程序", + "Silo Status: Stable": "舱体状态:稳定", + "Activate Battery Silo 02": "启动电池舱02", + "The brilliant scientists of this SEAF research station were abducted following an Illuminate hostile takeover. They would have wanted their life's work to be recovered and put in the service of Super Earth.\n\nAccess the station, download the research database, and upload it to the Super Earth mainframe.": "由于光能者的入侵占领,驻守超级地球武装部队研究站的杰出科学家们惨遭绑架。他们肯定希望自己毕生的研究成果能够被妥善寻回,为建设超级地球贡献力量。\n\n前往该研究站,下载研究数据库,然后上传至超级地球主机。", + "The Illuminate have invaded this colony, turning its citizens into Voteless hordes. They have raised uncanny, malevolent monoliths that generate some kind of exotic energy fields. We know neither their function nor their true nature—that is why we must destroy them.\n\nWe must cast off their occupation. Deploy to the colony, tear down the invaders' structures, and raise the flag of Super Earth once more.": "光能者入侵了这片拓殖地,将其中的公民变为了无票者。它们立起了邪恶的诡异巨石,想打造某种奇异的能量场。我们不知道巨石的功能,也不了解其中的性质,所以必须将它们摧毁。\n\n我们必须让拓殖地摆脱敌人的占领。前往拓殖地,摧毁入侵者的建筑,再次升起超级地球的旗帜。", + "INITIATE DRILL SEQUENCE": "启动钻机程序", + "The streets of this Megafactory are riddled with terrorist emblems and Cyborg propaganda. It is your duty to redress this affront, and to bring Democracy to this oppressed place.\n\nStorm the Megafactory and raise the flag of Super Earth, the one true symbol of Unity.": "这座超大型工厂的街道随处可见恐怖分子的标志和生化人的宣传物。你的职责是纠正这种冒犯行为,并将民主带到这片受压迫的土地。\n\n突袭超大型工厂,升起超级地球的旗帜,这是唯一真正的团结象征。", + "Return to Super Earth flag": "返回超级地球旗帜所在位置", + "Activate terminal at base of Central Tower": "在中央巨塔底启动终端", + "Terminal System": "终端系统", + "RETRIEVE LAUNCH CODES": "取回发射代码", + "Probe may cause significant hearing loss": "探测仪可能会严重影响听觉", + "Turn all valves indicated by the terminal": "按照终端的提示,调整所有阀门", + "Place switches to indicated positions": "将开关调到指定位置", + "CONTROL CHAMBER LOCKED": "控制室已锁定", + "Adjust pipe valves": "调整管道阀门", + "A large Automaton air base in this region is conducting frequent troop deployments by Dropship—a tactical advantage we cannot allow.\n\nDeploy behind enemy lines and destroy their Dropships and the air base's infrastructure.": "机器人在该地区有一座大型航空基地正在频繁使用运输舰调度部队——我们不能放任它们继续占领这种战术优势。\n\n深入敌方防线背后,摧毁它们的运输舰,破坏航空基地的基础设施。", + "Influence (Self)": "影响力(自我)", + "Influence (Community)": "影响力(社区)", + "SECURE BLACK BOX": "取回黑匣子", + "Launch Codes": "发射代码", + "START FUEL PUMPS": "启动燃料泵", + "Destroy all Warp Gateways in the vicinity": "摧毁附近的所有传送门", + "VERIFY TRANSFER CHECKSUM": "验证传输校验和", + "MISSION REWARDS": "任务奖励数", + "Establish connection to Super Destroyer to secure reinforcements": "与超级驱逐舰建立连接,获得增援", + "FUELING STATION": "燃料站", + "DEPLOY SEISMIC PROBE": "部署地震探测仪", + "The Automatons are synthesizing some kind of nutrient-dense plasma from organic material. Undeniable intel shows 100% of this organic material came from loyal citizens with high potential and excellent facial symmetry. The purpose of this plasma is yet unknown, but its production is extremely costly.\n\nDue to enemy anti-air, this mission must be extremely rapid. Destroy the Bio-Processors that fuel plasma synthesis, then extract.": "机器人正在用有机物质合成某种富含营养的等离子。有确凿情报显示,这些有机物质100%来自潜力巨大而且面部完美对称的忠诚公民。这种等离子的具体用途尚未明确,但其生产成本极其高昂。\n\n因敌方出动防空火力,此次任务的行动必须极其迅速。摧毁为合成等离子提供动力的生物处理器,然后撤离。", + "A network of towers stand ready to dispense bug-killing Termicide across the planet. Once they're active, this planet will be cleansed of Terminids, forever.\n\nActivate the Termicide Dispersion Tower in this region, and bathe it in a purifying haze of Termicide.": "巨塔网络已准备好在星球各地喷洒灭虫终结剂。一旦启动,这颗星球就可以永远免受终结族的威胁。\n\n启动该地区的灭虫终结剂喷洒塔,让灭虫终结剂的雾气带来净化的洗礼。", + "Use LiDAR towers to gather Gloom spore data and upload it from a communication relay.": "使用激光雷达塔收集“阴霾”孢子数据,并通过通信中继站上传数据。", + "Activate Shuttle Bay Terminal": "启动运输船坞终端", + "A fuel station in this district powers the Cyborg Production Unit with highly combustible hydrogen.": "该区域的燃料站为生化人的生产单元供应高度易燃的氢气能源。", + "#TYPE: +#AMOUNT/#POTENTIAL": "#TYPE:+#AMOUNT/#POTENTIAL", + "DESTROY EXOSPIRE": "摧毁异界尖塔", + "Use terminal to reset fuses": "使用终端重置熔断器", + "Destroy Automaton Anti-Air Emplacements": "摧毁机器人的防空炮台", + "WARHEAD": "弹头", + "Research data available and ready for upload": "研究数据准备就绪,可供上传", + "Location data ready": "附近地点的数据已准备就绪", + "Salute the Flag of Super Earth": "向超级地球旗帜敬礼", + "EXTRACT MYSTERIOUS SUBSTANCE": "提取神秘物质", + "Use terminal to direct hydrogen into Power Core": "使用终端将氢气导入动力核心", + "Drill Status: Stable": "钻机状态:稳定", + "Silo Power Module": "舱体电力模块", + "RAZE STRATEGIC INFRASTRUCTURE": "摧毁战略基础设施", + "Infiltrate this site to acquire high-value intel, and extract with it in your possession.": "潜入此地获取高价值情报,携带情报撤离。", + "TRANSMITTING DATA": "传输数据", + "SEAF units have encountered Impalers in this region. They are not capable of dealing with this threat.\n\nAs elite Helldivers, you must hunt down and kill all Impalers in the area.": "超级地球武装部队已在该地区遭遇穿刺虫。他们无法应对这一威胁。\n\n作为精锐部队的绝地潜兵,你必须找到并消灭该地区所有穿刺虫。", + "An illegal propaganda broadcast has been traced to this location.": "经追查发现,有非法宣传广播正在此处运营。", + "A heavily-guarded cache of high-grade platinum is located here. The material is the rightful property of Super Earth and its citizens, and it is your duty to reclaim it. \n\nLocal reinforcements will activate as soon as your presence is detected. Get in, reclaim the material, and get out.": "这里存有一批高品质铂金,周围戒备森严。这些物资属于超级地球及其公民的合法财产,将其夺回是你们的职责。\n\n敌军在当地的增援部队一旦发现你们,就会立即启动。闯入目的地,夺回物资,然后撤离。", + "Drill may disturb subterranean creatures": "钻机可能惊扰地下生物", + "SILO HATCH LOCKED": "发射井舱门未解锁", + "ACTIVATE TCS+": "启动TCS+", + "Enemy ships deployed: #COUNT": "已部署敌舰数:#COUNT", + "ERROR: DISENGAGE ALL HATCH LOCKS": "错误:请解除所有舱门锁", + "Destroy Shrieker-infested towers to cleanse this district from its would-be parasites.": "摧毁遍地尖啸虫的塔巢,清除此区域中潜藏的寄生虫。", + "Eradicate Terminid eggs": "彻底清除终结族虫卵", + "Heavy Automaton forces are gathered in this location.": "大批机器人部队集结于此地。", + "A mechanical chiller at this location cools the hydrogen that flows into the Cyborg Production Unit.": "这里的机械冷却器为流入生化人生产单元的氢气降温。", + "Kill the Terminid": "击杀终结族", + "RELEASE STERILIZING AGENT": "释放灭菌剂", + "CONDEMN ILLICIT EXPERIMENTS": "谴责非法实验", + "Destroy the Bio-Processors that fuel synthesis of organic plasma, then extract.": "摧毁为合成有机等离子提供动力的生物处理器,然后撤离。", + "Activate the Seismic Scan": "启动地震扫描", + "Battery Silo 03 Offline": "电池舱03停用", + "Destroy Automaton Dropships": "摧毁机器人运输舰", + "Brave the Megafactory and liberate this land from Cyborg occupation.": "勇闯超大型工厂,将这片土地从生化人的占领中解放出来。", + "Find probes sent into the Gloom and extract their research data.": "找到发射至“阴霾”的探测仪,提取研究数据。", + "Use hub terminal to upload recordings": "使用中继站终端上传记录", + "Once the black box has been secured, it must be transported to this interplanetary uplink site to upload its data to the Ministry of Defense's top-secret network.": "拿到黑匣子之后,必须将它转移到这个星际上行链路点位,将数据上传到国防部的绝密网络。", + "B. Silo 03": "电池舱03", + "ALERT: ENCRYPTED TRANSMISSION RECEIVED\n\nDECRYPTING…\n.\n.\n.\nCLASSIFICATION: TOP SECRET\n\nMINISTRY OF DEFENSE\nDIRECTORATE OF HELLDIVER READINESS\nORIGINATING STATION: MARS\n\nMEMORANDUM FOR: Helldiver Readiness Command\nSUBJECT: Daily Incoming Recruit Report\n\nTotal Incoming Trainees: 48,736\nAvg. Age (Years): 18.7 \nAvg. Combat Readiness Rating: 27.1%\nAvg. Patriotism Rating: 97.4%\n\nExpected Survival Rate: 21.3% \nProjected Helldiver Production: WITHIN QUOTA\n\nEND TRANSMISSION": "警告:接收到加密传输\n\n正在解密……\n.\n.\n.\n级别:绝密\n\n国防部\n绝地潜兵备战理事会\n发出站:火星\n\n备忘录收件人:绝地潜兵备战指挥部\n主题:新兵招募每日报告\n\n受训新兵总数:48,736\n平均年龄(岁):18.7\n平均备战评分:27.1%\n平均爱国评分:97.4%\n\n预期存活率:21.3%\n绝地潜兵计划产量:配额内\n\n结束传输", + "OUTFLOW": "外流", + "Use terminal to align communication signal": "使用终端校准通信信号", + "New Missions Available": "解锁新任务", + "Deep cover intelligence has, through highly classified and heroic means, identified a mutated strain of larvae in this hive. Find the mutated larvae and retrieve them for study by our heroic Bug Anatomy/Weapons Development (BAWD) Specialists.": "我方人员英勇果敢地通过高度保密的途径传回情报,确定此虫窝内存在一种变异幼体。找出并带回变异幼体,供虫族解剖/武器研发(BAWD)的英勇专家进行研究。", + "EVACUATE COLONISTS": "撤离拓殖地居民", + "SECURE RESEARCH SITE": "保障研究地点的安全", + "Opportunity Completed": "完成机遇任务", + "OPPORTUNITY REWARD": "机遇奖励", + "EVACUATION PROTOCOL: ACTIVE": "疏散协议:已启动", + "Proceed to Support Stratagem Training Area": "前往支援战略配备训练区", + "FUSE 5": "熔断器5", + "Defend Battery Silo until activation is complete": "保卫电池舱,直到启动完毕", + "A massive number of Automaton militants are concentrated in this overrun city. Decisive action must be taken to reduce their numbers. \n \nDeploy to the middle of the combat zone, and kill as many bots as you can.": "大量机器人武装分子集结在这座沦陷的城市中。必须果断采取行动,削减它们的数量。\n\n动身前往战区中心,全力消灭机器人。", + "Confirm depth using drill interface": "使用钻机界面确认深度", + "Gather nearby assets and place them in the container": "收集附近的资源,放进容器里", + "Pull transformer unit lever": "拉动变压器单元操纵杆", + "Eliminate Brood Commander": "消灭虫族指挥官", + "Escort Citizens safely to Shuttle Bay": "护送公民安全前往运输船坞", + "Please clear launch area": "请离开发射区域", + "OPERATION MODIFIER ADDED": "已添加行动限制条件", + "Purge Terminid spawn by delivering a nuclear payload to all Nursery Chambers.": "将核炸药送入所有繁育腔室,彻底清除终结族幼虫。", + "LAUNCH SEQUENCE INITIATED": "发射程序已启动", + "Find and destroy any active Automaton fabricators": "寻找并消灭所有运作中的机器人构筑者", + "TWO": "二", + "In this region, orbital bombardment has exposed seams of what appear to be rare and valuable mineral ores. \n\nWe cannot let the Automatons exploit them before the planet is liberated. Get down there and collect soil sample data, to confirm if the material is worth extracting.": "该地区在轨道轰炸之后露出的矿层中似乎存在稀有的珍贵矿石。\n\n绝对不能放任机器人在我们解放这颗星球前开采这些矿石。前往地表,收集土壤样本数据,确认其开采价值。", + "Glorious Victory": "辉煌胜利", + "Warning: Critically Unstable": "警告:状态极其不稳定", + "Protect our way of life from the Automatons by any means necessary.": "不惜一切代价也要捍卫我们的生存之道,不能让机器人损害半分。", + "RETRIEVE VALUABLE DATA": "检索有价值的数据", + "File transfer in progress": "文件正在输送", + "PROVING GROUND OPERATION": "试炼场行动", + "MAIN COMPONENTS": "主要组件", + "DISRUPT SHIELD GENERATOR": "破坏防护罩生成装置", + "LOAD ARTILLERY SHELLS": "装填炮弹", + "Pumping in progress...": "正在泵取……", + "A Ground All-Terrain Extraction Rig (GATER) has been deployed to this area, where multiple high-value substance reservoirs have been identified.\n\nYou have been summarily certified as Expert Large Vehicle Operators. Deploy to the area and utilize the GATER to extract the mysterious substance from all identified locations.": "此区域已部署地面全地形采集钻机(GATER),也已确认存在多个珍贵物质储藏点。\n\n仓促间你已被授予大型载具驾驶专家的资格。请部署到该区域并使用GATER从所有确认地点提取神秘物质。", + "According to atmospheric measurements, airborne spore density in this area is reaching critical levels. It is only a matter of hours before this district becomes uninhabitable.\n\nDestroy the Terminid bio-weapons producing these spores, and allow our citizens to breathe Freely once more.": "根据大气测量数据,此区域空气中的孢子密度已接近临界水平。再过几个小时,此区域将变得不适宜居住。\n\n摧毁产生这些孢子的终结族生物武器,让我们的公民能再次自由呼吸。", + "GUNSHIP FACILITY": "炮舰设施", + "DATA JACK OPERATIONAL": "数据接口运作正常", + "RETRIEVE THE CHEMICALS": "回收化学原料", + "BUFFER TANK": "缓冲罐", + "Use terminal to sabotage Control Tower": "使用终端破坏控制塔", + "DESTROY BIO-PROCESSORS": "摧毁生物处理器", + "Open valve": "打开阀门", + "Please reset all blown fuses": "请重置所有熔断的熔断器", + "Escort facility staff safely to Evacuation Shuttle": "将设施人员护送至疏散运输船", + "MISSION TIME #HOURS:#MINUTES:#SECONDS": "任务时长 #HOURS:#MINUTES:#SECONDS", + "ACTIVATE LAUNCHER SUB-SYSTEMS": "启动发射器子系统", + "PLANETARY DEFENSE CANNON ARMED": "行星防御加农炮已启动", + "EARN YOUR HELLDIVER CAPE": "努力赢得绝地潜兵披肩", + "Smelting": "冶炼", + "RAISE FLAG OF SUPER EARTH": "升起超级地球旗帜", + "Confirm that drill site is safe for operation": "确认钻探地点可安全作业", + "Defend Drill during deployment": "部署期间保卫钻机", + "Enter the GATER": "进入GATER", + "INPUT ACTIVATION SEQUENCE": "输入启动程序", + "THREAT LEVEL: LOW": "威胁等级:低", + "CONFIRM DRILL POSITION": "确认钻机位置", + "Cut the bots off from their information network by destroying their Command Bunkers.": "摧毁指挥碉堡,切断机器人的信息网络。", + "Turn Off": "关闭", + "Enemy hostiles have located a reserve of classified defensive assets placed in long-term storage for city defense. To prevent the hard-fought cache from falling into the enemy's totalitarian grip, they must be rapidly evacuated off-world.\n \nCommencing evacuation will reveal your position to the invaders. Defend the site until transport is complete.": "敌军已发现一批为城防长期储备的机密防御资产。为防止这批来之不易的储备物资落入敌人极权的掌控之中,必须迅速将其撤离至外太空。\n\n启动撤离程序后,入侵者将知晓你的位置。保卫阵地,直至撤离完成。", + "A massive Terminid swarm has gathered in this area. We cannot leave this threat unchecked if we are to take the city back.\n\nKill as many Terminids as you can to thin their numbers.": "大批终结族已在此区域聚集。要夺回这座城市,我们必须消除这一威胁。\n\n全力击杀更多终结族,削减它们的数量。", + "This planet is so thoroughly infested that it appears to be a single interconnected Terminid hive. Gloom spores originate from somewhere inside this planet.\n\nIt is difficult to predict what threats will be encountered on this planet. The Helldivers must delve into the enemy's caves to expunge their secrets. Reclaim the Hive World and free our citizens from the terror of the Gloom.": "这颗星球彻底被侵染,看起来就像内部互相连通的巨大终结族虫窝。“阴霾”孢子源自这颗星球内部某处。\n\n我们很难预测会在这里遭遇怎样的威胁。绝地潜兵必须深入敌方洞穴,抹除它们的秘密。收复虫窝世界,让我们的公民摆脱对“阴霾”的恐惧。", + "Recover the dropped #ENTITY": "取回掉落的#ENTITY", + "ACTIVATE DRILL 1?": "是否启动1号钻机?", + "HIGH-VALUE PICKUPS": "高价值拾取物", + "SYSTEM BOOTING...": "系统正在启动…", + "ICBM raising into launch position": "洲际弹道导弹正在抬升至发射位置", + "ELIMINATE FACTORY STRIDER": "消灭移动工厂", + "THREE": "三", + "ERADICATE ILLUMINATE FORCES": "彻底消灭光能者部队", + "We must seize this opportunity to destroy the Terminid Supercolony. Helldivers all across the planet will deploy with a limited supply of the exotic matter known as Dark Fluid, and insert it at critical points in the planet's crust. \n\nOnce critical mass is reached, the planet will collapse into a black hole, destroying the threat to Liberty once and for all.": "我们必须抓住这次机会,摧毁终结族超级拓殖地。全星球的绝地潜兵将携带名为“暗液体”的限量供应奇异物质上阵,须将这种物质注入星球地壳的临界点。\n\n一旦达到临界质量,星球就会坍缩成黑洞,彻底摧毁所有威胁自由的敌人。", + "Eradicated Light Bug Nest": "已摧毁轻型巢穴", + "Megafactories like this one double as strategic command nodes and industrial cores for large-scale Cyborg and Automaton production.\n\nStorm its walls and reduce this socialist hub to rubble.": "这类超大型工厂既是生化人的战略指挥节点,也是它们用于大规模生产生化人和机器人的工业核心。\n\n攻破其防御系统,将这个暴政据点夷为平地。", + "Reports indicate that a Bile Titan was last observed in this location.": "报告显示,吐酸泰坦的最后目击地点就在这个位置。", + "Use Prospecting Drill to retrieve final sample": "使用勘探钻机取得第三份样本", + "The Terminid advance has swarmed across this region, leaving one of our top secret research stations surrounded by the enemy.\n\nUse your clearance to unlock the emergency bunker doors, and defend the facility staff as they transfer to the evacuation shuttle.": "终结族的大军已经席卷了这个地区,我们的绝密研究站被敌人包围。\n\n使用你的权限打开紧急掩体的门,将该设施中的人员转移到疏散运输船,并在这个过程中保卫他们的安全。", + "Plant flag in designated area": "在指定区域竖立旗帜", + "Destroy the Illuminate's Gazer Spires.": "摧毁光能者凝视者尖塔。", + "Weather Reconnaissance aircraft that were in operation when the Gloom originally spread to this planet may contain useful data on Gloom-infused atmosphere. \n\nFind their black boxes and use a local relay station to decrypt and upload the research data to the Ministry of Science mainframe.": "在“阴霾”最初蔓延至该星球时,恰有气象侦察机在空中作业,或许能提供有关“阴霾”侵袭大气层的有用数据。\n\n找到黑匣子,利用当地中继站解密研究数据并上传至科学部主机。", + "Deposit Tactical Video Camera in Hub container": "将战术摄像机存入中继站储存箱", + "Reset Tower Alignment": "重置激光雷达塔对齐", + "FIRING SEQUENCE INITIATED": "发射程序已启动", + "SAMPLE 03": "样本03", + "The Automaton Legion relies on its strict hierarchical structure; remove the leaders, and the ranks will fall easily.\n\nWe believe there are Devastators present in the region. Find them, and destroy them.": "机器人军团依赖于严格的层级结构。清除领袖,它们的军队就会土崩瓦解。\n\n据悉,该地区存在蹂躏者。找到它们并将其摧毁。", + "DESTROY GAZER SPIRE": "摧毁凝视者尖塔", + "Decades-old pumps have been rendered inoperable by unchecked Terminid infestation. But the pumps remain structurally intact, and the reservoirs they once pumped are now filled with extremely valuable E-711.\n\nClear the Terminid outgrowth clogging the pipeline, and restore it to operation.": "因为终结族肆虐侵染,在这里放置数十年的泵机无法正常运作。但这些泵机的结构仍然完好,从前泵取的库存现在装满了极为珍贵的711元素。\n\n清除堵塞管道的滋生终结族,让管道恢复运作。", + "System Access Module": "系统访问模块", + "INSTALL ROOTKIT": "安装后门程序", + "LINK TO SUPER DESTROYER": "连接至超级驱逐舰", + "Reduce the bug population by any means necessary.": "不惜一切手段减少虫族数量。", + "RECLAIM CITY": "收复城市", + "LINK HELLPODS TO DESTROYER": "将绝地喷射舱连接至驱逐舰", + "Disgraceful Conduct": "可耻行为", + "PURGE HATCHERIES": "清除孵化点", + "Wait": "请稍候", + "Influence (Start)": "影响力(初始)", + "Destroy all the mutated Terminid eggs in this area.": "摧毁该地区内所有的变异终结族虫卵。", + "Repel the enemy forces attempting to claim this city.": "击退企图占领这座城市的敌军。", + "Mournful Victory": "悲哀得胜", + "Please evacuate the premises": "请从此处撤离", + "Eradicate the Gloom-producing Spore Lung deep within the Hive.": "消灭深藏在虫窝内孕育“阴霾”的孢肺。", + "Raise the Super Earth flag as an unassailable beacon of Liberty.": "升起超级地球旗帜,犹如树立起一座坚不可摧的解放灯塔。", + "Drill sites excavated": "已挖掘的钻探点", + "Fuel transfer in progress": "燃料正在输送", + "#COUNT SAMPLES": "#COUNT份样本", + "SABOTAGE AIR BASE": "破坏航空基地", + "Insert SSSD into receptacle": "将超级固态硬盘置入插槽", + "Insert SSSD into hatch": "将超级固态硬盘置入舱门", + "Manual valve adjustment required": "需要手动调整阀门", + "Decades-old pumps have been rendered inoperable by unchecked Terminid infestation. But the pumps remain structurally intact, and the reservoirs they once pumped are now filled with a new, strange E-710-like substance. \n\nClear the Terminid outgrowth clogging the pipeline, and restore it to operation.": "因为终结族肆虐侵染,在这里放置数十年的泵机无法正常运作。但这些泵机的结构仍然完好,从前泵取的库存现在装满了类似710元素的新奇怪物质。\n\n清除堵塞管道的滋生终结族,让管道恢复运作。", + "Cleared Stronghold": "已摧毁要塞", + "OPEN SILO HATCH": "打开发射井舱门", + "Lightning Spire": "闪电尖塔", + "Deployed Enemy Ship": "已部署敌舰", + "B. Silo 02": "电池舱02", + "Terminids in this area are multiplying exponentially. Left unchecked, this infestation will soon grow out of hand.\n\nDestroy their hives and kill as many bugs as you can.": "该地区的终结族正以指数级增长。如不加以管控,虫害很快就会到了一发不可收拾的地步。\n\n摧毁它们的虫窝,竭力消灭这些虫族。", + "We must show the galaxy that even in the face of oppression, Freedom remains defiant. \n \nInfiltrate this Terminid-infested region and raise our Flag as an unassailable beacon of Liberty.": "我们必须让整个银河系都知道,纵使面对压迫,自由仍傲然不屈。\n\n潜入终结族占据的这个地区,升起我们的旗帜,犹如树立起一座坚不可破的解放灯塔。", + "RAISING LAUNCHER": "正在抬升发射器", + "ACTIVATE TOWER": "启动通信塔", + "Fortification Quantity": "防御工事数量", + "Call down a Hellbomb to destroy the Cannon": "呼叫地狱火炸弹摧毁加农炮", + "Loadout Progression": "武装配置进度", + "RETRIEVE ESSENTIAL PERSONNEL": "找回重要人员", + "Select hydrogen outflow target": "选择氢气流出目标", + "ACTIVATION FAILURE: VALVES BLOCKED": "启动失败:阀门受阻", + "Long-range laser artillery enforces the Illuminate's tyrannical grip over this area, engaging targets in orbit and on the ground with deadly precision.\n\nTheir presence prevents us from establishing a foothold in this region. Deploy to the area and eliminate all active Gazer Spires.": "远程激光大炮维系着光能者对该区域的暴政统治,它们能以致命精度打击轨道和地面目标。\n\n这些武器的存在,导致我方无法在该地区内建立据点。部署到该区域,摧毁所有还在运行的凝视者尖塔。", + "TCS+ activation complete": "TCS+激活完成", + "Com.Mission Inf (Self)": "完成任务的影响力(自我)", + "The Void's loitering presence has visibly reshaped the surface of this world. Further analysis is required to determine how deep this corruption extends below ground.\n\nYou have been issued a reinforced Prospecting Drill. Collect soil samples to assess the full extent of the Void's unnatural influence.": "寂域盘踞附近,已明显重塑该星球的地表环境。需开展进一步分析,查明这种腐化现象在地下的渗透深度。\n\n你已获得一台加强版勘探钻机。采集土壤样本,评估寂域所带来的异常影响范围。", + "Initiate to download data to encrypted SSSD": "启动并将数据下载至加密超级固态硬盘", + "Transport Vessel to Payload Site": "运送容器至投放点", + "Fuel transport shuttle incoming": "燃料运输船即将抵达", + "Battery Silo 02 Offline": "电池舱02停用", + "Infiltrate the site and acquire undeniable evidence of the enemy's unforgivable crimes.": "潜入现场,获取敌军不可饶恕罪行的铁证。", + "Utilize the GATER to extract the E-711 from all identified sites.": "使用GATER从所有确认地点提取711元素。", + "Specimen Case": "样本箱", + "ONE": "一", + "Deliver any SSSD Hard Drives": "运送所有超级固态硬盘", + "Drill site nearby": "附近有钻探点", + "DAILY REWARD": "每日奖励", + "Secure a black box containing critical intel from a downed SEAF recon aircraft.": "从被击落的超级地球武装部队侦察机中取回存有关键情报的黑匣子。", + "Evacuate civilians trapped behind Automaton lines.": "疏散被困在机器人战线后方的平民。", + "The Automatons have constructed an air base where our citizens' homes once stood, allowing them to dominate the city's airspace. \n\nBreach the base and raze it to the ground. Don't leave a single Dropship standing.": "机器人在公民家园的废墟上建造起了空军基地,借此掌控了城市的制空权。\n\n突入基地,将它夷为平地。运输舰一艘都不要留。", + "Find Impaler": "找到穿刺虫", + "The Ministry of Science has launched hundreds of thousands of robotic space probes into the Gloom. The Gloom interferes with signal transmission. One is crashed in this area.\n\nFind the probe, and boost its signal to transmit its data past the atmospheric Gloom to the Super Destroyer.": "科学部向“阴霾”发射了数十万个机器人太空探测仪。但“阴霾”会干扰信号传输。有一个探测仪在此区域坠毁。\n\n找到探测仪并增强其信号,将数据穿越大气层中的“阴霾”传至超级驱逐舰。", + "Adjust valves in Control Chamber to overload engine": "在控制室调节阀门使引擎过载", + "INITIATE AREA SCAN": "启动区域扫描", + "Use terminal to open bunker hatch": "使用终端,打开掩体舱门", + "Defy invaders who dare forsake our flag. Proudly raise our enduring symbol of Managed Democracy, and reclaim this city in the name of Freedom.": "抗击丢弃我方旗帜的入侵者。高举管理式民主的不朽象征,以自由之名收复这座城市。", + "SEAF troops report sightings of a Devastator in this area.": "超级地球武装部队士兵报告称,在这片区域发现了蹂躏者。", + "Uploading data to Super Earth Mainframe": "正在向超级地球主机上传数据", + "Redirect fuel to new target": "更改燃料流向,将其输送至新目标", + "You will be fighting the #RACE.": "你将会迎战#RACE。", + "WAR IMPACT": "战争冲击", + "Operating at 100% efficiency": "当前运行效率:100%", + "Victory": "胜利", + "Intel has pinpointed the storage of two highly valuable products at this location: high-grade platinum and fusion batteries. Produced at extremely high cost, the materials are intended to facilitate the mass murder of innocent civilians. It is imperative that they are seized before this can happen.\n\nRaid the facility. Secure and extract platinum bars and fusion batteries on-site.": "情报部门已确定此处储存着两种高价值物品:高纯度铂金和聚变电池。这些材料耗费巨资生产,敌人意图用来大规模屠杀无辜平民。必须赶在它们达成目标之前夺得这些材料。\n\n突袭基地。夺取并撤走现场的铂金条和聚变电池。", + "Escort and protect researchers as they travel to the evacuation zone.": "护送研究员安全转移至疏散区。", + "Hatch opening. Thank you for your patience.": "舱门正在开启。感谢你的耐心等待。", + "Please adjust routing protocol": "请调整路由协议", + "SAMPLE COLLECTION IN PROGRESS": "正在收集样本", + "INTEL EXTRACTED BY": "情报提取人:", + "This anti-aircraft emplacement is preventing the spread of liberty across the skies of this planet. Take it out before any more families are forced to attend martyrdom celebrations for their fallen heroes.": "此对空炮台将妨碍自由在这颗星球的天空中传播。越快摧毁,越少家庭被迫感受阵亡英雄哀悼会的痛楚。", + "Data Jack Status: Critically Damaged": "数据接口状态:严重受损", + "Eliminate Variant": "消灭亚种", + "CULL SPAWN": "抑制孵化", + "Completing this Operation helps liberate this Megafactory. Successfully liberating Megafactories significantly contributes to the planet's Liberation.": "完成此次行动有助于解放这所超大型工厂。成功解放超大型工厂将大幅推动星球解放进程。", + "Unknown and unexpected system error": "未知意外系统错误", + "Fuel": "燃料", + "A cache of 99% purity platinum is located here. The Automatons intend to use this valuable metal to endanger Democracy. Seize it.": "这里存有一批纯度高达99%的铂金。机器人企图利用这批贵重金属来危害民主伟业。夺取铂金。", + "AVERT VOID": "抵御寂域", + "Destroy the Automatons' Counter-Orbital Cannons in the area.": "摧毁该区域内机器人的反轨道加农炮。", + "OPERATION COMPLETED": "行动完成", + "Eliminate Devastators": "消灭蹂躏者", + "Proceed to Final Test": "前往终极考验", + "A TCS+ station at this site is loaded with refined Termicide 2.0, now with no credible risk of unintended mutagenic side effects. Once initiated, it will sterilize the area with fumes highly lethal to Terminids, yet entirely safe to humans.\n\nActivate the TCS+ station, and bathe the region in a purifying haze of Termicide.": "此处的TCS+站已装载精制灭虫终结剂2.0,无任何可证实的意外诱变副作用风险。一旦启动,它将释放对终结族极度致命但对人类完全安全的烟雾,对该区域进行彻底消杀。\n\n启动TCS+站,让这片区域沐浴在灭虫终结剂的净化烟雾中。", + "Confirm": "确认", + "The Cyborgs dictate the surrounding air domain from this fortified air base. It must be decisively obliterated.\n\nInfiltrate the base and tear it down. Destroy any grounded Dropships in sight.": "生化人凭借这座要塞化空军基地掌控着周边空域。必须将其彻底摧毁。\n\n渗透基地并将其拆毁。摧毁看到的所有停靠运输舰。", + "Use terminal to activate fuel transfer": "使用终端,重新启动燃料运输", + "AIR CONTROL TOWER MAINFRAME": "航空控制塔主机", + "DEFEND PLANET": "保卫星球", + "Free trapped colonists and escort them to safe evacuation.": "释放受困的拓殖地居民,护送他们前往安全的撤离点。", + "AQUIFER DRILL": "含水层钻机", + "Release the hose": "卸除软管", + "ESTABLISHING LINK": "建立连接", + "Massive uncanny storms have erupted on this planet. These \"Exostorms\" emanate from otherworldly spires, unearthed by the Illuminate from the ruins of their fallen empire.\n\nThe intentions of the Illuminate are unclear, but undeniably sinister. Strike their crude bases and return them to rubble.": "这颗星球上爆发了诡异的巨型风暴。这些“异界风暴”的源头是光能者从其陨落帝国废墟中挖掘出的异界尖塔。\n\n光能者的意图不明,但无疑邪恶至极。直捣这个粗制滥造的基地,将其再次夷为平地。", + "OPEN SSSD HATCH": "打开超级固态硬盘舱门", + "CONDUCT MOBILE E-711 EXTRACTION": "移动式提取711元素", + "Turn On": "开启", + "Throw grenade into artificial bug hole": "将榴弹丢进人造虫穴", + "EXTRACT E-711": "提取711元素", + "Deactivate corrupted battery silos": "关闭出错的电池舱", + "Destroy all Harvesters in the area.": "摧毁区域内的所有猎杀器。", + "All assets evacuated. Proceed to extraction.": "全部目标已疏散完毕。开始撤离程序。", + "Illuminate Warp Ships are docked here. Destroy them while they are vulnerable.": "光能者穿梭舰在此停靠。趁它们不备时摧毁穿梭舰。", + "PROTECT LAUNCHERS": "保护发射器", + "Our enemies have forced conflict upon this region. There can be no peace until they are defeated.": "敌军让该地区陷入战火之中。唯有将其击败才能恢复和平。", + "The Automatons are conducting mineral surveys to identify rich ore veins to recklessly exploit. It is critical that we secure those sites first, so that this planet's resources are used responsibly. \n\nExpropriate the coordinates of this region's prospective sites from the Automatons, and extract site samples to assess their potential.": "机器人正在开展矿物勘探,寻找能够供它们肆意开采的富矿脉。我们必须抢先占领这些地点,确保该星球的资源得到合理利用。\n\n从机器人手中没收该地区勘探点的坐标,并提取现场样本,评估开采潜力。", + "Please manually disengage all hatch locks.": "请手动解除所有舱门锁。", + "Locate and eliminate the Automaton Hulk.": "找到并消灭机器人巨型者。", + "Automaton Dropship": "机器人运输舰", + "A SEAF research station in the region has been overrun by Terminids. Their vital work must be recovered.\n\nGet to the station, download the research database, and upload it to the Super Earth mainframe using the nearby Satellite Uplink Station.": "该地区的一座超级地球武装部队研究站已被终结族占领。他们的重要工作必须恢复。\n\n前往该研究站,下载研究数据库,然后使用附近的卫星上行链路站点将其上传至超级地球主机。", + "Larva Container": "幼虫储存器", + "Raising the symbol of Managed Democracy will send an undeniable message that Freedom reigns in this land once more.": "举起象征管理式民主的标志将传递出毋庸置疑的信息:自由精神再次征服这片拓殖地。", + "Eradicated Medium Bug Nest": "已摧毁中型巢穴", + "Access codes for the Planetary Defense Cannon are held at this location.": "行星防御加农炮的访问代码存放在此处。", + "Sabotage the Megafactory's fuel and ammunition depots.": "破坏超大型工厂的燃料和弹药库。", + "INITIATE EMERGENCY BACKUP": "启动紧急备份", + "Use Orbital Precision Strike Stratagem to kill enemies": "使用轨道精准攻击战略配备击杀敌人", + "Use terminal to initiate emergency data backup": "使用终端启动紧急数据库备份", + "HELLDIVERS EXTRACTED": "绝地潜兵撤离数", + "Research Point": "研究点数", + "INITIATE DATA WIPE": "启动数据抹除", + "Moving to drill position...": "移动到钻探位置……", + "STIMS USED:": "治疗剂使用次数:", + "Relay Tower": "中继塔", + "The Prospecting Drill in this location can extract sediment cores, analyze their composition, and upload the generated data.": "这里的勘探钻机可以提取沉积物核心,分析其成分,并上传产生的数据。", + "Find the Illuminate altar": "找到光能者祭坛", + "TRACE LOCAL DEFENSE NETWORK": "追踪本地防御网络", + "Allow shuttles to collect deposited fuel from reserves.": "让运输船从油田采集沉积燃料。", + "The black box must be delivered to the interplanetary uplink site at this location, for encrypted upload to the Ministry of Defense.": "必须将黑匣子转移到该位置的星际上行链路点位,以便加密上传至国防部。", + "BUG HORDE": "虫族群袭", + "SAM Launcher": "地对空导弹发射器", + "KILL BUGS": "击杀虫族敌人", + "Destroy fuel silos": "摧毁燃料仓", + "SILO FULLY CHARGED": "舱体充能完毕", + "ERROR: Communication Tower Offline": "错误:通信塔离线", + "Please access the nearby transmission station to proceed": "请前往附近的传输站继续操作", + "Use Stratagem: #ENTITY": "使用战略配备:#ENTITY", + "Deploy deep behind enemy lines. Certain missions will have severely limited Super Destroyer support.": "深入敌后。部分任务将很难获得超级驱逐舰支援。", + "SEIZE THE CIVILIAN SATELLITE TOWERS": "夺取民用卫星塔", + "RECOVER SSSD": "找回超级固态硬盘", + "BATTERY STORAGE STATION CONSOLE": "电池储存站控制台", + "Investigate and Upload Findings": "调查并上传发现的结果", + "Destroyed Light Automaton Outpost": "已摧毁轻型机器人哨站", + "EXPECTED PAYOUT": "预期收益", + "Wait for Data Jack to deploy": "等待数据接口部署", + "Take down the Harvester": "解决猎杀器", + "Investigate Rogue Research Station": "调查叛变科研站", + "Glorious Sacrifice": "光荣牺牲", + "Emergency Holding Area Terminal System": "应急等待区终端系统", + "An experimental vessel containing 40 grams of weapons-grade Dark Fluid suspended in a magnetic field.": "试验性容器,装载有40克武器级暗液体,悬浮于磁场之内。", + "Downloading research data to SSSD": "正在将研究数据下载到超级固态硬盘", + "Successful Extraction": "成功撤离", + "REDIRECT FUEL FLOW": "更改燃料流向", + "Please stand by.": "请稍候。", + "While most Terminids were killed by the Termicide, some survived and adapted. Now, they threaten to evolve further and take over the entire planet. Every Termicide Dispersion Tower on this planet must be shut down as soon as possible.": "尽管灭虫终结剂消灭了大部分终结族,但是仍有一部分幸存了下来,并且适应了灭虫终结剂。现在,它们甚至有可能进一步进化,占领整颗星球。必须尽快关闭这颗星球上的每一座灭虫终结剂喷洒塔。", + "Hatch opening…": "舱门正在开启……", + "Insert Vessel into Drill": "将容器置入钻机", + "MISSION TIME REMAINING": "任务剩余时间", + "Destroy Automaton infrastructure to cripple their troop production capabilities.": "摧毁机器人的基础设施,削弱它们的军队生产能力。", + "DISRUPT SOCIALIST INDUSTRY": "破坏党同伐异的产业", + "Access Codes": "访问代码", + "DEFENSE NETWORK BREACHED": "防御网络已突破", + "Liberty guides our hand": "解放精神指引我们行动", + "DESTROY AIR BASE CONTROL TOWER": "摧毁航空基地控制塔", + "Com.Mission Inf (Community)": "完成任务的影响力(社区)", + "RETRIEVE ACCESS CODES": "取回访问代码", + "SAMPLES EXTRACTED:": "提取样本数:", + "Verify all readings are within unsafe limits": "确认所有读数都在非安全限度内", + "Enemy ships in reserve: #COUNT": "待部署敌舰数:#COUNT", + "PLEASE EVACUATE AREA": "请撤离该区域", + "Rocket Launch in Progress": "准备发射火箭弹", + "ANNEX QUARRY": "吞并采石场", + "Locate Pump Site": "找到泵机", + "Intel indicates that the Automatons are stockpiling ammunition in this location.": "情报显示机器人正在此地囤积弹药。", + "FUSE 2": "熔断器2", + "The bio-processors here are the first step in synthesis of organic plasma. They must be destroyed.": "这里的生物处理器是合成有机等离子的第一步。必须将其摧毁。", + "REFINERY CENTRAL CONTROL": "精炼厂中央控制", + "MISSION IMPACT": "任务影响", + "Transport SSSD Hard Drive to Communications Relay": "将超级固态硬盘转移至通信中继站", + "Kill all Terminids": "击杀所有终结族", + "SAMPLES EXTRACTED #COUNT": "提取样本数 #COUNT", + "Pick up Secondary Weapon": "拾取次要武器", + "Daily Complete": "完成每日任务", + "Eradicate Void blossoms to combat planetary mutation.": "铲除寂域之花,阻止星球变异。", + "Ready to initiate reloading sequence for M723 Orbital Slag Shell": "即将启动M723轨道熔渣炮弹装填程序", + "Find mining sites identified by the Automatons and extract samples to assess their potential.": "寻找机器人发现的采矿点,提取样本,评估开采潜力。", + "Local communication towers must be located and activated, to enable broadcasts to civilians.": "必须定位并启动本地通信塔,才能向平民进行广播。", + "Free this land from Illuminate occupation.": "把这片土地从光能者的占领中解放出来。", + "Initiate Fire Sequence": "启动开炮进攻程序", + "x#VALUE": "x#VALUE", + "INITIATE PRODUCTION SEQUENCE": "启动生产序列", + "Verify post-landing integrity": "核实着陆后完整性", + "TERMINATE ILLEGAL BROADCAST": "关停非法广播", + "Deactivating...": "正在关闭…", + "REDIRECT FUEL TO NEW TARGET": "更改燃料流向,将其输送至新目标", + "Cognitive Disruption Field detected": "侦测发现感知干扰域场", + "Conduct a geological survey to identify valuable ore veins.": "进行地质调查,寻找珍贵矿脉。", + "We have received reports of the presence of Bile Titans in this region, posing a considerable threat to our operations.\n\nAny specimen encountered must be eliminated before it has a chance to breed.": "我们收到的报告显示,该地区内出没的吐酸泰坦对我们的行动构成了巨大的威胁。\n\n一旦遇到该生物,立即将其消灭,以防其繁殖。", + "DESTROY EGGS": "摧毁虫卵", + "Automaton Dropships are docked at this location.": "机器人运输舰停靠于此地。", + "Intel indicates a massive and covert Automaton industrial undertaking, which the enemy has taken extreme measures to keep hidden. Further intel is located on the ground at this location. Low orbit interdiction weaponry makes prolonged Destroyer deployment impossible. Once deployed, you're on your own.\n\nThis operation is extremely dangerous. But it is imperative we identify the nature and locations of the Automaton scheme.": "情报显示机器人正在秘密开展大规模工业项目,而且已采取极端措施进行隐蔽。在此处的地面上可获取更多情报。低轨道拦截武器使驱逐舰无法长时间部署。一旦部署,接下来就只能靠你们自己了。\n\n此次行动极其危险。但我们必须查明机器人阴谋的性质和地点。", + "POWER CORE": "动力核心", + "ELIMINATE AUTOMATON HULKS": "消灭机器人巨型者", + "COGNITIVE DISRUPTOR": "感知干扰器", + "Deactivate Battery Silo 03": "关闭电池舱03", + "Use door controls to release facility staff from Emergency Bunkers": "使用门控装置将设施中的人员从紧急掩体中放出去", + "Utilize the GATER to extract the mysterious substance from all identified sites.": "使用GATER从所有确认地点提取神秘物质。", + "An SEAF reconnaissance plane was shot down over this region. Its top-secret intel must be recovered immediately, before it can be destroyed by the enemy.": "超级地球武装部队的一架侦察机在这片沦陷的拓殖地被击落。必须立即取回机上的绝密情报,以免被敌人摧毁。", + "REPEL INVASION": "抵御入侵", + "SWITCH 2": "开关2", + "Initiate Data Transmission": "启动数据传输", + "Locate and destroy Illuminate Warp Gateways.": "寻找并摧毁光能者传送门。", + "This Control Tower is the nexus of enemy aerial operations in the region.": "该控制塔是敌方在此区域空中作战的指挥中枢。", + "An SEAF recon aircraft has been downed by the invaders mid-mission. Recover the aircraft's data drives before they are destroyed.": "一架超级地球武装部队侦察机在执行任务期间被入侵者击落。必须在侦察机的数据驱动器被毁前将其找回。", + "Input launch code: #OTHER": "输入发射代码:#OTHER", + "ALERT: ENCRYPTED TRANSMISSION RECEIVED\n\nDECRYPTING…\n.\n.\n.\nCLASSIFICATION: TOP SECRET\n\nMINISTRY OF DEFENSE\nDIRECTORATE OF HELLDIVER READINESS\nORIGINATING STATION: UNDISCLOSED LOCATION\n\nMEMORANDUM FOR: Helldiver Readiness Command\nSUBJECT: Daily Incoming Recruit Report\n\nTotal Incoming Trainees: 48,736\nAvg. Age (Years): 18.7 \nAvg. Combat Readiness Rating: 27.1%\nAvg. Patriotism Rating: 97.4%\n\nExpected Survival Rate: 21.3% \nProjected Helldiver Production: WITHIN QUOTA\n\nEND TRANSMISSION": "警告:接收到加密传输\n\n正在解密……\n.\n.\n.\n级别:绝密\n\n国防部\n绝地潜兵备战理事会\n发出站:机密位置\n\n备忘录收件人:绝地潜兵备战指挥部\n主题:新兵招募每日报告\n\n受训新兵总数:48,736\n平均年龄(岁):18.7\n平均备战评分:27.1%\n平均爱国评分:97.4%\n\n预期存活率:21.3%\n绝地潜兵计划产量:配额内\n\n结束传输", + "A Terminid Nursery has been identified beneath the surface at this location. Millions of Terminid larvae gestate in the underground chambers.\n\nTerminid Nurseries consist of one or more Nursery Chambers. Use the Hive Breaker Drill to deliver a nuclear extermination device to each one.": "此位置地底下发现了终结族繁育窝。数百万只终结族幼虫正在地下腔室中孵化。\n\n终结族繁育窝由数量不等的繁育腔室组成。使用虫窝破裂者将核灭绝装置送入各个腔室。", + "Pick up the AR-23 Liberator": "拾取AR-23“解放者”", + "Com.Mission Inf (Max)": "完成任务的影响力(最大)", + "ACTIVATE DRILL": "启动钻机", + "Deactivate Stratagem Jamming?": "是否停止干扰战略配备?", + "An abandoned SEAF Mobile Radar is located here. It can provide key information on the local area.": "这里有台被遗弃的超级地球武装部队移动雷达。可以从中获取当地区域的关键情报。", + "Prepare and launch the ICBM.": "做好准备工作,发射洲际弹道导弹。", + "RADAR": "雷达", + "Illuminate Warp Ships have docked at this location. Destroy them.": "光能者穿梭舰已在此处停靠。消灭它们。", + "to Discharge Dark Fluid": "释放暗液体", + "The Exospire rising from these ruins is defiling the atmospheric integrity of the planet. \nIt is protected by a force field that blocks access to its core chamber. Electromagnetic interference may hinder Stratagem usage.\n\nBreach the Exospire's defenses, and destroy its core to trigger its collapse.": "这座从废墟中拔地而起的异界尖塔正在玷污星球大气的完整性。\n它受到力场的保护,通向其核心密室的路径被这一力场所封锁。电磁干扰可能会阻碍战略配备的使用。\n\n突破异界尖塔的防御,通过摧毁其核心促使其坍塌。", + "Wait for generator diagnostics sequence to complete": "请等待发电机诊断程序完成", + "Use terminal to raise surface-to-air launcher": "使用终端抬升地对空导弹发射器", + "Ready to Fire Orbital Cannon. Find target using adjacent control terminal": "准备启动轨道加农炮。利用邻近控制终端寻找目标", + "Repel the Illuminate contingent attacking this planet.": "击退正在攻打这颗星球的光能者分遣队。", + "SQUAD PAYOUT": "小队收益", + "Aerial scanning has identified high levels of Automaton production in this area.": "空中扫描确认该区域存在大量机器人生产活动。", + "MORTAR EMPLACEMENT": "迫击炮台", + "Activate Artillery Terminal": "启动大炮终端", + "Oil pumps activating": "油泵正在启动", + "To limit Terminid population growth, we must strike at their mature hives.\n\nActivate a dormant ICBM silo on the planet to wipe out massive concentrations of bugs at once.": "为了限制终结族种群数量增长的速度,我们必须袭击它们成熟的虫窝。\n\n启动这颗星球上一座暂停使用的洲际弹道导弹发射井,瞬间抹除多个大型虫族聚居地。", + "This building has been overrun by Terminids and is now a Shrieker breeding ground.": "这栋建筑已被终结族攻陷,现在成为了尖啸虫的繁殖之地。", + "An Illuminate Harvester is located in this area. Find it and destroy it.": "此区域有光能者猎杀器。找到它,并将其摧毁。", + "ESTABLISHING CONNECTION": "正在建立连接", + "Artillery Activation Required": "需要启动大炮", + "ESTABLISHING NETWORK LINK": "正在建立网络连接", + "EVACUATE CITIZENS": "疏散公民", + "HIGH-VALUE TARGETS": "高价值目标", + "Drill Status: Damaged": "钻机状态:受损", + "LiDAR Tower currently lowered.": "激光雷达塔现已降下。", + "50% of Objectives Completed": "达成50%的目标", + "Eradicate the specified number of Terminids and Terminid nests.": "消灭指定数量的终结族及其巢穴。", + "DEPLOY DARK FLUID": "部署暗液体", + "Insufficient fuel": "燃料不足", + "Load Fusion Batteries into Cargo Container": "将聚变电池装入货物集装箱", + "The TCS is ready. Secure this planet from the bugs forevermore.": "TCS准备就绪。让这颗星球永远免受虫害。", + "FACILITY OPERATION INACTIVE": "设施无法操作", + "DESTROY FREIGHTERS": "摧毁货轮", + "DRILLING IN PROGRESS": "正在钻探", + "ACTIVATE TCS+ STATION": "启动TCS+站", + "SECURE TACTICAL VIDEO CAMERA": "获取战术摄像机", + "#COUNT [SC]": "#COUNT [SC]", + "The Automatons have gained ground in this city, constructing a network of Fabricators which allow them to replicate extremely rapidly.\n \nTheir locations have been identified. We must strike now before they self-replicate out of control.": "机器人在这座城市中夺得了一席之地,建立起构筑者网络,大幅提高了增殖速度。\n\n它们的位置已确定。我们必须立即行动,防止敌人失控地自我增殖。", + "Stratagem Jamming Inactive": "战略配备干扰程序停止", + "This fueling station is offline. It must be reactivated to initiate fuel distribution.": "这座燃料站已停止运转,需重新启动才能恢复燃料输送。", + "ACCESS RESTRICTED": "禁止访问", + "Free trapped citizens and escort them to evacuation.": "释放受困公民,护送他们前往撤离点。", + "Stand clear of parts being raised": "离开正在抬升的部件", + "DEPLOY THUMPER": "部署地下发射器", + "Cannon operation can damage hearing.": "加农炮操作会损伤听力。", + "ELIMINATE HULK": "消灭巨型者", + "Please adjust all indicated valves.": "请按提示调整所有阀门。", + "Automaton Gunships are being manufactured in this area.": "这个地区在制造机器人炮舰。", + "STATUE": "雕像", + "Colonists who escaped Illuminate abduction and mind control—likely the most patriotic and steadfast of their demographic—are trapped in emergency shelters. The enemy is closing in; without rescue, they are doomed.\n\nTransport ships are inbound, but the evacuation zone is under enemy control. The Helldivers are the colonists' only hope.": "逃离了光能者的囚禁及其精神控制的拓殖地居民(可能是该群体中最爱国、最坚定的人)现在困于紧急避难所中。敌人正在逼近,如果不实施营救,这些居民恐怕连性命也保不住。\n\n运输舰即将抵达,但撤离区域仍受敌人管控。绝地潜兵是拓殖地居民的最后一丝希望。", + "This square is lined with statues of tyrants and war criminals, hailed by the Cyborgs as visionaries.": "这个广场上矗立着暴君和战犯的雕像,生化人却把他们奉为远见卓识之士。", + "DEATHS:": "阵亡次数:", + "Unknowable Forces": "未知力量", + "Engines": "引擎", + "Initiate Firing Sequence": "启动发射程序", + "Activate Battery Silo 03": "启动电池舱03", + "Use Prospecting Drill to retrieve first sample": "使用勘探钻机取得第一份样本", + "EXTRACT RESEARCH PROBE DATA": "提取研究探测仪数据", + "Terrain Scan will reveal nearby locations": "地形扫描可显示附近的地点", + "WARNING: STATION INOPERABLE": "警告:站点无法运转", + "REPEL INVASION FLEET": "击退入侵舰队", + "REACTIVATE POWER GENERATOR": "重新启动发电机", + "ACTIVATE DATA TERMINAL": "启动数据终端", + "EXHAUST SYSTEM NORMAL": "排气系统正常", + "Aim Orbital Cannon": "瞄准轨道加农炮", + "NUKE NURSERY CHAMBER": "用核武器炸毁繁育腔室", + "Log in to the probe interface": "登录探测仪界面", + "BRIEFCASE": "公文包", + "ILLUMINATE ARTIFACT": "光能者古物", + "XP Awarded": "奖励经验", + "The Illuminate are invading our loyal, prosperous, peaceful colony, seeking to turn our citizens into Voteless abominations and create strange energy fields for some unknown, un-Democratic purpose. They must be stopped.": "光能者准备入侵我们忠诚、繁荣、和平的拓殖地,企图将我们的公民变为无票者那样的怪物,然后创造奇怪的能量场,以满足它们非民主的不明目的。必须阻止它们。", + "SSSD HARD DRIVE": "超级固态硬盘", + "EXTRACT ANOMALOUS MATERIAL": "提取异常物质", + "Refinery products are shipped for further processing via freighters docked here. Destroy them.": "精炼厂的产品通过停靠此处的货轮运往后方进行深加工。摧毁它们。", + "Restock ammo": "补充弹药", + "Extract with tactical video camera": "携带战术摄像机撤离", + "Please don't touch moving parts": "请勿触碰活动部件", + "Illuminate Harvesters are patrolling this city block. Seek and destroy the roaming menace.": "光能者猎杀器正在该城区巡逻。搜寻并歼灭这股游荡的敌人。", + "High-value intel of the enemy's plans is hard-coded onto devices that high-confidence intel indicates is located at this location. \n\nInfiltrate the site, acquire the intel, and extract with it in your possession.": "有关敌军计划的高价值情报已通过硬编码写入设备中,可靠情报显示,该设备就在此处。\n\n潜入现场,获取情报,并携带情报撤离。", + "Fortification Class": "防御工事等级", + "KEYCARD": "钥匙卡", + "Enemy defenses in this area make prolonged Super Destroyer deployment impossible for certain missions. Be prepared to operate with severely limited Super Destroyer support.": "该区域敌方防线坚挺,在部分任务中,超级驱逐舰无法长时间部署。请做好无法获得超级驱逐舰支援的准备。", + "Use terminal to complete takeover": "使用终端完成占领", + "Deposit any SSSD Hard Drives in receiving dock": "将全部超级固态硬盘存放到接收码头", + "Destroy Terminid Spore Spewer": "摧毁终结族孢子喷涌虫", + "Activate Liberated terminal": "启动已经解放的终端", + "Destroy the Shrieker Nest": "摧毁尖啸虫巢穴", + "TACTICAL VIDEO CAMERA": "战术摄像机", + "UPLOAD SAMPLE DATA?": "是否上传样本数据?", + "Log in to Shuttle Bay Terminal": "登录运输船坞终端", + "RAISE DISH": "抬升天线", + "Operate Data Jack terminal": "操作数据接口终端", + "A heavily reinforced Automaton convoy is expected to cross through this region. Intercept and destroy the convoy before it leaves the mission area.": "重装强化的机器人车队预计将穿越该区域。在车队离开任务区域之前将其拦截并摧毁。", + "No Reinforcement Pods available": "暂无增援舱。", + "Locate broadcast tower": "找到广播塔", + "Destroy Spore Spewers to allow our citizens to breathe Freely.": "摧毁孢子喷涌虫,让我们的公民能够自由呼吸。", + "BLACK BOX": "黑匣子", + "Repel the Illuminate invaders before they can do whatever it is they are doing.": "在光能者采取任何举动之前将它们驱逐。", + "Retrieve and transmit the vital research data.": "检索并传输关键研究数据。", + "BATTERY SILO 02": "电池舱02", + "An Automaton invasion fleet is attacking this planet.\n\nWe must repel the invading forces before it is too late!": "机器人的侵略舰队正在攻打这颗星球。\n\n我们必须及早击退侵略势力!", + "ELIMINATE BROOD COMMANDER": "消灭虫族指挥官", + "SEAF Combat Botanists have confirmed: the Illuminate are seeding Void-altered blossoms to reshape this world's ecosystem. Their alien pollen contaminates native flora through cross-pollination, spreading a toxin that gradually mutates the entire planet.\n\nThis bioengineered sickness must be cut off at its roots. Eradicate every single one of these flowers.": "超级地球武装部队战斗植物学家证实:光能者正在播撒因寂域而变异的花种,试图重塑该星球的生态系统。这些异星花粉正通过异花授粉污染本地植物,传播一种会令整颗星球逐渐变异的毒素。\n\n必须将这种生物工程病害斩草除根。铲除每一朵寂域之花。", + "Planetary Defense Cannon rearming…": "行星防御加农炮正在装弹……", + "Com.Mission Inf (Start)": "完成任务的影响力(初始)", + "EXPLORE THE GLOOM": "探索“阴霾”", + "Locate and destroy Automaton Fabricators.": "寻找并消灭机器人构筑者。", + "Hellpods will be deployed to this location upon mission launch. Due to the Super Destroyer's absence, normal reinforcement will be unavailable. \n\nSecuring this site will give access to additional reinforcements, who will deploy directly from this location.": "任务开始时,绝地喷射舱将部署至此位置。因超级驱逐舰不在场,无法获得常规增援。\n\n占领此地点可获得额外增援,增援力量将直接部署到此处。", + "We must show the galaxy that even in the face of oppression, Freedom remains defiant. \n \nInfiltrate behind Automaton lines and raise our Flag as an unassailable beacon of Liberty.": "我们必须让整个银河系都知道,纵使面对压迫,自由仍傲然不屈。\n\n潜入机器人的防线后方,升起我们的旗帜,犹如树立起一座坚不可破的解放灯塔。", + "A dense Terminid swarm is located here. Eradicate it.": "这里聚集着终结族虫群。彻底消灭它们。", + "Find Factory Strider": "寻找移动工厂", + "Reload": "装填弹药", + "DEPLOY NUCLEAR PAYLOAD": "部署核炸药", + "Select systems to sabotage": "选择要破坏的系统", + "Orbital-range cannons in this Megafactory are suppressing our Super Destroyers—a clear violation of war conventions.\n\nThis tactical imbalance will not go unaddressed. Destroy every Counter-Orbital Cannon within the perimeter.": "这所超大型工厂内的轨道射程炮正在压制我方超级驱逐舰,这公然违反战争公约。\n\n我们必须纠正这种战术上的劣势。摧毁区域内所有反轨道加农炮。", + "Retrieve the Flag of Super Earth": "取回超级地球旗帜", + "SSSD": "超级固态硬盘", + "Electrical": "电力", + "Interplanetary Data Transmission Ready": "星际数据传输就绪", + "This planet is believed to contain valuable ores, but intense Terminid activity (and elevated mortality rates for civilian geologists) have so far hindered surveying efforts.\n\nActivate the Prospecting Drill to collect soil sample data and verify the planetary composition.": "据悉,这颗星球拥有珍贵的矿藏,但是由于终结族频繁活动(同时平民地质学家死亡率上升),我们的调查工作一直困难重重。\n\n启动勘探钻机,收集土壤样本数据,核实这颗星球的构成成分。", + ">> BLOCKED <<": ">> 受阻 <<", + "LEVEL UP REWARD": "升级奖励", + "Close Door": "关门", + "A massive Terminid Nursery has been discovered here, crawling with millions of freshly-hatched larvae, mere weeks from ravenous adulthood. They must be wiped out, before they reach maturity and kill innocent human children.\n\nTerminid Nurseries consist of one or more Nursery Chambers. Use the Hive Breaker Drill to deliver a nuclear extermination device to each one.": "我方发现此处存在一个巨大的终结族繁育窝,聚集着上百万只刚刚孵化的幼虫,只需几周,它们便能成长为贪婪的成虫。必须将它们铲除,以免其育成并残害无辜的儿童。\n\n终结族繁育窝由多个繁育腔室组成。使用“虫窝破裂者”钻机将核试验设备送至每一个腔室。", + "BACK UP EMERGENCY DATABASE": "备份紧急数据库", + "Prepare your defenses.\n\nTime left until automatic initiation begins: #TIME": "做好防御准备。\n\n自动启动程序倒计时:#TIME", + "DEMOCRATIZE THE VOID": "民主解放寂域", + "Select designated coordinates in grid": "选择网格中的指定坐标", + "Use terminal to initiate launch": "使用终端,下令发射", + "Call in your Super Destroyer, enabling the usage of stratagems for a limited time. One use per mission.": "呼叫超级驱逐舰,启用战略配备,限时生效。每次任务使用一次。", + "ALERT: INCOMING FUEL BLOCKED": "警告:燃料输入路径受阻", + "Activating this generator will supply critically-needed power to SEAF devices in the region.": "启动这台发电机可以为超级地球武装部队在该地区的设备提供急需的能源。", + "Seize the Automaton industrial complex in the name of Managed Democracy.": "以管理式民主之名占领机器人工业联合体。", + "TARGET NETWORK COORDINATES": "定位网络坐标", + "Evacuation shuttle en route": "疏散运输船即将抵达", + "An Orbital Cannon is located here. Infiltrate the site and use a Hellbomb to destroy it.": "轨道加农炮就位于此处。潜入此地点,使用地狱火炸弹将其摧毁。", + "PREPARING AREA SCAN": "准备启动区域扫描", + "DANGER - ENEMY PRESENCE": "危险 - 进入敌人势力范围", + "Protect our way of life from the Terminids by any means necessary.": "不惜一切代价也要捍卫我们的生存之道,不能让终结族损害半分。", + "Raise signal strength to 100%": "将信号强度提高至100%", + "Elapsed time on surface": "行星地表历时", + "SABOTAGE ORGO-PLASMA SYNTHESIS": "破坏有机等离子合成", + "Use terminal to unlock Control Chamber": "使用终端解锁控制室", + "NUKE NURSERY": "用核武器炸毁繁育窝", + "GUIDANCE": "制导", + "This colony is occupied by the Illuminate invaders. It must be freed.": "此拓殖地被入侵的光能者所占领。必须解放这里。", + "Pick up Stims from Injury Simulator": "从损伤模拟器中拾取治疗剂", + "PORTABLE COMMS RELAY": "便携式通信中继站", + "NEUTRALIZE GROUND-TO-ORBIT DEFENSES": "瘫痪地对轨道防御系统", + "Kill Illuminate forces to reduce their numbers.": "击杀光能者部队,削减它们的数量。", + "DESTROY AUTOMATON COMMAND BUNKER": "摧毁机器人指挥碉堡", + "There are millions of kilometers of Terminid tunnels beneath the surface of this planet. A detailed subterranean mapping is necessary to identify critical targets.\n\nUtilize a repurposed Prospecting Drill to collect samples of the infested mantle. Analyses will identify properties of local Terminid structures.": "这颗星球地表下有长达数百万公里的终结族通道。需要进行细致的地下测绘确定关键目标。\n\n使用改装过的勘探钻机收集被侵染地幔的样本。通过分析即可确定当地终结族结构的特性。", + "Incriminating evidence recorded": "已录下罪证", + "This Hive World produces Gloom spores deep within the extensive Terminid cave networks. They are also the sole known source of extremely valuable E-711.\n\nNothing is more important than freeing our citizens from the threat of the Gloom. The acquisition of E-711 is also the top priority for galactic security. Your orders are clear.": "这个虫窝世界在纵深复杂的终结族洞穴网络里生产“阴霾”孢子。它们也是极为珍贵的711元素唯一已知的来源。\n\n眼下最重要的是让我们的公民摆脱“阴霾”的威胁。获取711元素也是确保银河系安全的首要任务。指令十分明确。", + "Destroy mutated Terminid eggs": "摧毁变异终结族虫卵", + "Take back this city from its illegal occupants.": "夺回这座城市,驱逐非法入侵者。", + "Drill into the Terminid Hive to analyze its composition.": "钻入终结族虫窝分析其组成结构。", + "Drilling in progress...": "正在钻探……", + "Cull the Terminids' foul brood and their odious progenitors.": "剿灭终结族可憎的幼虫和虫族始祖。", + "RAISE LIDAR TOWER?": "升起激光雷达塔?", + "The Illuminate's insidious schemes to subvert Managed Democracy are futile. Even in the most unfree depths of the Void, Liberty shall reign supreme over tyranny.\n\nTopple their monoliths and hoist the Flag of Super Earth. Let it stand as an eternal beacon of Light against the Void's fleeting darkness.": "光能者企图颠覆管理式民主的阴险诡计注定徒劳无功。即使在最不自由的寂域深处,自由亦将凌驾于暴政之上。\n\n推倒光能者巨石,升起超级地球的旗帜。让这面旗帜成为永恒的光明灯塔,照耀着寂域短暂的黑暗。", + "DESTROY COMMAND BUNKERS": "摧毁指挥碉堡", + ">> UNLOCK <<": ">> 解锁 <<", + "Infiltrate Automaton territory and destroy their fuel and munitions stockpiles.": "潜入机器人领地,销毁其库存燃料和弹药。", + "Manually realign the satellite tower": "手动重新对齐卫星塔", + "The downed SEAF aircraft is located here. Its black box contains crucial intel.": "被击落的超级地球武装部队飞行器就位于此处。它的黑匣子内存有关键情报。", + "RESTORE AIR QUALITY": "恢复空气质量", + "Destroy Automatons": "摧毁机器人", + "Load weapon": "给武器装弹", + "ACTIVATE OIL PUMPS": "启动油泵", + "A downed recon plane is crashed here. Its data is stored in a black box somewhere amongst the wreckage.": "被击落的侦察机在此处坠毁。存有数据的黑匣子就在坠毁点附近。", + "Wait for reroute to complete": "等待完成重新路由", + "A remote SEAF research station in this region remains structurally intact despite the Void's illegal planetary annexation. Data collected before and after the planet's fall is of critical importance to our efforts to understand this lawless realm.\n\nAccess the station, download the research database, and upload it to the Super Earth mainframe.": "尽管寂域非法吞并星球,该地区一座偏远的超级地球武装部队研究站仍然结构完好。该星球陷落前后收集到的数据,对于我们了解寂域这一法外之地至关重要。\n\n前往该研究站,下载研究数据库,然后将其上传至超级地球主机。", + "CHART TERMINID TUNNELS": "绘制终结族隧道网络", + "A SEAF Reconnaissance aircraft was just shot down at this site. The aircraft had identified critical intelligence of enemy force allocations. \n\nInfiltrate the area and secure the black box containing the intel.": "超级地球武装部队的一架侦察机刚刚在此地被击落。该侦察机发现了敌军兵力部署的关键情报。\n\n潜入该区域,取回存有情报的黑匣子。", + "DRIVE VEHICLE TO DROP-OFF LOCATION": "驾驶载具到降落地点", + "Use Upload Data stratagem to begin upload": "使用“上传数据”战略配备,开始上传", + "RAISE LAUNCHER": "抬升发射器", + "This facility contains unpatriotically produced research data, and must be razed to the ground.": "该设施产生的研究数据有违爱国精神,必须将其夷为平地。", + "#RACE PRESENCE": "#RACE势力", + "Activate Prospecting Drill": "启动勘探钻机", + "Backpack": "装有化学武器的背包", + "The Automaton offensive has taken this area, leaving one of our top secret research stations surrounded by the enemy.\n\nUse your clearance to unlock the emergency bunker doors, and defend the facility staff as they transfer to the evacuation shuttle.": "机器人的部队已经占领了这个地区,我们的绝密研究站被敌人包围。\n\n使用你的权限打开紧急掩体的门,将该设施中的人员转移到疏散运输船,并在这个过程中保卫他们的安全。", + "Station active": "站点已启动", + "Hatch ready for opening": "舱门随时可以开启", + "RAISE PLANETARY DEFENSE CANNON": "抬升行星防御加农炮", + "Terminids in this region threaten Freedom in a variety of ways, each more despicable than the last. They must be stopped.": "该地区的终结族不择手段地威胁着我们的自由,使出的手段越发卑鄙。我们必须阻止它们。", + "Kill Terminids to thin their numbers.": "击杀终结族,削减它们的数量。", + "Defend Freedom": "捍卫自由", + "Collecting sample": "正在收集样本", + "The missile launch code disk was left at a base in this region.": "存有导弹发射代码的磁盘遗落在该地区的一座基地里。", + "START UPLOAD AT TRANSMISSION STATION": "在传输站开始上传", + "UPLOAD ESCAPE POD DATA": "上传逃生舱的数据", + "Deactivate the battery silos to shut down the dispersion of Termicide.": "关闭电池舱,停止喷洒灭虫终结剂。", + "Recover top-secret intel from a downed SEAF reconnaissance aircraft.": "从被击落的超级地球武装部队侦察机找回绝密情报。", + "Gloom spores suffuse the planet's atmosphere from the ground to the exosphere. Scattered LiDAR towers can be used to measure the density and composition of Gloom spores.\n\nActivate the towers, download their data, and transmit it off-planet using the local relay station.": "从地面到外逸层,“阴霾”孢子充斥着整个星球的大气层。各地的激光雷达塔可以测量“阴霾”孢子的密度和构成。\n\n启动激光塔并下载数据,利用当地中继站将数据传输至星球外。", + "Open Door": "开门", + "Evacuate the area": "撤离该区域", + "Bug Extermination": "歼灭虫族", + "The extractors over this massive repository of crude oil have ceased functioning and must be re-activated.": "这里储存着大量原油,但采油机已停止运转,需重新启动。", + "SWITCH 4": "开关4", + "Beware of blinding blizzards and deep snow.": "小心阻挡视线的暴风雪和深厚的积雪。", + "DARK FLUID VESSEL": "暗液体容器", + "Activate the Drilling Platform and ensure the successful extraction of E-711.": "启动钻机平台并确保成功提取711元素。", + "Superior Valor": "卓越勇士", + "EXTRACT ORGANIC PLASMA": "提取有机等离子", + "Honorable Duty": "忠于使命", + "THREAT LEVEL: MAXIMUM": "威胁等级:最高", + "Illuminate forces have encroached upon a region believed to contain rich mineral deposits. If valuable resources do exist here, the enemy cannot be allowed to bend them towards their despotic schemes.\n\nDeploy the Prospecting Drill and collect soil samples to verify the site’s value.": "光能者部队已经入侵据称蕴藏着丰富矿产的地区。若此地确实蕴藏着宝贵资源,绝不能任其沦为敌人推进专制企图的工具。\n\n部署勘探钻机并采集土壤样本,核实此地的开发价值。", + "OPPORTUNITY MISSION": "机遇任务", + "EXTERMINATE TERMINIDS": "消灭终结族", + "Please input activation sequence": "请输入启动程序", + "TARGETING": "锁定目标", + "Destroy Automaton Detector Tower": "摧毁机器人探测塔", + "LAUNCHERS ACTIVE": "发射器已启动", + "Launch site inoperable. Proceed to extraction.": "发射点无法正常运行。开始撤离程序。", + "Activate the Planetary Defense Cannon and use it to bring down the Illuminate Overship.": "启动行星防御加农炮,击沉光能者统御舰。", + "Manually disengage all silo hatch locks": "手动解除所有发射井舱门锁", + "Restore functionality to the pump site.": "使泵机区恢复运作。", + "OPERATION MODIFIER REMOVED": "已移除行动限制条件", + "Enemy Quantity": "敌人数量", + "Planetary scanning has revealed a number of Automaton supply bases, hidden deep behind their defensive lines.\n\nInfiltrate quickly and destroy their stockpiles before they can mount a concerted defense.": "星球扫描发现机器人有多座补给基地隐藏在防线深处。\n\n迅速潜入敌方腹地,在它们组织起有效的防御之前销毁它们的库存物资。", + "Lock the fuel hose to the transfer pump": "将燃料软管锁定在输送泵上", + "KILLS:": "杀敌数:", + "The Illuminate have laid false claim to this city, besmirching our streets with more of their despotic monoliths. \n \nDeploy to the city, raze the enemy's totalitarian monuments, and raise the Flag of Super Earth to restore hope to our citizens.": "光能者以不义之名占领这座城市,立起更多专制的巨石,玷污我们的街道。\n\n前往城市,摧毁敌人极权主义的象征,升起超级地球旗帜,重燃公民的希望。", + "A Gazer Spire surveys the surrounding area from this vantage point.": "一座凝视者尖塔从此处制高点监视着周边区域。", + "Several districts of this Megafactory contain supplies that fuel the Automatons' radicalized war machine.\n\nBreach their supply depots and destroy their stockpiles.": "这所超大型工厂内多个区域存储的物资正在为机器人的激进战争机器提供补给。\n\n突破敌方补给库,摧毁它们的物资储备。", + "Mineral analysis complete": "矿物分析完成", + "Truly Exceptional Heroism": "非凡英杰", + "ELIMINATE BROOD COMMANDERS": "消灭虫族指挥官", + "ANTI-AIR EMPLACEMENT": "防空炮台", + "Use terminal to complete sabotage": "使用终端完成破坏", + "Kill Illuminate Overseers": "击杀光能者的监视者", + "PERFORMING SYSTEMS CHECK...": "正在执行系统检查…", + "SQUAD IMPACT #INFLUENCE": "小队影响力 #INFLUENCE", + "There are crucial oil reserves in this area needed to fuel our continued war effort.\n\nNavigate the Terminid swarm, reactivate the pumps, and transfer the fuel to the waiting transport shuttles.": "这块区域内的油田对于支撑我们的长线战争至关重要。\n\n绕开终结族虫群,重新启动泵机,将燃料转移到待命的运输船上。", + "Priming Seismic Probe": "地震探测仪正在准备", + "Bring each of the three battery silos online to activate this TCS+ station.": "启动全部三个电池舱,即可启动这座TSC+站。", + "PLATINUM BAR": "铂金条", + "Surveillance suggests a Brood Commander is in this location.": "监控显示,虫族指挥官正位于此处。", + "A Ground All-Terrain Extraction Rig (GATER) has been deployed to this area, where multiple E-711 reservoirs have been identified.\n\nYou have been summarily certified as Expert Large Vehicle Operators. Deploy to the area and utilize the GATER to extract E-711 from all identified locations.": "此区域已部署地面全地形采集钻机(GATER),也已确认存在多个711元素储藏点。\n\n仓促间你已被授予大型载具驾驶专家的资格。请部署到该区域并使用GATER从所有确认地点提取711元素。", + "Automaton troops are mass produced daily in the bowels of this Megafactory, then deployed in service of the Cyborgs' senseless expansionism.\n\nDisrupt their industry of death. Destroy their fabricators one by one.": "在这所超大型工厂深处,每天都在批量生产机器人的部队,随后被部署并服务于生化人毫无意义的扩张主义。\n\n瓦解敌人的死亡工业。逐一摧毁它们的构筑者。", + "INFILTRATE ILLUMINATE LAIR": "潜入光能者巢穴", + "We have identified a number of heavily-guarded bunkers in this region. We suspect they contain Command Nodes central to linking in to the Automaton Transmission Stream.\n\nDestroy the bunkers, and cut the bots off from the flow of information.": "该地区内发现有多座防备森严的碉堡。我们怀疑其中存在连接机器人数据传输流的重要指挥节点。\n\n摧毁这些碉堡,切断机器人的信息传输。", + "TCS+ ACTIVATION TERMINAL": "TCS+启动终端", + "Please keep limbs away from moving drill parts": "四肢请勿靠近钻机的活动部件", + "A new, highly dangerous Terminid Variant has decimated SEAF units in this area. We must limit the spread of this mutant strain. \n\nFind and eradicate the Variant. Exercise extreme caution.": "一种极其危险的新型终结族亚种在该区域重挫了超级地球武装部队。我们必须限制该突变种扩散。\n\n找到并铲除该亚种。务必谨慎行事。", + "SYSTEM ERROR": "系统错误", + "REINFORCEMENT PODS": "增援太空舱", + "BATTERY SILO 01": "电池舱01", + "Activate the Drilling Platform and ensure the successful extraction of the E-710-like substance.": "启动钻机平台并确保成功提取类似710元素的物质。", + "Input code to authorize ejection": "输入代码,授权弹出", + "Repel the Automaton invasion fleet attacking this planet.": "击退正在攻打这颗星球的机器人侵略舰队。", + "To curb Terminid population growth, we must strike at their vile hatcheries.\n\nFind and destroy all Terminid eggs in the area before the enemy has a chance to react.": "为了抑制终结族种群数量增长的速度,我们必须袭击它们可恨的孵化点。\n\n迅速行动,找到并摧毁该区域内所有终结族虫卵,不给它们反击的机会。", + "Power up Battery Silos": "为电池舱供电", + "PAYLOAD SITE": "投放点", + "Drive the Automatons off this planet.": "将机器人逐出这颗星球。", + "RETURN TO AREA": "返回区域", + "MELEE KILLS:": "近战击杀数:", + "THREAT LEVEL: HIGH": "威胁等级:高", + "Data Jack Status: Stable": "数据接口状态:稳定", + "The Automatons have gained ground in this region, constructing a vast network of Fabricators which allow them to replicate extremely rapidly.\n\nWe have detected a narrow window of maintenance, giving us a chance to strike at their facilities. Destroy all that you can.": "机器人在该地区内夺得了一席之地。它们建立起庞大的构筑者网络,大幅提高了增殖速度。\n\n我们侦测发现短暂的维护窗口期,这是发动突袭的宝贵时机。尽可能摧毁一切。", + "OBTAIN COORDINATES": "获取坐标", + "Find Terminid Charger": "找到终结族强袭虫", + "Deactivate Battery Silo 02": "关闭电池舱02", + "BLITZ": "闪电战", + "Deploy into the Exostorm and shatter the Exospires that sustain it.": "部署至异界风暴内部,粉碎维持风暴运作的异界尖塔。", + "Release the fuel hose": "卸除燃料软管", + "ACTIVATE TERMINID CONTROL SYSTEM": "启动终结族遏制体系", + "Illuminate forces have aggregated in vast numbers in this region. We must seize this tactical opportunity to annihilate them while they remain clustered.\n\nEliminate the squids and their monstrous congregation. Kill as many as possible.": "光能者部队已在该地区内大量集结。我们必须抓住这一战术窗口,趁其集结之时将其一举歼灭。\n\n消灭那些鱿鱼及其丑陋的聚群。尽可能消灭光能者。", + "SEARCH AND DESTROY": "搜寻并摧毁", + "Jammer deactivated": "干扰装置已关闭", + "ERROR - MANUAL ALIGNMENT REQUIRED": "错误,需要手动对齐", + "Secure the black box from a crashed weather reconnaissance aircraft and transmit the data off-planet.": "从坠毁的气象侦察机中取出黑匣子,并将数据传输至星球外。", + "CALIBRATE VOLTAGE": "校准电压", + "UNDISCLOSED LOCATION": "机密位置", + "Eliminate Hulk": "消灭巨型者", + "Find Automaton Devastators": "找到机器人蹂躏者", + "B. Silo 01": "电池舱01", + "Gallantry Beyond Measure": "无上英雄", + "SEAL BUG HOLES": "封闭虫穴", + "Find and eliminate the Terminid Variant.": "找到并消灭终结族亚种。", + "BATTERY SILO 03": "电池舱03", + "Descend upon Cyberstan and free it from the Cyborgs' oppressive grip once and for all.": "降临生化斯坦,将这个星球从生化人的压迫统治中彻底解放出来。", + "The Terminids have stolen highly valuable specimens of enemy larvae and eggs. Recover them.": "终结族偷走了极为珍贵的敌方幼虫样本和虫卵样本。请把样本找回来。", + "Reload Artillery": "为大炮装填弹药", + "CONDUCT GEOLOGICAL SURVEY": "开展地质调查", + "Find Automaton Hulk": "找到机器人巨型者", + "Costly Failure": "惨痛失利", + "COLLECT MINERAL DATA": "收集矿物数据", + "Establish connection to SEAF network": "与超级地球武装部队网络建立连接", + "Regulate engine output in Control Chamber": "在控制室调节引擎输出", + "Extract with SSSD": "携带超级固态硬盘撤离", + "Once acquired, bring the footage to this location for secure extraction.": "获取录像后,将其运至此处进行安全撤离。", + "Database downloading": "数据库正在下载", + "Use drill interface to deploy Nuclear Payload": "使用钻机界面部署核炸药", + "Find the downed SEAF recon aircraft": "找到被击落的超级地球武装部队侦察机", + "Proceed to Graduation Chamber and become a Helldiver": "前往毕业礼堂,成为绝地潜兵", + "Return to terminal and force-start unit": "返回终端并强制启动装置", + "Activate Battery Silo 01": "启动电池舱01", + "Production of new Cyborgs requires a bio-synthetic process conducted in massive production units. They are structurally blastproof, but can be destroyed from within by exploiting the volatile hydrogen fuel used in the process.\n\nFlood the Production Unit with hydrogen, then destabilize its integrity until it fails safe and self-destructs.": "生产新的生化人需要在大型生产单元中进行生物合成工序。生产单元的结构可抵御爆炸,但可以利用工序中使用的易燃氢燃料从内部将其摧毁。\n\n向生产单元灌入过量氢气,然后破坏其结构稳定性,直至触发故障保护机制并自毁。", + "CLEANSE INFESTED DISTRICT": "净化侵染区域", + "Drill Status: Critically Damaged": "钻机状态:严重受损", + "Disrupt production of organic plasma and secure samples of the liquid for further analysis.": "破坏有机等离子的生产过程,获取液体样本供进一步分析。", + "SAMPLE 02": "样本02", + "The Cyborgs have assembled a large detachment of Automatons in this sector. They must be dismantled, before they march upon our homes and leave orphans in their wake.\n\nTheir numbers must be thinned. Destroy as many as possible.": "生化人已在该分区集结了大批机器人部队。必须将它们通通拆解,不能让它们进军我们的家园、造成无数孤儿寡母的惨况。\n\n必须削减敌方兵力。尽可能消灭敌人。", + "INTELLIGENCE REPORT": "情报汇报", + "DATA PACKAGES DELIVERED (#COUNT / #TARGET)": "已交付的数据包(#COUNT / #TARGET)", + "The Automatons are using augmented cannons with high-orbit reach to bombard our Super Destroyers.\n \nWe cannot allow our aerospace superiority to be challenged. Deploy to the area and destroy any active Counter-Orbital Cannons.": "机器人正在使用具有高轨道射程的增强型加农炮轰击我方的超级驱逐舰。\n\n我方的空天优势不容挑战。部署到该区域,摧毁所有还在运行的反轨道加农炮。", + "QUELL EXOSTORM": "平息异界风暴", + "Extract with the Specimens": "携带样本撤离", + "Massive Automaton factories in this region are fueling their advance. They must be destroyed.\n\nThis dormant ICBM silo is beyond their range of detection; launch a devastating strike before they can mount a defense.": "该地区的大型机器人工厂为机器人的推进行动提供了源源不断的动力。必须将其摧毁。\n\n这座暂停使用的洲际弹道导弹发射井位于它们的探测范围之外。在它们构筑防线之前发动毁灭性打击。", + "Use terminal to establish communication with Super Destroyer": "使用终端与超级驱逐舰建立通信", + "Calibrate LiDAR tower alignment": "校准对齐激光雷达塔", + "PRIMARY OBJECTIVES": "主要目标", + "Destroyed Medium Automaton Outpost": "已摧毁中型机器人哨站", + "An arcane Illuminate device at this location is creating a mind-disruption field, filling one's mind with un-Democratic thoughts that make it difficult to think or push Stratagem codes properly.": "这个地点有件神秘的光能者设备创造出了干扰思维的域场,令人的大脑塞满不民主的思想,进而难以思考,也难以正确输入战略配备代码。", + "Efforts to expand into the Gloom are underway. The Helldivers must support these efforts through data collection and resource extraction.": "我们正在向“阴霾”区域扩张。绝地潜兵必须通过收集数据和开采资源提供支援。", + "RETRIEVE MUTANT LARVA": "取回变异幼虫", + "Redirect fuel to Transfer Station": "更改燃料流向,将其输送至中转站", + "TOWER MISALIGNED": "卫星塔方向偏离", + "INTERCEPT CONVOY": "拦截车队", + "Flag": "旗帜", + "DISTANCE TRAVELED:": "行军距离:", + "Pressure": "压力", + "Reroute command path to override automaton control.": "更改命令路径,夺取机器人的控制权限。", + "#CURRENT / #TARGET Rockets": "#CURRENT / #TARGET火箭弹", + "Please clear front of surface-to-air launcher": "请离开地对空导弹发射器的正面", + "DETECTOR TOWER": "探测塔", + "#COUNT/#TOTAL objectives completed": "达成#COUNT/#TOTAL的目标", + "This location has been strategically chosen to maximize the flag's inspirational impact.": "这个位置经过精心选择,目的是最大限度地发挥旗帜鼓舞人心的力量。", + "A compact comms relay hub that can be effortlessly deployed on demand.": "小巧的通信中继站,可按需轻松部署。", + "The citizens are safe for now, trapped inside emergency bunkers. They must be released and escorted to the facility's shuttle bay for extraction.": "困在紧急掩体里的公民们暂无危险。你必须把他们放出来,护送至该设施的运输船坞,帮助他们撤离。", + "RETRIEVE THE BLACK BOX": "取回黑匣子", + "LOCK TARGET COORDINATES": "锁定目标坐标", + "SWITCH 5": "开关5", + "Defend the evacuation of top-secret military assets.": "护送绝密军事资产撤离。", + "DESTROY HARVESTER": "摧毁猎杀器", + "ERROR: MANUALLY ADJUST BLOCKED VALVES": "错误:请手动调整受阻阀门", + "#SECONDS REMAINING UNTIL LOADOUT!": "武装配置还剩#SECONDS!", + "Open Shuttle Bay Door": "打开运输船坞门", + "The enemy is closing in on a cache of high-value assets that have been sequestered since the First Galactic War. We cannot allow them to be captured.\n\nThe enemy will be alerted to your position as soon as the evacuation process is initiated. Defend the site until all assets have been safely transported off-planet.": "敌人正逼近一批自第一次星系战争以来一直处于封存状态的高价值目标。我们不能让其落入敌人魔爪。\n\n撤离程序一旦开始,敌人就会注意到你的位置。保卫阵地,直到所有目标安全运离星球。", + "CALIBRATE PROBE": "校准探测仪", + "Destroy mutated Terminid eggs and deactivate the Termicide Dispersion Tower to prevent any further mutations.": "摧毁变异终结族虫卵,关闭灭虫终结剂喷洒塔,预防终结族进一步变异。", + "Calibrate voltage to maximize output": "校准电压,将输出提升至最大", + "WORLD LIBERATED": "解放的星球", + "ELIMINATE ANNIHILATOR TANK": "消灭湮灭坦克", + "#COUNT Samples Extracted": "已提取#COUNT份样本", + "VARIANT ERADICATION": "铲除亚种", + "Clear area of enemies (#REMAINING Remaining)": "肃清敌方区域(还剩#REMAINING)", + "Shuttle Bay System": "运输船坞系统", + "Complete Helldiver Obstacle Course": "完成绝地潜兵障碍训练", + "Destroy Illuminate Warp Gates": "摧毁光能者传送门", + "ERADICATE VOID BLOSSOMS": "清除寂域之花", + "DESTROY SPORE SPEWER": "摧毁孢子喷涌虫", + "Locate the Spore Lung underground": "在洞穴中搜寻孢肺", + "Activate Jammer Terminal": "启动干扰装置终端", + "Strange Illuminate monoliths seem to be creating fields of negative energy. We do not understand their purpose or their true nature. That is why they must be destroyed.": "古怪的光能者巨石似乎创造出了负能量的域场。我们不知道巨石的目的,也不清楚其中的性质。所以只能将它们全部摧毁。", + "#CURRENT / #TOTAL kills": "#CURRENT / #TOTAL次击杀", + "Please stand clear of platform.": "请远离发射平台。", + "SSA Radar has identified a fleet of Illuminate invasion ships descending upon this sector from the close orbit. They intend to seize control of the area in an aerial blitz.\n\nYou are the last line of defense. Destroy all enemy ships as quickly as possible.": "SSA雷达侦测到光能者入侵舰队正从近地轨道登陆该分区,企图通过空中闪电战夺取区域控制权。\n\n你是最后一道防线。迅速摧毁所有敌舰。", + "Manually disengage all hatch locks": "手动解除所有舱门锁", + "SHOTS HIT:": "命中次数:", + "ANOMALOUS MATERIAL EXTRACTED": "已提取异常物质", + "Destroy the Illuminate Monolith": "摧毁光能者巨石", + "BATTERY SILO ACTIVATING": "电池舱正在启动", + "TRANSFER OIL TO SHUTTLE": "将油输送至运输船", + "ACCIDENTALS:": "意外阵亡次数:", + "Please Log In": "请登录", + "EJECT HARD DRIVE": "弹出硬盘", + "FLOOD HYDROGEN PIPELINE": "灌注氢气管道", + "Rerouting Turret Control...": "正在变更炮台控制路径…", + "SUPPRESS TOXIC POLLINATION": "遏制毒素授粉", + "Use Machine Gun Stratagem to call in Support Weapon": "使用机枪战略配备,呼叫支援武器", + "Secondary Objectives Completed": "达成次要目标", + "#NAME LIBERATED": "成功解放#NAME", + "HELLPOD LAUNCH IMMINENT!": "绝地喷射舱即将发射!", + "Locate and eliminate the Automaton Factory Strider": "找到并消灭机器人移动工厂。", + "Crushing": "破碎", + "Stable": "稳定", + "Transmission to Super Earth Mainframe in progress": "正在向超级地球主机进行传输", + "Killed Hive Lord": "击杀霸王虫", + "Use the Cannon to shoot down the Overship": "使用加农炮,击沉统御舰", + "ACQUIRE EVIDENCE": "获取证据", + "Tower supports demolished": "塔巢支撑结构已摧毁", + "CONDUCT MOBILE SUBSTANCE EXTRACTION": "移动式提取物质", + "Activate the Battlefield Injury Simulator": "启动战场损伤模拟器", + "A Nursery Chamber is located here, ripe with millions of feeding larvae who tunneled here after hatching on the surface. Use the Hive Breaker Drill to deliver a nuclear payload and wipe them out.": "此处有一个繁育腔室,其抚育着数百万只在地表孵化后就钻入地下觅食的幼虫,使用“虫窝破裂者”钻机将核炸药送入腔室,将幼虫铲除。", + "This city is under attack. It cannot be allowed to fall to the forces of oppression.": "这座城市遇袭。绝不能让它落入压迫者之手。", + "Activate Mobile Radar": "启动移动雷达", + "Radar scans of this region have detected anomalous subsurface readings. By analyzing the signatures of extracted material, we can trace their source of origin and uncover the path to our final destination within the Void.\n\nYou have been authorized one GATER, already deployed. Use it to extract anomalous material from all indicated sites.": "该地区的雷达扫描检测到异常的地下读数。通过分析提取物的特征,我们就能寻踪溯源,找到通往寂域内部最终目的地的路线。\n\n你已获准使用一台已部署的地面全地形采集钻机。使用这台地面全地形采集钻机从所有已标记地点提取异常物质。", + "RESTART PUMPS": "重启泵机", + "INTEL EXTRACTED": "获取情报", + "Please stand by": "请稍候", + "INITIATING ARTILLERY SYSTEM": "正在启动大炮系统", + "Kill Automatons to reduce their numbers.": "击杀机器人,削减它们的数量。", + "Silo Status: Unstable": "舱体状态:不稳定", + "Reload Orbital Shell": "装填轨道炮弹", + "FREQUENCY ALIGNMENT": "校准频率", + "AA EMPLACEMENT": "防空炮台", + "Locate and destroy Terminid structures.": "找到并摧毁终结族虫窝结构。", + "Destroy the Exospire to suppress the growing Exostorm.": "摧毁异界尖塔,平息越发狂躁的异界风暴。", + "Automaton Horde": "机器人群袭", + "DELIVER ANY SSSD HARD DRIVES": "运送所有超级固态硬盘", + "The Gloom may be compounded by the Terminid scum overrunning the planet's surface.\n\nWipe the region clean of all Terminid presence, including their fetid nests.": "由于可憎的终结族在星球上四处肆虐,“阴霾”可能会愈发猖獗。\n\n清除该区域的所有终结者,包括它们臭气熏天的巢穴。", + "CONFIRM SCAN AREA": "确认扫描区域", + "Satellite imagery confirms that the Automatons are operating a fuel depot in this area.": "卫星图像证实机器人在该区域内有一座正在运作的燃料库。", + "Cleared Light Illuminate Encampment": "已摧毁光能者轻型营地", + "Periodic sandstorms pose a significant threat to visibility.": "周期性沙尘暴会严重影响能见度。", + "Deploy to the unknown Hive World and reclaim it in the name of Super Earth.": "前往未知的虫窝世界部署行动,以超级地球之名收复要地。", + "Destroy the Illuminate's strange and unnatural spacecraft.": "摧毁光能者古怪的飞行器。", + "OPTIONAL OBJECTIVES": "可选目标", + "EXTRACTION SUCCESSFUL": "撤离成功", + "LIDAR STATION": "激光雷达站", + "CONDUCT MOBILE EXTRACTION": "移动式提取", + "[ DATA FOUND ]": "[ 已找到数据 ]", + "collect the data disc": "收集数据磁盘", + "ACTIVATE UPLINK": "启动上行链路", + "DEMOLISH CYBORG ASSEMBLY UNIT": "摧毁生化人的组装单元", + "GROUND ALL-TERRAIN EXTRACTION RIG": "地面全地形采集钻机", + "Inside this towering facility, Cyborgs are grown in pod-like artificial wombs.": "在这座高耸的设施内部,生化人在舱形人造子宫中完成培育生长。", + "Move closer to objective": "移动至离目标更近的位置", + "Login required": "需要登录", + "SWITCH 3": "开关3", + "EVACUATE PRIORITY CITIZENS": "疏散优先级公民", + "Chemical Backpack": "装有化学武器的背包", + "BAY DOOR CONTROL": "坞门控制", + "Searching for problems. Please wait.": "正在查找问题。请稍候。", + "Eliminate Charger": "消灭强袭虫", + "Load Platinum Bars into Cargo Container": "将铂金条装入货物集装箱", + "Invading Illuminate forces have unleashed Harvesters upon the city. These intolerant machines patrol the streets in this area, devastating once-peaceful neighborhoods and murdering innocent civilians. Destroy them, and reclaim control of this sector.": "入侵的光能者部队已在城市投放猎杀器。这些偏狭的机器正在该区域的街道巡逻,摧毁曾经安宁的社区,屠杀无辜平民。消灭它们,夺回该分区的控制权。", + "Joint Operation": "联合行动", + "LOG IN": "登录", + "Input Access Code: #OTHER": "输入访问代码:#OTHER", + "DESTROY INFESTED TOWER": "摧毁侵染塔巢", + "Destroy buildings within the Megafactory": "摧毁超大型工厂内的建筑", + "Large quantities of eggs are located in this area. Use any means necessary to destroy them.": "该区域内发现大量虫卵。使用一切必要手段将它们摧毁。", + "Tune probe to lock onto signal": "调节探测仪,锁定信号", + "Calibrating seismic sensor array": "正在校准地震传感器阵列", + "The recon aircraft is located here. Its precious black box must be recovered.": "侦察机位于此处。必须取回机上珍贵的黑匣子。", + "Input code to authorize access": "输入代码,授权访问", + "ORGANIC PLASMA FLOW BLOCKED": "有机等离子流受阻", + "Fire Artillery Command": "开炮指令", + "Multiple opportunities to disrupt the enemy's opaque and sinister machinations have been identified in this region. Illuminate forces are highly concentrated here; expect significant resistance. \n \nDisrupt their schemes and restore peace to this area.": "在该地区发现多个可挫败敌人阴谋诡计的良机。光能者部队在此处重兵集结;我方预计将遭遇敌人的顽强抵抗。\n\n挫败光能者的阴谋,恢复该地区的安宁。", + "Destroy all facility buildings": "摧毁设施内的所有建筑", + "COLLECT GLOOM SPORE READINGS": "收集“阴霾”孢子数据", + "Initiate off-planet evacuation of high-value assets, and defend the site until evacuation is complete.": "启动高价值目标撤离星球的程序,并保卫阵地,直至撤离完成。", + "CHECK ALL SUB-SYSTEMS": "检查所有子系统", + "Input code to raise satellite tower": "输入代码以抬升卫星塔", + "CRITICAL SYSTEM FAILURE": "系统严重故障", + "ALL SYSTEMS OPERATIONAL": "所有系统均正常运行", + "DESTROY MONOLITH": "摧毁巨石", + "DELIVER CARGO TO THE PICKUP POINT": "将货物送到聚集点", + "INVALID DROP POINT": "无效降落点", + "ELIMINATE CHARGERS": "消灭强袭虫", + "JOINT OPERATION": "联合行动", + "Transport Black Box to Communications Relay": "将黑匣子转移至通信中继站", + "Extract with Intel Package": "携带情报包裹撤离", + "SPORE SPEWER": "孢子喷涌虫", + "Destroy the Megafactory's Counter-Orbital Cannons.": "摧毁超大型工厂的反轨道加农炮。", + "CONFISCATE ASSETS": "没收资产", + "Please manually load all shells": "请手动装填所有炮弹", + "Turret reload sequence initiated...": "炮台装弹程序已启动…", + "ENEMY BIO-PROCESSORS": "敌方生物处理器", + "Protect our citizens' E-711 interests from Terminid despoilment.": "保护我们公民的711元素利益免遭终结族破坏。", + "ELIMINATE VARIANT": "消灭亚种", + "Test w/ Above Settings": "测试上述设置", + "A dense swarm of Terminids has amassed in this region.": "有大量终结族聚集在这个地区。", + "INPUT ACCESS CODE": "输入访问代码", + "TECTONIC DRILL": "地壳钻机", + "Open hatch to deliver SSSD": "打开舱门运送超级固态硬盘", + "Find Variant": "找到亚种", + "MAIN OBJECTIVES": "主要目标", + "BATTERY DISPERSAL INTERFACE": "电池分配界面", + "LOCAL TERMINAL": "本地终端", + "Activate the TCS+ station to cleanse this area of Terminids.": "启动TCS+站,清除该区域的终结族。", + "Gloom-infested planets appear to have more extensive hive patterns than normal.\n\nDeploy Seismic Probes to collect scans of their tunnel networks, then use a local relay station to upload the data to a Ministry of Science hub.": "在受“阴霾”侵蚀的星球上,虫窝的散布范围似乎比普通星球更广泛。\n\n部署地震探测仪,收集隧道网络的扫描数据,再利用当地中继站将数据上传至科学部中心。", + "Firing sequence initiated": "发射程序已启动", + "Proceed to Reinforcement Training Area": "前往增援训练区", + "The TCS created several fissures in the planet's crust in this area. A Drill stratagem can be used to deploy Dark Fluid payloads in these locations.": "这片区域内,星球的地壳因TCS而出现了一些裂缝。钻机战略配备可以用于在这些地点部署暗液体。", + "Conduct a geological survey to assess planetary composition.": "开展地质调查,评估星球的构成成分。", + "E-711": "711元素", + "Log in to Jammer Terminal": "登录干扰装置终端", + "Find Terminid Bile Titan": "找到终结族吐酸泰坦", + "CENTRAL NETWORK": "中央网络", + "We have located a key facility in the Automaton's mining operations. Platinum ore is extracted, refined, and shipped to other facilities for further processing. \n\nThese assets have been deemed forfeit to the Federation. Seize them.": "我们已找到机器人采矿作业的关键设施。它们在此开采和加工铂金矿石,然后运往其他设施进行深加工。\n\n这些资产已认定为归联邦所有。夺取它们。", + "The Illuminate have invaded this region and promptly raised a blasphemous monolith as a symbol of their occupation. We must show the galaxy that even in the face of oppression, Freedom remains defiant. \n \nTear down their tyrannical emblem, and raise our Flag as an unassailable beacon of Liberty.": "光能者入侵了该地区,并迅速立起了一块亵渎性的巨石作为占领标志。我们必须让整个银河系都知道,纵使面对压迫,自由仍傲然不屈。\n\n推倒它们暴政的象征,升起我方旗帜,犹如树立起一座坚不可摧的解放灯塔。", + "SHUTTLE LEAVING WITH VEHICLE": "运输船已带着载具离开", + "There is reason to believe this facility holds undeniable proof of socialist war crimes. Weapons of mass destruction, breaches of interstellar humanitarian law, unspeakable threats to our citizens. Held deep behind enemy lines.\n\nYou must bring the truth to light. Infiltrate the site and obtain footage of this wrongdoing. Our citizens must see the true face of the enemy.": "我方有理由相信这座设施内有敌方战争罪行的确凿证据。大规模杀伤性武器、违反星际人道主义法、对我方公民构成不可言说的威胁,全都深藏于敌后。\n\n你必须揭露真相。潜入现场并录下他们的罪行。必须要让我们的公民看清敌人的真面目。", + "This heavily-guarded bunker is thought to contain a vital Command Node for the Automaton Transmission Stream.": "据悉,这座防备森严的碉堡中可能有机器人数据传输流的重要指挥节点。", + "COLLECT ENCRYPTED HARD DRIVE": "收集加密硬盘", + "STATION INOPERABLE": "站点无法运转", + "COMMS RELAY HUB": "通信中继站", + "The encrypted drives were abandoned at these coordinates.": "加密硬盘被遗弃在这些坐标处。", + "A nest of flying Shriekers has been reported in this area.": "这个地区内发现飞空尖啸虫的巢穴。", + "The Spore Lung is located deep within this Terminid tunnel complex.": "孢肺位于这个终结族地下网络通道的深处。", + "#COUNT XP TO NEXT LEVEL": "升到下一等级还需要#COUNT经验", + "FREE THE CITY": "解放城市", + "Use terminal to wipe sensitive data": "使用终端抹除敏感数据", + "Disrupt the Illuminate's opaque and sinister machinations in this region.": "挫败光能者在该地区的阴谋诡计。", + "Override Turret Control": "夺取炮台控制权限", + "This planet was purged of the Gloom at great cost. Now, a Terminid outbreak threatens to mutate it into a festering Hive World once again. Our ethically sourced E-711 deposits and the lives of hard-working pump inspectors are imperiled.\n\nYou must stop the bugs from despoiling what we have rightfully secured. Do not let this planet sink back into the Gloom.": "这颗星球曾为肃清“阴霾”付出巨大的代价。现在,一场终结族暴乱使其再次面临沦为腐化巢窝世界的威胁。我们以道德方式采集的711元素,以及辛勤工作的泵机督察员的生命都将危在旦夕。\n\n必须阻止这些害虫破坏我们正大光明取得的一切。绝不能让这颗星球再次深陷“阴霾”。", + "The Terminid Control System is complete. All across the planet, Termicide Dispersion Towers await activation. This planet won't be completely immunized from the Terminids until every single Tower is activated.": "终结族遏制体系业已建成,遍布星球的灭虫终结剂喷洒塔只待启动。必须启动每一座喷洒塔才能让终结族彻底从这颗星球上消失。", + "ACTIVATE DRILL 2?": "是否启动2号钻机?", + "Welcome to Voragon Systems Generic Military Terminal.": "欢迎使用沃瑞肯系统通用型军用终端。", + "Warning: Stay Clear of Launchers": "警告:请远离发射器", + "Move GATER to indicated drill sites": "将地面全地形采集钻机移至已标记的钻探点", + "TIMES REINFORCING:": "增援次数:", + "Eliminate Terminids underground": "消灭地下的终结族", + "ELIMINATE IMPALER": "消灭穿刺虫", + "BUNKER HATCH LOCKED": "掩体舱门未解锁", + "CALL IN SUPER DESTROYER": "呼叫超级驱逐舰", + "We have received credible reports of brutal Automaton Hulks in the region. Destroying them would weaken the Automaton command structure.\n\nLocate the Hulks, and eliminate them.": "据可靠消息称,该地区内存在着残暴的机器人巨型者。将其摧毁可以削弱机器人的指挥结构。\n\n找到巨型者,将其消灭。", + "Planetary scanning has identified a vast assemblage of Automaton troops in this region. This may be in preparation for an offensive on nearby Super Earth installations.\n\nYou must reduce their numbers—kill as many bots as you can.": "星球扫描的结果显示,该地区聚集有大量的机器人士兵。它们或许正在准备进攻附近属于超级地球的设施。\n\n你必须削减其数量——尽可能击杀更多机器人。", + "OIL PUMP CONTROL SYSTEM": "油泵控制系统", + "Use the Hive Drill to destroy all subterranean Terminid structures in the area.": "使用虫窝钻机摧毁该地区内所有终结族地下结构物。", + "Community Rewards": "社区奖励", + "VERIFY TRANSFER AT TERMINAL": "在终端验证传输", + "Missile fueling in progress": "正在为导弹添加燃料", + "Purge site of Terminid Matter": "抹除目标地点内的终结族物质痕迹", + "Concrete, undeniable evidence of unspeakable Automaton atrocities are located here. Capture them with the tactical video camera so the truth can be brought to light.": "证明机器人暴行的确凿证据就在此处。用战术摄像机录下证据,让真相大白于天下。", + "The cache of high-value assets is located here. Fortify your defenses, then initiate evacuation and defend the site until evacuation is complete.": "高价值目标的隐匿之处就在这里。加强防御然后开始撤离,并保卫此处,直至撤离完成。", + "SHUTTLE BAY": "运输船坞", + "RAISE TOWER": "升起信号塔", + "SEAF SAM-SITE": "超级地球武装部队地对空导弹基地", + "This Nuclear Missile travels over long distances at high speeds, to strike before the enemy has time to retreat or retaliate.": "这枚核导弹能以极快的速度击中超远距离外的目标,不给敌人撤退或反击的机会。", + "Illuminate Artifact": "光能者古物", + "FUSE 4": "熔断器4", + "ELIMINATE OVERSEERS": "消灭监视者", + "Orbital infrared scans have detected the waste heat of an Automaton Factory Strider in this region. If it is allowed to persist, the planet will be overrun with mechanical monstrosities before long.\n\nEnd it.": "轨道红外线在该区域内扫描发现一名移动工厂的余热。如果放任不管,这颗星球迟早会被机械怪物攻陷。\n \n终结它。", + "Interact with the main terminal": "与主终端交互", + "ELIMINATE BILE TITANS": "消灭吐酸泰坦", + "Eliminate Impaler": "消灭穿刺虫", + "RECEIVE SCAN DATA": "接收扫描数据", + "Use Resupply Stratagem to call in supplies": "使用重新补给战略配备,呼叫补给物资", + "SWITCH 1": "开关1", + "SEAF in this region have reported sightings of Chargers exhibiting dangerous new mutations.\n\nThese specimens must be eliminated before their mutant strain spreads.": "该地区的超级地球武装部队报告称,发现强袭虫表现出危险的新型突变属性。\n\n必须在突变种扩散之前将其消灭。", + "Rapidly clear the area": "迅速肃清该区域", + "Eliminate Factory Strider": "消灭移动工厂", + "Use terminal to commandeer refinery": "使用终端接管精炼厂", + "Root out the Terminid infestation on this planet.": "彻底清除侵袭这颗星球的终结族。", + "Collect the #ENTITY": "收集#ENTITY", + "Package Progress": "包裹进度", + "SYSTEM PROCESSING...": "系统正在处理…", + "Orbital infrared scans have detected a Factory Strider in this area.": "轨道红外线在该区域内扫描发现一名移动工厂。", + "Use terminal to eject SSSD Hard Drive": "使用终端弹出超级固态硬盘", + "PREVENT SPIRE GROWTH": "阻止虫塔繁殖", + "Choking fog and torrential rainfall can affect sight range.": "令人窒息的浓雾和暴雨会影响视野能见度。", + "RAISING MISSILE - PLEASE WAIT": "正在抬升导弹高度,请稍候", + "CHECK MEMORY ADDRESS": "检查存储器地址", + "Use terminal to raise Planetary Defense Cannon": "使用终端抬升行星防御加农炮", + "The Exospire is located here. Its power core is housed in a subterranean chamber at its base.": "异界尖塔矗立于此。其动力核心位于底部的地下密室中。", + "DESTROY STOCKPILED AMMUNITION": "摧毁库存弹药", + "Cleared Heavy Illuminate Encampment": "已摧毁光能者重型营地", + "Transferring data from SSSD": "从超级固态硬盘传输数据", + "This is a potential platinum-rich site identified by the Automatons. Take a site sample to determine its viability.": "这是机器人发现的潜在富铂金矿点。采集现场样本,确定开采价值。", + "HATCH OPEN": "舱门已打开", + "Repel the fleet of invading Illuminate ships before they can seize control of the area.": "在敌人夺取该区域之前,击退入侵的光能者舰队。", + "FUSE 3": "熔断器3", + "Call down a Hellbomb to destroy the Gazer Spire": "呼叫地狱火炸弹摧毁凝视者尖塔", + "The antenna responsible for the local Automaton Transmission Stream is thought to be located here.": "据悉,机器人的本地数据传输天线应该就在这里。", + "UPLOAD DATA VIA LOCAL RELAY": "通过当地转接设备上传数据", + "Destroy Antenna transmitters": "摧毁天线发射器", + "This area is overgrown with noxious blossoms that spread the Void's taint.": "该区域长满了散播寂域污秽的毒花。", + "Call in a large container to load up with liberated goods for secure extraction.": "呼叫大型集装箱,装载解放物资以便安全撤离。", + "Deploy to the Supercolony, call down the Dark Fluid Vessel, and insert it at each of the payload sites to help destroy the planet.": "部署至超级拓殖地,呼叫暗液体容器,然后将其注入各投放点,准备摧毁该星球。", + "Planetary Defense Cannon in lowered position.": "行星防御加农炮处于收起状态。", + "The Automatons' grip on this planet has been greatly weakened. We must press the advance now, before they have a chance to bolster their forces.\n\nAs Helldivers, you can reach their last holdouts and deal the final blow, to drive them off this planet for good.": "机器人对这颗星球的掌控已经大幅减弱。我们必须立刻向前推进,不给它们喘息之机。\n\n作为绝地潜兵,你们可以奔袭最后的顽固分子,给予它们致命一击,将其彻底逐出这颗星球。", + "Be advised that you will shortly expire if you are reading this": "注意,读到这条消息意味着你命不久矣", + "Coordinates of potential ore strains, identified by the Automatons, are located here. Seize them.": "机器人发现的潜在矿脉坐标情报就在此处。夺取坐标。", + "Destroy statues within the Megafactory": "摧毁超大型工厂内的雕像", + "1ST": "第1", + "Destroy Stalker Lair": "摧毁追踪虫巢穴", + "DISRUPT VOID": "扰乱寂域", + "Flag raising": "升起旗帜", + "Activate the communications relay": "启动通信转接程序", + "STRATAGEMS USED:": "战略配备使用次数:", + "Validate data checksum to confirm data integrity": "验证数据校验和,确认数据完整性", + "Near-Total Victory": "几近全胜", + "Find ammo shells and load into artillery gun": "找到炮弹,将其装入大炮", + "MOBILE RADAR": "移动雷达", + "Oil Extractor": "采油机", + "CAPTURE BUG TERRITORY": "占据虫族领地", + "Adjust all valves to maximize hydrogen flow": "调节所有阀门,使氢气流量达到最高", + "Match security grid pattern": "匹配安全网格图案", + "STRATAGEM JAMMER": "战略配备干扰装置", + "Manually disengage hatch locks": "手动解除舱门锁", + "This tower will summon Bot Dropships if intruders are detected.": "探测到入侵者后,这座塔将呼叫机器人运输舰。", + "Call down a Hellbomb and use it to destroy the monolith": "呼叫地狱火炸弹摧毁巨石", + "OIL EXTRACTORS ACTIVATING": "采油机正在启动", + "Use terminal to log in to research database": "使用终端登录研究数据库", + "Capture evidence of Illuminate atrocities": "收集光能者暴行证据", + "Evacuate civilians trapped deep within the Terminid swarm.": "疏散被困在终结族虫群深处的平民。", + "MISSILE CONTROL SYSTEM": "导弹控制系统", + "SILO HATCH UNLOCKED": "发射井舱门已解锁", + "Destroy Access Node": "摧毁接入节点", + "COLLECT BLACK BOX": "收集黑匣子", + "Move through Highly Realistic Battlefield Simulator": "通过高度逼真的模拟战场", + "DEPLOY SIGNAL PROBE": "部署信号探测仪", + "Activate all charges to trigger overload": "激活所有充电装置以触发过载", + "Pick up grenades": "拾取榴弹", + "Search for the target in the indicated map area": "接近目标区域", + "Find the hard disk containing the Launch Codes.": "找到存有发射代码的硬盘。", + "Worthwhile Sacrifice": "死得其所", + "DATA TRANSMISSION": "数据传输", + "SPECIMEN CASE": "样本箱", + "Use drill interface to deploy sterilizing agent": "使用钻机界面部署灭菌剂", + "SCOUR SURFACE": "肃清地表", + "Find and eradicate all Impalers in the region.": "找到并铲除该地区所有穿刺虫", + "LiDAR Tower activating": "激光雷达塔正在启动", + "OBJECTIVE LOCATION UNKNOWN": "目标位置未确认", + "A cache of cutting-edge fusion batteries are located here. They are made with stolen materials. Seize them.": "这里存有一批尖端聚变电池。它们是用盗取的材料制造而成的。夺取电池。", + "Tighten all exhaust pipe clamps": "紧固所有排气管管夹", + "UPLOAD BLACK BOX DATA": "上传黑匣子数据", + "Operate deep in enemy territory to uncover what vast operation the Automatons want to keep out of Liberty's sight.": "深入敌方领地,调查机器人试图瞒过自由锐眼的大规模行动。", + "JOINT OPERATION AVAILABLE": "可参与的联合行动", + "Deactivate Battery Silo 01": "关闭电池舱01", + "The Ground All-Terrain Extraction Rig (GATER) is located here.": "地面全地形采集钻机(GATER)在这里。", + "System override successful": "成功取得系统权限", + "RETRIEVE RECON CRAFT INTEL": "取回侦察机情报", + "Track down and eliminate the Charger.": "追踪并消灭强袭虫。", + "The Terminid swarm has descended on this planet and threatens to infest it.\n\nWe must repel this vile incursion before it is too late!": "终结族虫群涌入这颗星球,企图将其占领。\n\n我们必须及早挫败它们邪恶的入侵行动!", + "SABOTAGE SUPPLY BASES": "破坏补给基地", + "TAKE DOWN OVERSHIP": "击沉统御舰", + "Sabotage Automaton air capabilities in the region.": "破坏机器人在该地区的空运能力。", + "Use terminal to calibrate generator voltage": "使用终端,校准发电机电压", + "Use terminal to upload virus": "使用终端上传病毒", + "ERADICATE TERMINID SWARM": "彻底清除终结族虫群", + "Drilling in progress": "正在钻探", + "SELECT DATA MODULE FOR UPLOAD": "选择上传数据模块", + "FRIENDLY FIRE DAMAGE:": "友军误伤造成伤害:", + "Reloading": "正在装填炮弹", + "STALKER LAIR": "追踪虫巢穴", + "A massive Terminid Nursery has been discovered here, crawling with millions of freshly-hatched larvae, mere weeks from ravenous adulthood. They must be wiped out, before they reach maturity even if we must sacrifice the city to do so.\n\nTerminid Nurseries consist of one or more Nursery Chambers. Use the Hive Breaker Drill to deliver a nuclear extermination device to each one.": "我方发现此处存在一个巨大的终结族繁育窝,聚集着上百万只刚刚孵化的幼虫,只需几周,它们便能成长为贪婪的成虫。为避免它们育成,必须将它们全部铲除,即使要牺牲整座城市也在所不惜。\n\n终结族繁育窝由数量不等的繁育腔室组成。使用虫窝破裂者将核灭绝装置送入各个腔室。", + "Eradicate Void Blossoms in the area": "清除该区域的寂域之花", + "Main Refinery Components Listed": "已列出主要精炼厂组件", + "You will deploy to the surface of the Supercolony in vicinity of former TCS nodes, where the crust has been weakened. Once on the surface, call down the Dark Fluid Vessel and deliver it to each Payload site.\n\nThe Supercolony is like nothing you have deployed to before. Expect extreme resistance. All of Super Earth is counting on you.": "你将部署至超级拓殖地的地表,靠近以前TCS节点的位置,该处的地壳较为薄弱。一旦降落,立即呼叫暗液体容器,并将其运送至各投放点。\n\n超级拓殖地不同于你们曾经战斗过的任何战场,你们可能会遭遇极端反抗。超级地球一切都靠你了。", + "Level-Up Reward": "升级奖励", + "A group of Class-A citizens are stranded at a priority evacuation port. We cannot leave these patriots to be slaughtered by the Terminids.\n \nGet to the port and secure the evacuation of as many civilians as can fit aboard the designated transport shuttle.": "一组A级公民被困在优先级疏散港口。我们不能让这些爱国者为终结族所残杀。\n\n前往港口,确保让尽可能多的平民登上指定运输船进行疏散。", + "Transmit data burst": "传输数据冲压包", + "RECOVER SCIENTIFIC SPECIMENS": "找回科学样本", + "Use terminal to complete TCS+ activation": "使用终端完成TCS+激活", + "ENABLE OIL EXTRACTION": "设法采油", + "EXTRACT WITH #ENTITY": "携带#ENTITY撤离", + "A dense nest of Stalkers has been sighted in this area.": "这个地区内发现有大量追踪虫聚居的巢穴。", + "SHOTS FIRED:": "开火次数:", + "DESTROY DROPSHIPS": "摧毁运输舰", + "RAISING SURFACE-TO-AIR LAUNCHER": "正在抬升地对空导弹发射器", + "SEAF Combat Engineers have deployed a Rapid Modular Drilling Platform above a pool of E-711 within the Terminid caves. High Terminid activity has made the area extremely dangerous and made extraction impossible.\n\nDeploy to the Hive World and manually activate the Rig. Protect the extraction process until the E-711 is safely airlifted away.": "终结族洞穴深处有整整一池的711元素,超级地球武装部队战斗工程师已在其上方部署了快速模块化钻机平台。终结族活动频繁,导致该区域变得异常危险,提取难度极大。\n\n前往虫窝世界并手动激活钻机装置。提取过程中要捍卫阵地,保护711元素安全空运离开。", + "Destroy Stratagem Jammer": "摧毁战略配备干扰装置", + "SYSTEM BOOTING": "系统正在启动", + "Transfer in progress": "正在输送", + "Intel Package": "情报包裹", + "EVACUATE HIGH-VALUE ASSETS": "疏散高价值目标", + "No Deaths": "从未阵亡", + "Raw ore is refined into high-grade platinum at this refinery. Seize control of it.": "这座精炼厂将原矿加工成高品质铂金。夺取控制权。", + "Call down a Hellbomb to destroy the Cooling Tower": "呼叫地狱火炸弹摧毁冷却塔", + "TOUCH": "触碰", + "Illuminate Warp Ships are docked in this area. These ships are critical to the Illuminate invasion, used for all terrestrial military functions including personnel abduction and combatant deployment.\n\nWhile the ships are grounded, they are vulnerable. Find them and destroy them.": "光能者穿梭舰在此区域停靠。这些舰船对光能者的入侵行动而言非常重要,人员绑架和作战人员部署等所有地面军事行动都需要用到这些舰船。\n\n如果舰船无法起飞,它们将无力抵御攻击。找到舰船,并将其摧毁。", + "This fuel facility can be used to transfer crucial reserves to hovering shuttles.": "这座燃料设施可以将宝贵的储备资源输送至悬停的运输船。", + "Access relay controls": "获取中继控制权限", + "Within this laboratory, vile experiments twist upstanding citizens into grotesque thralls.": "在这座实验室内,邪恶的实验将正直的公民扭曲为丑陋的奴仆。", + "#WAVES waves completed": "击溃#WAVES波攻势", + "Prepare and launch the local ICBM.": "做好准备工作,发射当地的洲际弹道导弹。", + "RAISE SIGNAL STRENGTH": "提高信号强度", + "An Access Node linked to the Exospire's subterranean shield generator is stationed here.": "此处部署有接入节点,与异界尖塔地下的防护罩生成装置相连。", + "Reactivating these abandoned SEAF LiDAR towers will provide invaluable geographical data of the area.": "重新启用这些废弃的超级地球武装部队激光雷达塔,即可生成该地区的宝贵地理数据。", + "Use map to navigate to Helldiver Training Facility": "使用地图前往绝地潜兵训练基地", + "Cyberstan, once again, forms the axis of the Cyborg Legion's insurrection. Massive Megafactories cover its surface, churning out mechanical armies and weapons of mass extinction.\n\nThe Ministry of Defense has ordered the unconditional destruction of Cyberstan. Descend upon their Megafactories and put a permanent end to the Cyborg threat.": "生化斯坦再度成为生化人军团叛乱的核心。庞大的超大型工厂遍布地表,源源不断地制造机械军团与灭绝性武器。\n\n国防部已下令无条件摧毁生化斯坦。降落到这些超大型工厂,彻底终结生化人威胁。", + "TRANSMISSION STATION UPLOAD READY": "传输站上传程序准备就绪", + "Extract with Black Box": "带黑匣子撤离", + "Log in to Missile Control System": "登录导弹控制系统", + "This planet has been subjected to extended Illuminate debasement, and its corruption runs deep. Analysis of its corrupted biome will enable continued progress through the Void.": "这颗星球长期遭受光能者的侵蚀,腐化已经根深蒂固。分析这颗星球被腐化的生态系统,可以帮助我们继续深入寂域。", + "Inject Dark Fluid beneath the Supercolony's crust to destroy it once and for all.": "将暗液体注入超级拓殖地的地壳内,彻底将其摧毁。", + "Colony Breach Progress": "拓殖地攻破进度", + "MANUALLY set FLOW RATE VALVES to maximum output.": "手动将流量阀门设置为最大输出。", + "Conduct mass-scale Terminid fumigation to ensure planetary safety.": "开展大规模终结族熏杀作业,保障星球安全。", + "Illuminate forces are converging on the xenophobic ruins of their former empire. They must not be allowed to restore the relics of their tyrannical order.\n\nActivate the dormant ICBM silo in this region and reduce these makeshift lairs to ashes.": "光能者的部队正在其昔日帝国充满排外色彩的废墟之上集结。我们绝不能纵容他们重建这些象征其暴政秩序的遗迹。\n\n启动该地区休眠中的洲际弹道导弹发射井,将这些简陋的据点化为灰烬。", + "Close valve": "关闭阀门", + "Ammunition Input Required": "需要加入弹药", + "Find Terminid Brood Commander": "找到虫族指挥官", + "Open": "打开", + "Destroy Dark Fluid cells to destabilize Core": "摧毁暗液体电池,破坏核心的稳定性", + "Raise the Super Earth flag as an unassailable beacon of Unity.": "升起超级地球旗帜,犹如树立起一座坚不可摧的团结灯塔。", + "PLANETARY DEFENSE CANNON RAISING…": "行星防御加农炮正在抬升……", + "INPUT SYSTEM LOGIN CODE": "输入系统登录码", + "TOWER CONTROL TERMINAL": "通信塔控制终端", + "Upload sample data using drill interface": "使用钻机界面上传样本数据", + "Find and destroy all Terminid eggs.": "找到并摧毁终结族的所有虫卵。", + "SEIZE HIGH-GRADE PLATINUM": "夺取高品质铂金", + "SHUTTLE ENROUTE": "运输船正在航行", + "THREAT LEVEL: MODERATE": "威胁等级:中", + "This SEAF communication relay can be used to send information to ships in planetary orbit.": "这个超级地球武装部队通信转接设备可以用于给行星轨道上的舰船发送信息。", + "Select target network coordinates in grid": "选择网格中的目标网络坐标", + "We have identified the source of the Gloom: large subterranean fruiting bodies known as Spore Lungs. Larval Terminids within the Lungs appear to produce the Gloom spores, while the Lung itself pumps it into the exosphere.\n\nThe exact biology is unimportant. Delve deep into the Hive and detonate a Hellbomb within to eradicate the Spore Lung.": "我们已确认“阴霾”的源头是被称为“孢肺”的巨型地下子实体。该结构内的终结族幼虫似乎会产生“阴霾”孢子,再由孢肺泵入大气外逸层。\n\n眼下最重要的不是弄清楚其中具体的生物学原理。而是要深入虫窝内部,引爆地狱火炸弹,彻底毁灭孢肺。", + "Please stay clear of all moving parts": "请勿靠近所有活动部件", + "Scientists vital to the continued war effort were working in this top-secret research facility when the invasion hit. \n\nThey are currently kept safe inside emergency bunkers that must be opened from the outside to allow for an authorized evacuation.": "遭到入侵时,在这场持久战中起到至关重要作用的科学家正在这座绝密研究设施中孜孜不倦地工作。\n\n他们目前在紧急掩体里很安全,必须从外侧打开该掩体,才能执行授权撤离行动。", + "Reports indicate that the Annihilator Tank was last observed in this location.": "报告显示,湮灭坦克的最后目击地点就在这个位置。", + "A group of Class-A citizens are stranded at an emergency evacuation port. We cannot leave these patriots to be massacred by the Automatons.\n \nGet to the port and secure the evacuation of as many civilians as can fit aboard the designated transport shuttle.": "一组A级公民被困在紧急疏散港口。我们不能让这些爱国者为机器人所屠戮。\n\n前往港口,确保让尽可能多的平民登上指定运输船进行疏散。", + "Hack into the terminal to sabotage stationary defenses": "入侵终端以破坏固定防御设施", + "Log in to the Tower Control Panel": "登录广播塔控制面板", + "Warning: Silo susceptible to damage while charging": "阻止终结族靠近电池舱", + "Activate relay dish lift mechanism": "启动中继天线升降装置", + "Manual dish adjustment required": "需要手动调整天线", + "Facilitate our deepening understanding of the Gloom, so that it may be ultimately destroyed.": "尽快加深我们对“阴霾”的了解,以便最终将其摧毁。", + "Eradicated Heavy Bug Nest": "已摧毁重型巢穴", + "It is only a matter of time before this planet grants us safe passage into the Void. The Illuminate have deployed a massive fleet to drive our forces back and prevent the completion of this monumental breakthrough.\n\nPut an end to their interference. Hold this planet at all costs.": "我们借助这颗星球打开安全进入寂域的通道已指日可待。光能者已派出一支大型舰队,企图击退我方部队,阻止我们完成这一重大突破。\n\n终结他们的阻挠。不惜一切代价,守住这颗星球。", + "Confiscate platinum and fusion batteries at this site.": "没收此处的铂金和聚变电池。", + "Secure the SSSD containing the top-secret Cannon Access Codes.": "找到内含机密加农炮访问代码的超级固态硬盘。", + "Restore functionality to the E-711 pump site.": "使711元素泵机恢复运行。", + "Sabotage the Megafactory's air capabilities.": "破坏超大型工厂的空中作战能力。", + "Find and close any active Terminid holes": "找寻并关闭所有活动的终结族虫穴", + "DEACTIVATE TERMICIDE TOWER": "关闭灭虫终结塔", + "Battery silo offline": "电池舱停用", + "Activate the Termicide Dispersion Tower to immunize this area from the Terminids.": "启动灭虫终结剂喷洒塔,消灭该区域内的终结族。", + "ACTIVATE TRANSFER": "开始输送", + "EVACUATE HIGH-VALUE ARTIFACTS": "撤走高价值文物", + "This planet is the center of Illuminate operations within the Void. They have constructed extensive facilities, whose nature is bewildering to Democratic minds and affronts to all things Free. Tear them down, and put an end to the Void.": "这颗星球是光能者在寂域中的行动枢纽。他们建造了规模庞大的设施,民主的思维难以理解其中的本质,这些地方全都是对一切自由事物的公然亵渎。将这里夷为平地,终结寂域的存在。", + "COLLECT METEOROLOGICAL DATA": "收集气象数据", + "DISRUPT ILLUMINATE": "挫败光能者", + "INPUT LAUNCH CODE": "输入发射代码", + "RETRIEVE KEYCARD": "取得钥匙卡", + "Halt the extensive Automaton industrial operations on this lava-covered planet. Annex their facilities and seize their stolen goods.": "阻止机器人在这颗熔岩覆盖的星球上展开大规模工业活动。占领它们的设施,夺回被盗的物资。", + "Connect Battery Silos to Central Tower": "将电池舱与中央巨塔连接起来", + "Completed: #AMOUNT M": "完成:#AMOUNT", + "PRIMING SEISMIC PROBE": "地震探测仪正在准备", + "Battery Silo 01 Offline": "电池舱01停用", + "ACTIVATE PUMPS": "启动泵机", + "Power unavailable": "电力不可用", + "Use drill interface to switch drills": "使用钻机界面切换钻机", + "Seal indicated exhaust pipes": "密封已标记的排气管", + "The Overship is the command-and-control nexus of Illuminate forces in this sector. Its oppressive presence must be destroyed.\n\nA Planetary Defense Cannon in this area can penetrate its shields. Activate the Cannon and use it to bring down the Overship.": "统御舰是该分区光能者部队的指挥中枢。必须摧毁这艘暴政舰船。\n\n该区域的行星防御加农炮可穿透其护盾。启动加农炮,击沉统御舰。", + "The Illuminate have carved a totalitarian lair amid this region's tangled growth. Heretical altars and foul laboratories create unspeakable horrors that would terrorize every household in the galaxy. \n\nInfiltrate this twisted cradle of corruption. Expose and put an end to their depravity.": "光能者在该地区茂密的丛林深处建造了一座极权主义巢穴。它们在异端祭坛和肮脏实验室里炮制出的不可名状的恐怖存在,足以令银河系的每家每户都活在恐惧之中。\n\n潜入这个扭曲的腐化巢穴。揭露并终结它们的邪恶勾当。", + "FUELING MISSILE - PLEASE WAIT": "正在为导弹添加燃料,请稍候", + "PLACE DATA DRIVE IN INPUT TRAY": "将数据硬盘放进输入托盘", + "FUSE 1": "熔断器1", + "CONTROL CHAMBER UNLOCKED": "控制室已解锁", + "ACTIVATE DRILL 3?": "是否启动3号钻机?", + "We have discovered extensive Automaton mining and processing operations on this previously uninhabited planet. This lava-covered world is rich in mineral resources, but constant eruptions and a noxious atmosphere makes it unsuitable for human habitation. \n\nThe Automatons are recklessly exploiting the natural riches of this planet, stealing them from our citizens and transforming them into tools of Socialist oppression. We must stop them, annex their industry, and seize their stolen goods.": "我们发现机器人在这颗此前无人居住的星球上进行大规模采矿和加工作业。这颗被熔岩覆盖的星球矿物资源丰富,但上面的火山持续喷发,大气环境有毒,不适合人类居住。\n\n机器人肆意开采这颗星球的自然财富,从我们公民手中窃取资源,并转化为党同伐异的工具。我们必须阻止它们,吞并它们的产业,夺回被盗的物资。", + "CRITICAL SYSTEMS INTERFACE": "关键系统界面", + "Charge into the Exostorm and save this planet from falling to the Void.": "挺进异界风暴,拯救这颗星球,使其免于堕入寂域。", + "RUN SABOTAGE SOFTWARE": "运行破坏软件", + "This altar’s wellspring is crawling with Illuminate tadpoles, poised to evolve into fully fledged war criminals at any moment.": "这座祭坛的泉眼中爬满了光能者蝌蚪,它们随时可能蜕变为彻头彻尾的战犯。", + "#COUNT% XP RATING": "#COUNT%经验等级", + "FLAG": "旗帜", + "Filter": "筛选", + "Low death bonus: #AMOUNT M": "低阵亡率加分:#AMOUNT", + "Thank you for your cooperation": "感谢您的配合", + "INVESTIGATE VOID PLANET": "调查寂域星球", + "AA Emplacement": "防空炮台", + "Loot Update": "战利品更新", + "SAFEGUARD VITAL E-711": "保卫VITAL E-711", + "Black Box": "黑匣子", + "ANOMALOUS MATERIAL SITE": "异常物质地点", + "DESTROY PROTOSPIRE": "摧毁原始虫塔", + "#TYPE: +#AMOUNT/#POTENTIAL M": "#TYPE:+#AMOUNT/#POTENTIAL", + "DISABLING CRITICAL SYSTEMS...": "正在关闭关键系统…", + "Illuminate Exospires are channeling an aberrant Exostorm that rages on the surface of this world. The planet is at risk of being consumed by the Void, unless we act now.\n\nLay waste to their abyssal sanctums. Not a single Exospire can remain if Freedom’s light is to prevail.": "光能者异界尖塔正引导一股畸变的异界风暴,在这个世界的地表肆虐。若不立即采取行动,星球恐将被寂域吞噬。\n\n彻底捣毁它们的深渊圣所。只有摧毁所有的异界尖塔,自由之光方能普照。", + "Destroy the Cognitive Disruptor's power supply.": "摧毁感知干扰器的能源。", + "SEIZE FUSION BATTERIES": "夺取聚变电池", + "Retrieve coordinates": "获取坐标", + "HALT CYBORG PRODUCTION": "使生化人停产", + "Maiden voyage of the #SHIP_NAME.": "#SHIP_NAME的首航。", + "The Automatons have heavily industrialized this region and are producing a nonstop supply of fresh troops. \n\nDestroy their infrastructure and kill as many bots as you can.": "机器人已经在该地区实现重度工业化,同时在源源不断地为自己的军队输送新鲜血液。\n\n摧毁它们的基础设施,尽可能击杀机器人。", + "COMPROMISE AUTOMATON DEFENSES": "破坏机器人的防御系统", + "Use terminal to raise satellite tower": "使用终端抬升卫星塔", + "DESTROY ROGUE RESEARCH STATION": "摧毁叛变科研站", + "The Illuminate have corrupted this planet after sequestering it within the Void. Stop this planetary degradation, and aid in the collection of data that will lead us further into the Void.": "光能者将这颗星球困在寂域中,然后对其进行了彻底腐化。阻止这颗星球的进一步恶化,协助我们收集数据,为深入寂域开辟道路。", + "RAPID ACQUISITION": "快速夺取", + "Destroy Command Bunker": "摧毁指挥碉堡", + "Activate Artillery": "启动大炮", + "Call down a Hellbomb to destroy the Counter-Orbital Cannon": "呼叫地狱火炸弹摧毁反轨道加农炮", + "Automatons in this region pose an undeniable and multifaceted threat to Liberty. Do whatever it takes to defend our way of life.": "毋庸置疑,该地区的机器人对解放大业的多个方面都构成威胁。不惜一切代价也要捍卫我们的生存之道。", + "The Automatons are synthesizing some kind of nutrient-dense plasma from organic material. Undeniable intel shows 100% of this organic material came from loyal citizens with high potential and excellent facial symmetry. The purpose of this plasma is yet unknown, but its production is extremely costly.\n\nDisrupt the plasma production and secure samples of the liquid for further analysis.": "机器人正在用有机物质合成某种富含营养的等离子。有确凿情报显示,这些有机物质100%来自潜力巨大而且面部完美对称的忠诚公民。这种等离子用途尚不明确,但其生产成本极其高昂。\n\n破坏等离子的生产过程,获取液体样本供进一步分析。", + "Samples Found": "已找到样本数", + "Keep hands away from extractors": "请勿触碰提取器", + "Illuminate invaders have located Priority Emergency Bunkers (available to citizens at Class B and above), and are ruthlessly targeting these non-combatants in clear violation of galactic law. \n \nTransport ships are inbound to evacuate the citizens. The Helldivers must ensure these patriotic and loyal citizens reach safe harbor.": "光能者已发现向B级及以上公民开放的优先紧急掩体,正残忍屠杀这些平民,公然践踏星际法律。\n\n帮助公民撤离的运输舰即将抵达。绝地潜兵必须确保这些忠诚的爱国公民安全登舰。", + "An Automaton Hulk was last reported in this location.": "据报告称,机器人巨型者的最后目击地点就在这个位置。", + "ANNEX UNTAPPED MINERAL SITES": "吞并未开发的矿点", + "EXTRACT WITH FOOTAGE": "带录像撤离", + "OUTPOSTS DESTROYED": "已摧毁哨站", + "Highest priority upload speed": "最高优先级上传速度", + "RAISE SATELLITE TOWER": "抬升卫星塔", + "Proceed to Live Fire Range": "前往实弹靶场", + "A massive Terminid swarm is gathering in this region. Left unchecked, it threatens to explode out of control.\n\nKill as many Terminids as you can to thin their numbers.": "一个庞大的终结族虫群正在该地区集结。如果置之不理,它们可能有失控的风险。\n\n尽可能击杀更多终结族,削减它们的数量。", + "Once the GATER is secured, use it to extract the resources in this area.": "GATER到位就绪后,立即使用它在该区域提取资源。", + "ICBM Launching": "洲际弹道导弹即将发射", + "READY TO LAUNCH": "准备发射", + "The Illuminate have discovered a long-sequestered cache of top-secret, highly valuable assets, frozen in cryostasis since the First Galactic War. These assets cannot be allowed to fall into the Illuminate's clutches.\n\nDefend the site long enough for all evacuation rockets to launch.": "光能者发现了一处尘封已久的绝密贵重资产库,该库存自第一次星系战争以来就利用冷冻技术封存至今。不能让这批资产落入光能者手中。\n\n坚守撤离点,直至所有撤离火箭发射完毕。", + "ERROR - TOWER MISALIGNED": "错误,卫星塔方向偏离", + "Shameful Return": "屈辱归来", + "ROOT OUT HIVES": "清除虫窝", + "Geological grid map scale 1:100": "地质网格地图比例尺 1:100", + "Abandoned SEAF artillery can be reactivated for ground-based support.": "重新启动废弃的超级地球武装部队大炮可以提供陆基火力支援。", + "ACTIVATE SEISMIC SCAN?": "是否启动地震扫描?", + "NEUTRALIZE ORBITAL CANNON": "阻止敌方使用轨道加农炮", + "THREAT LEVEL: SUBSTANTIAL": "威胁等级:较高", + "TRANSMIT DATA PACKAGE": "传输数据包", + "Liberate the Hive World to prevent the spread of the Gloom, and extract as much E-711 as possible.": "解放虫窝世界,阻止“阴霾”扩散,并尽可能提取更多711元素。", + "INITIATE POWER SURGE": "启动电涌", + "INITIATE POWER TRANSFER": "开始输电", + "CLEANSE FOUL SHRINE": "净化污秽神社", + "Purification": "提纯", + "Bypass terminal security": "绕过终端安全系统", + "Proceed to TCS+ activation terminal": "前往TCS+激活终端", + "Helldiver Replacements": "绝地潜兵替补兵员", + "Enter code to begin activation process": "输入代码激活启动程序", + "MISSION TIME : #MINUTES:#SECONDS": "任务用时:#MINUTES:#SECONDS", + "Briefcase": "公文包", + "FINAL TEST IN PROGRESS": "正在进行终极考验", + "Activate Hive Breaker Drill": "启动“虫窝破裂者”钻机", + "ACQUIRE SOIL SCAN DATA": "获取土壤扫描数据", + "Raising satellite tower": "正在抬升卫星塔", + "SEAF Combat Engineers have deployed a Rapid Modular Drilling Platform above a pool of a mysterious E-710-like substance deep within the Terminid caves. High Terminid activity has made the area extremely dangerous and made extraction impossible.\n\nDeploy to the Hive World and manually activate the Rig. Protect the extraction process until the substance is safely airlifted away.": "终结族洞穴深处有整整一池的类710元素神秘物质,超级地球武装部队战斗工程师已在其上方部署了快速模块化钻机平台。终结族活动频繁,导致该区域变得异常危险,提取难度极大。\n\n前往虫窝世界并手动激活钻机装置。提取过程中要捍卫阵地,保护神秘物质安全空运离开。", + "Use the Portable Hellbomb to destroy the Hive Lung": "使用便携式地狱火炸弹摧毁虫窝孢肺", + "We have received reports from this region of Brood Commanders exhibiting dangerous new mutations.\n\nFind and eliminate them before they can breed.": "我们收到了来自该地区的报告。据称,虫族指挥官表现出危险的新型突变属性。\n\n在此类生物繁殖之前找到它们并将其消灭。", + "ELIMINATE CHARGER": "消灭强袭虫", + "Shuttle Bay Terminal System": "运输船坞终端系统", + "DESTROY TRANSMISSION NETWORK": "摧毁传输网络", + "Track down and eliminate the Brood Commander.": "追踪并消灭虫族指挥官。", + "Terminal": "终端", + "BLOWN FUSES FOUND": "发现熔断器熔断", + "GENERATOR CONTROL UNIT": "发电机控制单元", + "Use terminal to lock the target coordinates": "使用终端,锁定目标坐标", + "A vast network of underground hives has allowed the Terminids in this region to become entrenched, breeding and swelling in number.\n\nFortunately, this hive has just gone into a brief hibernation. Infiltrate, and destroy all you can before the Terminids return to full strength.": "庞大的地下虫窝网络使终结族得以在该地区根深蒂固,不断繁殖壮大。\n\n幸好,这个虫窝刚刚进入了短暂的休眠状态。赶在终结族完全恢复力量之前潜入其中,尽可能摧毁一切。", + "Wait for power charge": "等待充电", + "Thank you for your service": "感谢你的付出", + "ESTABLISH COMMUNICATION UPLINK": "建立通信上行链路", + "CARGO CONTAINER": "货物集装箱", + "Use terminal to open silo hatch": "使用终端,打开发射井舱门", + "TOTAL: +#AMOUNT M": "总计:+#AMOUNT", + "The high-value intel is located here. It is locked inside a secure containment unit.": "高价值情报位于此处。情报被锁在安全收容装置内。", + "Nuclear Missile": "核导弹", + "Locate and unlock system access port": "定位并解锁系统访问端口", + "Destroyed Heavy Automaton Outpost": "已摧毁重型机器人哨站", + "Network connection lost": "网络连接丢失", + "ELIMINATE AUTOMATON FACTORY STRIDER": "消灭机器人移动工厂", + "Defend Battery Silo 03": "保卫电池舱03", + "Station inoperable at current time": "站点目前无法运转" +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/equipment.py b/hexi/plugins/nonebot_plugin_helldivers_tools/equipment.py new file mode 100644 index 0000000..7c3deff --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/equipment.py @@ -0,0 +1,66 @@ +import os +import random +from nonebot import logger +from .equipment_renderer import render_equipment_card +from .equipment_store import list_stratagems + + +basic_path = os.path.dirname(__file__) +save_path = os.path.join(basic_path, "temp") +img_path = os.path.join(basic_path, "img") +data_path = os.path.join(basic_path, "data") + + +async def get_random_equipment(count): + data = list_stratagems() + indices = select_random_equipment(len(data), count) + selected_equipment = [data[i] for i in indices] + + return await render_equipment_card(selected_equipment) + + +async def get_equipment_by_combination(type_combination): + data = list_stratagems() + + equipment_by_type = categorize_equipment_by_type(data) + selected_equipment = select_equipment_by_type(equipment_by_type, type_combination) + + logger.debug(f"根据组合选择的装备: {selected_equipment}") + return await render_equipment_card(selected_equipment) + + +def categorize_equipment_by_type(data): + equipment_by_type = {} + for item in data: + equip_type = item['type'] + if equip_type not in equipment_by_type: + equipment_by_type[equip_type] = [] + equipment_by_type[equip_type].append(item) + return equipment_by_type + + +def select_equipment_by_type(equipment_by_type, type_combination): + selected_equipment = [] + backpack_count = 0 + + for equip_type, count in type_combination.items(): + if equip_type in equipment_by_type: + available_items = equipment_by_type[equip_type] + random.shuffle(available_items) + selected = 0 + for item in available_items: + if selected < count: + if item['backpack'] == 1 and backpack_count >= 1: + continue + selected_equipment.append(item) + selected += 1 + if item['backpack'] == 1: + backpack_count += 1 + else: + break + + return selected_equipment + + +def select_random_equipment(max_equipment, count): + return random.sample(range(max_equipment), count) \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/equipment_renderer.py b/hexi/plugins/nonebot_plugin_helldivers_tools/equipment_renderer.py new file mode 100644 index 0000000..edf4d2d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/equipment_renderer.py @@ -0,0 +1,102 @@ +import random +import secrets +from pathlib import Path +from typing import Any + +from nonebot import require + +# 顺序很重要:先 require 声明依赖,再 import(与 war_renderer 一致) +require("nonebot_plugin_htmlrender") + +from nonebot_plugin_htmlrender import get_new_page # noqa: E402 + +from .war_renderer import _font_faces, _logo_data_uri, _rel + +basic_path = Path(__file__).resolve().parent +template_path = basic_path / "templates" +img_path = basic_path / "img" + +# 战备类型 -> (标签, 主题色) +TYPE_STYLE: dict[str, dict[str, str]] = { + "blue": {"label": "武装·补给", "color": "#6bb7ea"}, + "red": {"label": "轨道·飞鹰", "color": "#fe6d6a"}, + "green": {"label": "战术·设备", "color": "#7ecb3f"}, +} + + +def _load_template(name: str) -> str: + """读取 templates/ 下的模板文件(UTF-8),每次渲染实时读取,便于改模板即时生效。""" + return (template_path / name).read_text(encoding="utf-8") + + +def _equip_icon(equip: dict[str, Any]) -> str: + """战备图标:读取 img/helldivers/ 下的 PNG,配合 用相对路径链接。""" + raw = equip.get("path") or "" + if not raw: + return "" + p = basic_path / raw.replace("\\", "/") + if not p.exists(): + return "" + return f"" + + +def _item_html(equip: dict[str, Any]) -> str: + name = equip.get("name") or "未知战备" + alias = (random.choice(equip["alias"]) if equip.get("alias") else None) or "" + type_key = equip.get("type") or "" + style = TYPE_STYLE.get(type_key, {"label": "其他", "color": "#cccccc"}) + label = style["label"] + color = style["color"] + backpack = "背包位" if equip.get("backpack") else "" + alias_html = f"{alias}" if alias else "" + meta_tail = f" · {backpack}" if backpack else "" + return f""" +
    +
    {_equip_icon(equip)}
    +
    +
    {name}
    +
    + {label} + {alias_html}{meta_tail} +
    +
    +
    """ + + +def _build_html(items: list[dict[str, Any]]) -> str: + rows = "".join(_item_html(e) for e in items) + return ( + _load_template("equip_card.html") + .replace("@@BASE@@", basic_path.as_uri() + "/") + .replace("@@FONT_FACES@@", _font_faces()) + .replace("@@CSS@@", _load_template("equip_card.css")) + .replace("@@LOGO@@", _logo_data_uri()) + .replace("@@ROWS@@", rows) + ) + + +async def _html_to_png(html: str, width: int = 640) -> bytes: + async with get_new_page() as page: + # 初始视口高度给一个小于内容的值,便于按 scrollHeight 收紧,避免截出多余空白 + await page.set_viewport_size({"width": width, "height": 300}) + # 图片/字体用相对路径 + 解析;写临时 .html 到插件根目录, + # 使页面与 img/、data/ 同目录树,file:// 同源即可加载(无需额外标志)。 + tmp = basic_path / f"_equip_render_{secrets.token_hex(6)}.html" + tmp.write_text(html, encoding="utf-8") + try: + await page.goto(tmp.as_uri(), wait_until="networkidle") + # 视口高度收紧到内容实际高度,避免 full_page 截出多余空白 + height = await page.evaluate("document.documentElement.scrollHeight") + await page.set_viewport_size({"width": width, "height": height}) + return await page.screenshot(full_page=True, type="png") + finally: + try: + tmp.unlink() + except OSError: + pass + + +async def render_equipment_card(items: list[dict[str, Any]]) -> bytes: + """把随机/组合出的战备渲染成一张 PNG 图(使用 nonebot_plugin_htmlrender)。""" + html = _build_html(items) + return await _html_to_png(html) diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/equipment_store.py b/hexi/plugins/nonebot_plugin_helldivers_tools/equipment_store.py new file mode 100644 index 0000000..c1bab31 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/equipment_store.py @@ -0,0 +1,321 @@ +# -*- coding: utf-8 -*- +"""战备(SQLite)数据存取层。 + +把原来写在 data/equipment.json 的战备数据迁移到 SQLite,供 +- equipment.py 随机/组合抽取 +- 战备管理后台(stratagem_admin.py) 的读/写/导入/导出 + +三层语义弱化为单表 + is_custom 标记: +- 从 data/equipment.json 首次播种的记录 is_custom=0(基础库) +- 管理后台手动新增的记录 is_custom=1 +- 手动编辑都是直接改行,不另建覆盖层(当前不做 API 同步,因此单表即可) +""" + +from __future__ import annotations + +import json +import sqlite3 +import time +from pathlib import Path +from typing import Any + +from nonebot import logger + +basic_path = Path(__file__).resolve().parent +DATA_DIR = basic_path / "data" +DB_PATH = DATA_DIR / "equipment.db" +SEED_PATH = DATA_DIR / "archive" / "equipment.json" + + +def _connect() -> sqlite3.Connection: + conn = sqlite3.connect(DB_PATH) + conn.row_factory = sqlite3.Row + return conn + + +def _now() -> str: + return time.strftime("%Y-%m-%d %H:%M:%S") + + +def _load_seed() -> list[dict[str, Any]]: + """读取随包的 equipment.json 作为初始基础库。""" + if not SEED_PATH.exists(): + return [] + try: + data = json.loads(SEED_PATH.read_text(encoding="utf-8")) + return data if isinstance(data, list) else [] + except Exception as e: # noqa: BLE001 + logger.warning(f"读取 equipment.json 失败,跳过播种: {e}") + return [] + + +def init_db() -> None: + """建表(WAL 便于网页与 bot 并发读写),空表时从 equipment.json 播种。""" + DATA_DIR.mkdir(parents=True, exist_ok=True) + with _connect() as conn: + conn.execute("PRAGMA journal_mode=WAL") + conn.execute( + """ + CREATE TABLE IF NOT EXISTS stratagems ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + name_en TEXT NOT NULL DEFAULT '', + type TEXT NOT NULL DEFAULT 'blue', + backpack INTEGER NOT NULL DEFAULT 0, + icon TEXT NOT NULL DEFAULT '', + alias TEXT NOT NULL DEFAULT '[]', + is_custom INTEGER NOT NULL DEFAULT 0, + created_at TEXT, + updated_at TEXT, + UNIQUE(name) + ) + """ + ) + cur = conn.execute("SELECT COUNT(*) AS n FROM stratagems") + if cur.fetchone()["n"] == 0: + now = _now() + for item in _load_seed(): + if not isinstance(item, dict): + continue + name = (item.get("name") or "").strip() + if not name: + continue + alias = item.get("alias") or [] + if isinstance(alias, str): + alias = [a.strip() for a in alias.split(",") if a.strip()] + conn.execute( + """ + INSERT OR IGNORE INTO stratagems + (name, name_en, type, backpack, icon, alias, is_custom, created_at, updated_at) + VALUES (?,?,?,?,?,?,?,?,?) + """, + ( + name, + item.get("name_en") or "", + item.get("type") or "blue", + 1 if item.get("backpack") else 0, + item.get("path") or item.get("icon") or "", + json.dumps(alias, ensure_ascii=False), + 0, + now, + now, + ), + ) + conn.commit() + + +def _row_to_item(row: sqlite3.Row) -> dict[str, Any]: + try: + alias = json.loads(row["alias"] or "[]") + if not isinstance(alias, list): + alias = [] + except Exception: # noqa: BLE001 + alias = [] + return { + "id": row["id"], + "name": row["name"], + "name_en": row["name_en"] or "", + "type": row["type"] or "blue", + "backpack": bool(row["backpack"]), + "path": row["icon"] or "", + "icon": row["icon"] or "", + "alias": alias, + "is_custom": bool(row["is_custom"]), + } + + +def _normalize_alias(value: Any) -> list[str]: + if isinstance(value, str): + parts = [v.strip() for v in value.replace(",", ",").replace("、", ",").replace("\n", ",").split(",") if v.strip()] + elif isinstance(value, list): + parts = [v.strip() for v in value if isinstance(v, str) and v.strip()] + else: + parts = [] + seen: set[str] = set() + out: list[str] = [] + for p in parts: + if p not in seen: + seen.add(p) + out.append(p) + return out + + +def list_stratagems() -> list[dict[str, Any]]: + init_db() + with _connect() as conn: + rows = conn.execute("SELECT * FROM stratagems ORDER BY id").fetchall() + return [_row_to_item(r) for r in rows] + + +def count_stratagems() -> int: + init_db() + with _connect() as conn: + return int(conn.execute("SELECT COUNT(*) AS n FROM stratagems").fetchone()["n"]) + + +def list_stratagems_page(page: int = 1, page_size: int = 20) -> tuple[list[dict[str, Any]], int]: + init_db() + total = count_stratagems() + offset = (page - 1) * page_size + with _connect() as conn: + rows = conn.execute( + "SELECT * FROM stratagems ORDER BY id LIMIT ? OFFSET ?", + (page_size, offset), + ).fetchall() + return [_row_to_item(r) for r in rows], total + + +def get_stratagem(seed: int) -> dict[str, Any] | None: + init_db() + with _connect() as conn: + row = conn.execute("SELECT * FROM stratagems WHERE id=?", (seed,)).fetchone() + return _row_to_item(row) if row else None + + +def create_stratagem(item: dict[str, Any]) -> dict[str, Any]: + init_db() + name = (item.get("name") or "").strip() + if not name: + raise ValueError("name 不能为空") + now = _now() + with _connect() as conn: + cursor = conn.execute( + """ + INSERT INTO stratagems (name, name_en, type, backpack, icon, alias, is_custom, created_at, updated_at) + VALUES (?,?,?,?,?,?,?,?,?) + """, + ( + name, + item.get("name_en") or "", + item.get("type") or "blue", + 1 if item.get("backpack") else 0, + item.get("icon") or item.get("path") or "", + json.dumps(_normalize_alias(item.get("alias")), ensure_ascii=False), + 1, + now, + now, + ), + ) + conn.commit() + new_id = cursor.lastrowid + row = get_stratagem(new_id) + assert row is not None + return row + + +def update_stratagem(seed: int, fields: dict[str, Any]) -> dict[str, Any] | None: + init_db() + if not fields: + return get_stratagem(seed) + # 只允许安全字段 + allowed = {"name", "name_en", "type", "backpack", "icon", "path", "alias"} + updates: dict[str, Any] = {} + for k in allowed: + if k in fields: + updates[k] = fields[k] + if "alias" in updates: + updates["alias"] = json.dumps(_normalize_alias(updates["alias"]), ensure_ascii=False) + if "path" in updates and "icon" not in updates: + updates["icon"] = updates.pop("path") + elif "icon" in updates: + updates.pop("path", None) + if not updates: + return get_stratagem(seed) + updates["updated_at"] = _now() + sets = ", ".join(f"{k}=?" for k in updates) + params = list(updates.values()) + [seed] + with _connect() as conn: + cur = conn.execute(f"UPDATE stratagems SET {sets} WHERE id=?", params) + conn.commit() + if cur.rowcount == 0: + return None + return get_stratagem(seed) + + +def delete_stratagem(seed: int) -> bool: + init_db() + with _connect() as conn: + cur = conn.execute("DELETE FROM stratagems WHERE id=?", (seed,)) + conn.commit() + return cur.rowcount > 0 + + +def import_items(items: list[dict[str, Any]]) -> dict[str, int]: + """按 id(存在则更新) 或 name(存在则更新) 合并导入;新增的记录标记为 custom。 + + 返回 {added, updated, skipped} + """ + init_db() + added = 0 + updated = 0 + skipped = 0 + now = _now() + with _connect() as conn: + for item in items: + if not isinstance(item, dict): + skipped += 1 + continue + name = (item.get("name") or "").strip() + if not name: + skipped += 1 + continue + seed = item.get("id") + existing: dict[str, Any] | None = None + if isinstance(seed, int): + row = conn.execute("SELECT * FROM stratagems WHERE id=?", (seed,)).fetchone() + existing = _row_to_item(row) if row else None + if existing is None: + row = conn.execute("SELECT * FROM stratagems WHERE name=?", (name,)).fetchone() + existing = _row_to_item(row) if row else None + if existing is None: + conn.execute( + """ + INSERT INTO stratagems (name, name_en, type, backpack, icon, alias, is_custom, created_at, updated_at) + VALUES (?,?,?,?,?,?,?,?,?) + """, + ( + name, + item.get("name_en") or "", + item.get("type") or "blue", + 1 if item.get("backpack") else 0, + item.get("icon") or item.get("path") or "", + json.dumps(_normalize_alias(item.get("alias")), ensure_ascii=False), + 1, + now, + now, + ), + ) + added += 1 + else: + fields = { + "name": name, + "name_en": (item.get("name_en") or existing.get("name_en") or ""), + "type": (item.get("type") or existing.get("type") or "blue"), + "backpack": bool(item.get("backpack", existing.get("backpack"))), + "icon": (item.get("icon") or item.get("path") or existing.get("icon") or ""), + "alias": item.get("alias", existing.get("alias")), + } + conn.execute( + """ + UPDATE stratagems + SET name=?, name_en=?, type=?, backpack=?, icon=?, alias=?, updated_at=? + WHERE id=? + """, + ( + fields["name"], + fields["name_en"], + fields["type"], + 1 if fields["backpack"] else 0, + fields["icon"], + json.dumps(_normalize_alias(fields["alias"]), ensure_ascii=False), + now, + existing["id"], + ), + ) + updated += 1 + conn.commit() + return {"added": added, "updated": updated, "skipped": skipped} + + +def export_items() -> list[dict[str, Any]]: + return list_stratagems() \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/hd2_api.py b/hexi/plugins/nonebot_plugin_helldivers_tools/hd2_api.py new file mode 100644 index 0000000..8882cc9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/hd2_api.py @@ -0,0 +1,168 @@ +import asyncio +import time +from typing import Any, Awaitable, Callable + +import httpx +from nonebot import logger + +from .config import config + +# 简单的进程内缓存 {key: (过期时间戳, 数据)},用于聚合战况时只打一次接口 +_cache: dict[str, tuple[float, Any]] = {} + + +def _headers(language: str | None = None) -> dict[str, str]: + # 两个 X-Super-* 头必须都存在,否则公共实例(ValidateClients)会直接返回 400 + lang = language or config.hd2_api_language + return { + "Accept-Language": f"{lang},en-US;q=0.5", + "X-Super-Client": config.hd2_super_client, + "X-Super-Contact": config.hd2_super_contact or config.hd2_super_client, + } + + +def _base_url() -> str: + return config.hd2_api_base_url.rstrip("/") + + +async def _get_json(url: str, language: str | None = None) -> Any: + async with httpx.AsyncClient(timeout=15) as client: + resp = await client.get(url, headers=_headers(language)) + if resp.status_code != 200: + raise httpx.HTTPStatusError( + f"{resp.status_code} {resp.reason_phrase} for {url}\n{resp.text[:400]}", + request=resp.request, + response=resp, + ) + return resp.json() + + +async def _cached(key: str, fetcher: Callable[[], Awaitable[Any]]) -> Any: + now = time.time() + hit = _cache.get(key) + if hit and hit[0] > now: + return hit[1] + data = await fetcher() + _cache[key] = (now + config.hd2_cache_ttl, data) + return data + + +# ---- 原始接口 fetchers(不带缓存,供各 get_* 包装) ---- + +async def _fetch_war() -> Any: + return await _get_json(f"{_base_url()}/api/v1/war") + + +async def _fetch_major_orders() -> Any: + return await _get_json(f"{_base_url()}/api/v1/assignments") + + +async def _fetch_campaigns(language: str | None) -> Any: + return await _get_json(f"{_base_url()}/api/v1/campaigns", language) + + +async def _fetch_planets(language: str | None) -> Any: + return await _get_json(f"{_base_url()}/api/v1/planets", language) + + +async def _fetch_planet_detail(index: int, language: str | None) -> Any: + return await _get_json(f"{_base_url()}/api/v1/planets/{index}", language) + + +async def _fetch_raw_status() -> Any: + # 原始接口一次返回全部:planetActiveEffects / spaceStations / planetStatus 等 + return await _get_json(f"{_base_url()}/raw/api/WarSeason/801/Status") + + +# ---- 对外封装(各自带缓存,可单独调用) ---- + +async def get_war() -> Any: + """星系战况概要(年代起止/阵营/影响倍率等)。""" + return await _cached("war", _fetch_war) + + +async def get_major_orders() -> Any: + """重要指令(最高指令 / assignments,含任务目标、奖励、阵营)。""" + return await _cached("assignments", _fetch_major_orders) + + +async def get_campaigns(language: str | None = None) -> Any: + """当前参与战役的星球列表(含每颗参战星球的进度/事件/危害等)。""" + key = f"campaigns:{language or ''}" + return await _cached(key, lambda: _fetch_campaigns(language)) + + +async def get_planets(language: str | None = None) -> Any: + """全星球表(每颗星的 biome/hazards/event/currentOwner/statistics 等)。""" + key = f"planets:{language or ''}" + return await _cached(key, lambda: _fetch_planets(language)) + + +async def get_planet_detail(index: int, language: str | None = None) -> Any: + """单星球详细情况(biome/hazards/event/statistics/attacking/regions 等)。""" + key = f"planet:{index}:{language or ''}" + return await _cached(key, lambda: _fetch_planet_detail(index, language)) + + +async def get_raw_status() -> Any: + """原始 WarSeason/801/Status(planetStatus/planetActiveEffects/spaceStations...)。""" + return await _cached("raw_status", _fetch_raw_status) + + +async def get_space_stations() -> list[Any]: + """空间站(民主空间站 DSS 等)。""" + raw = await get_raw_status() + return list((raw or {}).get("spaceStations") or []) + + +async def get_planet_effects(index: int | None = None) -> dict[int, list[int]]: + """星球当前生效效果 {星球index: [galacticEffectId...]};传 index 时只返回该星球的集合。""" + raw = await get_raw_status() + effects: dict[int, list[int]] = {} + for item in (raw or {}).get("planetActiveEffects") or []: + if ( + isinstance(item, dict) + and item.get("index") is not None + and item.get("galacticEffectId") is not None + ): + effects.setdefault(item["index"], []).append(item["galacticEffectId"]) + if index is not None: + return {index: effects.get(index, [])} + return effects + + +# ---- 聚合入口(渲染战报用;也可改为按需调用各 get_* 组装) ---- + +async def get_briefing_data() -> dict[str, Any]: + """并发拉取战报所需的分组数据,带缓存,返回聚合结果。""" + war, assignments, campaigns, planets, raw_status = await asyncio.gather( + get_war(), + get_major_orders(), + get_campaigns(), + get_planets(language="en-US"), # 用英文星名匹配高清地形图;currentOwner 等不受语言影响 + get_raw_status(), + ) + + logger.info("已获取 helldivers 战况数据") + planet_english = { + p["index"]: p.get("name") + for p in (planets or []) + if p.get("index") is not None and p.get("name") + } + # 星球当前效果:{星球index: [galacticEffectId...]} + planet_effects: dict[int, list[int]] = {} + for item in (raw_status or {}).get("planetActiveEffects") or []: + if isinstance(item, dict) and item.get("index") is not None and item.get("galacticEffectId") is not None: + planet_effects.setdefault(item["index"], []).append(item["galacticEffectId"]) + # 空间站(民主空间站 DSS 等):独立展示,不混进普通星球效果 + space_stations = (raw_status or {}).get("spaceStations") or [] + return { + "war": war, + "assignments": assignments, + "campaigns": campaigns, + "planets": planets, + "planet_english": planet_english, + "planet_effects": planet_effects, + "space_stations": space_stations, + "fetched_at": int(time.time()), + } diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/icon_utils.py b/hexi/plugins/nonebot_plugin_helldivers_tools/icon_utils.py new file mode 100644 index 0000000..29c9c2b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/icon_utils.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +"""SVG -> PNG 转换 + 可选 HD2 风格边框,用于战备图标上传。""" + +from __future__ import annotations + +import base64 +import io +import re +from pathlib import Path + +from PIL import Image, ImageDraw + +SCHEMA_SIZE = 550 # 与随包 PNG 图标一致 +TYPE_COLORS = { + "blue": "#6bb7ea", + "red": "#fe6d6a", + "green": "#7ecb3f", +} + +basic_path = Path(__file__).resolve().parent +IMG_DIR = basic_path / "img" / "helldivers" + + +def sanitize_filename(name: str) -> str: + """把战备名转成安全的 Windows 文件名(保留中文/空格,去掉非法字符)。""" + s = re.sub(r'[\\/:*?"<>|]', "_", name).strip() + s = re.sub(r"\s+", " ", s) + return s or "strategem" + + +def _hex_to_rgb(hex_color: str) -> tuple[int, int, int]: + h = hex_color.lstrip("#") + if len(h) == 3: + h = "".join(c * 2 for c in h) + return tuple(int(h[i : i + 2], 16) for i in (0, 2, 4)) # type: ignore[return-value] + + +def _apply_frame(src_png: bytes, size: int, frame_color: str) -> bytes: + """把透明的 SVG 画面叠到 HD2 风格画布上:彩色边框 + 深色内底 + 居中图形。""" + rgb = _hex_to_rgb(frame_color) + img = Image.open(io.BytesIO(src_png)).convert("RGBA") + canvas = Image.new("RGBA", (size, size), rgb + (255,)) + draw = ImageDraw.Draw(canvas) + border = max(10, size // 20) + # 外圈用类型色,内部深色 + draw.rectangle([0, 0, size - 1, size - 1], fill=rgb + (255,)) + draw.rectangle([border, border, size - 1 - border, size - 1 - border], fill=(12, 12, 12, 255)) + # 去掉透明边距再居中 + alpha = img.getchannel("A") + bbox = alpha.getbbox() + glyph = img.crop(bbox) if bbox else img + inner = size - 2 * border + avail = int(inner * 0.82) + glyph.thumbnail((avail, avail), Image.LANCZOS) + ox = (size - glyph.width) // 2 + oy = (size - glyph.height) // 2 + canvas.alpha_composite(glyph, (ox, oy)) + out = io.BytesIO() + canvas.save(out, format="PNG") + return out.getvalue() + + +async def _render_svg(svg_text: str, size: int) -> bytes: + """用 Chromium 的 canvas 把 SVG 光栅化为带透明通道的 PNG。 + + 用 toDataURL 导出而非截图,避免 omit_background 在部分环境把透明背景 + 拍成白色,从而保住透明 alpha。 + """ + from playwright.async_api import async_playwright + + data_uri = "data:image/svg+xml;base64," + base64.b64encode(svg_text.encode("utf-8")).decode() + script = ( + "() => new Promise((resolve) => {" + "const img = new Image();" + "img.onload = () => {" + "const canvas = document.createElement('canvas');" + f"canvas.width = {size}; canvas.height = {size};" + "const ctx = canvas.getContext('2d');" + f"ctx.clearRect(0,0,{size},{size});" + f"const scale = Math.min({size} / img.width, {size} / img.height);" + "const w = img.width * scale, h = img.height * scale;" + f"ctx.drawImage(img, ({size}-w)/2, ({size}-h)/2, w, h);" + "resolve(canvas.toDataURL('image/png'));" + "};" + "img.onerror = () => resolve('');" + f"img.src = '{data_uri}';" + "})" + ) + async with async_playwright() as p: + browser = await p.chromium.launch() + page = await browser.new_page() + await page.set_content("") + data_url = await page.evaluate(script) + await browser.close() + return base64.b64decode(data_url.split(",", 1)[1]) + + +async def svg_to_png(svg_text: str, framed: bool = False, frame_color: str | None = None, size: int = SCHEMA_SIZE) -> bytes: + """SVG -> PNG。framed=True 时叠加 HD2 风格边框到类型色。""" + if not svg_text.strip(): + raise ValueError("SVG 内容为空") + png = await _render_svg(svg_text, size) + if framed: + png = _apply_frame(png, size, frame_color or TYPE_COLORS["blue"]) + return png + + +def save_icon_png(png_bytes: bytes, name: str) -> str: + """写入 img/helldivers/.png,返回相对路径。""" + IMG_DIR.mkdir(parents=True, exist_ok=True) + filename = sanitize_filename(name) + ".png" + dest = IMG_DIR / filename + dest.write_bytes(png_bytes) + return f"img/helldivers/{filename}" \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/image_builder.py b/hexi/plugins/nonebot_plugin_helldivers_tools/image_builder.py new file mode 100644 index 0000000..f2a4bda --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/image_builder.py @@ -0,0 +1,45 @@ +import os +import random +from io import BytesIO +from datetime import datetime +from PIL import Image, ImageOps, ImageDraw, ImageFont + +basic_path = os.path.dirname(__file__) +save_path = os.path.join(basic_path, "temp") +img_path = os.path.join(basic_path, "img") +data_path = os.path.join(basic_path, "data") + + +def create_image(selected_equipment): + new_img = Image.new('RGBA', (800, 500), (0, 0, 0, 1000)) + logo_path = img_path + "/super earth.png" + logo = Image.open(logo_path) + new_img = image_paste(logo, new_img, (682, 20)) + draw = ImageDraw.Draw(new_img) + ch_text_font = ImageFont.truetype(data_path + '/font/msyh.ttc', 36) + pos_horizon = 20 + + for equipment in selected_equipment: + name = equipment['name'] + alias = random.choice(equipment['alias']) if equipment['alias'] else None + + path = basic_path + "/" + equipment['path'].replace("\\", "/") + icon = Image.open(path) + icon = icon.resize((100, 100)) + new_img = image_paste(icon, new_img, (20, pos_horizon)) + draw.text((140, pos_horizon + 5), '战备名称:', fill='white', font=ch_text_font) + draw.text((140, pos_horizon + 50), f'{name} - ({alias})', fill='white', font=ch_text_font) + pos_horizon += 120 + + b_io = BytesIO() + new_img = ImageOps.expand(new_img, border=10, fill="white") + new_img.save(b_io, format="PNG") + return b_io + + +def image_paste(paste_image, under_image, pos): + if paste_image.mode == 'RGBA': + under_image.paste(paste_image, pos, mask=paste_image.split()[3]) + else: + under_image.paste(paste_image, pos) + return under_image \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/TCS.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/TCS.svg new file mode 100644 index 0000000..afb366f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/TCS.svg @@ -0,0 +1 @@ + Terminid Control System + Terminid Control System +Terminid Control System +Terminid Control System + \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/Heavy_SEAF_Presence_Icon.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/Heavy_SEAF_Presence_Icon.svg new file mode 100644 index 0000000..c0f67fc --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/Heavy_SEAF_Presence_Icon.svg @@ -0,0 +1,5 @@ + + Traced by Dogo314 + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/Spore_Burst_Strain_Icon.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/Spore_Burst_Strain_Icon.svg new file mode 100644 index 0000000..736a1f3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/Spore_Burst_Strain_Icon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/Wrench.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/Wrench.svg new file mode 100644 index 0000000..192989b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/Wrench.svg @@ -0,0 +1,54 @@ + + + +image/svg+xml diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/fonts/Steelworks-Regular.Ds5vcyJ-.woff b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/fonts/Steelworks-Regular.Ds5vcyJ-.woff new file mode 100644 index 0000000..6aa6926 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/fonts/Steelworks-Regular.Ds5vcyJ-.woff differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/fonts/TTSquares-Black.s7Ta46_A.woff b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/fonts/TTSquares-Black.s7Ta46_A.woff new file mode 100644 index 0000000..064cfff Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/fonts/TTSquares-Black.s7Ta46_A.woff differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/fonts/TTSquares-Bold.Bgw268aV.woff b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/fonts/TTSquares-Bold.Bgw268aV.woff new file mode 100644 index 0000000..24d0a5d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/fonts/TTSquares-Bold.Bgw268aV.woff differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-defense.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-defense.png new file mode 100644 index 0000000..32ace01 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-defense.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-defense.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-defense.svg new file mode 100644 index 0000000..da77ada --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-defense.svg @@ -0,0 +1,5 @@ + + Traced by Dogo314 + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-high-priority.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-high-priority.png new file mode 100644 index 0000000..20f5438 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-high-priority.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-high-priority.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-high-priority.svg new file mode 100644 index 0000000..c1b7f82 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-high-priority.svg @@ -0,0 +1,12 @@ + + Traced by Dogo314 + + + + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-invasion.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-invasion.png new file mode 100644 index 0000000..cd45ae3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-invasion.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-invasion.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-invasion.svg new file mode 100644 index 0000000..1d0deea --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-invasion.svg @@ -0,0 +1,5 @@ + + Traced by Dogo314 + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-liberation.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-liberation.png new file mode 100644 index 0000000..e5a5fdf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-liberation.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-liberation.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-liberation.svg new file mode 100644 index 0000000..67fe0b7 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-liberation.svg @@ -0,0 +1,12 @@ + + Traced by Dogo314 + + + + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-recon.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-recon.png new file mode 100644 index 0000000..22b5880 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-recon.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-recon.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-recon.svg new file mode 100644 index 0000000..8b6227e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/campaign-recon.svg @@ -0,0 +1,12 @@ + + Traced by Dogo314 + + + + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-appropriators.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-appropriators.png new file mode 100644 index 0000000..592412b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-appropriators.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-appropriators.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-appropriators.svg new file mode 100644 index 0000000..5470629 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-appropriators.svg @@ -0,0 +1,5 @@ + + Traced by Dogo314 + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-cyborgs.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-cyborgs.png new file mode 100644 index 0000000..5cab7bb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-cyborgs.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-cyborgs.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-cyborgs.svg new file mode 100644 index 0000000..77ff76c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-cyborgs.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dragonroach.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dragonroach.png new file mode 100644 index 0000000..9781a5f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dragonroach.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dragonroach.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dragonroach.svg new file mode 100644 index 0000000..c37bce8 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dragonroach.svg @@ -0,0 +1 @@ +effect-dragonroach \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-blockade.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-blockade.png new file mode 100644 index 0000000..f6b1f6e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-blockade.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-blockade.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-blockade.svg new file mode 100644 index 0000000..d3cf257 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-blockade.svg @@ -0,0 +1,13 @@ + + Traced by Dogo314 + + + + + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-eagle.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-eagle.png new file mode 100644 index 0000000..4eaf697 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-eagle.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-eagle.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-eagle.svg new file mode 100644 index 0000000..d9b5bef --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-eagle.svg @@ -0,0 +1,15 @@ + + Traced by Dogo314 + + + + + + + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-heavy-ordnance.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-heavy-ordnance.png new file mode 100644 index 0000000..130d9b6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-heavy-ordnance.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-heavy-ordnance.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-heavy-ordnance.svg new file mode 100644 index 0000000..5ca5cca --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss-heavy-ordnance.svg @@ -0,0 +1,13 @@ + + Traced by Dogo314 + + + + + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss.png new file mode 100644 index 0000000..e72877a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss.svg new file mode 100644 index 0000000..3a06e0e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-dss.svg @@ -0,0 +1,4 @@ + + Traced by Dogo314 + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-factory-hub.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-factory-hub.png new file mode 100644 index 0000000..7c7482f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-factory-hub.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-factory-hub.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-factory-hub.svg new file mode 100644 index 0000000..473a609 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-factory-hub.svg @@ -0,0 +1 @@ +effect-factory-hub \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-generic.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-generic.png new file mode 100644 index 0000000..165ab88 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-generic.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-gloom.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-gloom.png new file mode 100644 index 0000000..9d44d54 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-gloom.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-gloom.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-gloom.svg new file mode 100644 index 0000000..c17f076 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-gloom.svg @@ -0,0 +1 @@ +effect-gloom \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-heavy-seaf.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-heavy-seaf.png new file mode 100644 index 0000000..07007af Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-heavy-seaf.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-heavy-seaf.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-heavy-seaf.svg new file mode 100644 index 0000000..e9e6c3b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-heavy-seaf.svg @@ -0,0 +1 @@ +Heavy SEAF Presence \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-hive-lord.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-hive-lord.png new file mode 100644 index 0000000..8df3de3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-hive-lord.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-hive-lord.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-hive-lord.svg new file mode 100644 index 0000000..9704b83 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-hive-lord.svg @@ -0,0 +1 @@ +effect-hive-lord \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-hive-world.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-hive-world.png new file mode 100644 index 0000000..bdb4aa2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-hive-world.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-hive-world.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-hive-world.svg new file mode 100644 index 0000000..c49ab0f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-hive-world.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-incineration-corps.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-incineration-corps.png new file mode 100644 index 0000000..592ffda Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-incineration-corps.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-incineration-corps.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-incineration-corps.svg new file mode 100644 index 0000000..7816280 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-incineration-corps.svg @@ -0,0 +1,5 @@ + + Traced by Dogo314 + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-invasion-fleet.webp b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-invasion-fleet.webp new file mode 100644 index 0000000..aef241c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-invasion-fleet.webp differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-jet-brigade-factory.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-jet-brigade-factory.png new file mode 100644 index 0000000..4f65068 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-jet-brigade-factory.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-jet-brigade-factory.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-jet-brigade-factory.svg new file mode 100644 index 0000000..b9beb7b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-jet-brigade-factory.svg @@ -0,0 +1 @@ +Jet Brigade Factory \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-jet-brigade.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-jet-brigade.png new file mode 100644 index 0000000..e1b1bd5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-jet-brigade.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-jet-brigade.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-jet-brigade.svg new file mode 100644 index 0000000..c460b46 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-jet-brigade.svg @@ -0,0 +1,5 @@ + + Traced by Dogo314 + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-mindless-masses.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-mindless-masses.png new file mode 100644 index 0000000..ab8aa51 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-mindless-masses.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-mindless-masses.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-mindless-masses.svg new file mode 100644 index 0000000..d535c22 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-mindless-masses.svg @@ -0,0 +1,5 @@ + + Traced by Dogo314 + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-mine.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-mine.png new file mode 100644 index 0000000..65b5693 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-mine.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-predator-strain.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-predator-strain.png new file mode 100644 index 0000000..2147c60 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-predator-strain.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-predator-strain.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-predator-strain.svg new file mode 100644 index 0000000..4dec863 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-predator-strain.svg @@ -0,0 +1,4 @@ + + Traced by Dogo314 + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-rupture-strain.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-rupture-strain.png new file mode 100644 index 0000000..d5f286e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-rupture-strain.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-rupture-strain.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-rupture-strain.svg new file mode 100644 index 0000000..c95a72f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-rupture-strain.svg @@ -0,0 +1,5 @@ + + Traced by Dogo314 + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-spore-burst-strain.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-spore-burst-strain.png new file mode 100644 index 0000000..360410d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-spore-burst-strain.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-spore-burst-strain.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-spore-burst-strain.svg new file mode 100644 index 0000000..9907dfd --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-spore-burst-strain.svg @@ -0,0 +1 @@ +Spore Burst Strain \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-tcs-plus.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-tcs-plus.png new file mode 100644 index 0000000..7800b29 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-tcs-plus.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-tcs-plus.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-tcs-plus.svg new file mode 100644 index 0000000..e1b1a93 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-tcs-plus.svg @@ -0,0 +1,5 @@ +Terminid Control System+ + + + + \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-vote-snatchers.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-vote-snatchers.png new file mode 100644 index 0000000..e98cbe5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-vote-snatchers.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-vote-snatchers.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-vote-snatchers.svg new file mode 100644 index 0000000..dab246e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/effect-vote-snatchers.svg @@ -0,0 +1,5 @@ + + Traced by Dogo314 + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-automaton.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-automaton.png new file mode 100644 index 0000000..2451a9b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-automaton.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-automaton.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-automaton.svg new file mode 100644 index 0000000..c6dced0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-automaton.svg @@ -0,0 +1 @@ + Automatons \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-illuminate.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-illuminate.png new file mode 100644 index 0000000..e3d7fbc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-illuminate.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-illuminate.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-illuminate.svg new file mode 100644 index 0000000..ba2d059 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-illuminate.svg @@ -0,0 +1 @@ + Illuminate \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-super-earth.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-super-earth.png new file mode 100644 index 0000000..81d0bc1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-super-earth.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-super-earth.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-super-earth.svg new file mode 100644 index 0000000..7464f3c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-super-earth.svg @@ -0,0 +1 @@ + Humans \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-terminid.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-terminid.png new file mode 100644 index 0000000..efd86eb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-terminid.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-terminid.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-terminid.svg new file mode 100644 index 0000000..f5a982d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/faction-terminid.svg @@ -0,0 +1 @@ + Terminids \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-acid-storms.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-acid-storms.png new file mode 100644 index 0000000..0e281a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-acid-storms.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-acid-storms.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-acid-storms.svg new file mode 100644 index 0000000..241cfbf --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-acid-storms.svg @@ -0,0 +1,8 @@ + + Traced by Dogo314 + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-blizzards.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-blizzards.png new file mode 100644 index 0000000..e4c2ebd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-blizzards.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-blizzards.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-blizzards.svg new file mode 100644 index 0000000..42a9e75 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-blizzards.svg @@ -0,0 +1,8 @@ + + Traced by Dogo314 + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-extreme-cold.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-extreme-cold.png new file mode 100644 index 0000000..646c580 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-extreme-cold.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-extreme-cold.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-extreme-cold.svg new file mode 100644 index 0000000..985ba1f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-extreme-cold.svg @@ -0,0 +1,8 @@ + + Traced by Dogo314 + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-fire-tornados.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-fire-tornados.png new file mode 100644 index 0000000..be58c68 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-fire-tornados.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-fire-tornados.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-fire-tornados.svg new file mode 100644 index 0000000..100933c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-fire-tornados.svg @@ -0,0 +1,8 @@ + + Traced by Dogo314 + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-intense-heat.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-intense-heat.png new file mode 100644 index 0000000..c85ae5f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-intense-heat.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-intense-heat.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-intense-heat.svg new file mode 100644 index 0000000..76c7914 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-intense-heat.svg @@ -0,0 +1,8 @@ + + Traced by Dogo314 + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-ion-storms.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-ion-storms.png new file mode 100644 index 0000000..12beaf6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-ion-storms.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-ion-storms.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-ion-storms.svg new file mode 100644 index 0000000..f0b9901 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-ion-storms.svg @@ -0,0 +1,8 @@ + + Traced by Dogo314 + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-meteor-storms.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-meteor-storms.png new file mode 100644 index 0000000..dba3a6c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-meteor-storms.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-meteor-storms.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-meteor-storms.svg new file mode 100644 index 0000000..8872a44 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-meteor-storms.svg @@ -0,0 +1,8 @@ + + Traced by Dogo314 + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-rainstorms.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-rainstorms.png new file mode 100644 index 0000000..b8cfb5f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-rainstorms.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-rainstorms.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-rainstorms.svg new file mode 100644 index 0000000..cbb50d1 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-rainstorms.svg @@ -0,0 +1,8 @@ + + Traced by Dogo314 + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-sandstorms.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-sandstorms.png new file mode 100644 index 0000000..98678dc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-sandstorms.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-sandstorms.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-sandstorms.svg new file mode 100644 index 0000000..a76a1cd --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-sandstorms.svg @@ -0,0 +1,8 @@ + + Traced by Dogo314 + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-thick-fog.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-thick-fog.png new file mode 100644 index 0000000..d7547d0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-thick-fog.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-thick-fog.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-thick-fog.svg new file mode 100644 index 0000000..06f21d4 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-thick-fog.svg @@ -0,0 +1,8 @@ + + Traced by Dogo314 + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-tremors.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-tremors.png new file mode 100644 index 0000000..571d75c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-tremors.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-tremors.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-tremors.svg new file mode 100644 index 0000000..e7b77b4 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-tremors.svg @@ -0,0 +1,8 @@ + + Traced by Dogo314 + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-volcanic-activity.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-volcanic-activity.png new file mode 100644 index 0000000..397ad00 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-volcanic-activity.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-volcanic-activity.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-volcanic-activity.svg new file mode 100644 index 0000000..d47ce58 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/hazard-volcanic-activity.svg @@ -0,0 +1,8 @@ + + Traced by Dogo314 + + + + + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-helldiver.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-helldiver.png new file mode 100644 index 0000000..a7b5e9f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-helldiver.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-helldiver.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-helldiver.svg new file mode 100644 index 0000000..117f99e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-helldiver.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-helldivers-2.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-helldivers-2.png new file mode 100644 index 0000000..8321293 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-helldivers-2.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-helldivers.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-helldivers.png new file mode 100644 index 0000000..bf4ae83 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-helldivers.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-major-order.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-major-order.png new file mode 100644 index 0000000..99492d1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-major-order.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-major-order.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-major-order.svg new file mode 100644 index 0000000..f141b60 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-major-order.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-news.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-news.png new file mode 100644 index 0000000..bc2da31 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-news.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-news.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-news.svg new file mode 100644 index 0000000..356d804 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/icons/misc-news.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/acamar-iv.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/acamar-iv.png new file mode 100644 index 0000000..ca53e9d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/acamar-iv.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/achernar-secundus.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/achernar-secundus.png new file mode 100644 index 0000000..29c2c66 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/achernar-secundus.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/achird-iii.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/achird-iii.png new file mode 100644 index 0000000..ec8a616 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/achird-iii.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/acrux-ix.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/acrux-ix.png new file mode 100644 index 0000000..4a849ca Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/acrux-ix.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/acrux.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/acrux.png new file mode 100644 index 0000000..c57b65f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/acrux.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/adhara.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/adhara.png new file mode 100644 index 0000000..6e59f91 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/adhara.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/aesir-pass.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/aesir-pass.png new file mode 100644 index 0000000..33de966 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/aesir-pass.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/afoyay-bay.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/afoyay-bay.png new file mode 100644 index 0000000..af2676f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/afoyay-bay.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/ain-5.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/ain-5.png new file mode 100644 index 0000000..1da06d5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/ain-5.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/alamak-vii.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/alamak-vii.png new file mode 100644 index 0000000..694755b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/alamak-vii.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/alaraph.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/alaraph.png new file mode 100644 index 0000000..8faffe9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/alaraph.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/angel-s-venture.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/angel-s-venture.png new file mode 100644 index 0000000..94039b1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/angel-s-venture.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/aurora-bay.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/aurora-bay.png new file mode 100644 index 0000000..192d52b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/aurora-bay.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/azterra.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/azterra.png new file mode 100644 index 0000000..284be3e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/azterra.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/basquine-viii.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/basquine-viii.png new file mode 100644 index 0000000..0066939 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/basquine-viii.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/blistica.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/blistica.png new file mode 100644 index 0000000..901400a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/blistica.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/bore-rock.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/bore-rock.png new file mode 100644 index 0000000..0e54370 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/bore-rock.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/borea.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/borea.png new file mode 100644 index 0000000..a6e110a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/borea.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/brilliance.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/brilliance.png new file mode 100644 index 0000000..2690437 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/brilliance.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/charbal-vii.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/charbal-vii.png new file mode 100644 index 0000000..52a120b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/charbal-vii.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/charon-prime.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/charon-prime.png new file mode 100644 index 0000000..25cade1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/charon-prime.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/choepessa-iv.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/choepessa-iv.png new file mode 100644 index 0000000..33ca706 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/choepessa-iv.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/choohe.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/choohe.png new file mode 100644 index 0000000..a051731 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/choohe.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/chort-bay.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/chort-bay.png new file mode 100644 index 0000000..b76a3e5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/chort-bay.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/cirrus.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/cirrus.png new file mode 100644 index 0000000..5387896 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/cirrus.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/claorell.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/claorell.png new file mode 100644 index 0000000..6d68e80 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/claorell.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/clasa.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/clasa.png new file mode 100644 index 0000000..0d8f66f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/clasa.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/crimsica.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/crimsica.png new file mode 100644 index 0000000..b3e063b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/crimsica.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/curia.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/curia.png new file mode 100644 index 0000000..e1676ff Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/curia.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/darius-ii.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/darius-ii.png new file mode 100644 index 0000000..c206128 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/darius-ii.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/demiurg.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/demiurg.png new file mode 100644 index 0000000..6f728ac Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/demiurg.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/duma-tyr.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/duma-tyr.png new file mode 100644 index 0000000..99a30c8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/duma-tyr.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/elysian-meadows.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/elysian-meadows.png new file mode 100644 index 0000000..1f1fa54 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/elysian-meadows.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/erata-prime.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/erata-prime.png new file mode 100644 index 0000000..67fe621 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/erata-prime.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/erson-sands.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/erson-sands.png new file mode 100644 index 0000000..071af22 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/erson-sands.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/esker.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/esker.png new file mode 100644 index 0000000..0ea9c46 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/esker.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/estanu.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/estanu.png new file mode 100644 index 0000000..42b8198 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/estanu.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/eukoria.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/eukoria.png new file mode 100644 index 0000000..6748c98 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/eukoria.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/fenrir-iii.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/fenrir-iii.png new file mode 100644 index 0000000..ffbc861 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/fenrir-iii.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/fori-prime.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/fori-prime.png new file mode 100644 index 0000000..f2e83e7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/fori-prime.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/fronteria.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/fronteria.png new file mode 100644 index 0000000..ca606f8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/fronteria.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gacrux.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gacrux.png new file mode 100644 index 0000000..a6e48d3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gacrux.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gaellivare.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gaellivare.png new file mode 100644 index 0000000..d9caf63 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gaellivare.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gar-haren.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gar-haren.png new file mode 100644 index 0000000..562e75c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gar-haren.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gatria.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gatria.png new file mode 100644 index 0000000..be4d3bb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gatria.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gemma.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gemma.png new file mode 100644 index 0000000..9a3a1c0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/gemma.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/genesis-prime.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/genesis-prime.png new file mode 100644 index 0000000..003deba Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/genesis-prime.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/grand-errant.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/grand-errant.png new file mode 100644 index 0000000..4e8baf9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/grand-errant.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/haldus.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/haldus.png new file mode 100644 index 0000000..b0ed380 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/haldus.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/heeth.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/heeth.png new file mode 100644 index 0000000..0696292 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/heeth.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/hellmire.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/hellmire.png new file mode 100644 index 0000000..a123ee1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/hellmire.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/herthon-secundus.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/herthon-secundus.png new file mode 100644 index 0000000..9885c6c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/herthon-secundus.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/hesoe-prime.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/hesoe-prime.png new file mode 100644 index 0000000..912b382 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/hesoe-prime.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/heze-bay.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/heze-bay.png new file mode 100644 index 0000000..15bdf47 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/heze-bay.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/hort.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/hort.png new file mode 100644 index 0000000..07c1328 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/hort.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/hydrobius.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/hydrobius.png new file mode 100644 index 0000000..f836394 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/hydrobius.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/ingmar.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/ingmar.png new file mode 100644 index 0000000..f72d7a9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/ingmar.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/iro.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/iro.png new file mode 100644 index 0000000..e36ad89 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/iro.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/irulta.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/irulta.png new file mode 100644 index 0000000..42e2e20 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/irulta.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/julheim.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/julheim.png new file mode 100644 index 0000000..b713042 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/julheim.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/karlia.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/karlia.png new file mode 100644 index 0000000..fd1bf34 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/karlia.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/keid.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/keid.png new file mode 100644 index 0000000..032c1a9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/keid.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/kerth-secundus.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/kerth-secundus.png new file mode 100644 index 0000000..2037706 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/kerth-secundus.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/lesath.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/lesath.png new file mode 100644 index 0000000..157b8be Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/lesath.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/luxuriant.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/luxuriant.png new file mode 100644 index 0000000..451beb4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/luxuriant.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/mantes.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/mantes.png new file mode 100644 index 0000000..1bf2473 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/mantes.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/marfark.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/marfark.png new file mode 100644 index 0000000..7296434 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/marfark.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/martale.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/martale.png new file mode 100644 index 0000000..846e0e1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/martale.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/matar-bay.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/matar-bay.png new file mode 100644 index 0000000..1418058 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/matar-bay.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/meissa.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/meissa.png new file mode 100644 index 0000000..312d710 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/meissa.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/menkent.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/menkent.png new file mode 100644 index 0000000..8f580e3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/menkent.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/merak.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/merak.png new file mode 100644 index 0000000..2c1bf75 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/merak.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/merga-iv.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/merga-iv.png new file mode 100644 index 0000000..d17789c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/merga-iv.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/mintoria.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/mintoria.png new file mode 100644 index 0000000..78a73ab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/mintoria.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/mog.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/mog.png new file mode 100644 index 0000000..708c991 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/mog.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/mort.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/mort.png new file mode 100644 index 0000000..93c5447 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/mort.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/myrium.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/myrium.png new file mode 100644 index 0000000..61e1926 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/myrium.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/new-stockholm.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/new-stockholm.png new file mode 100644 index 0000000..dfbdb8b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/new-stockholm.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/nivel-43.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/nivel-43.png new file mode 100644 index 0000000..9554085 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/nivel-43.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/oasis.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/oasis.png new file mode 100644 index 0000000..e84ef77 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/oasis.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/omicron.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/omicron.png new file mode 100644 index 0000000..d53db48 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/omicron.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/p-pli-ix.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/p-pli-ix.png new file mode 100644 index 0000000..1d01562 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/p-pli-ix.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/pandion-xxiv.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/pandion-xxiv.png new file mode 100644 index 0000000..f387228 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/pandion-xxiv.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/parsh.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/parsh.png new file mode 100644 index 0000000..6231e7b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/parsh.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/partion.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/partion.png new file mode 100644 index 0000000..ea3b101 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/partion.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/peacock.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/peacock.png new file mode 100644 index 0000000..f81f91a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/peacock.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/phact-bay.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/phact-bay.png new file mode 100644 index 0000000..4bff47f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/phact-bay.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/pherkad-secundus.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/pherkad-secundus.png new file mode 100644 index 0000000..af9452d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/pherkad-secundus.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/polaris-prime.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/polaris-prime.png new file mode 100644 index 0000000..ef02927 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/polaris-prime.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/rd-4.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/rd-4.png new file mode 100644 index 0000000..fc40457 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/rd-4.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/reaf.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/reaf.png new file mode 100644 index 0000000..b75cb1d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/reaf.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/regnus.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/regnus.png new file mode 100644 index 0000000..f0b0a10 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/regnus.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/rirga-bay.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/rirga-bay.png new file mode 100644 index 0000000..c24ca8f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/rirga-bay.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/rogue-5.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/rogue-5.png new file mode 100644 index 0000000..0dd652e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/rogue-5.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/sangis.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/sangis.png new file mode 100644 index 0000000..2379c5f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/sangis.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/shelt.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/shelt.png new file mode 100644 index 0000000..3883eb3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/shelt.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/shete.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/shete.png new file mode 100644 index 0000000..a4cfe9d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/shete.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/siemnot.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/siemnot.png new file mode 100644 index 0000000..fcad506 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/siemnot.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/socorro-iii.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/socorro-iii.png new file mode 100644 index 0000000..171d80c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/socorro-iii.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/tarsh.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/tarsh.png new file mode 100644 index 0000000..c1abfc4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/tarsh.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/terrek.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/terrek.png new file mode 100644 index 0000000..cf67199 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/terrek.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/trandor.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/trandor.png new file mode 100644 index 0000000..8860c6d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/trandor.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/troost.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/troost.png new file mode 100644 index 0000000..291ab38 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/troost.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/turing.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/turing.png new file mode 100644 index 0000000..e36d716 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/turing.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/ursica-xi.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/ursica-xi.png new file mode 100644 index 0000000..8023f94 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/ursica-xi.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/ustotu.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/ustotu.png new file mode 100644 index 0000000..64271ee Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/ustotu.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/valmox.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/valmox.png new file mode 100644 index 0000000..2d16e22 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/valmox.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/vandalon-iv.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/vandalon-iv.png new file mode 100644 index 0000000..f536d92 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/vandalon-iv.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/varylia-5.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/varylia-5.png new file mode 100644 index 0000000..87e2590 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/varylia-5.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/vega-bay.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/vega-bay.png new file mode 100644 index 0000000..93fd34a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/vega-bay.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/veld.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/veld.png new file mode 100644 index 0000000..db71d04 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/veld.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/vernen-wells.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/vernen-wells.png new file mode 100644 index 0000000..55b2dcb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/vernen-wells.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/vog-sojoth.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/vog-sojoth.png new file mode 100644 index 0000000..2d3831c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/vog-sojoth.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/wasat.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/wasat.png new file mode 100644 index 0000000..0da4beb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/wasat.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/wezen.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/wezen.png new file mode 100644 index 0000000..e4d4e9a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/wezen.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/x-45.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/x-45.png new file mode 100644 index 0000000..70c8aa8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/x-45.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/yed-prior.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/yed-prior.png new file mode 100644 index 0000000..a7c746e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/yed-prior.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zea-rugosia.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zea-rugosia.png new file mode 100644 index 0000000..e26680c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zea-rugosia.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zefia.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zefia.png new file mode 100644 index 0000000..7cf0944 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zefia.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zosma.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zosma.png new file mode 100644 index 0000000..febec41 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zosma.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zygos.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zygos.png new file mode 100644 index 0000000..815c54a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zygos.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zzaniah-prime.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zzaniah-prime.png new file mode 100644 index 0000000..526c0ad Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/planets/zzaniah-prime.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/描述性文本.txt b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/描述性文本.txt new file mode 100644 index 0000000..ecf2f11 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/assets/描述性文本.txt @@ -0,0 +1,153 @@ +武器实验/军火库扩充 +有时,超级地球最高指挥部会向地狱潜兵提供某些战略战术,作为额外的任务标准战术。这些强化纯粹是附加效果,不会占用地狱潜兵战略战术配置栏位。 + +民主空间站 +民主空间站除了解放运动外,还可以提供由地狱潜兵资助的“战术行动”,从而增强对任何被环绕行星的“作战支持”。 + +DSS Eagle Icon.svg +飞鹰风暴 +Eaglestorm.png +在任务期间定期部署鹰式空中打击。减缓敌军在防御战役中的推进速度。 +DSS 人员从巨大的三层集结湾部署 24 小时轮换的鹰式战斗机机队,为地球上所有地狱俯冲者行动提供近距离空中支援,并在短时间内阻止敌人的进攻。 +成本: 普通样本6,480,000 +期间: 24小时 +冷却: 4天 +飞鹰风暴 +DSS在任务期间部署飞鹰机枪扫射。 +飞鹰风暴 +防御战役中敌军推进速度减慢。 +当地狱俯冲者位于主要目标区域或可选/次要目标区域内时,“飞鹰风暴”不会激活/开始。但这并不意味着目标区域内的敌方单位不会受到“飞鹰风暴”的攻击。 +即使地狱潜兵踏入目标区域,雄鹰风暴仍将持续到结束。 +当地狱潜兵位于目标区域内时,冷却计时器不会停止。一旦目标区域内没有地狱潜兵,鹰击风暴将立即发动。 +目标范围为以“地狱俯冲者”为掩体的半径200米。如果没有非东南亚空军目标,则“鹰”式扫射攻击将随机投放至射程边缘附近的区域。 +DSS 的行动页面错误地表明它会部署鹰式空袭,但受鹰式风暴影响的星球上的“效果”部分正确地表明 DSS 会部署鹰式扫射。 +受鹰风暴影响的防御战役的计时器将暂停,直到鹰风暴不再影响该星球为止。 +DSS轨道封锁图标.svg +轨道封锁 +封锁.png +防御行动无法从该星球发起。 “地狱舱空间优化推进器”在所有任务中自动激活。 +DSS启动零重力反舰导弹系统,目标是所有试图脱离行星大气层的大型敌方飞船。此外,还将多余的人力调往超级驱逐舰后勤支援部门。 +成本: 请购单4,320,000,000 +期间: 24小时 +冷却: 2天 +轨道封锁 +地狱舱空间优化推进器在所有任务中自动激活。 +轨道封锁 +防御行动不可能起源于这个星球。 +轨道封锁无法结束一场已经开始的防御战役。 +DSS重型军械分发图标.svg +重型军械分发 +轰炸.png +在任务中可以使用轨道380毫米高爆弹幕战术。加快解放战役的进程。 +DSS后勤舰队为所有环绕地球运行的超级驱逐舰提供剩余的380毫米炮弹。此外,它还为东南亚空军的行动提供军械支援,加速解放进程。 +成本: 稀有样本4,320,000 +期间: 24小时 +冷却: 5天 +武器实验 +所有地狱俯冲者都可以使用轨道380毫米高爆弹幕战术。 +尽管其描述表明它可以加快解放战役的进程,但它也可以加快地狱潜兵在防御和入侵战役中的行动。 +尽管在“效果”部分被标记为“武器实验”,但实际上这是一次额外的380毫米轨道高爆弹幕呼叫。使用时,“地狱俯冲者”会优先消耗其选择的380毫米炮弹,而不是DSS的。 +这门额外的 380 毫米弹幕炮只有在任务中首次使用后才会应用舰船升级效果;冷却时间缩短效果在使用后立即生效。 +自2025 年 1 月 16 日起,已取代行星轰炸。 + + +DSS 图标.svg +效果 +对DSS悬停的星球施加的效果。 +运营支持 +DSS 在该星球附近的存在对解放战役的进展起到了一定的推动作用。 +外骨骼储备 +该行星附近的深空卫星 (DSS) 可使所有外骨骼策略的冷却时间减少 35%。 +尽管其描述表明它可以加快解放战役的进程,但它也可以加快地狱潜兵在防御和入侵战役中的行动。 +外骨骼冷却时间缩短效果是在A2-4-1 大指令完成后添加的。 +环境条件 +环境条件是指在任务过程中所经历的影响行星环境的地球物理事件。 + +酸雨环境状况图标.svg 酸雨——腐蚀性酸雨敌我双方单位的护甲效能。 +暴雪环境状况图标.svg 暴风雪——强烈的暴风雪敌我双方单位的机动性,并适度降低其能见度。 +极寒环境条件图标.svg 极寒天气——冰冻温度会降低射速并延缓武器的热量积聚。 +火龙卷风环境状况图标.svg 火龙卷风——地球遭受致命火龙卷风的肆虐。 +高温环境条件图标.svg 高温——高温天气会增加体力消耗,并加快武器的散热速度。 +离子风暴环境状况图标.svg 离子风暴——离子风暴会间歇性地使战略失效。 +流星风暴环境状况图标.svg 流星风暴——流星撞击地表,造成巨大破坏。 +暴雨环境状况图标.svg 暴雨——倾盆大雨会降低能见度。 +沙尘暴环境状况图标.svg 沙尘暴——浓密的沙尘暴敌我双方部队的机动性,并大大降低其能见度。 +浓雾环境状况图标.svg 浓雾——浓雾会略微降低敌我双方的能见度。 +震颤环境状况图标.svg 震动——频繁的地震会使玩家和敌人同时陷入眩晕。 +火山活动环境状况图标.svg 火山活动——火山会将燃烧的岩石抛射到地球各处。 +通用效果图标.png 浓重的幽暗笼罩:这颗星球完全被幽暗笼罩,后勤支援严重受阻。撤离时间增加40秒,雄鹰战机重新装弹时间增加30%,拾取的弹药减少50%。 +中度阴霾笼罩:阴霾完全笼罩了这颗星球,阻碍了各种后勤行动。撤离时间增加30秒,雄鹰战机重新装弹时间增加20%。 +轻度昏暗覆盖:昏暗粒子会干扰鹈鹕号的着陆,使撤离时间增加20 秒。 +幽暗源:这颗星球持续产生浓厚的幽暗大气,使得后勤支援极其困难。增援总数减少 20%,雄鹰战机重新装弹时间增加30%,拾取的弹药减少50%。 +作战效果 +有时,在某些事件或重大指令期间,部分(如果不是全部)星球可能会获得额外的效果/修正,该效果/修正适用于所有难度。 + +轨道波动:所有轨道策略的冷却时间增加。(请勿与同名的行动修正器混淆,此效果仅影响轨道策略。) +医疗物资短缺:每个地狱潜兵部署的兴奋剂数量减少 1。 +飞行员短缺:撤离需要额外 30 秒。 +鹰眼重装速度变慢: 鹰眼重装速度降低25%。 +运算修饰符 +作战修正器是地狱潜兵在战场上必须克服的额外障碍。困难模式下会出现一个修正器,不可能模式下会增加到两个。正在进行防御战役的星球上不会出现作战修正器。困难难度图标.svg 不可能的难度图标.svg + +一般的 +复杂策略规划——策略调用时间增加了50%。 +轨道波动——策略冷却时间增加25%。 +情报不足——目标位置被隐藏了。 +平民与东南亚武装部队在场-东南亚武装部队士兵小队和平民均在战场上。(事件修正仅在都市生物群落中存在) +阵营专属 + 终结者部落 + +大气孢子——地图被虫孢子遮蔽。 +游荡尖啸者——飞行尖啸者群在战场上穿梭。 + 自动机军团 + +武装直升机巡逻——飞行武装直升机在战场上巡逻。 + 光明会 + +利维坦封锁——飞行利维坦战舰在战场上巡逻。 +已移除 +AA防御——战略槽位减少1个。 +大气干扰——轨道策略散射增加。 +电子对抗措施——战略代码被扰乱。 +作战部队 +有些星球或城市会有影响单位生成类型的修正值,无论是友军单位还是敌军单位,这些修正值要么会增加特定单位的出现频率,要么用独特的变种单位替换某些单位,要么拥有完全独特的单位。 + + 终结者部落 + +子派系: +捕食者变种-猎手和潜行者将出现独特的狡猾变种。 +破裂菌株-战士、喷射者和冲锋者的独特掘地变种将会出现。 +孢子爆发菌株-拾荒者、猎人和战士将出现独特的爆炸变种。 +龙蟑螂——胆汁泰坦将被一种独特的飞行敌人——龙蟑螂——所取代。 +蜂巢领主——体型庞大的蠕虫状蜂巢领主将会出现。(需要完成自杀任务或更高难度。)自杀难度图标.svg + 自动机军团 + +子派系: +喷气旅——独特的突击突袭者单位将与配备喷气背包的士兵、机枪突袭者、政委、毁灭者、绿巨人灼烧者和绿巨人重击者一同出现。 +焚化军团——独特的烈焰毁灭者和绿巨人火焰轰炸机单位将与持火变种的士兵、火箭袭击者和重型毁灭者一同出现。 +赛博格——独特的赛博格煽动者、激进分子和Vox引擎单位将会出现。 +敌方部队: +绿巨人涌动 -绿巨人单位的生成频率将增加。 +重型装甲部队涌现——坦克和巨型机甲的生成频率将增加。 +毁灭者涌动 -毁灭者单位的生成频率将增加。 + 光明会 + +子派系: +侵占者——独特的入侵者、验证者和守门人单位将会出现。 +选票窃取者——独特的恶棍和粉碎者单位将会出现 +敌方师团: +无脑群众——无投票权和血肉暴民单位的生成频率将增加。 +入侵舰队-无投票者、监督者、新月监督者、高阶监督者、血肉暴徒、观察者、收割者和黄貂鱼单位将以更高的频率生成。 + 超级地球联邦 + +分配: +东南亚空军重兵部署——东南亚空军士兵将乘坐鹈鹕运输机部署到任务区域。 +其他影响 +护甲被动技能 +护甲被动技能是玩家专属的独特能力或强化效果,与相应的护甲绑定。根据技能的不同,会影响不同的属性,从而改变地狱潜兵在任务中的作战方式。 + +助推器 +每名地狱潜兵在部署前都可以选择装备增益道具,为整个小队提供增益效果。根据增益道具的不同,它可以改变地狱潜兵的属性、某些装备或任务机制。 + +身体状况 +身体状况指的是地狱潜兵在战场上可能遭受的不利影响。这些状况的严重程度不一,从轻微的减益效果到若不及时治疗则可能致命。根据状况的不同,它可能是由自身造成的、环境因素导致的,或是由敌人的攻击引起的。 \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/board.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/board.png new file mode 100644 index 0000000..696a08f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/board.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/board2.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/board2.png new file mode 100644 index 0000000..41e7a89 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/board2.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AC-8 机炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AC-8 机炮.png new file mode 100644 index 0000000..5f93c52 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AC-8 机炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/APW-1 反器材步枪.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/APW-1 反器材步枪.png new file mode 100644 index 0000000..e7b796f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/APW-1 反器材步枪.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/ARC-3 电弧发射器.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/ARC-3 电弧发射器.png new file mode 100644 index 0000000..42067de Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/ARC-3 电弧发射器.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX-LAS-5 漫游车.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX-LAS-5 漫游车.png new file mode 100644 index 0000000..2e4fcef Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX-LAS-5 漫游车.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX·AR-23 护卫犬.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX·AR-23 护卫犬.png new file mode 100644 index 0000000..bb5dbae Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX·AR-23 护卫犬.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX·ARC-3 K-9.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX·ARC-3 K-9.png new file mode 100644 index 0000000..8c9e2ff Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX·ARC-3 K-9.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX·FLAM-75 热狗.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX·FLAM-75 热狗.png new file mode 100644 index 0000000..c45c106 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX·FLAM-75 热狗.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX·TX-13 腐息.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX·TX-13 腐息.png new file mode 100644 index 0000000..fbef0e4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/AX·TX-13 腐息.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·AC-8 自动哨戒炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·AC-8 自动哨戒炮.png new file mode 100644 index 0000000..71e581a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·AC-8 自动哨戒炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·ARC-3 特斯拉塔.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·ARC-3 特斯拉塔.png new file mode 100644 index 0000000..1a5f347 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·ARC-3 特斯拉塔.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·FLAM-40 火焰喷射哨戒炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·FLAM-40 火焰喷射哨戒炮.png new file mode 100644 index 0000000..d41a83e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·FLAM-40 火焰喷射哨戒炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·G-16 加特林哨戒炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·G-16 加特林哨戒炮.png new file mode 100644 index 0000000..65f6466 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·G-16 加特林哨戒炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·GM-17 瓦斯迫击哨戒炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·GM-17 瓦斯迫击哨戒炮.png new file mode 100644 index 0000000..d1461f4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·GM-17 瓦斯迫击哨戒炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·LAS-98 激光哨戒炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·LAS-98 激光哨戒炮.png new file mode 100644 index 0000000..c86b7ba Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·LAS-98 激光哨戒炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·M-12 迫击哨戒炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·M-12 迫击哨戒炮.png new file mode 100644 index 0000000..128d500 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·M-12 迫击哨戒炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·M-23 电磁冲击波迫击哨戒炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·M-23 电磁冲击波迫击哨戒炮.png new file mode 100644 index 0000000..6a3cbf1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·M-23 电磁冲击波迫击哨戒炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·MG-43 哨戒机枪.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·MG-43 哨戒机枪.png new file mode 100644 index 0000000..b725fbf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·MG-43 哨戒机枪.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·MLS-X 火箭哨戒炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·MLS-X 火箭哨戒炮.png new file mode 100644 index 0000000..578cc4f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/A·MLS-X 火箭哨戒炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/B-1 补给背包.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/B-1 补给背包.png new file mode 100644 index 0000000..6527b18 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/B-1 补给背包.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/B-100 便携式地狱火炸弹.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/B-100 便携式地狱火炸弹.png new file mode 100644 index 0000000..2f3eb7c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/B-100 便携式地狱火炸弹.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/B·FLAM-80 焚燃者.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/B·FLAM-80 焚燃者.png new file mode 100644 index 0000000..d9f29eb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/B·FLAM-80 焚燃者.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/B·MD C4背包.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/B·MD C4背包.png new file mode 100644 index 0000000..2564fc5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/B·MD C4背包.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/CQC-1 唯一真旗.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/CQC-1 唯一真旗.png new file mode 100644 index 0000000..fac17a1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/CQC-1 唯一真旗.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/CQC-20 破门锤.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/CQC-20 破门锤.png new file mode 100644 index 0000000..89c0a58 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/CQC-20 破门锤.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/CQC-9 除叶工具.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/CQC-9 除叶工具.png new file mode 100644 index 0000000..a3d92cc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/CQC-9 除叶工具.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EAT-17 消耗性反坦克武器.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EAT-17 消耗性反坦克武器.png new file mode 100644 index 0000000..b96e577 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EAT-17 消耗性反坦克武器.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EAT-411 荡平者.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EAT-411 荡平者.png new file mode 100644 index 0000000..2e86fa3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EAT-411 荡平者.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EAT-700 消耗性凝固汽油弹.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EAT-700 消耗性凝固汽油弹.png new file mode 100644 index 0000000..bdd3206 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EAT-700 消耗性凝固汽油弹.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EXO-45 爱国者外骨骼机甲.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EXO-45 爱国者外骨骼机甲.png new file mode 100644 index 0000000..653215e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EXO-45 爱国者外骨骼机甲.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EXO-49 解放者外骨骼机甲.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EXO-49 解放者外骨骼机甲.png new file mode 100644 index 0000000..6331e60 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EXO-49 解放者外骨骼机甲.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EXO-51 伐木者.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EXO-51 伐木者.png new file mode 100644 index 0000000..e0fc2da Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EXO-51 伐木者.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EXO-55 突破.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EXO-55 突破.png new file mode 100644 index 0000000..5f8e08c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/EXO-55 突破.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/E·AT-12 反坦克炮台.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/E·AT-12 反坦克炮台.png new file mode 100644 index 0000000..bdd194c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/E·AT-12 反坦克炮台.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/E·GL-21 掷弹兵防卫墙.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/E·GL-21 掷弹兵防卫墙.png new file mode 100644 index 0000000..4f35287 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/E·GL-21 掷弹兵防卫墙.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/E·MG-101 重机枪部署支架.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/E·MG-101 重机枪部署支架.png new file mode 100644 index 0000000..45b7658 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/E·MG-101 重机枪部署支架.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/FAF-14 飞矛.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/FAF-14 飞矛.png new file mode 100644 index 0000000..ef927c2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/FAF-14 飞矛.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/FLAM-40 火焰喷射器.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/FLAM-40 火焰喷射器.png new file mode 100644 index 0000000..8c38258 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/FLAM-40 火焰喷射器.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/FX-12 防护罩生成中继器.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/FX-12 防护罩生成中继器.png new file mode 100644 index 0000000..0098e25 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/FX-12 防护罩生成中继器.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/GL-21 榴弹发射器.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/GL-21 榴弹发射器.png new file mode 100644 index 0000000..f8db675 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/GL-21 榴弹发射器.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/GL-28 弹链式榴弹发射器.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/GL-28 弹链式榴弹发射器.png new file mode 100644 index 0000000..51e7e4f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/GL-28 弹链式榴弹发射器.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/GL-52 缓和使者.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/GL-52 缓和使者.png new file mode 100644 index 0000000..109e340 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/GL-52 缓和使者.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/GR-8 无后坐力炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/GR-8 无后坐力炮.png new file mode 100644 index 0000000..b7821a9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/GR-8 无后坐力炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LAS-98 激光大炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LAS-98 激光大炮.png new file mode 100644 index 0000000..36d05d0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LAS-98 激光大炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LAS-99 类星体加农炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LAS-99 类星体加农炮.png new file mode 100644 index 0000000..3d718f6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LAS-99 类星体加农炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LIFT-182 传送背包.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LIFT-182 传送背包.png new file mode 100644 index 0000000..976d991 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LIFT-182 传送背包.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LIFT-850 喷射背包.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LIFT-850 喷射背包.png new file mode 100644 index 0000000..fc9c4fb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LIFT-850 喷射背包.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LIFT-860 悬浮背包.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LIFT-860 悬浮背包.png new file mode 100644 index 0000000..9478e68 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/LIFT-860 悬浮背包.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/M-1000 重装机枪.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/M-1000 重装机枪.png new file mode 100644 index 0000000..a316e90 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/M-1000 重装机枪.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/M-102 快速侦察载具.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/M-102 快速侦察载具.png new file mode 100644 index 0000000..d13c74c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/M-102 快速侦察载具.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/M-105 盟友.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/M-105 盟友.png new file mode 100644 index 0000000..f5c60ef Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/M-105 盟友.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MD-17 反坦克地雷.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MD-17 反坦克地雷.png new file mode 100644 index 0000000..d6fb7f0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MD-17 反坦克地雷.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MD-6 反步兵雷区.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MD-6 反步兵雷区.png new file mode 100644 index 0000000..5865863 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MD-6 反步兵雷区.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MD-8 毒气地雷.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MD-8 毒气地雷.png new file mode 100644 index 0000000..1700d85 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MD-8 毒气地雷.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MD-I4 燃烧地雷.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MD-I4 燃烧地雷.png new file mode 100644 index 0000000..650e7c0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MD-I4 燃烧地雷.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MG-206 重机枪.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MG-206 重机枪.png new file mode 100644 index 0000000..1df6ac0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MG-206 重机枪.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MG-43 机枪.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MG-43 机枪.png new file mode 100644 index 0000000..151f469 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MG-43 机枪.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MGX-42 子弹风暴.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MGX-42 子弹风暴.png new file mode 100644 index 0000000..b5f3caf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MGX-42 子弹风暴.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MLS-4X 突击兵.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MLS-4X 突击兵.png new file mode 100644 index 0000000..9f8f02f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MLS-4X 突击兵.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MS-11 单兵导弹发射井.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MS-11 单兵导弹发射井.png new file mode 100644 index 0000000..c1f95b3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/MS-11 单兵导弹发射井.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/PLAS-45 纪元.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/PLAS-45 纪元.png new file mode 100644 index 0000000..6ce3012 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/PLAS-45 纪元.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/RL-77 空爆火箭弹发射器.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/RL-77 空爆火箭弹发射器.png new file mode 100644 index 0000000..0052713 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/RL-77 空爆火箭弹发射器.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/RS-422 磁轨炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/RS-422 磁轨炮.png new file mode 100644 index 0000000..c993078 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/RS-422 磁轨炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/S-11 矛枪.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/S-11 矛枪.png new file mode 100644 index 0000000..db41a94 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/S-11 矛枪.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/SH-20 防弹护盾背包.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/SH-20 防弹护盾背包.png new file mode 100644 index 0000000..3188953 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/SH-20 防弹护盾背包.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/SH-32 防护罩生成包.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/SH-32 防护罩生成包.png new file mode 100644 index 0000000..36a3acd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/SH-32 防护罩生成包.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/SH-51 定向护盾.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/SH-51 定向护盾.png new file mode 100644 index 0000000..bda54df Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/SH-51 定向护盾.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/StA-X3 W.A.S.P.发射器.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/StA-X3 W.A.S.P.发射器.png new file mode 100644 index 0000000..18dd6a3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/StA-X3 W.A.S.P.发射器.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/TD-220 堡垒MK XVI.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/TD-220 堡垒MK XVI.png new file mode 100644 index 0000000..88d35e8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/TD-220 堡垒MK XVI.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/TX-41 灭菌器.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/TX-41 灭菌器.png new file mode 100644 index 0000000..14e2ac5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/TX-41 灭菌器.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道120MM高爆弹火力网.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道120MM高爆弹火力网.png new file mode 100644 index 0000000..5768e37 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道120MM高爆弹火力网.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道380MM高爆弹火力网.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道380MM高爆弹火力网.png new file mode 100644 index 0000000..428bc46 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道380MM高爆弹火力网.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道凝固汽油弹火力网.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道凝固汽油弹火力网.png new file mode 100644 index 0000000..13c11db Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道凝固汽油弹火力网.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道加特林火力网.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道加特林火力网.png new file mode 100644 index 0000000..602bc69 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道加特林火力网.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道厌恶攻击.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道厌恶攻击.png new file mode 100644 index 0000000..1b913c6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道厌恶攻击.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道毒气攻击.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道毒气攻击.png new file mode 100644 index 0000000..f7494aa Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道毒气攻击.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道游走火力网.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道游走火力网.png new file mode 100644 index 0000000..4ed7abd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道游走火力网.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道激光炮.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道激光炮.png new file mode 100644 index 0000000..3e94ee7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道激光炮.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道炮攻击.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道炮攻击.png new file mode 100644 index 0000000..82f2bcf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道炮攻击.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道烟雾攻击.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道烟雾攻击.png new file mode 100644 index 0000000..e887dc0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道烟雾攻击.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道电磁冲击波攻击.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道电磁冲击波攻击.png new file mode 100644 index 0000000..4ae55e6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道电磁冲击波攻击.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道空爆攻击.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道空爆攻击.png new file mode 100644 index 0000000..0d02fcb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道空爆攻击.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道精准攻击.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道精准攻击.png new file mode 100644 index 0000000..ad39a7f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/轨道精准攻击.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰110MM火箭巢.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰110MM火箭巢.png new file mode 100644 index 0000000..4ffd1f3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰110MM火箭巢.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰500KG炸弹.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰500KG炸弹.png new file mode 100644 index 0000000..b9f4b2f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰500KG炸弹.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰凝固汽油弹空袭.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰凝固汽油弹空袭.png new file mode 100644 index 0000000..c34c661 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰凝固汽油弹空袭.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰机枪扫射.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰机枪扫射.png new file mode 100644 index 0000000..f462d6b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰机枪扫射.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰烟雾攻击.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰烟雾攻击.png new file mode 100644 index 0000000..d8a4b25 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰烟雾攻击.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰空袭.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰空袭.png new file mode 100644 index 0000000..dcdbaa7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰空袭.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰集束炸弹.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰集束炸弹.png new file mode 100644 index 0000000..b3a6b0e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/helldivers/飞鹰集束炸弹.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/README.txt b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/README.txt new file mode 100644 index 0000000..d0b66c1 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/README.txt @@ -0,0 +1,45 @@ +绝地潜兵战况卡片 · 图标 PNG 包 +================================ + +由 hd2_icon_src 的 SVG 素材转换而来,供 + hexi\plugins\nonebot_plugin_helldivers_tools\img\assets\icons\ +使用(机器人渲染战况卡片时用 PNG 代替 SVG)。 + +转换规格 +-------- +- 尺寸:128×128,透明背景 +- 主体:约占画布 80%(≈102px),居中 +- 颜色:**保留源 SVG 原有颜色**,不做改动 + - faction/ 按阵营自带上色(超级地球蓝 / 终结族橙 / 机器人红 / 光能族紫) + - hazard/ 保留原样的「白色圆底徽章 + 黑色字形」 + - effect/ 源文件是什么色就保留什么色(白色字形保持白,子派系彩色保持彩色) + - campaign/、effect-dss*、misc/ 源自白色保持白 + +命名 +---- +与对应 SVG 同名(如 effect-factory-hub.png、faction-terminid.png), +机器人 `_icon_any()` / `EFFECT_ICONS` 查键名不变。 + +统一尺寸说明 +------------ +所有图标都按「最长边≈102px、水平垂直居中」归一化, +避免原始 SVG 尺寸/留白不一导致卡片上大小参差。 + +目录 +---- +faction/ 阵营图标 4 个 +campaign/ 战役类型图标 5 个 +effect/ 星球效果图标 21 个 + effect-generic.png(原样) + effect-invasion-fleet.webp(原样) +hazard/ 环境危害图标 12 个 +misc/ 杂项 3 个 + misc-helldivers.png / misc-helldivers-2.png(原样) + +说明 +---- +- effect-invasion-fleet.webp、effect-generic.png、misc-helldivers*.png + 为源素材中原本就是位图/非 SVG 的文件,未改动,按原名保留。 +- badge_sources/ 原始官方徽章(含彩色底)仅作参考,未包含在本包内。 + +使用注意 +-------- +若 icons 目录里同名 .svg 与 .png 同时存在,当前代码优先 SVG。 +想用本包 PNG 时,请删除同名 .svg(或改代码优先 PNG)。 diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-defense.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-defense.png new file mode 100644 index 0000000..32ace01 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-defense.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-high-priority.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-high-priority.png new file mode 100644 index 0000000..20f5438 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-high-priority.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-invasion.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-invasion.png new file mode 100644 index 0000000..cd45ae3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-invasion.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-liberation.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-liberation.png new file mode 100644 index 0000000..e5a5fdf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-liberation.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-recon.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-recon.png new file mode 100644 index 0000000..22b5880 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/campaign/campaign-recon.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-appropriators.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-appropriators.png new file mode 100644 index 0000000..592412b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-appropriators.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-cyborgs.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-cyborgs.png new file mode 100644 index 0000000..5cab7bb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-cyborgs.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dragonroach.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dragonroach.png new file mode 100644 index 0000000..9781a5f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dragonroach.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dss-blockade.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dss-blockade.png new file mode 100644 index 0000000..f6b1f6e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dss-blockade.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dss-eagle.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dss-eagle.png new file mode 100644 index 0000000..4eaf697 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dss-eagle.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dss-heavy-ordnance.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dss-heavy-ordnance.png new file mode 100644 index 0000000..130d9b6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dss-heavy-ordnance.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dss.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dss.png new file mode 100644 index 0000000..e72877a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-dss.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-factory-hub.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-factory-hub.png new file mode 100644 index 0000000..7c7482f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-factory-hub.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-generic.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-generic.png new file mode 100644 index 0000000..165ab88 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-generic.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-gloom.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-gloom.png new file mode 100644 index 0000000..9d44d54 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-gloom.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-heavy-seaf.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-heavy-seaf.png new file mode 100644 index 0000000..07007af Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-heavy-seaf.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-hive-lord.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-hive-lord.png new file mode 100644 index 0000000..8df3de3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-hive-lord.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-hive-world.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-hive-world.png new file mode 100644 index 0000000..bdb4aa2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-hive-world.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-incineration-corps.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-incineration-corps.png new file mode 100644 index 0000000..592ffda Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-incineration-corps.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-invasion-fleet.webp b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-invasion-fleet.webp new file mode 100644 index 0000000..aef241c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-invasion-fleet.webp differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-jet-brigade-factory.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-jet-brigade-factory.png new file mode 100644 index 0000000..4f65068 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-jet-brigade-factory.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-jet-brigade.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-jet-brigade.png new file mode 100644 index 0000000..e1b1bd5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-jet-brigade.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-mindless-masses.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-mindless-masses.png new file mode 100644 index 0000000..ab8aa51 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-mindless-masses.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-predator-strain.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-predator-strain.png new file mode 100644 index 0000000..2147c60 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-predator-strain.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-rupture-strain.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-rupture-strain.png new file mode 100644 index 0000000..d5f286e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-rupture-strain.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-spore-burst-strain.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-spore-burst-strain.png new file mode 100644 index 0000000..360410d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-spore-burst-strain.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-tcs-plus.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-tcs-plus.png new file mode 100644 index 0000000..7800b29 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-tcs-plus.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-vote-snatchers.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-vote-snatchers.png new file mode 100644 index 0000000..e98cbe5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/effect/effect-vote-snatchers.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/faction/faction-automaton.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/faction/faction-automaton.png new file mode 100644 index 0000000..2451a9b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/faction/faction-automaton.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/faction/faction-illuminate.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/faction/faction-illuminate.png new file mode 100644 index 0000000..e3d7fbc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/faction/faction-illuminate.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/faction/faction-super-earth.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/faction/faction-super-earth.png new file mode 100644 index 0000000..81d0bc1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/faction/faction-super-earth.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/faction/faction-terminid.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/faction/faction-terminid.png new file mode 100644 index 0000000..efd86eb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/faction/faction-terminid.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-acid-storms.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-acid-storms.png new file mode 100644 index 0000000..0e281a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-acid-storms.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-blizzards.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-blizzards.png new file mode 100644 index 0000000..e4c2ebd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-blizzards.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-extreme-cold.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-extreme-cold.png new file mode 100644 index 0000000..646c580 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-extreme-cold.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-fire-tornados.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-fire-tornados.png new file mode 100644 index 0000000..be58c68 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-fire-tornados.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-intense-heat.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-intense-heat.png new file mode 100644 index 0000000..c85ae5f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-intense-heat.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-ion-storms.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-ion-storms.png new file mode 100644 index 0000000..12beaf6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-ion-storms.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-meteor-storms.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-meteor-storms.png new file mode 100644 index 0000000..dba3a6c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-meteor-storms.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-rainstorms.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-rainstorms.png new file mode 100644 index 0000000..b8cfb5f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-rainstorms.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-sandstorms.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-sandstorms.png new file mode 100644 index 0000000..98678dc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-sandstorms.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-thick-fog.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-thick-fog.png new file mode 100644 index 0000000..d7547d0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-thick-fog.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-tremors.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-tremors.png new file mode 100644 index 0000000..571d75c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-tremors.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-volcanic-activity.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-volcanic-activity.png new file mode 100644 index 0000000..397ad00 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/hazard/hazard-volcanic-activity.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-helldiver.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-helldiver.png new file mode 100644 index 0000000..a7b5e9f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-helldiver.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-helldivers-2.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-helldivers-2.png new file mode 100644 index 0000000..8321293 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-helldivers-2.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-helldivers.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-helldivers.png new file mode 100644 index 0000000..bf4ae83 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-helldivers.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-major-order.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-major-order.png new file mode 100644 index 0000000..99492d1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-major-order.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-news.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-news.png new file mode 100644 index 0000000..bc2da31 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/icons/misc/misc-news.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/super earth.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/super earth.png new file mode 100644 index 0000000..4e02ab0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/super earth.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/企业微信截图_1787895661897.png b/hexi/plugins/nonebot_plugin_helldivers_tools/img/企业微信截图_1787895661897.png new file mode 100644 index 0000000..37f17e1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_helldivers_tools/img/企业微信截图_1787895661897.png differ diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/喷气旅孵化厂.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/喷气旅孵化厂.svg new file mode 100644 index 0000000..dfe7fd7 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/喷气旅孵化厂.svg @@ -0,0 +1 @@ + Jet Brigade Factories Jet Brigade FactoriesJet Brigade FactoriesJet Brigade Factories \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/工厂枢纽.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/工厂枢纽.svg new file mode 100644 index 0000000..0dc1ba1 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/工厂枢纽.svg @@ -0,0 +1 @@ + Factory Hub Factory HubFactory HubFactory Hub \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/虫窝世界.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/虫窝世界.svg new file mode 100644 index 0000000..45a58db --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/虫窝世界.svg @@ -0,0 +1 @@ + Hive WorldHive World Hive WorldHive WorldHive World \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/蟑龙.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/蟑龙.svg new file mode 100644 index 0000000..0cea165 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/蟑龙.svg @@ -0,0 +1 @@ + DragonroachDragonroachDragonroach \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/阴霾.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/阴霾.svg new file mode 100644 index 0000000..1293470 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/阴霾.svg @@ -0,0 +1 @@ + Interstellar Spore CloudInterstellar Spore CloudInterstellar Spore CloudInterstellar Spore CloudInterstellar Spore Cloud \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/img/霸王虫.svg b/hexi/plugins/nonebot_plugin_helldivers_tools/img/霸王虫.svg new file mode 100644 index 0000000..55f0782 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/img/霸王虫.svg @@ -0,0 +1 @@ + Hive LordHive LordHive Lord \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/stratagem_admin.py b/hexi/plugins/nonebot_plugin_helldivers_tools/stratagem_admin.py new file mode 100644 index 0000000..e4a52a3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/stratagem_admin.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +"""战备管理 API:作为统一 Web 的一个模块,挂到 /api/helldivers。 + +- 不再自己出 HTML,页面由统一前端 (hexi/web) 渲染。 +- 鉴权统一走 hexi.web_auth(OAuth2 + SQLite)。 +""" + +from __future__ import annotations + +from pathlib import Path + +from fastapi import Depends, FastAPI, HTTPException, Request +from fastapi.responses import FileResponse, JSONResponse + +from hexi.web_auth import require_admin + +from .equipment_store import ( + create_stratagem, + delete_stratagem, + export_items, + get_stratagem, + import_items, + list_stratagems, + list_stratagems_page, + update_stratagem, +) +from .icon_utils import TYPE_COLORS, save_icon_png, svg_to_png + +basic_path = Path(__file__).resolve().parent + + +def _get_body(request: Request): + return request.json() + + +def build_admin_app() -> FastAPI | None: + """构建战备 API 子应用(挂载到 /api/helldivers)。""" + app = FastAPI(title="Helldivers Stratagems API") + auth = require_admin + + @app.get("/stratagems") + async def api_list(page: int = 1, page_size: int = 20, _: dict = auth): + page = max(1, page) + page_size = min(max(1, page_size), 100) + items, total = list_stratagems_page(page, page_size) + return {"items": items, "total": total, "page": page, "page_size": page_size} + + @app.post("/stratagems") + async def api_create(request: Request, _: dict = auth): + body = await _get_body(request) + try: + item = create_stratagem(body) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + return {"ok": True, "item": item} + + @app.put("/stratagems/{seed}") + async def api_update(seed: int, request: Request, _: dict = auth): + body = await _get_body(request) + item = update_stratagem(seed, body) + if item is None: + raise HTTPException(status_code=404, detail="未找到该战备") + return {"ok": True, "item": item} + + @app.delete("/stratagems/{seed}") + async def api_delete(seed: int, _: dict = auth): + if not delete_stratagem(seed): + raise HTTPException(status_code=404, detail="未找到该战备") + return {"ok": True} + + @app.post("/import") + async def api_import(request: Request, _: dict = auth): + body = await _get_body(request) + if isinstance(body, dict): + items = body.get("items") + else: + items = body + if not isinstance(items, list): + raise HTTPException(status_code=400, detail="需要 JSON 数组或 {items: [...]}") + result = import_items(items) + return {"ok": True, **result} + + @app.get("/export") + async def api_export(_: dict = auth): + return JSONResponse(export_items()) + + @app.get("/img/{path:path}") + async def icon_file(path: str): + base = (basic_path / "img").resolve() + target = (basic_path / "img" / path).resolve() + if not target.is_relative_to(base) or not target.exists(): + raise HTTPException(status_code=404, detail="图片不存在") + return FileResponse(target) + + @app.post("/stratagems/{seed}/icon") + async def api_upload_icon(seed: int, request: Request, _: dict = auth): + body = await _get_body(request) + svg = (body.get("svg") or "").strip() + framed = bool(body.get("framed")) + item = get_stratagem(seed) + if item is None: + raise HTTPException(status_code=404, detail="未找到该战备") + frame_color = TYPE_COLORS.get(item.get("type"), "#6bb7ea") + try: + png = await svg_to_png(svg, framed=framed, frame_color=frame_color) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + except Exception as e: + raise HTTPException(status_code=500, detail=f"SVG 转换失败: {type(e).__name__}: {e}") + rel = save_icon_png(png, item.get("name") or f"strategem-{seed}") + update_stratagem(seed, {"icon": rel}) + return {"ok": True, "icon": rel} + + return app \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/templates/brief_card.css b/hexi/plugins/nonebot_plugin_helldivers_tools/templates/brief_card.css new file mode 100644 index 0000000..7c3af6f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/templates/brief_card.css @@ -0,0 +1,102 @@ +* { box-sizing: border-box; margin: 0; padding: 0; } +body { background: #070707; font-family: "HC Sinclair", "FS Sinclair", "HD2 Body", "HD2 Sans", "Microsoft YaHei", "Noto Sans SC", sans-serif; color: #fbfaf5; padding: 16px; } +.card { width: 750px; background: linear-gradient(165deg, #0f0f0f 0%, #0a0a0a 100%); border: 1px solid #262626; border-radius: 16px; padding: 24px 26px; } +.header { display: flex; align-items: center; margin-bottom: 20px; } +.brief-overview { margin-bottom: 20px; } +.brief-overview .order { margin-bottom: 12px; } +.brief-overview > .box:last-child { margin-bottom: 0; } +.header .logo { width: 56px; height: 56px; margin-right: 16px; } +.header .title { font-size: 34px; font-weight: 700; color: #FFE710; letter-spacing: 3px; text-transform: uppercase; } +.header .subtitle { font-size: 13px; color: #9a9a90; margin-top: 4px; letter-spacing: 1px; } +/* 标题用 HD2 军事硬朗中文字体(创客贴金刚体),正文回落系统黑体 */ +.box-title, .order-title, .header .title { font-family: "HD2 Display", "HC Sinclair", "Microsoft YaHei", "Noto Sans SC", sans-serif; } +/* 中文用途字体:星球名=爱点风雅黑,星系名=造字工房尚黑 */ +.planet { font-family: "HD2 Planet", "HC Sinclair", "Microsoft YaHei", "Noto Sans SC", sans-serif; } +.sector-name { font-family: "HD2 Sector", "HC Sinclair", "Microsoft YaHei", "Noto Sans SC", sans-serif; } +/* 小标签用思源黑体;line-height:1 收紧行框,避免中文大行高导致文字视觉偏下 */ +.efx, .stat .k, .chip, .order-meta { font-family: "HD2 Sans", "HC Sinclair", "Microsoft YaHei", "Noto Sans SC", sans-serif; line-height: 1; } +/* 星系战况(stat)用思源黑体,数字/统计更清晰平直 */ +.stat .v, .stat .k { font-family: "HD2 Sans", "HC Sinclair", "Microsoft YaHei", "Noto Sans SC", sans-serif; } +.box { background: #161616; border: 1px solid #2a2a2a; border-radius: 12px; padding: 18px 20px; margin-bottom: 20px; } +.box-title { display: flex; align-items: center; font-size: 17px; font-weight: 700; color: #fbfaf5; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 14px; } +.box-title .dot { width: 8px; height: 8px; border-radius: 50%; background: #FFE710; margin-right: 9px; box-shadow: 0 0 10px #FFE710; } +.ic { display: inline-block; flex: none; } +.empty { color: #9a9a90; font-size: 15px; } +.order { border-left: 3px solid #FFE710; background: linear-gradient(90deg, #1a1a17 0%, #161616 100%); } +.order-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; } +.order-title2 { display: flex; align-items: center; gap: 6px; font-size: 17px; font-weight: 700; color: #fbfaf5; text-transform: uppercase; letter-spacing: 1px; } +.order-remain { font-size: 14px; font-weight: 700; color: #FFE710; } +.order-desc { font-size: 15px; color: #d9d6c8; line-height: 1.7; } +.order-ov { margin-top: 12px; } +.order-ov-title { font-size: 13px; color: #9a9a90; letter-spacing: 1px; margin-bottom: 6px; } +.order-target { display: flex; align-items: center; gap: 8px; margin-top: 8px; font-size: 13px; } +.ot-dot { flex: none; width: 10px; height: 10px; border-radius: 3px; } +.ot-main { flex: 1; min-width: 0; } +.ot-name { display: block; min-width: 0; color: #fbfaf5; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +/* 重要指令目标:格子型进度条(双色交战,解放=蓝领先/防守=敌色侵占蓝条) */ +.otseg { height: 7px; margin: 5px 0 0; gap: 2px; } +.otseg i { box-shadow: inset 0 0 0 1px rgba(0,0,0,0.3); } +.ot-pct { flex: none; min-width: 50px; text-align: right; color: #fbfaf5; } +.order-meta { display: flex; gap: 26px; margin-top: 12px; font-size: 14px; color: #CBCBCD; } +.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; background: #101010; border: 1px solid #2a2a2a; border-radius: 10px; overflow: hidden; } +.stat { position: relative; min-width: 0; background: transparent; border: 0; border-radius: 0; padding: 13px 8px 11px; text-align: center; } +.stat:nth-child(4n + 2), .stat:nth-child(4n + 3), .stat:nth-child(4n + 4) { border-left: 1px solid #2d2d2a; } +.stat:nth-child(n + 5) { border-top: 1px solid #2d2d2a; } +.stat .v { font-family: "FS Sinclair", "HC Sinclair", sans-serif; font-size: 25px; line-height: 1; font-weight: 700; color: #fbfaf5; letter-spacing: 1px; } +.stat .k { font-family: "HD2 Sans", "Microsoft YaHei", "Noto Sans SC", sans-serif; font-size: 11px; color: #8d8d85; margin-top: 7px; letter-spacing: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.camps { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; } +.campsec { margin-top: 16px; } +.campsec:first-child { margin-top: 0; } +.campsec-title { display: flex; align-items: center; gap: 7px; font-size: 15px; font-weight: 700; letter-spacing: 1px; margin-bottom: 10px; } +.campsec-title .campsec-sub { margin-left: auto; font-size: 12px; color: #9a9a90; font-weight: 400; } +/* 单卡(参考图样式,缩放到两列网格的紧凑 tile) */ +.camp { position: relative; display: flex; background: #0c0c0c; background-size: cover; background-position: center top; border: 1px solid #2a2a2a; border-radius: 14px; overflow: hidden; min-height: 300px; box-shadow: 0 8px 22px rgba(0,0,0,0.5); } +.camp-veil { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(5,5,5,0.30) 0%, rgba(5,5,5,0.56) 46%, rgba(5,5,5,0.94) 100%); pointer-events: none; } +.camp-rail { position: relative; z-index: 3; width: 42px; flex: none; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; padding: 12px 0 14px; gap: 9px; background: linear-gradient(180deg, #151515 0%, #0a0a0a 100%); border-right: 1px solid rgba(255,255,255,0.08); box-shadow: inset 3px 0 12px rgba(0,0,0,0.6); } +.camp-rail::before { content: ""; position: absolute; left: 1px; top: 0; bottom: 0; width: 3px; background: linear-gradient(180deg, var(--rc), rgba(0,0,0,0)); } +.rail-icon { display: flex; align-items: center; justify-content: center; width: 100%; height: 28px; margin-top: 4px; } +.rail-icon .ic { width: 24px; height: 24px; margin-right: 0; display: block; } +.rail-text { writing-mode: vertical-rl; text-align: center; letter-spacing: 3px; line-height: 1; font-size: 13px; font-weight: 700; color: #fbfaf5; opacity: 0.92; margin-top: 10px; text-shadow: 0 1px 4px rgba(0,0,0,0.8); } +.rail-dots { display: flex; flex-direction: column; align-items: center; gap: 6px; margin-top: auto; } +.rail-dots i { width: 5px; height: 5px; border-radius: 50%; background: rgba(255,255,255,0.35); } +.camp-body { position: relative; z-index: 2; flex: 1; min-width: 0; padding: 12px 12px 12px 11px; } +.camp-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; } +.camp-title { min-width: 0; } +.camp .planet { font-family: "HD2 Planet", "HC Sinclair", "Microsoft YaHei", "Noto Sans SC", sans-serif; font-size: 19px; font-weight: 700; color: #fff; text-transform: uppercase; letter-spacing: 1px; text-shadow: 0 2px 6px rgba(0,0,0,0.9); line-height: 1.1; } +.camp-faction { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 700; margin-top: 5px; text-shadow: 0 1px 4px rgba(0,0,0,0.9); } +.camp-prog { flex: none; text-align: right; } +.camp-pct { font-family: "FS Sinclair", "HC Sinclair", sans-serif; font-size: 22px; font-weight: 700; line-height: 1; color: #fff; text-shadow: 0 2px 6px rgba(0,0,0,0.9); } +.camp-prog-label { font-size: 11px; color: #c9c9c0; margin-top: 4px; letter-spacing: 1px; text-shadow: 0 1px 4px rgba(0,0,0,0.9); } +.segbar { display: flex; gap: 3px; height: 9px; margin: 12px 0 0; } +.segbar i { flex: 1; background: rgba(255,255,255,0.10); border-radius: 2px; } +/* 双色交战进度条:两股颜色争地盘,谁段多谁占优 */ +.segbar-duo i { box-shadow: inset 0 0 0 1px rgba(0,0,0,0.35); border-radius: 2px; } +.camp-remain { font-size: 12px; color: #d9d6c8; margin-top: 7px; text-shadow: 0 1px 4px rgba(0,0,0,0.9); } +.camp-remain b { color: #fbfaf5; font-weight: 700; } +.info-rows { margin-top: 11px; border-top: 1px solid rgba(255,255,255,0.08); } +.irow { display: flex; align-items: center; gap: 7px; padding: 8px 2px; border-bottom: 1px solid rgba(255,255,255,0.06); } +.irow-ic { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; color: #b0b0a8; } +.irow-ic .ic { width: 15px !important; height: 15px !important; margin-right: 0; } +.irow-label { flex: none; min-width: 52px; font-size: 11px; color: #9a9a90; letter-spacing: 1px; } +.irow-val { flex: 1; text-align: right; font-size: 13px; font-weight: 700; color: #fbfaf5; } +.haz-val { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 3px 10px; } +.hzt { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; } +.hzt .ic { display: inline-block; } +.feat-row { display: flex; align-items: flex-start; gap: 8px; margin-top: 10px; } +.feat-label { display: inline-flex; align-items: center; gap: 5px; flex: none; font-size: 13px; font-weight: 700; color: #fbfaf5; } +.feat-tags { display: flex; flex-wrap: wrap; gap: 5px; flex: 1; min-width: 0; } +/* 星球效果 徽章(复用 efx,尺寸放大适配单卡) */ +.efx { display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; background: rgba(224,196,106,0.12); border: 1px solid; border-radius: 20px; padding: 1px 9px; } +.feat-tags .efx { padding: 4px 10px; font-size: 12px; font-weight: 700; } +/* 民主空间站(DSS)增益标识:会动的星球,驻扎给该星球带来 buff;字体用思源黑体(HD2 Sans) */ +.dss { margin: 0 0 6px; padding: 6px 10px; background: linear-gradient(90deg, #6bb7ea28, #6bb7ea0c); border: 1px solid #6bb7ea55; border-radius: 8px; font-family: "HD2 Sans", "Microsoft YaHei", "Noto Sans SC", sans-serif; } +.dss-head { display: flex; align-items: center; gap: 6px; } +.dss-ic { display: inline-flex; flex: none; } +.dss-tx { font-size: 13px; font-weight: 700; color: #6bb7ea; letter-spacing: 1px; } +.dss-actions { display: flex; flex-wrap: wrap; gap: 4px 8px; margin: 3px 0 0 22px; font-size: 13px; color: #6bb7ea; } +.dss-inherent { margin: 3px 0 0 22px; font-size: 13px; color: #6bb7ea; line-height: 1.4; word-break: break-word; } +.dss-b { display: inline-flex; align-items: center; gap: 3px; } +.dss-b .ic { width: 13px; height: 13px; } +.chips { display: flex; flex-wrap: wrap; gap: 10px; } +.chip { display: inline-flex; align-items: center; gap: 6px; border: 1px solid; border-radius: 20px; padding: 6px 16px; font-size: 14px; font-weight: 700; background: #101010; letter-spacing: 1px; } +.foot { text-align: center; font-size: 12px; color: #5a5a52; margin-top: 4px; } diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/templates/brief_card.html b/hexi/plugins/nonebot_plugin_helldivers_tools/templates/brief_card.html new file mode 100644 index 0000000..dbcd5ba --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/templates/brief_card.html @@ -0,0 +1,23 @@ + + + + + + + + +
    + @@HEADER@@ +
    + @@MAJOR_ORDER@@ + @@STATS@@ +
    + @@CAMPAIGNS@@ + @@CONTROL@@ +
    数据来源:helldivers-2/api 社区接口 · 仅供娱乐
    +
    + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/templates/equip_card.css b/hexi/plugins/nonebot_plugin_helldivers_tools/templates/equip_card.css new file mode 100644 index 0000000..304124b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/templates/equip_card.css @@ -0,0 +1,20 @@ +* { box-sizing: border-box; margin: 0; padding: 0; } +body { background: #070707; font-family: "HC Sinclair", "FS Sinclair", "HD2 Body", "HD2 Sans", "Microsoft YaHei", "Noto Sans SC", sans-serif; color: #fbfaf5; padding: 16px; } +.card { width: 600px; background: linear-gradient(165deg, #0f0f0f 0%, #0a0a0a 100%); border: 1px solid #262626; border-radius: 0; padding: 24px 26px; } +.header { display: flex; align-items: center; margin-bottom: 20px; } +.header .logo { width: 56px; height: 56px; margin-right: 16px; } +.header .title { font-family: "HD2 Display", "HC Sinclair", "Microsoft YaHei", "Noto Sans SC", sans-serif; font-size: 30px; font-weight: 700; color: #FFE710; letter-spacing: 3px; text-transform: uppercase; } +.header .subtitle { font-size: 13px; color: #9a9a90; margin-top: 4px; letter-spacing: 1px; } +.box { background: #161616; border: 1px solid #2a2a2a; border-radius: 0; padding: 18px 20px; } +.box-title { display: flex; align-items: center; font-family: "HD2 Display", "HC Sinclair", "Microsoft YaHei", "Noto Sans SC", sans-serif; font-size: 17px; font-weight: 700; color: #fbfaf5; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 14px; } +.box-title .dot { width: 8px; height: 8px; border-radius: 50%; background: #FFE710; margin-right: 9px; box-shadow: 0 0 10px #FFE710; } +.eq-list { display: flex; flex-direction: column; gap: 12px; } +.eq-row { display: flex; align-items: center; gap: 14px; background: #101010; border: 1px solid #262626; border-radius: 0; padding: 10px 14px; } +.eq-icwrap { flex: none; width: 72px; height: 72px; display: flex; align-items: center; justify-content: center; background: #0a0a0a; border: 1px solid #2a2a2a; border-radius: 0; overflow: hidden; } +.eq-ic { max-width: 100%; max-height: 100%; object-fit: contain; } +.eq-info { flex: 1; min-width: 0; } +.eq-name { font-family: "HD2 Planet", "HC Sinclair", "Microsoft YaHei", "Noto Sans SC", sans-serif; font-size: 19px; font-weight: 700; color: #fbfaf5; letter-spacing: 1px; } +.eq-meta { display: flex; align-items: center; gap: 8px; margin-top: 6px; font-size: 12px; color: #9a9a90; font-family: "HD2 Sans", "Microsoft YaHei", "Noto Sans SC", sans-serif; } +.eq-badge { display: inline-flex; align-items: center; justify-content: center; padding: 1px 9px; border: 1px solid; border-radius: 0; font-weight: 700; white-space: nowrap; font-family: "HD2 Sans", "Microsoft YaHei", "Noto Sans SC", sans-serif; } +.eq-alias { color: #d9d6c8; font-family: "HD2 Sans", "Microsoft YaHei", "Noto Sans SC", sans-serif; } +.foot { text-align: center; font-size: 12px; color: #5a5a52; margin-top: 16px; } diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/templates/equip_card.html b/hexi/plugins/nonebot_plugin_helldivers_tools/templates/equip_card.html new file mode 100644 index 0000000..c23732b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/templates/equip_card.html @@ -0,0 +1,27 @@ + + + + + + + + +
    +
    + +
    +
    超级地球武装部
    +
    Random Stratagem · 随机战备
    +
    +
    +
    +
    战备列表
    +
    @@ROWS@@
    +
    +
    超级地球永远需要你 · For Super Earth!!!!!
    +
    + + diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/utils.py b/hexi/plugins/nonebot_plugin_helldivers_tools/utils.py new file mode 100644 index 0000000..beb625d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/utils.py @@ -0,0 +1,84 @@ +import asyncio +import io +import json +import os +import re +from datetime import datetime +from typing import Optional, Union +import base64 + +from PIL import Image +from playwright.async_api import async_playwright +from nonebot.adapters.onebot.v11 import MessageEvent, MessageSegment +from nonebot import logger + +basic_path = os.path.dirname(__file__) +save_path = os.path.join(basic_path, "temp") + +headers = { + "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.1.6) ", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + "Accept-Language": "zh-cn" +} + + +def gen_ms_img(image: Union[bytes, Image.Image]) -> MessageSegment: + if isinstance(image, bytes): + return MessageSegment.image( + pic2b64(Image.open(io.BytesIO(image))) + ) + else: + return MessageSegment.image( + pic2b64(image) + ) + + +def get_present_time() -> int: + return int(datetime.timestamp(datetime.now())) + + +async def screen_shot(url: str, time_present: int) -> Optional[str or bool]: + async with async_playwright() as p: + browser = await p.chromium.launch() + page = await browser.new_page() + try: + # 设置视口大小 + await page.set_viewport_size({"width": 2800, "height": 2800}) + await page.goto(url) + await page.wait_for_load_state('networkidle') + with open(f'{basic_path}/data/plantes_mix.json', 'r', encoding='utf-8') as file: + replacements = json.load(file) + # 遍历字典,构建替换脚本 + replacement_script = "" + for keyword, replacement in replacements.items(): + escaped_keyword = json.dumps(keyword) + escaped_replacement = json.dumps(replacement) + replacement_script += f""" + document.body.outerHTML = document.body.outerHTML.replace(new RegExp({escaped_keyword}, 'g'), {escaped_replacement}); + """ + + # 在页面上执行替换脚本 + await page.evaluate(replacement_script) + + except Exception as e: + return f"访问网站异常{type(e)}`{e}`" + await asyncio.sleep(1) + logger.info("正在保存图片...") + img_path = os.path.join(save_path, f'{time_present}.png') + await page.screenshot( + path=img_path, + full_page=True + ) + logger.info("正在压缩图片...") + img_convert = Image.open(img_path) + img_convert.save(img_path, quality=80) + logger.info("图片保存成功!") + await browser.close() + return "success" + + +def pic2b64(pic: Image) -> str: + buf = io.BytesIO() + pic.save(buf, format='PNG') + base64_str = base64.b64encode(buf.getvalue()).decode() + return 'base64://' + base64_str diff --git a/hexi/plugins/nonebot_plugin_helldivers_tools/war_renderer.py b/hexi/plugins/nonebot_plugin_helldivers_tools/war_renderer.py new file mode 100644 index 0000000..7df2bd9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_helldivers_tools/war_renderer.py @@ -0,0 +1,909 @@ +import json +import re +from datetime import datetime, timezone +from pathlib import Path +from typing import Any + +from nonebot import require + +# 顺序很重要:先 require 声明依赖,再 import(与 nonebot_plugin_picstatus 一致) +require("nonebot_plugin_htmlrender") + +from nonebot_plugin_htmlrender import get_new_page # noqa: E402 + +basic_path = Path(__file__).resolve().parent +img_path = basic_path / "img" +data_path = basic_path / "data" +template_path = basic_path / "templates" + + +def _rel(p: Path) -> str: + """返回相对插件目录的正斜杠相对路径(配合 解析;可移植、file:// 同目录树可加载)。""" + return p.relative_to(basic_path).as_posix() + + +def _load_template(name: str) -> str: + """读取 templates/ 下的模板文件(UTF-8)。每次渲染实时读取,便于直接改模板即时生效。""" + return (template_path / name).read_text(encoding="utf-8") + +# ---- 常量 ---- + +FACTIONS: dict[str, tuple[str, str]] = { + "Super Earth": ("超级地球", "#6bb7ea"), + "Humans": ("超级地球", "#6bb7ea"), # API 阵营名为 Humans + "Terminids": ("终结族", "#ff9900"), + "Automaton": ("机器人", "#fe6d6a"), # API 用单数 Automaton + "Automatons": ("机器人", "#fe6d6a"), + "Illuminate": ("光能族", "#CF64F8"), +} + +REWARD_TYPES: dict[int, str] = { + 1: "奖章", + 2: "征用券", + 3: "超级货币", + 4: "补助", + 5: "经验", +} + +_name_map: dict[str, str] | None = None + + +# ---- 数据工具 ---- + +def _load_name_map() -> dict[str, str]: + global _name_map + if _name_map is None: + # 统一从 data/i18n.json 的 planet 字段取(已合并 plantes_mix.json 的星球/文案翻译) + _name_map = _load_i18n().get("planet", {}) + return _name_map + + +def _localized(value: Any) -> str: + """提取本地化字段。API 在指定语言下返回字符串,invarants 模式下可能是 {lang: text} 字典。""" + if value is None: + return "" + if isinstance(value, str): + return value + if isinstance(value, dict): + for key in ("zh-Hans", "zh-CN", "zh-Hant", "zh"): + if value.get(key): + return str(value[key]) + for v in value.values(): + if v: + return str(v) + return "" + return str(value) + + +def _is_cjk(text: str) -> bool: + return any("\u4e00" <= ch <= "\u9fff" for ch in text) + + +def _strict_lookup(mapping: dict[str, str], value: str) -> str | None: + """严格匹配:整串精确匹配(先原样,再整串大小写不敏感),不做子串/模糊匹配;未命中返回 None。""" + if not value: + return None + if value in mapping: + return mapping[value] + low = value.lower() + for k, v in mapping.items(): + if k.lower() == low: + return v + return None + + +def _translate(text: str) -> str: + """严格翻译:整串能精确匹配到 i18n.json 的 planet 表才译,否则原样返回(不做模糊/乱配)。""" + s = text or "" + if _is_cjk(s): + return s + return _strict_lookup(_load_name_map(), s) or s + + +def _sector(value: Any) -> str: + """星系本地化:优先用 API 已返回的中文;否则去掉可能的 "Sector" 后缀后严格查 sector 表。""" + s = _localized(value) + if not s: + return "" + if _is_cjk(s): + return s + key = re.sub(r"\s*SECTOR\s*$", "", s.strip(), flags=re.IGNORECASE) + return _strict_lookup(_load_i18n().get("sector", {}), key) or _translate(s) + + +def _fmt_num(value: Any) -> str: + try: + n = int(value) + except (TypeError, ValueError): + return str(value or "—") + if n >= 100_000_000: + return f"{n / 100_000_000:.2f}亿" + if n >= 10_000: + return f"{n / 10_000:.1f}万" + return f"{n:,}" + + +def _fmt_hud_num(value: Any) -> str: + """战情数字使用游戏 HUD 常见的 K/M/B 单位,避免中文单位挤占空间。""" + try: + n = float(value) + except (TypeError, ValueError): + return str(value or "—") + if abs(n) >= 1_000_000_000: + return f"{n / 1_000_000_000:.1f}B" + if abs(n) >= 1_000_000: + return f"{n / 1_000_000:.1f}M" + if abs(n) >= 1_000: + return f"{n / 1_000:.1f}K" + return f"{int(n):,}" if n.is_integer() else f"{n:.1f}" + + +def _fmt_pct(value: Any) -> str: + try: + v = float(value) + except (TypeError, ValueError): + return "—" + if v <= 1: + v *= 100 + return f"{max(0, min(100, round(v)))}%" + + +def _remaining(expiration: Any, now_ts: int) -> str: + if not expiration: + return "?" + try: + s = str(expiration).strip().replace("Z", "+00:00") + # Python 3.10 的 fromisoformat 最多支持 6 位小数秒,超长微秒需截断到 6 位 + s = re.sub(r"\.(\d{6})\d+", r".\1", s) + dt = datetime.fromisoformat(s) + if dt.tzinfo is None: + dt = dt.replace(tzinfo=timezone.utc) + secs = (dt - datetime.fromtimestamp(now_ts, tz=timezone.utc)).total_seconds() + except (ValueError, TypeError): + return "?" + if secs <= 0: + return "已结束" + h, m = int(secs // 3600), int((secs % 3600) // 60) + return f"{h}小时{m}分" + + +def _faction(name: str) -> tuple[str, str]: + key = (name or "").strip().title() + if key in FACTIONS: + return FACTIONS[key] + return (name or "未知"), "#cccccc" + + +def _logo_data_uri() -> str: + logo = img_path / "super earth.png" + if not logo.exists(): + return "" + # 用相对路径链接而非 base64,避免 HTML 膨胀导致渲染慢(配合 解析) + return _rel(logo) + + +def _svg_inline(path: Path, color: str, em: str = "1.2em") -> str: + """把任意 SVG 文件改成 currentColor,返回内联 。""" + if not path or not Path(path).exists(): + return "" + raw = Path(path).read_text(encoding="utf-8") + vb = re.search(r'viewBox="([^"]+)"', raw) + vb = vb.group(1) if vb else "0 0 1000 1000" + inner = re.sub(r"^\s*]*>", "", raw, count=1) + inner = re.sub(r"\s*$", "", inner) + inner = re.sub(r'fill="#[0-9a-fA-F]+"', 'fill="currentColor"', inner) + inner = re.sub(r'stroke="#[0-9a-fA-F]+"', 'stroke="currentColor"', inner) + return ( + f'' + f"{inner}" + ) + + +def _icon_svg(name: str, color: str, em: str = "1.2em") -> str: + """读取 img/assets/icons/{name}.svg,返回内联 ; + 原始游戏 SVG(含XML声明/DOCTYPE/嵌套svg)内联会破坏HTML结构导致文字不显示,改用 原样嵌入。""" + p = img_path / "assets" / "icons" / f"{name}.svg" + if not p.exists(): + return "" + raw = p.read_text(encoding="utf-8") + if " 1: + # 原始游戏 SVG 内联会破坏HTML结构导致文字不显示;用相对路径链接而非 base64 + return ( + f"" + ) + return _svg_inline(p, color, em) + + +def _icon_any(name: str, color: str, em: str = "1.2em") -> str: + """优先用 PNG/webp 位图(用户转好的固定尺寸图标);无位图再用 SVG(currentColor 可变色)。""" + # 图标用相对路径链接而非 base64(HTML 更小、渲染更快) + for ext in (".png", ".webp"): + p = img_path / "assets" / "icons" / f"{name}{ext}" + if p.exists(): + return ( + f"" + ) + svg = img_path / "assets" / "icons" / f"{name}.svg" + if svg.exists(): + return _icon_svg(name, color, em) + return "" + + +# 阵营中文名 -> 图标 +FACTION_ICON: dict[str, str] = { + "超级地球": "faction-super-earth", + "终结族": "faction-terminid", + "机器人": "faction-automaton", + "光能族": "faction-illuminate", +} + +# 星球效果 -> 图标 +EFFECT_ICONS: dict[str, str] = { + "1187": "effect-gloom", "1188": "effect-gloom", "1190": "effect-gloom", "1193": "effect-gloom", + "1243": "effect-predator-strain", "1245": "effect-predator-strain", + "1244": "effect-spore-burst-strain", "1386": "effect-spore-burst-strain", + "1303": "effect-rupture-strain", "1310": "effect-rupture-strain", + "1306": "effect-dragonroach", "1309": "effect-dragonroach", + "1307": "effect-hive-lord", "1308": "effect-hive-lord", + "1311": "effect-hive-world", + "1202": "effect-jet-brigade", "1203": "effect-jet-brigade", + "1209": "effect-dss-eagle", "1212": "effect-dss-eagle", "1216": "effect-dss-eagle", + "1210": "effect-dss-blockade", "1213": "effect-dss-blockade", "1215": "effect-dss-blockade", + "1211": "effect-dss-heavy-ordnance", "1214": "effect-dss-heavy-ordnance", + "1232": "effect-factory-hub", + "1238": "effect-dss", + "1239": "effect-jet-brigade-factory", + "1248": "effect-incineration-corps", "1249": "effect-incineration-corps", + "1360": "effect-cyborgs", "1361": "effect-cyborgs", + "1379": "effect-appropriators", "1380": "effect-appropriators", + "1377": "effect-mindless-masses", "1378": "effect-mindless-masses", + "1402": "effect-vote-snatchers", "1403": "effect-vote-snatchers", + "1413": "effect-invasion-fleet", "1414": "effect-invasion-fleet", + "1395": "effect-tcs-plus", + "1400": "effect-heavy-seaf", "1401": "effect-heavy-seaf", + "1324": "effect-mine", +} + +# 子派系/种族事件效果 -> 种族主题色(效果徽章按种族着色,不再统一金色) +EFFECT_RACE_COLOR: dict[str, str] = { + # 终结族 (橙) + "1187": "#ff9900", "1188": "#ff9900", "1190": "#ff9900", "1193": "#ff9900", + "1243": "#ff9900", "1245": "#ff9900", "1244": "#ff9900", "1386": "#ff9900", + "1303": "#ff9900", "1310": "#ff9900", "1306": "#ff9900", "1309": "#ff9900", + "1307": "#ff9900", "1308": "#ff9900", "1311": "#ff9900", + # 机器人 (红) + "1202": "#fe6d6a", "1203": "#fe6d6a", "1239": "#fe6d6a", "1248": "#fe6d6a", + "1249": "#fe6d6a", "1360": "#fe6d6a", "1361": "#fe6d6a", + # 光能族 (紫) + "1377": "#CF64F8", "1378": "#CF64F8", "1379": "#CF64F8", "1380": "#CF64F8", + "1402": "#CF64F8", "1403": "#CF64F8", "1413": "#CF64F8", "1414": "#CF64F8", + # 超级地球 (蓝) —— DSS 行动/设施 + "1209": "#6bb7ea", "1216": "#6bb7ea", "1210": "#6bb7ea", "1215": "#6bb7ea", + "1211": "#6bb7ea", "1217": "#6bb7ea", "1232": "#6bb7ea", "1234": "#6bb7ea", + "1236": "#6bb7ea", "1238": "#6bb7ea", "1261": "#6bb7ea", "1353": "#6bb7ea", + "1262": "#6bb7ea", "1279": "#6bb7ea", "1286": "#6bb7ea", "1287": "#6bb7ea", + "1291": "#6bb7ea", "1292": "#6bb7ea", "1400": "#6bb7ea", "1401": "#6bb7ea", +} + +# 环境危害(英名 -> 图标);API 里的 hazard.name 为英文,ID 化/未知时退化为无图标。 +HAZARD_ICON: dict[str, str] = { + "Acid Storms": "hazard-acid-storms", + "Blizzards": "hazard-blizzards", + "Extreme Cold": "hazard-extreme-cold", + "Fire Tornadoes": "hazard-fire-tornados", + "Intense Heat": "hazard-intense-heat", + "Ion Storms": "hazard-ion-storms", + "Meteor Storms": "hazard-meteor-storms", + "Rainstorms": "hazard-rainstorms", + "Sandstorms": "hazard-sandstorms", + "Thick Fog": "hazard-thick-fog", + "Tremors": "hazard-tremors", + "Volcanic Activity": "hazard-volcanic-activity", +} + + +# ---- 星球缩略图 ---- + +_bg_index: dict[str, Path] | None = None + + +def _planet_bg(index: Any, planet_english: dict[Any, Any]) -> str: + """按星球 index 查英文名,匹配 planets/ 下的高清地形图,返回 CSS background-image 值;没图返回空。""" + global _bg_index + if _bg_index is None: + _bg_index = {} + d = img_path / "assets" / "planets" + if d.exists(): + for f in d.glob("*.png"): + _bg_index[f.stem] = f + eng = _localized(planet_english.get(index)) if index is not None else "" + if not eng: + return "" + slug = re.sub(r"[^a-z0-9]+", "-", eng.lower()).strip("-") + f = _bg_index.get(slug) + if f is None: + return "" + # 背景大图用相对路径链接而非 base64(HTML 更小、渲染更快;配合 ) + return f"url({_rel(f)})" + + +_font_cache: str | None = None + + +def _font_faces() -> str: + """内嵌 @font-face:拉丁/数字用 HD2 游戏字体(FS/HC Sinclair);中文按用途分配—— + 星球名=爱点风雅黑,星系名=造字工房尚黑,重要指令=创客贴金刚体,正文=一品创享体。""" + global _font_cache + if _font_cache is not None: + return _font_cache + spec = ( + (400, "HCSinclair-Normal.woff2", "woff2", "HC Sinclair"), + (500, "HCSinclair-Medium.woff2", "woff2", "HC Sinclair"), + (700, "FSSinclair-Bold.ttf", "ttf", "FS Sinclair"), + ) + faces = [] + for weight, fname, fmt, family in spec: + p = data_path / "font" / fname + if p.exists(): + # 字体用文件路径链接而非 base64(HTML 更小、渲染更快) + faces.append( + f"@font-face{{font-family:'{family}';" + f"src:url({_rel(p)}) format('{fmt}');" + f"font-weight:{weight};font-style:normal;font-display:swap;}}" + ) + # 中文字体(按用途分配):星球名/星系名/重要指令/正文 + pkg = data_path / "font" / "HD2S字体包" + chinese = ( + ("HD2 Planet", "商用免费/爱点风雅黑/爱点风雅黑.ttf"), + ("HD2 Sector", "商用授权/造字工坊尚黑/造字工房尚黑G0v1常规体.otf"), + ("HD2 Display", "商用免费/创客贴金刚体/ChuangKeTieJinGangTi-2.otf"), + ("HD2 Body", "商用免费/一品创享体/一品创享体 1.20.ttf"), + ("HD2 Sans", "商用免费/思源黑体/SourceHanSansCN-Regular.otf"), + ) + for family, rel in chinese: + p = pkg / rel + if p.exists(): + fmt = "opentype" if p.suffix.lower() == ".otf" else "truetype" + faces.append( + f"@font-face{{font-family:'{family}';" + f"src:url({_rel(p)}) format('{fmt}');" + "font-weight:100 900;font-style:normal;font-display:swap;}" + ) + _font_cache = "\n".join(faces) + return _font_cache + + +# ---- 各板块渲染 ---- + +def _render_header(fetched_at: int) -> str: + t = datetime.fromtimestamp(fetched_at).strftime("%Y-%m-%d %H:%M") + return f""" +
    + +
    超级地球战况简报
    +
    Galactic War Briefing · {t}
    +
    + """ + + +def _render_major_order(data: dict[str, Any]) -> str: + assignments = data.get("assignments") or [] + if not assignments: + return "
    今日暂无重要指令
    " + a = assignments[0] + title = _translate(_localized(a.get("title"))) or "重要指令" + description = _translate(_localized(a.get("briefing") or a.get("description"))) + remain = _remaining(a.get("expiration"), data["fetched_at"]) + rewards = a.get("rewards") + if rewards is None: + rewards = [a["reward"]] if a.get("reward") else [] + reward_text = "" + for r in rewards or []: + amount = r.get("amount") if isinstance(r, dict) else r + rtype = r.get("type") if isinstance(r, dict) else None + label = REWARD_TYPES.get(int(rtype), "") if rtype is not None else "" + reward_text += f"{_fmt_num(amount)}{label} " + if reward_text: + reward_text = reward_text.strip() + + # 指令目标(ORDER OVERVIEW):从 tasks 提取目标星球 index(valueType=12 / 取最大值), + # 用 /planets 英名翻译成中文,匹配 campaign 的 health/maxHealth 取解放进度 + eng = data.get("planet_english") or {} + camp_by_idx = {c.get("planet", {}).get("index"): c for c in (data.get("campaigns") or [])} + targets = [] + for task in (a.get("tasks") or []): + values = task.get("values") or [] + vtypes = task.get("valueTypes") or [] + idx = None + for i, v in enumerate(values): + vt = vtypes[i] if i < len(vtypes) else None + if vt == 12: + idx = v + break + if idx is None and values: + idx = max(values) + if idx is None: + continue + ename = eng.get(idx) + pname = _translate(ename) if ename else f"星球{idx}" + pct_text = "—" + bar_html = "" + dot_color = "#FFE710" + camp = camp_by_idx.get(idx) + if camp: + p = camp.get("planet") or {} + owner_cn, owner_color = _faction(p.get("currentOwner")) + is_defense = owner_cn == "超级地球" + health = float(p.get("health") or 0) + max_health = float(p.get("maxHealth") or 0) + if is_defense: + # 防守:蓝=剩余血(超级地球控制);敌色=入侵进度(侵占蓝条) + se_pct = max(0, min(100, round(health / max_health * 100))) if max_health else 0 + inv_pct = 100 - se_pct + enemy_color = _faction(camp.get("faction") or p.get("currentOwner"))[1] + bar_html = _segbar_duo(enemy_color, inv_pct, "#6bb7ea", cls="otseg") + pct_text = f"{inv_pct}%" + dot_color = enemy_color + else: + # 解放:蓝=解放进度;敌色=残余 + lib_pct = max(0, min(100, round((max_health - health) / max_health * 100))) if max_health else 0 + bar_html = _segbar_duo("#6bb7ea", lib_pct, owner_color, cls="otseg") + pct_text = f"{lib_pct}%" + dot_color = "#6bb7ea" + targets.append((pname, pct_text, bar_html, dot_color)) + + ov_html = "" + if targets: + rows = [] + for pname, pct_text, bar_html, dot_color in targets: + rows.append( + f"
    " + f"" + f"{pname}{bar_html}" + f"{pct_text}
    " + ) + ov_html = ( + '
    ' + '
    指令目标
    ' + + "".join(rows) + + "
    " + ) + + return f""" +
    +
    + {_icon_svg('misc-major-order', '#FFE710')}{title} + 剩余:{remain} +
    +
    {description or "无任务描述"}
    + {ov_html} +
    奖励:{reward_text or "—"}
    +
    + """ + + +def _render_stats(war: Any, campaign_count: int = 0) -> str: + stats = (war or {}).get("statistics") or {} + items = [ + ("参战潜兵", _fmt_hud_num(stats.get("playerCount"))), + ("任务完成率", _fmt_pct(stats.get("missionSuccessRate"))), + ("当前战役数", _fmt_hud_num(campaign_count)), + ("终结族总击杀", _fmt_hud_num(stats.get("terminidKills"))), + ("机器人总击杀", _fmt_hud_num(stats.get("automatonKills"))), + ("光能族总击杀", _fmt_hud_num(stats.get("illuminateKills"))), + ("潜兵总阵亡", _fmt_hud_num(stats.get("deaths"))), + ("任务完成总数", _fmt_hud_num(stats.get("missionsWon"))), + ] + cells = "".join( + f"
    {v}
    {k}
    " + for k, v in items + ) + return f""" +
    +
    星系战况
    +
    {cells}
    +
    + """ + + +# ---- 星球效果(planetActiveEffects) ---- + +_i18n_cache: dict | None = None + + +def _load_i18n() -> dict: + """读取 data/i18n.json(规范化翻译数据):{biome, hazard, effect, planet} 各为 {key: 中文}。""" + global _i18n_cache + if _i18n_cache is None: + p = data_path / "i18n.json" + _i18n_cache = json.loads(p.read_text(encoding="utf-8")) if p.exists() else {} + return _i18n_cache + + +def _planet_effects_html(index: Any, planet_effects: dict[Any, Any], color: str) -> str: + """星球卡「效果插槽」:把这个星球当前所有的 planetActiveEffect 都列出来(事件/特征一视同仁, + 不分类),没有就返回空;没了自然消失。最多展示 6 个。""" + i18n_eff = _load_i18n().get("effect", {}) + seen: list[tuple[str, str]] = [] + seen_keys: set[str] = set() + for gid in (planet_effects.get(index) or []): + label = i18n_eff.get(str(gid), "") + if label and label not in seen_keys: + seen_keys.add(label) + seen.append((label, str(gid))) + if not seen: + return "" + spans = [] + for label, gid in seen[:6]: # 最多6个 + c = EFFECT_RACE_COLOR.get(gid, "#e0c46a") + spans.append( + f"" + f"{_icon_any(EFFECT_ICONS.get(gid, ''), c)} {label}" + ) + return "".join(spans) + + +def _ui_icon(name: str, color: str, em: str = "1em") -> str: + """内联小图标(fill/stroke 用 currentColor,可配色),用于单卡信息/战役/特征行。""" + icons = { + "globe": '', + "diver": '', + "mountain": '', + "cloud": '', + "crosshair": '', + "clock": '', + "warn": '', + "grid": '', + } + d = icons.get(name, "") + if not d: + return "" + return f"{d}" + + +def _segbar_duo(first_color: str, first_pct: float, second_color: str, segs: int = 28, cls: str = "") -> str: + """双色交战进度条:前一色占 first_pct 的段数,其余为第二色;谁段多谁占优。 + 用于表达“蓝色(超级地球) vs 敌方种族色”两股势力在进度条上争地盘。""" + first_pct = max(0, min(100, first_pct)) + n1 = round(first_pct / 100 * segs) + cells = "".join( + f"" if i < n1 + else f"" + for i in range(segs) + ) + return f"
    {cells}
    " + + +def _info_row(icon: str, label: str, value: str, color: str) -> str: + return ( + f"
    " + f"{_ui_icon(icon, color, '15px')}" + f"{label}" + f"{value or '—'}
    " + ) + + +def _dss_badge(planet_index: Any, space_stations: list[Any] | None) -> str: + """民主空间站(DSS)——看作一个“会动的星球”:它驻扎在哪个星球,就给那个星球带来增益 buff。 + 性质与插槽里的“事件/特征”不同,因此做成独立的「民主空间站」元素展示。""" + st = next((s for s in (space_stations or []) if s.get("planetIndex") == planet_index), None) + if not st: + return "" + eff = _load_i18n().get("effect", {}) + name = eff.get("1217", "") or "民主空间站" + # 分类:带图标的特殊行动 vs 固有效果(去 (Marker) 后缀、去重、跳过无标签) + actions = [] # [[icon]label] + inherent = [] # [label] + seen_a: set[str] = set() + seen_i: set[str] = set() + for g in (st.get("activeEffectIds") or []): + gid = str(g) + b = re.sub(r"\s*\(Marker\)\s*$", "", eff.get(gid, "")).strip() + if not b: + continue + icon_name = EFFECT_ICONS.get(gid, "") + if icon_name in ("effect-dss-eagle", "effect-dss-blockade", "effect-dss-heavy-ordnance"): + if b in seen_a: + continue + seen_a.add(b) + icon = _icon_any(icon_name, "#6bb7ea", "13px") + actions.append(f"{icon}{b}") + else: + if b in seen_i: + continue + seen_i.add(b) + inherent.append(b) + icon = _icon_any("effect-dss", "#6bb7ea", "16px") + # 两行:一行=带图标的特殊行动(无·连接),一行=固有效果(单独) + actions_line = f"
    {''.join(actions)}
    " if actions else "" + inherent_line = f"
    {' · '.join(inherent)}
    " if inherent else "" + return ( + f"
    " + f"
    {icon}{name}
    " + f"{inherent_line}{actions_line}
    " + ) + + +def _camp_card_html(cd: dict) -> str: + """单张战役卡片(新设计:左侧军种竖栏 + 行星背景 + 分段进度 + 信息行 + 主要战役 + 特征/事件)。""" + bg = cd.get("bg", "") + style = f"background-image:{bg};" if bg else "" + color = cd.get("color", "#cccccc") + owner_cn = cd.get("owner_cn", "") + rail_icon = _icon_any(FACTION_ICON.get(owner_cn, ""), "#fbfaf5", "24px") + heading = f""" +
    +
    +
    {cd['name']}
    +
    {_icon_any(FACTION_ICON.get(owner_cn, ''), color)}{owner_cn} · {cd['kind']}
    +
    +
    +
    {cd['pct_text']}
    +
    {cd['progress_label']}
    +
    +
    """ + remain = ( + f"
    剩余时间:{cd['remain']}
    " + if cd.get("remain") + else "" + ) + info = "".join( + [ + _info_row("globe", "所属星系", cd.get("sector"), color), + _info_row("diver", "部署潜兵", cd.get("players_fmt"), color), + _info_row("mountain", "地形特征", cd.get("biome"), color), + ( + f"
    " + f"{_ui_icon('cloud', color, '15px')}" + f"环境事件" + f"{cd.get('hazard_html') or '—'}
    " + ), + ] + ) + feat_rows = "" + if cd.get("effects_html"): + feat_rows = ( + f"
    {_ui_icon('grid', color)}星球效果" + f"{cd['effects_html']}
    " + ) + return f""" +
    +
    +
    + {rail_icon} + {cd['kind_label']} + +
    +
    + {heading} + {cd.get('dss_html') or ''} + {cd['bar_html']} + {remain} +
    {info}
    + {feat_rows} +
    +
    """ + + +def _render_campaigns(campaigns: list[Any], planet_english: dict[Any, Any], planet_effects: dict[Any, Any], space_stations: list[Any] | None = None, top_per_race: int | None = None) -> str: + if not campaigns: + return "
    当前无进行中的战役
    " + now = int(datetime.now(timezone.utc).timestamp()) + # 空间站所在星球(民主空间站 DSS 等):独立于插槽事件,作为增益 buff 标识展示 + station_planets = {int(st.get("planetIndex")) for st in (space_stations or []) if st.get("planetIndex") is not None} + i18n = _load_i18n() + biome_map = i18n.get("biome", {}) + hazard_map = i18n.get("hazard", {}) + # 预处理每个战役 + enriched = [] + for c in campaigns: + p = c.get("planet") or {} + # 星球名:优先用英文名(i18n.json 简体)再翻译;API zH-Hans 是繁体,不用 + en_name = _localized(planet_english.get(p.get("index"))) + name = _translate(en_name) if en_name else (_translate(_localized(p.get("name"))) or "未知星球") + sector = _sector(p.get("sector")) + owner_cn, color = _faction(p.get("currentOwner")) + is_defense = owner_cn == "超级地球" + kind = "防守" if is_defense else "解放" + kind_label = "保卫战" if is_defense else "解放战" + # 进度用“双色交战条”:蓝色=超级地球,另一色=敌方种族;谁段多谁占优。 + # 解放=蓝领先(解放进度);防守=反过来(敌方入侵领先),单卡高度可控。 + max_health = float(p.get("maxHealth") or 0) + health = float(p.get("health") or 0) + if is_defense: + # 防守:入侵/受害进度 = 进攻事件剩余血量%(主要战役框里那个终结族进攻进度)。 + # 蓝色条被敌方颜色侵占;被击退则 event.health 下降、蓝条恢复。 + ev = p.get("event") or {} + event_mh = float(ev.get("maxHealth") or 0) + inv_pct = max(0, min(100, round(float(ev.get("health") or 0) / event_mh * 100))) if event_mh else 0 + enemy_color = _faction(c.get("faction") or p.get("currentOwner"))[1] + else: + # 解放:蓝色=解放进度;敌方=残余;owner 即敌方,color 即敌方色 + inv_pct = max(0, min(100, round((max_health - health) / max_health * 100))) if max_health else 0 + enemy_color = color + # 双色交战条:解放=蓝领先(解放进度);防守=反过来(敌色=入侵进度,侵占蓝条) + bar_html = ( + _segbar_duo(enemy_color, inv_pct, "#6bb7ea") + if is_defense + else _segbar_duo("#6bb7ea", inv_pct, enemy_color) + ) + if is_defense: + progress_label = "入侵进度" + pct_text = f"{inv_pct}%" + pct_num = inv_pct + else: + progress_label = "解放进度" + pct_text = f"{inv_pct}%" + pct_num = inv_pct + players = (p.get("statistics") or {}).get("playerCount") or 0 + # 地形特征 + raw_biome = _localized((p.get("biome") or {}).get("name")) + biome = _strict_lookup(biome_map, raw_biome) or _translate(raw_biome) + # 环境事件(危害):一颗星球可能同时出现多个,做一个可换行、右对齐的图标+名称列表。 + # 空间够则一行放下,不够自动换行。 + haz_icon = {k.strip().lower(): v for k, v in HAZARD_ICON.items()} + haz_items = [] + for h in (p.get("hazards") or []): + raw = _localized(h.get("name")) + if not raw or raw.lower() in ("none", "unknown"): + continue + cn = _strict_lookup(hazard_map, raw) or _translate(raw) + icon = _icon_any(haz_icon.get(raw.strip().lower(), ""), color, "13px") + haz_items.append(f"{icon}{cn}") + hazard_html = "".join(haz_items) if haz_items else "无" + # 剩余时间(事件倒计时;无事件则空) + ev = p.get("event") or {} + has_event = bool(ev.get("faction")) and bool(ev.get("maxHealth")) + remaining = _remaining(ev.get("endTime"), now) if has_event else "" + # 归属种族:防守(超级地球被攻)取进攻方 campaign.faction,解放(星球被该种族占据)取 currentOwner + if is_defense: + race_cn, _ = _faction(c.get("faction") or p.get("currentOwner")) + else: + race_cn = owner_cn + effects_html = _planet_effects_html(p.get("index"), planet_effects, color) + bg = _planet_bg(p.get("index"), planet_english) + dss_html = _dss_badge(p.get("index"), space_stations) if p.get("index") in station_planets else "" + enriched.append( + { + "race_cn": race_cn, + "owner_cn": owner_cn, + "name": name, + "sector": sector or "—", + "color": color, + "kind": kind, + "kind_label": kind_label, + "progress_label": progress_label, + "pct_text": pct_text, + "pct_num": pct_num, + "bar_html": bar_html, + "players": players, + "players_fmt": _fmt_num(players), + "biome": biome or "—", + "hazard_html": hazard_html, + "remain": remaining, + "effects_html": effects_html, + "dss_html": dss_html, + "bg": bg, + } + ) + + # 三大种族各一个板块,板块内按玩家人数降序 + RACES = ("终结族", "机器人", "光能族") + name_to_color = {cn: color for cn, color in FACTIONS.values()} + sections = [] + for race in RACES: + items = [e for e in enriched if e["race_cn"] == race] + if not items: + continue + # 玩家数多者优先,进度仅作并列次项 + items.sort(key=lambda e: (e["players"], e["pct_num"]), reverse=True) + total_players = sum(e["players"] for e in items) + shown = items[:top_per_race] if top_per_race else items + rows = "".join(_camp_card_html(e) for e in shown) + color = name_to_color.get(race, "#cccccc") + icon = _icon_any(FACTION_ICON.get(race, ""), color) + sections.append(f""" +
    +
    {icon}{race} · {len(items)}玩家 {_fmt_num(total_players)}
    +
    {rows}
    +
    """) + + if not sections: + # 兜底:全部战役仍按玩家数降序铺开 + remaining = sorted(enriched, key=lambda e: (e["players"], e["pct_num"]), reverse=True) + rows = "".join(_camp_card_html(e) for e in remaining) + return f""" +
    +
    进行中的战役
    +
    {rows}
    +
    + """ + + return f""" +
    +
    进行中的战役
    + {''.join(sections)} +
    + """ + + +def _render_control(planets: list[Any]) -> str: + if not planets: + return "" + name_to_color = {cn: color for cn, color in FACTIONS.values()} + counts: dict[str, int] = {} + for p in planets: + owner = (p.get("currentOwner") or "").strip() + cn, _ = _faction(owner) + counts[cn] = counts.get(cn, 0) + 1 + chips = [] + for cn in ("超级地球", "终结族", "机器人", "光能族"): + if cn in counts: + color = name_to_color.get(cn, "#cccccc") + chips.append( + f"{_icon_any(FACTION_ICON.get(cn, ''), color)} {cn} {counts[cn]}" + ) + if not chips: + return "" + return f""" +
    +
    星系控制
    +
    {''.join(chips)}
    +
    + """ + + +def _build_html(data: dict[str, Any], top_per_race: int | None = None) -> str: + # 模板骨架 + 样式在 templates/ 里,此处按需加载并填充;CSS 含花括号,不用 .format,改用 replace + return ( + _load_template("brief_card.html") + .replace("@@BASE@@", basic_path.as_uri() + "/") + .replace("@@FONT_FACES@@", _font_faces()) + .replace("@@CSS@@", _load_template("brief_card.css")) + .replace("@@HEADER@@", _render_header(data["fetched_at"])) + .replace("@@MAJOR_ORDER@@", _render_major_order(data)) + .replace("@@STATS@@", _render_stats(data.get("war"), len(data.get("campaigns") or []))) + .replace( + "@@CAMPAIGNS@@", + _render_campaigns( + data.get("campaigns") or [], + data.get("planet_english") or {}, + data.get("planet_effects") or {}, + data.get("space_stations") or [], + top_per_race, + ), + ) + .replace("@@CONTROL@@", _render_control(data.get("planets") or [])) + ) + + +async def _html_to_png(html: str, width: int = 782) -> bytes: + import secrets + async with get_new_page() as page: + await page.set_viewport_size({"width": width, "height": 800}) + # 图片/字体用相对路径 + 解析;写临时 .html 到插件根目录, + # 使页面与 img/、data/ 同目录树,file:// 同源即可加载(无需额外标志)。 + tmp = basic_path / f"_render_{secrets.token_hex(6)}.html" + tmp.write_text(html, encoding="utf-8") + try: + await page.goto(tmp.as_uri(), wait_until="networkidle") + return await page.screenshot(full_page=True, type="png") + finally: + try: + tmp.unlink() + except OSError: + pass + + +async def render_war_briefing(data: dict[str, Any], top_per_race: int | None = None) -> bytes: + """把战况数据渲染成一张图,返回 PNG bytes。top_per_race 非 None 时每板块只画该种族人数前 N 张卡。""" + html = _build_html(data, top_per_race) + return await _html_to_png(html) + + +# 样式与 HTML 骨架已抽离到 templates/(brief_card.css / brief_card.html), +# 由 _build_html 里的 _load_template(...) 按需加载并填充。 +# 风格参考 Helldivers Companion:近黑底 + 金 #FFE710 主色 + 奶油白 #fbfaf5 + 亮色阵营色 diff --git a/hexi/plugins/nonebot_plugin_hexi_core/__init__.py b/hexi/plugins/nonebot_plugin_hexi_core/__init__.py new file mode 100644 index 0000000..78ac2eb --- /dev/null +++ b/hexi/plugins/nonebot_plugin_hexi_core/__init__.py @@ -0,0 +1,26 @@ +from nonebot import get_driver, logger +from nonebot.plugin import PluginMetadata + +__plugin_meta__ = PluginMetadata( + name="HeXi 核心工具", + description="HeXi 公共工具库:权限分级、消息解析、限频器、命令冷却、插件热插拔等", + usage="工具库 + 帮助/插件管理命令(帮助、插件列表、加载/卸载/重载插件)", + type="application", +) + +# 显式导入子模块注册 matcher(load_plugins 只加载到插件包层,不会自动导入包内模块) +from . import ( # noqa: E402,F401 + cooldown, + custom_utils, + message_utils, + plugin_control, + plugin_manager, + rate_limit, +) + + +@get_driver().on_startup +async def _startup_plugin_gate() -> None: + """等所有插件 matcher 注册完成后,把统一 filter 规则注入到 application 插件。""" + n = plugin_control.instrument_plugin_gate() + logger.info(f"插件控制面: 已注入 {n} 条 gateway 规则") diff --git a/hexi/plugins/nonebot_plugin_hexi_core/cooldown.py b/hexi/plugins/nonebot_plugin_hexi_core/cooldown.py new file mode 100644 index 0000000..8d74a98 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_hexi_core/cooldown.py @@ -0,0 +1,132 @@ +"""命令冷却(CD):给命令触发器加冷却,支持按用户/按群/全局三种作用域 + +基于 rate_limit 的令牌桶实现(rate=1/seconds, capacity=1): +触发一次取走唯一令牌,seconds 秒内无法再次触发。冷却键由 scope 决定: +- "user"(默认):按用户 QQ 号 → 同一用户群聊/私聊共用同一 CD(同 nonebot1 传 user_id) +- "group":按群共享 → 全群一个 CD(同 nonebot1 传 group_id),私聊退化为按用户 +- "global":所有人共享一个 CD + +用法一(装饰器,包在 on_command 外面): + from hexi.plugins.nonebot_plugin_hexi_core.cooldown import cooldown + + # 单用户 10s CD,群聊/私聊共用 + bf_cmd = cooldown(10, hint="查询太频繁了,{secs} 秒后再试")(on_command("bf3")) + # 全群共享 60s CD + daily_cmd = cooldown(60, scope="group")(on_command("打卡")) + + @bf_cmd.handle() + async def handler(bot: Bot, ev: MessageEvent): + ... + +用法二(手动查询/触发,自定义提示文本): + from hexi.plugins.nonebot_plugin_hexi_core.cooldown import Cooldown + + cd = Cooldown(10) + if cd.in_cd(ev.get_user_id()): + await matcher.finish(f"冷却中,还剩 {cd.remaining(ev.get_user_id()):.0f} 秒") + cd.try_trigger(ev.get_user_id()) +""" + +import itertools +import math +from collections.abc import Callable +from typing import Any, Literal + +from nonebot.adapters import Event +from nonebot.dependencies import Dependent +from nonebot.matcher import Matcher + +from hexi.plugins.nonebot_plugin_hexi_core.rate_limit import RateLimiter, get_limiter + +# 无 name 时的实例序号,保证同一进程内各实例的注册表 key 互不冲突 +_cd_seq = itertools.count(1) + +Scope = Literal["user", "group", "global"] + + +def _scope_key(scope: Scope) -> Callable[[Event], str]: + """按冷却作用域生成默认冷却键函数(与 key 参数二选一)""" + if scope == "group": + + def key(event: Event) -> str: + # 群聊按群共享;私聊没有群,退化为按用户 + group_id = getattr(event, "group_id", None) + if group_id is not None: + return f"group:{group_id}" + return f"user:{event.get_user_id()}" + + return key + if scope == "global": + return lambda event: "global" + return lambda event: f"user:{event.get_user_id()}" + + +class Cooldown: + """每用户命令冷却器:同一用户在群聊/私聊共用同一 CD(默认按键为用户 QQ 号)""" + + def __init__(self, seconds: float, *, name: str | None = None): + if seconds <= 0: + raise ValueError(f"seconds 必须大于 0,收到 {seconds!r}") + self.seconds = float(seconds) + self.name = name + self._rate = 1.0 / self.seconds + + def _limiter(self, key: str) -> RateLimiter: + # 复用令牌桶:rate=1/seconds、capacity=1 → 取走唯一令牌后 seconds 秒内无法再取 + if self.name is None: + self.name = f"anon:{next(_cd_seq)}" # 惰性固化,保证 key 稳定 + return get_limiter(f"cd:{self.name}:{key}", rate=self._rate, capacity=1) + + def try_trigger(self, key: str) -> bool: + """尝试触发一次:冷却中返回 False,否则记录触发时刻并返回 True""" + return self._limiter(key).try_acquire() + + def in_cd(self, key: str) -> bool: + """是否处于冷却中""" + return self.remaining(key) > 0 + + def remaining(self, key: str) -> float: + """剩余冷却秒数(0 表示不在冷却中,可触发)""" + return self._limiter(key).remaining_secs() + + +def cooldown( + seconds: float, + *, + hint: str | None = None, + name: str | None = None, + scope: Scope = "user", + key: Callable[[Event], str] | None = None, +): + """给命令触发器(on_command 的返回值)加冷却,返回加好 CD 的触发器 + + - scope: 冷却作用域 + - "user"(默认): 按用户 QQ 号,群聊/私聊共用同一冷却(同 nonebot1 传 user_id) + - "group": 按群共享(全群一个 CD),私聊退化为按用户 + - "global": 所有人共享一个 CD + - key: 自定义冷却键函数;传了 key 则忽略 scope + - hint: 冷却中提示文本,{secs} 会被替换为剩余秒数(向上取整);不传用默认文案 + - name: 冷却器名称;不传时按触发器对象生成,热重载后 CD 会重置 + + 原理:向前置插入一个 guard handler,冷却中 finish 提示并终止, + 未冷却则放行后续真正的事件处理函数。 + """ + cd = Cooldown(seconds, name=name) + key_fn = key or _scope_key(scope) + + async def guard(matcher: Matcher, event: Event): + """CD 检查 handler:冷却中提示并结束,否则放行""" + uid = key_fn(event) + if not cd.try_trigger(uid): + secs = math.ceil(cd.remaining(uid)) + msg = (hint or "操作太频繁了,请 {secs} 秒后再试").format(secs=secs) + await matcher.finish(msg) + + def deco(matcher: type[Matcher]) -> type[Matcher]: + if cd.name is None: + cd.name = f"cd:{next(_cd_seq)}" + dep = Dependent[Any].parse(call=guard, allow_types=Matcher.HANDLER_PARAM_TYPES) + matcher.handlers.insert(0, dep) + return matcher + + return deco diff --git a/hexi/plugins/nonebot_plugin_hexi_core/custom_utils.py b/hexi/plugins/nonebot_plugin_hexi_core/custom_utils.py new file mode 100644 index 0000000..b475c64 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_hexi_core/custom_utils.py @@ -0,0 +1,60 @@ +from typing import List + +from nonebot import get_plugin_config +from nonebot.adapters import Event +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent +from pydantic import BaseModel + +class Config(BaseModel): + # 管理员的QQ号 + SUPERUSERS: List[str] = [] # 必填 +pc = get_plugin_config(Config) + +# 权限等级(与 hoshino 的 priv 保持一致) +USER = 1 +GROUP_ADMIN = 2 +GROUP_OWNER = 3 +SUPERUSER = 999 + +# 管理操作所需的最低权限等级 +MANAGE_PRIV = GROUP_ADMIN + + +async def check_admin(event: Event) -> bool: + return event.get_user_id() in pc.SUPERUSERS + + +async def get_user_priv(bot: Bot, event: MessageEvent) -> int: + """获取用户权限等级:超管=999 群主=3 群管理=2 普通群员=1""" + if str(event.user_id) in pc.SUPERUSERS: + return SUPERUSER + if not isinstance(event, GroupMessageEvent): + return USER + try: + info = await bot.get_group_member_info( + group_id=event.group_id, user_id=event.user_id + ) + role = info.get("role") + if role == "owner": + return GROUP_OWNER + if role == "admin": + return GROUP_ADMIN + except Exception: + pass + return USER + + +async def check_manage(bot: Bot, event: MessageEvent) -> bool: + """是否为管理及以上权限""" + return await get_user_priv(bot, event) >= MANAGE_PRIV + + +async def check_bot_admin(bot: Bot, group_id: int) -> bool: + """bot 是否为该群的群管理/群主""" + try: + info = await bot.get_group_member_info( + group_id=group_id, user_id=bot.self_id + ) + return info.get("role") != "member" + except Exception: + return False diff --git a/hexi/plugins/nonebot_plugin_hexi_core/docs/NoneBot2_能力清单.md b/hexi/plugins/nonebot_plugin_hexi_core/docs/NoneBot2_能力清单.md new file mode 100644 index 0000000..324e562 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_hexi_core/docs/NoneBot2_能力清单.md @@ -0,0 +1,416 @@ +# NoneBot2 + OneBot V11 完整能力清单 + +> 本文档整理 NoneBot2 框架和 OneBot V11 协议的全部原生能力, +> 用于指导 HexiCore 封装层的设计——只封装原生不方便用的部分。 + +--- + +# 一、NoneBot2 框架能力 + +## 1. 事件响应器(Matcher) + +| 创建方式 | 用途 | +|---|---| +| `on_command(cmd, aliases)` | 命令匹配(最常用) | +| `on_startswith(prefix)` | 前缀匹配 | +| `on_endswith(suffix)` | 后缀匹配 | +| `on_fullmatch(text)` | 完全匹配 | +| `on_keyword(words)` | 关键词匹配 | +| `on_regex(pattern)` | 正则匹配 | +| `on_message()` | 所有消息 | +| `on_notice()` | 通知事件 | +| `on_request()` | 请求事件 | +| `on_type(event_types)` | 指定事件类型 | + +**Matcher 生命周期方法:** +```python +matcher.handle() # 注册处理函数 +matcher.got(key, prompt) # 等待用户输入 +matcher.receive("id") # 等待下一条消息 +matcher.send(msg) # 发送消息 +matcher.finish(msg) # 发送并结束 +matcher.reject(msg) # 拒绝输入,重新等待 +matcher.pause() # 暂停,等待下一条消息 +matcher.stop_propagation()# 阻止后续匹配器 +``` + +**内置权限:** +```python +from nonebot.permission import SUPERUSER, GROUP_ADMIN, GROUP_OWNER, GROUP, PRIVATE +``` + +**内置规则:** +```python +from nonebot.rule import to_me, is_type, command, keyword, startswith, endswith, fullmatch, regex +``` + +--- + +## 2. 依赖注入(DI) + +**类型注入(直接写类型注解即可):** +```python +async def handler( + bot: Bot, + event: Event, + state: T_State, + matcher: Matcher, +): ... +``` + +**参数依赖(from nonebot.params):** +| 依赖 | 返回值 | +|---|---| +| `CommandArg()` | 命令参数 `Message` | +| `Command()` | 命令名 `tuple[str, ...]` | +| `RawCommand()` | 原始命令文本 | +| `CommandStart()` | 命令前缀 | +| `EventMessage()` | 事件消息 `Message` | +| `EventPlainText()` | 纯文本 | +| `EventToMe()` | 是否 @ 机器人 `bool` | +| `Arg(key)` | `got` 获取的参数 | +| `ArgStr(key)` | `got` 参数的字符串 | +| `ArgPlainText(key)` | `got` 参数的纯文本 | +| `RegexGroup()` | 正则捕获组 | +| `RegexStr()` | 正则匹配文本 | + +--- + +## 3. 消息系统 + +### Message 类(List[MessageSegment]) + +```python +msg.extract_plain_text() # 提取纯文本 +msg.has("image") # 是否包含某类型 +msg.only("text") # 是否只有某类型 +msg["text"] # 过滤出所有文本段 +msg["text", 0] # 第一个文本段 +msg.include("text", "image") # 只保留指定类型 +msg.exclude("image") # 排除指定类型 +msg.count("image") # 计数 +msg.index("image") # 索引 +msg + "text" # 拼接 +Message.template("{} {}").format(a, b) # 模板 +``` + +### OneBot V11 MessageSegment + +```python +MessageSegment.text("hello") # 文本 +MessageSegment.image(file) # 图片(URL/路径/base64) +MessageSegment.record(file) # 语音 +MessageSegment.video(file) # 视频 +MessageSegment.at(user_id) # @某人 +MessageSegment.at_all() # @全体 +MessageSegment.reply(msg_id) # 回复 +MessageSegment.face(id) # QQ表情 +MessageSegment.poke(type, id) # 戳一戳 +MessageSegment.forward(id) # 转发消息 +MessageSegment.json(data) # JSON卡片 +MessageSegment.xml(data) # XML卡片 +MessageSegment.share(url, title) # 链接分享 +MessageSegment.music(type, id) # 音乐卡片 +MessageSegment.location(lat, lon) # 位置 +``` + +--- + +## 4. UniMessage(跨平台消息,nonebot-plugin-alconna) + +```python +UniMessage.text("hello") # 文本 +UniMessage.at("123456") # @某人 +UniMessage.at_all() # @全体 +UniMessage.image(url="...") # 图片 +UniMessage.audio(url="...") # 音频 +UniMessage.voice(url="...") # 语音 +UniMessage.video(url="...") # 视频 +UniMessage.file("id") # 文件 +UniMessage.reply("msg_id") # 回复 +UniMessage.emoji("id") # 表情 +``` + +**发送与操作:** +```python +await msg.send() # 发送 +await msg.send(at_sender=True) # @发送者 +await msg.send(reply_to=True) # 回复原消息 +await msg.finish() # 发送并结束 +receipt = await msg.send() # 获取回执 +await receipt.recall(delay=5) # 5秒后撤回 +await receipt.edit(UniMessage.text("新内容")) # 编辑 +await receipt.reaction("thumbsup") # 添加表情回应 +``` + +**序列化:** +```python +data = msg.dump() # 存储 +msg = UniMessage.load(data) # 还原 +``` + +--- + +# 二、OneBot V11 协议能力 + +## 1. 消息类 API + +| API | 参数 | 说明 | +|---|---|---| +| `send_msg` | `message_type`, `user_id`/`group_id`, `message` | 通用发送 | +| `send_private_msg` | `user_id`, `message` | 私聊发送 | +| `send_group_msg` | `group_id`, `message` | 群聊发送 | +| `delete_msg` | `message_id` | 撤回消息 | +| `get_msg` | `message_id` | 获取消息详情 | +| `get_forward_msg` | `id` | 获取转发消息内容 | + +## 2. 群管理 API + +| API | 参数 | 说明 | +|---|---|---| +| `set_group_kick` | `group_id`, `user_id`, `reject_add_request` | 踢出成员 | +| `set_group_ban` | `group_id`, `user_id`, `duration` | 禁言(0=解除) | +| `set_group_anonymous_ban` | `group_id`, `anonymous_flag`, `duration` | 禁言匿名 | +| `set_group_whole_ban` | `group_id`, `enable` | 全员禁言 | +| `set_group_admin` | `group_id`, `user_id`, `enable` | 设置/取消管理员 | +| `set_group_card` | `group_id`, `user_id`, `card` | 修改群名片 | +| `set_group_name` | `group_id`, `group_name` | 修改群名 | +| `set_group_leave` | `group_id`, `is_dismiss` | 退群/解散 | +| `set_group_special_title` | `group_id`, `user_id`, `special_title` | 设置群头衔 | +| `set_group_anonymous` | `group_id`, `enable` | 开关匿名聊天 | + +## 3. 请求处理 API + +| API | 参数 | 说明 | +|---|---|---| +| `set_friend_add_request` | `flag`, `approve`, `remark` | 好友申请 | +| `set_group_add_request` | `flag`, `sub_type`, `approve`, `reason` | 加群/邀请申请 | + +## 4. 信息查询 API + +| API | 参数 | 说明 | +|---|---|---| +| `get_login_info` | — | 获取登录信息 | +| `get_stranger_info` | `user_id`, `no_cache` | 获取陌生人信息 | +| `get_friend_list` | — | 获取好友列表 | +| `get_group_info` | `group_id`, `no_cache` | 获取群信息 | +| `get_group_list` | — | 获取群列表 | +| `get_group_member_info` | `group_id`, `user_id`, `no_cache` | 获取群成员信息 | +| `get_group_member_list` | `group_id` | 获取群成员列表 | +| `get_group_honor_info` | `group_id`, `type` | 获取群荣耀信息 | + +## 5. 社交 API + +| API | 参数 | 说明 | +|---|---|---| +| `send_like` | `user_id`, `times` | 点赞(最多10次/天) | + +## 6. 媒体 API + +| API | 参数 | 说明 | +|---|---|---| +| `get_image` | `file` | 获取图片文件 | +| `get_record` | `file`, `out_format` | 获取语音文件 | +| `can_send_image` | — | 检查能否发图 | +| `can_send_record` | — | 检查能否发语音 | + +## 7. 系统 API + +| API | 参数 | 说明 | +|---|---|---| +| `get_status` | — | 运行状态 | +| `get_version_info` | — | 版本信息 | +| `set_restart` | `delay` | 重启 | +| `clean_cache` | — | 清理缓存 | + +--- + +# 三、OneBot V11 事件类型 + +## 消息事件 + +| 事件类 | 关键字段 | +|---|---| +| `GroupMessageEvent` | `group_id`, `user_id`, `message_id`, `message`, `sender` | +| `PrivateMessageEvent` | `user_id`, `message_id`, `message`, `sender` | + +**GroupMessageEvent.sender 字段:** +```python +sender.user_id # QQ号 +sender.nickname # 昵称 +sender.card # 群名片 +sender.role # "owner" / "admin" / "member" +sender.title # 群头衔 +sender.sex # 性别 +sender.age # 年龄 +sender.area # 地区 +sender.level # 等级 +``` + +## 通知事件 + +| 事件类 | 关键字段 | 说明 | +|---|---|---| +| `PokeNotifyEvent` | `group_id`, `user_id`, `target_id` | 戳一戳 | +| `GroupIncreaseNoticeEvent` | `group_id`, `user_id`, `operator_id` | 成员加入 | +| `GroupDecreaseNoticeEvent` | `group_id`, `user_id`, `operator_id` | 成员离开 | +| `GroupBanNoticeEvent` | `group_id`, `user_id`, `operator_id`, `duration` | 禁言 | +| `GroupAdminNoticeEvent` | `group_id`, `user_id` | 管理员变动 | +| `GroupRecallNoticeEvent` | `group_id`, `user_id`, `operator_id`, `message_id` | 群消息撤回 | +| `FriendRecallNoticeEvent` | `user_id`, `message_id` | 私聊消息撤回 | +| `FriendAddNoticeEvent` | `user_id` | 好友添加 | +| `GroupUploadNoticeEvent` | `group_id`, `user_id`, `file` | 文件上传 | +| `GroupNotifyEvent` | `sub_type="lucky_king"` | 红包运气王 | +| `GroupNotifyEvent` | `sub_type="honor"` | 荣誉变更 | + +## 请求事件 + +| 事件类 | 关键字段 | 说明 | +|---|---|---| +| `FriendRequestEvent` | `user_id`, `comment`, `flag` | 好友申请 | +| `GroupRequestEvent` | `group_id`, `user_id`, `comment`, `flag`, `sub_type` | 加群/邀请申请 | + +## 元事件 + +| 事件类 | 说明 | +|---|---| +| `MetaEvent` (lifecycle) | 生命周期(enable/disable/connect) | +| `MetaEvent` (heartbeat) | 心跳 | + +--- + +# 四、HexiCore 封装建议 + +## 已有原生能力(无需封装,直接用) + +| 能力 | 原生用法 | +|---|---| +| 发消息 | `UniMessage.text("hello").send()` | +| 发图片 | `UniMessage.image(url="...").send()` | +| @某人 | `UniMessage.at("123").send()` | +| 回复消息 | `UniMessage.reply("msg_id").send()` | +| 撤回消息 | `bot.delete_msg(message_id=...)` | +| 禁言 | `bot.set_group_ban(group_id=..., user_id=..., duration=...)` | +| 踢人 | `bot.set_group_kick(group_id=..., user_id=...)` | +| 群名片 | `bot.set_group_card(group_id=..., user_id=..., card=...)` | +| 管理员 | `bot.set_group_admin(group_id=..., user_id=..., enable=...)` | +| 群头衔 | `bot.set_group_special_title(group_id=..., user_id=..., title=...)` | +| 好友申请 | `bot.set_friend_add_request(flag=..., approve=...)` | +| 加群申请 | `bot.set_group_add_request(flag=..., sub_type=..., approve=...)` | +| 判断群/私聊 | `isinstance(event, GroupMessageEvent)` | +| 获取发送者 | `event.sender.user_id` / `event.sender.nickname` | +| 获取群号 | `event.group_id` | +| 获取消息ID | `event.message_id` | +| 判断管理员 | `event.sender.role in ("admin", "owner")` | +| 判断超级用户 | `str(event.user_id) in driver.config.superusers` | +| 遍历消息段 | `for seg in event.message: ...` | +| 获取纯文本 | `event.get_plaintext()` | + +## 值得封装(原生用起来麻烦) + +### 1. 戳一戳(Poke) +```python +# 原生:需要知道 API 非标准 +await bot.call_api("send_poke", group_id=group_id, user_id=user_id) + +# HexiCore 封装:简化为 +await hexi.poke(group_id, user_id) +``` + +### 2. 合并转发消息 +```python +# 原生:需要手动构建 node 结构 +nodes = [ + {"type": "node", "data": {"user_id": "123", "nickname": "name", "content": [seg]}}, + ... +] +await bot.call_api("send_group_forward_msg", group_id=group_id, message=nodes) + +# HexiCore 封装:链式构建 +forward = hexi.forward() +forward.add("123", "name", UniMessage.text("内容")) +forward.add("456", "name2", UniMessage.image(url="...")) +await forward.send(group_id) +``` + +### 3. 消息加精 / 取消加精 +```python +# 原生:API 名称不直观 +await bot.call_api("set_msg_essence", message_id=msg_id) +await bot.call_api("delete_msg_essence", message_id=msg_id) + +# HexiCore 封装 +await hexi.essence(msg_id) # 加精 +await hexi.unessence(msg_id) # 取消 +``` + +### 4. 获取 At 用户列表 +```python +# 原生:需要遍历 +at_users = [seg.data["qq"] for seg in event.message if seg.type == "at"] + +# HexiCore 封装 +users = hexi.get_at_users(event) +``` + +### 5. 是否好友 / 是否群成员 +```python +# 原生:需要调用 API + 异常处理 +try: + await bot.get_stranger_info(user_id=user_id) + is_friend = True +except: + is_friend = False + +# HexiCore 封装 +is_friend = await hexi.is_friend(user_id) +is_member = await hexi.is_member(group_id, user_id) +``` + +### 6. 权限推断(可发送/可撤回/可禁言等) +```python +# 原生:没有直接 API,需要根据身份推断 +role = event.sender.role +can_ban = role in ("admin", "owner") # 但还需要检查机器人自身是否是管理员 + +# HexiCore 封装 +can_ban = await hexi.can_ban(group_id, user_id) # 检查目标是否可被禁言 +can_kick = await hexi.can_kick(group_id, user_id) # 检查目标是否可被踢 +``` + +### 7. 获取回复的原始消息 +```python +# 原生:event.reply 只有 message_id,需要再调 API 获取内容 +reply_msg = await bot.get_msg(message_id=event.reply.message_id) + +# HexiCore 封装 +reply_content = hexi.get_reply_content(event) # 直接返回 Message 对象 +``` + +### 8. 获取消息来源(群号/私聊) +```python +# 原生:需要类型判断 + 字段访问 +if isinstance(event, GroupMessageEvent): + source = event.group_id +elif isinstance(event, PrivateMessageEvent): + source = event.user_id + +# HexiCore 封装 +source = hexi.get_source(event) # 统一返回 +``` + +--- + +## 总结:HexiCore 定位 + +``` +HexiCore = 原生能力的便利封装层 + +目标:让业务层用一行代码完成需要写 3-5 行的操作 + +原则: +1. 不重复造轮子——原生好用的直接用 +2. 封装复杂 API 调用——简化参数、统一接口 +3. 提供便捷判断方法——省去类型检查和异常处理 +4. 保持轻量——只做薄封装,不改变底层行为 +``` diff --git a/hexi/plugins/nonebot_plugin_hexi_core/docs/清单.md b/hexi/plugins/nonebot_plugin_hexi_core/docs/清单.md new file mode 100644 index 0000000..ffb8405 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_hexi_core/docs/清单.md @@ -0,0 +1,156 @@ +# HexiCore 能力清单(精简版) + +> **设计目标** +> +> HexiCore 是原生能力的便利封装层,只封装「原生写起来麻烦」的操作。 +> 普通消息发送、构建、解析直接使用 Alconna UniMessage,不重复封装。 + +--- + +# 需要封装的能力 + +## 一、消息操作(简化 API 调用) + +| 能力 | 原生写法 | HexiCore 写法 | +|---|---|---| +| 戳一戳 | `bot.call_api("send_poke", group_id=..., user_id=...)` | `await hexi.poke(group_id, user_id)` | +| 消息加精 | `bot.call_api("set_msg_essence", message_id=...)` | `await hexi.essence(msg_id)` | +| 取消加精 | `bot.call_api("delete_msg_essence", message_id=...)` | `await hexi.unessence(msg_id)` | +| 合并转发 | 手动构建 node 结构 | `forward.add(user_id, nickname, content).send(group_id)` | + +--- + +## 二、信息提取(省去遍历/判断) + +| 能力 | 原生写法 | HexiCore 写法 | +|---|---|---| +| 获取 At 用户列表 | `[seg.data["qq"] for seg in event.message if seg.type == "at"]` | `hexi.get_at_users(event)` | +| 获取回复内容 | `bot.get_msg(message_id=event.reply.message_id)` | `hexi.get_reply_content(event)` | +| 获取消息来源 | 类型判断 + 字段访问 | `hexi.get_source(event)` | + +--- + +## 三、身份查询(需要 API 调用) + +| 能力 | 原生写法 | HexiCore 写法 | +|---|---|---| +| 是否好友 | `bot.get_stranger_info()` + 异常处理 | `await hexi.is_friend(user_id)` | +| 是否群成员 | `bot.get_group_member_info()` + 异常处理 | `await hexi.is_member(group_id, user_id)` | +| 获取群成员信息 | `bot.get_group_member_info()` | `await hexi.get_member_info(group_id, user_id)` | + +--- + +## 四、权限推断(原生无直接 API) + +| 能力 | 说明 | +|---|---| +| `hexi.can_ban(group_id, user_id)` | 检查目标是否可被禁言(机器人是管理员 + 目标不是群主) | +| `hexi.can_kick(group_id, user_id)` | 检查目标是否可被踢出 | +| `hexi.can_set_admin(group_id)` | 检查机器人是否有管理员权限 | +| `hexi.is_admin(user_id)` | 判断用户是否为管理员 | +| `hexi.is_owner(user_id)` | 判断用户是否为群主 | +| `hexi.is_superuser(user_id)` | 判断用户是否为超级用户 | + +--- + +## 五、批量操作(省去循环) + +| 能力 | 说明 | +|---|---| +| `hexi.ban_multi(group_id, user_ids, duration)` | 批量禁言 | +| `hexi.kick_multi(group_id, user_ids)` | 批量踢出 | + +--- + +# 不需要封装(直接用原生) + +| 类别 | 能力 | 原生用法 | +|---|---|---| +| 消息发送 | 文本/图片/语音/视频/文件 | `UniMessage.text/image/record/video/file().send()` | +| 消息发送 | @某人/@全体 | `UniMessage.at()/at_all().send()` | +| 消息发送 | 回复消息 | `UniMessage.reply(msg_id).send()` | +| 消息操作 | 撤回消息 | `bot.delete_msg(message_id=...)` | +| 群管理 | 禁言 | `bot.set_group_ban(group_id=..., user_id=..., duration=...)` | +| 群管理 | 踢人 | `bot.set_group_kick(group_id=..., user_id=...)` | +| 群管理 | 群名片 | `bot.set_group_card(group_id=..., user_id=..., card=...)` | +| 群管理 | 管理员 | `bot.set_group_admin(group_id=..., user_id=..., enable=...)` | +| 群管理 | 群头衔 | `bot.set_group_special_title(group_id=..., user_id=..., title=...)` | +| 群管理 | 群名 | `bot.set_group_name(group_id=..., group_name=...)` | +| 群管理 | 全员禁言 | `bot.set_group_whole_ban(group_id=..., enable=...)` | +| 请求处理 | 好友申请 | `bot.set_friend_add_request(flag=..., approve=...)` | +| 请求处理 | 加群申请 | `bot.set_group_add_request(flag=..., sub_type=..., approve=...)` | +| 事件判断 | 群/私聊消息 | `isinstance(event, GroupMessageEvent)` | +| 事件信息 | 发送者 | `event.sender.user_id` / `event.sender.nickname` | +| 事件信息 | 群号 | `event.group_id` | +| 事件信息 | 消息ID | `event.message_id` | +| 事件信息 | 纯文本 | `event.get_plaintext()` | +| 事件信息 | 消息段遍历 | `for seg in event.message: ...` | + +--- + +# 业务层调用示例 + +```python +from nonebot_plugin_alconna import UniMessage + +# 普通消息 — 直接用 UniMessage +await UniMessage.text("Hello").send() +await UniMessage.image(url="https://...").send() +await UniMessage.at("123456").text("你好").send() + +# 平台能力 — 用 HexiCore 封装 +await hexi.poke(group_id, user_id) # 戳一戳 +await hexi.essence(msg_id) # 加精 +await hexi.unessence(msg_id) # 取消加精 + +# 转发消息 — 链式构建 +forward = hexi.forward() +forward.add("123", "Alice", UniMessage.text("消息1")) +forward.add("456", "Bob", UniMessage.image(url="...")) +await forward.send(group_id) + +# 信息提取 — 一行搞定 +users = hexi.get_at_users(event) # At 用户列表 +reply = hexi.get_reply_content(event) # 回复内容 +source = hexi.get_source(event) # 消息来源 + +# 身份查询 — 异常处理已封装 +is_friend = await hexi.is_friend(user_id) # 是否好友 +is_member = await hexi.is_member(group_id, uid) # 是否群成员 +info = await hexi.get_member_info(group_id, uid)# 群成员信息 + +# 权限推断 — 自动检查机器人权限 +if await hexi.can_ban(group_id, user_id): + await bot.set_group_ban(group_id=group_id, user_id=user_id, duration=60) + +# 身份判断 +if hexi.is_admin(event): # 管理员 +if hexi.is_owner(event): # 群主 +if hexi.is_superuser(event): # 超级用户 +``` + +--- + +# 架构设计 + +``` +hexi/plugins/nonebot_plugin_hexi_core/ +├── __init__.py # 插件入口,导出 hexi 对象 +├── poke.py # 戳一戳 +├── forward.py # 合并转发消息构建器 +├── essence.py # 消息加精/取消 +├── extract.py # 消息提取(At列表、回复内容、来源) +├── member.py # 身份查询(好友、群成员) +├── permission.py # 权限推断(可禁言、可踢人等) +└── utils.py # 工具函数 +``` + +--- + +# 设计原则 + +1. **薄封装** — 每个函数只是对原生 API 的简化调用,不添加额外逻辑 +2. **类型安全** — 使用类型注解,配合 Pydantic 校验 +3. **异常处理** — 内部处理 API 异常,对外返回布尔值或 None +4. **单一职责** — 每个模块只负责一类能力 +5. **可选依赖** — 业务层可以选择用原生 API 或 HexiCore 封装 diff --git a/hexi/plugins/nonebot_plugin_hexi_core/message_handle.py b/hexi/plugins/nonebot_plugin_hexi_core/message_handle.py new file mode 100644 index 0000000..511b989 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_hexi_core/message_handle.py @@ -0,0 +1,43 @@ +from nonebot.adapters.onebot.v11 import MessageSegment + + +class TextMessage: + def __init__(self, text): + self.text = text + + +class ImageMessage: + def __init__(self, image): + self.image = image + + +class UnknownMessage: + def __init__(self, raw): + self.raw = raw + + +class MessageState: + def __init__(self, data_dict): + self.data_dict = data_dict + + # 获取命令头 + def get_command(self): + return self.data_dict['_prefix']['command'] + + # 获取回复 + def get_reply(self): + return self.data_dict['reply'] + + # 获取回复对象的文本 + + # 获取命令参数 + def get_command_arg(self): + command_arg_list = self.data_dict['_prefix']['command_arg'] + if command_arg_list: + command_arg = command_arg_list[0] + if isinstance(command_arg, MessageSegment): + if command_arg.type == 'text': + return TextMessage(command_arg.data['text']) + elif command_arg.type == 'image': + return ImageMessage(command_arg.data['url']) + return None # 返回 None 表示命令参数为空或无法解析 diff --git a/hexi/plugins/nonebot_plugin_hexi_core/message_utils.py b/hexi/plugins/nonebot_plugin_hexi_core/message_utils.py new file mode 100644 index 0000000..324e16e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_hexi_core/message_utils.py @@ -0,0 +1,110 @@ +from nonebot import get_bot +from nonebot import require +from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent, MessageSegment +from nonebot.log import logger + +require("nonebot_plugin_htmlrender") +from nonebot_plugin_htmlrender import md_to_pic + + +async def send_markdown( + bot: Bot, + event: MessageEvent, + markdown: str, + fallback_text: str | None = None, +) -> None: + """发送 Markdown + + 优先尝试 OneBot 后端的原生 markdown 消息段;后端不支持/失败时 + 自动降级为 htmlrender 把 Markdown 渲染成图片发送,保证任何后端都能看到。 + """ + # 1. 尝试原生 markdown 消息段(不同后端字段可能不同,失败自动降级) + try: + seg = MessageSegment("markdown", {"content": markdown}) + await bot.send(event=event, message=Message(seg)) + return + except Exception as e: + logger.warning(f"原生 markdown 发送失败,尝试降级为图片: {e}") + + # 2. 降级:htmlrender 渲染成图片 + try: + img = await md_to_pic(md=markdown, width=540, device_scale_factor=4) + await bot.send(event=event, message=MessageSegment.image(img)) + except Exception as e: + logger.error(f"Markdown 渲染图片失败,发送纯文本: {e}") + await bot.send(event=event, message=fallback_text or markdown) + + +async def send_poke(group_id: int | None = None, user_id: int = 0): + """发送戳一戳(OneBot V11 send_poke API) + + group_id 为空时向私聊发送戳一戳;失败返回 None + """ + bot = get_bot() + params = {"user_id": int(user_id)} + if group_id: + params["group_id"] = int(group_id) + logger.debug(f"send_poke: {params}") + try: + return await bot.call_api("send_poke", **params) + except Exception as e: + logger.error(f"send_poke 失败: {e}") + return None + + +def get_reply_message(event: MessageEvent) -> Message: + """获取消息内容:若为回复消息则返回被回复的消息,否则返回当前消息""" + if event.reply is not None: + logger.info(f"此条消息为回复消息: {event.reply.message}") + return event.reply.message + logger.info(f"此条消息为普通消息: {event.message}") + return event.message + + +def build_forward_nodes( + self_id: int, + entries: list[tuple[str, str]], + sender_name: str | None = None, +) -> list[dict]: + """构造合并转发节点列表 + + entries: [(发送者名, 消息内容), ...] + sender_name: 非空时所有节点统一使用该昵称(用于把插件名等放进 content, + 而不是作为转发节点的发送者昵称) + """ + return [ + { + "type": "node", + "data": { + "name": sender_name if sender_name is not None else name, + "uin": str(self_id), + "content": content, + }, + } + for name, content in entries + ] + + +async def send_forward_msg( + bot: Bot, + event: MessageEvent, + entries: list[tuple[str, str]], + fallback: str, + sender_name: str | None = None, +): + """群聊发送合并转发消息,私聊或发送失败时回退纯文本 + + entries: [(发送者名, 消息内容), ...] + sender_name: 非空时统一用于节点发送者昵称(插件名等应写入 content) + """ + group_id = getattr(event, "group_id", None) + if group_id: + try: + await bot.send_group_forward_msg( + group_id=group_id, + messages=build_forward_nodes(event.self_id, entries, sender_name), + ) + return + except Exception as e: + logger.warning(f"合并转发发送失败,回退文本: {e}") + await bot.send(event, fallback) diff --git a/hexi/plugins/nonebot_plugin_hexi_core/plugin_control.py b/hexi/plugins/nonebot_plugin_hexi_core/plugin_control.py new file mode 100644 index 0000000..7d399a4 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_hexi_core/plugin_control.py @@ -0,0 +1,250 @@ +# -*- coding: utf-8 -*- +"""所有插件上层的 filter 规则:全局启用 + 分群控制 + 群聊/私聊使用控制。 + +设计: +- 以「插件模块名(含 __plugin_meta__ 的包根)」为稳定 identifier。 +- 两层状态存 hexi/data/plugin_control.json: + { + "": { + "global": {"enabled": true, "chat": ["group","private"]}, + "groups": {"": {"enabled": true, "chat": ["group"]}} + } + } +- 默认(未受管插件)全部放行,仅受管的做过滤,避免误伤。 +- 通过往 NoneBot matcher 注册表里每个 application 插件 matcher 的 + rule 追加一个 gate checker(Rule &),实现「在所有插件之上」的统一闸门。 +- 启动时 instrument_plugin_gate() 扫一次;热加载/热重载后再扫一次。 +""" + +from __future__ import annotations + +import json +import sys +from pathlib import Path +from typing import Any, Optional + +from nonebot import get_loaded_plugins, logger +from nonebot.internal.matcher import matchers as matchers_registry +from nonebot.rule import Rule + +_PLUGIN_ROOT = Path(__file__).resolve().parents[2] # hexi/ +DATA_DIR = _PLUGIN_ROOT / "data" +STORE_PATH = DATA_DIR / "plugin_control.json" + +DEFAULT_CHAT = ["group", "private"] + +# matcher 被注入后打标,避免重复叠加 gate checker +_GATE_ATTR = "_hexi_plugin_gate_applied" + + +def _default_level() -> dict[str, Any]: + return {"enabled": True, "chat": list(DEFAULT_CHAT)} + + +def _default_entry() -> dict[str, Any]: + return {"global": _default_level(), "groups": {}} + + +_controls: dict[str, dict[str, Any]] = {} + + +def load() -> None: + """从磁盘加载控制面状态(幂等)。""" + global _controls + if STORE_PATH.exists(): + try: + data = json.loads(STORE_PATH.read_text(encoding="utf-8")) + _controls = data if isinstance(data, dict) else {} + except Exception as e: # noqa: BLE001 + logger.warning(f"加载插件控制配置失败: {type(e).__name__}: {e}") + _controls = {} + else: + _controls = {} + + +def save() -> None: + """持久化控制面状态。""" + DATA_DIR.mkdir(parents=True, exist_ok=True) + STORE_PATH.write_text( + json.dumps(_controls, ensure_ascii=False, indent=2), encoding="utf-8" + ) + + +def _norm_level(level: Optional[dict[str, Any]]) -> dict[str, Any]: + lvl = _default_level() + if level: + if "enabled" in level: + lvl["enabled"] = bool(level["enabled"]) + chat = level.get("chat") + if isinstance(chat, list) and chat: + # 只保留合法值 + lvl["chat"] = [c for c in chat if c in {"group", "private"}] or DEFAULT_CHAT + return lvl + + +def get_plugin_control(plugin_id: str) -> dict[str, Any]: + """返回某插件的控制配置(含 global + groups),未受管返回默认全放行。""" + entry = _controls.get(plugin_id) + if not entry: + return { + "global": _default_level(), + "groups": {}, + "managed": False, + } + return { + "global": _norm_level(entry.get("global")), + "groups": { + str(gid): _norm_level(level) for gid, level in (entry.get("groups") or {}).items() + }, + "managed": True, + } + + +def set_global( + plugin_id: str, enabled: Optional[bool] = None, chat: Optional[list[str]] = None +) -> dict[str, Any]: + """设置全局开关/聊天类型,返回最新控制配置。""" + entry = _controls.setdefault(plugin_id, _default_entry()) + level = _norm_level(entry.get("global")) + if enabled is not None: + level["enabled"] = bool(enabled) + if chat is not None: + level["chat"] = [c for c in chat if c in {"group", "private"}] or DEFAULT_CHAT + entry["global"] = level + save() + return get_plugin_control(plugin_id) + + +def set_group( + plugin_id: str, + group_id: str, + enabled: Optional[bool] = None, + chat: Optional[list[str]] = None, +) -> dict[str, Any]: + """设置某群对某插件的开关/聊天类型,返回最新控制配置。""" + entry = _controls.setdefault(plugin_id, _default_entry()) + groups = entry.setdefault("groups", {}) + gid = str(group_id) + level = _norm_level(groups.get(gid)) + if enabled is not None: + level["enabled"] = bool(enabled) + if chat is not None: + level["chat"] = [c for c in chat if c in {"group", "private"}] or DEFAULT_CHAT + groups[gid] = level + save() + return get_plugin_control(plugin_id) + + +def remove_group(plugin_id: str, group_id: str) -> dict[str, Any]: + """移除某群覆盖(回到继承全局)。""" + entry = _controls.get(plugin_id) + if entry: + entry.get("groups", {}).pop(str(group_id), None) + save() + return get_plugin_control(plugin_id) + + +def remove_plugin(plugin_id: str) -> None: + """清空某插件所有覆盖,恢复默认放行。""" + _controls.pop(plugin_id, None) + save() + + +def list_plugins() -> list[dict[str, Any]]: + """枚举所有 application 插件(或注册了配置 schema 的插件)及其控制面状态。""" + from nonebot.plugin import get_loaded_plugins + from hexi.web_config import has_schema + + result: list[dict[str, Any]] = [] + seen: set[str] = set() + for p in get_loaded_plugins(): + mod = p.module_name + if mod in seen: + continue + seen.add(mod) + meta = p.metadata + if not meta: + continue + if meta.type != "application" and not has_schema(mod): + continue + ctl = get_plugin_control(mod) + result.append( + { + "id": mod, + "name": meta.name, + "description": meta.description or "", + "usage": meta.usage or "", + "enabled": ctl["global"]["enabled"], + "chat": ctl["global"]["chat"], + "groups": {gid: lvl for gid, lvl in ctl["groups"].items()}, + "managed": ctl["managed"], + } + ) + result.sort(key=lambda x: x["name"]) + return result + + +def _resolve_plugin_id(module_name: str) -> Optional[str]: + """把 matcher 的模块名回溯到带 __plugin_meta__ / NoneBot 注册表的插件根模块。""" + parts = module_name.split(".") + for i in range(len(parts), 0, -1): + cand = ".".join(parts[:i]) + for p in get_loaded_plugins(): + if p.module_name == cand: + return cand + mod = sys.modules.get(cand) + if mod is not None and getattr(mod, "__plugin_meta__", None) is not None: + return cand + return None + + +def _gate_checker(plugin_id: str): + """为单个插件生成一个异步 rule checker(读控制面状态)。""" + + async def _check(bot, event, state) -> bool: # noqa: ANN001 + return _allowed(plugin_id, event) + + return _check + + +def _allowed(plugin_id: str, event) -> bool: + """决定某事件是否允许进入该插件。""" + cfg = get_plugin_control(plugin_id) + is_group = getattr(event, "message_type", "") == "group" or ( + getattr(event, "group_id", None) is not None + ) + if is_group: + gid = str(getattr(event, "group_id", "") or "") + gcfg = cfg["groups"].get(gid) + level = gcfg if gcfg is not None else cfg["global"] + else: + level = cfg["global"] + if not level["enabled"]: + return False + chat_type = "group" if is_group else "private" + return chat_type in level["chat"] + + +def instrument_plugin_gate() -> int: + """给所有 application 插件 matcher 追加统一 gate 规则,返回注入数量。""" + count = 0 + for group in matchers_registry.values(): + for matcher in group: + if getattr(matcher, _GATE_ATTR, False): + continue + mod = getattr(matcher, "module_name", None) + if not mod: + continue + pid = _resolve_plugin_id(mod) + if not pid: + continue + checker = Rule(_gate_checker(pid)) + current = getattr(matcher, "rule", None) + matcher.rule = checker if current is None else current & checker + setattr(matcher, _GATE_ATTR, pid) + count += 1 + return count + + +# 导入时加载状态(幂等,可重复调用 load() 刷新) +load() diff --git a/hexi/plugins/nonebot_plugin_hexi_core/plugin_manager.py b/hexi/plugins/nonebot_plugin_hexi_core/plugin_manager.py new file mode 100644 index 0000000..52e4ac3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_hexi_core/plugin_manager.py @@ -0,0 +1,308 @@ +"""插件热插拔管理:运行时加载/卸载/重载插件(仅超管) + +通过直接导入模块并自行维护注册表,绕开 NoneBot PluginManager 的 +重复检查限制(load_plugin 每次都会向全局 _managers 追加 manager, +重复加载会触发 "Plugin already exists" 错误)。 +""" + +import importlib +import sys +from types import ModuleType + +from nonebot import get_driver, logger, on_command, on_message, require +from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent +from nonebot.internal.matcher import matchers as matchers_registry +from nonebot.params import CommandArg +from nonebot.permission import SUPERUSER +from nonebot.plugin import ( + Plugin, + PluginMetadata, + _plugins, + get_loaded_plugins, + get_plugin_by_module_name, +) +from nonebot.rule import Rule, to_me + +require("nonebot_plugin_alconna") +from nonebot_plugin_alconna import UniMessage + +from hexi.plugins.nonebot_plugin_hexi_core.message_utils import send_forward_msg +from . import plugin_control + +__plugin_meta__ = PluginMetadata( + name="插件管理", + description="热插拔插件:运行时加载/卸载/重载插件(仅超管)", + usage="插件列表 / 加载插件 <模块名> / 卸载插件 <模块名> / 重载插件 <模块名>", + type="application", +) + +def _forward_sender_name() -> str: + """合并转发节点的发送者昵称(用机器人配置昵称,插件名写进 content)""" + nickname = get_driver().config.nickname + return next(iter(nickname), "Bot") if nickname else "Bot" + + +def _match_help(event: MessageEvent) -> bool: + """匹配 help/帮助/菜单 开头(支持 at bot 后跟命令,可带插件名参数) + + on_command 的命令规则只匹配第一段为文本的消息, + "at bot + help" 第一段是 at 段无法触发,故用 on_message 自定义规则。 + """ + text = event.message.extract_plain_text().strip() + return text in ("help", "帮助", "菜单") or text.startswith( ("help ", "帮助 ", "菜单 ") + ) + + +help_cmd = on_message(rule=Rule(_match_help) & to_me(), block=True) +plugin_list_cmd = on_command("插件列表", permission=SUPERUSER, block=True) +plugin_load_cmd = on_command("加载插件", permission=SUPERUSER, block=True) +plugin_unload_cmd = on_command("卸载插件", permission=SUPERUSER, block=True) +plugin_reload_cmd = on_command("重载插件", permission=SUPERUSER, block=True) + +# 自管理的热插拔插件注册表:模块名 -> 模块 +_hot_plugins: dict[str, ModuleType] = {} + + +def _registered_matchers(module_name: str) -> list: + """获取某模块注册的全部 matcher(含子模块,注册表按优先级分组)""" + return [ + m + for group in matchers_registry.values() + for m in group + if getattr(m, "module_name", None) + and ( + m.module_name == module_name + or m.module_name.startswith(module_name + ".") + ) + ] + + +def _collect_module_names(plugin: Plugin) -> list[str]: + """收集插件及其全部子插件的模块名(用于查 matcher 与清缓存)""" + names = [plugin.module_name] + for sub in plugin.sub_plugins: + names.extend(_collect_module_names(sub)) + return names + + +def _unregister_plugin(plugin: Plugin) -> None: + """从 NoneBot 插件注册表移除插件(递归移除子插件)""" + for sub in list(plugin.sub_plugins): + _unregister_plugin(sub) + _plugins.pop(plugin.id_, None) + if parent := plugin.parent_plugin: + parent.sub_plugins.discard(plugin) + + +def hot_load(name: str) -> bool: + """热加载插件模块(直接 import,matcher 随之注册)""" + if name in _hot_plugins: + return False + if any(p.module_name == name for p in get_loaded_plugins()): + return False + importlib.import_module(name) + _hot_plugins[name] = sys.modules[name] + logger.info(f"插件已热加载: {name}") + try: + plugin_control.instrument_plugin_gate() + except Exception as e: # noqa: BLE001 + logger.warning(f"热加载后注入 gateway 失败: {type(e).__name__}: {e}") + return True + + +def hot_unload(name: str) -> bool: + """热卸载插件:移除 matcher、清理 NoneBot 注册表与模块缓存 + + 不限于热加载的插件:启动时加载的插件(hexi/plugins 与 pyproject.toml + 声明)同样支持卸载,以 NoneBot 插件注册表为准查找。 + """ + plugin = get_plugin_by_module_name(name) + if plugin is None and name not in _hot_plugins: + return False + + module_names = _collect_module_names(plugin) if plugin else [name] + + for mod_name in module_names: + for m in _registered_matchers(mod_name): + group = matchers_registry.get(m.priority) + if group and m in group: + group.remove(m) + if plugin is not None: + _unregister_plugin(plugin) + + # 清理模块缓存(含子模块),保证重载拿到新模块 + for mod_name in [ + n + for n in sys.modules + if any(n == base or n.startswith(base + ".") for base in module_names) + ]: + sys.modules.pop(mod_name, None) + # 清理自管理注册表(含以子模块名登记的情况) + for key in list(_hot_plugins): + if any(key == base or key.startswith(base + ".") for base in module_names): + _hot_plugins.pop(key, None) + + logger.info(f"插件已热卸载: {name}") + return True + + +def hot_reload(name: str) -> bool: + """热重载插件:先卸载再加载""" + hot_unload(name) + return hot_load(name) + + +def _plugin_owner(mod_name: str) -> tuple[str, object] | None: + """找到模块归属的插件(自身或回溯父包直到有 meta),返回 (归属模块名, meta)""" + parts = mod_name.split(".") + for i in range(len(parts), 0, -1): + cand = ".".join(parts[:i]) + # 优先 NoneBot 注册表中的 metadata + for p in get_loaded_plugins(): + if p.module_name == cand: + meta = p.metadata + break + else: + module = sys.modules.get(cand) + meta = getattr(module, "__plugin_meta__", None) if module else None + if meta is not None: + return cand, meta + return None + + +def _visible_plugins() -> list[tuple[str, object]]: + """可显示的应用型插件列表 [(模块名, meta), ...] + + 以全局 matcher 注册表为准(正规插件、hexi_core 子模块、热加载插件一网打尽), + 子模块 matcher 回溯到所属插件包,仅保留 type='application',排除 alconna 等 library。 + """ + seen: dict[str, object] = {} + for group in matchers_registry.values(): + for m in group: + mod = getattr(m, "module_name", None) + if not mod: + continue + owner = _plugin_owner(mod) + if owner and owner[0] not in seen: + seen[owner[0]] = owner[1] + result = [] + for mod in sorted(seen): + meta = seen[mod] + if meta.type != "application": + continue + result.append((mod, meta)) + return result + + +def _find_plugin(name: str): + """按 模块名/meta名(含模糊) 查找应用型插件的 meta""" + for mod, meta in _visible_plugins(): + if mod == name or meta.name == name or name in meta.name: + return meta + return None + + +@help_cmd.handle() +async def help_handle(bot: Bot, ev: MessageEvent): + text = ev.message.extract_plain_text().strip() + # 提取插件名参数 + arg = "" + for kw in ("help", "帮助", "菜单"): + if text.startswith(kw): + arg = text[len(kw) :].strip() + break + + if arg: + # 单插件详细帮助 + meta = _find_plugin(arg) + if meta is None: + await UniMessage.text( + f"未找到插件「{arg}」,发送「帮助」查看所有插件" + ).send() + return + content = f"【{meta.name}】{meta.description}" + if meta.usage: + content += f"\n{meta.usage}" + await send_forward_msg( + bot, ev, [(meta.name, content)], content, + sender_name=_forward_sender_name(), + ) + return + + # 总览(仅显示有触发命令的应用型插件,内容以插件名开头) + entries: list[tuple[str, str]] = [] + fallback_lines = ["===== 插件菜单 ====="] + for _, meta in _visible_plugins(): + content = f"【{meta.name}】{meta.description}" + entries.append((meta.name, content)) + fallback_lines.append(content) + entries.append(("提示", "发送「帮助 插件名」查看插件详细用法")) + fallback_lines.append("发送「帮助 插件名」查看插件详细用法") + await send_forward_msg( + bot, ev, entries, "\n".join(fallback_lines), + sender_name=_forward_sender_name(), + ) + + +@plugin_list_cmd.handle() +async def plugin_list_handle(bot: Bot, ev: MessageEvent): + entries: list[tuple[str, str]] = [] + fallback_lines = ["已加载插件:"] + for mod, meta in _visible_plugins(): + content = f"{meta.name}\n{mod}" + entries.append((meta.name, content)) + fallback_lines.append(content) + await send_forward_msg( + bot, ev, entries, "\n".join(fallback_lines), + sender_name=_forward_sender_name(), + ) + + +@plugin_load_cmd.handle() +async def plugin_load_handle(ev: MessageEvent, arg: Message = CommandArg()): + name = arg.extract_plain_text().strip() + if not name: + await UniMessage.text( + "用法:加载插件 <模块名>,如 hexi.plugins.nonebot_plugin_dice" + ).send() + return + try: + if hot_load(name): + await UniMessage.text(f"插件 {name} 加载成功").send() + else: + await UniMessage.text(f"插件 {name} 已加载或模块不存在").send() + except Exception as e: + logger.error(f"加载插件 {name} 失败", exc_info=True) + await UniMessage.text(f"加载失败: {type(e).__name__}: {e}").send() + + +@plugin_unload_cmd.handle() +async def plugin_unload_handle(ev: MessageEvent, arg: Message = CommandArg()): + name = arg.extract_plain_text().strip() + if not name: + await UniMessage.text( + "用法:卸载插件 <模块名>,如 hexi.plugins.nonebot_plugin_dice" + ).send() + return + if hot_unload(name): + await UniMessage.text(f"插件 {name} 已卸载").send() + else: + await UniMessage.text(f"未找到插件 {name}(未加载或模块名有误)").send() + + +@plugin_reload_cmd.handle() +async def plugin_reload_handle(ev: MessageEvent, arg: Message = CommandArg()): + name = arg.extract_plain_text().strip() + if not name: + await UniMessage.text( + "用法:重载插件 <模块名>,如 hexi.plugins.nonebot_plugin_dice" + ).send() + return + try: + if hot_reload(name): + await UniMessage.text(f"插件 {name} 重载成功").send() + else: + await UniMessage.text(f"插件 {name} 重载失败(模块不存在)").send() + except Exception as e: + logger.error(f"重载插件 {name} 失败", exc_info=True) + await UniMessage.text(f"重载失败: {type(e).__name__}: {e}").send() diff --git a/hexi/plugins/nonebot_plugin_hexi_core/rate_limit.py b/hexi/plugins/nonebot_plugin_hexi_core/rate_limit.py new file mode 100644 index 0000000..509da71 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_hexi_core/rate_limit.py @@ -0,0 +1,181 @@ +"""限频器(令牌桶):为依赖外部 API 的插件限速,避免请求过频被限流返回 403/429 + +纯逻辑实现,不依赖 NoneBot 运行时;同步(requests)与异步(httpx/aiohttp)均可用。 + +用法: + from hexi.plugins.nonebot_plugin_hexi_core import rate_limit + + # 异步请求前取令牌(无令牌时等待,最多等 timeout 秒,超时返回 False) + if not await rate_limit.acquire("steam", rate=1, capacity=2): + await UniMessage.text("查询太频繁了,歇会儿再来~").send() + return + + # 同步请求前取令牌(不等待,超限立即失败) + if not rate_limit.acquire_sync("bf_api", rate=0.5, wait=False): + return "请求过于频繁,请稍后再试" + + # 拿到响应后检测是否被限流(403/429),可据此告警或退避 + if rate_limit.is_ratelimited(resp.status_code): + ... +""" + +import asyncio +import threading +import time + +from nonebot.log import logger + +# 常见限流状态码:403(服务端按频率拒绝)与 429(Too Many Requests) +_RATE_LIMIT_CODES = frozenset({403, 429}) + + +class RateLimiter: + """令牌桶限频器 + + - rate: 每秒补充的令牌数;capacity: 桶容量(最大突发),默认取 max(rate, 1) + - 惰性补充:按距上次取令牌的时间差计算补充量,无需后台任务 + - 线程安全:临界区用 threading.Lock 保护,同步/异步调用可并发使用 + """ + + def __init__(self, rate: float, capacity: int | None = None): + if rate <= 0: + raise ValueError(f"rate 必须大于 0,收到 {rate!r}") + if capacity is not None and capacity < 1: + raise ValueError(f"capacity 必须 >= 1,收到 {capacity!r}") + self._rate = float(rate) + self._capacity = float(capacity if capacity is not None else max(rate, 1)) + self._tokens = self._capacity + self._last_refill = time.monotonic() + self._lock = threading.Lock() + + def _refill(self) -> None: + """按经过的时间补充令牌(调用方需持有 _lock)""" + now = time.monotonic() + self._tokens = min( + self._capacity, self._tokens + (now - self._last_refill) * self._rate + ) + self._last_refill = now + + def try_acquire(self) -> bool: + """尝试取 1 个令牌:有则立即成功,无则返回 False(不阻塞)""" + with self._lock: + self._refill() + if self._tokens >= 1: + self._tokens -= 1 + return True + return False + + def remaining_secs(self) -> float: + """距下一个令牌可用的秒数;0 表示当前有令牌可用(不消费令牌)""" + with self._lock: + self._refill() + return max(0.0, (1.0 - self._tokens) / self._rate) + + def _wait_secs(self, deadline: float | None) -> float: + """计算距下次尝试还需等待的秒数;已超时返回 -1 表示放弃""" + with self._lock: + self._refill() + need = max(1.0 - self._tokens, 0.0) / self._rate + if deadline is not None: + remaining = deadline - time.monotonic() + if remaining <= 0: + return -1.0 + need = min(need, remaining) + return need + + async def acquire(self, timeout: float | None = None) -> bool: + """异步取 1 个令牌:无令牌时 asyncio.sleep 等待补充(不阻塞事件循环) + + timeout 为 None 时无限等待;超时返回 False + """ + deadline = None if timeout is None else time.monotonic() + timeout + while True: + if self.try_acquire(): + return True + wait = self._wait_secs(deadline) + if wait < 0: + return False + await asyncio.sleep(wait) + + def acquire_sync(self, timeout: float | None = None) -> bool: + """同步取 1 个令牌:无令牌时 time.sleep 等待补充(阻塞当前线程) + + timeout 为 None 时无限等待;超时返回 False + """ + deadline = None if timeout is None else time.monotonic() + timeout + while True: + if self.try_acquire(): + return True + wait = self._wait_secs(deadline) + if wait < 0: + return False + time.sleep(wait) + + +# 按名称共享的限频器注册表:同名(如同一外部 API)的所有插件共用同一配额 +_limiters: dict[str, RateLimiter] = {} +_registry_lock = threading.Lock() + + +def get_limiter(name: str, rate: float, capacity: int | None = None) -> RateLimiter: + """获取(或创建)指定名称的限频器,同名共享同一配额 + + 首次创建后,后续调用若 rate/capacity 与已有实例不一致会告警(以先创建者为准)。 + """ + with _registry_lock: + limiter = _limiters.get(name) + if limiter is None: + limiter = RateLimiter(rate, capacity) + _limiters[name] = limiter + logger.debug( + f"限频器已创建: {name}" + f"(rate={limiter._rate}, capacity={limiter._capacity})" + ) + elif (limiter._rate, limiter._capacity) != ( + float(rate), + float(capacity if capacity is not None else max(rate, 1)), + ): + logger.warning( + f"限频器 {name} 已存在(rate={limiter._rate}, " + f"capacity={limiter._capacity}),本次参数被忽略" + ) + return limiter + + +async def acquire( + name: str, + rate: float, + capacity: int | None = None, + *, + wait: bool = True, + timeout: float | None = None, +) -> bool: + """异步限频入口:获取(或创建)名为 name 的限频器并取令牌 + + wait=True 时等待令牌(最多 timeout 秒,None 为无限); + wait=False 时超限立即返回 False。 + """ + limiter = get_limiter(name, rate, capacity) + if not wait: + return limiter.try_acquire() + return await limiter.acquire(timeout) + + +def acquire_sync( + name: str, + rate: float, + capacity: int | None = None, + *, + wait: bool = True, + timeout: float | None = None, +) -> bool: + """同步限频入口(requests 等阻塞调用):语义同 acquire()""" + limiter = get_limiter(name, rate, capacity) + if not wait: + return limiter.try_acquire() + return limiter.acquire_sync(timeout) + + +def is_ratelimited(status_code: int | None) -> bool: + """判断 HTTP 状态码是否为限流响应(403 或 429)""" + return status_code in _RATE_LIMIT_CODES diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/dictionary.json b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/dictionary.json new file mode 100644 index 0000000..4331ad0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/dictionary.json @@ -0,0 +1,38 @@ +{ + "a": "ei", + "b": "bi", + "c": "xi", + "d": "di", + "e": "yi", + "f": "ai fu", + "g": "ji", + "h": "ai chi", + "i": "ai", + "j": "zhei", + "k": "kei", + "l": "ai lu", + "m": "ai mu", + "n": "en", + "o": "ou", + "p": "pi", + "q": "kiu", + "r": "a", + "s": "ai si", + "t": "ti", + "u": "you", + "v": "wei", + "w": "da bu liu", + "x": "ai ke si", + "y": "wai", + "z": "zei", + "0": "ling", + "1": "yi", + "2": "er", + "3": "san", + "4": "si", + "5": "wu", + "6": "liu", + "7": "qi", + "8": "ba", + "9": "jiu" +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/huoZiYinShua.py b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/huoZiYinShua.py new file mode 100644 index 0000000..fcf5327 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/huoZiYinShua.py @@ -0,0 +1,254 @@ +# -*- coding: UTF-8 -*- +#鬼畜音源的活字印刷 +#作者:DSP_8192 + +import soundfile as sf +import psola +import numpy as np +from pypinyin import lazy_pinyin +import json +from pathlib import Path +from io import BytesIO +import base64 + + + + +#-------------------------------------------- +#全局变量 +#-------------------------------------------- +#目标采样率 +_targetSR = 44100 + + + + +#-------------------------------------------- +#自定义函数 +#-------------------------------------------- +#文件路径转文件夹路径 +def _fileName2FolderName(fileName): + for i in range(len(fileName)-1, -1, -1): + if fileName[i] == '\\' or fileName[i] == '/': + return fileName[0:i+1] + + + +#标准化音频,统一音量 +def _normalizeAudio(data): + rms = np.sqrt(np.mean(data**2)) + normData = data / rms * 0.2 + return normData + + + +#读取音频文件 +def _loadAudio(fileDir, norm): + data, sampleRate = sf.read(fileDir) + #双声道转单声道 + if (len(data.shape) == 2): + #左右声道相加除以2 + data = (data[:, 0] + data[:, 1]) / 2 + #统一采样率 + if (sampleRate != _targetSR): + #计算转换后的长度 + newLength = int((_targetSR / sampleRate) * len(data)) + #转换 + data = np.interp(np.array(range(newLength)), np.linspace(0,newLength-1,len(data)), data) + #标准化 + if norm: + data = _normalizeAudio(data) + return data + + + +#改变音高和速度 +def _modifyPitchAndSpeed(data, pitchMultiple, speedMultiple): + if (pitchMultiple == 1 and speedMultiple == 1): + #没有改动的必要,直接返回 + return data + + elif (pitchMultiple > 2 or speedMultiple < 0.5): + print("过于极端的音调和速度参数可能导致输出结果与预期不符,故不作改动") + return data + + else: + #第一次拉伸 + if (speedMultiple / pitchMultiple == 1): + #没有拉伸的必要 + step1 = data + else: + #不改变音高的同时在时间上拉伸(PSOLA) + #constant_stretch过小会导致bug,因此分两次拉伸 + step1 = psola.vocode(data, _targetSR, constant_stretch=1/pitchMultiple) + step1 = psola.vocode(step1, _targetSR, constant_stretch=speedMultiple) + #第二次拉伸,以改变音高的方式拉伸回来 + newLength = int(len(data) / speedMultiple) + step2 = np.interp(np.array(range(newLength)), np.linspace(0,newLength-1,len(step1)), step1) + return step2 + + + + +#-------------------------------------------- +#活字印刷类 +#-------------------------------------------- +class huoZiYinShua: + def __init__(self, configuration): + try: + #读取设置文件 + dictFile = open(configuration["dictFile"], encoding="utf8") #读取单字词典 (json) + ysddTableFile = open(configuration["ysddTableFile"], encoding="utf8") #读取原声大碟文本与文件名对照表 (json) + + self.__voicePath = configuration["sourceDirectory"] #单字音频文件存放目录 + self.__ysddPath = configuration["ysddSourceDirectory"] #原声大碟音频文件存放目录 + self.__dictionary = json.load(dictFile) #定义非中文字符读法的词典 + self.__ysddTable = json.load(ysddTableFile) #原声大碟文本与文件名对照表 + + #统一为小写 + dictItems = list(self.__ysddTable.items()) + #转换为list是为了切断dictItems与self.__ysddTable的联系,否则报错dictionary changed size during iteration + for i in dictItems: + self.__ysddTable[i[0].lower()] = self.__ysddTable.pop(i[0]) + #从长到短排序,越长片段优先级越高 + self.__ysddTable = sorted(self.__ysddTable.items(), + key=lambda x:len(x[0]), + reverse=True) + self.__ysddTable = dict(self.__ysddTable) + + self.__configSucceed = True + + except Exception as e: + self.__configSucceed = False + print(e) + + + + #配置是否成功 + def configSucceed(self): + return self.__configSucceed + + + + + #返回b64音频 + def export(self, rawData, inYsddMode=False, + pitchMult=1, speedMult=1, norm=False, reverse=False): + self.__concatenate(rawData, inYsddMode, pitchMult, speedMult, norm, reverse) + base64_data = base64.b64encode(self.__export().getvalue()) + return base64_data + + + + #生成中间文件 + def __concatenate(self, rawData, inYsddMode, pitchMult, speedMult, norm, reverse): + missingPinyin = [] + self.__concatenated = np.array([]) + + #预处理,转为小写 + rawData = rawData.lower() + pronunciations = [] + + #分割使用活字印刷的部分和使用原声大碟的部分 + splitted = [[rawData, False]] #[文本, 是否使用原声大碟] + #遍历要匹配的句子 + if inYsddMode: + for ysdd in self.__ysddTable.items(): + #遍历文本 + i = -1 + while i < (len(splitted) - 1): + i += 1 + if splitted[i][1]: #已经被划分为原声大碟部分 + continue + #存在匹配 + if ysdd[0] in splitted[i][0]: + indexBegin = splitted[i][0].index(ysdd[0]) #获取开始位置 + #分割 + splitted.insert(i+1, [splitted[i][0][indexBegin:indexBegin+len(ysdd[0])], True]) + splitted.insert(i+2, [splitted[i][0][indexBegin+len(ysdd[0]):], False]) + splitted[i][0] = splitted[i][0][0:indexBegin] + + + #转换自定义的字符 + for i in range(0, len(splitted)): + pronunciations.append([]) + #使用活字印刷 + if (not splitted[i][1]): + pronunciations[i].append("") + for ch in splitted[i][0]: + if ch in self.__dictionary: + #词典中存在匹配,转换 + pronunciations[i][0] += self.__dictionary[ch] + " " + else: + #保持不变 + pronunciations[i][0] += ch + " " + pronunciations[i].append(False) #标记 + #使用原声大碟 + else: + pronunciations[i].append(splitted[i][0]) #直接复制 + pronunciations[i].append(True) #标记 + + + #拼接音频 + for i in range(0, len(pronunciations)): + #使用活字印刷 + if (not pronunciations[i][1]): + #将汉字转换成拼音 + pinyin = lazy_pinyin(pronunciations[i][0]) + #拆成单独的字 + for text in pinyin: + for word in text.split(): + #拼接每一个字 + try: + self.__concatenated = np.concatenate((self.__concatenated, + _loadAudio(self.__voicePath + + word + ".wav", + norm))) + #如果出现错误 + except Exception as e: + if word != ",": + print(e) #显示错误信息 + #加入缺失素材列表 + if word not in missingPinyin: + missingPinyin.append(word) + #以空白音频代替 + self.__concatenated = np.concatenate((self.__concatenated, + np.zeros(int(_targetSR/4)))) + + #使用原声大碟 + else: + #拼接 + try: + self.__concatenated = np.concatenate((self.__concatenated, + _loadAudio(self.__ysddPath + + self.__ysddTable[pronunciations[i][0]], + norm))) + #如果出现错误 + except Exception as e: + print(e) #显示错误信息 + #加入缺失素材列表 + if self.__ysddTable[pronunciations[i][0]] not in missingPinyin: + missingPinyin.append(self.__ysddTable[pronunciations[i][0]]) + #以空白音频代替 + self.__concatenated = np.concatenate((self.__concatenated, + np.zeros(int(_targetSR/4)))) + + + #音高偏移 + self.__concatenated = _modifyPitchAndSpeed(self.__concatenated, pitchMult, speedMult) + + #倒放 + if(reverse): + self.__concatenated = np.flip(self.__concatenated) + + #如果缺失拼音,则发出警告 + #if len(missingPinyin) != 0: + # print("警告:缺失或未定义{}".format(missingPinyin)) + + + + #返回二进制音频 + def __export(self): + bytesout = BytesIO() + sf.write(bytesout, self.__concatenated, _targetSR, format="MP3") + return bytesout diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/requirements.txt b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/requirements.txt new file mode 100644 index 0000000..2852d4f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/requirements.txt @@ -0,0 +1,9 @@ +psola +numpy +soundfile +pypinyin +playsound +#注意:如果直接用pip install playsound安装,Windows系统下会报错 +#需要去原作者Github页面下载最新的playsound.py +#https://github.com/TaylorSMarks/playsound/blob/master/playsound.py +Pillow \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/settings.json b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/settings.json new file mode 100644 index 0000000..859a919 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/settings.json @@ -0,0 +1,6 @@ +{ + "sourceDirectory": "./HuoZiYinShua/sources/", + "ysddSourceDirectory": "./HuoZiYinShua/ysddSources/", + "dictFile": "./HuoZiYinShua/dictionary.json", + "ysddTableFile": "./HuoZiYinShua/ysddTable.json" +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/a.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/a.wav new file mode 100644 index 0000000..f22860c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/a.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ai.wav new file mode 100644 index 0000000..a9cc1d0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/an.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/an.wav new file mode 100644 index 0000000..3f2b3e0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/an.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ao.wav new file mode 100644 index 0000000..71fb2fc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ba.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ba.wav new file mode 100644 index 0000000..84c2bc3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ba.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bai.wav new file mode 100644 index 0000000..d8bdd31 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ban.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ban.wav new file mode 100644 index 0000000..750b466 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ban.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bang.wav new file mode 100644 index 0000000..c1822fd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bao.wav new file mode 100644 index 0000000..4d5321f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bei.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bei.wav new file mode 100644 index 0000000..d13201b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bei.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ben.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ben.wav new file mode 100644 index 0000000..85d911f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ben.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/beng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/beng.wav new file mode 100644 index 0000000..0b93bba Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/beng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bi.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bi.wav new file mode 100644 index 0000000..4904cdf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bi.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bian.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bian.wav new file mode 100644 index 0000000..d825c97 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bian.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/biao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/biao.wav new file mode 100644 index 0000000..0d8f13e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/biao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bie.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bie.wav new file mode 100644 index 0000000..9ec72d8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bie.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bin.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bin.wav new file mode 100644 index 0000000..4ca5e82 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bin.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bing.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bing.wav new file mode 100644 index 0000000..4ca5e82 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bing.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bo.wav new file mode 100644 index 0000000..56cf7fd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bu.wav new file mode 100644 index 0000000..a514341 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/bu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cai.wav new file mode 100644 index 0000000..e493699 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/can.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/can.wav new file mode 100644 index 0000000..afe6a5b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/can.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cang.wav new file mode 100644 index 0000000..ef87169 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cao.wav new file mode 100644 index 0000000..0299a90 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ceng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ceng.wav new file mode 100644 index 0000000..81e7fc9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ceng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cha.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cha.wav new file mode 100644 index 0000000..940ac50 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cha.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chai.wav new file mode 100644 index 0000000..e493699 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chan.wav new file mode 100644 index 0000000..b278877 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chang.wav new file mode 100644 index 0000000..95d69b9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chao.wav new file mode 100644 index 0000000..0299a90 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/che.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/che.wav new file mode 100644 index 0000000..1db42b9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/che.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chen.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chen.wav new file mode 100644 index 0000000..411a573 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chen.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cheng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cheng.wav new file mode 100644 index 0000000..f4a2354 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cheng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chi.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chi.wav new file mode 100644 index 0000000..9b84a96 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chi.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chong.wav new file mode 100644 index 0000000..dbdd05d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chou.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chou.wav new file mode 100644 index 0000000..9d41e1c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chou.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chu.wav new file mode 100644 index 0000000..4d462c3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chuan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chuan.wav new file mode 100644 index 0000000..2dfca1d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chuan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chuang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chuang.wav new file mode 100644 index 0000000..e73b300 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chuang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chui.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chui.wav new file mode 100644 index 0000000..a752d88 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chui.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chun.wav new file mode 100644 index 0000000..c1443b4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/chun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ci.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ci.wav new file mode 100644 index 0000000..d16681d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ci.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cong.wav new file mode 100644 index 0000000..e2e2fc8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cou.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cou.wav new file mode 100644 index 0000000..e784492 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cou.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cu.wav new file mode 100644 index 0000000..8126a35 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cui.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cui.wav new file mode 100644 index 0000000..5d957d7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cui.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cun.wav new file mode 100644 index 0000000..077f0fe Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cuo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cuo.wav new file mode 100644 index 0000000..4b7d9be Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/cuo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/da.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/da.wav new file mode 100644 index 0000000..e0969cf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/da.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dai.wav new file mode 100644 index 0000000..6bdfac6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dan.wav new file mode 100644 index 0000000..2cd7626 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dang.wav new file mode 100644 index 0000000..e94d945 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dao.wav new file mode 100644 index 0000000..5a6cb1d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/de.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/de.wav new file mode 100644 index 0000000..d5f0317 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/de.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/deng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/deng.wav new file mode 100644 index 0000000..635a7fb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/deng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/di.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/di.wav new file mode 100644 index 0000000..3dc42f1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/di.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dian.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dian.wav new file mode 100644 index 0000000..acedbee Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dian.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/diao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/diao.wav new file mode 100644 index 0000000..207f6e6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/diao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/die.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/die.wav new file mode 100644 index 0000000..47e9b37 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/die.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ding.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ding.wav new file mode 100644 index 0000000..cb4a58c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ding.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dong.wav new file mode 100644 index 0000000..25e31c8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dou.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dou.wav new file mode 100644 index 0000000..1b6dfcf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dou.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/du.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/du.wav new file mode 100644 index 0000000..b1c469e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/du.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/duan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/duan.wav new file mode 100644 index 0000000..fc86167 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/duan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dui.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dui.wav new file mode 100644 index 0000000..a0d212d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dui.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dun.wav new file mode 100644 index 0000000..46b6191 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/dun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/duo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/duo.wav new file mode 100644 index 0000000..38d7b84 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/duo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/e.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/e.wav new file mode 100644 index 0000000..4538947 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/e.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ei.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ei.wav new file mode 100644 index 0000000..8443ebb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ei.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/en.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/en.wav new file mode 100644 index 0000000..2bafd76 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/en.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/eng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/eng.wav new file mode 100644 index 0000000..0b74d76 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/eng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/er.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/er.wav new file mode 100644 index 0000000..01c30d8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/er.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fa.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fa.wav new file mode 100644 index 0000000..8313eac Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fa.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fan.wav new file mode 100644 index 0000000..3ecb87b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fang.wav new file mode 100644 index 0000000..36eebfd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fei.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fei.wav new file mode 100644 index 0000000..28075a2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fei.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fen.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fen.wav new file mode 100644 index 0000000..ebf5548 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fen.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/feng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/feng.wav new file mode 100644 index 0000000..8b467e9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/feng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fou.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fou.wav new file mode 100644 index 0000000..af03e40 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fou.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fu.wav new file mode 100644 index 0000000..ed0f9fb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/fu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ga.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ga.wav new file mode 100644 index 0000000..08c47be Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ga.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gai.wav new file mode 100644 index 0000000..366dd70 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gan.wav new file mode 100644 index 0000000..ebbb39a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gang.wav new file mode 100644 index 0000000..1e3842e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gao.wav new file mode 100644 index 0000000..d0f257c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ge.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ge.wav new file mode 100644 index 0000000..dc51f56 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ge.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gei.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gei.wav new file mode 100644 index 0000000..f3ce177 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gei.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gen.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gen.wav new file mode 100644 index 0000000..7735165 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gen.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/geng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/geng.wav new file mode 100644 index 0000000..3710127 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/geng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gong.wav new file mode 100644 index 0000000..b83299b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gou.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gou.wav new file mode 100644 index 0000000..8bb9a86 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gou.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gu.wav new file mode 100644 index 0000000..ef47c0f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gua.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gua.wav new file mode 100644 index 0000000..0441b67 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gua.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/guai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/guai.wav new file mode 100644 index 0000000..515f4eb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/guai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/guan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/guan.wav new file mode 100644 index 0000000..be8cab1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/guan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/guang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/guang.wav new file mode 100644 index 0000000..6bdf5b4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/guang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gui.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gui.wav new file mode 100644 index 0000000..88cd0d9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gui.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gun.wav new file mode 100644 index 0000000..7b17985 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/gun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/guo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/guo.wav new file mode 100644 index 0000000..d9069d0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/guo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ha.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ha.wav new file mode 100644 index 0000000..5c9a3ce Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ha.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hai.wav new file mode 100644 index 0000000..06b419a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/han.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/han.wav new file mode 100644 index 0000000..77ed670 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/han.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hao.wav new file mode 100644 index 0000000..79a883f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/he.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/he.wav new file mode 100644 index 0000000..283e680 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/he.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hei.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hei.wav new file mode 100644 index 0000000..7efff6c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hei.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hen.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hen.wav new file mode 100644 index 0000000..6510cd0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hen.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/heng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/heng.wav new file mode 100644 index 0000000..712f1f8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/heng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hong.wav new file mode 100644 index 0000000..d2f0754 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hou.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hou.wav new file mode 100644 index 0000000..84abcc6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hou.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hu.wav new file mode 100644 index 0000000..035278e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hua.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hua.wav new file mode 100644 index 0000000..4612496 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hua.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/huai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/huai.wav new file mode 100644 index 0000000..84bc568 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/huai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/huan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/huan.wav new file mode 100644 index 0000000..4d834d8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/huan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/huang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/huang.wav new file mode 100644 index 0000000..196e79c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/huang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hui.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hui.wav new file mode 100644 index 0000000..7a5c7d9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hui.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hun.wav new file mode 100644 index 0000000..7f90101 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/hun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/huo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/huo.wav new file mode 100644 index 0000000..9ac427f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/huo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ji.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ji.wav new file mode 100644 index 0000000..2363978 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ji.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jia.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jia.wav new file mode 100644 index 0000000..1f85182 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jia.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jian.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jian.wav new file mode 100644 index 0000000..717ec14 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jian.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jiang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jiang.wav new file mode 100644 index 0000000..cb26ea2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jiang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jiao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jiao.wav new file mode 100644 index 0000000..f061fe9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jiao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jie.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jie.wav new file mode 100644 index 0000000..b68413f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jie.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jin.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jin.wav new file mode 100644 index 0000000..7c307ea Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jin.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jing.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jing.wav new file mode 100644 index 0000000..aba171a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jing.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jiong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jiong.wav new file mode 100644 index 0000000..734d000 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jiong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jiu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jiu.wav new file mode 100644 index 0000000..2971879 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jiu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ju.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ju.wav new file mode 100644 index 0000000..6932082 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ju.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/juan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/juan.wav new file mode 100644 index 0000000..cad4615 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/juan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jue.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jue.wav new file mode 100644 index 0000000..58172b9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jue.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jun.wav new file mode 100644 index 0000000..2d5ad5c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/jun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ka.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ka.wav new file mode 100644 index 0000000..5506956 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ka.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kai.wav new file mode 100644 index 0000000..5f7bab5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kan.wav new file mode 100644 index 0000000..8b74e89 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kang.wav new file mode 100644 index 0000000..1c3739d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kao.wav new file mode 100644 index 0000000..5f23457 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ke.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ke.wav new file mode 100644 index 0000000..9b4ee1a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ke.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kiu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kiu.wav new file mode 100644 index 0000000..05c618f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kiu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kong.wav new file mode 100644 index 0000000..3a037b9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kou.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kou.wav new file mode 100644 index 0000000..cbd9d4a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kou.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ku.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ku.wav new file mode 100644 index 0000000..6b46410 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ku.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kua.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kua.wav new file mode 100644 index 0000000..487b767 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kua.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kuai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kuai.wav new file mode 100644 index 0000000..25451e6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kuai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kuan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kuan.wav new file mode 100644 index 0000000..38deab6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kuan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kuang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kuang.wav new file mode 100644 index 0000000..f43af27 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kuang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kui.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kui.wav new file mode 100644 index 0000000..8e51cea Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kui.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kun.wav new file mode 100644 index 0000000..01fa5f1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/kun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/la.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/la.wav new file mode 100644 index 0000000..9175413 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/la.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lai.wav new file mode 100644 index 0000000..0a3f16b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lan.wav new file mode 100644 index 0000000..e70da63 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lang.wav new file mode 100644 index 0000000..023612c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lao.wav new file mode 100644 index 0000000..f447d85 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/le.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/le.wav new file mode 100644 index 0000000..c37c39b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/le.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lei.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lei.wav new file mode 100644 index 0000000..a925c69 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lei.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/li.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/li.wav new file mode 100644 index 0000000..9ce474b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/li.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lia.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lia.wav new file mode 100644 index 0000000..22f4418 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lia.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lian.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lian.wav new file mode 100644 index 0000000..33fcfa1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lian.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/liang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/liang.wav new file mode 100644 index 0000000..3e5f36a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/liang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/liao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/liao.wav new file mode 100644 index 0000000..87f3a04 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/liao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lie.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lie.wav new file mode 100644 index 0000000..8bd14ab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lie.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lin.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lin.wav new file mode 100644 index 0000000..9b49270 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lin.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ling.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ling.wav new file mode 100644 index 0000000..dbc9617 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ling.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/liu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/liu.wav new file mode 100644 index 0000000..5e413e0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/liu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/long.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/long.wav new file mode 100644 index 0000000..5b4822b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/long.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lu.wav new file mode 100644 index 0000000..384c50f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/luan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/luan.wav new file mode 100644 index 0000000..69a69b9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/luan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lun.wav new file mode 100644 index 0000000..3953f25 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/luo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/luo.wav new file mode 100644 index 0000000..df1d8ed Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/luo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lv.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lv.wav new file mode 100644 index 0000000..a0a2634 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/lv.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ma.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ma.wav new file mode 100644 index 0000000..9f499e3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ma.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mai.wav new file mode 100644 index 0000000..4e7ecd8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/man.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/man.wav new file mode 100644 index 0000000..fe56d3d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/man.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mang.wav new file mode 100644 index 0000000..29c967f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mao.wav new file mode 100644 index 0000000..6e62b03 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/me.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/me.wav new file mode 100644 index 0000000..e0fab63 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/me.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mei.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mei.wav new file mode 100644 index 0000000..6d675da Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mei.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/men.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/men.wav new file mode 100644 index 0000000..49cf786 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/men.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/meng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/meng.wav new file mode 100644 index 0000000..4a0a4cf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/meng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mi.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mi.wav new file mode 100644 index 0000000..3baabc9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mi.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mian.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mian.wav new file mode 100644 index 0000000..bf25121 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mian.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/miao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/miao.wav new file mode 100644 index 0000000..0da8faa Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/miao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/min.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/min.wav new file mode 100644 index 0000000..f962904 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/min.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ming.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ming.wav new file mode 100644 index 0000000..2674825 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ming.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/miu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/miu.wav new file mode 100644 index 0000000..610f686 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/miu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mo.wav new file mode 100644 index 0000000..2b4bad2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mu.wav new file mode 100644 index 0000000..c94dd86 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/mu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/na.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/na.wav new file mode 100644 index 0000000..7e5ca95 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/na.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nai.wav new file mode 100644 index 0000000..f7f5512 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nan.wav new file mode 100644 index 0000000..20ad642 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nao.wav new file mode 100644 index 0000000..7203f18 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ne.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ne.wav new file mode 100644 index 0000000..3cc7d64 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ne.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nei.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nei.wav new file mode 100644 index 0000000..e90bc9c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nei.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/neng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/neng.wav new file mode 100644 index 0000000..95484e9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/neng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ni.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ni.wav new file mode 100644 index 0000000..82cbefd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ni.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nian.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nian.wav new file mode 100644 index 0000000..2d9f381 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nian.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/niao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/niao.wav new file mode 100644 index 0000000..1d6af37 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/niao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ning.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ning.wav new file mode 100644 index 0000000..6577c54 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ning.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/niu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/niu.wav new file mode 100644 index 0000000..9e0d199 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/niu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nong.wav new file mode 100644 index 0000000..1cf7d0d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nu.wav new file mode 100644 index 0000000..aac6b16 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nv.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nv.wav new file mode 100644 index 0000000..610fd31 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nv.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nve.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nve.wav new file mode 100644 index 0000000..6ad5d37 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/nve.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/o.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/o.wav new file mode 100644 index 0000000..ce4dfb3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/o.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ou.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ou.wav new file mode 100644 index 0000000..ce4dfb3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ou.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pa.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pa.wav new file mode 100644 index 0000000..501c73c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pa.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pai.wav new file mode 100644 index 0000000..c80467f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pan.wav new file mode 100644 index 0000000..210b2a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pao.wav new file mode 100644 index 0000000..2871020 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pei.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pei.wav new file mode 100644 index 0000000..e3fa43c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pei.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pen.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pen.wav new file mode 100644 index 0000000..5f5804d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pen.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/peng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/peng.wav new file mode 100644 index 0000000..2eb3242 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/peng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pi.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pi.wav new file mode 100644 index 0000000..fc42738 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pi.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pian.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pian.wav new file mode 100644 index 0000000..37fa3f1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pian.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/piao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/piao.wav new file mode 100644 index 0000000..51b127a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/piao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pin.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pin.wav new file mode 100644 index 0000000..d35cf35 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pin.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ping.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ping.wav new file mode 100644 index 0000000..68746f8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ping.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/po.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/po.wav new file mode 100644 index 0000000..5a69325 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/po.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pu.wav new file mode 100644 index 0000000..94f0798 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/pu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qi.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qi.wav new file mode 100644 index 0000000..5e4adb6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qi.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qian.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qian.wav new file mode 100644 index 0000000..f499440 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qian.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qiang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qiang.wav new file mode 100644 index 0000000..603eba6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qiang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qiao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qiao.wav new file mode 100644 index 0000000..a7dc0af Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qiao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qie.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qie.wav new file mode 100644 index 0000000..a7cc4c8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qie.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qin.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qin.wav new file mode 100644 index 0000000..a6ac779 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qin.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qing.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qing.wav new file mode 100644 index 0000000..adf6585 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qing.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qiong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qiong.wav new file mode 100644 index 0000000..6fc0580 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qiong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qiu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qiu.wav new file mode 100644 index 0000000..173a110 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qiu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qu.wav new file mode 100644 index 0000000..b25cd6a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/quan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/quan.wav new file mode 100644 index 0000000..d84dc9b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/quan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/que.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/que.wav new file mode 100644 index 0000000..e502fe7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/que.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qun.wav new file mode 100644 index 0000000..141e8f4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/qun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ran.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ran.wav new file mode 100644 index 0000000..ef1f813 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ran.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rang.wav new file mode 100644 index 0000000..40c5d24 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rao.wav new file mode 100644 index 0000000..ced24ac Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/re.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/re.wav new file mode 100644 index 0000000..bae6aed Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/re.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ren.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ren.wav new file mode 100644 index 0000000..0e5b103 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ren.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/reng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/reng.wav new file mode 100644 index 0000000..83deb1d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/reng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ri.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ri.wav new file mode 100644 index 0000000..1cd5e3c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ri.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rong.wav new file mode 100644 index 0000000..22fbfbe Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rou.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rou.wav new file mode 100644 index 0000000..de30664 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rou.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ru.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ru.wav new file mode 100644 index 0000000..441722f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ru.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rui.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rui.wav new file mode 100644 index 0000000..fb60ae2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/rui.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ruo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ruo.wav new file mode 100644 index 0000000..a75095f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ruo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sa.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sa.wav new file mode 100644 index 0000000..660a085 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sa.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sai.wav new file mode 100644 index 0000000..86ca9ff Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/san.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/san.wav new file mode 100644 index 0000000..22c5236 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/san.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sang.wav new file mode 100644 index 0000000..db1de19 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sao.wav new file mode 100644 index 0000000..6e69723 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/se.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/se.wav new file mode 100644 index 0000000..1ee0a04 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/se.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sha.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sha.wav new file mode 100644 index 0000000..cdf0374 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sha.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shan.wav new file mode 100644 index 0000000..6c9756e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shang.wav new file mode 100644 index 0000000..c08ba54 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shao.wav new file mode 100644 index 0000000..c1085a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/she.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/she.wav new file mode 100644 index 0000000..e12ea4b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/she.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shen.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shen.wav new file mode 100644 index 0000000..d174904 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shen.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sheng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sheng.wav new file mode 100644 index 0000000..5be2dba Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sheng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shi.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shi.wav new file mode 100644 index 0000000..a0e8419 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shi.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shou.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shou.wav new file mode 100644 index 0000000..b706c4c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shou.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shu.wav new file mode 100644 index 0000000..2cf24ba Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shua.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shua.wav new file mode 100644 index 0000000..ca2def0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shua.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shuai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shuai.wav new file mode 100644 index 0000000..f37d4ae Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shuai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shuang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shuang.wav new file mode 100644 index 0000000..cee3bd8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shuang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shui.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shui.wav new file mode 100644 index 0000000..99295d4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shui.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shun.wav new file mode 100644 index 0000000..c883d7b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shuo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shuo.wav new file mode 100644 index 0000000..9d6fb0a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/shuo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/si.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/si.wav new file mode 100644 index 0000000..962ab22 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/si.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/song.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/song.wav new file mode 100644 index 0000000..b7b0151 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/song.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/su.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/su.wav new file mode 100644 index 0000000..d207a3e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/su.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/suan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/suan.wav new file mode 100644 index 0000000..351bcc5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/suan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sui.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sui.wav new file mode 100644 index 0000000..ab94c93 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sui.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sun.wav new file mode 100644 index 0000000..9676707 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/sun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/suo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/suo.wav new file mode 100644 index 0000000..5494934 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/suo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ta.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ta.wav new file mode 100644 index 0000000..a10de88 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ta.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tai.wav new file mode 100644 index 0000000..9ec4dee Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tan.wav new file mode 100644 index 0000000..ddd7696 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tang.wav new file mode 100644 index 0000000..60522ce Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tao.wav new file mode 100644 index 0000000..5e24992 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/teng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/teng.wav new file mode 100644 index 0000000..4907443 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/teng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ti.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ti.wav new file mode 100644 index 0000000..cd5b65e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ti.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tian.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tian.wav new file mode 100644 index 0000000..a3d1333 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tian.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tiao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tiao.wav new file mode 100644 index 0000000..f59261c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tiao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tie.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tie.wav new file mode 100644 index 0000000..677758f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tie.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ting.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ting.wav new file mode 100644 index 0000000..eab5b90 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ting.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tong.wav new file mode 100644 index 0000000..05f0e3e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tou.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tou.wav new file mode 100644 index 0000000..e0c96a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tou.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tu.wav new file mode 100644 index 0000000..2d06efd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tuan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tuan.wav new file mode 100644 index 0000000..c9200b8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tuan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tui.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tui.wav new file mode 100644 index 0000000..2ec9c21 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tui.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tun.wav new file mode 100644 index 0000000..591ad50 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tuo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tuo.wav new file mode 100644 index 0000000..9564724 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/tuo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wa.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wa.wav new file mode 100644 index 0000000..397b972 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wa.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wai.wav new file mode 100644 index 0000000..20d01a2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wan.wav new file mode 100644 index 0000000..a63180d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wang.wav new file mode 100644 index 0000000..40f6020 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wei.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wei.wav new file mode 100644 index 0000000..12d2a78 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wei.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wen.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wen.wav new file mode 100644 index 0000000..18ace51 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wen.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wo.wav new file mode 100644 index 0000000..b5f792e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wu.wav new file mode 100644 index 0000000..02f1681 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/wu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xi.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xi.wav new file mode 100644 index 0000000..d33fb99 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xi.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xia.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xia.wav new file mode 100644 index 0000000..c62eb1f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xia.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xian.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xian.wav new file mode 100644 index 0000000..bda1dc7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xian.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xiang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xiang.wav new file mode 100644 index 0000000..e8866b3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xiang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xiao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xiao.wav new file mode 100644 index 0000000..ec3990f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xiao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xie.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xie.wav new file mode 100644 index 0000000..41eaa1e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xie.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xin.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xin.wav new file mode 100644 index 0000000..09caae5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xin.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xing.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xing.wav new file mode 100644 index 0000000..abc4105 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xing.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xiong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xiong.wav new file mode 100644 index 0000000..af4e511 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xiong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xiu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xiu.wav new file mode 100644 index 0000000..3606bcd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xiu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xu.wav new file mode 100644 index 0000000..4429bea Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xuan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xuan.wav new file mode 100644 index 0000000..ba5e0df Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xuan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xue.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xue.wav new file mode 100644 index 0000000..c09d836 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xue.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xun.wav new file mode 100644 index 0000000..f201ee4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/xun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ya.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ya.wav new file mode 100644 index 0000000..5cb46aa Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ya.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yan.wav new file mode 100644 index 0000000..fb9cbaf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yang.wav new file mode 100644 index 0000000..ac0fb32 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yao.wav new file mode 100644 index 0000000..cbc049d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ye.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ye.wav new file mode 100644 index 0000000..8716b49 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ye.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yi.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yi.wav new file mode 100644 index 0000000..94da1d3 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yi.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yin.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yin.wav new file mode 100644 index 0000000..00343f9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yin.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ying.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ying.wav new file mode 100644 index 0000000..6a58237 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ying.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yong.wav new file mode 100644 index 0000000..d20000a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/you.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/you.wav new file mode 100644 index 0000000..4c67051 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/you.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yu.wav new file mode 100644 index 0000000..8ac5271 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yuan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yuan.wav new file mode 100644 index 0000000..41d710f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yuan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yue.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yue.wav new file mode 100644 index 0000000..1363140 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yue.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yun.wav new file mode 100644 index 0000000..9e8879c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/yun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/za.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/za.wav new file mode 100644 index 0000000..4dac880 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/za.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zai.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zai.wav new file mode 100644 index 0000000..9ef9802 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zai.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zan.wav new file mode 100644 index 0000000..7406b8f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zao.wav new file mode 100644 index 0000000..17ccc13 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ze.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ze.wav new file mode 100644 index 0000000..8e7127a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/ze.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zei.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zei.wav new file mode 100644 index 0000000..ac276ec Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zei.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zen.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zen.wav new file mode 100644 index 0000000..4b02eb1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zen.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zeng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zeng.wav new file mode 100644 index 0000000..7f5bec7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zeng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zha.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zha.wav new file mode 100644 index 0000000..c656b5a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zha.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhan.wav new file mode 100644 index 0000000..5e43909 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhang.wav new file mode 100644 index 0000000..186ff87 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhao.wav new file mode 100644 index 0000000..c960edc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhe.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhe.wav new file mode 100644 index 0000000..95d4ca0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhe.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhei.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhei.wav new file mode 100644 index 0000000..8362a81 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhei.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhen.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhen.wav new file mode 100644 index 0000000..b54eaa5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhen.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zheng.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zheng.wav new file mode 100644 index 0000000..9f1beae Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zheng.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhi.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhi.wav new file mode 100644 index 0000000..4317f47 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhi.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhong.wav new file mode 100644 index 0000000..ad4a691 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhou.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhou.wav new file mode 100644 index 0000000..0d6d582 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhou.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhu.wav new file mode 100644 index 0000000..5571c7f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhua.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhua.wav new file mode 100644 index 0000000..bed9d1e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhua.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhuan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhuan.wav new file mode 100644 index 0000000..c36510b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhuan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhuang.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhuang.wav new file mode 100644 index 0000000..85b7139 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhuang.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhui.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhui.wav new file mode 100644 index 0000000..2e7a10f Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhui.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhun.wav new file mode 100644 index 0000000..0e01094 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhuo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhuo.wav new file mode 100644 index 0000000..ff2b889 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zhuo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zi.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zi.wav new file mode 100644 index 0000000..51acfbb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zi.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zong.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zong.wav new file mode 100644 index 0000000..22fb97c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zong.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zou.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zou.wav new file mode 100644 index 0000000..3209d34 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zou.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zu.wav new file mode 100644 index 0000000..e7437dd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zuan.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zuan.wav new file mode 100644 index 0000000..40e92c4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zuan.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zui.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zui.wav new file mode 100644 index 0000000..affb504 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zui.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zun.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zun.wav new file mode 100644 index 0000000..9381a5c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zun.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zuo.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zuo.wav new file mode 100644 index 0000000..5ba18a7 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/sources/zuo.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/AQ1.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/AQ1.wav new file mode 100644 index 0000000..482b2ab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/AQ1.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/AQ2.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/AQ2.wav new file mode 100644 index 0000000..2913fde Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/AQ2.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/bobi.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/bobi.wav new file mode 100644 index 0000000..b423999 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/bobi.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/by.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/by.mp3 new file mode 100644 index 0000000..88cd275 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/by.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/d.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/d.mp3 new file mode 100644 index 0000000..59f260d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/d.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/djha.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/djha.wav new file mode 100644 index 0000000..3544283 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/djha.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/euz.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/euz.wav new file mode 100644 index 0000000..7784d90 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/euz.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/ga.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/ga.mp3 new file mode 100644 index 0000000..e47c3e2 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/ga.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/gwysmgx.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/gwysmgx.mp3 new file mode 100644 index 0000000..2b12f50 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/gwysmgx.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/hlldxf.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/hlldxf.wav new file mode 100644 index 0000000..7e3a402 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/hlldxf.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/jtlaidian.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/jtlaidian.wav new file mode 100644 index 0000000..171f6bb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/jtlaidian.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/jyxa.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/jyxa.mp3 new file mode 100644 index 0000000..19ac5e1 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/jyxa.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/kzzll.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/kzzll.mp3 new file mode 100644 index 0000000..c79d346 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/kzzll.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/miyu.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/miyu.wav new file mode 100644 index 0000000..0f32335 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/miyu.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/nxhw.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/nxhw.mp3 new file mode 100644 index 0000000..cb855ff Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/nxhw.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/nzmzmca.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/nzmzmca.mp3 new file mode 100644 index 0000000..7e7fff5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/nzmzmca.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/omns.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/omns.mp3 new file mode 100644 index 0000000..90b7fcf Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/omns.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/sddl.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/sddl.wav new file mode 100644 index 0000000..d4b8a4c Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/sddl.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/waao.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/waao.wav new file mode 100644 index 0000000..00f6002 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/waao.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/wcsndm.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/wcsndm.mp3 new file mode 100644 index 0000000..b185bd4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/wcsndm.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/wsdg.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/wsdg.wav new file mode 100644 index 0000000..6c5051d Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/wsdg.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/wssddl.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/wssddl.wav new file mode 100644 index 0000000..02ef2d6 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/wssddl.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/wxhn.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/wxhn.mp3 new file mode 100644 index 0000000..350d3fe Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/wxhn.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/xh.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/xh.wav new file mode 100644 index 0000000..26200f4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/xh.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/ydglm.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/ydglm.mp3 new file mode 100644 index 0000000..33ba374 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/ydglm.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/zaiQ.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/zaiQ.wav new file mode 100644 index 0000000..65ee319 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/zaiQ.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/啊1.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/啊1.wav new file mode 100644 index 0000000..01fd8ca Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/啊1.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/啊2.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/啊2.wav new file mode 100644 index 0000000..4816d17 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/啊2.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/好汉.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/好汉.wav new file mode 100644 index 0000000..05bc9c0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/好汉.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/愉悦送走.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/愉悦送走.mp3 new file mode 100644 index 0000000..a707531 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/愉悦送走.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/欧内的手.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/欧内的手.wav new file mode 100644 index 0000000..a97baab Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/欧内的手.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/欧西给1.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/欧西给1.wav new file mode 100644 index 0000000..69b59b8 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/欧西给1.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/欧西给2.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/欧西给2.wav new file mode 100644 index 0000000..937068e Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/欧西给2.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/欧西给3.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/欧西给3.wav new file mode 100644 index 0000000..e1becc9 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/欧西给3.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/癌症晚期.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/癌症晚期.wav new file mode 100644 index 0000000..09397fa Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/癌症晚期.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/给你妈.mp3 b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/给你妈.mp3 new file mode 100644 index 0000000..6b7bfd0 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/给你妈.mp3 differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/走位.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/走位.wav new file mode 100644 index 0000000..3f11c49 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/走位.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/韭菜盒子.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/韭菜盒子.wav new file mode 100644 index 0000000..5b7d600 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/韭菜盒子.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫1.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫1.wav new file mode 100644 index 0000000..607700a Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫1.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫2.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫2.wav new file mode 100644 index 0000000..f10ccee Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫2.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫3.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫3.wav new file mode 100644 index 0000000..3d3ae5b Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫3.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫4.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫4.wav new file mode 100644 index 0000000..c7b0e39 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫4.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫5.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫5.wav new file mode 100644 index 0000000..b301fde Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫5.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫6.wav b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫6.wav new file mode 100644 index 0000000..e30c9f5 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddSources/鬼叫6.wav differ diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddTable.json b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddTable.json new file mode 100644 index 0000000..cf94516 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_huoziyinshua/HuoZiYinShua/ysddTable.json @@ -0,0 +1,53 @@ +{ + "米浴说的道理": "miyu.wav", + "啊米浴说的道理": "miyu.wav", + "大家好啊": "djha.wav", + "我是说的道理": "wssddl.wav", + "今天来点大家想看的东西": "jtlaidian.wav", + "今天来点儿大家想看的东西": "jtlaidian.wav", + "说的道理": "sddl.wav", + "波比是我爹": "bobi.wav", + "啊嘛波比是我爹": "bobi.wav", + "哇袄": "waao.wav", + "欧西给": "欧西给1.wav", + "欧西给1": "欧西给1.wav", + "欧西给2": "欧西给2.wav", + "欧西给3": "欧西给3.wav", + "AQ": "AQ1.wav", + "AQ1": "AQ1.wav", + "AQ2": "AQ2.wav", + "再Q": "zaiQ.wav", + "走位": "走位.wav", + "诶乌兹": "euz.wav", + "欧内的手": "欧内的手.wav", + "好汉": "好汉.wav", + "我是电棍": "wsdg.wav", + "啊1": "啊1.wav", + "啊2": "啊2.wav", + "韭菜盒子": "韭菜盒子.wav", + "癌症晚期": "癌症晚期.wav", + "鬼叫1": "鬼叫1.wav", + "鬼叫2": "鬼叫2.wav", + "鬼叫3": "鬼叫3.wav", + "鬼叫4": "鬼叫4.wav", + "鬼叫5": "鬼叫5.wav", + "鬼叫6": "鬼叫6.wav", + "白银": "by.mp3", + "爹": "d.mp3", + "滚啊": "ga.mp3", + "跟我有什么关系": "gwysmgx.mp3", + "救一下啊": "jyxa.mp3", + "卡在这里了": "kzzll.mp3", + "你怎么这么菜啊": "nzmzmca.mp3", + "阿米诺斯": "omns.mp3", + "阿弥诺斯": "omns.mp3", + "我阐释你的梦": "wcsndm.mp3", + "一德格拉米": "ydglm.mp3", + "我喜欢你": "wxhn.mp3", + "你喜欢我": "nxhw.mp3", + "给你妈": "给你妈.mp3", + "愉悦送走": "愉悦送走.mp3", + "喜欢": "xh.wav", + "哈里路大旋风": "hlldxf.wav", + "哈利路大旋风": "hlldxf.wav" +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/README.md b/hexi/plugins/nonebot_plugin_huoziyinshua/README.md new file mode 100644 index 0000000..6ea11dd --- /dev/null +++ b/hexi/plugins/nonebot_plugin_huoziyinshua/README.md @@ -0,0 +1,40 @@ +# HuoZiYinShua_HoshinoBot + +适用于HoshinoBot的otto活字印刷插件 + +核心代码来自[DSP-8192/HuoZiYinShua](https://github.com/DSP-8192/HuoZiYinShua),参考了[Kazagumo/nonebot-HuoZiYinShua](https://github.com/Kazagumo/nonebot-HuoZiYinShua)的修改,截止本次编辑,两个仓库均未声明开源协议。 + +## 安装方法 +1. 在hoshino/modules下clone本仓库`git clone https://github.com/SlightDust/HuoZiYinShua_HoshinoBot.git` +2. 在hoshino/config/__bot__.py中加入 + +```python +MODULES_ON = { +... +'HuoZiYinShua_HoshinoBot', # otto活字印刷 +} +``` +3. 重启hoshino + +另外需要手动安装以下pip库: +soundfile +psola +numpy +pypinyin + +功能默认开启。服务叫ottohzys。 + +## 使用说明 +|指令|说明|指令示例| +|----|----|----| +| otto 一些内容 | otto语音活字印刷 | otto 大家好啊,我是里见光钻 | +|otto 一些内容-reverse| 活字印刷,并倒放 | otto 哈里路大旋风 -reverse | + +## Todo List +- [x] 基本功能 +- [ ] 异步 +- [ ] 添加更多原生大碟 + +## 日志 +2023/12/27 缝好了,能用了 +2023/12/29 以-reverse结尾可以倒放 \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_huoziyinshua/__init__.py b/hexi/plugins/nonebot_plugin_huoziyinshua/__init__.py new file mode 100644 index 0000000..64be4b6 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_huoziyinshua/__init__.py @@ -0,0 +1,48 @@ +import os +import re + +from nonebot import on_startswith, require +from nonebot.adapters.onebot.v11 import MessageEvent +from nonebot.plugin import PluginMetadata + +require("nonebot_plugin_alconna") +from nonebot_plugin_alconna import UniMessage + +from .HuoZiYinShua.huoZiYinShua import huoZiYinShua + +__plugin_meta__ = PluginMetadata( + name="otto活字印刷", + description="鬼畜音源活字印刷(otto语音合成)", + usage="otto 一些内容 生成otto语音\notto 一些内容 -reverse 生成并倒放", + type="application", +) + +self_path = os.path.dirname(__file__) +settings = { + "sourceDirectory": os.path.join(self_path, "HuoZiYinShua", "sources", ""), + "ysddSourceDirectory": os.path.join(self_path, "HuoZiYinShua", "ysddSources", ""), + "dictFile": os.path.join(self_path, "HuoZiYinShua", "dictionary.json"), + "ysddTableFile": os.path.join(self_path, "HuoZiYinShua", "ysddTable.json"), +} + +HZYS = huoZiYinShua(settings) + +otto = on_startswith("otto") + + +@otto.handle() +async def otto_handle(ev: MessageEvent): + txt = ev.message.extract_plain_text().removeprefix("otto") + pattern_reverse = re.compile(r"-reverse\s*$") + + if re.search(pattern_reverse, txt): + # 结尾匹配到 -reverse + reverse = True + txt = re.sub(pattern_reverse, "", txt) + txt = ",,," + txt # 加一段空白 + else: + reverse = False + txt = txt + ",,," # 加一段空白 + + b64audio = HZYS.export(txt, inYsddMode=True, reverse=reverse) + await UniMessage.voice(url=f"base64://{b64audio.decode()}").send() diff --git a/hexi/plugins/nonebot_plugin_learning_chat/__init__.py b/hexi/plugins/nonebot_plugin_learning_chat/__init__.py new file mode 100644 index 0000000..b862c22 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/__init__.py @@ -0,0 +1,137 @@ +from nonebot import require + +require("nonebot_plugin_orm") + +import asyncio +import random +import time + +from nonebot import on_message, require, logger, get_adapter +from nonebot.adapters.onebot.v11 import ( + GroupMessageEvent, + GROUP, + Message, + ActionFailed, + Adapter, +) +from nonebot.params import Arg +from nonebot.plugin import PluginMetadata +from nonebot.rule import Rule +from nonebot.typing import T_State +from nonebot_plugin_orm import get_session +from sqlalchemy import insert +from .handler import LearningChat +from .models import ChatMessage +from .config import config_manager, NICKNAME +from . import web_api +from . import web_hub +from hexi.web_plugin_registry import register_web_plugin + +require("nonebot_plugin_apscheduler") +from nonebot_plugin_apscheduler import scheduler + +# 注册到统一 Web 管理台(/hub):hub 启动时挂载 /api/learning_chat +register_web_plugin( + "learning_chat", + "群聊学习", + "chat", + lambda: web_hub.build_admin_app(), + module_name=__name__, +) + +__plugin_meta__ = PluginMetadata( + name="群聊学习", + description="学习群友们的发言、复读以及主动发言", + usage="详见README", + type="application", + homepage="https://github.com/CMHopeSunshine/nonebot-plugin-learning-chat", + supported_adapters={"~onebot.v11"}, + extra={"author": "惜月"}, +) + + +async def ChatRule(event: GroupMessageEvent, state: T_State) -> bool: + if answers := await LearningChat(event).answer(): + state["answers"] = answers + return True + return False + + +learning_chat = on_message( + priority=99, + block=False, + rule=Rule(ChatRule), + permission=GROUP, + state={ + "pm_name": "群聊学习", + "pm_description": "(被动技能)bot会学习群友们的发言", + "pm_usage": "群聊学习", + "pm_priority": 1, + }, +) + + +@learning_chat.handle() +async def _(event: GroupMessageEvent, answers=Arg("answers")): + for answer in answers: + try: + logger.info( + "群聊学习", f'{NICKNAME}将向群{event.group_id}回复"{answer}"' + ) + msg = await learning_chat.send(Message(answer)) + async with get_session() as session: + session.add(ChatMessage( + group_id=event.group_id, + user_id=event.self_id, + message_id=msg["message_id"], + message=answer, + raw_message=answer, + time=int(time.time()), + plain_text=Message(answer).extract_plain_text(), + )) + await session.commit() + await asyncio.sleep(random.random() + 0.5) + except ActionFailed: + logger.info( + "群聊学习", + f'{NICKNAME}向群{event.group_id}的回复"{answer}"发送失败,可能处于风控中', + ) + + +@scheduler.scheduled_job("interval", minutes=3, misfire_grace_time=5) +async def speak_up(): + if not config_manager.config.total_enable: + return + try: + bots = get_adapter(Adapter).bots + if len(bots) == 0: + return + bot = list(bots.values())[0] + except ValueError: + return + if not (speak := await LearningChat.speak(int(bot.self_id))): + return + group_id, messages = speak + for msg in messages: + try: + logger.info("群聊学习", f'{NICKNAME}向群{group_id}主动发言"{msg}"') + send_result = await bot.send_group_msg( + group_id=group_id, message=Message(msg) + ) + async with get_session() as session: + session.add(ChatMessage( + group_id=group_id, + user_id=int(bot.self_id), + message_id=send_result["message_id"], + message=msg, + raw_message=msg, + time=int(time.time()), + plain_text=Message(msg).extract_plain_text(), + )) + await session.commit() + await asyncio.sleep(random.randint(2, 4)) + except ActionFailed: + logger.info( + "群聊学习", + f'{NICKNAME}向群{group_id}主动发言"{msg}"发送失败,可能处于风控中', + ) diff --git a/hexi/plugins/nonebot_plugin_learning_chat/config.py b/hexi/plugins/nonebot_plugin_learning_chat/config.py new file mode 100644 index 0000000..610f2f9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/config.py @@ -0,0 +1,115 @@ +from typing import List, Dict +from pathlib import Path +from pydantic import BaseModel, Field + +from nonebot import get_driver, logger +from nonebot.utils import escape_tag +from ruamel import yaml + +CONFIG_PATH = Path(__file__).resolve().parents[2] / "data" / "learning_chat" / "learning_chat.yml" +CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True) + +driver = get_driver() +try: + SUPERUSERS: List[int] = [int(s) for s in driver.config.superusers] +except Exception: + SUPERUSERS = [] + logger.warning("请在.env.prod文件中中配置超级用户SUPERUSERS") + +try: + NICKNAME: str = list(driver.config.nickname)[0] +except Exception: + NICKNAME = "bot" + +COMMAND_START = driver.config.command_start.copy() +if "" in COMMAND_START: + COMMAND_START.remove("") + + +class ChatGroupConfig(BaseModel): + enable: bool = Field(default=True, alias="群聊学习开关") + ban_words: List[str] = Field(default_factory=list, alias="屏蔽词") + ban_users: List[int] = Field(default_factory=list, alias="屏蔽用户") + answer_threshold: int = Field(default=4, alias="回复阈值") + answer_threshold_weights: List[int] = Field(default=[10, 30, 60], alias="回复阈值权重") + repeat_threshold: int = Field(default=3, alias="复读阈值") + break_probability: float = Field(default=0.25, alias="打断复读概率") + speak_enable: bool = Field(default=True, alias="主动发言开关") + speak_threshold: int = Field(default=5, alias="主动发言阈值") + speak_min_interval: int = Field(default=300, alias="主动发言最小间隔") + speak_continuously_probability: float = Field(default=0.5, alias="连续主动发言概率") + speak_continuously_max_len: int = Field(default=3, alias="最大连续主动发言句数") + speak_poke_probability: float = Field(default=0.5, alias="主动发言附带戳一戳概率") + + def update(self, **kwargs): + for key, value in kwargs.items(): + if key in self.__fields__: + self.__setattr__(key, value) + + +class ChatConfig(BaseModel): + total_enable: bool = Field(default=True, alias="群聊学习总开关") + enable_web: bool = Field(default=True, alias="启用后台管理") + web_username: str = Field(default="chat", alias="后台管理用户名") + web_password: str = Field(default="admin", alias="后台管理密码") + web_secret_key: str = Field( + default="49c294d32f69b732ef6447c18379451ce1738922a75cd1d4812ef150318a2ed0", + alias="后台管理token密钥", + ) + ban_words: List[str] = Field(default_factory=list, alias="全局屏蔽词") + ban_users: List[int] = Field(default_factory=list, alias="全局屏蔽用户") + KEYWORDS_SIZE: int = Field(default=3, alias="单句关键词分词数量") + cross_group_threshold: int = Field(default=3, alias="跨群回复阈值") + learn_max_count: int = Field(default=6, alias="最高学习次数") + dictionary: List[str] = Field(default_factory=list, alias="自定义词典") + group_config: Dict[int, ChatGroupConfig] = Field(default_factory=dict, alias="分群配置") + + def update(self, **kwargs): + for key, value in kwargs.items(): + if key in self.__fields__: + self.__setattr__(key, value) + + +class ChatConfigManager: + def __init__(self): + self.file_path = CONFIG_PATH + if self.file_path.exists(): + self.config = ChatConfig.parse_obj( + yaml.load( + self.file_path.read_text(encoding="utf-8"), Loader=yaml.Loader + ) + ) + else: + self.config = ChatConfig() + self.save() + + def get_group_config(self, group_id: int) -> ChatGroupConfig: + if group_id not in self.config.group_config: + self.config.group_config[group_id] = ChatGroupConfig() + self.save() + return self.config.group_config[group_id] + + @property + def config_list(self) -> List[str]: + return list(self.config.dict(by_alias=True).keys()) + + def save(self): + with self.file_path.open("w", encoding="utf-8") as f: + yaml.dump( + self.config.dict(by_alias=True), + f, + indent=2, + Dumper=yaml.RoundTripDumper, + allow_unicode=True, + ) + + +config_manager = ChatConfigManager() + + +def log_debug(command: str, info: str): + logger.opt(colors=True).debug(f"[{command}]{escape_tag(info)}") + + +def log_info(command: str, info: str): + logger.opt(colors=True).info(f"[{command}]{escape_tag(info)}") diff --git a/hexi/plugins/nonebot_plugin_learning_chat/handler.py b/hexi/plugins/nonebot_plugin_learning_chat/handler.py new file mode 100644 index 0000000..e88d46b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/handler.py @@ -0,0 +1,780 @@ +import asyncio +import datetime +import random +import re +import time +from dataclasses import dataclass +from functools import cached_property, cmp_to_key + +# from ..nonebot_plugin_hexi_core.MessageUtils import send_poke + +try: + import jieba_fast.analyse as jieba_analyse +except ImportError: + import jieba.analyse as jieba_analyse +from typing import List, Union, Optional, Tuple +from enum import IntEnum, auto +from nonebot import get_adapter +from nonebot.adapters.onebot.v11 import GroupMessageEvent, MessageSegment, ActionFailed, Adapter +from sqlalchemy import select, delete, func +from nonebot_plugin_orm import get_session +from .models import ChatBlackList, ChatContext, ChatAnswer, ChatMessage +from .config import ( + config_manager, + SUPERUSERS, + NICKNAME, + COMMAND_START, + log_info, + log_info, +) + +chat_config = config_manager.config + +NO_PERMISSION_WORDS = [f"{NICKNAME}就喜欢说这个,哼!", f"你管得着{NICKNAME}吗!"] +ENABLE_WORDS = [f"{NICKNAME}会尝试学你们说怪话!", f"好的呢,让{NICKNAME}学学你们的说话方式~"] +DISABLE_WORDS = [f"好好好,{NICKNAME}不学说话就是了!", f"果面呐噻,{NICKNAME}以后不学了..."] +SORRY_WORDS = [ + f"{NICKNAME}知道错了...达咩!", + f"{NICKNAME}不会再这么说了...", + f"果面呐噻,{NICKNAME}说错话了...", +] +DOUBT_WORDS = [f"{NICKNAME}有说什么奇怪的话吗?"] +BREAK_REPEAT_WORDS = ["打断复读", "打断!"] +ALL_WORDS = ( + NO_PERMISSION_WORDS + + SORRY_WORDS + + DOUBT_WORDS + + ENABLE_WORDS + + DISABLE_WORDS + + BREAK_REPEAT_WORDS +) + + +class Result(IntEnum): + Learn = auto() + Pass = auto() + Repeat = auto() + Ban = auto() + SetEnable = auto() + SetDisable = auto() + + +@dataclass +class MessageData: + """用于在 session 外安全传递消息数据的普通数据类""" + group_id: int + user_id: int + message_id: int + message: str + raw_message: str + plain_text: str + time: int + + @cached_property + def is_plain_text(self) -> bool: + return "[CQ:" not in self.message + + @cached_property + def keyword_list(self) -> List[str]: + if not self.is_plain_text and not len(self.plain_text): + return [] + return jieba_analyse.extract_tags(self.plain_text, topK=chat_config.KEYWORDS_SIZE) + + @cached_property + def keywords(self) -> str: + if not self.is_plain_text and not len(self.plain_text): + return self.message + return ( + self.message if len(self.keyword_list) < 2 else " ".join(self.keyword_list) + ) + + +def _db_to_message_data(m: ChatMessage) -> MessageData: + """将数据库 ChatMessage 对象转为普通 MessageData""" + return MessageData( + group_id=m.group_id, + user_id=m.user_id, + message_id=m.message_id, + message=m.message, + raw_message=m.raw_message, + plain_text=m.plain_text, + time=m.time, + ) + + +class LearningChat: + def __init__(self, event: GroupMessageEvent): + if event.reply: + self.reply = event.reply + self.data = MessageData( + group_id=event.group_id, + user_id=event.user_id, + message_id=event.message_id, + message=re.sub( + r"(\[CQ:at,qq=.+])|(\[CQ:reply,id=.+])", + "", + re.sub(r"(,subType=\d+,url=.+])", r"]", event.raw_message), + ).strip(), + raw_message=event.raw_message, + plain_text=event.get_plaintext(), + time=event.time, + ) + else: + self.data = MessageData( + group_id=event.group_id, + user_id=event.user_id, + message_id=event.message_id, + message=re.sub( + r"(\[CQ:at,qq=.+])", + "", + re.sub(r"(,subType=\d+,url=.+])", r"]", event.raw_message), + ).strip(), + raw_message=event.raw_message, + plain_text=event.get_plaintext(), + time=event.time, + ) + self.reply = None + self.bot_id = event.self_id + self.to_me = event.to_me or NICKNAME in self.data.message + self.role = "superuser" if event.user_id in SUPERUSERS else event.sender.role + self.config = config_manager.get_group_config(self.data.group_id) + self.ban_users = set(chat_config.ban_users + self.config.ban_users) + self.ban_words = set(chat_config.ban_words + self.config.ban_words) + + async def _learn(self) -> Result: + if self.to_me and any(w in self.data.message for w in {"学说话", "快学", "开启学习"}): + return Result.SetEnable + elif self.to_me and any(w in self.data.message for w in {"闭嘴", "别学", "关闭学习"}): + return Result.SetDisable + elif not chat_config.total_enable or not self.config.enable: + log_info("群聊学习", f"➤该群{self.data.group_id}未开启群聊学习,跳过") + return Result.Pass + elif COMMAND_START and self.data.message.startswith(tuple(COMMAND_START)): + log_info("群聊学习", "➤该消息以命令前缀开头,跳过") + return Result.Pass + elif self.data.user_id in self.ban_users: + log_info("群聊学习", f"➤发言人{self.data.user_id}在屏蔽列表中,跳过") + return Result.Pass + elif self.to_me and any(w in self.data.message for w in {"不可以", "达咩", "不能说这"}): + return Result.Ban + + async with get_session() as session: + if not await self._check_allow(session, self.data): + log_info("群聊学习", "➤消息未通过校验,跳过") + return Result.Pass + + if self.reply: + result = await session.execute( + select(ChatMessage).where(ChatMessage.message_id == self.reply.message_id).limit(1) + ) + db_message = result.scalar_one_or_none() + if not db_message: + log_info("群聊学习", "➤回复的消息不在数据库中,跳过") + return Result.Pass + if db_message.user_id in self.ban_users: + log_info("群聊学习", "➤回复的人在屏蔽列表中,跳过") + return Result.Pass + if not await self._check_allow(session, _db_to_message_data(db_message)): + log_info("群聊学习", "➤回复的消息未通过校验,跳过") + return Result.Pass + await self._set_answer(session, _db_to_message_data(db_message)) + return Result.Learn + else: + result = await session.execute( + select(ChatMessage) + .where( + ChatMessage.group_id == self.data.group_id, + ChatMessage.time >= self.data.time - 3600, + ) + .order_by(ChatMessage.time.desc()) + .limit(5) + ) + messages = [_db_to_message_data(m) for m in result.scalars().all()] + if messages: + if messages[0].message == self.data.message: + log_info("群聊学习", "➤复读中,跳过") + return Result.Repeat + for message in messages: + if ( + message.user_id not in self.ban_users + and set(self.data.keyword_list) & set(message.keyword_list) + and self.data.keyword_list != message.keyword_list + and await self._check_allow(session, message) + ): + await self._set_answer(session, message) + return Result.Learn + if messages[0].user_id in self.ban_users or not await self._check_allow(session, messages[0]): + log_info("群聊学习", "➤最后一条消息未通过校验,跳过") + return Result.Pass + await self._set_answer(session, messages[0]) + return Result.Learn + else: + return Result.Pass + + async def answer(self) -> Optional[List[Union[MessageSegment, str]]]: + """获取这句话的回复""" + result = await self._learn() + + # 保存本条消息到数据库 + async with get_session() as session: + session.add(ChatMessage( + group_id=self.data.group_id, + user_id=self.data.user_id, + message_id=self.data.message_id, + message=self.data.message, + raw_message=self.data.raw_message, + plain_text=self.data.plain_text, + time=self.data.time, + )) + await session.commit() + + if result == Result.Ban: + if self.role not in {"superuser", "admin", "owner"}: + return [random.choice(NO_PERMISSION_WORDS)] + if self.reply: + ban_result = await self._ban(message_id=self.reply.message_id) + else: + ban_result = await self._ban() + if ban_result: + return [random.choice(SORRY_WORDS)] + else: + return [random.choice(DOUBT_WORDS)] + elif result in [Result.SetEnable, Result.SetDisable]: + if self.role not in {"superuser", "admin", "owner"}: + return [random.choice(NO_PERMISSION_WORDS)] + self.config.update(enable=(result == Result.SetEnable)) + config_manager.config.group_config[self.data.group_id] = self.config + config_manager.save() + log_info( + "群聊学习", + f'群{self.data.group_id}{"开启" if result == Result.SetEnable else "关闭"}学习功能', + ) + return [random.choice(ENABLE_WORDS if result == Result.SetEnable else DISABLE_WORDS)] + elif result == Result.Pass: + return None + elif result == Result.Repeat: + async with get_session() as session: + already_result = await session.execute( + select(ChatMessage).where( + ChatMessage.group_id == self.data.group_id, + ChatMessage.time >= self.data.time - 3600, + ChatMessage.user_id == self.bot_id, + ChatMessage.message == self.data.message, + ).limit(self.config.repeat_threshold + 5) + ) + if already_result.scalar_one_or_none(): + log_info("群聊学习", "➤➤已经复读过了,跳过") + return None + msgs_result = await session.execute( + select(ChatMessage) + .where( + ChatMessage.group_id == self.data.group_id, + ChatMessage.time >= self.data.time - 3600, + ) + .order_by(ChatMessage.time.desc()) + .limit(self.config.repeat_threshold) + ) + messages = [_db_to_message_data(m) for m in msgs_result.scalars().all()] + if not messages: + return None + if ( + len(messages) >= self.config.repeat_threshold + and all(message.message == self.data.message for message in messages) + and any(message.user_id != self.data.user_id for message in messages) + ): + if random.random() < self.config.break_probability: + log_info("群聊学习", "➤➤达到复读阈值,打断复读!") + return [random.choice(BREAK_REPEAT_WORDS)] + else: + log_info("群聊学习", f"➤➤达到复读阈值,复读{messages[0].message}") + return [self.data.message] + return None + else: + if self.data.is_plain_text and len(self.data.plain_text) <= 1: + log_info("群聊学习", "➤➤消息过短,不回复") + return None + async with get_session() as session: + ctx_result = await session.execute( + select(ChatContext).where(ChatContext.keywords == self.data.keywords).limit(1) + ) + context = ctx_result.scalar_one_or_none() + if not context: + log_info("群聊学习", "➤➤尚未有已学习的回复,不回复") + return None + + if not self.to_me: + answer_choices = list( + range( + self.config.answer_threshold - len(self.config.answer_threshold_weights) + 1, + self.config.answer_threshold + 1, + ) + ) + answer_count_threshold = random.choices( + answer_choices, weights=self.config.answer_threshold_weights + )[0] + if len(self.data.keyword_list) == chat_config.KEYWORDS_SIZE: + answer_count_threshold -= 1 + cross_group_threshold = chat_config.cross_group_threshold + else: + answer_count_threshold = 1 + cross_group_threshold = 1 + + log_info( + "群聊学习", + f"➤➤本次回复阈值为{answer_count_threshold},跨群阈值为{cross_group_threshold}", + ) + + cross_kw_result = await session.execute( + select(ChatAnswer.keywords) + .where(ChatAnswer.context_id == context.id) + .group_by(ChatAnswer.keywords) + .having(func.count(ChatAnswer.keywords) >= cross_group_threshold) + ) + cross_keywords = [row[0] for row in cross_kw_result.all()] + + answers_cross_result = await session.execute( + select(ChatAnswer).where( + ChatAnswer.context_id == context.id, + ChatAnswer.count >= answer_count_threshold, + ChatAnswer.keywords.in_(cross_keywords), + ) + ) + answers_cross = answers_cross_result.scalars().all() + + answer_same_result = await session.execute( + select(ChatAnswer).where( + ChatAnswer.context_id == context.id, + ChatAnswer.count >= answer_count_threshold, + ChatAnswer.group_id == self.data.group_id, + ) + ) + answer_same_group = answer_same_result.scalars().all() + + # 提前把所有需要的字段读出来,避免 session 关闭后访问报错 + candidate_answers = [] + for answer in set(answers_cross) | set(answer_same_group): + a_keywords = answer.keywords + a_group_id = answer.group_id + a_count = answer.count + a_messages = list(answer.messages) + if not await self._check_allow_answer(session, a_keywords, a_group_id, a_messages): + continue + candidate_answers.append({ + "count": a_count, + "messages": a_messages, + "keywords": a_keywords, + }) + + if not candidate_answers: + log_info("群聊学习", "➤➤没有符合条件的候选回复") + return None + + sum_count = sum(a["count"] for a in candidate_answers) + per_list = [ + a["count"] / sum_count * (1 - 1 / a["count"]) + for a in candidate_answers + ] + per_list.append(1 - sum(per_list)) + + result_answer = random.choices(candidate_answers + [None], weights=per_list)[0] + if result_answer is None: + log_info("群聊学习", "➤➤但不进行回复") + return None + + result_message = random.choice(result_answer["messages"]) + log_info("群聊学习", f"➤➤将回复{result_message}") + + await asyncio.sleep(random.random() + 0.5) + return [result_message] + + async def _ban(self, message_id: Optional[int] = None) -> bool: + bots = get_adapter(Adapter).bots + if len(bots) == 0: + return False + bot = list(bots.values())[0] + async with get_session() as session: + if message_id: + msg_result = await session.execute( + select(ChatMessage).where(ChatMessage.message_id == message_id).limit(1) + ) + db_message = msg_result.scalar_one_or_none() + if not db_message or db_message.message in ALL_WORDS: + return False + keywords = db_message.keywords + try: + await bot.delete_msg(message_id=message_id) + except ActionFailed: + log_info("群聊学习", f"待禁用消息{message_id}尝试撤回失败") + else: + lr_result = await session.execute( + select(ChatMessage) + .where( + ChatMessage.group_id == self.data.group_id, + ChatMessage.user_id == self.bot_id, + ) + .order_by(ChatMessage.time.desc()).limit(1) + ) + last_reply = lr_result.scalar_one_or_none() + if not last_reply or last_reply.message in ALL_WORDS: + return False + keywords = last_reply.keywords + try: + await bot.delete_msg(message_id=last_reply.message_id) + except ActionFailed: + log_info("群聊学习", f"待禁用消息{last_reply.message_id}尝试撤回失败") + + bl_result = await session.execute( + select(ChatBlackList).where(ChatBlackList.keywords == keywords).limit(1) + ) + ban_word = bl_result.scalar_one_or_none() + if ban_word: + if self.data.group_id not in ban_word.ban_group_id: + ban_word.ban_group_id = ban_word.ban_group_id + [self.data.group_id] + if len(ban_word.ban_group_id) >= 2: + ban_word.global_ban = True + log_info("群聊学习", f"学习词{keywords}将被全局禁用") + await session.execute(delete(ChatAnswer).where(ChatAnswer.keywords == keywords)) + else: + log_info("群聊学习", f"群{self.data.group_id}禁用了学习词{keywords}") + await session.execute( + delete(ChatAnswer).where( + ChatAnswer.keywords == keywords, + ChatAnswer.group_id == self.data.group_id, + ) + ) + else: + log_info("群聊学习", f"群{self.data.group_id}禁用了学习词{keywords}") + ban_word = ChatBlackList(keywords=keywords, ban_group_id=[self.data.group_id]) + session.add(ban_word) + await session.execute( + delete(ChatAnswer).where( + ChatAnswer.keywords == keywords, + ChatAnswer.group_id == self.data.group_id, + ) + ) + await session.execute(delete(ChatContext).where(ChatContext.keywords == keywords)) + await session.commit() + return True + + @staticmethod + async def add_ban(data: Union[ChatMessage, ChatContext, ChatAnswer]): + # 提前读出需要的字段 + keywords = data.keywords + group_id = getattr(data, "group_id", None) + is_message = isinstance(data, ChatMessage) + + async with get_session() as session: + bl_result = await session.execute( + select(ChatBlackList).where(ChatBlackList.keywords == keywords).limit(1) + ) + ban_word = bl_result.scalar_one_or_none() + if ban_word: + if is_message and group_id: + if group_id not in ban_word.ban_group_id: + ban_word.ban_group_id = ban_word.ban_group_id + [group_id] + if len(ban_word.ban_group_id) >= 2: + ban_word.global_ban = True + log_info("群聊学习", f"学习词{keywords}将被全局禁用") + await session.execute(delete(ChatAnswer).where(ChatAnswer.keywords == keywords)) + else: + log_info("群聊学习", f"群{group_id}禁用了学习词{keywords}") + await session.execute( + delete(ChatAnswer).where( + ChatAnswer.keywords == keywords, + ChatAnswer.group_id == group_id, + ) + ) + else: + ban_word.global_ban = True + log_info("群聊学习", f"学习词{keywords}将被全局禁用") + await session.execute(delete(ChatAnswer).where(ChatAnswer.keywords == keywords)) + else: + if is_message and group_id: + log_info("群聊学习", f"群{group_id}禁用了学习词{keywords}") + ban_word = ChatBlackList(keywords=keywords, ban_group_id=[group_id]) + await session.execute( + delete(ChatAnswer).where( + ChatAnswer.keywords == keywords, + ChatAnswer.group_id == group_id, + ) + ) + else: + log_info("群聊学习", f"学习词{keywords}将被全局禁用") + ban_word = ChatBlackList(keywords=keywords, global_ban=True) + await session.execute(delete(ChatAnswer).where(ChatAnswer.keywords == keywords)) + session.add(ban_word) + await session.execute(delete(ChatContext).where(ChatContext.keywords == keywords)) + await session.commit() + + @staticmethod + async def speak(self_id: int) -> Optional[Tuple[int, List[Union[str, MessageSegment]]]]: + cur_time = int(time.time()) + today_time = time.mktime(datetime.date.today().timetuple()) + + async with get_session() as session: + groups_result = await session.execute( + select(ChatMessage.group_id, func.count(ChatMessage.id).label("count")) + .where(ChatMessage.time >= today_time) + .group_by(ChatMessage.group_id) + .having(func.count(ChatMessage.id) >= 10) + ) + groups = [row[0] for row in groups_result.all()] + if not groups: + return None + + total_messages = {} + for group_id in groups: + msgs_result = await session.execute( + select(ChatMessage) + .where(ChatMessage.group_id == group_id, ChatMessage.time >= today_time) + .order_by(ChatMessage.time.desc()) + ) + msgs = [_db_to_message_data(m) for m in msgs_result.scalars().all()] + if msgs: + total_messages[group_id] = msgs + + if not total_messages: + return None + + def group_popularity_cmp(left_group, right_group): + def cmp(a, b): + return (a > b) - (a < b) + left_group_id, left_messages = left_group + right_group_id, right_messages = right_group + left_duration = left_messages[0].time - left_messages[-1].time + right_duration = right_messages[0].time - right_messages[-1].time + return cmp( + len(left_messages) / left_duration if left_duration else 0, + len(right_messages) / right_duration if right_duration else 0, + ) + + popularity = sorted(total_messages.items(), key=cmp_to_key(group_popularity_cmp), reverse=True) + log_info("群聊学习", f'主动发言:群热度排行{">>".join([str(g[0]) for g in popularity])}') + + for group_id, messages in popularity: + if len(messages) < 30: + log_info("群聊学习", f"主动发言:群{group_id}消息小于30条,不发言") + continue + + config = config_manager.get_group_config(group_id) + ban_words = set( + chat_config.ban_words + config.ban_words + [ + "[CQ:xml", "[CQ:json", "[CQ:at", "[CQ:video", "[CQ:record", "[CQ:share", + ] + ) + + if not config.speak_enable or not config.enable: + log_info("群聊学习", f"主动发言:群{group_id}未开启,不发言") + continue + + lr_result = await session.execute( + select(ChatMessage) + .where(ChatMessage.group_id == group_id, ChatMessage.user_id == self_id) + .order_by(ChatMessage.time.desc()).limit(1) + ) + last_reply = lr_result.scalar_one_or_none() + if last_reply: + last_reply_time = last_reply.time + if last_reply_time >= messages[0].time: + log_info("群聊学习", f"主动发言:群{group_id}最后一条消息是{NICKNAME}发的,不发言") + continue + elif cur_time - last_reply_time < config.speak_min_interval: + log_info("群聊学习", f"主动发言:群{group_id}上次主动发言时间小于主动发言最小间隔,不发言") + continue + + avg_interval = (messages[0].time - messages[-1].time) / len(messages) + silent_time = cur_time - messages[0].time + threshold = avg_interval * config.speak_threshold + if silent_time < threshold: + log_info("群聊学习", f"主动发言:群{group_id}已沉默时间({silent_time})小于阈值({int(threshold)}),不发言") + continue + + ctx_result = await session.execute( + select(ChatContext).where(ChatContext.count >= config.answer_threshold) + ) + contexts = ctx_result.scalars().all() + if not contexts: + continue + + speak_list = [] + contexts_list = list(contexts) + random.shuffle(contexts_list) + for context in contexts_list: + if ( + not speak_list or random.random() < config.speak_continuously_probability + ) and len(speak_list) < config.speak_continuously_max_len: + ans_result = await session.execute( + select(ChatAnswer).where( + ChatAnswer.context_id == context.id, + ChatAnswer.group_id == group_id, + ChatAnswer.count >= config.answer_threshold, + ) + ) + answers = ans_result.scalars().all() + if answers: + answer_data = [(a.count, a.time, list(a.messages), a.keywords) for a in answers] + answer = random.choices( + answer_data, + weights=[a[0] + 1 if a[1] >= today_time else a[0] for a in answer_data], + )[0] + message = random.choice(answer[2]) + if len(message) < 2: + continue + if message.startswith("[") and message.endswith("]"): + continue + if any(word in message for word in ban_words): + continue + speak_list.append(message) + follow_keywords = answer[3] + + while ( + random.random() < config.speak_continuously_probability + and len(speak_list) < config.speak_continuously_max_len + ): + fc_result = await session.execute( + select(ChatContext).where(ChatContext.keywords == follow_keywords).limit(1) + ) + follow_context = fc_result.scalar_one_or_none() + if follow_context: + fa_result = await session.execute( + select(ChatAnswer).where( + ChatAnswer.group_id == group_id, + ChatAnswer.context_id == follow_context.id, + ChatAnswer.count >= config.answer_threshold, + ) + ) + follow_answers = fa_result.scalars().all() + if follow_answers: + fa_data = [(a.count, a.time, list(a.messages), a.keywords) for a in follow_answers] + follow_answer = random.choices( + fa_data, + weights=[a[0] + 1 if a[1] >= today_time else a[0] for a in fa_data], + )[0] + message = random.choice(follow_answer[2]) + follow_keywords = follow_answer[3] + if len(message) < 2: + continue + if message.startswith("[") and message.endswith("]"): + continue + if all(word not in message for word in ban_words): + speak_list.append(message) + else: + break + else: + break + else: + break + + if speak_list: + if random.random() < config.speak_poke_probability: + last_speak_users = {m.user_id for m in messages[:5] if m.user_id != self_id} + if last_speak_users: + select_user = random.choice(list(last_speak_users)) + speak_list.append(MessageSegment("poke", {"qq": select_user})) + # 手动戳 + # await send_poke(group_id=group_id, user_id=select_user) + return group_id, speak_list + else: + log_info("群聊学习", f"主动发言:群{group_id}没有找到符合条件的发言,不发言") + + log_info("群聊学习", "主动发言:没有符合条件的群,不主动发言") + return None + + async def _set_answer(self, session, message: MessageData): + """在已有 session 内设置回复,不新开 session""" + ctx_result = await session.execute( + select(ChatContext).where(ChatContext.keywords == message.keywords).limit(1) + ) + context = ctx_result.scalar_one_or_none() + if context: + if context.count < chat_config.learn_max_count: + context.count += 1 + context.time = self.data.time + ans_result = await session.execute( + select(ChatAnswer).where( + ChatAnswer.keywords == self.data.keywords, + ChatAnswer.group_id == self.data.group_id, + ChatAnswer.context_id == context.id, + ).limit(1) + ) + answer = ans_result.scalar_one_or_none() + if answer: + if answer.count < chat_config.learn_max_count: + answer.count += 1 + answer.time = self.data.time + if self.data.message not in answer.messages: + answer.messages = answer.messages + [self.data.message] + answer_count = answer.count + else: + answer = ChatAnswer( + keywords=self.data.keywords, + group_id=self.data.group_id, + time=self.data.time, + context=context, + messages=[self.data.message], + ) + session.add(answer) + answer_count = 1 + else: + context = ChatContext(keywords=message.keywords, time=self.data.time) + session.add(context) + await session.flush() + answer = ChatAnswer( + keywords=self.data.keywords, + group_id=self.data.group_id, + time=self.data.time, + context=context, + messages=[self.data.message], + ) + session.add(answer) + answer_count = 1 + + await session.commit() + log_info( + "群聊学习", + f"➤将被学习为{message.message}的回答,已学次数为{answer_count}", + ) + + async def _check_allow(self, session, message: MessageData) -> bool: + """检查 MessageData 是否合法""" + raw_message = message.message + if any( + i in raw_message + for i in {"[CQ:xml", "[CQ:json", "[CQ:at", "[CQ:video", "[CQ:record", "[CQ:share"} + ): + return False + if any(i in raw_message for i in self.ban_words): + return False + if raw_message.startswith("[") and raw_message.endswith("]"): + return False + bl_result = await session.execute( + select(ChatBlackList).where(ChatBlackList.keywords == message.keywords).limit(1) + ) + ban_word = bl_result.scalar_one_or_none() + if ban_word: + if ban_word.global_ban or message.group_id in ban_word.ban_group_id: + return False + return True + + async def _check_allow_answer(self, session, keywords: str, group_id: int, messages: List[str]) -> bool: + """检查 ChatAnswer 内容是否合法(使用原始字段而非 ORM 对象)""" + if not messages: + return False + raw_message = messages[0] + if any( + i in raw_message + for i in {"[CQ:xml", "[CQ:json", "[CQ:at", "[CQ:video", "[CQ:record", "[CQ:share"} + ): + return False + if any(i in raw_message for i in self.ban_words): + return False + if raw_message.startswith("[") and raw_message.endswith("]"): + return False + bl_result = await session.execute( + select(ChatBlackList).where(ChatBlackList.keywords == keywords).limit(1) + ) + ban_word = bl_result.scalar_one_or_none() + if ban_word: + if ban_word.global_ban or group_id in ban_word.ban_group_id: + return False + return True \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_learning_chat/models.py b/hexi/plugins/nonebot_plugin_learning_chat/models.py new file mode 100644 index 0000000..3db3b5c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/models.py @@ -0,0 +1,110 @@ +import functools +import json +from functools import cached_property +from typing import List, Optional, TYPE_CHECKING + +try: + import ujson as json +except ImportError: + import json +try: + import jieba_fast as jieba + import jieba_fast.analyse as jieba_analyse +except ImportError: + import jieba + import jieba.analyse as jieba_analyse + +from nonebot import require +require("nonebot_plugin_orm") + +from nonebot_plugin_orm import Model +from sqlalchemy import BigInteger, Boolean, Integer, Text, ForeignKey, Index +from sqlalchemy.orm import Mapped, mapped_column, relationship +from sqlalchemy.types import JSON + +from .config import config_manager + +config = config_manager.config + +JSON_DUMPS = functools.partial(json.dumps, ensure_ascii=False) +jieba.setLogLevel(jieba.logging.INFO) +jieba.load_userdict(config.dictionary) + + +class ChatMessage(Model): + __tablename__ = "learning_chat_message" + __table_args__ = ( + Index("ix_message_group_time", "group_id", "time"), + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + group_id: Mapped[int] = mapped_column(BigInteger) + user_id: Mapped[int] = mapped_column(BigInteger) + message_id: Mapped[int] = mapped_column(BigInteger) + message: Mapped[str] = mapped_column(Text) + raw_message: Mapped[str] = mapped_column(Text) + plain_text: Mapped[str] = mapped_column(Text) + time: Mapped[int] = mapped_column(Integer) + + @cached_property + def is_plain_text(self) -> bool: + return "[CQ:" not in self.message + + @cached_property + def keyword_list(self) -> List[str]: + if not self.is_plain_text and not len(self.plain_text): + return [] + return jieba_analyse.extract_tags(self.plain_text, topK=config.KEYWORDS_SIZE) + + @cached_property + def keywords(self) -> str: + if not self.is_plain_text and not len(self.plain_text): + return self.message + return ( + self.message if len(self.keyword_list) < 2 else " ".join(self.keyword_list) + ) + + +class ChatContext(Model): + __tablename__ = "learning_chat_context" + __table_args__ = ( + Index("ix_context_keywords_time", "keywords", "time"), + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + keywords: Mapped[str] = mapped_column(Text) + time: Mapped[int] = mapped_column(Integer) + count: Mapped[int] = mapped_column(Integer, default=1) + + answers: Mapped[List["ChatAnswer"]] = relationship(back_populates="context") + + +class ChatAnswer(Model): + __tablename__ = "learning_chat_answer" + __table_args__ = ( + Index("ix_answer_keywords_time", "keywords", "time"), + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + keywords: Mapped[str] = mapped_column(Text) + group_id: Mapped[int] = mapped_column(BigInteger) + count: Mapped[int] = mapped_column(Integer, default=1) + time: Mapped[int] = mapped_column(Integer) + messages: Mapped[list] = mapped_column(JSON, default=list) + + context_id: Mapped[Optional[int]] = mapped_column( + Integer, ForeignKey("learning_chat_context.id"), nullable=True + ) + context: Mapped[Optional[ChatContext]] = relationship(back_populates="answers") + + +class ChatBlackList(Model): + __tablename__ = "learning_chat_blacklist" + __table_args__ = ( + Index("ix_blacklist_keywords", "keywords"), + ) + + id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) + keywords: Mapped[str] = mapped_column(Text) + global_ban: Mapped[bool] = mapped_column(Boolean, default=False) + ban_group_id: Mapped[list] = mapped_column(JSON, default=list) \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/.gitignore b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/README.md b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/README.md new file mode 100644 index 0000000..33895ab --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/README.md @@ -0,0 +1,5 @@ +# Vue 3 + TypeScript + Vite + +This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 ` + + \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/package-lock.json b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/package-lock.json new file mode 100644 index 0000000..a87aee2 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/package-lock.json @@ -0,0 +1,1559 @@ +{ + "name": "learning-chat-admin", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "learning-chat-admin", + "version": "1.0.0", + "dependencies": { + "@element-plus/icons-vue": "^2.3.2", + "axios": "^1.5.0", + "element-plus": "^2.14.3", + "pinia": "^2.1.6", + "vue": "^3.3.4", + "vue-router": "^4.2.5" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "@vitejs/plugin-vue": "^4.5.0", + "typescript": "^5.2.2", + "vite": "^4.5.0", + "vue-tsc": "^1.8.19" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz", + "integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz", + "integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "license": "MIT" + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.8.tgz", + "integrity": "sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@types/lodash": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.25.tgz", + "integrity": "sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==", + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/node": { + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~7.19.0" + } + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.6.2.tgz", + "integrity": "sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.0.0 || ^5.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-1.11.1.tgz", + "integrity": "sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "1.11.1" + } + }, + "node_modules/@volar/source-map": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-1.11.1.tgz", + "integrity": "sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "muggle-string": "^0.3.1" + } + }, + "node_modules/@volar/typescript": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-1.11.1.tgz", + "integrity": "sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "1.11.1", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.32", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.32.tgz", + "integrity": "sha512-4x74Tbtqnda8s/NSD6e1Dr5p1c8HdMU5RWSjMSUzb8RTcUQqevDCxVAitcLBKT+ie3o0Dl9crc/S/opJM7qBGQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.2", + "@vue/shared": "3.5.32", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.32", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.32.tgz", + "integrity": "sha512-ybHAu70NtiEI1fvAUz3oXZqkUYEe5J98GjMDpTGl5iHb0T15wQYLR4wE3h9xfuTNA+Cm2f4czfe8B4s+CCH57Q==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.32", + "@vue/shared": "3.5.32" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.32", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.32.tgz", + "integrity": "sha512-8UYUYo71cP/0YHMO814TRZlPuUUw3oifHuMR7Wp9SNoRSrxRQnhMLNlCeaODNn6kNTJsjFoQ/kqIj4qGvya4Xg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.2", + "@vue/compiler-core": "3.5.32", + "@vue/compiler-dom": "3.5.32", + "@vue/compiler-ssr": "3.5.32", + "@vue/shared": "3.5.32", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.8", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.32", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.32.tgz", + "integrity": "sha512-Gp4gTs22T3DgRotZ8aA/6m2jMR+GMztvBXUBEUOYOcST+giyGWJ4WvFd7QLHBkzTxkfOt8IELKNdpzITLbA2rw==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.32", + "@vue/shared": "3.5.32" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/language-core": { + "version": "1.8.27", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-1.8.27.tgz", + "integrity": "sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "~1.11.1", + "@volar/source-map": "~1.11.1", + "@vue/compiler-dom": "^3.3.0", + "@vue/shared": "^3.3.0", + "computeds": "^0.0.1", + "minimatch": "^9.0.3", + "muggle-string": "^0.3.1", + "path-browserify": "^1.0.1", + "vue-template-compiler": "^2.7.14" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.32", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.32.tgz", + "integrity": "sha512-/ORasxSGvZ6MN5gc+uE364SxFdJ0+WqVG0CENXaGW58TOCdrAW76WWaplDtECeS1qphvtBZtR+3/o1g1zL4xPQ==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.32" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.32", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.32.tgz", + "integrity": "sha512-pDrXCejn4UpFDFmMd27AcJEbHaLemaE5o4pbb7sLk79SRIhc6/t34BQA7SGNgYtbMnvbF/HHOftYBgFJtUoJUQ==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.32", + "@vue/shared": "3.5.32" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.32", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.32.tgz", + "integrity": "sha512-1CDVv7tv/IV13V8Nip1k/aaObVbWqRlVCVezTwx3K07p7Vxossp5JU1dcPNhJk3w347gonIUT9jQOGutyJrSVQ==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.32", + "@vue/runtime-core": "3.5.32", + "@vue/shared": "3.5.32", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.32", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.32.tgz", + "integrity": "sha512-IOjm2+JQwRFS7W28HNuJeXQle9KdZbODFY7hFGVtnnghF51ta20EWAZJHX+zLGtsHhaU6uC9BGPV52KVpYryMQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.32", + "@vue/shared": "3.5.32" + }, + "peerDependencies": { + "vue": "3.5.32" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.32", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.32.tgz", + "integrity": "sha512-ksNyrmRQzWJJ8n3cRDuSF7zNNontuJg1YHnmWRJd2AMu8Ij2bqwiiri2lH5rHtYPZjj4STkNcgcmiQqlOjiYGg==", + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.3.0.tgz", + "integrity": "sha512-aHfz47g0ZhMtTVHmIzMVpJy8ePhhOy68GY5bv110+5DVtZ+W7BsOx+m61UNQqfrWyPztIHIanWa3E2tib3NFIw==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "14.3.0", + "@vueuse/shared": "14.3.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/@vueuse/metadata": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.3.0.tgz", + "integrity": "sha512-BwxmbAzwAVF50+MW57GXOUEV61nFBGnlBvrTqj49PqWJu3uw7hdu72ztXeZ33RdZtDY6kO+bfCAE1PCn88Tktw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.3.0.tgz", + "integrity": "sha512-bZpge9eSXwa4ToSiqJ7j6KRwhAsneMFoSz3LMWKQDkqimm3D/tbFlrklrs/IOqC8tEcYmXQZJ6N0UrjhBirVCg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.15.0.tgz", + "integrity": "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/computeds": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/computeds/-/computeds-0.0.1.tgz", + "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/dayjs": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", + "license": "MIT" + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/element-plus": { + "version": "2.14.3", + "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.14.3.tgz", + "integrity": "sha512-pJcvxcpZjYruNzuJhAeVwnbYjfNgzBKnWHwSVEhwzM2/kcLI3brzmtIBxtPqd4hQWJfD1PRnjoc1WipLw2eBGg==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^4.2.0", + "@element-plus/icons-vue": "^2.3.2", + "@floating-ui/dom": "^1.7.6", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.8", + "@types/lodash": "^4.17.24", + "@types/lodash-es": "^4.17.12", + "@vueuse/core": "14.3.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.20", + "lodash": "^4.18.1", + "lodash-es": "^4.18.1", + "lodash-unified": "^1.0.3", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0", + "vue-component-type-helpers": "^3.3.5" + }, + "peerDependencies": { + "vue": "^3.3.7" + } + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT", + "peer": true + }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "license": "MIT", + "peer": true + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "license": "MIT", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/muggle-string": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.3.1.tgz", + "integrity": "sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", + "license": "BSD-3-Clause" + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/pinia": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz", + "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.3", + "vue-demi": "^0.14.10" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "typescript": ">=4.4.4", + "vue": "^2.7.0 || ^3.5.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/postcss": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/rollup": { + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.30.0.tgz", + "integrity": "sha512-kQvGasUgN+AlWGliFn2POSajRQEsULVYFGTvOZmK06d7vCD+YhZztt70kGk3qaeAXeWYL5eO7zx+rAubBc55eA==", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "4.5.14", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.14.tgz", + "integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.32", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.32.tgz", + "integrity": "sha512-vM4z4Q9tTafVfMAK7IVzmxg34rSzTFMyIe0UUEijUCkn9+23lj0WRfA83dg7eQZIUlgOSGrkViIaCfqSAUXsMw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/compiler-dom": "3.5.32", + "@vue/compiler-sfc": "3.5.32", + "@vue/runtime-dom": "3.5.32", + "@vue/server-renderer": "3.5.32", + "@vue/shared": "3.5.32" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-component-type-helpers": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/vue-component-type-helpers/-/vue-component-type-helpers-3.3.9.tgz", + "integrity": "sha512-3c/UfMe0SqyEfcGTyH7mfshHagJ9QTCbppCb0/uGpHZpFug7+If3GeGZN7I0YheKEExemx3xldQPoO7PQSOLQg==", + "license": "MIT" + }, + "node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/vue-router": { + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.6.4.tgz", + "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/vue-template-compiler": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", + "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/vue-tsc": { + "version": "1.8.27", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-1.8.27.tgz", + "integrity": "sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "~1.11.1", + "@vue/language-core": "1.8.27", + "semver": "^7.5.4" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": "*" + } + } + } +} diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/package.json b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/package.json new file mode 100644 index 0000000..22cae09 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/package.json @@ -0,0 +1,27 @@ +{ + "name": "learning-chat-admin", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix" + }, + "dependencies": { + "@element-plus/icons-vue": "^2.3.2", + "axios": "^1.5.0", + "element-plus": "^2.14.3", + "pinia": "^2.1.6", + "vue": "^3.3.4", + "vue-router": "^4.2.5" + }, + "devDependencies": { + "@types/node": "^25.6.0", + "@vitejs/plugin-vue": "^4.5.0", + "typescript": "^5.2.2", + "vite": "^4.5.0", + "vue-tsc": "^1.8.19" + } +} diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/public/favicon.svg b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/public/favicon.svg new file mode 100644 index 0000000..6893eb1 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/App.vue b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/App.vue new file mode 100644 index 0000000..c9ecb13 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/App.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/api/client.ts b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/api/client.ts new file mode 100644 index 0000000..fe5f51f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/api/client.ts @@ -0,0 +1,204 @@ +import axios, { AxiosError } from 'axios'; +import { ElMessage } from 'element-plus'; +import router from '@/router'; +import { useAuthStore } from '@/stores/auth'; +import type { + ApiResponse, + BlacklistItem, + ChatAnswer, + ChatContext, + ChatMessage, + GlobalConfig, + GroupConfig, + GroupInfo, + LoginResult, + PaginatedData, +} from '@/types'; + +/** 带状态码的请求错误 */ +export class ApiError extends Error { + status: number; + + /** 认证失效类错误: 已由全局拦截器提示并跳转登录, 视图层不再重复弹窗 */ + authHandled = false; + + constructor(message: string, status = 0) { + super(message); + this.status = status; + } +} + +let redirectingToLogin = false; + +/** 认证失效: 清除登录态并跳转登录页(避免并发失败时重复跳转) */ +function handleUnauthorized() { + const authStore = useAuthStore(); + authStore.logout(); + if (router.currentRoute.value.path !== '/login' && !redirectingToLogin) { + redirectingToLogin = true; + ElMessage.warning('登录已失效,请重新登录'); + router.push('/login').finally(() => { + redirectingToLogin = false; + }); + } +} + +class ApiClient { + private axiosInstance; + + constructor() { + this.axiosInstance = axios.create({ + baseURL: '/learning_chat/api', + timeout: 30000, + }); + + // 请求: 附加 token 头(后端契约: authentication() 读取 token header) + this.axiosInstance.interceptors.request.use((config) => { + const authStore = useAuthStore(); + if (authStore.token) { + config.headers.token = authStore.token; + } + return config; + }); + + // 响应: 三态归一化 + // 1. {"status": 0, "msg", "data"} → 成功, 返回整个信封(data 由调用方取) + // 2. {"status": !=0, "msg"} → 业务失败(HTTP 200 内) + // 3. {"detail": ...}(HTTP 400/422)→ 认证失效/参数错误 + // 4. 裸 dict(全局/分群配置 GET)→ 直接返回 + this.axiosInstance.interceptors.response.use( + (response) => { + const data = response.data; + if (data && typeof data === 'object' && !Array.isArray(data)) { + if (typeof data.detail !== 'undefined') { + handleUnauthorized(); + const err = new ApiError(String(data.detail), response.status); + err.authHandled = true; + throw err; + } + if (typeof data.status === 'number') { + if (data.status === 0) return data; + throw new ApiError(String(data.msg || '操作失败'), data.status); + } + } + return data; + }, + (error: AxiosError) => { + const status = error.response?.status; + const data = error.response?.data as { detail?: unknown } | undefined; + const isAuthError = status === 400 || status === 422; + // 后端认证失效契约为 HTTP 400/422 + {"detail"} + if (isAuthError) { + handleUnauthorized(); + } + const detail = data?.detail; + const message = + typeof detail === 'string' + ? detail + : status === 0 + ? '无法连接到服务器' + : error.message || '网络请求失败'; + const apiError = new ApiError(message, status ?? 0); + apiError.authHandled = isAuthError; + return Promise.reject(apiError); + } + ); + } + + /** 登录 */ + async login(username: string, password: string): Promise> { + return this.axiosInstance.post('/login', { username, password }); + } + + /** 获取群列表 */ + async getGroupList(): Promise> { + return this.axiosInstance.get('/get_group_list'); + } + + /** 获取全局配置(裸 dict) */ + async getGlobalConfig(): Promise { + return this.axiosInstance.get('/chat_global_config'); + } + + /** 保存全局配置 */ + async saveGlobalConfig(data: GlobalConfig): Promise { + return this.axiosInstance.post('/chat_global_config', data); + } + + /** 获取分群配置(裸 dict, 概率为百分比) */ + async getGroupConfig(groupId: number | string): Promise { + return this.axiosInstance.get(`/chat_group_config?group_id=${groupId}`); + } + + /** 保存分群配置(groupId 传 'all' 表示保存至所有群) */ + async saveGroupConfig(groupId: number | string, data: GroupConfig): Promise { + return this.axiosInstance.post(`/chat_group_config?group_id=${groupId}`, data); + } + + /** 获取聊天消息 */ + async getMessages(params: { + page?: number; + perPage?: number; + orderBy?: string; + orderDir?: string; + group_id?: string; + user_id?: string; + message?: string; + }): Promise>> { + return this.axiosInstance.get('/get_chat_messages', { params }); + } + + /** 获取学习内容 */ + async getContexts(params: { + page?: number; + perPage?: number; + orderBy?: string; + orderDir?: string; + keywords?: string; + }): Promise>> { + return this.axiosInstance.get('/get_chat_contexts', { params }); + } + + /** 获取回复 */ + async getAnswers(params: { + page?: number; + perPage?: number; + orderBy?: string; + orderDir?: string; + context_id?: number; + keywords?: string; + }): Promise>> { + return this.axiosInstance.get('/get_chat_answers', { params }); + } + + /** 获取禁用列表 */ + async getBlacklist(params: { + page?: number; + perPage?: number; + keywords?: string; + bans?: string; + }): Promise>> { + return this.axiosInstance.get('/get_chat_blacklist', { params }); + } + + /** 删除(type: message | context | answer | blacklist) */ + async deleteChat(type: string, id: number): Promise { + return this.axiosInstance.delete(`/delete_chat?type=${type}&id=${id}`); + } + + /** 禁用(type: message | context | answer) */ + async banChat(type: string, id: number): Promise { + return this.axiosInstance.put(`/ban_chat?type=${type}&id=${id}`); + } + + /** 批量删除/取消禁用(type: answer | blacklist | context | message, id 可选) */ + async deleteAll(type: string, id?: number): Promise { + let url = `/delete_all?type=${type}`; + if (id !== undefined) { + url += `&id=${id}`; + } + return this.axiosInstance.put(url); + } +} + +export default new ApiClient(); diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/components/FullTextDialog.vue b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/components/FullTextDialog.vue new file mode 100644 index 0000000..475fbe6 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/components/FullTextDialog.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/main.ts b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/main.ts new file mode 100644 index 0000000..b45aba9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/main.ts @@ -0,0 +1,22 @@ +import { createApp } from 'vue'; +import { createPinia } from 'pinia'; +import ElementPlus from 'element-plus'; +import 'element-plus/dist/index.css'; +import * as ElementPlusIconsVue from '@element-plus/icons-vue'; +import router from '@/router'; +import App from '@/App.vue'; +import '@/style.css'; + +// 移除旧版「API 地址设置」功能残留(同源架构下该功能已废弃, 写死的地址会导致跨域失败) +localStorage.removeItem('API_BASE_URL'); + +const app = createApp(App); + +for (const [key, component] of Object.entries(ElementPlusIconsVue)) { + app.component(key, component); +} + +app.use(createPinia()); +app.use(router); +app.use(ElementPlus); +app.mount('#app'); diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/router/index.ts b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/router/index.ts new file mode 100644 index 0000000..0ed3295 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/router/index.ts @@ -0,0 +1,105 @@ +import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; +import { ElMessage } from 'element-plus'; +import { useAuthStore } from '@/stores/auth'; + +// 懒加载视图 +const Login = () => import('@/views/Login.vue'); +const Config = () => import('@/views/Config.vue'); +const Messages = () => import('@/views/Messages.vue'); +const Contexts = () => import('@/views/Contexts.vue'); +const Answers = () => import('@/views/Answers.vue'); +const Blacklist = () => import('@/views/Blacklist.vue'); + +const routes: RouteRecordRaw[] = [ + { + path: '/', + redirect: () => { + const authStore = useAuthStore(); + return authStore.isAuthenticated ? '/config' : '/login'; + }, + }, + { + path: '/login', + name: 'Login', + component: Login, + meta: { requiresAuth: false }, + }, + { + path: '/config', + name: 'Config', + component: Config, + meta: { requiresAuth: true }, + }, + { + path: '/messages', + name: 'Messages', + component: Messages, + meta: { requiresAuth: true }, + }, + { + path: '/contexts', + name: 'Contexts', + component: Contexts, + meta: { requiresAuth: true }, + }, + { + path: '/answers', + name: 'Answers', + component: Answers, + meta: { requiresAuth: true }, + }, + { + path: '/blacklist', + name: 'Blacklist', + component: Blacklist, + meta: { requiresAuth: true }, + }, + { + path: '/:pathMatch(.*)*', + redirect: '/login', + meta: { requiresAuth: false }, + }, +]; + +const router = createRouter({ + // base 与 vite.config.ts 的 base 保持一致, 否则 SPA 导航会产生不带前缀的根路径 URL, 刷新即 404 + history: createWebHistory('/learning_chat/'), + routes, +}); + +// 全局路由守卫 +router.beforeEach((to, _from) => { + const authStore = useAuthStore(); + + // token 已过期(按 JWT exp 主动检测) -> 立即登出跳登录页 + if (authStore.token) { + const exp = authStore.getTokenExpiry(authStore.token); + if (exp !== null && exp * 1000 <= Date.now()) { + authStore.logout(); + if (to.path !== '/login') { + ElMessage.warning('登录已过期,请重新登录'); + return { path: '/login', query: { redirect: to.fullPath } }; + } + } + } + + const requiresAuth = to.meta.requiresAuth; + + // 需要登录但未认证 -> 跳登录页 + if (requiresAuth && !authStore.isAuthenticated) { + return { + path: '/login', + query: { redirect: to.fullPath }, + }; + } + + // 已登录但访问登录页 -> 跳配置页 + if (to.path === '/login' && authStore.isAuthenticated) { + return '/config'; + } + + // 其他情况放行 + return true; +}); + +export default router; \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/stores/auth.ts b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/stores/auth.ts new file mode 100644 index 0000000..f7aa1a9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/stores/auth.ts @@ -0,0 +1,81 @@ +import { defineStore } from 'pinia'; +import { ref, computed } from 'vue'; + +export const useAuthStore = defineStore('auth', () => { + // 初始化时从 localStorage 读取 + const token = ref(localStorage.getItem('token') || ''); + const username = ref(localStorage.getItem('username') || ''); + + const isAuthenticated = computed(() => !!token.value); + + let expireTimer: ReturnType | null = null; + + /** 解析 JWT payload 中的 exp(unix 秒); 非 JWT 或解析失败返回 null */ + const getTokenExpiry = (t: string): number | null => { + try { + const payload = t.split('.')[1]; + if (!payload) return null; + const json = JSON.parse( + atob(payload.replace(/-/g, '+').replace(/_/g, '/')) + ); + return typeof json.exp === 'number' ? json.exp : null; + } catch { + return null; + } + }; + + /** + * 注册到期自动登出: + * - token 已过期 → 立即 logout 并返回 true + * - 未过期 → 在 exp 时刻触发 onExpired 回调 + */ + const scheduleAutoLogout = (onExpired?: () => void): boolean => { + if (expireTimer) { + clearTimeout(expireTimer); + expireTimer = null; + } + if (!token.value) return false; + const exp = getTokenExpiry(token.value); + if (exp === null) return false; + const remainingMs = exp * 1000 - Date.now(); + if (remainingMs <= 0) { + logout(); + return true; + } + expireTimer = setTimeout(() => { + logout(); + onExpired?.(); + }, remainingMs); + return false; + }; + + const setAuth = (newToken: string, newUsername: string) => { + token.value = newToken; + username.value = newUsername; + localStorage.setItem('token', newToken); + localStorage.setItem('username', newUsername); + // 登录即武装到期定时器 + scheduleAutoLogout(); + }; + + const logout = () => { + if (expireTimer) { + clearTimeout(expireTimer); + expireTimer = null; + } + token.value = ''; + username.value = ''; + localStorage.removeItem('token'); + localStorage.removeItem('username'); + }; + + return { + token, + username, + isAuthenticated, + getTokenExpiry, + scheduleAutoLogout, + setAuth, + logout, + }; +}); diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/style.css b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/style.css new file mode 100644 index 0000000..fe37268 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/style.css @@ -0,0 +1,79 @@ +/* 全局样式 — Element Plus 自带 reset, 这里只保留主题与少量通用类 */ +html, +body, +#app { + height: 100%; + margin: 0; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + background: #f5f7fa; + color: #303133; +} + +/* 页面级白色卡片容器(列表页) */ +.page-card { + background: #fff; + border-radius: 8px; + padding: 20px; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06); +} + +/* 页面顶部说明条 */ +.page-tip { + margin-bottom: 16px; +} + +/* 搜索栏与操作行 */ +.toolbar { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-bottom: 16px; +} + +.toolbar .el-input { + width: 160px; +} + +.toolbar .toolbar-wide { + width: 240px; +} + +/* 分页容器 */ +.pagination-wrap { + display: flex; + justify-content: center; + margin-top: 16px; +} + +/* 表格内可点击查看完整内容的长文本单元格 */ +.clickable-cell { + cursor: pointer; + color: #606266; + transition: color 0.2s; +} + +.clickable-cell:hover { + color: var(--el-color-primary); + text-decoration: underline; +} + +/* 单行省略(配合可点击单元格使用) */ +.cell-ellipsis { + display: block; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* 表单辅助说明文字 */ +.help-text { + font-size: 12px; + color: #909399; + line-height: 1.6; + margin-top: 4px; +} diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/types/index.ts b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/types/index.ts new file mode 100644 index 0000000..20f4ac5 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/types/index.ts @@ -0,0 +1,97 @@ +/** + * 与后端 web_api.py 契约一致的类型定义 + */ + +/** 后端统一信封(列表/操作类接口); 配置 GET 返回裸 dict, 认证错误返回 {"detail"} */ +export interface ApiResponse { + status: number; + msg: string; + data?: T; +} + +export interface PaginatedData { + items: T[]; + total: number; +} + +export interface LoginResult { + token: string; +} + +export interface GroupInfo { + label: string; + value: number; +} + +export interface ChatMessage { + id: number; + message_id: string | number; + group_id: number; + user_id: number; + raw_message: string; + message?: string; + /** unix 秒整数 */ + time: number; +} + +export interface ChatContext { + id: number; + keywords: string; + /** unix 秒整数 */ + time: number; + count: number; +} + +export interface ChatAnswer { + id: number; + group_id: number; + keywords: string; + /** unix 秒整数 */ + time: number; + count: number; + context_id: number; + /** 旧数据可能为 null */ + messages: Array<{ msg: string }> | null; +} + +export interface BlacklistItem { + id: number; + keywords: string; + bans: string; + global_ban?: boolean; + ban_group_id?: number[]; +} + +export interface GlobalConfig { + total_enable: boolean; + enable_web: boolean; + web_username: string; + web_password: string; + web_secret_key: string; + KEYWORDS_SIZE: number; + cross_group_threshold: number; + learn_max_count: number; + ban_words: string[]; + ban_users: string[]; + dictionary: string[]; +} + +export interface GroupConfig { + enable: boolean; + answer_threshold: number; + answer_threshold_weights: number[]; + repeat_threshold: number; + /** 0-100 百分比(后端 GET ×100 / POST ÷100 契约) */ + break_probability: number; + speak_enable: boolean; + speak_threshold: number; + speak_min_interval: number; + /** 0-100 百分比 */ + speak_continuously_probability: number; + speak_continuously_max_len: number; + /** 0-100 百分比 */ + speak_poke_probability: number; + ban_words: string[]; + ban_users: string[]; + member_list: GroupInfo[]; +} diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/utils/format.ts b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/utils/format.ts new file mode 100644 index 0000000..5278598 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/utils/format.ts @@ -0,0 +1,14 @@ +/** 后端 time 为 unix 秒整数, 格式化为本地时间(兼容毫秒/字符串) */ +export function formatTime(time: number | string | null | undefined): string { + if (time === null || time === undefined || time === '') return ''; + let t = Number(time); + if (Number.isNaN(t)) return String(time); + if (t < 1e12) t *= 1000; // 秒 → 毫秒 + return new Date(t).toLocaleString('zh-CN'); +} + +/** 从错误对象提取可读消息(ApiError/普通 Error/未知值) */ +export function errorMessage(err: unknown, fallback: string): string { + if (err instanceof Error && err.message) return err.message; + return fallback; +} diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/utils/notify.ts b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/utils/notify.ts new file mode 100644 index 0000000..61b9aa0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/utils/notify.ts @@ -0,0 +1,12 @@ +import { ElMessage } from 'element-plus'; +import { ApiError } from '@/api/client'; +import { errorMessage } from './format'; + +/** + * 展示错误提示。 + * 认证失效类错误已由全局拦截器统一提示并跳转登录, 这里跳过, 避免重复弹窗。 + */ +export function showError(err: unknown, fallback: string): void { + if (err instanceof ApiError && err.authHandled) return; + ElMessage.error(errorMessage(err, fallback)); +} diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Answers.vue b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Answers.vue new file mode 100644 index 0000000..527dd8f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Answers.vue @@ -0,0 +1,264 @@ + + + + + diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Blacklist.vue b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Blacklist.vue new file mode 100644 index 0000000..d5706b2 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Blacklist.vue @@ -0,0 +1,170 @@ + + + + + diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Config.vue b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Config.vue new file mode 100644 index 0000000..8092e5e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Config.vue @@ -0,0 +1,586 @@ + + + + + diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Contexts.vue b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Contexts.vue new file mode 100644 index 0000000..1a4a497 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Contexts.vue @@ -0,0 +1,280 @@ + + + diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Login.vue b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Login.vue new file mode 100644 index 0000000..dd91db4 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Login.vue @@ -0,0 +1,159 @@ + + + + + diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Messages.vue b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Messages.vue new file mode 100644 index 0000000..1ca958e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/views/Messages.vue @@ -0,0 +1,188 @@ + + + diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/vue.d.ts b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/vue.d.ts new file mode 100644 index 0000000..4ca75b5 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/src/vue.d.ts @@ -0,0 +1,5 @@ +declare module '*.vue' { + import type { DefineComponent } from 'vue' + const component: DefineComponent<{}, {}, any> + export default component +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/tsconfig.app.json b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/tsconfig.app.json new file mode 100644 index 0000000..5c750c5 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/tsconfig.app.json @@ -0,0 +1,14 @@ +{ + "extends": "@vue/tsconfig/tsconfig.dom.json", + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "types": ["vite/client"], + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/tsconfig.json b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/tsconfig.json new file mode 100644 index 0000000..735d292 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + + /* 路径别名 */ + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + + /* Vue支持 */ + "types": ["vite/client"] + }, + "include": ["src", "src/**/*.ts", "src/**/*.vue", "src/**/*.tsx"], + "references": [{ "path": "./tsconfig.node.json" }] +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/tsconfig.node.json b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/tsconfig.node.json new file mode 100644 index 0000000..4eb43d0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "strict": true + }, + "include": ["vite.config.ts"] +} \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/vite.config.ts b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/vite.config.ts new file mode 100644 index 0000000..3a9116b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web/learning-chat-admin/vite.config.ts @@ -0,0 +1,26 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import path from 'node:path' + +export default defineConfig({ + plugins: [vue()], + // 构建产物由 bot 在 /learning_chat 路径下提供 + base: '/learning_chat/', + resolve: { + alias: { + '@': path.resolve(process.cwd(), 'src'), + }, + }, + server: { + port: 5173, + open: false, + host: '0.0.0.0', + // 开发模式下 API 请求转发到 bot 端口 + proxy: { + '/learning_chat/api': { + target: 'http://localhost:39697', + changeOrigin: true, + }, + }, + }, +}) \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web_api.py b/hexi/plugins/nonebot_plugin_learning_chat/web_api.py new file mode 100644 index 0000000..ae2ef1f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web_api.py @@ -0,0 +1,369 @@ +import datetime +from typing import Optional, Union + +from fastapi import FastAPI +from fastapi import Header, HTTPException, Depends +from fastapi.responses import JSONResponse, HTMLResponse, RedirectResponse +from jose import jwt +from nonebot import get_app, get_adapter, logger +from nonebot.adapters.onebot.v11 import Adapter +from pydantic import BaseModel +from sqlalchemy import select, delete, update, func + +try: + import jieba_fast as jieba +except ImportError: + import jieba + +from nonebot_plugin_orm import get_session +from .handler import LearningChat +from .models import ChatMessage, ChatContext, ChatAnswer, ChatBlackList +from .config import config_manager, driver +from .web_frontend import ensure_frontend_ready, mount_frontend + + +def authentication(): + def inner(token: Optional[str] = Header(...)): + try: + payload = jwt.decode(token, config_manager.config.web_secret_key, algorithms="HS256") + if ( + not (username := payload.get("username")) + or username != config_manager.config.web_username + ): + raise HTTPException(status_code=400, detail="登录验证失败或已失效,请重新登录") + except (jwt.JWTError, jwt.ExpiredSignatureError, AttributeError): + raise HTTPException(status_code=400, detail="登录验证失败或已失效,请重新登录") + + return Depends(inner) + + +class UserModel(BaseModel): + username: str + password: str + + +@driver.on_startup +async def init_web(): + if not config_manager.config.enable_web: + return + if not await ensure_frontend_ready(): + logger.warning("群聊学习 | 前端构建失败, 管理页面将不可用") + app: FastAPI = get_app() + + @app.post("/learning_chat/api/login", response_class=JSONResponse) + async def login(user: UserModel): + if ( + user.username != config_manager.config.web_username + or user.password != config_manager.config.web_password + ): + return {"status": -100, "msg": "登录失败,请确认用户ID和密码无误"} + token = jwt.encode( + { + "username": user.username, + "exp": datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=30), + }, + config_manager.config.web_secret_key, + algorithm="HS256", + ) + return {"status": 0, "msg": "登录成功", "data": {"token": token}} + + @app.options("/learning_chat/api/login") + async def options_login(): + return JSONResponse(content={}, status_code=200) + + @app.get("/learning_chat/api/get_group_list", response_class=JSONResponse, dependencies=[authentication()]) + async def get_group_list_api(): + try: + bots = get_adapter(Adapter).bots + if len(bots) == 0: + return {"status": -100, "msg": "获取群和好友列表失败,请确认已连接GOCQ"} + bot = list(bots.values())[0] + group_list = await bot.get_group_list() + group_list = [ + {"label": f'{group["group_name"]}({group["group_id"]})', "value": group["group_id"]} + for group in group_list + ] + return {"status": 0, "msg": "ok", "data": {"group_list": group_list}} + except ValueError: + return {"status": -100, "msg": "获取群和好友列表失败,请确认已连接GOCQ"} + + @app.options("/learning_chat/api/get_group_list") + async def options_get_group_list(): + return JSONResponse(content={}, status_code=200) + + @app.get("/learning_chat/api/chat_global_config", response_class=JSONResponse, dependencies=[authentication()]) + async def get_chat_global_config(): + # 注意: 不再注入 member_list —— 前端全局配置页不使用(仅分群配置需要, + # 由 chat_group_config 单独拉取单个群成员), 避免串行拉取全部群成员导致接口卡顿 + return config_manager.config.dict(exclude={"group_config"}) + + @app.post("/learning_chat/api/chat_global_config", response_class=JSONResponse, dependencies=[authentication()]) + async def post_chat_global_config(data: dict): + config_manager.config.update(**data) + config_manager.save() + async with get_session() as session: + await session.execute( + update(ChatContext) + .where(ChatContext.count > config_manager.config.learn_max_count) + .values(count=config_manager.config.learn_max_count) + ) + await session.execute( + update(ChatAnswer) + .where(ChatAnswer.count > config_manager.config.learn_max_count) + .values(count=config_manager.config.learn_max_count) + ) + await session.commit() + jieba.load_userdict(config_manager.config.dictionary) + return {"status": 0, "msg": "保存成功"} + + @app.options("/learning_chat/api/chat_global_config") + async def options_chat_global_config(): + return JSONResponse(content={}, status_code=200) + + @app.get("/learning_chat/api/chat_group_config", response_class=JSONResponse, dependencies=[authentication()]) + async def get_chat_group_config(group_id: int): + try: + bots = get_adapter(Adapter).bots + if len(bots) == 0: + return {"status": -100, "msg": "获取群和好友列表失败,请确认已连接GOCQ"} + bot = list(bots.values())[0] + members = await bot.get_group_member_list(group_id=group_id) + member_list = [ + {"label": f'{member["nickname"] or member["card"]}({member["user_id"]})', "value": member["user_id"]} + for member in members + ] + config = config_manager.get_group_config(group_id).dict() + config["break_probability"] = config["break_probability"] * 100 + config["speak_continuously_probability"] = config["speak_continuously_probability"] * 100 + config["speak_poke_probability"] = config["speak_poke_probability"] * 100 + config["member_list"] = member_list + return config + except ValueError: + return {"status": -100, "msg": "获取群和好友列表失败,请确认已连接GOCQ"} + + @app.post("/learning_chat/api/chat_group_config", response_class=JSONResponse, dependencies=[authentication()]) + async def post_chat_group_config(group_id: Union[int, str], data: dict): + if not data.get("answer_threshold_weights"): + return {"status": 400, "msg": "回复阈值权重不能为空,必须至少有一个数值"} + data["break_probability"] = data["break_probability"] / 100 + data["speak_continuously_probability"] = data["speak_continuously_probability"] / 100 + data["speak_poke_probability"] = data["speak_poke_probability"] / 100 + bots = get_adapter(Adapter).bots + if len(bots) == 0: + return {"status": -100, "msg": "获取群和好友列表失败,请确认已连接GOCQ"} + bot = list(bots.values())[0] + groups = ( + [{"group_id": group_id}] if group_id != "all" else await bot.get_group_list() + ) + for group in groups: + config = config_manager.get_group_config(int(group["group_id"])) + config.update(**data) + config_manager.config.group_config[int(group["group_id"])] = config + config_manager.save() + return {"status": 0, "msg": "保存成功"} + + @app.options("/learning_chat/api/chat_group_config") + async def options_chat_group_config(): + return JSONResponse(content={}, status_code=200) + + @app.get("/learning_chat/api/get_chat_messages", response_class=JSONResponse, dependencies=[authentication()]) + async def get_chat_messages( + page: int = 1, + perPage: int = 10, + orderBy: str = "time", + orderDir: str = "desc", + group_id: Optional[str] = None, + user_id: Optional[str] = None, + message: Optional[str] = None, + ): + async with get_session() as session: + stmt = select(ChatMessage) + if group_id: + stmt = stmt.where(ChatMessage.group_id == int(group_id)) + if user_id: + stmt = stmt.where(ChatMessage.user_id == int(user_id)) + if message: + stmt = stmt.where(ChatMessage.raw_message.contains(message)) + + order_col = getattr(ChatMessage, orderBy or "time", ChatMessage.time) + stmt = stmt.order_by(order_col.asc() if (orderDir or "desc") == "asc" else order_col.desc()) + + count_result = await session.execute(select(func.count()).select_from(stmt.subquery())) + total = count_result.scalar() + + items_result = await session.execute(stmt.offset((page - 1) * perPage).limit(perPage)) + items = [ + {c.name: getattr(row, c.name) for c in ChatMessage.__table__.columns} + for row in items_result.scalars().all() + ] + return {"status": 0, "msg": "ok", "data": {"items": items, "total": total}} + + @app.options("/learning_chat/api/get_chat_messages") + async def options_get_chat_messages(): + return JSONResponse(content={}, status_code=200) + + @app.get("/learning_chat/api/get_chat_contexts", response_class=JSONResponse, dependencies=[authentication()]) + async def get_chat_context( + page: int = 1, + perPage: int = 10, + orderBy: str = "time", + orderDir: str = "desc", + keywords: Optional[str] = None, + ): + async with get_session() as session: + stmt = select(ChatContext) + if keywords: + stmt = stmt.where(ChatContext.keywords.contains(keywords)) + order_col = getattr(ChatContext, orderBy or "time", ChatContext.time) + stmt = stmt.order_by(order_col.asc() if (orderDir or "desc") == "asc" else order_col.desc()) + + count_result = await session.execute(select(func.count()).select_from(stmt.subquery())) + total = count_result.scalar() + + items_result = await session.execute(stmt.offset((page - 1) * perPage).limit(perPage)) + items = [ + {c.name: getattr(row, c.name) for c in ChatContext.__table__.columns} + for row in items_result.scalars().all() + ] + return {"status": 0, "msg": "ok", "data": {"items": items, "total": total}} + + @app.options("/learning_chat/api/get_chat_contexts") + async def options_get_chat_contexts(): + return JSONResponse(content={}, status_code=200) + + @app.get("/learning_chat/api/get_chat_answers", response_class=JSONResponse, dependencies=[authentication()]) + async def get_chat_answers( + context_id: Optional[int] = None, + page: int = 1, + perPage: int = 10, + orderBy: str = "count", + orderDir: str = "desc", + keywords: Optional[str] = None, + ): + async with get_session() as session: + stmt = select(ChatAnswer) + if context_id: + stmt = stmt.where(ChatAnswer.context_id == context_id) + if keywords: + stmt = stmt.where(ChatAnswer.keywords.contains(keywords)) + order_col = getattr(ChatAnswer, orderBy or "count", ChatAnswer.count) + stmt = stmt.order_by(order_col.asc() if (orderDir or "desc") == "asc" else order_col.desc()) + + count_result = await session.execute(select(func.count()).select_from(stmt.subquery())) + total = count_result.scalar() + + items_result = await session.execute(stmt.offset((page - 1) * perPage).limit(perPage)) + items = [] + for row in items_result.scalars().all(): + item = {c.name: getattr(row, c.name) for c in ChatAnswer.__table__.columns} + item["messages"] = [{"msg": m} for m in item["messages"]] + items.append(item) + return {"status": 0, "msg": "ok", "data": {"items": items, "total": total}} + + @app.options("/learning_chat/api/get_chat_answers") + async def options_get_chat_answers(): + return JSONResponse(content={}, status_code=200) + + @app.get("/learning_chat/api/get_chat_blacklist", response_class=JSONResponse, dependencies=[authentication()]) + async def get_chat_blacklist( + page: int = 1, + perPage: int = 10, + keywords: Optional[str] = None, + bans: Optional[str] = None, + ): + async with get_session() as session: + stmt = select(ChatBlackList).order_by(ChatBlackList.id.desc()) + if keywords: + stmt = stmt.where(ChatBlackList.keywords.contains(keywords)) + + count_result = await session.execute(select(func.count()).select_from(stmt.subquery())) + total = count_result.scalar() + + # bans 过滤需要基于全部数据(而非当前页), 故先全量取回再过滤、再分页 + items_result = await session.execute(stmt) + items = [] + for row in items_result.scalars().all(): + item = {c.name: getattr(row, c.name) for c in ChatBlackList.__table__.columns} + ban_ids = item["ban_group_id"] or [] + item["bans"] = "全局禁用" if item["global_ban"] else (str(ban_ids[0]) if ban_ids else "") + items.append(item) + if bans: + items = [x for x in items if bans in x["bans"]] + total = len(items) + items = items[(page - 1) * perPage : page * perPage] + return {"status": 0, "msg": "ok", "data": {"items": items, "total": total}} + + @app.options("/learning_chat/api/get_chat_blacklist") + async def options_get_chat_blacklist(): + return JSONResponse(content={}, status_code=200) + + @app.delete("/learning_chat/api/delete_chat", response_class=JSONResponse, dependencies=[authentication()]) + async def delete_chat(id: int, type: str): + try: + async with get_session() as session: + if type == "message": + await session.execute(delete(ChatMessage).where(ChatMessage.id == id)) + elif type == "context": + await session.execute(delete(ChatAnswer).where(ChatAnswer.context_id == id)) + await session.execute(delete(ChatContext).where(ChatContext.id == id)) + elif type == "answer": + await session.execute(delete(ChatAnswer).where(ChatAnswer.id == id)) + elif type == "blacklist": + await session.execute(delete(ChatBlackList).where(ChatBlackList.id == id)) + await session.commit() + return {"status": 0, "msg": "删除成功"} + except Exception as e: + return {"status": 500, "msg": f"删除失败,{e}"} + + @app.options("/learning_chat/api/delete_chat") + async def options_delete_chat(): + return JSONResponse(content={}, status_code=200) + + @app.put("/learning_chat/api/ban_chat", response_class=JSONResponse, dependencies=[authentication()]) + async def ban_chat(id: int, type: str): + try: + async with get_session() as session: + if type == "message": + result = await session.execute(select(ChatMessage).where(ChatMessage.id == id)) + data = result.scalar_one() + elif type == "context": + result = await session.execute(select(ChatContext).where(ChatContext.id == id)) + data = result.scalar_one() + else: + result = await session.execute(select(ChatAnswer).where(ChatAnswer.id == id)) + data = result.scalar_one() + await LearningChat.add_ban(data) + return {"status": 0, "msg": "禁用成功"} + except Exception as e: + return {"status": 500, "msg": f"禁用失败: {e}"} + + @app.options("/learning_chat/api/ban_chat") + async def options_ban_chat(): + return JSONResponse(content={}, status_code=200) + + @app.put("/learning_chat/api/delete_all", response_class=JSONResponse, dependencies=[authentication()]) + async def delete_all(type: str, id: Optional[int] = None): + try: + async with get_session() as session: + if type == "answer": + if id: + await session.execute(delete(ChatAnswer).where(ChatAnswer.context_id == id)) + else: + await session.execute(delete(ChatAnswer)) + elif type == "blacklist": + await session.execute(delete(ChatBlackList)) + elif type == "context": + await session.execute(delete(ChatContext)) + elif type == "message": + await session.execute(delete(ChatMessage)) + await session.commit() + return {"status": 0, "msg": "操作成功"} + except Exception as e: + return {"status": 500, "msg": f"操作失败,{e}"} + + @app.options("/learning_chat/api/delete_all") + async def options_delete_all(): + return JSONResponse(content={}, status_code=200) + + # 静态资源挂载放在所有 API 路由之后, 保证 /learning_chat/api/* 优先匹配 + mount_frontend(app) \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web_frontend.py b/hexi/plugins/nonebot_plugin_learning_chat/web_frontend.py new file mode 100644 index 0000000..a999ff6 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web_frontend.py @@ -0,0 +1,99 @@ +"""前端管理页面的构建与静态挂载。 + +方案: 不再由 bot 拉起 vite dev server, 而是把构建产物用 FastAPI StaticFiles +挂载到 bot 端口 /learning_chat 路径, 与 API 同源, 无孤儿进程、无 CORS 问题。 +前端开发时手动 `npm run dev` 即可(API 已配置 dev proxy)。 +""" + +import asyncio +from pathlib import Path + +from fastapi.responses import FileResponse +from fastapi.staticfiles import StaticFiles +from nonebot import logger + +BASE_DIR = Path(__file__).resolve().parent +ADMIN_DIR = BASE_DIR / "web" / "learning-chat-admin" +DIST_DIR = ADMIN_DIR / "dist" + +# 参与构建新鲜度检查的源文件(不在 src/ 下的) +SRC_FILES = ("vite.config.ts", "index.html", "package.json") + + +def _dist_is_stale() -> bool: + """dist/index.html 不存在, 或比任何源码旧时视为需要重建""" + dist_index = DIST_DIR / "index.html" + if not dist_index.exists(): + return True + dist_mtime = dist_index.stat().st_mtime + for src_file in (ADMIN_DIR / "src").rglob("*"): + if src_file.is_file() and src_file.stat().st_mtime > dist_mtime: + return True + return any( + (ADMIN_DIR / name).stat().st_mtime > dist_mtime + for name in SRC_FILES + if (ADMIN_DIR / name).exists() + ) + + +async def build_frontend() -> bool: + """执行 vite 构建, 返回是否成功""" + logger.info("群聊学习 | 前端源码已更新, 开始重新构建(约10-40秒)...") + proc = await asyncio.create_subprocess_exec( + "npx.cmd", + "vite", + "build", + cwd=str(ADMIN_DIR), + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.STDOUT, + ) + output, _ = await proc.communicate() + if proc.returncode != 0: + logger.error( + "群聊学习 | 前端构建失败(%s):\n%s", + proc.returncode, + output.decode(errors="ignore")[-3000:], + ) + return False + logger.info("群聊学习 | 前端构建完成") + return True + + +async def ensure_frontend_ready() -> bool: + """确保构建产物是最新的, 返回是否可用(最新或已成功重建)""" + if not _dist_is_stale(): + return True + return await build_frontend() + + +def mount_frontend(app) -> None: + """将构建产物挂载到 bot 端口的 /learning_chat 路径(需在 API 路由注册后调用)。 + + history 模式 SPA 需要回退: assets/ 静态挂载 + 真实文件直接返回, + 其余路径(如 /login /config 等前端路由)一律回退到 index.html。 + """ + if not DIST_DIR.exists(): + logger.error("群聊学习 | 前端构建产物不存在, 管理页面不可用") + return + assets_dir = DIST_DIR / "assets" + if assets_dir.exists(): + app.mount( + "/learning_chat/assets", + StaticFiles(directory=str(assets_dir)), + name="learning_chat_assets", + ) + dist_resolved = DIST_DIR.resolve() + + @app.get("/learning_chat/{full_path:path}") + async def learning_chat_spa(full_path: str): + target = (DIST_DIR / full_path).resolve() + if full_path and target.is_file() and target.is_relative_to(dist_resolved): + return FileResponse(target) + # SPA 回退: 前端路由(如 /login /config)全部交给 index.html + return FileResponse(DIST_DIR / "index.html") + + @app.get("/learning_chat") + async def learning_chat_root(): + return FileResponse(DIST_DIR / "index.html") + + logger.info("群聊学习 | 管理页面已挂载: http://:/learning_chat/") diff --git a/hexi/plugins/nonebot_plugin_learning_chat/web_hub.py b/hexi/plugins/nonebot_plugin_learning_chat/web_hub.py new file mode 100644 index 0000000..9d14348 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_learning_chat/web_hub.py @@ -0,0 +1,296 @@ +# -*- coding: utf-8 -*- +"""群聊学习 Web API 子应用(挂载到 /api/learning_chat)。 + +统一鉴权走 hexi.web_auth(OAuth2 + SQLite),与统一管理台 /hub 共用登录态。 +旧版独立后台 /learning_chat(JWT 自鉴权)保留可用,前端由 hub 渲染。 +""" + +from __future__ import annotations + +from typing import Optional, Union + +from fastapi import FastAPI +from fastapi.responses import JSONResponse +from sqlalchemy import delete, select, update, func + +try: + import jieba_fast as jieba +except ImportError: + import jieba + +from nonebot import get_adapter +from nonebot.adapters.onebot.v11 import Adapter +from nonebot_plugin_orm import get_session + +from hexi.web_auth import require_admin + +from .handler import LearningChat +from .models import ChatMessage, ChatContext, ChatAnswer, ChatBlackList +from .config import config_manager + +API = require_admin + + +def _ok(data=None, msg: str = "ok") -> JSONResponse: + return JSONResponse({"status": 0, "msg": msg, "data": data}) + + +async def _first_bot(): + try: + bots = get_adapter(Adapter).bots + return next(iter(bots.values()), None) + except (ValueError, AttributeError): + return None + + +def build_admin_app() -> FastAPI | None: + """构建群聊学习管理 API 子应用(挂载到 /api/learning_chat)。""" + if not config_manager.config.enable_web: + return None + + app = FastAPI(title="Learning Chat API") + auth = API + + @app.get("/get_group_list", response_class=JSONResponse, dependencies=[auth]) + async def get_group_list_api(): + bot = await _first_bot() + if bot is None: + return JSONResponse({"status": -100, "msg": "获取群和好友列表失败,请确认已连接GOCQ"}) + group_list = await bot.get_group_list() + group_list = [ + {"label": f'{group["group_name"]}({group["group_id"]})', "value": group["group_id"]} + for group in group_list + ] + return _ok({"group_list": group_list}) + + @app.get("/chat_global_config", response_class=JSONResponse, dependencies=[auth]) + async def get_chat_global_config(): + return config_manager.config.dict(exclude={"group_config"}) + + @app.post("/chat_global_config", response_class=JSONResponse, dependencies=[auth]) + async def post_chat_global_config(data: dict): + config_manager.config.update(**data) + config_manager.save() + async with get_session() as session: + await session.execute( + update(ChatContext) + .where(ChatContext.count > config_manager.config.learn_max_count) + .values(count=config_manager.config.learn_max_count) + ) + await session.execute( + update(ChatAnswer) + .where(ChatAnswer.count > config_manager.config.learn_max_count) + .values(count=config_manager.config.learn_max_count) + ) + await session.commit() + jieba.load_userdict(config_manager.config.dictionary) + return {"status": 0, "msg": "保存成功"} + + @app.get("/chat_group_config", response_class=JSONResponse, dependencies=[auth]) + async def get_chat_group_config(group_id: int): + bot = await _first_bot() + if bot is None: + return JSONResponse({"status": -100, "msg": "获取群和好友列表失败,请确认已连接GOCQ"}) + members = await bot.get_group_member_list(group_id=group_id) + member_list = [ + {"label": f'{member["nickname"] or member["card"]}({member["user_id"]})', "value": member["user_id"]} + for member in members + ] + config = config_manager.get_group_config(group_id).dict() + config["break_probability"] = config["break_probability"] * 100 + config["speak_continuously_probability"] = config["speak_continuously_probability"] * 100 + config["speak_poke_probability"] = config["speak_poke_probability"] * 100 + config["member_list"] = member_list + return config + + @app.post("/chat_group_config", response_class=JSONResponse, dependencies=[auth]) + async def post_chat_group_config(group_id: Union[int, str], data: dict): + if not data.get("answer_threshold_weights"): + return JSONResponse({"status": 400, "msg": "回复阈值权重不能为空,必须至少有一个数值"}) + data["break_probability"] = data["break_probability"] / 100 + data["speak_continuously_probability"] = data["speak_continuously_probability"] / 100 + data["speak_poke_probability"] = data["speak_poke_probability"] / 100 + bot = await _first_bot() + if bot is None: + return JSONResponse({"status": -100, "msg": "获取群和好友列表失败,请确认已连接GOCQ"}) + groups = ( + [{"group_id": group_id}] if group_id != "all" else await bot.get_group_list() + ) + for group in groups: + config = config_manager.get_group_config(int(group["group_id"])) + config.update(**data) + config_manager.config.group_config[int(group["group_id"])] = config + config_manager.save() + return {"status": 0, "msg": "保存成功"} + + @app.get("/get_chat_messages", response_class=JSONResponse, dependencies=[auth]) + async def get_chat_messages( + page: int = 1, + perPage: int = 10, + orderBy: str = "time", + orderDir: str = "desc", + group_id: Optional[str] = None, + user_id: Optional[str] = None, + message: Optional[str] = None, + ): + async with get_session() as session: + stmt = select(ChatMessage) + if group_id: + stmt = stmt.where(ChatMessage.group_id == int(group_id)) + if user_id: + stmt = stmt.where(ChatMessage.user_id == int(user_id)) + if message: + stmt = stmt.where(ChatMessage.raw_message.contains(message)) + + order_col = getattr(ChatMessage, orderBy or "time", ChatMessage.time) + stmt = stmt.order_by(order_col.asc() if (orderDir or "desc") == "asc" else order_col.desc()) + + count_result = await session.execute(select(func.count()).select_from(stmt.subquery())) + total = count_result.scalar() + + items_result = await session.execute(stmt.offset((page - 1) * perPage).limit(perPage)) + items = [ + {c.name: getattr(row, c.name) for c in ChatMessage.__table__.columns} + for row in items_result.scalars().all() + ] + return _ok({"items": items, "total": total}) + + @app.get("/get_chat_contexts", response_class=JSONResponse, dependencies=[auth]) + async def get_chat_context( + page: int = 1, + perPage: int = 10, + orderBy: str = "time", + orderDir: str = "desc", + keywords: Optional[str] = None, + ): + async with get_session() as session: + stmt = select(ChatContext) + if keywords: + stmt = stmt.where(ChatContext.keywords.contains(keywords)) + order_col = getattr(ChatContext, orderBy or "time", ChatContext.time) + stmt = stmt.order_by(order_col.asc() if (orderDir or "desc") == "asc" else order_col.desc()) + + count_result = await session.execute(select(func.count()).select_from(stmt.subquery())) + total = count_result.scalar() + + items_result = await session.execute(stmt.offset((page - 1) * perPage).limit(perPage)) + items = [ + {c.name: getattr(row, c.name) for c in ChatContext.__table__.columns} + for row in items_result.scalars().all() + ] + return _ok({"items": items, "total": total}) + + @app.get("/get_chat_answers", response_class=JSONResponse, dependencies=[auth]) + async def get_chat_answers( + context_id: Optional[int] = None, + page: int = 1, + perPage: int = 10, + orderBy: str = "count", + orderDir: str = "desc", + keywords: Optional[str] = None, + ): + async with get_session() as session: + stmt = select(ChatAnswer) + if context_id: + stmt = stmt.where(ChatAnswer.context_id == context_id) + if keywords: + stmt = stmt.where(ChatAnswer.keywords.contains(keywords)) + order_col = getattr(ChatAnswer, orderBy or "count", ChatAnswer.count) + stmt = stmt.order_by(order_col.asc() if (orderDir or "desc") == "asc" else order_col.desc()) + + count_result = await session.execute(select(func.count()).select_from(stmt.subquery())) + total = count_result.scalar() + + items_result = await session.execute(stmt.offset((page - 1) * perPage).limit(perPage)) + items = [] + for row in items_result.scalars().all(): + item = {c.name: getattr(row, c.name) for c in ChatAnswer.__table__.columns} + item["messages"] = [{"msg": m} for m in item["messages"]] if item["messages"] else None + items.append(item) + return _ok({"items": items, "total": total}) + + @app.get("/get_chat_blacklist", response_class=JSONResponse, dependencies=[auth]) + async def get_chat_blacklist( + page: int = 1, + perPage: int = 10, + keywords: Optional[str] = None, + bans: Optional[str] = None, + ): + async with get_session() as session: + stmt = select(ChatBlackList).order_by(ChatBlackList.id.desc()) + if keywords: + stmt = stmt.where(ChatBlackList.keywords.contains(keywords)) + + count_result = await session.execute(select(func.count()).select_from(stmt.subquery())) + total = count_result.scalar() + + items_result = await session.execute(stmt) + items = [] + for row in items_result.scalars().all(): + item = {c.name: getattr(row, c.name) for c in ChatBlackList.__table__.columns} + ban_ids = item["ban_group_id"] or [] + item["bans"] = "全局禁用" if item["global_ban"] else (str(ban_ids[0]) if ban_ids else "") + items.append(item) + if bans: + items = [x for x in items if bans in x["bans"]] + total = len(items) + items = items[(page - 1) * perPage : page * perPage] + return _ok({"items": items, "total": total}) + + @app.delete("/delete_chat", response_class=JSONResponse, dependencies=[auth]) + async def delete_chat(id: int, type: str): + try: + async with get_session() as session: + if type == "message": + await session.execute(delete(ChatMessage).where(ChatMessage.id == id)) + elif type == "context": + await session.execute(delete(ChatAnswer).where(ChatAnswer.context_id == id)) + await session.execute(delete(ChatContext).where(ChatContext.id == id)) + elif type == "answer": + await session.execute(delete(ChatAnswer).where(ChatAnswer.id == id)) + elif type == "blacklist": + await session.execute(delete(ChatBlackList).where(ChatBlackList.id == id)) + await session.commit() + return {"status": 0, "msg": "删除成功"} + except Exception as e: + return JSONResponse({"status": 500, "msg": f"删除失败,{e}"}) + + @app.put("/ban_chat", response_class=JSONResponse, dependencies=[auth]) + async def ban_chat(id: int, type: str): + try: + async with get_session() as session: + if type == "message": + result = await session.execute(select(ChatMessage).where(ChatMessage.id == id)) + data = result.scalar_one() + elif type == "context": + result = await session.execute(select(ChatContext).where(ChatContext.id == id)) + data = result.scalar_one() + else: + result = await session.execute(select(ChatAnswer).where(ChatAnswer.id == id)) + data = result.scalar_one() + await LearningChat.add_ban(data) + return {"status": 0, "msg": "禁用成功"} + except Exception as e: + return JSONResponse({"status": 500, "msg": f"禁用失败: {e}"}) + + @app.put("/delete_all", response_class=JSONResponse, dependencies=[auth]) + async def delete_all(type: str, id: Optional[int] = None): + try: + async with get_session() as session: + if type == "answer": + if id: + await session.execute(delete(ChatAnswer).where(ChatAnswer.context_id == id)) + else: + await session.execute(delete(ChatAnswer)) + elif type == "blacklist": + await session.execute(delete(ChatBlackList)) + elif type == "context": + await session.execute(delete(ChatContext)) + elif type == "message": + await session.execute(delete(ChatMessage)) + await session.commit() + return {"status": 0, "msg": "操作成功"} + except Exception as e: + return JSONResponse({"status": 500, "msg": f"操作失败,{e}"}) + + return app diff --git a/hexi/plugins/nonebot_plugin_makeaquote/Reply.py b/hexi/plugins/nonebot_plugin_makeaquote/Reply.py new file mode 100644 index 0000000..03f4230 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_makeaquote/Reply.py @@ -0,0 +1,50 @@ +from nonebot.adapters.onebot.v11 import Bot, Message +from nonebot import logger + + +class Reply: + def __init__(self): + self.message: str = '' + self.user_id: int = -1 + self.user_card: str = '' + self.time: int = -1 + + +async def extract_reply(event, bot: Bot) -> Reply: + """ + 提取回复内容 + """ + logger.info(event['group_id']) + reply_data = Reply() + if event['reply'] and event['reply']['message_id']: # 待优化 + reply = event['reply'] + sender = reply['sender'] + mes: Message = reply['message'] + print(mes) + msg = mes[0]['data']['text'] + if msg: + reply_data.message = msg + meminfo = await get_member_info(bot=bot, user_id=sender['user_id'], group_id=event['group_id']) + reply_data.user_card = (meminfo["card"] or meminfo["nickname"]) + reply_data.time = reply['time'] + reply_data.user_id = reply['sender']['user_id'] + else: + reply_data.message = -1 + else: + mes: Message = event["message"] + print(mes) + msg = mes[0]['data']['text'].replace("maq","") + if msg: + reply_data.message = msg + meminfo = await get_member_info(bot=bot, user_id=event['user_id'], group_id=event['group_id']) + reply_data.user_card = (meminfo["card"] or meminfo["nickname"]) + reply_data.time = event['time'] + reply_data.user_id = event['user_id'] + else: + reply_data.message = -1 + return reply_data + + +async def get_member_info(bot: Bot, group_id: int, user_id: int): + member_info = await bot.get_group_member_info(group_id=group_id, user_id=user_id) + return member_info diff --git a/hexi/plugins/nonebot_plugin_makeaquote/__init__.py b/hexi/plugins/nonebot_plugin_makeaquote/__init__.py new file mode 100644 index 0000000..2b111cb --- /dev/null +++ b/hexi/plugins/nonebot_plugin_makeaquote/__init__.py @@ -0,0 +1,36 @@ +from nonebot import logger, on_message, require + +require("nonebot_plugin_alconna") +from nonebot_plugin_alconna import UniMessage +from nonebot.adapters.onebot.v11 import Bot, Event +from nonebot.plugin import PluginMetadata +from nonebot.rule import keyword + +from .Reply import extract_reply +from .make_a_qoute import generate + +__plugin_meta__ = PluginMetadata( + name="语录", + description="生成一条语录", + usage="发送【maq】", + type="application", +) + +maq = on_message(keyword("maq")) + + +@maq.handle() +async def maq_handle(bot: Bot, ev: Event): + event = ev.dict() + try: + if event.get("message_type") != "group": + return + reply = await extract_reply(event, bot) + if reply.message == -1: + await maq.finish("请引用文字消息") + logger.info(f"{reply.user_id}, {reply.user_card}, {reply.message}") + image = await generate(reply) + await UniMessage.image(raw=image.getvalue()).send() + except (KeyError, TypeError) as e: + logger.error(e) + await maq.finish(str(e)) diff --git a/hexi/plugins/nonebot_plugin_makeaquote/data/font/SourceHanSansCN-Bold.otf b/hexi/plugins/nonebot_plugin_makeaquote/data/font/SourceHanSansCN-Bold.otf new file mode 100644 index 0000000..8e1e869 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_makeaquote/data/font/SourceHanSansCN-Bold.otf differ diff --git a/hexi/plugins/nonebot_plugin_makeaquote/data/font/SourceHanSansCN-Medium.otf b/hexi/plugins/nonebot_plugin_makeaquote/data/font/SourceHanSansCN-Medium.otf new file mode 100644 index 0000000..630d546 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_makeaquote/data/font/SourceHanSansCN-Medium.otf differ diff --git a/hexi/plugins/nonebot_plugin_makeaquote/make_a_qoute.py b/hexi/plugins/nonebot_plugin_makeaquote/make_a_qoute.py new file mode 100644 index 0000000..7857087 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_makeaquote/make_a_qoute.py @@ -0,0 +1,181 @@ +import hashlib +from io import BytesIO +from pathlib import Path +from time import localtime, strftime + +import cjk_textwrap +import httpx +import numpy as np +from nonebot.log import logger +from PIL import Image, ImageDraw, ImageFont +from pilmoji import Pilmoji +from pilmoji.source import TwemojiEmojiSource + +from .Reply import Reply + +# --- 常量 --- +_FONT_DIR = Path(__file__).resolve().parent / "data" / "font" +FONT_SMALL = 24 # 用户卡片 / 时间 +FONT_TIME = 18 # 时间 +FONT_TEXT_MAX = 32 # 正文最大字号 +FONT_TEXT_MIN = 12 # 正文最小字号(低于此则截断) + +# --- 字体懒加载 --- +_font_cache: dict = {} + + +def _get_font(name: str, size: int) -> ImageFont.FreeTypeFont: + key = (name, size) + if key not in _font_cache: + path = _FONT_DIR / name + _font_cache[key] = ImageFont.truetype(str(path), size, encoding="unic") + return _font_cache[key] + + +def _font_small() -> ImageFont.FreeTypeFont: + return _get_font("SourceHanSansCN-Bold.otf", FONT_SMALL) + + +def _font_time() -> ImageFont.FreeTypeFont: + return _get_font("SourceHanSansCN-Bold.otf", FONT_TIME) + + +def _auto_fit( + text: str, + draw: ImageDraw.ImageDraw, + max_width: float, + max_height: float, +) -> tuple[list[str], ImageFont.FreeTypeFont, int, int]: + """ + 自动缩放字号使文本适合 max_width × max_height 区域。 + 返回 (行列表, 字体, 字号, 行间距)。 + """ + for size in range(FONT_TEXT_MAX, FONT_TEXT_MIN - 1, -2): + font = _get_font("SourceHanSansCN-Medium.otf", size) + chars_per_line = max(1, int(max_width / (size * 0.92))) + lines = wrap_text(text, chars_per_line) + spacing = int(size * 0.75) + total_h = len(lines) * (size + spacing) - spacing + if total_h <= max_height and all( + draw.textlength(line, font) <= max_width for line in lines + ): + return lines, font, size, spacing + + # 最小字号兜底:允许截断 + font = _get_font("SourceHanSansCN-Medium.otf", FONT_TEXT_MIN) + chars_per_line = max(1, int(max_width / (FONT_TEXT_MIN * 0.92))) + lines = wrap_text(text, chars_per_line) + spacing = int(FONT_TEXT_MIN * 0.75) + return lines, font, FONT_TEXT_MIN, spacing + + +async def generate(reply: Reply) -> BytesIO: + """ + 生成图片 — 正文根据长度自动缩放字号,无需截断 + """ + image = Image.new('RGBA', (1280, 640), (0, 0, 0, 255)) + draw = ImageDraw.Draw(image) + + x_start = 601.1 + x_end = 1241.1 + max_width = x_end - x_start # ≈ 640px + max_height = 400 # 为用户卡片留出空间 + + # 自动缩放 + text_wrapped, text_font, font_size, line_spacing = _auto_fit( + reply.message, draw, max_width, max_height, + ) + + # 垂直居中 + total_h = len(text_wrapped) * (font_size + line_spacing) - line_spacing + y_min = 100 - font_size + y_max = 512 + y = int((y_max - y_min) / 2 - total_h / 2) + + # --- Pilmoji --- + with Pilmoji(image, source=TwemojiEmojiSource, emoji_position_offset=(0, 10)) as emoji: + for line in text_wrapped: + text_size = draw.textlength(line, text_font) + x = int(x_start + (max_width - text_size) / 2) + emoji.text((x, y), line, font=text_font, fill=(255, 255, 255, 255), embedded_color=True) + y += font_size + line_spacing + + # --- 头像 --- + img_content = await download_avatar(str(reply.user_id)) + avatar = Image.open(img_content).resize((640, 640)) + avatar = alpha_gradient(avatar, 320, 640) + image.paste(avatar, (0, 0), avatar) + + # --- 用户卡片 --- + x_center = 921.1 + card_size = draw.textlength("- " + reply.user_card, _font_small()) + x_card_start = x_center - card_size / 2 + draw.text((x_card_start, y), "- " + reply.user_card, font=_font_small(), fill=(169, 172, 184, 255)) + + # --- 时间 --- + fmt_time = strftime("%Y.%m.%d %H:%M", localtime(reply.time)) + time_size = draw.textlength(fmt_time, _font_small()) + x_time_start = x_end - time_size + draw.text((x_time_start, 640 - FONT_SMALL - 20), fmt_time, font=_font_time(), fill=(169, 172, 184, 255)) + + # --- 输出 --- + bytes_io = BytesIO() + image.convert('RGB').save(bytes_io, format="JPEG") + return bytes_io + + +def wrap_text(text: str, width: int) -> list[str]: + """ + 按宽度自动换行,支持中日韩文本。 + 先按换行符分行,再用 cjk_textwrap.wrap 按宽度折行。 + """ + return [wrapped for line in text.splitlines() for wrapped in cjk_textwrap.wrap(line, width)] + + +def alpha_gradient(image, x_s: int, x_e: int): + """ + 为图像添加从 x_s 到 x_e 的左右渐变透明度遮罩。 + 使用 numpy 加速,避免逐像素 putpixel 的低效操作。 + """ + image = image.convert("RGBA") + w, h = image.size + + # 默认全不透明 + gradient = np.full((h, w), 255, dtype=np.uint8) + + # 生成渐变列 + xs = np.linspace(0, 1, x_e - x_s, endpoint=False) + alphas = 255 - (np.sin(xs * np.pi - np.pi / 2) / 2 + 0.5) * 255 + alphas = alphas.astype(np.uint8) + + # 应用到对应范围 + gradient[:, x_s:x_e] = alphas[np.newaxis, :] + + mask = Image.fromarray(gradient, mode="L") + image.putalpha(mask) + return image + + +async def download_avatar(user_id: str) -> BytesIO: + url = f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=640" + data = await download_url(url) + if not data or hashlib.md5(data).hexdigest() == "acef72340ac0e914090bd35799f5594e": + url = f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=100" + data = await download_url(url) + return BytesIO(data) + + +async def download_url(url: str) -> bytes: + """ + 下载指定 URL 内容,带 3 次重试和超时。 + 如果失败,返回空字节串 b""。 + """ + async with httpx.AsyncClient(timeout=5.0) as client: + for i in range(3): + try: + resp = await client.get(url) + if resp.status_code == 200: + return resp.content + except Exception as e: + logger.warning(f"下载失败 {url}, 重试 {i + 1}/3: {e}") + return b"" diff --git a/hexi/plugins/nonebot_plugin_mc_server_status/__init__.py b/hexi/plugins/nonebot_plugin_mc_server_status/__init__.py new file mode 100644 index 0000000..e101ed9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_mc_server_status/__init__.py @@ -0,0 +1,244 @@ +import ast +from asyncio import gather +from base64 import b64decode +from io import BytesIO +from re import findall +from typing import Union +import json +from mcstatus import BedrockServer, JavaServer +from nonebot import on_command, on_regex +from nonebot.adapters.onebot.v11 import ( + Bot, + GroupMessageEvent, + Message, + MessageEvent, +) +from nonebot.adapters.onebot.v11 import ( + MessageSegment as MS, +) +from nonebot.log import logger +from nonebot.params import RegexGroup +from nonebot.plugin import PluginMetadata + +from .config import Config, pc, save_file, var + +# 统一配置标准:把管理 QQ / 机器人 QQ / 数据文件名暴露给 Web 管理台 +from hexi.config_standard import register_model_config # noqa: E402 + +register_model_config( + __name__, + pc, + fields=["mc_status_admin_qqnum", "mc_status_bot_qqnum_list", "mc_status_data_filename"], + labels={ + "mc_status_admin_qqnum": "管理员 QQ 号", + "mc_status_bot_qqnum_list": "响应机器人 QQ 列表", + "mc_status_data_filename": "数据文件名", + }, + descriptions={ + "mc_status_admin_qqnum": "可执行添加/删除服务器等管理的 QQ 号(每行一个)", + "mc_status_bot_qqnum_list": "按优先级响应的机器人 QQ 号(每行一个,可空)", + "mc_status_data_filename": "群服务器数据文件名(hexi/data 下)", + }, +) + +__plugin_meta__ = PluginMetadata( + name="MC服务器信息查询插件", + description="如名", + type="application", + homepage="https://github.com/nikissXI/nonebot_plugins/tree/main/nonebot_plugin_setu_customization", + supported_adapters={"~onebot.v11"}, + config=Config, + usage=f"""插件命令如下: + 信息 # 字面意思,需要加命令前缀,默认/ + 信息数据 # 查看已启用群以及服务器信息,需要加命令前缀,默认/ + 添加服务器 # 字面意思 + 删除服务器 # 字面意思 + """, +) + + +async def group_check(event: GroupMessageEvent, bot: Bot) -> bool: + return event.group_id in var.group_list and bot == var.handle_bot + + +async def admin_check(event: MessageEvent, bot: Bot) -> bool: + return bot == var.handle_bot and event.user_id in pc.mc_status_admin_qqnum + + +xinxi = on_command("信息", rule=group_check) +list_all = on_command("信息数据", rule=admin_check) +add_server = on_regex( + r"^添加服务器\s*((\d+)\s+(\S+)\s+(\S+)\s+(\S+))?", rule=admin_check +) +del_server = on_regex(r"^删除服务器\s*((\d+)\s+(\S+))?", rule=admin_check) +test_server = on_regex(r"^测试服务器\s*((\S+)\s+(\S+))?", rule=admin_check) + + +@xinxi.handle() +async def _(event: GroupMessageEvent): + group = event.group_id + task_list = [] + for server_name in var.group_list[group]: + server_host = var.group_list[group][server_name][0] + server_type = var.group_list[group][server_name][1] + task_list.append( + check_mc_status( + server_name, + server_host, + server_type, + ) + ) + result = await gather(*task_list) + count = 0 + msg = "" + print(result) + for r in result: + count += 1 + if count > 1: + msg += "\n=== 分割线 ===\n" + msg += r + await xinxi.finish(msg) + + +@add_server.handle() +async def _(mp=RegexGroup()): + if not mp[0]: + await add_server.finish( + f"添加服务器 [群号] [名称] [服务器地址] [类型]\n类型写js或bds,js是Java服务器,bds是基岩服务器\n服务器地址如果知道端口号把端口加上,否则查询速度会慢一点\n添加例子:\nexp1: 添加服务器 114514 哈皮咳嗽 mc.hypixel.net js\nexp2: 添加服务器 114514 某基岩服 mc.bds.net bds\nexp3: 添加服务器 114514 某Java服 mc.java.net:25577 js" + ) + else: + group = int(mp[1]) + new_server_name = mp[2] + server_host = mp[3] + server_type = mp[4].lower() + + if server_type not in ["js", "bds"]: + await add_server.finish("类型请填js或bds") + + if group not in var.group_list: + var.group_list[group] = {new_server_name: [server_host, server_type]} + else: + for server_name in var.group_list[group]: + if new_server_name == server_name: + await add_server.finish("有同名服务器啦!") + var.group_list[group][new_server_name] = [server_host, server_type] + save_file() + await add_server.finish("添加成功") + + +@del_server.handle() +async def _(mp=RegexGroup()): + if not mp[0]: + await del_server.finish(f"删除服务器 [群号] [名称]") + else: + group = int(mp[1]) + name = mp[2] + + if group not in var.group_list: + await del_server.finish("这个群没有添加服务器") + else: + if name in var.group_list[group]: + var.group_list[group].pop(name) + if not var.group_list[group]: + var.group_list.pop(group) + save_file() + await del_server.finish("删除成功") + else: + await del_server.finish("没找到该名称的服务器") + + +@list_all.handle() +async def _(): + msg = "" + for group_id in var.group_list: + msg += f"群{group_id}服务器列表\n" + for server_name in var.group_list[group_id]: + server_host, server_type = var.group_list[group_id][server_name] + msg += f"{server_name} {server_host} {server_type}\n" + msg += "\n" + if not msg: + msg = "无数据" + await list_all.finish(f"mc_status数据\n{msg}") + + +@test_server.handle() +async def _(mp=RegexGroup()): + if not mp[0]: + await test_server.finish( + f"测试服务器 [服务器地址] [类型]\n类型写js或bds,js是Java服务器,bds是基岩服务器" + ) + else: + server_host = mp[1] + server_type = mp[2].lower() + + if server_type not in ["js", "bds"]: + await add_server.finish("类型请填js或bds") + + msg = await check_mc_status("测试", server_host, server_type) + await list_all.finish(msg) + + +async def check_mc_status( + name: str, host: str, server_type: str +) -> Union[str, Message]: + try: + if server_type == "js": + js = await JavaServer.async_lookup(host, timeout=2) + status = js.status() + # if status.description.strip(): + # print(f"des: {status.description}") + version_list = findall(r"\d+\.\d+(?:\.[\dxX]+)?", status.version.name) + if len(version_list) != 1: + version = f"{version_list[0]}-{version_list[-1]}" + else: + version = version_list[0] + + online = f"{status.players.online}/{status.players.max}" + if status.players.online and status.players.sample: + anonymous_player = 0 + _player_list = [] + for p in status.players.sample: + if p.id == "00000000-0000-0000-0000-000000000000": + anonymous_player += 1 + else: + _player_list.append(p.name) + + if anonymous_player: + _player_list.append(f"[{anonymous_player}个匿名玩家]") + + if _player_list: + player_list = "\n".join(_player_list) + + else: + player_list = "没返回玩家列表" + + else: + player_list = "没人在线" + + latency = round(status.latency) + # base64图标 + if status.favicon: + aa, bb = status.favicon.split("base64,") + icon = MS.image(BytesIO(b64decode(bb))) + "\n" + else: + icon = "" + msg = ( + icon + + f"名称:{name}\n版本:{version}\n在线:{online}\n延迟:{latency}ms\n在线列表:\n{player_list}" + ) + + else: + if host.find(":") != -1: + host, port = host.split(":") + else: + host, port = host, 19132 + bds = BedrockServer(host=host, port=int(port)) + status = await bds.async_status() + online = f"{status.players_online}/{status.players_max}" + latency = round(status.latency) + version = status.version.version + msg = f"名称:{name} 【{version}】\n在线:{online} 延迟:{latency}ms" + except Exception as e: + msg = f"名称:{name} 查询失败!\n错误:{repr(e)}" + + return msg diff --git a/hexi/plugins/nonebot_plugin_mc_server_status/config.py b/hexi/plugins/nonebot_plugin_mc_server_status/config.py new file mode 100644 index 0000000..364ce1b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_mc_server_status/config.py @@ -0,0 +1,115 @@ +from json import dump, load +from os import makedirs +from pathlib import Path +from typing import List, Optional + +from nonebot import get_bot, get_bots, get_driver, get_plugin_config +from nonebot.adapters import Bot +from pydantic import BaseModel + +# 数据目录:项目 hexi/data/ 下(与其它插件数据统一) +DATA_DIR = Path(__file__).resolve().parents[2] / "data" + + +class Config(BaseModel): + # 管理员的QQ号(别问我为什么) + mc_status_admin_qqnum: List[int] = [] # 必填 + # 机器人的QQ号(如果写了就按优先级响应,否则就第一个连上的响应) ['1234','5678','6666'] + mc_status_bot_qqnum_list: List[str] = [] # 可选 + # 数据文件名 + mc_status_data_filename: str = "mc_status_data.json" + + +class Var: + # 处理消息的bot + handle_bot: Optional[Bot] = None + # {"123456": {"提肛": ["mc.hypixel.net:25565","java"]}} + group_list = {} + + +driver = get_driver() +pc = get_plugin_config(Config) +var = Var() + + +@driver.on_startup +async def on_startup(): + makedirs(DATA_DIR, exist_ok=True) + + if not (DATA_DIR / pc.mc_status_data_filename).exists(): + save_file() + else: + load_file() + + +def load_file(): + with open(DATA_DIR / pc.mc_status_data_filename, "r", encoding="utf-8") as r: + tmp_data = load(r) + for i in tmp_data: + var.group_list[int(i)] = tmp_data[i] + + +def save_file(): + with open(DATA_DIR / pc.mc_status_data_filename, "w", encoding="utf-8") as w: + dump(var.group_list, w, indent=4, ensure_ascii=False) + + +# qq机器人连接时执行 +@driver.on_bot_connect +async def on_bot_connect(bot: Bot): + # 是否有写bot qq,如果写了只处理bot qq在列表里的 + if pc.mc_status_bot_qqnum_list and bot.self_id in pc.mc_status_bot_qqnum_list: + # 如果已经有bot连了 + if var.handle_bot: + # 当前bot qq 下标 + handle_bot_id_index = pc.mc_status_bot_qqnum_list.index( + var.handle_bot.self_id + ) + # 新连接的bot qq 下标 + new_bot_id_index = pc.mc_status_bot_qqnum_list.index(bot.self_id) + # 判断优先级,下标越低优先级越高 + if new_bot_id_index < handle_bot_id_index: + var.handle_bot = bot + + # 没bot连就直接给 + else: + var.handle_bot = bot + + # 不写就给第一个连的 + elif not pc.mc_status_bot_qqnum_list and not var.handle_bot: + var.handle_bot = bot + + +# qq机器人断开时执行 +@driver.on_bot_disconnect +async def on_bot_disconnect(bot: Bot): + # 判断掉线的是否为handle bot + if bot == var.handle_bot: + # 如果有写bot qq列表 + if pc.mc_status_bot_qqnum_list: + # 获取当前连着的bot列表(需要bot是在bot qq列表里) + available_bot_id_list = [ + bot_id for bot_id in get_bots() if bot_id in pc.mc_status_bot_qqnum_list + ] + if available_bot_id_list: + # 打擂台排序? + new_bot_index = pc.mc_status_bot_qqnum_list.index( + available_bot_id_list[0] + ) + for bot_id in available_bot_id_list: + now_bot_index = pc.mc_status_bot_qqnum_list.index(bot_id) + if now_bot_index < new_bot_index: + new_bot_index = now_bot_index + # 取下标在qq列表里最小的bot qq为新的handle bot + var.handle_bot = get_bot(pc.mc_status_bot_qqnum_list[new_bot_index]) + + else: + var.handle_bot = None + + # 不写就随便给一个连着的(如果有) + elif var.handle_bot: + try: + new_bot = get_bot() + var.handle_bot = new_bot + except ValueError: + var.handle_bot = None diff --git a/hexi/plugins/nonebot_plugin_ncm_saying/__init__.py b/hexi/plugins/nonebot_plugin_ncm_saying/__init__.py new file mode 100644 index 0000000..f5769d8 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_ncm_saying/__init__.py @@ -0,0 +1,45 @@ +import httpx +from nonebot import logger, on_command +from nonebot.adapters import Message +from nonebot.matcher import Matcher +from nonebot.params import CommandArg +from nonebot.adapters.onebot.v11 import MessageEvent, Bot, MessageSegment +import re +import json + +from nonebot.plugin import PluginMetadata + +__plugin_meta__ = PluginMetadata( + name="网抑云", + description="随机一条网易云热评", + usage="/网抑云 | 网易云热评 | emo:随机一条网易云热评", + type="application", +) + +__help_version__ = '0.1.0' +__help_plugin_name__ = "网抑云" +__usage__ = """一开口就老网抑云了 + +指令:/网抑云|网易云热评:随机一条网易云热评""" + +hitokoto_matcher = on_command("网抑云", aliases={"网易云热评", "emo"}) + + +@hitokoto_matcher.handle() +async def hitokoto(event: MessageEvent): + async with httpx.AsyncClient() as client: + response = await client.get("https://v.api.aa1.cn/api/api-wenan-wangyiyunreping/index.php?aa1=text") + if response.is_error: + logger.error("获取网抑云失败") + return + # 提取 JSON 部分 + pattern = r'

    (.*?)

    ' + match = re.search(pattern, response.text) + + if match: + data = match.group(1) + logger.info(f"解析后的数据:{data}") + mes = (MessageSegment.reply(event.message_id), data.split("——")[0]) + await hitokoto_matcher.finish(mes) + else: + logger.warning("未找到 匹配 部分") diff --git a/hexi/plugins/nonebot_plugin_picfinder_take/README.md b/hexi/plugins/nonebot_plugin_picfinder_take/README.md new file mode 100644 index 0000000..c4010cd --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picfinder_take/README.md @@ -0,0 +1,76 @@ +# picfinder_take +个人~~缝合~~修改的Hoshino bot搜图插件。 + +这个插件的主要思路其实是在hoshino上还原隔壁 [@Tsuk1ko](https://github.com/Tsuk1ko) 大佬家的[竹竹](https://github.com/Tsuk1ko/cq-picsearcher-bot)的搜图交互体验(所以插件名是たけ) + +代码主体部分参考了 [@Watanabe-Asa](https://github.com/Watanabe-Asa)大佬的 [搜图](https://github.com/pcrbot/Salmon-plugin-transplant#%E6%90%9C%E5%9B%BE)与 [@Cappuccilo](https://github.com/Cappuccilo)大佬的 [以图搜图](https://github.com/pcrbot/cappuccilo_plugins#%E4%BB%A5%E5%9B%BE%E6%90%9C%E5%9B%BE),感谢各位大佬的代码) + +--- + +- 6.1更新:增加私聊搜图、截屏识别和代理功能 + +- 6.24更新:增加回复搜图功能,搜图请求更换为异步(感谢 [@蓝红心](https://github.com/LHXnois)大佬) + +- 7.9更新:增加自定义HOST功能,在qiang内又不想用全局代理的用户(?)可以单独为SauceNao和ascii2d配置反代或ip直连)(继续感谢 [@蓝红心](https://github.com/LHXnois)大佬) + +- 7.26更新:回复搜图增加at支持 + +- 10.20更新:增加批量搜图计数与吞图提示 + +- 12.12更新:增加频道搜图支持,适配go-cqhttp-1.0.0beat8-fix2(还是感谢 [@蓝红心](https://github.com/LHXnois)大佬) + +- 22.01.10更新:适配新版图片CQcode,增加IGNORE_STAMP配置项,可在批量搜索中自动忽略subType不为0的图片(比如表情包);用cloudscraper绕过ascii2d近期新增的cf认证 + +## 特点 + +- 搜索SauceNao,在相似率过低时自动补充搜索ascii2d,相似率阈值可在config中调整。搜索结果显示数量可在config中调整。 + +- 解析SauceNao和ascii2d搜索结果的作品详细信息。SauceNao全部42个index格式解析都已完成;ascii2d常见格式应该也能解析,一些奇怪格式的外部登录不敢保证) + +- 获取SauceNao和ascii2d的结果缩略图,缩略图可在config中关闭。 + +- 搜图结果可由普通回复切换为合并转发回复,减少刷屏情况。发送模式可在config中调整。 + +- 增加批量搜图模式,解决移动端文字命令+图片发送麻烦的问题。 + +- 增加搜图每人每日限额,可在config中调整限额。要懂得节制噢.jpg + +- 增加简单的手机截屏识别功能,判断为整屏手机截屏时会拒绝搜索 ~~(你会截你马个图.jpg)~~ + +- 增加私聊搜图功能,有效缓解腾讯吞图(但反之临时会话下搜索结果含图片与链接时概率被吞无法发送,若要稳定使用需加bot好友) + +- 增加代理设置,方便qiang内使用 + +- 增加回复搜图功能,可直接对群友发送的图片进行回复搜索,省去转发过程) + +- New!增加IGNORE_STAMP配置项,可在批量搜索中自动忽略沙雕群友发的表情包,减少资源浪费与刷屏) + + +## 用法 + +- 申请并在config中配置SauceNao的API key + +- 发送 ``@bot+图片`` 或 ``[bot昵称]搜图+图片`` 进行单张搜索。 + +- 发送 ``[bot昵称]搜图`` 进入连续搜图模式,连续搜图模式下同一用户所发送所有图片都将直接搜索; + + 发送 ``谢谢[bot昵称]`` 退出连续搜图模式,或停止发图等待超时后自动退出连续搜图模式。 + +- 对他人发送的图片回复 ``@bot 搜图`` 或``[bot昵称]搜图`` 进行回复搜索。 + +- 私聊下直接发送图片即可进行搜索。 + + +## 频道使用 + +对特定子频道中收到的所有图片进行搜索(本质应该算是个常驻的连续搜图?) +在qq群这样可能影响讨论,但是在频道可以专门开一个搜图子频道只用来搜图! + +食用方法: + +- 创建一个专门的子频道 +- 搞到频道id和子频道id(看log) +- 按{频道id: [子频道id]}格式填到config.py里的enableguild里 +- 发送图片开始搜图 + +开启慢速模式然后给bot管理体验更佳 diff --git a/hexi/plugins/nonebot_plugin_picfinder_take/__init__.py b/hexi/plugins/nonebot_plugin_picfinder_take/__init__.py new file mode 100644 index 0000000..a0a4077 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picfinder_take/__init__.py @@ -0,0 +1,466 @@ +import re +from asyncio import sleep +from datetime import datetime, timedelta + +from nonebot import get_driver, on_message, on_startswith, require +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, PrivateMessageEvent +from nonebot.exception import ActionFailed +from nonebot.log import logger +from nonebot.plugin import PluginMetadata +from nonebot.rule import is_type, to_me + +require("nonebot_plugin_alconna") +from nonebot_plugin_alconna import UniMessage + +from .config import ( + CHAIN_REPLY, + CHECK, + DAILY_LIMIT, + IGNORE_STAMP, + SAUCENAO_KEY, + SEARCH_TIMEOUT, + threshold, +) +from .image import check_screenshot, get_image_data_ascii, get_image_data_sauce + +# 统一配置标准:把「插件内部常量」也暴露给 Web 管理台(来源无关)。 +# 说明:Web 读取/修改会写入 plugin_config.json 并热更新 config 模块属性; +# 要在运行期立即生效,插件各使用点应改用 get_effective_value 读取(见 docs/plugin-config-standard.md §5b)。 +from hexi.config_standard import register_config_items # noqa: E402 +from . import config as _cfgmod # noqa: E402 + +register_config_items( + __name__, + [ + {"key": "SAUCENAO_KEY", "label": "SauceNAO API Key", "type": "password", "secret": True}, + {"key": "DAILY_LIMIT", "label": "每日搜图限额", "type": "int", "default": 50}, + {"key": "SEARCH_TIMEOUT", "label": "批量搜索超时(秒)", "type": "int", "default": 60}, + {"key": "CHECK", "label": "开启截屏判定", "type": "bool", "default": True}, + {"key": "THUMB_ON", "label": "启用缩略图", "type": "bool", "default": True}, + {"key": "CHAIN_REPLY", "label": "合并转发回复", "type": "bool", "default": True}, + {"key": "IGNORE_STAMP", "label": "批量忽略表情包", "type": "bool", "default": True}, + {"key": "threshold", "label": "相似度阈值", "type": "float", "default": 70}, + ], + store=_cfgmod, +) + +__plugin_meta__ = PluginMetadata( + name="搜图", + description="SauceNAO + ascii2d 二次元搜图", + usage=( + "(xx为bot名称)\n" + "[@bot+图片] 单张/多张搜图\n" + "[xx搜图] 进入批量搜图模式\n" + "[谢谢xx] 退出批量搜图模式" + ), + type="application", +) + +driver_config = get_driver().config +SUPERUSERS = driver_config.superusers +NICKNAMES = list(driver_config.nickname) if driver_config.nickname else ["竹竹"] +NICKNAME = NICKNAMES[0] + +class DailyNumberLimiter: + """每日次数限制器(按年积日计数)""" + + def __init__(self, max_num): + self.max = max_num + self.today = -1 + self.count = {} + + def check(self, key) -> bool: + day = datetime.now().timetuple().tm_yday + if day != self.today: + self.today = day + self.count.clear() + return self.count.get(key, 0) < self.max + + def get_num(self, key): + return self.count.get(key, 0) + + def increase(self, key, num=1): + self.count[key] = self.count.get(key, 0) + num + + +lmtd = DailyNumberLimiter(DAILY_LIMIT) + + +class PicListener: + def __init__(self): + self.on = {} + self.count = {} + self.limit = {} + self.timeout = {} + + def get_on_off_status(self, gid): + return self.on[gid] if self.on.get(gid) is not None else False + + def turn_on(self, gid, uid): + self.on[gid] = uid + self.timeout[gid] = datetime.now() + timedelta(seconds=SEARCH_TIMEOUT) + self.count[gid] = 0 + self.limit[gid] = DAILY_LIMIT - lmtd.get_num(uid) + + def turn_off(self, gid): + self.on.pop(gid) + self.count.pop(gid) + self.timeout.pop(gid) + self.limit.pop(gid) + + def count_plus(self, gid): + self.count[gid] += 1 + + +pls = PicListener() + +start_finder = on_startswith(("识图", "搜图", "查图", "找图"), rule=to_me()) +picmessage = on_message(rule=is_type(GroupMessageEvent), block=False) +replymessage = on_message(rule=is_type(GroupMessageEvent), block=False) +thanks = on_startswith("谢谢") +pic_private = on_message(rule=is_type(PrivateMessageEvent), block=False) + + +def parse_report(text: str) -> UniMessage: + """将含 [CQ:image,file=...] 的搜索报告字符串转为 UniMessage""" + msg = UniMessage() + parts = re.split(r"(\[CQ:image,[^\]]*\])", text) + for part in parts: + if part.startswith("[CQ:image,"): + m = re.search(r"file=([^,\]]+)", part) + msg += UniMessage.image(url=m.group(1) if m else "") + elif part: + msg += UniMessage.text(part) + return msg + + +def _extract_image(ev) -> tuple[str, str, str | None] | None: + """从消息中提取第一张图片的 (file, url, subType),无图片返回 None""" + for m in ev.message: + if m.type == "image": + return m.data["file"], m.data["url"], m.data.get("subType") + return None + + +@start_finder.handle() +async def start_finder_handle(bot: Bot, ev: GroupMessageEvent): + uid = ev.user_id + gid = ev.group_id + mid = ev.message_id + if str(uid) not in SUPERUSERS: + await UniMessage.text("暂不支持在群聊中使用!").send() + return + ret = _extract_image(ev) + if not ret: + if pls.get_on_off_status(gid): + if uid == pls.on[gid]: + pls.timeout[gid] = datetime.now() + timedelta(seconds=30) + await UniMessage.text( + "您已经在搜图模式下啦!\n如想退出搜图模式请发送“谢谢竹竹”~" + ).send() + await start_finder.finish() + else: + await UniMessage.at(user_id=str(pls.on[gid])).text( + "正在搜图,请耐心等待~" + ).send() + await start_finder.finish() + pls.turn_on(gid, uid) + await UniMessage.text( + f"了解~请发送图片吧!支持批量噢!\n如想退出搜索模式请发送“谢谢{NICKNAME}”" + ).send() + await sleep(30) + ct = 0 + while pls.get_on_off_status(gid): + if datetime.now() < pls.timeout[gid]: + if ct != pls.count[gid]: + ct = pls.count[gid] + pls.timeout[gid] = datetime.now() + timedelta(seconds=60) + else: + temp = pls.on[gid] + if not pls.count[gid]: + await UniMessage.at(user_id=str(temp)).text( + " 由于超时,已为您自动退出搜图模式~\n您本次搜索期间未发送任何图片,请检查是否被吞图~" + ).send() + else: + await UniMessage.at(user_id=str(temp)).text( + f" 由于超时,已为您自动退出搜图模式,以后要记得说“谢谢{NICKNAME}”来退出搜图模式噢~\n您本次搜索共搜索了{pls.count[gid]}张图片~" + ).send() + pls.turn_off(ev.group_id) + break + await sleep(30) + return + file, url, _ = ret + if str(uid) not in SUPERUSERS: + if not lmtd.check(uid): + await UniMessage.text( + f"您今天已经搜过{DAILY_LIMIT}次图了,休息一下明天再来吧~" + ).send(at_sender=True) + return + + if CHECK: + result = await check_screenshot(bot, file, url) + if result: + if result == 1: + await UniMessage.reply(id=str(mid)).text( + "该图似乎是手机截屏,请进行适当裁剪后再尝试搜图~\n*请注意搜索漫画时务必截取一个完整单页进行搜图~" + ).send() + if result == 2: + await UniMessage.reply(id=str(mid)).text( + "该图似乎是长图拼接,请进行适当裁剪后再尝试搜图~\n*请注意搜索漫画时务必截取一个完整单页进行搜图~" + ).send() + return + await UniMessage.text("正在搜索,请稍候~").send() + await picfinder(bot, ev, url) + + +@picmessage.handle() +async def picmessage_handle(bot: Bot, ev: GroupMessageEvent): + mid = ev.message_id + atcheck = False + batchcheck = False + for m in ev.message: + if m.type == "at" and int(m.data["qq"]) == ev.self_id: + atcheck = True + if pls.get_on_off_status(ev.group_id): + if int(pls.on[ev.group_id]) == int(ev.user_id): + batchcheck = True + if not (batchcheck or atcheck): + return + uid = ev.user_id + ret = _extract_image(ev) + if not ret: + return + file, url, sbtype = ret + if str(uid) not in SUPERUSERS: + if not lmtd.check(uid): + await UniMessage.text( + f"您今天已经搜过{DAILY_LIMIT}次图了,休息一下明天再来吧~" + ).send(at_sender=True) + if pls.get_on_off_status(ev.group_id): + pls.turn_off(ev.group_id) + return + if pls.get_on_off_status(ev.group_id): + pls.count_plus(ev.group_id) + if pls.count[ev.group_id] > pls.limit[ev.group_id]: + await UniMessage.text( + f"您今天已经搜过{DAILY_LIMIT}次图了,休息一下明天再来吧~" + ).send(at_sender=True) + pls.turn_off(ev.group_id) + return + if sbtype and IGNORE_STAMP: + if sbtype != "0": + await UniMessage.reply(id=str(mid)).text( + "该图为表情,已忽略~如确需搜索请尝试单发搜索或回复搜索~" + ).send() + return + + if CHECK: + result = await check_screenshot(bot, file, url) + if result: + if result == 1: + await UniMessage.reply(id=str(mid)).text( + "该图似乎是手机截屏,请手动进行适当裁剪后再尝试搜图~\n*请注意搜索漫画时务必截取一个完整单页进行搜图~" + ).send() + if result == 2: + await UniMessage.reply(id=str(mid)).text( + "该图似乎是长图拼接,请手动进行适当裁剪后再尝试搜图~\n*请注意搜索漫画时务必截取一个完整单页进行搜图~" + ).send() + return + if "c2cpicdw.qpic.cn/offpic_new/" in url: + md5 = file[:-6].upper() + url = f"http://gchat.qpic.cn/gchatpic_new/0/0-0-{md5}/0?term=2" + await UniMessage.text("正在搜索,请稍候~").send() + await picfinder(bot, ev, url) + + +@replymessage.handle() +async def replymessage_handle(bot: Bot, ev: GroupMessageEvent): + mid = ev.message_id + uid = ev.user_id + seg = ev.message[0] + if seg.type != "reply": + return + tmid = seg.data["id"] + cmd = ev.message.extract_plain_text() + flag1 = 0 + flag2 = 0 + for m in ev.message[2:]: + if m.type == "at" and int(m.data["qq"]) == ev.self_id: + flag1 = 1 + for name in NICKNAMES: + if name in cmd: + flag1 = 1 + break + for pfcmd in ["识图", "搜图", "查图", "找图"]: + if pfcmd in cmd: + flag2 = 1 + if not (flag1 and flag2): + return + if str(uid) not in SUPERUSERS: + if not lmtd.check(uid): + await UniMessage.text( + f"您今天已经搜过{DAILY_LIMIT}次图了,休息一下明天再来吧~" + ).send(at_sender=True) + try: + tmsg = await bot.get_msg(message_id=int(tmid)) + except ActionFailed: + await UniMessage.text("该消息已过期,请重新转发~").send() + await replymessage.finish() + ret = re.search(r"\[CQ:image,file=(.*)?,url=(.*)\]", str(tmsg["message"])) + if not ret: + await UniMessage.text("未找到图片~").send() + return + file = ret.group(1) + url = ret.group(2) + + if ",subType=" in url: + url = url.split(",")[0] + elif ",subType=" in file: + file = file.split(",")[0] + + if CHECK: + result = await check_screenshot(bot, file, url) + if result: + if result == 1: + await UniMessage.reply(id=str(mid)).text( + "该图似乎是手机截屏,请手动进行适当裁剪后再尝试搜图~\n*请注意搜索漫画时务必截取一个完整单页进行搜图~" + ).send() + if result == 2: + await UniMessage.reply(id=str(mid)).text( + "该图似乎是长图拼接,请手动进行适当裁剪后再尝试搜图~\n*请注意搜索漫画时务必截取一个完整单页进行搜图~" + ).send() + return + if "c2cpicdw.qpic.cn/offpic_new/" in url: + md5 = file[:-6].upper() + url = f"http://gchat.qpic.cn/gchatpic_new/0/0-0-{md5}/0?term=2" + await UniMessage.text("正在搜索,请稍候~").send() + await picfinder(bot, ev, url) + + +@thanks.handle() +async def thanks_handle(bot: Bot, ev: GroupMessageEvent): + gid = ev.group_id + name = ev.message.extract_plain_text().removeprefix("谢谢").strip() + if name not in NICKNAMES: + return + if pls.get_on_off_status(gid): + if pls.on[gid] != ev.user_id: + await UniMessage.text("不能替别人结束搜图哦~").send() + return + if not pls.count[gid]: + await UniMessage.text("不用谢~\n您本次搜索期间未发送任何图片,请检查是否被吞图~").send() + else: + await UniMessage.text(f"不用谢~\n您本次搜索共搜索了{pls.count[gid]}张图片~").send() + pls.turn_off(gid) + return + await UniMessage.text("にゃ~").send() + + +@pic_private.handle() +async def pic_private_handle(bot: Bot, ev: PrivateMessageEvent): + uid = ev.user_id + ret = _extract_image(ev) + if not ret: + flag1 = flag2 = 0 + for name in NICKNAMES: + if name in str(ev.message): + flag1 = 1 + break + for pfcmd in ["识图", "搜图", "查图", "找图"]: + if pfcmd in str(ev.message): + flag2 = 1 + if flag1 and flag2: + await UniMessage.text("私聊搜图请直接发送图片~").send() + return + file, url, _ = ret + if not lmtd.check(uid): + await UniMessage.text( + f"您今天已经搜过{DAILY_LIMIT}次图了,休息一下明天再来吧~" + ).send() + return + if "c2cpicdw.qpic.cn/offpic_new/" in url: + md5 = file.upper() + logger.info(f"图片URL{url}") + url = f"https://gchat.qpic.cn/gchatpic_new/0/0-0-{md5}/0?term=2" + + await UniMessage.text("正在搜索,请稍候~").send() + result = await get_image_data_sauce(url, SAUCENAO_KEY) + image_data_report = result[0] + simimax = result[1] + if "Index #" in image_data_report: + su = next(iter(SUPERUSERS)) + await bot.send_private_msg(user_id=int(su), message="发生index解析错误") + await bot.send_private_msg(user_id=int(su), message=url) + await bot.send_private_msg(user_id=int(su), message=image_data_report) + await parse_report(image_data_report).send() + + if float(simimax) > float(threshold): + lmtd.increase(uid) + else: + if simimax != 0: + await UniMessage.text("相似度过低,换用ascii2d检索中…").send() + else: + logger.error("SauceNao not found imageInfo") + await UniMessage.text("SauceNao检索失败,换用ascii2d检索中…").send() + + image_data_report = await get_image_data_ascii(url) + if image_data_report[0]: + await parse_report(image_data_report[0]).send() + lmtd.increase(uid) + if image_data_report[1]: + await parse_report(image_data_report[1]).send() + if not (image_data_report[0] or image_data_report[1]): + logger.error("ascii2d not found imageInfo") + await UniMessage.text("ascii2d检索失败…").send() + + +async def chain_reply(bot: Bot, ev: GroupMessageEvent, chain, msg): + if not CHAIN_REPLY: + await parse_report(msg).send() + return chain + data = { + "type": "node", + "data": { + "name": str(NICKNAME) if str(NICKNAME) else "竹竹", + "uin": str(ev.self_id), + "content": str(msg), + }, + } + chain.append(data) + return chain + + +async def picfinder(bot: Bot, ev: GroupMessageEvent, image_data): + uid = ev.user_id + chain = [] + result = await get_image_data_sauce(image_data, SAUCENAO_KEY) + image_data_report = result[0] + simimax = result[1] + if "Index #" in image_data_report: + su = next(iter(SUPERUSERS)) + await bot.send_private_msg(user_id=int(su), message="发生index解析错误") + await bot.send_private_msg(user_id=int(su), message=image_data) + await bot.send_private_msg(user_id=int(su), message=image_data_report) + chain = await chain_reply(bot, ev, chain, image_data_report) + + if float(simimax) > float(threshold): + lmtd.increase(uid) + else: + if simimax != 0: + chain = await chain_reply(bot, ev, chain, "相似度过低,换用ascii2d检索中…") + else: + logger.error("SauceNao not found imageInfo") + chain = await chain_reply(bot, ev, chain, "SauceNao检索失败,换用ascii2d检索中…") + + image_data_report = await get_image_data_ascii(image_data) + if image_data_report[0]: + chain = await chain_reply(bot, ev, chain, image_data_report[0]) + lmtd.increase(uid) + if image_data_report[1]: + chain = await chain_reply(bot, ev, chain, image_data_report[1]) + if not (image_data_report[0] or image_data_report[1]): + logger.error("ascii2d not found imageInfo") + chain = await chain_reply(bot, ev, chain, "ascii2d检索失败…") + + if CHAIN_REPLY: + await bot.send_group_forward_msg(group_id=ev.group_id, messages=chain) diff --git a/hexi/plugins/nonebot_plugin_picfinder_take/config.py b/hexi/plugins/nonebot_plugin_picfinder_take/config.py new file mode 100644 index 0000000..0ca68e0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picfinder_take/config.py @@ -0,0 +1,50 @@ +import os + +threshold = 70 # SauceNAO相似度阈值,低于该相似度自动追加ascii2d搜索 + +SAUCENAO_KEY = "dfc2b9156f254754dee2ead531826020f6316f92" # SauceNAO 的 API key + +SAUCENAO_RESULT_NUM = 3 # SauceNAO搜索结果显示数量 + +ASCII_RESULT_NUM = 3 # ascii2d搜索结果显示数量 + +SEARCH_TIMEOUT = 60 # 连续搜索模式超时时长 + +DAILY_LIMIT = 50 # 搜图每日限额 + +CHAIN_REPLY = True # 是否启用合并转发回复模式 + +THUMB_ON = True # 是否启用缩略图 + +CHECK = True # 是否开启手机截屏判定 + +IGNORE_STAMP = True # 是否在批量搜索中忽略表情包 + +HOST_CUSTOM = { + # 自定义Host,不使用留空即可 + # 格式示例:'https://ascii2d.net' , 'http://localhost:12345' + 'SAUCENAO': '', + 'ASCII': '' +} + +# ascii2d 的 Cloudflare cookie 文件(Netscape 格式,浏览器导出,参考 nonebot_plugin_video_analysis 的 cookies.txt 用法) +# 获取方式:浏览器打开 ascii2d.net 过验证后,用 EditThisCookie / Cookie-Editor 扩展导出为 Netscape 格式, +# 保存为 nonebot_plugin_picfinder_take/data/cookies_ascii2d.txt +# 留空则使用 playwright 无 cookie 尝试(可能无法通过 Cloudflare 验证) +ASCII2D_COOKIES_FILE = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "data", "cookies_ascii2d.txt" +) + +proxies = { + 'http': '', + 'https': '' +} # 网络代理 + +enableguild = {0000: [00000, 1111], 123456: [2345]} # 频道白名单 格式{频道id: [子频道id]} + +helptext = ''' +(xx为bot名称) +[@bot+图片] 单张/多张搜图 +[xx搜图] 进入批量搜图模式 +[谢谢xx] 退出批量搜图模式 +'''.strip() diff --git a/hexi/plugins/nonebot_plugin_picfinder_take/image.py b/hexi/plugins/nonebot_plugin_picfinder_take/image.py new file mode 100644 index 0000000..adafbae --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picfinder_take/image.py @@ -0,0 +1,865 @@ +import asyncio +import base64 +import os +import re +from io import BytesIO +from random import randint +from traceback import format_exc + +import cloudscraper +import httpx +from PIL import Image +from lxml import etree +from nonebot.log import logger +from playwright.async_api import async_playwright + +from .config import ( + ASCII2D_COOKIES_FILE, + ASCII_RESULT_NUM, + HOST_CUSTOM, + SAUCENAO_RESULT_NUM, + THUMB_ON, + proxies, +) + + +def pic2b64(pic) -> str: + """PIL Image 转 base64:// 字符串""" + buf = BytesIO() + pic.save(buf, format="PNG") + return "base64://" + base64.b64encode(buf.getvalue()).decode() + + +def _img_cq(base64_str: str) -> str: + """生成图片 CQ 码字符串(用于嵌入搜索报告文本)""" + return f"[CQ:image,file={base64_str}]" + + +def _make_client(timeout: float) -> httpx.AsyncClient: + """构造 httpx 客户端(httpx 0.28 移除了 AsyncClient 的 proxies 参数,转为 mounts)""" + http_proxy = proxies.get("http") + https_proxy = proxies.get("https") + if http_proxy or https_proxy: + mounts = {} + if http_proxy: + mounts["http://"] = httpx.HTTPTransport(proxy=http_proxy) + if https_proxy: + mounts["https://"] = httpx.HTTPTransport(proxy=https_proxy) + return httpx.AsyncClient(mounts=mounts, timeout=timeout) + return httpx.AsyncClient(timeout=timeout) + + +async def get_pic(address): + async with _make_client(20) as client: + resp = await client.get(address) + return resp.content + + +def randcolor(): + return (randint(0, 255), randint(0, 255), randint(0, 255)) + + +def ats_pic(img): + if img.mode != "RGB": + img = img.convert("RGB") + width = img.size[0] - 1 # 长度 + height = img.size[1] - 1 # 宽度 + img.putpixel((0, 0), randcolor()) + img.putpixel((0, height), randcolor()) + img.putpixel((width, 0), randcolor()) + img.putpixel((width, height), randcolor()) + return img + + +async def check_screenshot(bot, file, imgurl): + async with _make_client(20) as client: + pichead = await client.head(imgurl) + if pichead.headers["Content-Type"] == "image/gif": + print("gif pic, not likely a screen shot") + return 0 + try: + resp = await client.get(imgurl) + image = Image.open(BytesIO(resp.content)) + except Exception: + print("download failed") + return 0 + cord = image.size[0] / image.size[1] + height = image.size[1] + print(cord) + if cord > 0.565: + print("too short, not likely a screen shot") + return 0 + if cord < 0.2: + print("too long, might be long screen shot") + return 2 + print("size checked, next ocr") + try: + ocr_result = await bot.call_api(".ocr_image", image=file) + except Exception: + print("ocr failed") + return False + flag = 0 + for result in ocr_result["texts"]: + key1 = re.search("[0-9]{1,2}:[0-9]{2}", result["text"]) # 时间 + key2 = re.search("移动|联通|电信", result["text"]) + key3 = re.search("4G|5G", result["text"]) + key4 = re.search("[0-9]{1,2}%", result["text"]) # 电量 + key5 = re.search("[0-9]{0,3}[\\\/][0-9]{0,3}", result["text"]) # 页数 + if key2 or key3 or key4: + print(str(result)) + loc = result["coordinates"][2]["y"] + if int(loc) < (int(height) / 19): + flag = 1 + if key1 or key5: + print(str(result)) + loc = result["coordinates"][2]["y"] + if int(loc) < (int(height) / 19) or int(loc) > (int(height) * 18 / 20): + flag = 1 + if flag: + break + if flag: + return 1 + else: + return 0 + + +def sauces_info(sauce): + service_name = "" + info = "" + try: + if sauce["header"]["index_id"] == 0: + service_name = "H-Magazines" + title = sauce["data"]["title"] + part = sauce["data"]["part"] + date = sauce["data"]["date"] + info = f"{title}-{part}/{date}" + + # index 1 "h-anime" disabled + + elif sauce["header"]["index_id"] == 2: + service_name = "H-Game CG" + company = sauce["data"]["company"] + title = sauce["data"]["title"] + info = f"[{company}] {title}" + + # index 3 "ddb-objects" disabled + + # index 4 "ddb-samples" disabled + + elif sauce["header"]["index_id"] == 5 or sauce["header"]["index_id"] == 6: + service_name = "pixiv" + author_name = sauce["data"]["member_name"] + title = sauce["data"]["title"] + info = f"「{title}」/「{author_name}」" + + # index 6 "pixiv historical" with 5 + + # index 7 "anime" disabled + + elif sauce["header"]["index_id"] == 8: + service_name = "nico nico seiga" + author_name = sauce["data"]["member_name"] + title = sauce["data"]["title"] + info = f"「{title}」/「{author_name}」" + + elif sauce["header"]["index_id"] == 9: + service_name = "Danbooru" + creator = sauce["data"]["creator"] + material = sauce["data"]["material"] + info = f"[{creator}]({material})" + + elif sauce["header"]["index_id"] == 10: + service_name = "drawr Images" + author_name = sauce["data"]["member_name"] + title = sauce["data"]["title"] + info = f"「{title}」/「{author_name}」" + + elif sauce["header"]["index_id"] == 11: + service_name = "Nijie Images" + author_name = sauce["data"]["member_name"] + title = sauce["data"]["title"] + info = f"「{title}」/「{author_name}」" + + elif sauce["header"]["index_id"] == 12: + service_name = "Yande.re" + creator = sauce["data"]["creator"] + material = sauce["data"]["material"] + info = f"[{creator}]({material})" + + # index 13 "animeop" disabled + + # index 14 "IMDb" disabled + + # index 15 "Shutterstock" disabled + + elif sauce["header"]["index_id"] == 16: + service_name = "FAKKU" + creator = sauce["data"]["creator"] + source = sauce["data"]["source"] + info = f"[{creator}]({source})" + + # index 17 reserved + + elif sauce["header"]["index_id"] == 18 or sauce["header"]["index_id"] == 38: + service_name = "H-Misc (ehentai)" + eng_name = sauce["data"]["eng_name"] + jp_name = sauce["data"]["jp_name"] + info = f"{jp_name}" if jp_name else f"{eng_name}" + + elif sauce["header"]["index_id"] == 19: + service_name = "2D-Market" + creator = sauce["data"]["creator"] + source = sauce["data"]["source"] + info = f"[{creator}]({source})" + + elif sauce["header"]["index_id"] == 20: + service_name = "MediBang" + member_name = sauce["data"]["member_name"] + title = sauce["data"]["title"] + info = f"「{title}」/「{member_name}」" + + elif sauce["header"]["index_id"] == 21: + service_name = "Anime" + title = sauce["data"]["source"] + year = sauce["data"]["year"] + part = sauce["data"]["part"] + est_time = sauce["data"]["est_time"] + time = est_time.split("/")[0] + info = f"《{title}》/{year}\n第{part}集,{time}" + + elif sauce["header"]["index_id"] == 22: + service_name = "H-Anime" + title = sauce["data"]["source"] + year = sauce["data"]["year"] + part = sauce["data"]["part"] + est_time = sauce["data"]["est_time"] + time = est_time.split("/")[0] + info = f"《{title}》/{year}\n第{part}集,{time}" + + elif sauce["header"]["index_id"] == 23: + service_name = "IMDb-Movies" + title = sauce["data"]["source"] + year = sauce["data"]["year"] + est_time = sauce["data"]["est_time"] + time = est_time.split("/")[0] + info = f"《{title}》/{year},{time}" + + elif sauce["header"]["index_id"] == 24: + service_name = "IMDb-Shows" + title = sauce["data"]["source"] + year = sauce["data"]["year"] + part = sauce["data"]["part"] + est_time = sauce["data"]["est_time"] + time = est_time.split("/")[0] + info = f"《{title}》/{year}\n第{part}集,{time}" + + elif sauce["header"]["index_id"] == 25: + service_name = "Gelbooru" + creator = sauce["data"]["creator"] + material = sauce["data"]["material"] + info = f"[{creator}]({material})" + + elif sauce["header"]["index_id"] == 26: + service_name = "Konachan" + creator = sauce["data"]["creator"] + material = sauce["data"]["material"] + info = f"[{creator}]({material})" + + elif sauce["header"]["index_id"] == 27: + service_name = "Sankaku Channel" + creator = sauce["data"]["creator"] + material = sauce["data"]["material"] + info = f"[{creator}]({material})" + + elif sauce["header"]["index_id"] == 28: + service_name = "Anime-Pictures.net" + creator = sauce["data"]["creator"] + material = sauce["data"]["material"] + info = f"[{creator}]({material})" + + elif sauce["header"]["index_id"] == 29: + service_name = "e621.net" + creator = sauce["data"]["creator"] + material = sauce["data"]["material"] + info = f"[{creator}]({material})" + + elif sauce["header"]["index_id"] == 30: + service_name = "Idol Complex" + creator = sauce["data"]["creator"] + material = sauce["data"]["material"] + info = f"[{creator}]({material})" + + elif sauce["header"]["index_id"] == 31: + service_name = "bcy.net Illust" + author_name = sauce["data"]["member_name"] + title = sauce["data"]["title"] + info = f"「{title}」/「{author_name}」" + + elif sauce["header"]["index_id"] == 32: + service_name = "bcy.net Cosplay" + author_name = sauce["data"]["member_name"] + title = sauce["data"]["title"] + info = f"「{title}」/「{author_name}」" + + elif sauce["header"]["index_id"] == 33: + service_name = "PortalGraphics.net" + member_name = sauce["data"]["member_name"] + title = sauce["data"]["title"] + info = f"「{title}」/「{member_name}」" + + elif sauce["header"]["index_id"] == 34: + service_name = "deviantArt" + author_name = sauce["data"]["author_name"] + title = sauce["data"]["title"] + info = f"「{title}」/「{author_name}」" + + elif sauce["header"]["index_id"] == 35: + service_name = "Pawoo.net" + illust_id = sauce["data"]["pawoo_id"] + author_name = sauce["data"]["pawoo_user_display_name"] + info = f"「{illust_id}」/「{author_name}」" + + elif sauce["header"]["index_id"] == 36: + service_name = "Madokami (Manga)" + source = sauce["data"]["source"] + part = sauce["data"]["part"] + info = part if source in part else f"{source}-{part}" + + elif sauce["header"]["index_id"] == 37 or sauce["header"]["index_id"] == 371: + service_name = "MangaDex" + artist = sauce["data"]["artist"] + author = sauce["data"]["author"] + source = sauce["data"]["source"] + part = sauce["data"]["part"] + info_a = f"[{artist}]" if artist == author else f"[{artist}({author})]" + info_b = part if source in part else f"{source}-{part}" + info = info_a + info_b + + # index 38 "H-Misc (ehentai)" with 18 + + elif sauce["header"]["index_id"] == 39: + service_name = "Artstation" + author_name = sauce["data"]["author_name"] + title = sauce["data"]["title"] + info = f"「{title}」/「{author_name}」" + + elif sauce["header"]["index_id"] == 40: + service_name = "FurAffinity" + author_name = sauce["data"]["author_name"] + title = sauce["data"]["title"] + info = f"「{title}」/「{author_name}」" + + elif sauce["header"]["index_id"] == 41: + service_name = "Twitter" + author_name = sauce["data"]["twitter_user_handle"] + time = sauce["data"]["created_at"] + info = f"「{time[0:10]}」/「{author_name}」" + + elif sauce["header"]["index_id"] == 42: + service_name = "Furry Network" + author_name = sauce["data"]["author_name"] + title = sauce["data"]["title"] + info = f"「{title}」/「{author_name}」" + + elif sauce["header"]["index_id"] == 43: + service_name = "Kemono" + service = sauce["data"]["service_name"] + author_name = sauce["data"]["user_name"] + title = sauce["data"]["title"] + info = f"「{title}」/「({service}){author_name}」" + + elif sauce["header"]["index_id"] == 44: + service_name = "Skeb" + creator_name = sauce["data"]["creator_name"] + creator = sauce["data"]["creator"] + info = f"[{creator_name}]({creator})" + + else: + index = sauce["header"]["index_id"] + service_name = f"Index #{index}" + info = "no info" + + except Exception as e: + index = sauce["header"]["index_id"] + service_name = f"Index #{index}" + info = "no info" + print(format_exc()) + + return service_name, info + + +class SauceNAO: + def __init__( + self, + api_key, + output_type=2, + testmode=0, + dbmask=None, + dbmaski=None, + db=999, + numres=3, + shortlimit=20, + longlimit=300, + ): + params = dict() + params["api_key"] = api_key + params["output_type"] = output_type + params["testmode"] = testmode + params["dbmask"] = dbmask + params["dbmaski"] = dbmaski + params["db"] = db + params["numres"] = numres + self.params = params + self.host = HOST_CUSTOM["SAUCENAO"] or "https://saucenao.com" + self.header = "————>saucenao<————" + + async def get_sauce(self, image_url): + logger.debug(f"Now starting get the SauceNAO data:{image_url}") + # 过滤 None 参数(SauceNAO 文件上传遇 dbmask=None 编码会返回 500) + params = {k: v for k, v in self.params.items() if v is not None} + # 优先本地下载图片后以文件形式提交,避免 SauceNAO 服务器抓取 QQ 图床失败 + try: + async with _make_client(20) as client: + resp = await client.get(image_url) + resp.raise_for_status() + image_bytes = resp.content + submit_ok = True + except Exception as e: + logger.error(f"图片本地下载失败({e}), 退回 URL 提交") + submit_ok = False + + if submit_ok: + params.pop("url", None) + async with _make_client(30) as client: + response = await client.post( + f"{self.host}/search.php", + params=params, + files={"file": ("search_image.jpg", image_bytes, "image/jpeg")}, + ) + else: + params["url"] = image_url + async with _make_client(15) as client: + response = await client.get(f"{self.host}/search.php", params=params) + + if response.status_code != 200: + raise RuntimeError( + f"SauceNAO 请求失败: HTTP {response.status_code}, 响应: {response.text[:100]!r}" + ) + return response.json() + + async def get_view(self, sauce) -> str: + sauces = await self.get_sauce(sauce) + repass = "" + simimax = 0 + index = 1 + + for sauce in sauces["results"]: + try: + url = ( + sauce["data"]["ext_urls"][0].replace("\\", "").strip() + if "ext_urls" in sauce["data"] + else "no link" + ) + similarity = sauce["header"]["similarity"] + if not similarity.replace(".", "").isdigit(): + similarity = 0 + simimax = float(similarity) if float(similarity) > simimax else simimax + thumbnail_url = sauce["header"]["thumbnail"] + if THUMB_ON: + try: + thumbnail_image = _img_cq( + pic2b64( + ats_pic( + Image.open(BytesIO(await get_pic(thumbnail_url))) + ) + ) + ) + except Exception as e: + print(format_exc()) + thumbnail_image = "[预览图下载失败]" + else: + thumbnail_image = "" + + service_name, info = sauces_info(sauce) + + putline = ( + f"搜索结果{index}:\n\n{thumbnail_image}\n\n平台:\n\n{service_name}:\n\n" + f"相似度:{similarity}%\n\n信息:\n\n{info}\n\n相关:\n\n{url}" + ) + if repass: + repass = "\n\n\n".join([repass, putline]) + else: + repass = putline + + except Exception as e: + print(format_exc()) + pass + index += 1 + return [repass, simimax] + + +headers = { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "Accept-Encoding": "gzip, deflate", + "Accept-Language": "zh-CN,zh;q=0.9", + "Cache-Control": "max-age=0", + "Connection": "keep-alive", + "Origin": "https://ascii2d.net", + "Referer": "https://ascii2d.net/", + "Sec-Fetch-Dest": "document", + "Sec-Fetch-Mode": "navigate", + "Sec-Fetch-Site": "same-origin", + "Sec-Fetch-User": "?1", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36", +} + + +class ascii2d: + def __init__(self, num=2): + self.num = num + self.host = HOST_CUSTOM["ASCII"] or "https://ascii2d.net" + self.header = "————>ascii2d<————" + self.scraper = cloudscraper.create_scraper() + + async def get_search_data(self, url: str, data=None): + if data is not None: + html = data + else: + html = await get_html_ascii2d(url) + + all_data = html.xpath('//div[@class="row item-box"]') + info = [] + for data in all_data[1 : self.num + 1]: + try: + title = "" + member = "" + if not data.xpath('.//img[@loading="lazy"]/@src'): + continue + thumb_url = data.xpath('.//img[@loading="lazy"]/@src')[0].strip() + thumb_url = f"{self.host}{thumb_url}" + + if not data.xpath('.//div[@class="detail-box gray-link"]/h6'): + data2 = ( + data.xpath('.//div[@class="external"]')[0] + if data.xpath('.//div[@class="external"]') + else data + ) + info_url = ( + data2.xpath(".//a/@href")[0].strip() + if data2.xpath(".//a/@rel") + else "no link" + ) + tag = "外部登录" if info_url == "no link" else info_url.split("/")[2] + else: + data2 = data.xpath('.//div[@class="detail-box gray-link"]/h6')[0] + info_url = data2.xpath(".//a/@href")[0].strip() + tag = ( + data2.xpath("./small/text()") or data2.xpath(".//a/text()") + )[0].strip() + + if tag == "pixiv" or tag == "twitter": + title = data2.xpath(".//a//text()")[0] + member = data2.xpath(".//a//text()")[1] + title = f"「{title}」/「{member}」" + elif tag == "外部登录": + title = data2.text.replace("\n", "") if data2.text else "" + else: + title = data2.text.replace("\n", "") + title = f"「{title}」" + + info.append([info_url, tag, thumb_url, title]) + except Exception as e: + print(format_exc()) + logger.error(e) + continue + + return info + + async def add_repass(self, tag: str, data, thumbnails: dict | None = None): + po = "——{}——".format(tag) + index = 1 + for line in data: + if THUMB_ON: + try: + thumb_content = (thumbnails or {}).get(line[2]) + if thumb_content is None: + thumb_content = self.scraper.get( + line[2], timeout=20, proxies=proxies + ).content + thumbnail_image = _img_cq( + pic2b64(ats_pic(Image.open(BytesIO(thumb_content)))) + ) + except Exception as e: + print(format_exc()) + thumbnail_image = "[预览图下载失败]" + else: + thumbnail_image = "" + putline = ( + f"搜索结果{index}:\n\n{thumbnail_image}\n\n平台:\n\n{line[1]}\n\n" + f"信息:\n\n{line[3]}\n\n相关:\n\n{line[0]}" + ) + po = "\n\n\n".join([po, putline]) + index += 1 + + return po + + async def get_view(self, ascii2d) -> str: + putline1 = "" + putline2 = "" + url_index = f"{self.host}/search/url/{ascii2d}" + logger.debug(f"Now starting get the {url_index}") + + try: + html_index = await get_html_ascii2d(url_index) + if html_index is None: + logger.error("ascii2d 页面获取失败(Cloudflare challenge 未通过)") + return [putline1, putline2] + except Exception as e: + print(format_exc()) + logger.error(f"ascii2d get html data failed: {e}") + return [putline1, putline2] + + neet_div = html_index.xpath( + '//div[@class="detail-link pull-xs-right hidden-sm-down gray-link"]' + ) + + if neet_div: + a_url_foot = neet_div[0].xpath("./span/a/@href") + url2 = f"{self.host}{a_url_foot[1]}" + + color = await self.get_search_data("", data=html_index) + bovw = await self.get_search_data(url2) + + # 用系统浏览器会话批量下载缩略图(带 CF cookie,避免被 Cloudflare 拦截) + thumb_urls = [line[2] for line in color + bovw] + thumbnails = await fetch_thumbs_playwright(thumb_urls) + + if color: + putline1 = await self.add_repass("色调检索", color, thumbnails) + + if bovw: + putline2 = await self.add_repass("特征检索", bovw, thumbnails) + + return [putline1, putline2] + + +async def get_image_data_sauce(image_url: str, api_key: str): + if type(image_url) == list: + image_url = image_url[0] + + logger.info("Loading Image Search Container……") + NAO = SauceNAO(api_key, numres=SAUCENAO_RESULT_NUM) + + logger.debug("Loading all view……") + repass = "" + simimax = 0 + # 网络抖动/免费key限流时重试,退避间隔同时规避 SauceNAO 的 4 秒限流 + for attempt in range(3): + try: + result = await NAO.get_view(image_url) + if result: + header = NAO.header + simimax = result[1] + repass = "\n".join([header, result[0]]) + break + except Exception as e: + logger.error(f"SauceNAO 第{attempt + 1}次尝试失败: {e}") + if attempt < 2: + await asyncio.sleep(2 * (attempt + 1)) + else: + return ["SauceNAO搜索失败……", 0] + + return [repass, simimax] + + +async def get_image_data_ascii(image_url: str): + if type(image_url) == list: + image_url = image_url[0] + + logger.info("Loading Image Search Container……") + ii2d = ascii2d(ASCII_RESULT_NUM) + + logger.debug("Loading all view……") + repass1 = "" + repass2 = "" + try: + putline = await ii2d.get_view(image_url) + if putline: + header = ii2d.header + if putline[0]: + repass1 = "\n".join([header, putline[0]]) + if putline[1]: + repass2 = "\n".join([header, putline[1]]) + except Exception as e: + logger.error(format_exc()) + return ["ascii2d搜索失败……", ""] + + return [repass1, repass2] + + +# 系统浏览器可执行文件(与获取 cookie 的浏览器同款 TLS 指纹) +CHROME_PATHS = [ + "C:/Program Files/Google/Chrome/Application/chrome.exe", + "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe", + "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe", + "C:/Program Files/Microsoft/Edge/Application/msedge.exe", +] + +# 专用浏览器 profile 目录(cf_clearance 持久化,首次过验证后长期有效) +CHROME_PROFILE_DIR = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "data", "chrome_profile" +) + + +def _parse_netscape_cookies(file_path: str) -> list[dict]: + """解析 Netscape 格式 cookies 文件(与 nonebot_plugin_video_analysis 同款)""" + cookies = [] + with open(file_path, "r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if not line or line.startswith("#"): + continue + parts = line.split("\t") + if len(parts) != 7: + continue + domain, flag, path, secure, expiry, name, value = parts + cookie = { + "name": name, + "value": value, + "domain": domain, + "path": path, + "secure": secure.upper() == "TRUE", + "sameSite": "Lax", + } + if expiry.isdigit() and int(expiry) > 0: + cookie["expires"] = int(expiry) + cookies.append(cookie) + return cookies + + +def _load_ascii2d_cookies(): + """读取配置的 ascii2d cookie 文件,未配置或不存在返回 None""" + if not ASCII2D_COOKIES_FILE or not os.path.isfile(ASCII2D_COOKIES_FILE): + return None + return _parse_netscape_cookies(ASCII2D_COOKIES_FILE) + + +def _save_netscape_cookies(cookies: list[dict], file_path: str): + """把浏览器回传的 cookies 写回 Netscape 格式文件(实现 cf_clearance 自愈)""" + lines = ["# Netscape HTTP Cookie File"] + for c in cookies: + domain = c.get("domain", "") + include_subdomains = "TRUE" if domain.startswith(".") else "FALSE" + path = c.get("path", "/") + secure = "TRUE" if c.get("secure") else "FALSE" + try: + expires = int(c.get("expires") or 0) + except (TypeError, ValueError): + expires = 0 + name = c.get("name", "") + value = c.get("value", "") + lines.append( + f"{domain}\t{include_subdomains}\t{path}\t{secure}\t{expires}\t{name}\t{value}" + ) + with open(file_path, "w", encoding="utf-8") as f: + f.write("\n".join(lines)) + + +async def get_html_ascii2d(url): + """获取 ascii2d 页面 HTML:配置了 cookie 文件时注入系统浏览器直过验证""" + return await get_html_content(url, cookies=_load_ascii2d_cookies()) + + +async def fetch_thumbs_playwright(urls: list[str]) -> dict: + """用系统浏览器会话批量下载缩略图(带 CF cookie,避免 Cloudflare 拦截)""" + if not urls: + return {} + result = {} + async with async_playwright() as p: + launch_kwargs = { + "headless": False, + "args": [ + "--window-position=-32000,-32000", + "--disable-blink-features=AutomationControlled", + ], + } + for path in CHROME_PATHS: + if os.path.isfile(path): + launch_kwargs["executable_path"] = path + break + context = await p.chromium.launch_persistent_context( + CHROME_PROFILE_DIR, **launch_kwargs + ) + cookies = _load_ascii2d_cookies() + if cookies: + await context.add_cookies(cookies) + try: + for u in urls: + try: + resp = await context.request.get(u, timeout=20000) + if resp.status == 200 and "image" in resp.headers.get( + "content-type", "" + ): + result[u] = await resp.body() + except Exception as e: + logger.debug(f"缩略图下载失败 {u}: {e}") + finally: + await context.close() + return result + + +async def get_html_content(url, cookies=None): + async with async_playwright() as p: + # 用系统 Chrome + 固定 profile 目录(cf_clearance 持久化,与浏览器获取 cookie 时同款 TLS 指纹) + # 不指定 UA:使用系统 Chrome 真实 UA,否则 cf_clearance(与 UA 绑定)会失效 + # headless 会被 Cloudflare 检测拒绝,用有头模式并将窗口移出屏幕避免打扰 + launch_kwargs = { + "headless": False, + "args": [ + "--window-position=-32000,-32000", + "--disable-blink-features=AutomationControlled", + ], + } + for path in CHROME_PATHS: + if os.path.isfile(path): + launch_kwargs["executable_path"] = path + break + context = await p.chromium.launch_persistent_context( + CHROME_PROFILE_DIR, **launch_kwargs + ) + await context.add_init_script( + "Object.defineProperty(navigator, 'webdriver', {get: () => undefined});" + ) + if cookies: + await context.add_cookies(cookies) + + page = context.pages[0] if context.pages else await context.new_page() + + try: + await page.goto(url, wait_until="domcontentloaded") + # 轮询等待 Cloudflare challenge 自动通过(最多约 20 秒) + passed = False + for _ in range(8): + await page.wait_for_timeout(2500) + title = await page.title() + if "Just a moment" not in title: + passed = True + break + html = etree.HTML(await page.content()) + # 浏览器可能刷新了 cf_clearance,回写文件实现自愈 + if passed and ASCII2D_COOKIES_FILE: + try: + _save_netscape_cookies( + await context.cookies(), ASCII2D_COOKIES_FILE + ) + logger.info("ascii2d cookies 已刷新回写") + except Exception as e: + logger.error(f"ascii2d cookies 回写失败: {e}") + print(f"获取到的html内容:{html}") + return html + except Exception as e: + print(f"Error fetching page: {e}") + return None + finally: + await context.close() diff --git a/hexi/plugins/nonebot_plugin_picstatus/__init__.py b/hexi/plugins/nonebot_plugin_picstatus/__init__.py new file mode 100644 index 0000000..d2a2b30 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/__init__.py @@ -0,0 +1,116 @@ +# ruff: noqa: E402 + +from nonebot import get_driver, require +from nonebot.plugin import PluginMetadata, inherit_supported_adapters + +require("nonebot_plugin_apscheduler") +require("nonebot_plugin_alconna") +require("nonebot_plugin_uninfo") +require("nonebot_plugin_localstore") + +from . import __main__ as __main__, misc_statistics as misc_statistics +from .bg_provider import bg_preloader +from .collectors import ( + enable_collectors, + load_builtin_collectors, + registered_collectors, +) +from .config import ConfigModel, config +from .templates import load_builtin_templates, loaded_templates + +# 统一配置标准:把常用、可安全热更的配置暴露给 Web 管理台 +# (路径/嵌套模型/复杂 list 字段不改,避免格式互转出错) +from hexi.config_standard import register_model_config # noqa: E402 + +register_model_config( + __name__, + config, + fields=[ + "ps_template", + "ps_command", + "ps_only_su", + "ps_need_at", + "ps_reply_target", + "ps_bg_provider", + "ps_collect_interval", + "ps_proc_len", + "ps_test_timeout", + "ps_show_current_bot_only", + "ps_ob_v11_use_get_status", + ], + types={"ps_bg_provider": "enum"}, + options={"ps_bg_provider": [ + {"value": "loli", "label": "loliapi"}, + {"value": "lolicon", "label": "lolicon"}, + {"value": "local", "label": "本地背景"}, + {"value": "none", "label": "无背景"}, + ]}, + labels={ + "ps_template": "状态卡片模板", + "ps_command": "触发指令(每行一个)", + "ps_only_su": "仅超级管理员可用", + "ps_need_at": "需要 @ 机器人", + "ps_reply_target": "回复原消息", + "ps_bg_provider": "背景来源", + "ps_collect_interval": "采集间隔(秒)", + "ps_proc_len": "进程列表长度", + "ps_test_timeout": "测速超时(秒)", + "ps_show_current_bot_only": "只显示当前 bot", + "ps_ob_v11_use_get_status": "OneBot v11 用 get_status", + }, + descriptions={ + "ps_template": "内置: default", + "ps_command": "每行一个命令,缺省为 运行状态/状态/zt/yxzt/status", + "ps_bg_provider": "loli/lolicon 在线随机图,local 本地, none 关闭", + "ps_collect_interval": "后台采集数据的时间间隔(秒)", + }, +) + + +driver = get_driver() + + +# lazy load builtin templates and collectors +@driver.on_startup +async def _(): + if config.ps_template not in loaded_templates: + load_builtin_templates() + current_template = loaded_templates.get(config.ps_template) + if current_template is None: + raise ValueError(f"Template {config.ps_template} not found") + + if (current_template.collectors is None) or any( + (x not in registered_collectors) for x in current_template.collectors + ): + load_builtin_collectors() + + collectors = ( + set(registered_collectors) + if current_template.collectors is None + else current_template.collectors + ) + await enable_collectors(*collectors) + + bg_preloader.start_preload() + + +usage = f"指令:{' / '.join(config.ps_command)}" +if config.ps_need_at: + usage += "\n注意:使用指令时需要@机器人" +if config.ps_only_su: + usage += "\n注意:仅SuperUser可以使用此指令" + +__version__ = "2.2.2" +__plugin_meta__ = PluginMetadata( + name="PicStatus", + description="以图片形式显示当前设备的运行状态", + usage=usage, + type="application", + homepage="https://github.com/lgc-NB2Dev/nonebot-plugin-picstatus", + config=ConfigModel, + supported_adapters=inherit_supported_adapters( + "nonebot_plugin_alconna", + "nonebot_plugin_uninfo", + ), + extra={"License": "MIT", "Author": "LgCookie"}, +) diff --git a/hexi/plugins/nonebot_plugin_picstatus/__main__.py b/hexi/plugins/nonebot_plugin_picstatus/__main__.py new file mode 100644 index 0000000..7ade6ad --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/__main__.py @@ -0,0 +1,81 @@ +import asyncio + +from cookit.loguru import warning_suppress +from cookit.nonebot.alconna import extract_reply_msg +from nonebot import logger, on_command +from nonebot.adapters import Bot as BaseBot, Event as BaseEvent, Message as BaseMessage +from nonebot.matcher import current_bot, current_event, current_matcher +from nonebot.params import CommandArg +from nonebot.permission import SUPERUSER +from nonebot.rule import Rule, to_me +from nonebot.typing import T_State +from nonebot_plugin_alconna.uniseg import Image, OriginalUniMsg, UniMessage, image_fetch + +from .bg_provider import BgBytesData, bg_preloader +from .collectors import collect_all +from .config import config +from .misc_statistics import bot_avatar_cache, bot_info_cache, cache_bot_avatar +from .templates import render_current_template + + +def check_empty_arg_rule(arg: BaseMessage = CommandArg()): + return not arg.extract_plain_text() + + +def trigger_rule(): + rule = Rule(check_empty_arg_rule) + if config.ps_need_at: + rule &= to_me() + return rule + + +_cmd, *_alias = config.ps_command +stat_matcher = on_command( + _cmd, + aliases=set(_alias), + rule=trigger_rule(), + permission=SUPERUSER if config.ps_only_su else None, +) + + +async def get_pic_from_msg(msg: UniMessage) -> BgBytesData | None: + msg = r if ((r := extract_reply_msg(msg)) and Image in r) else msg + if Image not in msg: + return None + img = msg[Image, 0] + data = await image_fetch( + current_event.get(), + current_bot.get(), + current_matcher.get().state, + img, + ) + if not data: + return None + return BgBytesData(data=data, mime=img.mimetype or "image") + + +@stat_matcher.handle() +async def _(bot: BaseBot, event: BaseEvent, state: T_State, msg: OriginalUniMsg): + if ( + (bot.self_id not in bot_avatar_cache) + and (info := bot_info_cache.get(bot.self_id)) + and info.avatar + ): + await cache_bot_avatar(info.avatar, bot, event, state) + + async def get_bg(): + with warning_suppress("Failed to fetch image from user message"): + if bg := await get_pic_from_msg(msg): + return bg + return await bg_preloader.get() + + try: + bg, collected = await asyncio.gather(get_bg(), collect_all()) + ret = await render_current_template(collected=collected, bg=bg) + except Exception: + logger.exception("获取运行状态图失败") + await UniMessage("获取运行状态图片失败,请检查后台输出").send( + reply_to=config.ps_reply_target, + ) + else: + await UniMessage.image(raw=ret).send(reply_to=config.ps_reply_target) diff --git a/hexi/plugins/nonebot_plugin_picstatus/bg_provider.py b/hexi/plugins/nonebot_plugin_picstatus/bg_provider.py new file mode 100644 index 0000000..714c266 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/bg_provider.py @@ -0,0 +1,411 @@ +import asyncio as aio +import mimetypes +import random +import sys +import time +from abc import ABC, abstractmethod +from collections.abc import AsyncIterable, Callable +from math import floor +from pathlib import Path +from typing import Generic, NamedTuple, ParamSpec, TypeAlias, TypedDict, TypeVar +from typing_extensions import override + +from cookit.common import race +from cookit.loguru import warning_suppress +from httpx import AsyncClient, Response +from nonebot import get_driver, logger + +from .config import BG_PRELOAD_CACHE_DIR, DEFAULT_BG_PATH, config + +if sys.version_info >= (3, 11): + from asyncio.taskgroups import TaskGroup +else: + from taskgroup import TaskGroup + + +class BgBytesData(NamedTuple): + data: bytes | None + mime: str + + +class BgFileData(NamedTuple): + path: Path | None + mime: str + + +BgData: TypeAlias = BgBytesData | BgFileData + +BGProviderType = Callable[[int], AsyncIterable[BgData]] +T = TypeVar("T") +TBP = TypeVar("TBP", bound=BGProviderType) +P = ParamSpec("P") + +DEFAULT_MIME = "application/octet-stream" + +registered_bg_providers: dict[str, BGProviderType] = {} + + +def get_bg_files() -> list["Path"]: + if not config.ps_bg_local_path.exists(): + logger.warning("Custom background path does not exist, fallback to default") + return [DEFAULT_BG_PATH] + if config.ps_bg_local_path.is_file(): + return [config.ps_bg_local_path] + + files = [x for x in config.ps_bg_local_path.glob("*") if x.is_file()] + if not files: + logger.warning("Custom background dir has no file in it, fallback to default") + return [DEFAULT_BG_PATH] + return files + + +BG_FILES = get_bg_files() + + +def refresh_bg_files(): + global BG_FILES + BG_FILES = get_bg_files() + + +def bg_provider(name: str | None = None): + def deco(func: TBP) -> TBP: + provider_name = name or func.__name__ + if provider_name in registered_bg_providers: + raise ValueError(f"Duplicate bg provider name `{provider_name}`") + registered_bg_providers[provider_name] = func + return func + + return deco + + +def iter_batch_sizes(size: int, max_size: int): + if size <= max_size: + yield size + else: + full_sizes = floor(max_size / size) + for _ in range(full_sizes): + yield max_size + if rest_count := full_sizes * max_size: + yield rest_count + + +def resp_to_bg_data(resp: Response): + return BgBytesData( + resp.content, + (resp.headers.get("Content-Type") or DEFAULT_MIME), + ) + + +class CoIterator(ABC, Generic[T]): + def __init__(self): + self.queue = aio.Queue[T | None]() + + @abstractmethod + async def run_tasks(self): ... + + async def run(self): + await self.run_tasks() + await self.queue.put(None) + + async def __aiter__(self): + async with TaskGroup() as t: + t.create_task(self.run()) + while (x := await self.queue.get()) is not None: + yield x + + +@bg_provider("loli") +class LoliBGProvider(CoIterator[BgData]): + def __init__(self, num: int): + super().__init__() + self.num = num + self.sem = aio.Semaphore(4) + + async def task_piece(self, cli: AsyncClient): + async with self.sem: + with warning_suppress("Failed to fetch image"): + x = resp_to_bg_data( + ( + await cli.get("https://www.loliapi.com/acg/pe/") + ).raise_for_status(), + ) + await self.queue.put(x) + + @override + async def run_tasks(self): + async with AsyncClient( + follow_redirects=True, + proxy=config.proxy, + timeout=config.ps_req_timeout, + ) as cli: + await aio.gather(*(self.task_piece(cli) for _ in range(self.num))) + + +class LoliconRespDataUrls(TypedDict): + original: str + + +class LoliconRespData(TypedDict): + urls: LoliconRespDataUrls + + +class LoliconResp(TypedDict): + data: list[LoliconRespData] + + +@bg_provider("lolicon") +class LoliconBGProvider(CoIterator[BgData]): + def __init__(self, num: int): + super().__init__() + self.num = num + self.sem = aio.Semaphore(4) + self.url_queue = aio.Queue[str | None]() + + async def do_fetch_urls_piece(self, num: int, cli: AsyncClient): + with warning_suppress("Failed to fetch urls"): + resp = await cli.get( + "https://api.lolicon.app/setu/v2", + params={ + "num": num, + "r18": config.ps_bg_lolicon_r18_type, + "proxy": "false", + "excludeAI": "true", + }, + ) + data: LoliconResp = resp.raise_for_status().json() + for x in data["data"]: + await self.url_queue.put(x["urls"]["original"]) + + async def fetch_urls_task_f(self): + async with AsyncClient( + follow_redirects=True, + proxy=config.proxy, + timeout=config.ps_req_timeout, + ) as cli: + for x in iter_batch_sizes(self.num, 20): + await self.do_fetch_urls_piece(x, cli) + await self.url_queue.put(None) + + async def fetch_image(self, url: str, cli: AsyncClient): + async with self.sem: + with warning_suppress("Failed to fetch image"): + bg = resp_to_bg_data((await cli.get(url)).raise_for_status()) + await self.queue.put(bg) + + @override + async def run_tasks(self): + pixiv_client = AsyncClient( + follow_redirects=True, + proxy=config.proxy, + timeout=config.ps_req_timeout, + headers={ + "User-Agent": ( + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " + "AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/119.0.0.0 " + "Safari/537.36" + ), + "Referer": "https://www.pixiv.net/", + }, + ) + async with TaskGroup() as t, pixiv_client: + t.create_task(self.fetch_urls_task_f()) + while (x := await self.url_queue.get()) is not None: + t.create_task(self.fetch_image(x, pixiv_client)) + + +@bg_provider() +async def local(num: int): + files = random.sample(BG_FILES, num) + # logger.debug(f"Chosen background `{files}`") + for x in files: + yield BgFileData( + x, + mimetypes.guess_type(x)[0] or DEFAULT_MIME, + ) + + +def create_none_bg(): + return BgBytesData(None, DEFAULT_MIME) + + +@bg_provider() +async def none(num: int): + for _ in range(num): + yield create_none_bg() + + +async def fetch_bg(num: int) -> AsyncIterable[BgData]: + if config.ps_bg_provider not in registered_bg_providers: + logger.warning( + f"Unknown background provider `{config.ps_bg_provider}`, fallback to local", + ) + async for x in local(num): + yield x + return + + # at least we should return one image (x) + # has_img = False + try: + provider = registered_bg_providers[config.ps_bg_provider] + async for x in provider(num): + # has_img = True + yield x + except Exception: + logger.exception( + "Error when getting background, fallback to get one local bg", + ) + async for x in local(1): + yield x + # else: + # if has_img: + # return + # logger.warning( + # "Background provider returned empty iterator, fallback to get one local bg", + # ) + # async for x in local(1): + # yield x + + +def cache_bg(bg: BgBytesData): + if not bg.data: + return BgFileData(None, bg.mime) + BG_PRELOAD_CACHE_DIR.mkdir(parents=True, exist_ok=True) + path = BG_PRELOAD_CACHE_DIR / f"{time.time_ns()}.{bg.mime.split('/')[-1]}" + path.write_bytes(bg.data) + return BgFileData(path, bg.mime) + + +def read_cached_bg_file(bg: BgFileData) -> BgBytesData | None: + if not bg.path: + return BgBytesData(None, bg.mime) + with warning_suppress("Failed to read cached file"): + data = bg.path.read_bytes() + if bg.path.is_relative_to(BG_PRELOAD_CACHE_DIR): + with warning_suppress("Failed to unlink cached file"): + bg.path.unlink() + return BgBytesData(data, bg.mime) + return None + + +async def get_one_fallback() -> BgBytesData: + with warning_suppress("Failed to get local bg file, fallback to none"): + async for x in local(1): + if bg := read_cached_bg_file(x): + return bg + logger.warning("Failed to read local bg file, fallback to none") + return create_none_bg() + + +class BgPreloader: + def __init__(self, preload_count: int): + # if preload_count < 1: + # raise ValueError("preload_count must be greater than or equals 1") + self.preload_count = preload_count + self.background_queue = aio.Queue[BgData]() + self.current_load_task_main: aio.Task | None = None + self.consumed_in_loading: bool = False + self.image_got_signal = aio.Event() + self.fire_tasks: set[aio.Task] = set() + + # we allow fetch_bg return less image than we require + async def preload_task( + self, + count: int, + fire: bool = False, + fire_done_signal: aio.Event | None = None, + ): + logger.debug(f"Preload task started, will preload {count} images, {fire=}") + try: + async for x in fetch_bg(count): + logger.debug("Got one image") + if self.preload_count > 0 or ( + fire_done_signal and fire_done_signal.is_set() + ): + x = cache_bg(x) if isinstance(x, BgBytesData) else x + await self.background_queue.put(x) + self.image_got_signal.set() + self.image_got_signal.clear() + except Exception: + logger.exception("Unexpected error occurred in preload task") + else: + logger.debug("Preload task finished") + + if fire: + return + if ( + self.consumed_in_loading + or self.background_queue.qsize() < self.preload_count + ): + self.consumed_in_loading = False + self.start_preload() + else: + self.current_load_task_main = None + + def start_preload(self, force: bool = False): + count = self.preload_count - self.background_queue.qsize() + if count <= 0 and not force: + logger.debug( + "Current background queue size meets preload count, skip preload", + ) + return + task = aio.create_task(self.preload_task(count)) + self.current_load_task_main = task + + def set_defer_preload(self): + if self.current_load_task_main: + logger.debug("Main preload task already running, set flag") + self.consumed_in_loading = True + else: + self.start_preload() + + async def _get_on_fire(self) -> BgBytesData: + task_done_signal = aio.Event() + fire_task = aio.create_task( + self.preload_task(1, fire=True, fire_done_signal=task_done_signal), + ) + fire_task.add_done_callback(lambda _: task_done_signal.set()) + fire_task.add_done_callback(lambda _: self.fire_tasks.discard(fire_task)) + self.fire_tasks.add(fire_task) + try: + await race( + # self.image_got_signal.wait(), # lazy to handle this racing condition now + task_done_signal.wait(), + aio.sleep(15), + ) + finally: + task_done_signal.set() + # fire_task.cancel() # should we cancel here? i'm letting it cache to queue + + if not self.background_queue.empty(): + bg = await self.background_queue.get() + self.set_defer_preload() + if (not isinstance(bg, BgFileData)) or (bg := read_cached_bg_file(bg)): + return bg + + logger.error("Unable to get an background image, falling back to local") + return await get_one_fallback() + + async def get(self) -> BgBytesData: + self.set_defer_preload() + + while not self.background_queue.empty(): + bg = await self.background_queue.get() + self.set_defer_preload() + if (not isinstance(bg, BgFileData)) or (bg := read_cached_bg_file(bg)): + return bg + + # normally all items in queue should be valid + # if they not, we should fetch + return await self._get_on_fire() + + +bg_preloader = BgPreloader(config.ps_bg_preload_count) + +driver = get_driver() + + +@driver.on_shutdown +async def _(): + for t in bg_preloader.fire_tasks: + t.cancel() diff --git a/hexi/plugins/nonebot_plugin_picstatus/collectors/__init__.py b/hexi/plugins/nonebot_plugin_picstatus/collectors/__init__.py new file mode 100644 index 0000000..71aead4 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/collectors/__init__.py @@ -0,0 +1,226 @@ +import asyncio +import importlib +import time +from abc import abstractmethod +from collections import deque +from collections.abc import Awaitable, Callable +from contextlib import suppress +from pathlib import Path +from typing import Any, Generic, TypeVar +from typing_extensions import override + +from nonebot import logger +from nonebot_plugin_apscheduler import scheduler + +from ..config import config + +T = TypeVar("T") +TI = TypeVar("TI") +TR = TypeVar("TR") +TC = TypeVar("TC", bound="Collector") +TCF = TypeVar("TCF", bound=Callable[[], Awaitable[Any]]) +R = TypeVar("R") + +Undefined = type("Undefined", (), {}) + + +class SkipCollectError(Exception): + pass + + +class Collector(Generic[TI, TR]): + @abstractmethod + async def _get(self) -> TI: ... + + @abstractmethod + async def get(self) -> TR: ... + + +class BaseNormalCollector(Collector[T, T], Generic[T]): + def __init__(self) -> None: + super().__init__() + + @override + async def get(self) -> T: + return await self._get() + + +class BaseFirstTimeCollector(Collector[T, T], Generic[T]): + def __init__(self) -> None: + super().__init__() + self._cached: T | Undefined = Undefined() + + @override + async def get(self) -> T: + if not isinstance(self._cached, Undefined): + return self._cached + data = await self._get() + self._cached = data + return data + + +class BasePeriodicCollector(Collector[T, deque[T]], Generic[T]): + def __init__(self, size: int = config.ps_default_collect_cache_size) -> None: + super().__init__() + self.data = deque(maxlen=size) + + @override + async def get(self) -> deque[T]: + return self.data + + async def collect(self): + try: + data = await self._get() + except SkipCollectError: + return + except Exception: + logger.exception("Error occurred while collecting data") + else: + self.data.append(data) + + +registered_collectors: dict[str, type[Collector]] = {} +enabled_collectors: dict[str, Collector] = {} + + +def collector(name: str): + def deco(cls: type[TC]) -> type[TC]: + if name in registered_collectors: + raise ValueError(f"Collector {name} already exists") + registered_collectors[name] = cls + logger.debug(f"Registered collector {name}") + return cls + + return deco + + +def _enable_collector(name: str): + if name not in registered_collectors: + raise ValueError(f"Collector {name} not found") + cls = registered_collectors[name] + if issubclass(cls, BasePeriodicCollector) and name in config.ps_collect_cache_size: + instance = cls(size=config.ps_collect_cache_size[name]) + else: + instance = cls() + enabled_collectors[name] = instance + + +async def enable_collectors(*names: str): + for name in names: + _enable_collector(name) + await init_first_time_collectors() + await setup_periodic_collectors_update_job() + + +def functional_collector(cls: type[Collector], name: str | None = None): + def deco(func: TCF) -> TCF: + collector_name = name or func.__name__ + if not collector_name: + raise ValueError("name must be provided") + + class Collector(cls): + async def _get(self) -> Any: + return await func() + + collector(collector_name)(Collector) + return func + + return deco + + +def normal_collector(name: str | None = None): + return functional_collector(BaseNormalCollector, name) + + +def first_time_collector(name: str | None = None): + return functional_collector(BaseFirstTimeCollector, name) + + +def periodic_collector(name: str | None = None): + return functional_collector(BasePeriodicCollector, name) + + +class BaseTimeBasedCounterCollector(Collector[R, Any], Generic[T, R]): + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.last_obj: Undefined | T = Undefined() + self.last_time: float = 0 + self.normal_delay: float = 1 + + @abstractmethod + async def _calc(self, past: T, now: T, time_passed: float) -> R: ... + + @abstractmethod + async def _get_obj(self) -> T: ... + + @override + async def _get(self) -> R: + past = self.last_obj + past_time = self.last_time + time_now = time.time() + time_passed = time_now - past_time + + self.last_time = time_now + self.last_obj = await self._get_obj() + if isinstance(past, Undefined): + raise SkipCollectError + return await self._calc(past, self.last_obj, time_passed) + + +class NormalTimeBasedCounterCollector( + BaseTimeBasedCounterCollector[T, R], + BaseNormalCollector[R], + Generic[T, R], +): + @override + async def get(self) -> R: + with suppress(SkipCollectError): + await self._get() + await asyncio.sleep(self.normal_delay) + return await self._get() + + +class PeriodicTimeBasedCounterCollector( + BaseTimeBasedCounterCollector[T, R], + BasePeriodicCollector[R], + Generic[T, R], +): ... + + +async def collect_all() -> dict[str, Any]: + async def get(name: str): + return name, await enabled_collectors[name].get() + + res = await asyncio.gather(*(get(name) for name in enabled_collectors)) + return dict(res) + + +def load_builtin_collectors(): + for module in Path(__file__).parent.iterdir(): + if not module.name.startswith("_"): + importlib.import_module(f".{module.stem}", __package__) + + +async def init_first_time_collectors(): + await asyncio.gather( + *( + x.get() + for x in enabled_collectors.values() + if isinstance(x, BaseFirstTimeCollector) + ), + ) + + +async def setup_periodic_collectors_update_job(): + collectors = [ + x for x in enabled_collectors.values() if isinstance(x, BasePeriodicCollector) + ] + if not collectors: + return + logger.debug("Setting up periodic collectors") + + @scheduler.scheduled_job("interval", seconds=config.ps_collect_interval) + async def _do(): + await asyncio.gather(*(x.collect() for x in collectors)) + + await _do() diff --git a/hexi/plugins/nonebot_plugin_picstatus/collectors/bot.py b/hexi/plugins/nonebot_plugin_picstatus/collectors/bot.py new file mode 100644 index 0000000..1535a79 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/collectors/bot.py @@ -0,0 +1,93 @@ +import asyncio +from dataclasses import dataclass +from datetime import datetime +from typing import TYPE_CHECKING + +from nonebot import get_bots, logger +from nonebot.matcher import current_bot + +from ..config import config +from ..misc_statistics import bot_connect_time, bot_info_cache, recv_num, send_num +from ..util import format_timedelta +from . import normal_collector + +if TYPE_CHECKING: + from nonebot.adapters import Bot as BaseBot + +try: + from nonebot.adapters.onebot.v11 import Bot as OBV11Bot +except ImportError: + OBV11Bot = None + + +@dataclass +class BotStatus: + self_id: str + adapter: str + nick: str + bot_connected: str + msg_rec: str + msg_sent: str + + +async def get_ob11_msg_num(bot: "BaseBot") -> tuple[int | None, int | None]: + if not (config.ps_ob_v11_use_get_status and OBV11Bot and isinstance(bot, OBV11Bot)): + return None, None + + try: + bot_stat = (await bot.get_status()).get("stat") + except Exception as e: + logger.warning( + f"Error when getting bot status: {e.__class__.__name__}: {e}", + ) + return None, None + if not bot_stat: + return None, None + + msg_rec = bot_stat.get("message_received") or bot_stat.get( + "MessageReceived", + ) + msg_sent = bot_stat.get("message_sent") or bot_stat.get("MessageSent") + return msg_rec, msg_sent + + +async def get_bot_status(bot: "BaseBot", now_time: datetime) -> BotStatus: + nick = ( + ((info := bot_info_cache[bot.self_id]).nick or info.name or info.id) + if (not config.ps_use_env_nick) and (bot.self_id in bot_info_cache) + else next(iter(config.nickname), None) + ) or "Bot" + bot_connected = ( + format_timedelta(now_time - t) + if (t := bot_connect_time.get(bot.self_id)) + else "未知" + ) + + msg_rec, msg_sent = await get_ob11_msg_num(bot) + if msg_rec is None: + msg_rec = recv_num.get(bot.self_id) + if msg_sent is None: + msg_sent = send_num.get(bot.self_id) + msg_rec = "未知" if (msg_rec is None) else str(msg_rec) + msg_sent = "未知" if (msg_sent is None) else str(msg_sent) + + return BotStatus( + self_id=bot.self_id, + adapter=bot.adapter.get_name(), + nick=nick, + bot_connected=bot_connected, + msg_rec=msg_rec, + msg_sent=msg_sent, + ) + + +@normal_collector() +async def bots() -> list[BotStatus]: + now_time = datetime.now().astimezone() + return ( + [await get_bot_status(current_bot.get(), now_time)] + if config.ps_show_current_bot_only + else await asyncio.gather( + *(get_bot_status(bot, now_time) for bot in get_bots().values()), + ) + ) diff --git a/hexi/plugins/nonebot_plugin_picstatus/collectors/cpu.py b/hexi/plugins/nonebot_plugin_picstatus/collectors/cpu.py new file mode 100644 index 0000000..7de088d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/collectors/cpu.py @@ -0,0 +1,70 @@ +import asyncio +from dataclasses import dataclass +from typing import cast + +import psutil +from cpuinfo import get_cpu_info +from nonebot import logger + +from . import first_time_collector, normal_collector, periodic_collector + + +@dataclass +class CpuFreq: + current: float | None + min: float | None # noqa: A003 + max: float | None # noqa: A003 + + +@first_time_collector() +async def cpu_brand() -> str: + try: + brand = ( + cast("str", get_cpu_info().get("brand_raw", "")) + .split("@", maxsplit=1)[0] + .strip() + ) + if brand.lower().endswith(("cpu", "processor")): + brand = brand.rsplit(maxsplit=1)[0].strip() + except Exception: + logger.exception("Error when getting CPU brand") + return "未知型号" + else: + return brand + + +@first_time_collector() +async def cpu_count_logical() -> int | None: + return psutil.cpu_count() + + +@first_time_collector() +async def cpu_count() -> int | None: + return psutil.cpu_count(logical=False) + + +async def get_cpu_percent() -> float: + """实时采样 0.5s,避免 psutil 首次调用返回 0.0""" + return await asyncio.to_thread(psutil.cpu_percent, 0.5) + + +async def get_cpu_percent_periodic() -> float: + """周期采样:两次调用之间的间隔即为采样区间,直接取瞬时差值即可""" + return psutil.cpu_percent() + + +normal_collector("cpu_percent")(get_cpu_percent) +periodic_collector("cpu_percent_periodic")(get_cpu_percent_periodic) + + +async def get_cpu_freq() -> CpuFreq: + cpu_freq = psutil.cpu_freq() + return CpuFreq( + current=getattr(cpu_freq, "current", None), + min=getattr(cpu_freq, "min", None), + max=getattr(cpu_freq, "max", None), + ) + + +normal_collector("cpu_freq")(get_cpu_freq) +periodic_collector("cpu_freq_periodic")(get_cpu_freq) diff --git a/hexi/plugins/nonebot_plugin_picstatus/collectors/disk.py b/hexi/plugins/nonebot_plugin_picstatus/collectors/disk.py new file mode 100644 index 0000000..3406786 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/collectors/disk.py @@ -0,0 +1,127 @@ +from dataclasses import dataclass +from typing import TypeAlias + +import psutil +from psutil._common import sdiskpart, sdiskio + +from ..config import config +from ..util import match_list_regexp +from . import ( + BaseTimeBasedCounterCollector, + NormalTimeBasedCounterCollector, + PeriodicTimeBasedCounterCollector, + collector, + normal_collector, + periodic_collector, +) + + +@dataclass +class DiskUsageNormal: + name: str + percent: float + used: int + total: int + + +@dataclass +class DiskUsageWithExc: + name: str + exception: str + + +DiskUsageType: TypeAlias = DiskUsageNormal | DiskUsageWithExc + + +@dataclass +class DiskIO: + name: str + read: float + write: float + + +@periodic_collector() +async def get_disk_usage() -> list[DiskUsageType]: + def get_one(disk: sdiskpart) -> DiskUsageType | None: + mountpoint = disk.mountpoint + + if match_list_regexp(config.ps_ignore_parts, mountpoint): + # logger.info(f"空间读取 分区 {mountpoint} 匹配 {regex.re.pattern},忽略") + return None + + try: + usage = psutil.disk_usage(mountpoint) + except Exception as e: + # logger.exception(f"读取 {mountpoint} 占用失败") + return ( + None + if config.ps_ignore_bad_parts + else DiskUsageWithExc(name=mountpoint, exception=str(e)) + ) + + return DiskUsageNormal( + name=mountpoint, + percent=usage.percent, + used=usage.used, + total=usage.total, + ) + + usage = [x for x in map(get_one, psutil.disk_partitions()) if x] + if config.ps_sort_parts: + usage.sort( + key=lambda x: x.percent if isinstance(x, DiskUsageNormal) else -1, + reverse=not config.ps_sort_parts_reverse, + ) + + return usage + + +normal_collector("disk_usage")(get_disk_usage) +periodic_collector("disk_usage_periodic")(get_disk_usage) + + +class BaseDiskIOCollector( + BaseTimeBasedCounterCollector[dict[str, sdiskio], list[DiskIO]], +): + async def _calc( + self, + past: dict[str, sdiskio], + now: dict[str, sdiskio], + time_passed: float, + ) -> list[DiskIO]: + def calc_one(name: str, past_it: sdiskio, now_it: sdiskio) -> DiskIO | None: + if match_list_regexp(config.ps_ignore_disk_ios, name): + # logger.info(f"IO统计 磁盘 {name} 匹配 {regex.re.pattern},忽略") + return None + + read = (now_it.read_bytes - past_it.read_bytes) / time_passed + write = (now_it.write_bytes - past_it.write_bytes) / time_passed + + if read == 0 and write == 0 and config.ps_ignore_no_io_disk: + # logger.info(f"IO统计 忽略无IO磁盘 {name}") + return None + + return DiskIO(name=name, read=read, write=write) + + res = [calc_one(name, past[name], now[name]) for name in past if name in now] + res = [x for x in res if x] + if config.ps_sort_disk_ios: + res.sort(key=lambda x: x.read + x.write, reverse=True) + return res + + async def _get_obj(self) -> dict[str, sdiskio]: + return psutil.disk_io_counters(perdisk=True) + + +@collector("disk_io") +class NormalDiskIOCollector( + BaseDiskIOCollector, + NormalTimeBasedCounterCollector[dict[str, sdiskio], list[DiskIO]], +): ... + + +@collector("disk_io_periodic") +class PeriodicDiskIOCollector( + BaseDiskIOCollector, + PeriodicTimeBasedCounterCollector[dict[str, sdiskio], list[DiskIO]], +): ... diff --git a/hexi/plugins/nonebot_plugin_picstatus/collectors/mem.py b/hexi/plugins/nonebot_plugin_picstatus/collectors/mem.py new file mode 100644 index 0000000..1c01ba2 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/collectors/mem.py @@ -0,0 +1,30 @@ +from dataclasses import dataclass + +import psutil + +from . import normal_collector, periodic_collector + + +@dataclass +class MemoryStat: + percent: float + used: int + total: int + + +async def get_memory_stat() -> MemoryStat: + mem = psutil.virtual_memory() + return MemoryStat(percent=mem.percent, used=mem.used, total=mem.total) + + +normal_collector("memory_stat")(get_memory_stat) +periodic_collector("memory_stat_periodic")(get_memory_stat) + + +async def get_swap_stat() -> MemoryStat: + swap = psutil.swap_memory() + return MemoryStat(percent=swap.percent, used=swap.used, total=swap.total) + + +normal_collector("swap_stat")(get_swap_stat) +periodic_collector("swap_stat_periodic")(get_swap_stat) diff --git a/hexi/plugins/nonebot_plugin_picstatus/collectors/misc.py b/hexi/plugins/nonebot_plugin_picstatus/collectors/misc.py new file mode 100644 index 0000000..21c0ac6 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/collectors/misc.py @@ -0,0 +1,130 @@ +import os +import platform +import time +from datetime import datetime +from pathlib import Path + +import nonebot +import psutil + +from ..misc_statistics import nonebot_run_time +from ..util import format_time_delta_ps +from . import first_time_collector, normal_collector, periodic_collector + + +def parse_env(env: str) -> dict[str, str | None]: + env_lines = env.strip().splitlines() + env_dict: dict[str, str | None] = {} + + for line in env_lines: + if "=" not in line: + env_dict[line.upper()] = None + continue + + key, value = line.split("=", 1) + env_dict[key.upper()] = value.strip("\"'").strip() + + return env_dict + + +def parse_env_file(env_file: str | Path) -> dict[str, str | None] | None: + if not isinstance(env_file, Path): + env_file = Path(env_file) + if not env_file.exists(): + return None + content = env_file.read_text(encoding="u8") + return parse_env(content) + + +# Thanks to https://github.com/nonedesktop/nonebot-plugin-guestool/blob/main/nonebot_plugin_guestool/info.py +def get_linux_name_version() -> tuple[str, str] | None: + env = parse_env_file("/etc/os-release") + if env and (name := env.get("NAME")) and (version_id := env.get("VERSION_ID")): + return name, version_id + + env = parse_env_file("/etc/lsb-release") + if ( + env + and (name := env.get("DISTRIB_ID")) + and (version_id := env.get("DISTRIB_RELEASE")) + ): + return name, version_id + + return None + + +@normal_collector("nonebot_run_time") +async def nonebot_run_time_str() -> str: + now_time = datetime.now().astimezone() + return ( + format_time_delta_ps(now_time - nonebot_run_time) + if nonebot_run_time + else "未知" + ) + + +@normal_collector() +async def system_run_time() -> str: + now_time = datetime.now().astimezone() + return format_time_delta_ps( + now_time - datetime.fromtimestamp(psutil.boot_time()).astimezone(), + ) + + +@first_time_collector() +async def nonebot_version() -> str: + return nonebot.__version__ + + +@first_time_collector() +async def ps_version() -> str: + from .. import __version__ + + return __version__ + + +async def get_time_str() -> str: + return time.strftime("%Y-%m-%d %H:%M:%S") + + +normal_collector("time")(get_time_str) +periodic_collector("time_periodic")(get_time_str) + + +@first_time_collector() +async def python_version() -> str: + return f"{platform.python_implementation()} {platform.python_version()}" + + +@first_time_collector() +async def system_name(): + system, _, release, version, machine, _ = platform.uname() + system, release, version = platform.system_alias(system, release, version) + + if system == "Java": + _, _, _, (system, release, machine) = platform.java_ver() + + if system == "Darwin": + return f"MacOS {platform.mac_ver()[0]} {machine}" + + if system == "Windows": + return f"Windows {release} {platform.win32_edition()} {machine}" + + if system == "Linux": + if (pfx := os.getenv("PREFIX")) and "termux" in pfx: + system = f"Termux (Android) {release}" # a strange platform + + elif os.getenv("ANDROID_ROOT") == "/system": + system = f"Linux (Android) {release}" + + elif ver := get_linux_name_version(): + name, version_id = ver + version = release if version_id.lower() == "rolling" else version_id + system = f"{name} {version}" + + else: + system = f"未知 Linux {release}" + + return f"{system} {machine}" + + return f"{system} {release}" diff --git a/hexi/plugins/nonebot_plugin_picstatus/collectors/network.py b/hexi/plugins/nonebot_plugin_picstatus/collectors/network.py new file mode 100644 index 0000000..2f1e8d1 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/collectors/network.py @@ -0,0 +1,124 @@ +import asyncio +import time +from dataclasses import dataclass +from typing import TypeAlias + +import psutil +from httpx import AsyncClient, ReadTimeout +from psutil._common import snetio + +from ..config import TestSiteCfg, config +from ..util import match_list_regexp +from . import ( + BaseTimeBasedCounterCollector, + NormalTimeBasedCounterCollector, + PeriodicTimeBasedCounterCollector, + collector, + normal_collector, +) + + +@dataclass +class NetworkIO: + name: str + sent: float + recv: float + + +@dataclass +class NetworkConnectionOK: + name: str + status: int + reason: str + delay: float + + +@dataclass +class NetworkConnectionError: + name: str + error: str + + +NetworkConnectionType: TypeAlias = NetworkConnectionOK | NetworkConnectionError + + +class BaseNetworkIOCollector( + BaseTimeBasedCounterCollector[dict[str, snetio], list[NetworkIO]], +): + async def _calc( + self, + past: dict[str, snetio], + now: dict[str, snetio], + time_passed: float, + ) -> list[NetworkIO]: + def calc_one(name: str, past_it: snetio, now_it: snetio) -> NetworkIO | None: + if match_list_regexp(config.ps_ignore_nets, name): + # logger.info(f"网卡IO统计 {name} 匹配 {regex.re.pattern},忽略") + return None + + sent = (now_it.bytes_sent - past_it.bytes_sent) / time_passed + recv = (now_it.bytes_recv - past_it.bytes_recv) / time_passed + + if sent == 0 and recv == 0 and config.ps_ignore_0b_net: + # logger.info(f"网卡IO统计 忽略无IO网卡 {name}") + return None + + return NetworkIO(name=name, sent=sent, recv=recv) + + res = [calc_one(name, past[name], now[name]) for name in past if name in now] + res = [x for x in res if x] + if config.ps_sort_nets: + res.sort(key=lambda x: x.sent + x.recv, reverse=True) + return res + + async def _get_obj(self) -> dict[str, snetio]: + return psutil.net_io_counters(pernic=True) + + +@collector("network_io") +class NormalDiskIOCollector( + BaseNetworkIOCollector, + NormalTimeBasedCounterCollector[dict[str, snetio], list[NetworkIO]], +): ... + + +@collector("network_io_periodic") +class PeriodicDiskIOCollector( + BaseNetworkIOCollector, + PeriodicTimeBasedCounterCollector[dict[str, snetio], list[NetworkIO]], +): ... + + +@normal_collector() +async def network_connection() -> list[NetworkConnectionType]: + def format_conn_error(error: Exception) -> str: + if isinstance(error, ReadTimeout): + return "超时" + return error.__class__.__name__ + + async def test_one(site: TestSiteCfg) -> NetworkConnectionType: + try: + async with AsyncClient( + timeout=config.ps_test_timeout, + proxy=config.proxy if site.use_proxy else None, + follow_redirects=True, + ) as client: + start = time.time() + resp = await client.get(str(site.url)) + delay = (time.time() - start) * 1000 + + except Exception as e: + return NetworkConnectionError(name=site.name, error=format_conn_error(e)) + + return NetworkConnectionOK( + name=site.name, + status=resp.status_code, + reason=resp.reason_phrase, + delay=delay, + ) + + res = await asyncio.gather(*map(test_one, config.ps_test_sites)) + if config.ps_sort_sites: + res.sort(key=lambda x: x.delay if isinstance(x, NetworkConnectionOK) else -1) + + return res diff --git a/hexi/plugins/nonebot_plugin_picstatus/collectors/process.py b/hexi/plugins/nonebot_plugin_picstatus/collectors/process.py new file mode 100644 index 0000000..48ecb50 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/collectors/process.py @@ -0,0 +1,61 @@ +import asyncio +from dataclasses import dataclass +from typing import cast + +import psutil + +from ..config import config +from ..util import match_list_regexp +from . import normal_collector, periodic_collector + + +@dataclass +class ProcessStatus: + name: str + cpu: float + mem: int + + +async def get_process_status() -> list[ProcessStatus]: + if not config.ps_proc_len: + return [] + + async def parse_one(proc: psutil.Process) -> ProcessStatus | None: + name = proc.name() + if match_list_regexp(config.ps_ignore_procs, name): + # logger.info(f"进程 {name} 匹配 {regex.re.pattern},忽略") + return None + + # proc.cpu_percent() + # await asyncio.sleep(1) + cpu_count = psutil.cpu_count() + with proc.oneshot(): + cpu = proc.cpu_percent() + cpu = ( + (cpu / cpu_count) if config.ps_proc_cpu_max_100p and cpu_count else cpu + ) + mem: int = proc.memory_info().rss + + return ProcessStatus(name=name, cpu=cpu, mem=mem) + + def sorter(x: ProcessStatus): + sort_by = config.ps_proc_sort_by + if sort_by == "mem": + return x.mem + # if sort_by == "cpu": + return x.cpu + + proc_list = cast( + "list[ProcessStatus | None | Exception]", + await asyncio.gather( + *(parse_one(proc) for proc in psutil.process_iter()), + return_exceptions=True, + ), + ) + proc_list = [x for x in proc_list if x and (not isinstance(x, Exception))] + proc_list.sort(key=sorter, reverse=True) + return proc_list[: config.ps_proc_len] + + +normal_collector("process_status")(get_process_status) +periodic_collector("process_status_periodic")(get_process_status) diff --git a/hexi/plugins/nonebot_plugin_picstatus/config.py b/hexi/plugins/nonebot_plugin_picstatus/config.py new file mode 100644 index 0000000..4069b2d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/config.py @@ -0,0 +1,118 @@ +import shutil +from pathlib import Path +from typing import Literal + +from cookit.nonebot.localstore import ensure_localstore_path_config +from nonebot import get_plugin_config +from nonebot.compat import type_validate_python +from nonebot_plugin_localstore import get_plugin_cache_dir +from pydantic import AnyHttpUrl, BaseModel, Field + +ensure_localstore_path_config() + +CACHE_DIR = get_plugin_cache_dir() + +BG_PRELOAD_CACHE_DIR = CACHE_DIR / "bg_preload" +if BG_PRELOAD_CACHE_DIR.exists(): + shutil.rmtree(BG_PRELOAD_CACHE_DIR) +BG_PRELOAD_CACHE_DIR.mkdir(parents=True, exist_ok=True) + +RES_PATH = Path(__file__).parent / "res" +ASSETS_PATH = RES_PATH / "assets" +TEMPLATE_PATH = RES_PATH / "templates" +DEFAULT_BG_PATH = ASSETS_PATH / "default_bg.webp" +DEFAULT_AVATAR_PATH = ASSETS_PATH / "default_avatar.webp" + +ProcSortByType = Literal["cpu", "mem"] + + +class TestSiteCfg(BaseModel): + name: str + url: AnyHttpUrl + use_proxy: bool = False + + +class ConfigModel(BaseModel): + # region builtin + superusers: set[str] + nickname: set[str] + # endregion + + # region global + proxy: str | None = None + # endregion + + # region behavior + ps_template: str = "default" + ps_command: list[str] = ["运行状态", "状态", "zt", "yxzt", "status"] + ps_only_su: bool = False + ps_need_at: bool = False + ps_reply_target: bool = True + ps_req_timeout: int | None = 10 + # endregion + + # region style + ps_bg_provider: str = "loli" + ps_bg_preload_count: int = 2 + ps_bg_lolicon_r18_type: Literal[0, 1, 2] = 0 + ps_bg_local_path: Path = DEFAULT_BG_PATH + ps_default_avatar: Path = DEFAULT_AVATAR_PATH + # endregion + + # region collectors + # region base + ps_collect_interval: int = 5 + ps_default_collect_cache_size: int = 1 + ps_collect_cache_size: dict[str, int] = Field(default_factory=dict) + # endregion + + # region header + ps_use_env_nick: bool = False + ps_show_current_bot_only: bool = False + ps_ob_v11_use_get_status: bool = True + ps_count_message_sent_event: bool | set[str] = False + ps_disconnect_reset_counter: bool = True + # endregion + + # region disk + # usage + ps_ignore_parts: list[str] = [] + ps_ignore_bad_parts: bool = False + ps_sort_parts: bool = True + ps_sort_parts_reverse: bool = False + # io + ps_ignore_disk_ios: list[str] = [r"^(loop|zram)\d*$"] + ps_ignore_no_io_disk: bool = False + ps_sort_disk_ios: bool = True + # endregion + + # region network + # io + ps_ignore_nets: list[str] = [r"^lo(op)?\d*$|^(Loopback|本地连接)"] + ps_ignore_0b_net: bool = False + ps_sort_nets: bool = True + # connection_test + ps_test_sites: list[TestSiteCfg] = [ # v1 compat #59 + type_validate_python( + TestSiteCfg, + {"name": "百度", "url": "https://www.baidu.com/"}, + ), + type_validate_python( + TestSiteCfg, + {"name": "Google", "url": "https://www.google.com/", "use_proxy": True}, + ), + ] + ps_sort_sites: bool = True + ps_test_timeout: int = 5 + # endregion + + # region process + ps_proc_len: int = 5 + ps_ignore_procs: list[str] = ["^System Idle Process$"] + ps_proc_sort_by: ProcSortByType = "cpu" + ps_proc_cpu_max_100p: bool = False + # endregion + # endregion components + + +config: ConfigModel = get_plugin_config(ConfigModel) diff --git a/hexi/plugins/nonebot_plugin_picstatus/misc_statistics.py b/hexi/plugins/nonebot_plugin_picstatus/misc_statistics.py new file mode 100644 index 0000000..7f6cb13 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/misc_statistics.py @@ -0,0 +1,153 @@ +from collections.abc import Callable +from datetime import datetime +from typing import Any + +from cookit.loguru import log_exception_warning +from nonebot import get_driver, logger +from nonebot.adapters import Bot as BaseBot, Event as BaseEvent +from nonebot.message import event_preprocessor +from nonebot.typing import T_State +from nonebot_plugin_alconna import image_fetch +from nonebot_plugin_alconna.uniseg import Image +from nonebot_plugin_uninfo import User, get_interface + +from .config import config + +nonebot_run_time: datetime = datetime.now().astimezone() +bot_connect_time: dict[str, datetime] = {} +recv_num: dict[str, int] = {} +send_num: dict[str, int] = {} + +bot_info_cache: dict[str, User] = {} +bot_avatar_cache: dict[str, bytes | None] = {} + +driver = get_driver() + +SEND_APIS: dict[str, list[str] | Callable[[str], bool]] = { + # "BilibiliLive": [], # 狗东西发消息不走 call_api + "Console": ["send_msg"], + "Ding": ["send"], + "Discord": ["create_message"], + "Feishu": ["im/v1/messages"], + "Kaiheila": ["message_create", "directMessage_create"], + "Minecraft": ["send_msg"], + "mirai2": ["send_friend_message", "send_group_message", "send_temp_message"], + "ntchat": lambda x: x.startswith("send_"), + "OneBot V11": ["send_private_msg", "send_group_msg", "send_msg"], + "OneBot V12": ["send_message"], + "QQ": [ + "post_dms_messages", + "post_messages", + "post_c2c_messages", + "post_c2c_files", + "post_group_messages", + "post_group_files", + ], + "RedProtocol": ["send_message", "send_fake_forward"], + "Satori": ["message_create"], + "Telegram": lambda x: x.startswith("send_"), + "大别野": ["send_message"], +} + + +def method_is_send_msg(platform: str, name: str) -> bool: + return (platform in SEND_APIS) and ( + (name in it) if isinstance((it := SEND_APIS[platform]), list) else it(name) + ) + + +if config.ps_count_message_sent_event: + + @event_preprocessor + async def _(bot: BaseBot, event: BaseEvent): + if ( + config.ps_count_message_sent_event + and ( + (config.ps_count_message_sent_event is True) + or bot.adapter.get_name() in config.ps_count_message_sent_event + ) + and ( + (event.get_type() == "message_sent") + or ( + event.get_type() == "message" and event.get_user_id() == bot.self_id + ) + ) + ): + # logger.debug(f"Bot {bot.self_id} sent counter +1") + send_num[bot.self_id] += 1 + + +if config.ps_count_message_sent_event is not True: + + @BaseBot.on_called_api + async def called_api( + bot: BaseBot, + exc: Exception | None, + api: str, + _: dict[str, Any], + __: Any, + ): + if ( + (not exc) + and (config.ps_count_message_sent_event is not True) + and ( + (config.ps_count_message_sent_event is False) + or (bot.adapter.get_name() not in config.ps_count_message_sent_event) + ) + and method_is_send_msg(bot.adapter.get_name(), api) + ): + # logger.debug(f"Bot {bot.self_id} sent counter +1") + send_num[bot.self_id] += 1 + + +async def cache_bot_avatar(avatar: str, bot: BaseBot, event: BaseEvent, state: T_State): + try: + img = await image_fetch(event, bot, state, Image(url=avatar)) + except Exception as e: + log_exception_warning(e, f"Failed to get avatar of bot {bot.self_id}") + return None + else: + if not img: + logger.warning( + f"Cannot get avatar of bot {bot.self_id}" + f" because image_fetch returned None", + ) + bot_avatar_cache[bot.self_id] = img + return img + + +async def cache_bot_info(bot: BaseBot): + try: + it = get_interface(bot) + info = (await it.get_user(bot.self_id)) if it else None + except Exception as e: + logger.warning(f"Error when getting bot info: {e.__class__.__name__}: {e}") + else: + if info: + bot_info_cache[bot.self_id] = info + return info + return None + + +@driver.on_bot_connect +async def _(bot: BaseBot): + bot_connect_time[bot.self_id] = datetime.now().astimezone() + if bot.self_id not in recv_num: + recv_num[bot.self_id] = 0 + if (bot.self_id not in send_num) and (bot.adapter.get_name() in SEND_APIS): + send_num[bot.self_id] = 0 + await cache_bot_info(bot) + + +@driver.on_bot_disconnect +async def _(bot: BaseBot): + bot_connect_time.pop(bot.self_id, None) + if config.ps_disconnect_reset_counter: + recv_num.pop(bot.self_id, None) + send_num.pop(bot.self_id, None) + + +@event_preprocessor +async def _(bot: BaseBot, event: BaseEvent): + if event.get_type() == "message": + recv_num[bot.self_id] += 1 diff --git a/hexi/plugins/nonebot_plugin_picstatus/res/assets/default_avatar.webp b/hexi/plugins/nonebot_plugin_picstatus/res/assets/default_avatar.webp new file mode 100644 index 0000000..00419fc Binary files /dev/null and b/hexi/plugins/nonebot_plugin_picstatus/res/assets/default_avatar.webp differ diff --git a/hexi/plugins/nonebot_plugin_picstatus/res/assets/default_bg.webp b/hexi/plugins/nonebot_plugin_picstatus/res/assets/default_bg.webp new file mode 100644 index 0000000..6ac7eeb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_picstatus/res/assets/default_bg.webp differ diff --git a/hexi/plugins/nonebot_plugin_picstatus/res/js/globalThis.d.ts b/hexi/plugins/nonebot_plugin_picstatus/res/js/globalThis.d.ts new file mode 100644 index 0000000..1452a19 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/res/js/globalThis.d.ts @@ -0,0 +1,3 @@ +declare module globalThis { + var plugins: (() => Promise)[]; +} diff --git a/hexi/plugins/nonebot_plugin_picstatus/res/js/init-global.js b/hexi/plugins/nonebot_plugin_picstatus/res/js/init-global.js new file mode 100644 index 0000000..baa7b7c --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/res/js/init-global.js @@ -0,0 +1 @@ +globalThis.plugins = []; diff --git a/hexi/plugins/nonebot_plugin_picstatus/res/js/lazy-load.js b/hexi/plugins/nonebot_plugin_picstatus/res/js/lazy-load.js new file mode 100644 index 0000000..28a3f90 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/res/js/lazy-load.js @@ -0,0 +1,77 @@ +/// +(() => { + /** + * @template {any[]} A + * @template R + * @param {(...args: A) => Promise} func + * @returns {(...args: A) => Promise} + */ + function wrapErr(func) { + return async (...args) => { + try { + return await func(...args); + } catch (e) { + console.error(e); + } + }; + } + + /** + * @param {string} url + */ + async function makeObjUrlFromUrl(url) { + const res = await fetch(url); + const blob = await res.blob(); + return URL.createObjectURL(blob); + } + + /** @typedef {(elem: HTMLElement, objUrl: string) => Promise} PropSetterType */ + + /** @type {Record} */ + const propSetterMap = { + 'data-background-image': async (elem, objUrl) => { + elem.style.backgroundImage = `url(${objUrl})`; + }, + 'data-src': async (elem, objUrl) => { + if (elem instanceof HTMLImageElement) elem.src = objUrl; + }, + }; + + /** + * @param {HTMLElement} elem + * @param {string} attr + * @param {PropSetterType} setter + */ + async function lazyLoadOne(elem, attr, setter) { + const url = elem.getAttribute(attr); + if (!url) return; + const objUrl = await makeObjUrlFromUrl(url); + await setter(elem, objUrl); + elem.removeAttribute(attr); + } + + /** + * @param {string} attr + */ + async function lazyLoad(attr) { + /** @type {HTMLElement[]} */ + // @ts-ignore + const elements = [...document.body.querySelectorAll(`[${attr}]`)].filter( + (v) => v instanceof HTMLElement + ); + const tasks = elements.map((v) => + wrapErr(lazyLoadOne)(v, attr, propSetterMap[attr]) + ); + await Promise.all(tasks); + } + + async function lazyLoadAll() { + await Promise.all(Object.keys(propSetterMap).map(lazyLoad)); + } + + // 使用 globalThis.plugins.push 注册插件 + // 只有这样才能保证你的插件运行完成之后才会网页截图 + globalThis.plugins.push(async () => { + await lazyLoadAll(); + }); +})(); diff --git a/hexi/plugins/nonebot_plugin_picstatus/res/js/load-plugin.js b/hexi/plugins/nonebot_plugin_picstatus/res/js/load-plugin.js new file mode 100644 index 0000000..20e31e8 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/res/js/load-plugin.js @@ -0,0 +1,10 @@ +(async () => { + for (const plugin of globalThis.plugins) { + try { + await plugin(); + } catch (e) { + console.error(e); + } + } + document.body.classList.add('done'); +})(); diff --git a/hexi/plugins/nonebot_plugin_picstatus/templates/__init__.py b/hexi/plugins/nonebot_plugin_picstatus/templates/__init__.py new file mode 100644 index 0000000..1eb8951 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/templates/__init__.py @@ -0,0 +1,65 @@ +import importlib +from collections.abc import Awaitable +from dataclasses import dataclass +from pathlib import Path +from typing import TYPE_CHECKING, Any, TypedDict +from typing_extensions import Protocol, Unpack + +from nonebot import logger + +from ..config import config + +if TYPE_CHECKING: + from ..bg_provider import BgBytesData + + +class TemplateRendererKwargs(TypedDict): + collected: dict[str, Any] + bg: "BgBytesData" + + +class TemplateRenderer(Protocol): + __name__: str + + def __call__( + self, + **kwargs: Unpack[TemplateRendererKwargs], + ) -> Awaitable[bytes]: ... + + +@dataclass() +class TemplateInfo: + renderer: TemplateRenderer + collectors: set[str] | None = None + + +loaded_templates: dict[str, TemplateInfo] = {} + + +def pic_template( + name: str | None = None, + collecting: set[str] | None = None, +): + def deco(func: TemplateRenderer): + template_name = name or func.__name__ + if template_name in loaded_templates: + raise ValueError(f"Template {template_name} already exists") + loaded_templates[template_name] = TemplateInfo( + renderer=func, + collectors=collecting, + ) + logger.debug(f"Registered template {template_name}") + + return deco + + +def load_builtin_templates(): + for module in Path(__file__).parent.iterdir(): + name = module.name + if (not module.is_dir()) or name.startswith("_"): + continue + assert importlib.import_module(f".{name}", __package__) + + +async def render_current_template(**kwargs: Unpack[TemplateRendererKwargs]): + return await loaded_templates[config.ps_template].renderer(**kwargs) diff --git a/hexi/plugins/nonebot_plugin_picstatus/templates/default/__init__.py b/hexi/plugins/nonebot_plugin_picstatus/templates/default/__init__.py new file mode 100644 index 0000000..f715c9b --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/templates/default/__init__.py @@ -0,0 +1,140 @@ +from collections import deque +from pathlib import Path +from typing import TYPE_CHECKING, Any, Literal + +import jinja2 +from cookit import flatten +from cookit.pyd import field_validator +from nonebot import get_plugin_config, require +from pydantic import BaseModel + +from ...util import debug +from .. import pic_template +from ..pw_render import ( + ROUTE_URL, + add_background_router, + add_root_router, + base_router_group, + make_file_router, + register_global_filter_to, + resolve_file_url, +) + +require("nonebot_plugin_htmlrender") + +from nonebot_plugin_htmlrender import get_new_page # noqa: E402 + +if TYPE_CHECKING: + from ...bg_provider import BgBytesData + +RES_PATH = Path(__file__).parent / "res" +TEMPLATE_PATH = RES_PATH / "templates" +CSS_PATH = RES_PATH / "css" +ENVIRONMENT = jinja2.Environment( + loader=jinja2.FileSystemLoader(str(TEMPLATE_PATH)), + autoescape=jinja2.select_autoescape(["html", "xml"]), + enable_async=True, +) +register_global_filter_to(ENVIRONMENT) + +template_router_group = base_router_group.copy() +template_router_group.router(f"{ROUTE_URL}/default/res/**/*", priority=99)( + make_file_router(query_name=None, base_path=RES_PATH, prefix_omit="default/res/"), +) + +COMPONENT_COLLECTORS = { + "header": {"bots", "nonebot_run_time", "system_run_time"}, + "cpu_mem": { + "cpu_percent", + "cpu_count", + "cpu_count_logical", + "cpu_freq", + "cpu_brand", + "memory_stat", + "swap_stat", + }, + "disk": {"disk_usage", "disk_io"}, + "network": {"network_io", "network_connection"}, + "process": {"process_status"}, + "footer": { + "nonebot_version", + "ps_version", + "time", + "python_version", + "system_name", + }, +} +PERIODIC_COLLECTORS_MAP = { + "cpu_percent": "cpu_percent_periodic", + "cpu_freq": "cpu_freq_periodic", + "disk_usage": "disk_usage_periodic", + "disk_io": "disk_io_periodic", + "memory_stat": "memory_stat_periodic", + "swap_stat": "swap_stat_periodic", + "time": "time_periodic", + "network_io": "network_io_periodic", + "process_status": "process_status_periodic", +} +PERIODIC_COLLECTORS_MAP_REVERSE = {v: k for k, v in PERIODIC_COLLECTORS_MAP.items()} + + +class TemplateConfig(BaseModel): + ps_default_components: list[str] = [ + "header", + "cpu_mem", + "disk", + "network", + "process", + "footer", + ] + ps_default_additional_css: list[str] = [] + ps_default_additional_script: list[str] = [] + ps_default_pic_format: Literal["jpeg", "png"] = "jpeg" + ps_default_use_periodic: bool = True + + @field_validator("ps_default_additional_css") + def resolve_css_url(cls, v: list[str]): # noqa: N805 + return [resolve_file_url(x, {"default/res/css": CSS_PATH}) for x in v] + + @field_validator("ps_default_additional_script") + def resolve_script_url(cls, v: list[str]): # noqa: N805 + return [resolve_file_url(x) for x in v] + + +template_config = get_plugin_config(TemplateConfig) +collecting = set( + flatten(COMPONENT_COLLECTORS[k] for k in template_config.ps_default_components), +) +if template_config.ps_default_use_periodic: + collecting = {(PERIODIC_COLLECTORS_MAP.get(x) or x) for x in collecting} + + +@pic_template(collecting=collecting) +async def default(collected: dict[str, Any], bg: "BgBytesData", **_) -> bytes: + for k, v in collected.copy().items(): + if ( + template_config.ps_default_use_periodic + and k in PERIODIC_COLLECTORS_MAP_REVERSE + ): + del collected[k] + k = PERIODIC_COLLECTORS_MAP_REVERSE[k] + if isinstance(v, deque): + collected[k] = v[-1] if v else None + + template = ENVIRONMENT.get_template("index.html.jinja") + html = await template.render_async(d=collected, config=template_config) + + if debug.enabled: + debug.write(html, "default_{time}.html") + + router_group = template_router_group.copy() + add_root_router(router_group, html) + add_background_router(router_group, bg) + + async with get_new_page() as page: + await router_group.apply(page) + await page.goto(f"{ROUTE_URL}/") + await page.wait_for_selector("body.done") + elem = await page.query_selector(".main-background") + assert elem + return await elem.screenshot(type="jpeg") diff --git a/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/index.css b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/index.css new file mode 100644 index 0000000..030dfc5 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/index.css @@ -0,0 +1,369 @@ +/* Base */ + +* { + --font-family: 'HarmonyOS Sans SC', 'Source Han Sans SC', 'Source Han Sans', + sans-serif; + --monospace-font-family: 'JetBrains Mono', 'Cascadia Code', 'Consolas', + monospace; + + --primary-text-color: #3a3a3a; + --secondary-text-color: #6a6a6a; + + --default-background: #3a3a3aaa; + --background-mask-color: #fafafa66; + --card-background-color: #fafafaaa; + --default-box-shadow: 2px 2px 6px #6a6a6a66; + + --label-red-text-color: var(--secondary-text-color); + --label-orange-text-color: var(--secondary-text-color); + --label-yellow-text-color: var(--secondary-text-color); + --label-green-text-color: var(--secondary-text-color); + --label-cyan-text-color: var(--secondary-text-color); + --label-blue-text-color: var(--secondary-text-color); + --label-purple-text-color: var(--secondary-text-color); + --label-gray-text-color: var(--secondary-text-color); + --label-black-text-color: #fafafa; + + --background-color: var(--card-background-color); + --label-red-bg-color: #e05661aa; + --label-orange-bg-color: #ee9025aa; + --label-yellow-bg-color: #eea825aa; + --label-green-bg-color: #1da912aa; + --label-cyan-bg-color: #56b6c2aa; + --label-blue-bg-color: #118dc3aa; + --label-purple-bg-color: #9a77cfaa; + --label-gray-bg-color: #bebebeaa; + --label-black-bg-color: #3a3a3aaa; + + --prog-low-text-color: var(--secondary-text-color); + --prog-medium-text-color: var(--secondary-text-color); + --prog-high-text-color: var(--secondary-text-color); + --prog-low-bg-color: var(--label-green-bg-color); + --prog-medium-bg-color: var(--label-orange-bg-color); + --prog-high-bg-color: var(--label-red-bg-color); + + --segment-color: #bebebe; +} + +.red { + --background-color: var(--label-red-bg-color); + --secondary-text-color: var(--label-red-text-color); +} + +.orange { + --background-color: var(--label-orange-bg-color); + --secondary-text-color: var(--label-orange-text-color); +} + +.yellow { + --background-color: var(--label-yellow-bg-color); + --secondary-text-color: var(--label-yellow-text-color); +} + +.green { + --background-color: var(--label-green-bg-color); + --secondary-text-color: var(--label-green-text-color); +} + +.cyan { + --background-color: var(--label-cyan-bg-color); + --secondary-text-color: var(--label-cyan-text-color); +} + +.blue { + --background-color: var(--label-blue-bg-color); + --secondary-text-color: var(--label-blue-text-color); +} + +.purple { + --background-color: var(--label-purple-bg-color); + --secondary-text-color: var(--label-purple-text-color); +} + +.gray { + --background-color: var(--label-gray-bg-color); + --secondary-text-color: var(--label-gray-text-color); +} + +.black { + --background-color: var(--label-black-bg-color); + --secondary-text-color: var(--label-black-text-color); +} + +.prog-low { + --background-color: var(--prog-low-bg-color); + --secondary-text-color: var(--prog-low-text-color); +} + +.prog-medium { + --background-color: var(--prog-medium-bg-color); + --secondary-text-color: var(--prog-medium-text-color); +} + +.prog-high { + --background-color: var(--prog-high-bg-color); + --secondary-text-color: var(--prog-high-text-color); +} + +.monospace { + font-family: var(--monospace-font-family); +} + +body { + font-family: var(--font-family); + color: var(--primary-text-color); + font-size: 20px; +} + +.main-background { + width: 650px; + background: var(--default-background); + background-repeat: no-repeat; + background-position: center; + background-size: cover; +} + +.main-background-mask { + padding: 16px; + background-color: var(--background-mask-color); +} + +.main { + display: grid; + grid-template-columns: 1fr; + gap: 16px; +} + +.card { + border-radius: 8px; + padding: 16px; + background: var(--card-background-color); + box-shadow: var(--default-box-shadow); + backdrop-filter: blur(2px); + overflow: hidden; +} + +.splitter > *:not(:first-child) { + margin-top: 8px; + padding-top: 8px; + border-top: 2px solid var(--segment-color); +} + +.align-right { + text-align: right; +} + +/* Span Label */ + +span.label { + padding: 2px 4px; + border-radius: 4px; + box-shadow: var(--default-box-shadow); + background-color: var(--background-color); + color: var(--secondary-text-color); +} + +.label-container { + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; +} + +.label-container > * { + margin-right: 2px; + margin-bottom: 2px; +} + +/* Account */ + +.account { + display: flex; + flex-direction: row; +} + +.account .avatar { + width: 125px; + height: 125px; + border-radius: 50%; + box-shadow: var(--default-box-shadow); + background-color: var(--card-background-color); +} + +.account .description { + margin-left: 16px; + display: flex; + flex-direction: column; + justify-content: center; +} + +.account .description .nickname { + font-size: 36px; + font-weight: bold; + margin-bottom: 8px; + word-break: break-word; + line-height: 1.1; +} + +/* Donut Chart */ + +.donut-chart { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; +} + +.donut-chart .chart-wrapper, +.donut-chart .chart, +.donut-chart .shadow { + width: 150px; + height: 150px; +} + +.donut-chart .chart-wrapper { + position: relative; +} + +.donut-chart .chart { + transform: rotate(-90deg); +} + +.donut-chart .chart .empty, +.donut-chart .chart .slice { + fill: transparent; + stroke-width: 15px; +} + +.donut-chart .chart .empty { + stroke: var(--label-gray-bg-color); +} + +.donut-chart .chart .slice { + stroke: var(--background-color); + stroke-dasharray: calc((67.5px * 2) * 3.1415926); + stroke-dashoffset: calc( + (67.5px * 2) * 3.1415926 / 360 * (360 - (360 * var(--percent))) + ); +} + +.donut-chart .shadow { + position: absolute; + top: 0; + border-radius: 50%; + box-shadow: var(--default-box-shadow); +} + +.donut-chart .label { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); +} + +.donut-chart .label, +.donut-chart .title { + font-size: 32px; + font-weight: bold; + text-wrap: nowrap; + white-space: nowrap; +} + +.donut-chart .desc { + font-size: 12px; + word-break: break-word; + color: var(--secondary-text-color); +} + +/* Progress Bar */ + +.progress-bar { + position: relative; + border-radius: 4px; + overflow: hidden; + box-shadow: var(--default-box-shadow); +} + +.progress-bar .background { + position: absolute; + width: 100%; + height: 100%; + background-color: var(--label-gray-bg-color); +} + +.progress-bar .progress { + position: absolute; + height: 100%; + background-color: var(--background-color); +} + +.progress-bar .label { + position: relative; + z-index: 1; + text-align: center; +} + +/* #### Split Line #### */ + +/* Card Header */ + +.card.header { + display: flex; + flex-direction: column; +} + +.card.header .label-container { + font-size: 16px; +} + +.card.header .extra > * { + flex-grow: 1; + text-align: center; +} + +/* Donut Chart Line */ + +.donut-chart-line { + display: grid; + gap: 8px; + grid-template-columns: repeat(3, 1fr); + align-items: start; +} + +/* List Grid */ + +.list-grid { + display: grid; + gap: 4px; + align-items: center; +} + +.list-grid.disk-usage { + grid-template-columns: auto minmax(180px, 100%) auto; +} + +.list-grid.disk-io, +.list-grid.network-io, +.list-grid.network-connection-test, +.list-grid.process-usage { + grid-template-columns: minmax(0, 100%) auto auto auto auto auto; +} + +.list-grid.network-connection-test { + grid-template-columns: minmax(0, 100%) auto auto auto; +} + +.list-grid.network-connection-test .error { + grid-column-end: span 3; + text-align: right; +} + +/* Footer */ + +.footer { + font-size: 14px; + text-align: center; + color: var(--primary-text-color); + text-shadow: var(--default-box-shadow); +} diff --git a/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/no-blur.css b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/no-blur.css new file mode 100644 index 0000000..5a2e3b0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/no-blur.css @@ -0,0 +1,3 @@ +.card { + backdrop-filter: none; +} diff --git a/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/no-radius.css b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/no-radius.css new file mode 100644 index 0000000..e2735ae --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/no-radius.css @@ -0,0 +1,5 @@ +.card, +span.label, +.progress-bar { + border-radius: 0; +} diff --git a/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/no-shadow.css b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/no-shadow.css new file mode 100644 index 0000000..8cf637a --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/no-shadow.css @@ -0,0 +1,3 @@ +* { + --default-box-shadow: none; +} diff --git a/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/theme-dark.css b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/theme-dark.css new file mode 100644 index 0000000..b4855cc --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/css/theme-dark.css @@ -0,0 +1,23 @@ +* { + --primary-text-color: #d0d6e2; + --secondary-text-color: #abb2bf; + + --default-background: #d0d6e2aa; + --background-mask-color: #282c3455; + --card-background-color: #282c3488; + --default-box-shadow: 2px 2px 6px #abb2bf66; + + --label-default-bg-color: #282c34aa; + --label-red-bg-color: #e06c75aa; + --label-orange-bg-color: #d19a66aa; + --label-yellow-bg-color: #e5c07baa; + --label-green-bg-color: #98c379aa; + --label-cyan-bg-color: #56b6c2aa; + --label-blue-bg-color: #61afefaa; + --label-purple-bg-color: #c678ddaa; + --label-gray-bg-color: #737c8caa; + --label-black-bg-color: #d0d6e2aa; + --label-black-text-color: #282c34; + + --segment-color: #5c6370; +} diff --git a/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/templates/index.html.jinja b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/templates/index.html.jinja new file mode 100644 index 0000000..5a173b1 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/templates/index.html.jinja @@ -0,0 +1,44 @@ +{% from 'macros.html.jinja' import header, cpu_mem, disk, network, process, footer %} + + + + + + + + + {% for css in config.ps_default_additional_css -%} + {% endfor %} + + + +
    +
    +
    + {% for name in config.ps_default_components %} + {% if name == "header" %} + {{ header(d) }} + {% elif name == "cpu_mem" %} + {{ cpu_mem(d) }} + {% elif name == "disk" %} + {{ disk(d) }} + {% elif name == "network" %} + {{ network(d) }} + {% elif name == "process" %} + {{ process(d) }} + {% elif name == "footer" %} + {{ footer(d) }} + {% endif %} + {% endfor %} +
    +
    +
    + + + + +{% for script in config.ps_default_additional_script -%} +{% endfor %} + + + diff --git a/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/templates/macros.html.jinja b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/templates/macros.html.jinja new file mode 100644 index 0000000..87ceb19 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/templates/default/res/templates/macros.html.jinja @@ -0,0 +1,142 @@ +{% macro donut_chart(percent, title, caption) %} +
    +
    + + + {% if percent != None %} + + {% endif %} + +
    +
    + {%- if percent == None %}未部署 + {%- else %}{{ '{0:.0f}%'.format(percent) }}{% endif -%} +
    +
    +
    {{ title }}
    +
    {{ caption | br }}
    +
    +{% endmacro %} + +{% macro header(d) %} +
    + {% for info in d.bots %} + + {% endfor %} +
    + NoneBot运行 {{ d.nonebot_run_time }} + 系统运行 {{ d.system_run_time }} +
    +
    +{% endmacro %} + +{% macro cpu_mem(d) %} +{% if d.cpu_count %}{% set count = d.cpu_count %}{% else %}{% set count = '??' %}{% endif %} +{% if d.cpu_count_logical %}{% set logical = d.cpu_count_logical %}{% else %}{% set logical = '??' %}{% endif %} +{% set freq = d.cpu_freq | format_cpu_freq %} +{% set ram_used = d.memory_stat.used | auto_convert_unit %} +{% set ram_total = d.memory_stat.total | auto_convert_unit %} +{% set swap_used = d.swap_stat.used | auto_convert_unit %} +{% set swap_total = d.swap_stat.total | auto_convert_unit %} +
    + {{ donut_chart(d.cpu_percent, "CPU", "{}核 {}线程 {}\n{}".format(count, logical, freq, d.cpu_brand)) }} + {{ donut_chart(d.memory_stat.percent, "RAM", "{} / {}").format(ram_used, ram_total) }} + {{ donut_chart(d.swap_stat.percent, "SWAP", "{} / {}").format(swap_used, swap_total) }} +
    +{% endmacro %} + +{% macro disk(d) %} +
    +
    + {% for it in d.disk_usage %} +
    {{ it.name }}
    +
    +
    + {% if it.exception %} +
    {{ it.exception }}
    + {% else %} +
    +
    {{ it.used | auto_convert_unit }} / {{ it.total | auto_convert_unit }}
    + {% endif %} +
    +
    + {%- if it.percent %}{{ '{0:.1f}%'.format(it.percent) }} + {%- else %}??.?%{% endif -%} +
    + {% endfor %} +
    + + {% if d.disk_io -%} +
    + {% for it in d.disk_io %} +
    {{ it.name }}
    +
    读
    +
    {{ it.read | auto_convert_unit(suffix='/s') }}
    +
    |
    +
    写
    +
    {{ it.write | auto_convert_unit(suffix='/s') }}
    + {% endfor %} +
    + {%- endif %} +
    +{% endmacro %} + +{% macro network(d) %} +
    +
    + {% for it in d.network_io or [] %} +
    {{ it.name }}
    +
    ↑
    +
    {{ it.sent | auto_convert_unit(suffix='/s') }}
    +
    |
    +
    ↓
    +
    {{ it.recv | auto_convert_unit(suffix='/s') }}
    + {% endfor %} +
    +
    + {% for it in d.network_connection %} +
    {{ it.name }}
    + {% if it.error %} +
    {{ it.error }}
    + {% else %} +
    {{ it.status }} {{ it.reason }}
    +
    |
    +
    {{ '{0:.2f}ms'.format(it.delay) }}
    + {% endif %} + {% endfor %} +
    +
    +{% endmacro %} + +{% macro process(d) %} +
    +
    + {% for it in d.process_status or [] %} +
    {{ it.name }}
    +
    CPU
    +
    {{ '{0:.1f}%'.format(it.cpu) }}
    +
    |
    +
    MEM
    +
    {{ it.mem | auto_convert_unit }}
    + {% endfor %} +
    +
    +{% endmacro %} + +{% macro footer(d) %} + +{% endmacro %} diff --git a/hexi/plugins/nonebot_plugin_picstatus/templates/pw_render.py b/hexi/plugins/nonebot_plugin_picstatus/templates/pw_render.py new file mode 100644 index 0000000..4ad8a36 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/templates/pw_render.py @@ -0,0 +1,142 @@ +from collections.abc import Callable +from pathlib import Path +from typing import TYPE_CHECKING, Any, TypeVar +from urllib.parse import urlencode + +from cookit import auto_convert_byte +from cookit.jinja import all_filters +from cookit.jinja.filters import cookit_global_filter +from cookit.pw import CKRouterFunc, RouterGroup, make_real_path_router +from cookit.pw.loguru import log_router_err +from nonebot import logger +from yarl import URL + +from ..config import DEFAULT_AVATAR_PATH, config +from ..misc_statistics import bot_avatar_cache +from ..util import format_cpu_freq + +if TYPE_CHECKING: + import jinja2 + from playwright.async_api import Request, Route + + from ..bg_provider import BgBytesData + +TC = TypeVar("TC", bound=Callable[..., Any]) + +ROOT_PATH = Path(__file__).parent.parent +RES_PATH = ROOT_PATH / "res" +ROUTE_URL = "http://picstatus.nonebot" +RES_LOCATION_MAP = { + "": RES_PATH, +} + +# region pw + +base_router_group = RouterGroup() + + +def resolve_file_url( + path: str, + additional_locations: dict[str, Path] | None = None, +) -> str: + if path.startswith("res:"): + path = path[4:].lstrip("/") + locations = {**RES_LOCATION_MAP, **(additional_locations or {})} + for pfx, loc in locations.items(): + if (loc / path).exists(): + return f"/{pfx}/{path}" + raise ValueError(f"Cannot resolve builtin resource `{path}`") + params = urlencode({"path": path}) + return f"/api/local_file?{params}" + + +def make_file_router( + query_name: str | None = None, + base_path: Path | None = None, + prefix_omit: str = "", +) -> CKRouterFunc: + @log_router_err() + @make_real_path_router + async def router(request: "Request", **_): + url = URL(request.url) + query_path = url.query.get(query_name, "") if query_name else url.path[1:] + if prefix_omit and query_path.startswith(prefix_omit): + query_path = query_path[len(prefix_omit) :] + path = Path((base_path / query_path) if base_path else query_path) + logger.debug(f"Associated file `{path}`") + return path + + return router + + +@base_router_group.router(f"{ROUTE_URL}/api/bot_avatar/*") +@log_router_err() +async def _(route: "Route", request: "Request", **_): + url = URL(request.url) + self_id = url.parts[-1] + + if self_id in bot_avatar_cache: + await route.fulfill(body=bot_avatar_cache[self_id]) + return + + data = ( + config.ps_default_avatar + if config.ps_default_avatar.is_file() + else DEFAULT_AVATAR_PATH + ).read_bytes() + await route.fulfill(body=data) + + +base_router_group.router(f"{ROUTE_URL}/api/local_file*")( + make_file_router(query_name="path", base_path=None), +) + +base_router_group.router(f"{ROUTE_URL}/**/*", priority=100)( + make_file_router(query_name=None, base_path=RES_PATH), +) + + +def add_root_router(router_group: RouterGroup, html: str): + @router_group.router(f"{ROUTE_URL}/") + @log_router_err() + async def _(route: "Route", **_): + await route.fulfill(content_type="text/html", body=html) + + +def add_background_router(router_group: RouterGroup, bg: "BgBytesData"): + @router_group.router(f"{ROUTE_URL}/api/background") + @log_router_err() + async def _(route: "Route", **_): + await route.fulfill(content_type=bg.mime, body=bg.data) + + +# endregion + +# region jinja + + +jinja_filter = type(cookit_global_filter)(all_filters.copy()) + + +def register_global_filter_to(env: "jinja2.Environment"): + env.filters.update(jinja_filter.data) + + +jinja_filter(format_cpu_freq) + + +@jinja_filter +def percent_to_color(percent: float) -> str: + if percent < 70: + return "prog-low" + if percent < 90: + return "prog-medium" + return "prog-high" + + +@jinja_filter +def auto_convert_unit(value: float, **kw) -> str: + return auto_convert_byte(value=value, with_space=False, **kw) + + +# endregion diff --git a/hexi/plugins/nonebot_plugin_picstatus/util.py b/hexi/plugins/nonebot_plugin_picstatus/util.py new file mode 100644 index 0000000..4d7a468 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_picstatus/util.py @@ -0,0 +1,39 @@ +import re +from functools import partial +from pathlib import Path +from typing import TYPE_CHECKING + +from cookit import DebugFileWriter, auto_convert_unit, format_timedelta + +if TYPE_CHECKING: + from .collectors.cpu import CpuFreq + +format_time_delta_ps = partial(format_timedelta, day_divider=" ", day_suffix="天") + + +def match_list_regexp(reg_list: list[str], txt: str) -> re.Match | None: + return next((match for r in reg_list if (match := re.search(r, txt))), None) + + +def format_freq(value: float) -> str: + """将 MHz 频率格式化为 MHz/GHz(十进制 1000 换算)""" + return auto_convert_unit( + units=("MHz", "GHz", "THz"), + multiplier=1000, + unit_threshold=1000, + value=value, + with_space=False, + ) + + +def format_cpu_freq(freq: "CpuFreq") -> str: + if not freq.current and not freq.max: + return "主频未知" + current = freq.current or freq.max or 0.0 + max_freq = freq.max or 0.0 + if not max_freq or max_freq == current: + return format_freq(current) + return f"{format_freq(current)} / {format_freq(max_freq)}" + + +debug = DebugFileWriter(Path(__file__).resolve().parents[2] / "logs", "picstatus") diff --git a/hexi/plugins/nonebot_plugin_random_jm_code/__init__.py b/hexi/plugins/nonebot_plugin_random_jm_code/__init__.py new file mode 100644 index 0000000..abb62ea --- /dev/null +++ b/hexi/plugins/nonebot_plugin_random_jm_code/__init__.py @@ -0,0 +1,151 @@ +import json +import random +import json +import random +import asyncio +import os +from typing import List + +from nonebot.adapters.onebot.v11 import MessageSegment, PokeNotifyEvent, Message +from nonebot.plugin.on import on_notice, on_command +from nonebot import on_type, on_message, logger +from nonebot.adapters import Event +from nonebot.matcher import Matcher +from nonebot.params import CommandArg +from nonebot.rule import to_me +from nonebot_plugin_alconna import UniMessage, get_target +from nonebot.plugin import PluginMetadata + +from hexi.plugins.nonebot_plugin_hexi_core.message_utils import send_poke + +__plugin_meta__ = PluginMetadata( + name="随机JM码", + description="随机发送JM码,支持添加与屏蔽", + usage="@bot 触发随机JM码;jm 添加JM码", + type="application", +) + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +FILE_PATH = os.path.join(BASE_DIR, "jm_code.json") + +TEXT_TEMPLATES = [ + "给你{code},拿去吧", + "给你{code},记得谢谢我", + "给你{code},注意保养弹簧" +] +BLOCK_CODE = ["350235", "350234"] + +WHITE_LIST = ["1019165018"] + +jm_handler = on_notice(priority=10, block=False, rule=to_me()) + +add_jm_code = on_command("jm", rule=to_me()) + + +@add_jm_code.handle() +async def add_more_jm_code(event: Event, matcher: Matcher): + input_code = event.get_message().extract_plain_text().strip() + cmd = matcher.state["_prefix"]["command"][0] + input_code = input_code.replace(cmd, "") + if input_code in BLOCK_CODE: + await UniMessage.at(event.get_user_id()).text(" 不准发石!!").send() + return + await add_new_jm_code(input_code) + await UniMessage.reply(event.get_user_id()).text(" 添加成功").send() + return + + +@jm_handler.handle() +async def random_jm_code(event: Event, poke_event: PokeNotifyEvent): + user_id = event.get_user_id() + logger.info(f"{user_id}触发了戳一戳") + target = get_target(event) + group_id = target.parent_id or target.id or poke_event.group_id + logger.info(f"触发戳一戳的群聊:{group_id}") + if group_id in WHITE_LIST: + logger.info(f"白名单:{group_id}") + choice = random.randint(0, 100) + logger.info(f"触发概率:{choice}") + if choice >= 50: + await poke_reply(event) + else: + logger.info("不做操作") + + else: + logger.info(f"不在白名单:{group_id}") + if target.private: + group_id = None + result = await send_poke(group_id=group_id, user_id=user_id) + logger.info(result) + return + + +async def poke_reply(event: Event): + user_id = event.get_user_id() + jm_message = await get_random_jm_code() + await UniMessage.at(user_id).text(" " + jm_message).send() + + +JM_CODES: List[int] = [] +_LOADED = False +LOCK = asyncio.Lock() + + +def _safe_write_json(data, file_path: str): + tmp_path = file_path + ".tmp" + + with open(tmp_path, "w", encoding="utf-8") as f: + json.dump(data, f, ensure_ascii=False, indent=2) + + # 原子替换(防止写一半崩溃) + os.replace(tmp_path, file_path) + + +async def load_codes(file_path: str = FILE_PATH): + global JM_CODES, _LOADED + + if _LOADED: + return + + async with LOCK: + if _LOADED: + return + + if not os.path.exists(file_path): + JM_CODES = [] + _safe_write_json(JM_CODES, file_path) + else: + with open(file_path, "r", encoding="utf-8") as f: + try: + JM_CODES = json.load(f) + except json.JSONDecodeError: + # 文件损坏时兜底 + JM_CODES = [] + + _LOADED = True + + +async def get_random_jm_code() -> str: + await load_codes() + + if not JM_CODES: + return "暂无可用代码" + + code = random.choice(JM_CODES) + logger.info(f"随机JM:{code}") + template = random.choice(TEXT_TEMPLATES) + + return template.format(code=code) + + +async def add_new_jm_code(new_code: int) -> bool: + await load_codes() + + async with LOCK: + if new_code in JM_CODES: + return False # 已存在 + + JM_CODES.append(new_code) + _safe_write_json(JM_CODES, FILE_PATH) + + return True diff --git a/hexi/plugins/nonebot_plugin_random_jm_code/jm_code.json b/hexi/plugins/nonebot_plugin_random_jm_code/jm_code.json new file mode 100644 index 0000000..351da38 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_random_jm_code/jm_code.json @@ -0,0 +1,286 @@ +[ + "219", + "224", + "759", + "877", + "878", + "2057", + "2388", + "2868", + "4333", + "6102", + "6411", + "18212", + "20106", + "20348", + "20902", + "21274", + "21407", + "21994", + "22392", + "27512", + "27701", + "28650", + "33775", + "39509", + "46555", + "47729", + "50514", + "54747", + "55427", + "58267", + "61257", + "62268", + "69354", + "73451", + "74891", + "77778", + "78665", + "80358", + "85055", + "86779", + "89218", + "98509", + "98669", + "101792", + "104738", + "105854", + "107184", + "114445", + "116157", + "122333", + "122427", + "124116", + "124561", + "125237", + "127282", + "135697", + "138809", + "140620", + "142464", + "142568", + "145289", + "148486", + "148624", + "149578", + "149906", + "151607", + "151696", + "181107", + "181611", + "190447", + "192957", + "203446", + "207063", + "209232", + "218796", + "220455", + "220995", + "220996", + "221659", + "223153", + "224879", + "225764", + "230702", + "230806", + "231692", + "235366", + "239642", + "239797", + "241726", + "245189", + "247044", + "248646", + "249121", + "251050", + "255015", + "258778", + "263104", + "265236", + "266615", + "268453", + "269417", + "271249", + "273943", + "278032", + "281142", + "284185", + "285994", + "290391", + "291407", + "293593", + "293867", + "303683", + "305291", + "305428", + "306326", + "306848", + "308472", + "308595", + "310176", + "318730", + "318731", + "322028", + "326357", + "329995", + "333722", + "334554", + "343898", + "346346", + "346862", + "352727", + "355019", + "355659", + "362197", + "362460", + "368639", + "368837", + "369504", + "370634", + "371570", + "371631", + "371875", + "373099", + "374495", + "377532", + "380052", + "382336", + "384297", + "385372", + "389479", + "390353", + "392326", + "394523", + "395280", + "395281", + "397150", + "397478", + "398569", + "401496", + "401574", + "409658", + "409896", + "410841", + "411613", + "412004", + "415513", + "417463", + "427706", + "429322", + "433023", + "434797", + "434801", + "435777", + "441189", + "441594", + "442137", + "443170", + "445794", + "448098", + "451603", + "451610", + "452501", + "452699", + "453931", + "454803", + "465335", + "467110", + "467180", + "468624", + "469738", + "471872", + "472952", + "475378", + "476677", + "477029", + "477990", + "478437", + "479907", + "480142", + "480841", + "481536", + "481979", + "482542", + "484683", + "485647", + "485870", + "486253", + "487798", + "488125", + "495051", + "495256", + "498750", + "501638", + "501838", + "502132", + "505048", + "505241", + "505253", + "505484", + "507975", + "508253", + "509489", + "509834", + "511010", + "513984", + "515569", + "517500", + "523276", + "524360", + "527354", + "529468", + "533458", + "533552", + "537119", + "541285", + "541762", + "542252", + "543247", + "543525", + "543749", + "544360", + "544401", + "545733", + "547590", + "549168", + "550176", + "552312", + "554413", + "563746", + "608258", + "1020570", + "1060990", + "1071423", + "1176067", + "1190464", + "1193587", + "1196804", + "1202415", + "1206636", + "1212262", + "1212643", + "1215962", + "1216628", + "1217450", + "1222299", + "1222320", + "1222393", + "1223363", + "1224091", + "1224493", + "2904551", + "3037141", + "3157283", + "3300062", + "3481682", + "3918941", + "3921012", + "4214502", + "4283473", + "4283484", + "4366352", + "4380002", + "5430811", + "1434077", + "1423811" +] \ No newline at end of file diff --git a/hexi/plugins/nonebot_plugin_regif/__init__.py b/hexi/plugins/nonebot_plugin_regif/__init__.py new file mode 100644 index 0000000..a3adb6d --- /dev/null +++ b/hexi/plugins/nonebot_plugin_regif/__init__.py @@ -0,0 +1,126 @@ +import os +import ssl +from nonebot import on_command, require, logger +from nonebot.adapters.onebot.v11 import MessageEvent +from nonebot.plugin import PluginMetadata + +from hexi.plugins.nonebot_plugin_hexi_core.message_utils import get_reply_message + +require("nonebot_plugin_alconna") +from nonebot_plugin_alconna import UniMessage +from nonebot.adapters.onebot.v11.bot import Bot +from nonebot.plugin.on import on_keyword +import httpx +from io import BytesIO +from PIL import Image, ImageSequence +re_gif = on_keyword({"倒放"}) + +__plugin_meta__ = PluginMetadata( + name="GIF倒放", + description="GIF倒放?", + usage="倒放+图片", + type="application", +) + +@re_gif.handle() +async def rev_gif(event: MessageEvent, bot: Bot): + # 情况1,用户对需要倒放的gif进行回复 + messages = get_reply_message(event) + await match_revgif(messages) + + +async def match_revgif(messages): + img_urls = [] + + for message in messages: + logger.info(f"遍历消息: {message}") + + # 只处理图片消息 + if message.type != "image": + continue + + url = message.data.get("url") + + if url: + img_urls.append(url) + + # 没有图片直接返回 + if not img_urls: + logger.info("消息中没有图片") + return + for url in img_urls: + logger.info(f"获取到的图片链接:{url}") + await do_revgif(img_urls) + + +ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS) + +fd = os.path.dirname(__file__) + + +async def do_revgif(image_urls): + gif_img = [] + + async with httpx.AsyncClient(timeout=30) as client: + for image_url in image_urls: + try: + resp = await client.get(image_url) + resp.raise_for_status() + + image = Image.open(BytesIO(resp.content)) + + # 不是gif或只有1帧 + if getattr(image, "n_frames", 1) == 1: + continue + + gif_img.append(image) + + except Exception as e: + logger.warning(f"下载或解析图片失败: {e}") + + if not gif_img: + await UniMessage.text("没有发现GIF图片").send() + return + + suit_gifs = [] + + for gif in gif_img: + if gif.n_frames <= 400: + suit_gifs.append(gif) + + if not suit_gifs: + await UniMessage.text("GIF帧数太多了,懒得倒放😅").send() + return + + suit_image = suit_gifs[0] + + sequence = [f.copy() for f in ImageSequence.Iterator(suit_image)] + logger.info(f"GIF帧数: {len(sequence)}") + if len(sequence) <= 2: + await UniMessage.text("写入文件时发生未知错误").send() + return + + await UniMessage.text("ℹ正在翻转图片序列,请稍候").send() + + sequence.reverse() + + bio = BytesIO() + + sequence[0].save( + bio, + format="GIF", + save_all=True, + append_images=sequence[1:], + disposal=1, + loop=0 + ) + + bio.seek(0) + + await UniMessage.image(raw=bio.getvalue()).send() + + +def image_to_bytes(image: Image.Image, input_format: str) -> bytes: + with BytesIO() as bio: + image.save(bio, format=input_format) + return bio.getvalue() diff --git a/hexi/plugins/nonebot_plugin_steam_info/__init__.py b/hexi/plugins/nonebot_plugin_steam_info/__init__.py new file mode 100644 index 0000000..c448201 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_steam_info/__init__.py @@ -0,0 +1,964 @@ +import asyncio +import time +import httpx +import nonebot +from io import BytesIO +from pathlib import Path +from nonebot.log import logger +from PIL import Image as PILImage +from nonebot.params import Depends +from nonebot.params import CommandArg +from nonebot import on_command, require +from nonebot.permission import SUPERUSER +from typing import Optional, List, Dict +from nonebot.adapters import Message, Event +from nonebot.plugin import PluginMetadata, inherit_supported_adapters + +require("nonebot_plugin_alconna") +require("nonebot_plugin_localstore") +require("nonebot_plugin_apscheduler") +from nonebot_plugin_alconna.uniseg import get_target as uni_get_target +import nonebot_plugin_localstore as store +from nonebot_plugin_apscheduler import scheduler +from nonebot_plugin_alconna import Text, Image, UniMessage, Target, At +from nonebot.adapters.onebot.v11 import Bot, MessageEvent, MessageSegment +from hexi.plugins.nonebot_plugin_hexi_core.cooldown import cooldown +from .config import Config +from .models import ProcessedPlayer +from .data_source import BindData, SteamInfoData, ParentData, DisableParentData +from .steam import ( + get_steam_id, + get_user_data, + STEAM_ID_OFFSET, + get_steam_users_info, + init_api_key_manager, + get_play_time as fetch_play_time, + get_game_cn_names, + localize_game_name, + migrate_game_names_json, + update_steamdb_apps, + _is_full_sync_done, + _query_game_names, + _query_game_icon_hashes, + _upsert_game_names, + _upsert_game_icon_hashes, +) +from .draw import ( + check_font, + set_font_paths, + draw_start_gaming, + draw_player_status, + draw_friends_status, + vertically_concatenate_images, +) +from .utils import ( + fetch_avatar, + get_game_icons, + image_to_bytes, + simplize_steam_player_data, +) + +__plugin_meta__ = PluginMetadata( + name="Steam信息", + description="播报绑定的 Steam 好友状态", + usage=""" + steamhelp: 查看帮助 + steambind [Steam ID 或 Steam 好友代码]: 绑定 Steam ID + steamunbind: 解绑 Steam ID + steaminfo (可选)[@某人 或 Steam ID 或 Steam好友代码]: 查看 Steam 主页 + steamcheck: 查看 Steam 好友状态 + steamenable: 启用 Steam 播报 + steamdisable: 禁用 Steam 播报 + steamplaytime (可选)[Steam ID 或 Steam好友代码]: 查看游玩时长排行 + steamdbupdate: 更新 SteamDB 游戏名映射(仅限超级管理员) + (群名/群头像/群内昵称均由机器人自动获取,无需手动设置) + """.strip(), + type="application", + homepage="https://github.com/zhaomaoniu/nonebot-plugin-steam-info", + config=Config, + supported_adapters=inherit_supported_adapters("nonebot_plugin_alconna"), +) + +help = on_command("steamhelp", aliases={"steam帮助"}, priority=10) +bind = on_command("steambind", aliases={"绑定steam"}, priority=10) +unbind = on_command("steamunbind", aliases={"解绑steam"}, priority=10) +info = on_command("steaminfo", aliases={"steam信息"}, priority=10) +# 谁在玩游戏:全群共享 CD,防一人狂点挤占 API 配额(steam.py 内另有总配额限频) +check = cooldown(30, scope="group", hint="群里刚有人查过,{secs} 秒后再试")( + on_command("steamcheck", aliases={"查看steam", "查steam", "谁在玩游戏"}, priority=10) +) +enable = on_command("steamenable", aliases={"启用steam"}, priority=10) +disable = on_command("steamdisable", aliases={"禁用steam"}, priority=10) +# 游戏时长表:单用户 15s CD +get_play_time = cooldown(15, hint="查询太频繁了,{secs} 秒后再试")( + on_command("steamplaytime", aliases={"游戏时长表"}, priority=10) +) +# 全量拉取 SteamDB 较重,仅限超级管理员触发 +update_steamdb = on_command( + "steamdbupdate", aliases={"更新steamdb"}, priority=10, permission=SUPERUSER +) + +if hasattr(nonebot, "get_plugin_config"): + config = nonebot.get_plugin_config(Config) +else: + from nonebot import get_driver + + config = Config.parse_obj(get_driver().config) + +set_font_paths( + config.steam_font_regular_path, + config.steam_font_light_path, + config.steam_font_bold_path, +) + +# 全部数据整合进单一 SQLite(绑定/播报状态/群信息/禁用/游戏名映射), +# 存插件目录 data/ 下,迁移只拷一个文件;头像缓存保留在 localstore +_plugin_data_dir = Path(__file__).resolve().parent / "data" +_plugin_data_dir.mkdir(parents=True, exist_ok=True) +db_path = _plugin_data_dir / "steam.db" +# 一次性迁移旧 JSON 游戏名映射到 SQLite(其余数据类内部自带迁移) +migrate_game_names_json(_plugin_data_dir / "game_names.json", db_path) +avatar_path = store.get_cache_dir("nonebot_plugin_steam_info") +cache_path = avatar_path + +bind_data = BindData(db_path) +steam_info_data = SteamInfoData(db_path) +parent_data = ParentData(db_path) +disable_parent_data = DisableParentData(db_path) + +try: + check_font() +except FileNotFoundError as e: + logger.error( + f"{e}, nonebot_plugin_steam_info 无法使用,请参照 `https://github.com/zhaomaoniu/nonebot-plugin-steam-info` 配置字体文件" + ) + +try: + config = nonebot.get_plugin_config(Config) + init_api_key_manager(config, db_path) + logger.success("Steam API key 管理器已初始化") +except Exception as e: + logger.error(f"初始化失败: {e}") + +# 统一配置标准:把常见可调配置暴露给 Web 管理台 +from hexi.config_standard import register_model_config # noqa: E402 + +register_model_config( + __name__, + config, + fields=[ + "steam_api_key", + "steam_request_interval", + "steam_broadcast_type", + "steam_playtime_theme", + "steam_disable_broadcast_on_startup", + "proxy", + ], + types={ + "steam_api_key": "text", + "steam_broadcast_type": "enum", + "steam_playtime_theme": "enum", + }, + options={ + "steam_broadcast_type": [ + {"value": "all", "label": "全部(带图)"}, + {"value": "part", "label": "部分(开始游戏图)"}, + {"value": "none", "label": "仅文字"}, + ], + "steam_playtime_theme": [ + {"value": "light", "label": "亮色"}, + {"value": "dark", "label": "暗色"}, + ], + }, + labels={ + "steam_api_key": "Steam Web API Key", + "steam_request_interval": "播报轮询间隔(秒)", + "steam_broadcast_type": "播报类型", + "steam_playtime_theme": "时长表主题", + "steam_disable_broadcast_on_startup": "启动时不播报", + "proxy": "代理", + }, + descriptions={ + "steam_api_key": "每行一个,可多 key 轮询;改后需重启生效", + "steam_request_interval": "播报轮询周期(分钟=值/60)", + "steam_broadcast_type": "控制播报附带图片的粒度", + "steam_playtime_theme": "游玩时长表图片主题", + "steam_disable_broadcast_on_startup": "True 时 bot 连接不触发首次播报", + "proxy": "如 http://127.0.0.1:7890", + }, +) + + + +async def get_target(event: Event, bot: Bot) -> Optional[Target]: + target = uni_get_target(event) + + if target.private: + # 不支持私聊消息 + return None + + return target + + +async def _refresh_parent_info(bot: Bot, parent_id: str) -> None: + """从 QQ 自动获取群名+群头像并更新缓存(steamupdate 指令已移除,一律自动)""" + name = None + try: + group_info = await bot.get_group_info(group_id=int(parent_id)) + name = group_info.get("group_name") or None + except Exception as e: + logger.warning(f"获取群 {parent_id} 信息失败: {e}") + try: + async with httpx.AsyncClient(timeout=10) as client: + resp = await client.get(f"http://p.qlogo.cn/gh/{parent_id}/{parent_id}/640") + if resp.status_code == 200 and resp.content: + avatar = PILImage.open(BytesIO(resp.content)) + parent_data.update(parent_id, avatar, name or str(parent_id)) + return + except Exception as e: + logger.warning(f"下载群 {parent_id} 头像失败: {e}") + if name: + parent_data.update_name(parent_id, name) + + +async def get_parent_info(bot: Bot, parent_id: str): + """获取群名+群头像:缓存新鲜直接返回,否则从 QQ 刷新(7 天过期)""" + if not parent_data.is_fresh(parent_id): + await _refresh_parent_info(bot, parent_id) + return parent_data.get(parent_id) + + +async def get_group_nickname(bot: Bot, parent_id: str, user_id: str) -> str: + """获取群内昵称:群名片优先,无名片用群昵称;失败返回空串""" + try: + info = await bot.get_group_member_info( + group_id=int(parent_id), user_id=int(user_id) + ) + return info.get("card") or info.get("nickname") or "" + except Exception as e: + logger.warning(f"获取群成员 {parent_id}/{user_id} 信息失败: {e}") + return "" + + +async def _fill_missing_icon_hashes(players: list[dict]) -> None: + """按需补 clienticon hash + + 对"多人同玩"且本地没有 icon hash 的游戏,用正在玩该游戏的绑定用户 steamid + 调一次 GetOwnedGames 拿 img_icon_url 写回映射表,避免依赖每日同步才有图标。 + """ + if not players: + return + + game_counts: dict[int, int] = {} + for p in players: + if p.get("gameid"): + gid = int(p["gameid"]) + game_counts[gid] = game_counts.get(gid, 0) + 1 + + missing = [ + gid + for gid, cnt in game_counts.items() + if cnt >= 2 and not _query_game_icon_hashes(db_path, [gid]).get(gid) + ] + if not missing: + return + + missing_set = set(missing) + reps: dict[int, str] = {} + for p in players: + if p.get("gameid") and int(p["gameid"]) in missing_set: + reps.setdefault(int(p["gameid"]), p["steamid"]) + + for steam_id in set(reps.values()): + games = await fetch_play_time(steam_id) + if games is None: + # 配额不足,等下次再补 + continue + entries = { + int(g["appid"]): g.get("clienticon") + for g in games + if g.get("appid") and g.get("clienticon") + } + if entries: + _upsert_game_icon_hashes(db_path, entries) + + +def format_play_duration(start_time: Optional[int]) -> str: + """根据游戏开始时间计算游玩时长,缺少开始时间时返回占位文案""" + if start_time is None: + return "未知时长" + elapsed = time.time() - start_time + hours = int(elapsed / 3600) + minutes = int(elapsed % 3600 / 60) + return f"{hours} 小时 {minutes} 分钟" if hours > 0 else f"{minutes} 分钟" + + +async def broadcast_steam_info( + parent_id: str, + old_players: List[ProcessedPlayer], + new_players: List[ProcessedPlayer], +): + if disable_parent_data.is_disabled(parent_id): + return None + + bot = nonebot.get_bot() + + play_data = steam_info_data.compare(old_players, new_players) + + # 游戏名本地化(中文名优先):只替换播报用的副本,不修改已存储的玩家数据, + # 否则下一轮对比时同一游戏的中英文名不一致会被误判为换游戏,反复通报 + appids = [ + int(p["gameid"]) + for entry in play_data + for p in (entry["player"], entry.get("old_player")) + if p and p.get("gameid") + ] + # 播报每 1~5 分钟一轮:只查本地映射表,不联网补全中文名 + # (appdetails 高频会被封 IP;缺中文名的游戏留到用户命令查询时再补) + names = await get_game_cn_names(appids, db_path, fetch_missing=False) + + def _localized_copy(p: Optional[ProcessedPlayer]) -> Optional[ProcessedPlayer]: + if p and p.get("gameid"): + return { + **p, + "gameextrainfo": localize_game_name( + p.get("gameextrainfo", ""), int(p["gameid"]), names + ), + } + return p + + for entry in play_data: + for key in ("player", "old_player"): + if entry.get(key): + entry[key] = _localized_copy(entry[key]) + + msg = [] + for entry in play_data: + player: ProcessedPlayer = entry["player"] + old_player: ProcessedPlayer = entry.get("old_player") + + if entry["type"] == "start": + msg.append(f"{player['personaname']} 开始玩 {player['gameextrainfo']} 了") + elif entry["type"] == "stop": + time_str = format_play_duration(old_player["game_start_time"]) + msg.append( + f"{player['personaname']} 玩了 {time_str} {old_player['gameextrainfo']} 后不玩了" + ) + elif entry["type"] == "change": + time_str = format_play_duration(old_player["game_start_time"]) + msg.append( + f"{player['personaname']} 玩了 {time_str} {old_player['gameextrainfo']} 后开始玩 {player['gameextrainfo']} 了" + ) + elif entry["type"] == "error": + msg.append( + f"出现错误!{player['personaname']}\nNew: {player.get('gameextrainfo')}\nOld: {old_player.get('gameextrainfo')}" + ) + else: + logger.error(f"未知的播报类型: {entry['type']}") + + if msg == []: + return 0 + + if config.steam_broadcast_type == "all": + # 与 steamcheck 一样:所有游戏都取图标(单人也要图标),商店页优先 + game_ids: list[int] = [] + seen: set[int] = set() + for p in new_players: + if p.get("gameid"): + gid = int(p["gameid"]) + if gid not in seen: + seen.add(gid) + game_ids.append(gid) + game_icons = ( + await get_game_icons(game_ids, config.proxy, db_path) if game_ids else {} + ) + + steam_status_data = [] + for player in (_localized_copy(p) for p in new_players): + data = await simplize_steam_player_data( + player, config.proxy, avatar_path, names + ) + entry = bind_data.get_by_steam_id(parent_id, player["steamid"]) + # 绑定的玩家展示群内昵称,未绑定/获取失败则用 Steam 昵称 + data["nickname"] = ( + await get_group_nickname(bot, parent_id, entry["user_id"]) + if entry is not None + else None + ) + data["game_icon"] = game_icons.get(data["gameid"]) + steam_status_data.append(data) + + parent_avatar, parent_name = await get_parent_info(bot, parent_id) + image = draw_friends_status(parent_avatar, parent_name, steam_status_data) + uni_msg = UniMessage([Text("\n".join(msg)), Image(raw=image_to_bytes(image))]) + elif config.steam_broadcast_type == "part": + images = [] + for entry in play_data: + if entry["type"] != "start": + continue + user_data = bind_data.get_by_steam_id( + parent_id, entry["player"]["steamid"] + ) + nickname = ( + await get_group_nickname(bot, parent_id, user_data["user_id"]) + if user_data is not None + else None + ) + images.append( + draw_start_gaming( + (await fetch_avatar(entry["player"], avatar_path, config.proxy)), + entry["player"]["personaname"], + entry["player"]["gameextrainfo"], + nickname, + ) + ) + if images == []: + uni_msg = UniMessage([Text("\n".join(msg))]) + else: + image = ( + vertically_concatenate_images(images) if len(images) > 1 else images[0] + ) + uni_msg = UniMessage( + [Text("\n".join(msg)), Image(raw=image_to_bytes(image))] + ) + elif config.steam_broadcast_type == "none": + uni_msg = UniMessage([Text("\n".join(msg))]) + else: + logger.error(f"未知的播报类型: {config.steam_broadcast_type}") + return None + try: + logger.info(f"播报发送: 群 {parent_id}, {len(msg)} 条: {msg}") + await uni_msg.send( + Target(parent_id, parent_id, True, False, "", bot.adapter.get_name()), bot + ) + return len(msg) + except Exception as e: + logger.error(f"✗ 播报发送失败 群 {parent_id}: {type(e).__name__}: {e}") + return 0 + + +# 初始化计数器 +current_key_index = 0 + + +def key_select_2(): + global current_key_index + # 获取key列表 + keys = config.steam_api_key + # 获取当前使用的 key + current_key: str = keys[current_key_index] + # 更新计数器 + current_key_index = (current_key_index + 1) % len(keys) + + return [current_key] + + +async def update_steam_info(): + steam_ids = bind_data.get_all_steam_id() + api_keys = config.steam_api_key + if not api_keys: + logger.warning("没有可用的 key。") + current_key = key_select_2() + logger.info(f"播报轮询: 开始拉取 {len(steam_ids)} 个绑定玩家, key={current_key}") + # 播报等得起,等待配额最多 60s;配额不足跳过本轮 + steam_info = await get_steam_users_info( + steam_ids, current_key, config.proxy, wait=True + ) + if steam_info is None: + logger.warning("✗ 播报轮询: Steam API 配额已满,跳过本轮") + return None + players = steam_info["response"]["players"] + logger.info(f"✓ 播报轮询: 成功拉取 {len(players)} 个玩家状态") + + old_players_dict: Dict[str, List[ProcessedPlayer]] = {} + + for parent_id in bind_data.content.keys(): + steam_ids = bind_data.get_all(parent_id) + old_players_dict[parent_id] = steam_info_data.get_players(steam_ids) + + steam_info_data.update_by_players(steam_info["response"]["players"]) + steam_info_data.save() + + return bind_data, old_players_dict + + +# 播报互斥锁:定时任务与启动/重连钩子共用,防止并发拉取导致 +# steam_info 表双写与重复广播 +_broadcast_lock = asyncio.Lock() + + +@scheduler.scheduled_job( + "interval", minutes=config.steam_request_interval / 60, id="update_steam_info" +) +async def fetch_and_broadcast_steam_info(): + try: + async with _broadcast_lock: + result = await update_steam_info() + if result is None: # API 配额不足,跳过本轮播报 + return + bind_data, old_players_dict = result + + total_changes = 0 + total_sent = 0 + for parent_id in bind_data.content.keys(): + old_players = old_players_dict[parent_id] + new_players = steam_info_data.get_players( + bind_data.get_all(parent_id) + ) + changes = await broadcast_steam_info( + parent_id, old_players, new_players + ) + if changes: + total_changes += changes + total_sent += 1 + + if total_changes: + logger.info( + f"✓ 播报轮询完成: {total_changes} 条变化, " + f"{total_sent}/{len(bind_data.content)} 个群有播报" + ) + else: + logger.info("✓ 播报轮询完成: 无状态变化,本轮不播报") + except Exception as e: + # 兜底:任何异常都要打堆栈,避免定时任务静默失败 + logger.error(f"✗ 播报轮询异常: {type(e).__name__}: {e}", exc_info=True) + + +async def _update_steam_info_once(bot): + """启动/重连时的首轮拉取(与定时任务互斥,只拉取不广播)""" + async with _broadcast_lock: + await update_steam_info() + + +if not config.steam_disable_broadcast_on_startup: + nonebot.get_driver().on_bot_connect(_update_steam_info_once) +else: + logger.info("已禁用启动时的 Steam 播报") + + +@help.handle() +async def help_handle(): + await help.finish(__plugin_meta__.usage) + + +@bind.handle() +async def bind_handle( + event: Event, target: Target = Depends(get_target), cmd_arg: Message = CommandArg() +): + parent_id = target.parent_id or target.id + + arg = cmd_arg.extract_plain_text() + + if not arg.isdigit(): + await bind.finish( + "请输入正确的 Steam ID 或 Steam好友代码,格式: steambind [Steam ID 或 Steam好友代码]" + ) + + steam_id = get_steam_id(arg) + + if user_data := bind_data.get(parent_id, event.get_user_id()): + user_data["steam_id"] = steam_id + bind_data.save() + + await bind.finish(f"已更新你的 Steam ID 为 {steam_id}") + else: + bind_data.add( + parent_id, + {"user_id": event.get_user_id(), "steam_id": steam_id, "nickname": None}, + ) + bind_data.save() + + await bind.finish(f"已绑定你的 Steam ID 为 {steam_id}") + + +@unbind.handle() +async def unbind_handle(event: Event, target: Target = Depends(get_target)): + parent_id = target.parent_id or target.id + user_id = event.get_user_id() + + if bind_data.get(parent_id, user_id) is not None: + bind_data.remove(parent_id, user_id) + bind_data.save() + + await unbind.finish("已解绑 Steam ID") + else: + await unbind.finish("未绑定 Steam ID") + + +@info.handle() +async def info_handle( + bot: Bot, + event: Event, + target: Target = Depends(get_target), + arg: Message = CommandArg(), +): + parent_id = target.parent_id or target.id + + uni_arg = await UniMessage.generate(message=arg, event=event, bot=bot) + at = uni_arg[At] + + if len(at) != 0: + user_id: str = at[0].target + user_data = bind_data.get(parent_id, user_id) + if user_data is None: + await info.finish("该用户未绑定 Steam ID") + steam_id = user_data["steam_id"] + steam_friend_code = str(int(steam_id) - STEAM_ID_OFFSET) + elif arg.extract_plain_text().strip() != "": + steam_id = int(arg.extract_plain_text().strip()) + if steam_id < STEAM_ID_OFFSET: + steam_friend_code = steam_id + steam_id += STEAM_ID_OFFSET + else: + steam_friend_code = steam_id - STEAM_ID_OFFSET + else: + user_data = bind_data.get(parent_id, event.get_user_id()) + + if user_data is None: + await info.finish( + "未绑定 Steam ID, 请使用 “steambind [Steam ID 或 Steam好友代码]” 绑定 Steam ID" + ) + + steam_id = user_data["steam_id"] + steam_friend_code = str(int(steam_id) - STEAM_ID_OFFSET) + + player_data = await get_user_data(steam_id, cache_path, config.proxy) + + # 游戏名本地化(中文名优先) + names = await get_game_cn_names( + [g.get("appid") for g in player_data["game_data"] if g.get("appid")], + db_path, + ) + for g in player_data["game_data"]: + g["game_name"] = localize_game_name(g["game_name"], g.get("appid"), names) + + draw_data = [ + { + "game_header": game["game_image"], + "game_name": game["game_name"], + "game_time": f"{game['play_time']} 小时", + "last_play_time": game["last_played"], + "achievements": game["achievements"], + "completed_achievement_number": game.get("completed_achievement_number"), + "total_achievement_number": game.get("total_achievement_number"), + } + for game in player_data["game_data"] + ] + + image = draw_player_status( + player_data["background"], + player_data["avatar"], + player_data["player_name"], + str(steam_friend_code), + player_data["description"], + player_data["recent_2_week_play_time"], + draw_data, + ) + + await info.finish( + await UniMessage( + Image(raw=image_to_bytes(image)), + ).export(bot) + ) + + +# 初始化计数器 +current_key_index_1 = 0 + + +def key_select(): + global current_key_index_1 + # 获取key列表 + keys = config.steam_api_key + # 获取当前使用的 key + current_key: str = keys[current_key_index_1] + # 更新计数器 + current_key_index_1 = (current_key_index_1 + 1) % len(keys) + + return [current_key] + + +@check.handle() +async def check_handle( + bot: Bot, + target: Target = Depends(get_target), + arg: Message = CommandArg(), +): + if arg.extract_plain_text().strip() != "": + return None + + parent_id = target.parent_id or target.id + + steam_ids = bind_data.get_all(parent_id) + + current_key = key_select() + + logger.info(f"当前调用的key:{current_key}") + # 用户命令快速失败,不挤占播报配额 + steam_info = await get_steam_users_info( + steam_ids, current_key, config.proxy, wait=False + ) + if steam_info is None: + await check.finish("Steam API 请求过于频繁,请稍后再试") + + logger.debug(f"{parent_id} Players info: {steam_info}") + + # 游戏名本地化(中文名优先) + players = steam_info["response"]["players"] + names = await get_game_cn_names( + [int(p["gameid"]) for p in players if p.get("gameid")], + db_path, + ) + for p in players: + if p.get("gameid"): + p["gameextrainfo"] = localize_game_name( + p.get("gameextrainfo", ""), int(p["gameid"]), names + ) + + # 统计所有游玩中的游戏(单人也要显示游戏图标),商店页优先抓取 clienticon + game_ids: list[int] = [] + seen: set[int] = set() + for p in players: + if p.get("gameid"): + gid = int(p["gameid"]) + if gid not in seen: + seen.add(gid) + game_ids.append(gid) + game_icons = ( + await get_game_icons(game_ids, config.proxy, db_path) if game_ids else {} + ) + + # 后台用正在玩的 steamid 补剩余缺的 hash(不阻塞当前出图;商店页为主要手段) + asyncio.create_task(_fill_missing_icon_hashes(players)) + + parent_avatar, parent_name = await get_parent_info(bot, parent_id) + + steam_status_data = [] + for player in players: + data = await simplize_steam_player_data( + player, config.proxy, avatar_path, names + ) + entry = bind_data.get_by_steam_id(parent_id, player["steamid"]) + data["nickname"] = ( + await get_group_nickname(bot, parent_id, entry["user_id"]) + if entry is not None + else None + ) + data["game_icon"] = game_icons.get(data["gameid"]) + steam_status_data.append(data) + + image = draw_friends_status(parent_avatar, parent_name, steam_status_data) + + await target.send(UniMessage(Image(raw=image_to_bytes(image)))) + + +@enable.handle() +async def enable_handle(target: Target = Depends(get_target)): + parent_id = target.parent_id or target.id + + disable_parent_data.remove(parent_id) + disable_parent_data.save() + + await enable.finish("已启用 Steam 播报") + + +@disable.handle() +async def disable_handle(target: Target = Depends(get_target)): + parent_id = target.parent_id or target.id + + disable_parent_data.add(parent_id) + disable_parent_data.save() + + await disable.finish("已禁用 Steam 播报") + + +async def _auto_sync_game_names(): + """启动时自动同步游戏名映射表:未全量同步过则全量拉取,已标记完成则跳过""" + try: + if _is_full_sync_done(db_path): + logger.info("游戏名映射表已全量同步过,跳过启动同步") + return + api_key = config.steam_api_key[0] + count = await update_steamdb_apps(db_path, api_key) + logger.info(f"游戏名映射表首次同步完成: {count} 条") + except Exception as e: + logger.error(f"游戏名映射表启动同步失败: {e}") + + +@scheduler.scheduled_job("cron", hour=5, minute=0, id="sync_missing_games") +async def _sync_missing_games(): + """扫描绑定用户游戏库,自动补全映射表缺失的游戏 + + 英文名从 GetOwnedGames 响应直接取(零额外请求),中文名留给查询时按需补全。 + """ + try: + all_games: dict[str, str] = {} + all_icons: dict[int, str] = {} + for parent_id in bind_data.content.keys(): + for steam_id in bind_data.get_all(parent_id): + games = await fetch_play_time(steam_id) + if games is None: # API 配额不足,跳过该用户 + logger.warning( + f"Steam API 配额已满,跳过 {steam_id} 的游戏同步" + ) + continue + for g in games: + if g.get("appid"): + all_games.setdefault(str(g["appid"]), g["name"]) + if g.get("clienticon"): + all_icons.setdefault(int(g["appid"]), g["clienticon"]) + if not all_games: + return + known = _query_game_names(db_path, [int(a) for a in all_games]) + missing = { + aid: name for aid, name in all_games.items() if aid not in known + } + if missing: + _upsert_game_names( + db_path, + { + aid: {"name_en": name, "name_ch": ""} + for aid, name in missing.items() + }, + ) + logger.info(f"补全映射表缺失游戏: {len(missing)} 个") + if all_icons: + _upsert_game_icon_hashes(db_path, all_icons) + logger.info(f"补全映射表游戏图标: {len(all_icons)} 个") + except Exception as e: + logger.error(f"补全映射表缺失游戏失败: {e}") + + +@scheduler.scheduled_job( + "cron", hour=4, minute=30, id="sync_game_names" +) +async def _daily_sync_game_names(): + """每日全量同步游戏名映射表(保证表内始终有全部游戏)""" + try: + api_key = config.steam_api_key[0] + count = await update_steamdb_apps(db_path, api_key) + logger.info(f"游戏名映射表每日全量同步完成: {count} 条") + except Exception as e: + logger.error(f"游戏名映射表每日同步失败: {e}") + + +async def _on_bot_connect(bot): + """bot 连接后后台执行映射表首次同步(不阻塞连接流程)""" + asyncio.create_task(_auto_sync_game_names()) + + +nonebot.get_driver().on_bot_connect(_on_bot_connect) + + +@update_steamdb.handle() +async def update_steamdb_handle(): + await update_steamdb.send("正在拉取 Steam 全量 app 列表...") + try: + api_key = config.steam_api_key[0] + count = await update_steamdb_apps(db_path, api_key) + except Exception as e: + logger.error(f"SteamDB 数据更新失败: {e}") + await update_steamdb.finish(f"SteamDB 数据更新失败: {e}") + if count: + await update_steamdb.finish(f"Steam 数据更新完成,共 {count} 个游戏") + else: + await update_steamdb.finish("Steam 数据拉取失败,稍后重试") + + +@get_play_time.handle() +async def get_play_time_handle( + bot: Bot, + event: MessageEvent, + target: Target = Depends(get_target), + cmd_arg: Message = CommandArg(), +): + parent_id = target.parent_id or target.id + user_data = None + + logger.info(f"游玩时长表:进入处理, parent={parent_id}") + arg_text = cmd_arg.extract_plain_text().strip() + + if arg_text: + if not arg_text.isdigit(): + await get_play_time.finish( + "请输入正确的 Steam ID 或 Steam好友代码,格式: steamplaytime [Steam ID 或 Steam好友代码]" + ) + steam_id = get_steam_id(arg_text) + else: + user_data = bind_data.get(parent_id, event.get_user_id()) + if user_data is None: + await get_play_time.finish( + "未绑定 Steam ID,请使用 steamplaytime [Steam ID 或 Steam好友代码] 查询,或先使用 steambind 绑定" + ) + steam_id = user_data["steam_id"] + await get_play_time.send("正在获取数据,请耐心等待") + logger.info(f"游玩时长表:开始获取数据, steam_id={steam_id}") + games = await fetch_play_time(steam_id) + if games is None: + await get_play_time.finish("Steam API 请求过于频繁,请稍后再试") + logger.info(f"游玩时长表:数据获取完成, 共 {len(games)} 款游戏") + + if not games: + await get_play_time.finish("没有获取到游玩数据(游戏可能未公开)") + + # 顺手把 GetOwnedGames 返回的 clienticon hash 写入映射表,供 steamcheck 图标使用 + icon_entries = { + int(g["appid"]): g.get("clienticon") + for g in games + if g.get("appid") and g.get("clienticon") + } + if icon_entries: + _upsert_game_icon_hashes(db_path, icon_entries) + + # 游戏名本地化:仅查本地映射表,有中文用中文,没有保持 API 原始名(不联网补全) + appids = [g["appid"] for g in games if g.get("appid")] + game_map = _query_game_names(db_path, appids) if appids else {} + names = { + int(aid): entry["name_ch"] + for aid, entry in game_map.items() + if entry.get("name_ch") + } + for g in games: + g["name"] = localize_game_name(g["name"], g.get("appid"), names) + + # 分离已游玩(表格/饼图)与全量(柱状图按时长分段,含 0 时长) + played = [g for g in games if g["playtime_hours"] > 0] + if not played: + await get_play_time.finish("没有游玩记录(游戏可能未公开或全部未游玩)") + for i, g in enumerate(played, 1): + g["rank"] = i + + # 渲染 HTML 图片(Playwright);失败则提示并结束 + try: + from .html_playtime import render_play_time_table + + # 头像与昵称:Steam 昵称常显,插件昵称(群昵称)设置了才显示 + steam_name, plugin_nick, avatar = "", "", None + try: + player_data = await get_user_data(steam_id, cache_path, config.proxy) + steam_name = player_data.get("player_name", "") + avatar = player_data.get("avatar") + except Exception as e: + logger.warning(f"获取玩家资料失败,省略头像昵称: {e}") + if user_data: + plugin_nick = await get_group_nickname( + bot, parent_id, user_data["user_id"] + ) + + logger.info(f"游玩时长表:开始渲染 HTML 图片, steam={steam_name}, nick={plugin_nick}") + img_bytes = await render_play_time_table( + played, games, steam_name, plugin_nick, avatar, + theme=config.steam_playtime_theme, + ) + logger.info(f"游玩时长表:渲染完成, {len(img_bytes)} bytes") + except Exception as e: + logger.error(f"渲染游玩时长表图片失败: {e}", exc_info=True) + await get_play_time.finish("游玩时长表渲染失败,请稍后重试") + + # 发送移出 try:finish 成功后抛的 StopPropagation 不能被 except 捕获 + # (否则图片发出后还会再补一句"渲染失败"),与 info 指令一致先 export + # 回复原指令消息,群消息多时不易混淆 + uni_msg = MessageSegment.reply(event.message_id) + await UniMessage( + Image(raw=img_bytes) + ).export(bot) + await get_play_time.finish(uni_msg) diff --git a/hexi/plugins/nonebot_plugin_steam_info/config.py b/hexi/plugins/nonebot_plugin_steam_info/config.py new file mode 100644 index 0000000..568cf1e --- /dev/null +++ b/hexi/plugins/nonebot_plugin_steam_info/config.py @@ -0,0 +1,33 @@ +from typing import Optional, Union, List +from pydantic import BaseModel, validator + + +class Config(BaseModel): + steam_api_key: Union[str, List[str]] + proxy: Optional[str] = None + steam_request_interval: int = 300 # seconds + steam_broadcast_type: str = "part" # all, part, none + steam_disable_broadcast_on_startup: bool = False + steam_font_regular_path: Optional[str] = "hexi/resource/fonts/MiSans-Regular.ttf" + steam_font_light_path: Optional[str] = "hexi/resource/fonts/MiSans-Light.ttf" + steam_font_bold_path: Optional[str] = "hexi/resource/fonts/MiSans-Bold.ttf" + + # 仅用于迁移旧 JSON 状态文件(运行时 API key 状态已持久化到 SQLite) + steam_api_key_state_path: Optional[str] = "hexi/data/api_keys_state.json" + + # 游玩时长表图片主题: light / dark,默认亮色 + steam_playtime_theme: str = "light" + + @validator("steam_playtime_theme") + def check_theme(cls, v): + v = (v or "light").strip().lower() + if v not in ("light", "dark"): + raise ValueError("steam_playtime_theme 只能是 light 或 dark") + return v + + @validator("steam_api_key", pre=True) + def ensure_list(cls, v): + if isinstance(v, str): + return [v] + return v + diff --git a/hexi/plugins/nonebot_plugin_steam_info/data_source.py b/hexi/plugins/nonebot_plugin_steam_info/data_source.py new file mode 100644 index 0000000..8fc32a5 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_steam_info/data_source.py @@ -0,0 +1,457 @@ +import json +import sqlite3 +from contextlib import closing +import time +from pathlib import Path +import httpx +from PIL import Image +from nonebot.log import logger +from typing import Any, List, Dict, Optional, Tuple + +from .models import Player, ProcessedPlayer + + +def _game_key(player: Player) -> Optional[tuple]: + """玩家当前游戏的稳定标识:gameid 优先,非 Steam 游戏(无 gameid)回退到游戏名""" + gameid = player.get("gameid") + if gameid: + return ("appid", str(gameid)) + name = player.get("gameextrainfo") + if name: + return ("name", name) + return None + + +def _connect(db_path: Path) -> sqlite3.Connection: + db_path.parent.mkdir(parents=True, exist_ok=True) + # isolation_level=None:自动提交模式,配合 closing 确保写入持久化 + return sqlite3.connect(str(db_path), isolation_level=None) + + +class BindData: + """绑定数据:parent_id + user_id -> {user_id, steam_id, nickname}""" + + def __init__(self, db_path: Path) -> None: + self.content: Dict[str, List[Dict[str, str]]] = {} + self._db_path = Path(db_path) + + with closing(_connect(self._db_path)) as conn: + conn.execute( + "CREATE TABLE IF NOT EXISTS bind_data (" + "parent_id TEXT NOT NULL," + "user_id TEXT NOT NULL," + "steam_id TEXT NOT NULL," + "nickname TEXT," + "PRIMARY KEY (parent_id, user_id))" + ) + self._migrate_json() + self._load() + + def _migrate_json(self) -> None: + json_path = self._db_path.parent / "bind_data.json" + if json_path.is_file(): + try: + data = json.loads(json_path.read_text("utf-8")) + with closing(_connect(self._db_path)) as conn: + for pid, entries in data.items(): + for entry in entries: + conn.execute( + "INSERT OR REPLACE INTO bind_data " + "(parent_id, user_id, steam_id, nickname) VALUES (?, ?, ?, ?)", + ( + pid, + entry.get("user_id", ""), + entry.get("steam_id", ""), + entry.get("nickname"), + ), + ) + json_path.rename(json_path.with_suffix(".json.bak")) + except Exception: + pass + + def _load(self) -> None: + with closing(_connect(self._db_path)) as conn: + rows = conn.execute( + "SELECT parent_id, user_id, steam_id, nickname FROM bind_data" + ).fetchall() + self.content = {} + for pid, uid, sid, nick in rows: + self.content.setdefault(pid, []).append( + {"user_id": uid, "steam_id": sid, "nickname": nick} + ) + + def save(self) -> None: + with closing(_connect(self._db_path)) as conn: + conn.execute("DELETE FROM bind_data") + for pid, entries in self.content.items(): + for entry in entries: + conn.execute( + "INSERT OR REPLACE INTO bind_data " + "(parent_id, user_id, steam_id, nickname) VALUES (?, ?, ?, ?)", + ( + pid, + entry.get("user_id", ""), + entry.get("steam_id", ""), + entry.get("nickname"), + ), + ) + + def add(self, parent_id: str, content: Dict[str, str]) -> None: + if parent_id not in self.content: + self.content[parent_id] = [content] + else: + self.content[parent_id].append(content) + + def remove(self, parent_id: str, user_id: str) -> None: + if parent_id not in self.content: + return + for data in self.content[parent_id]: + if data["user_id"] == user_id: + self.content[parent_id].remove(data) + break + + def update(self, parent_id: str, content: Dict[str, str]) -> None: + self.content[parent_id] = content + + def get(self, parent_id: str, user_id: str) -> Optional[Dict[str, str]]: + if parent_id not in self.content: + return None + for data in self.content[parent_id]: + if data["user_id"] == user_id: + return data + return None + + def get_by_steam_id( + self, parent_id: str, steam_id: str + ) -> Optional[Dict[str, str]]: + if parent_id not in self.content: + return None + for data in self.content[parent_id]: + if data["steam_id"] == steam_id: + return data + return None + + def get_all(self, parent_id: str) -> List[str]: + if parent_id not in self.content: + return [] + result = [] + for data in self.content[parent_id]: + if not data["steam_id"] in result: + result.append(data["steam_id"]) + return result + + def get_all_steam_id(self) -> List[str]: + result = [] + for parent_id in self.content: + for data in self.content[parent_id]: + if not data["steam_id"] in result: + result.append(data["steam_id"]) + return result + + +class SteamInfoData: + """播报状态:steamid -> 玩家数据(JSON 列存储,保留完整结构)""" + + def __init__(self, db_path: Path) -> None: + self.content: List[ProcessedPlayer] = [] + self._by_id: Dict[str, ProcessedPlayer] = {} + self._db_path = Path(db_path) + + with closing(_connect(self._db_path)) as conn: + conn.execute( + "CREATE TABLE IF NOT EXISTS steam_info (" + "steamid TEXT PRIMARY KEY," + "data TEXT NOT NULL)" + ) + self._migrate_json() + self._load() + + def _migrate_json(self) -> None: + json_path = self._db_path.parent / "steam_info.json" + if json_path.is_file(): + try: + data = json.loads(json_path.read_text("utf-8")) + if isinstance(data, list): + with closing(_connect(self._db_path)) as conn: + for player in data: + conn.execute( + "INSERT OR REPLACE INTO steam_info (steamid, data) VALUES (?, ?)", + (player["steamid"], json.dumps(player, ensure_ascii=False)), + ) + json_path.rename(json_path.with_suffix(".json.bak")) + except Exception: + pass + + def _load(self) -> None: + with closing(_connect(self._db_path)) as conn: + rows = conn.execute("SELECT data FROM steam_info").fetchall() + self.content = [json.loads(r[0]) for r in rows] + self._rebuild_index() + + def _rebuild_index(self) -> None: + """重建 steamid -> 玩家 索引,get_player 由线性扫描变 O(1)""" + self._by_id = {p["steamid"]: p for p in self.content} + + def save(self) -> None: + with closing(_connect(self._db_path)) as conn: + conn.execute("DELETE FROM steam_info") + for player in self.content: + conn.execute( + "INSERT OR REPLACE INTO steam_info (steamid, data) VALUES (?, ?)", + (player["steamid"], json.dumps(player, ensure_ascii=False)), + ) + + def update(self, player: ProcessedPlayer) -> None: + self.content.append(player) + self._by_id[player["steamid"]] = player + + def update_by_players(self, players: List[Player]): + # 将 Player 转换为 ProcessedPlayer + processed_players = [] + for player in players: + old_player = self.get_player(player["steamid"]) + + if old_player is None: + if player.get("gameextrainfo") is not None: + player["game_start_time"] = int(time.time()) + else: + player["game_start_time"] = None + processed_players.append(player) + else: + old_key = _game_key(old_player) + new_key = _game_key(player) + if new_key is not None and old_key is None: + # 开始游戏 + player["game_start_time"] = int(time.time()) + elif new_key is None and old_key is not None: + # 结束游戏 + player["game_start_time"] = None + elif new_key is not None and old_key is not None: + # 继续游戏:游戏不变则沿用开始时间,换游戏则从新游戏开始时重新计时 + if new_key == old_key: + player["game_start_time"] = old_player["game_start_time"] + else: + player["game_start_time"] = int(time.time()) + else: + player["game_start_time"] = None + processed_players.append(player) + + self.content = processed_players + self._rebuild_index() + + def get_player(self, steam_id: str) -> Optional[Player]: + return self._by_id.get(steam_id) + + def get_players(self, steam_ids: List[str]) -> List[Player]: + id_set = set(steam_ids) + result = [] + for player in self.content: + if player["steamid"] in id_set: + result.append(player) + return result + + def compare( + self, old_players: List[Player], new_players: List[Player] + ) -> List[Dict[str, Any]]: + result = [] + + old_players_dict = {player["steamid"]: player for player in old_players} + + for player in new_players: + old_player = old_players_dict.get(player["steamid"]) + if old_player is None: + continue + + new_game = _game_key(player) + old_game = _game_key(old_player) + + if new_game == old_game: + continue + + if new_game is not None and old_game is None: + entry_type = "start" + elif new_game is None and old_game is not None: + entry_type = "stop" + elif new_game is not None and old_game is not None: + entry_type = "change" + else: + entry_type = "error" + + result.append( + { + "type": entry_type, + "player": player, + "old_player": old_player, + } + ) + + return result + + +class ParentData: + """群信息:parent_id -> 群名 + 更新时间,头像图片存文件 + + 群名/群头像一律从 QQ 自动获取并缓存(steamupdate 指令已移除), + updated_at 用于判断缓存是否过期(默认 7 天自动刷新)。 + """ + + def __init__(self, db_path: Path) -> None: + self.content: Dict[str, str] = {} + self._updated_at: Dict[str, int] = {} + self._db_path = Path(db_path) + self._avatar_dir = self._db_path.parent / "avatars" + + with closing(_connect(self._db_path)) as conn: + conn.execute( + "CREATE TABLE IF NOT EXISTS parent_data (" + "parent_id TEXT PRIMARY KEY," + "name TEXT NOT NULL," + "updated_at INTEGER)" + ) + # 旧表迁移:补充 updated_at 列 + cols = [row[1] for row in conn.execute("PRAGMA table_info(parent_data)")] + if "updated_at" not in cols: + conn.execute("ALTER TABLE parent_data ADD COLUMN updated_at INTEGER") + self._migrate_json() + self._load() + + def _migrate_json(self) -> None: + json_path = self._db_path.parent / "parent_data.json" + if json_path.is_file(): + try: + data = json.loads(json_path.read_text("utf-8")) + self.content = {pid: name for pid, name in data.items()} + self.save() + json_path.rename(json_path.with_suffix(".json.bak")) + except Exception: + pass + # 迁移旧头像文件(data 根目录 -> avatars/ 子目录) + self._avatar_dir.mkdir(parents=True, exist_ok=True) + for old in self._db_path.parent.glob("*.png"): + try: + old.rename(self._avatar_dir / old.name) + except OSError: + pass + + def _load(self) -> None: + with closing(_connect(self._db_path)) as conn: + rows = conn.execute( + "SELECT parent_id, name, updated_at FROM parent_data" + ).fetchall() + self.content = {pid: name for pid, name, _ in rows} + self._updated_at = {pid: ts or 0 for pid, _, ts in rows} + + def save(self) -> None: + with closing(_connect(self._db_path)) as conn: + conn.execute("DELETE FROM parent_data") + for pid, name in self.content.items(): + conn.execute( + "INSERT OR REPLACE INTO parent_data " + "(parent_id, name, updated_at) VALUES (?, ?, ?)", + (pid, name, self._updated_at.get(pid, 0)), + ) + + def _download_avatar(self, parent_id: str, avatar_path: Path) -> None: + """头像缓存丢失时从 QQ 群头像接口重新下载""" + try: + url = f"http://p.qlogo.cn/gh/{parent_id}/{parent_id}/640" + resp = httpx.get(url, timeout=10) + if resp.status_code == 200 and resp.content: + self._avatar_dir.mkdir(parents=True, exist_ok=True) + avatar_path.write_bytes(resp.content) + except Exception as e: + logger.warning(f"群头像重新下载失败 {parent_id}: {e}") + + def update(self, parent_id: str, avatar: Image.Image, name: str) -> None: + self.content[parent_id] = name + self._updated_at[parent_id] = int(time.time()) + self.save() + # 保存图片 + self._avatar_dir.mkdir(parents=True, exist_ok=True) + avatar.save(self._avatar_dir / f"{parent_id}.png") + + def update_name(self, parent_id: str, name: str) -> None: + """只更新群名,不动头像(头像下载失败时的降级路径)""" + self.content[parent_id] = name + self._updated_at[parent_id] = int(time.time()) + self.save() + + def is_fresh(self, parent_id: str, ttl: int = 7 * 24 * 3600) -> bool: + """缓存是否新鲜(默认 7 天内自动刷新过)""" + return ( + parent_id in self.content + and int(time.time()) - self._updated_at.get(parent_id, 0) < ttl + ) + + def get(self, parent_id: str) -> Tuple[Image.Image, str]: + if parent_id not in self.content: + return ( + Image.open(Path(__file__).parent / "res/unknown_avatar.jpg"), + parent_id, + ) + avatar_path = self._avatar_dir / f"{parent_id}.png" + if not avatar_path.is_file(): + # 头像缓存丢失,自动重新下载 + self._download_avatar(parent_id, avatar_path) + if avatar_path.is_file(): + return Image.open(avatar_path), self.content[parent_id] + # 下载失败,降级默认头像 + return ( + Image.open(Path(__file__).parent / "res/unknown_avatar.jpg"), + self.content[parent_id], + ) + + +class DisableParentData: + """储存禁用 Steam 通知的 parent""" + + def __init__(self, db_path: Path) -> None: + self.content: List[str] = [] + self._db_path = Path(db_path) + + with closing(_connect(self._db_path)) as conn: + conn.execute( + "CREATE TABLE IF NOT EXISTS disable_parent_data (" + "parent_id TEXT PRIMARY KEY)" + ) + self._migrate_json() + self._load() + + def _migrate_json(self) -> None: + json_path = self._db_path.parent / "disable_parent_data.json" + if json_path.is_file(): + try: + data = json.loads(json_path.read_text("utf-8")) + if isinstance(data, list): + self.content = [str(pid) for pid in data] + self.save() + json_path.rename(json_path.with_suffix(".json.bak")) + except Exception: + pass + + def _load(self) -> None: + with closing(_connect(self._db_path)) as conn: + rows = conn.execute("SELECT parent_id FROM disable_parent_data").fetchall() + self.content = [r[0] for r in rows] + + def save(self) -> None: + with closing(_connect(self._db_path)) as conn: + conn.execute("DELETE FROM disable_parent_data") + for pid in self.content: + conn.execute( + "INSERT OR REPLACE INTO disable_parent_data (parent_id) VALUES (?)", + (pid,), + ) + + def add(self, parent_id: str) -> None: + if parent_id not in self.content: + self.content.append(parent_id) + self.save() + + def remove(self, parent_id: str) -> None: + if parent_id in self.content: + self.content.remove(parent_id) + self.save() + + def is_disabled(self, parent_id: str) -> bool: + return parent_id in self.content diff --git a/hexi/plugins/nonebot_plugin_steam_info/draw.py b/hexi/plugins/nonebot_plugin_steam_info/draw.py new file mode 100644 index 0000000..19455fc --- /dev/null +++ b/hexi/plugins/nonebot_plugin_steam_info/draw.py @@ -0,0 +1,1165 @@ +import numpy as np +from functools import lru_cache +from io import BytesIO +from pathlib import Path +from typing import List, Dict, Tuple +from colorsys import rgb_to_hsv, hsv_to_rgb +from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageEnhance + +from .utils import hex_to_rgb +from .models import DrawPlayerStatusData, Achievements + + +WIDTH = 400 +PARENT_AVATAR_SIZE = 72 +MEMBER_AVATAR_SIZE = 50 + +# 游戏图标与玩家信息的统一水平坐标 +GAME_ICON_X = 12 +GAME_ICON_SIZE = 26 +GAME_NAME_X = GAME_ICON_X + GAME_ICON_SIZE + 12 # 50:图标和游戏/玩家信息对齐点 +PLAYER_AVATAR_X = GAME_NAME_X - 2 # 48:头像带边框,内部头像落在 GAME_NAME_X +PLAYER_NAME_X = GAME_NAME_X + MEMBER_AVATAR_SIZE + 18 # 118:玩家昵称/游戏名/状态统一左对齐 + +unknown_avatar_path = Path(__file__).parent / "res/unknown_avatar.jpg" +parent_status_path = Path(__file__).parent / "res/parent_status.png" +friends_search_path = Path(__file__).parent / "res/friends_search.png" +busy_path = Path(__file__).parent / "res/busy.png" +zzz_online_path = Path(__file__).parent / "res/zzz_online.png" +zzz_gaming_path = Path(__file__).parent / "res/zzz_gaming.png" +gaming_path = Path(__file__).parent / "res/gaming.png" + +font_regular_path = None +font_light_path = None +font_bold_path = None + + +def set_font_paths(regular_path, light_path, bold_path): + global font_regular_path, font_light_path, font_bold_path + base_dir = Path().cwd() + font_regular_path = str((base_dir / regular_path).resolve()) + font_light_path = str((base_dir / light_path).resolve()) + font_bold_path = str((base_dir / bold_path).resolve()) + + +def check_font(): + if not Path(font_regular_path).exists(): + raise FileNotFoundError(f"Font file {font_regular_path} not found.") + if not Path(font_light_path).exists(): + raise FileNotFoundError(f"Font file {font_light_path} not found.") + if not Path(font_bold_path).exists(): + raise FileNotFoundError(f"Font file {font_bold_path} not found.") + + +@lru_cache(maxsize=None) +def get_font(path: str, size: int) -> ImageFont.FreeTypeFont: + """按 (路径, 字号) 缓存字体,避免每次绘制都重新解析字体文件""" + return ImageFont.truetype(path, size) + + +personastate_colors = { + 0: (hex_to_rgb("969697"), hex_to_rgb("656565")), + 1: (hex_to_rgb("6dcef5"), hex_to_rgb("4c91ac")), + 2: (hex_to_rgb("6dcef5"), hex_to_rgb("4c91ac")), + 3: (hex_to_rgb("45778e"), hex_to_rgb("365969")), + 4: (hex_to_rgb("6dcef5"), hex_to_rgb("4c91ac")), + 5: (hex_to_rgb("6dcef5"), hex_to_rgb("4c91ac")), + 6: (hex_to_rgb("6dcef5"), hex_to_rgb("4c91ac")), +} + + +def avatar_with_border( + avatar: Image.Image, border_width: int = 2, border_color=(255, 255, 255) +) -> Image.Image: + """给头像添加边框,返回比原头像大 2*border_width 的图像""" + width, height = avatar.size + bordered = Image.new( + "RGB", (width + border_width * 2, height + border_width * 2), border_color + ) + bordered.paste(avatar, (border_width, border_width)) + return bordered + + +def vertically_concatenate_images(images: List[Image.Image]) -> Image.Image: + widths, heights = zip(*(i.size for i in images)) + total_width = max(widths) + total_height = sum(heights) + + new_image = Image.new("RGB", (total_width, total_height)) + + y_offset = 0 + for image in images: + new_image.paste(image, (0, y_offset)) + y_offset += image.size[1] + + return new_image + + +def _truncate_with_ellipsis( + draw: ImageDraw.ImageDraw, text: str, font, max_width: int +) -> str: + """将文本按 max_width 省略号截断,返回最终绘制文本""" + ellipsis = "…" + truncated = "" + for ch in text: + if draw.textlength(truncated + ch + ellipsis, font=font) > max_width: + break + truncated += ch + return truncated + ellipsis + + +def _fit_name_nick( + draw: ImageDraw.ImageDraw, + name: str, + nickname: str, + name_font, + nick_font, + gap: int, + max_width: int, +) -> Tuple[str, str]: + """在 max_width 内排布 [主名][群昵称],返回 (主名绘制文本, 群昵称绘制文本) + + 主名优先: 主名过长时省略号截断主名,不再画群昵称; + 主名放得下时,群昵称只取剩余宽度,放不下则返回空串。 + """ + if draw.textlength(name, font=name_font) > max_width: + return _truncate_with_ellipsis(draw, name, name_font, max_width), "" + if not nickname: + return name, "" + available = max_width - draw.textlength(name, font=name_font) - gap + if available <= 0: + return name, "" + if draw.textlength(nickname, font=nick_font) <= available: + return name, nickname + return name, _truncate_with_ellipsis(draw, nickname, nick_font, available) + + +def draw_start_gaming( + avatar: Image.Image, friend_name: str, game_name: str, nickname: str = None +): + canvas = Image.open(gaming_path) + canvas.paste(avatar.resize((66, 66), Image.BICUBIC), (15, 20)) + + # 绘制名称:steam 昵称优先,群昵称小字挂尾,超宽省略号截断,避免画出图片外 + draw = ImageDraw.Draw(canvas) + name_font = get_font(font_regular_path, 19) + nick_font = get_font(font_light_path, 13) + name_drawn, nick_drawn = _fit_name_nick( + draw, friend_name, nickname or "", name_font, nick_font, 6, + canvas.width - 104 - 10, + ) + draw.text((104, 14), name_drawn, font=name_font, fill=hex_to_rgb("e3ffc2")) + if nick_drawn: + draw.text( + (104 + draw.textlength(name_drawn, font=name_font) + 6, 15), + nick_drawn, + font=nick_font, + fill=hex_to_rgb("969696"), + ) + + # 绘制"正在玩" + draw.text( + (103, 42), + "正在玩", + font=get_font(font_regular_path, 17), + fill=hex_to_rgb("969696"), + ) + + # 绘制游戏名称 + draw.text( + (104, 66), + game_name, + font=get_font(font_bold_path, 14), + fill=hex_to_rgb("91c257"), + ) + + return canvas + + +def draw_parent_status(parent_avatar: Image.Image, parent_name: str) -> Image.Image: + parent_avatar = parent_avatar.resize( + (PARENT_AVATAR_SIZE, PARENT_AVATAR_SIZE), Image.BICUBIC + ) + + canvas = Image.open(parent_status_path).resize((WIDTH, 120), Image.BICUBIC) + + draw = ImageDraw.Draw(canvas) + + # 在左下角 (16, 16) 处绘制头像 + avatar_height = 120 - 16 - PARENT_AVATAR_SIZE + canvas.paste(avatar_with_border(parent_avatar), (14, avatar_height - 2)) + + # 绘制名称 + draw.text( + (16 + PARENT_AVATAR_SIZE + 16, avatar_height + 12), + parent_name, + font=get_font(font_bold_path, 20), + fill=hex_to_rgb("6dcff6"), + ) + + # 绘制状态 + draw.text( + (16 + PARENT_AVATAR_SIZE + 16, avatar_height + 20 + 16), + "在线", + font=get_font(font_light_path, 18), + fill=hex_to_rgb("4c91ac"), + ) + + return canvas + + +def draw_friends_search() -> Image.Image: + canvas = Image.new("RGB", (WIDTH, 50), hex_to_rgb("434953")) + + friends_search = Image.open(friends_search_path) + + canvas.paste(friends_search, (WIDTH - friends_search.width, 0)) + + draw = ImageDraw.Draw(canvas) + + draw.text( + (24, 10), + "好友", + hex_to_rgb("b7ccd5"), + font=get_font(font_regular_path, 20), + ) + + return canvas + + +def draw_friend_status( + friend_avatar: Image.Image, + friend_name: str, + status: str, + personastate: int, + nickname: str = None, +) -> Image.Image: + friend_avatar = friend_avatar.resize( + (MEMBER_AVATAR_SIZE, MEMBER_AVATAR_SIZE), Image.BICUBIC + ) + + canvas = Image.new("RGB", (WIDTH, 64), hex_to_rgb("1e2024")) + + draw = ImageDraw.Draw(canvas) + + # 状态图标(忙碌/ZZZ)插在 steam 昵称与群昵称之间,先预留其宽度 + name_font = get_font(font_bold_path, 20) + nick_font = get_font(font_light_path, 13) + name_x = 22 + MEMBER_AVATAR_SIZE + 18 + icon = None + if personastate == 2: + icon = Image.open(busy_path) + elif personastate == 4: + icon = Image.open(zzz_online_path if status == "在线" else zzz_gaming_path) + # 让 zzz 图标与名字之间留出更明显的间距 + icon_gap = 12 + icon_space = icon.width + 2 * icon_gap if icon else 0 + + # 主名优先、群昵称小字挂尾,超宽均省略号截断,避免画出图片外 + name_drawn, nick_drawn = _fit_name_nick( + draw, friend_name, nickname or "", name_font, nick_font, 6, + WIDTH - name_x - 10 - icon_space, + ) + + # 绘制头像 + canvas.paste(avatar_with_border(friend_avatar), (20, 6)) + + # 忙碌/打盹沿用"在线"的配色(原实现通过递归 personastate=1 达到同样效果) + if personastate in (2, 4): + draw_state = 1 + else: + draw_state = personastate + + if status != "在线" and draw_state == 1: + fill = (hex_to_rgb("e3ffc2"), hex_to_rgb("8ebe56")) + elif status != "离开" and draw_state == 3: + fill = (hex_to_rgb("e3ffc2"), hex_to_rgb("8ebe56")) + else: + fill = personastate_colors[draw_state] + + # 绘制名称:steam 昵称 -> 状态图标 -> 群昵称 + x = name_x + draw.text((x, 12), name_drawn, font=name_font, fill=fill[0]) + x += int(draw.textlength(name_drawn, font=name_font)) + if icon: + canvas.paste(icon, (x + icon_gap, 18)) + x += icon_gap + icon.width + icon_gap + if nick_drawn: + draw.text((x, 13), nick_drawn, font=nick_font, fill=hex_to_rgb("969696")) + + # 绘制状态 + draw.text( + (22 + MEMBER_AVATAR_SIZE + 16, 36), + status, + font=get_font(font_regular_path, 18), + fill=fill[1], + ) + + return canvas + + +def _draw_game_group(members: list[dict]) -> Image.Image: + """绘制同一款游戏的分组卡片:游戏图标 + 游戏名 + 人数 + 好友列表""" + header_height = 52 + game_name = members[0].get("game_name") or members[0].get("status") or "游戏中" + icon = members[0].get("game_icon") + + canvas = Image.new( + "RGB", + (WIDTH, header_height + 64 * len(members)), + hex_to_rgb("1e2024"), + ) + draw = ImageDraw.Draw(canvas) + + # 游戏图标(Steam header.jpg 是宽图,先居中裁成正方形再缩放) + x = GAME_ICON_X + if icon: + icon_w, icon_h = icon.size + if icon_w > icon_h: + left = (icon_w - icon_h) // 2 + icon = icon.crop((left, 0, left + icon_h, icon_h)) + elif icon_h > icon_w: + top = (icon_h - icon_w) // 2 + icon = icon.crop((0, top, icon_w, top + icon_w)) + icon = icon.resize((GAME_ICON_SIZE, GAME_ICON_SIZE), Image.BICUBIC) + canvas.paste(icon, (x, (header_height - GAME_ICON_SIZE) // 2)) + x += GAME_ICON_SIZE + 12 + + # 游戏名(与玩家信息的水平对齐点一致) + game_font = get_font(font_bold_path, 16) + max_game_width = WIDTH - GAME_NAME_X - 100 + if draw.textlength(game_name, font=game_font) > max_game_width: + game_name = _truncate_with_ellipsis(draw, game_name, game_font, max_game_width) + draw.text( + (GAME_NAME_X, header_height // 2 - 10), + game_name, + font=game_font, + fill=hex_to_rgb("8f989b"), + ) + + # 右侧人数 + count_text = f"{len(members)} 人在玩" + count_font = get_font(font_regular_path, 14) + draw.text( + ( + WIDTH - draw.textlength(count_text, font=count_font) - 12, + header_height // 2 - 9, + ), + count_text, + font=count_font, + fill=hex_to_rgb("67665c"), + ) + + # 好友行(头像与游戏名水平对齐,形成树结构) + friend_indent = GAME_NAME_X - 22 # draw_friend_status 内部头像起点为 22 + for i, member in enumerate(members): + status = member["status"] + if status in ("在线", "未知", "") and member.get("game_name"): + status = member["game_name"] + row = draw_friend_status( + member["avatar"], + member["name"], + status, + member["personastate"], + member.get("nickname"), + ) + canvas.paste(row, (friend_indent, header_height + 64 * i)) + + return canvas + + +def draw_single_game_friend( + game_icon: Image.Image | None, + friend_avatar: Image.Image, + friend_name: str, + game_name: str, + status: str, + personastate: int, + nickname: str = None, +) -> Image.Image: + """单人游戏行:游戏图标 + 头像 + 昵称 + 游戏名 + 状态""" + row_height = 76 + icon_size = GAME_ICON_SIZE + canvas = Image.new("RGB", (WIDTH, row_height), hex_to_rgb("1e2024")) + draw = ImageDraw.Draw(canvas) + + # 游戏图标(最左,和多人组头一致) + if game_icon: + icon_w, icon_h = game_icon.size + if icon_w > icon_h: + left = (icon_w - icon_h) // 2 + game_icon = game_icon.crop((left, 0, left + icon_h, icon_h)) + elif icon_h > icon_w: + top = (icon_h - icon_w) // 2 + game_icon = game_icon.crop((0, top, icon_w, top + icon_w)) + game_icon = game_icon.resize((icon_size, icon_size), Image.BICUBIC) + canvas.paste(game_icon, (GAME_ICON_X, (row_height - icon_size) // 2)) + + # 头像(与多人玩家信息对齐到 GAME_NAME_X) + friend_avatar = friend_avatar.resize( + (MEMBER_AVATAR_SIZE, MEMBER_AVATAR_SIZE), Image.BICUBIC + ) + canvas.paste(avatar_with_border(friend_avatar), (PLAYER_AVATAR_X, 8)) + + # 名称行:steam 昵称 -> 状态图标 -> 群昵称 + name_font = get_font(font_bold_path, 18) + nick_font = get_font(font_light_path, 13) + name_x = PLAYER_NAME_X + icon = None + if personastate == 2: + icon = Image.open(busy_path) + elif personastate == 4: + icon = Image.open(zzz_online_path if status == "在线" else zzz_gaming_path) + icon_gap = 12 + icon_space = icon.width + 2 * icon_gap if icon else 0 + name_drawn, nick_drawn = _fit_name_nick( + draw, friend_name, nickname or "", name_font, nick_font, 6, + WIDTH - name_x - 10 - icon_space, + ) + + if personastate in (2, 4): + draw_state = 1 + else: + draw_state = personastate + if status != "在线" and draw_state == 1: + fill = (hex_to_rgb("e3ffc2"), hex_to_rgb("8ebe56")) + elif status != "离开" and draw_state == 3: + fill = (hex_to_rgb("e3ffc2"), hex_to_rgb("8ebe56")) + else: + fill = personastate_colors[draw_state] + + x = name_x + draw.text((x, 8), name_drawn, font=name_font, fill=fill[0]) + x += int(draw.textlength(name_drawn, font=name_font)) + if icon: + canvas.paste(icon, (x + icon_gap, 14)) + x += icon_gap + icon.width + icon_gap + if nick_drawn: + draw.text((x, 9), nick_drawn, font=nick_font, fill=hex_to_rgb("969696")) + + # 游戏名 + if game_name: + draw.text( + (name_x, 30), + game_name, + font=get_font(font_regular_path, 15), + fill=hex_to_rgb("91c257"), + ) + + # 状态详情(与游戏名相同则不重复画) + if status and status != game_name: + draw.text( + (name_x, 48), + status, + font=get_font(font_regular_path, 14), + fill=hex_to_rgb("969696"), + ) + + return canvas + + +def draw_gaming_friends_status(data: list[dict]) -> Image.Image: + # 按游戏分组:同一游戏的人列在同一个游戏标题下 + groups: dict[tuple, list[dict]] = {} + for d in data: + key = (d.get("gameid"), d.get("game_name") or d.get("status")) + groups.setdefault(key, []).append(d) + + # 排序:多人组按人数降序在前,单人组按游戏名 A-Z 在后 + def _group_name(members: list[dict]) -> str: + return (members[0].get("game_name") or members[0].get("status") or "").lower() + + group_list = list(groups.values()) + multi_groups = [m for m in group_list if len(m) >= 2] + single_groups = [m for m in group_list if len(m) == 1] + multi_groups.sort(key=lambda m: (-len(m), _group_name(m))) + single_groups.sort(key=_group_name) + + parts: list[Image.Image] = [] + for members in multi_groups + single_groups: + if len(members) == 1: + # 一个人玩的游戏:游戏图标 + 头像昵称 + 游戏名 + 状态 + member = members[0] + status = member["status"] + game_name = member.get("game_name") or "" + if status in ("在线", "未知", "") and game_name: + status = game_name + parts.append( + draw_single_game_friend( + member.get("game_icon"), + member["avatar"], + member["name"], + game_name, + status, + member["personastate"], + member.get("nickname"), + ) + ) + else: + parts.append(_draw_game_group(members)) + + if not parts: + return Image.new("RGB", (WIDTH, 64), hex_to_rgb("1e2024")) + return vertically_concatenate_images(parts) + + +def draw_online_friends_status(data: List[Dict[str, str]]) -> Image.Image: + canvas = Image.new( + "RGB", + (WIDTH, 64 + (MEMBER_AVATAR_SIZE + 16) * len(data) + 16), + hex_to_rgb("1e2024"), + ) + + draw = ImageDraw.Draw(canvas) + + # 绘制标题 + draw.text( + (22, 22), + "在线好友", + hex_to_rgb("c5d6d4"), + font=get_font(font_regular_path, 22), + ) + + # 绘制在线人数 + draw.text( + (115, 25), + f"({len(data)})", + hex_to_rgb("67665c"), + font=get_font(font_regular_path, 18), + ) + + # 绘制好友头像和名称 + friends_status_list = [ + draw_friend_status( + d["avatar"], d["name"], d["status"], d["personastate"], d["nickname"] + ) + for d in data + ] + + # 拼接好友头像和名称 + for i, friend_status in enumerate(friends_status_list): + canvas.paste(friend_status, (0, 64 + (MEMBER_AVATAR_SIZE + 16) * i)) + + return canvas + + +def draw_offline_friends_status(data: List[Dict[str, str]]) -> Image.Image: + canvas = Image.new( + "RGB", + (WIDTH, 64 + (MEMBER_AVATAR_SIZE + 16) * len(data) + 16), + hex_to_rgb("1e2024"), + ) + + draw = ImageDraw.Draw(canvas) + + # 绘制标题 + draw.text( + (22, 22), + "离线", + hex_to_rgb("c5d6d4"), + font=get_font(font_regular_path, 22), + ) + + # 绘制离线人数 + draw.text( + (72, 25), + f"({len(data)})", + hex_to_rgb("67665c"), + font=get_font(font_regular_path, 18), + ) + + # 绘制好友头像和名称 + friends_status_list = [ + draw_friend_status( + d["avatar"], d["name"], d["status"], d["personastate"], d["nickname"] + ) + for d in data + ] + + # 拼接好友头像和名称 + for i, friend_status in enumerate(friends_status_list): + canvas.paste(friend_status, (0, 64 + (MEMBER_AVATAR_SIZE + 16) * i)) + + return canvas + + +def draw_friends_status( + parent_avatar: Image.Image, parent_name: str, data: List[Dict[str, str]] +): + data.sort(key=lambda x: x["personastate"]) + + def _is_gaming(d: Dict[str, str]) -> bool: + # 有 gameid 说明确实在游戏里:即使 Steam 没返回详细状态(gameextrainfo), + # 也归入"游戏中"并显示游戏名,符合"具体状态获取不到就显示游戏名字"。 + if d.get("gameid"): + return d["personastate"] in (1, 2, 3, 4) + return ( + (d["personastate"] == 1 and d["status"] != "在线") + or (d["personastate"] == 3 and d["status"] != "离开") + or (d["personastate"] == 4 and d["status"] != "在线") + ) + + parent_status = draw_parent_status(parent_avatar, parent_name) + friends_search = draw_friends_search() + + status_images: List[Image.Image] = [] + height = parent_status.height + friends_search.height + + gaming_data = [d for d in data if _is_gaming(d)] + + if gaming_data: + status_images.append(draw_gaming_friends_status(gaming_data)) + height += status_images[-1].height + + online_data = [ + d + for d in data + if not _is_gaming(d) + and ( + (d["personastate"] == 1 and d["status"] == "在线") + or (d["personastate"] == 3 and d["status"] == "离开") + or (d["personastate"] == 4 and d["status"] == "在线") + or (d["personastate"] in [2, 5, 6]) + ) + ] + # 按 1, 2, 4, 5, 6, 3 的顺序排序 + online_data.sort(key=lambda x: (7 if x["personastate"] == 3 else x["personastate"])) + + if online_data: + status_images.append(draw_online_friends_status(online_data)) + height += status_images[-1].height + + offline_data = [d for d in data if d["personastate"] == 0] + if offline_data: + status_images.append(draw_offline_friends_status(offline_data)) + height += status_images[-1].height + + # 拼合图片 + canvas = Image.new("RGB", (WIDTH, height), hex_to_rgb("1e2024")) + draw = ImageDraw.Draw(canvas) + + canvas.paste(parent_status, (0, 0)) + canvas.paste(friends_search, (0, parent_status.height)) + + y = parent_status.height + friends_search.height + + for i, status_image in enumerate(status_images): + canvas.paste(status_image, (0, y)) + y += status_image.height + + # 绘制分割线 + if i != len(status_images) - 1: + draw.rectangle([0, y - 1, WIDTH, y], fill=hex_to_rgb("333439")) + + return canvas + + +def get_average_color(image: Image.Image) -> tuple[int, int, int]: + """获取图片的平均颜色""" + image_np = np.array(image) + average_color = image_np.mean(axis=(0, 1)).astype(int) + return tuple(average_color) + + +def split_image( + image: Image.Image, rows: int, cols: int +) -> tuple[list[Image.Image], int, int]: + """将图片分割为rows * cols份""" + width, height = image.size + piece_width = width // cols + piece_height = height // rows + pieces = [] + + for r in range(rows): + for c in range(cols): + box = ( + c * piece_width, + r * piece_height, + (c + 1) * piece_width, + (r + 1) * piece_height, + ) + piece = image.crop(box) + pieces.append(piece) + + return pieces, piece_width, piece_height + + +def recolor_image(image: Image.Image, rows: int, cols: int) -> Image.Image: + """分片图片,提取平均颜色后拼接""" + total_average_color = get_average_color(image) # 获取整体平均颜色 + pieces, piece_width, piece_height = split_image(image, rows, cols) + + diameter = min(pieces[0].size) # 以最小边为直径 + radius = diameter // 2 + new_image = Image.new("RGB", image.size, total_average_color) + + for i, piece in enumerate(pieces): + average_color = get_average_color(piece) # 获取每片的平均颜色 + + # 计算放置的位置 + row, col = divmod(i, cols) + x = col * piece_width + piece_width // 2 + y = row * piece_height + piece_height // 2 + + # 画圆 + circle = Image.new("RGBA", (piece_width, piece_height), (0, 0, 0, 0)) + draw = ImageDraw.Draw(circle) + draw.ellipse((0, 0, piece_width, piece_height), fill=average_color) + + # 将圆形图片粘贴到新图片上 + new_image.paste(circle, (x - radius, y - radius), circle) + + new_image = new_image.filter(ImageFilter.SMOOTH) + new_image = new_image.filter(ImageFilter.GaussianBlur(50)) + + return new_image + + +def create_gradient_image( + size: Tuple[int, int], color1: Tuple[int, int, int], color2: Tuple[int, int, int] +) -> Image.Image: + """创建渐变图片""" + # 确保颜色值在 0-255 范围内 + color1 = tuple(max(0, min(255, c)) for c in color1) + color2 = tuple(max(0, min(255, c)) for c in color2) + # 创建一个渐变的线性空间 + gradient_array = np.linspace(color1, color2, size[0]) + + # 将渐变数组的形状调整为 (height, width, 3) + gradient_image = np.tile(gradient_array, (size[1], 1, 1)).astype(np.uint8) + + return Image.fromarray(gradient_image, "RGBA") + + +def create_vertical_gradient_rect(width, height, start_color, end_color): + """ + 创建一个在竖直方向上渐变的矩形图像. + + Args: + width (int): 矩形的宽度 (以像素为单位). + height (int): 矩形的高度 (以像素为单位). + start_color (tuple): 起始颜色,格式为 (R, G, B),每个值范围为 0-255. + end_color (tuple): 结束颜色,格式为 (R, G, B),每个值范围为 0-255. + + Returns: + Image: PIL Image 对象,表示生成的渐变矩形. + """ + if width <= 0 or height <= 0: + return Image.new("RGBA", (1, 1), (0, 0, 0, 0)) + # 确保颜色不超过 0-255 的范围 + start_color = tuple(max(0, min(255, c)) for c in start_color) + end_color = tuple(max(0, min(255, c)) for c in end_color) + + # 使用 NumPy 创建一个线性渐变数组 + gradient_array = np.linspace(start_color, end_color, num=height, dtype=np.uint8) + gradient_array = np.tile(gradient_array[:, np.newaxis, :], (1, width, 1)) + + # 使用 Pillow 创建图像并填充颜色 + image = Image.fromarray(gradient_array) + return image + + +def random_color_offset( + color: Tuple[int, int, int], offset: int +) -> Tuple[int, int, int]: + return tuple( + min(255, max(0, c + np.random.randint(-offset, offset + 1))) for c in color + ) + + +def get_brightest_and_darkest_color( + image: Image.Image, + saturation_threshold: int = 100, + hue_difference_threshold: int = 30, +) -> Tuple[Tuple[int, int, int], Tuple[int, int, int]]: + """获取图片最亮和最暗的颜色""" + # 将RGB图像转换为HSV + img_hsv = np.array(image.convert("HSV")) + + # 设定一个阈值来定义“鲜艳的颜色”,例如饱和度大于150 + vivid_mask = img_hsv[..., 1] > saturation_threshold + + # 获取饱和度较高(鲜艳)的像素索引 + vivid_pixels = img_hsv[vivid_mask] + + if len(vivid_pixels) < 10: + return get_brightest_and_darkest_color(image, saturation_threshold - 10) + + # 在鲜艳的像素中,根据亮度(V通道)找到最亮和最暗的颜色 + brightest_pixel = vivid_pixels[np.argmax(vivid_pixels[..., 2])] + darkest_pixel = vivid_pixels[np.argmin(vivid_pixels[..., 2])] + + # 获取最亮和最暗的颜色的色相差异 + hue_difference = abs(int(brightest_pixel[0]) - int(darkest_pixel[0])) + + # 如果色相差异过小,则尝试寻找新的最暗颜色,直到色相差异大于设定阈值 + if hue_difference < hue_difference_threshold: + possible_dark_pixels = vivid_pixels[vivid_pixels[..., 0] != brightest_pixel[0]] + if len(possible_dark_pixels) > 0: + darkest_pixel = possible_dark_pixels[ + np.argmin(possible_dark_pixels[..., 2]) + ] + + # 将最亮和最暗的像素从HSV转回RGB + brightest_color = ( + Image.fromarray(np.uint8([[brightest_pixel]]), "HSV") + .convert("RGB") + .getpixel((0, 0)) + ) + darkest_color = ( + Image.fromarray(np.uint8([[darkest_pixel]]), "HSV") + .convert("RGB") + .getpixel((0, 0)) + ) + + return brightest_color, darkest_color + + +def draw_game_info( + header: Image.Image, + game_name: str, + game_time: str, + last_play_time: str, + achievements: List[Achievements], + completed_achievement_number: int, + total_achievement_number: int, + achievement_color: Tuple[int, int, int], +) -> Image.Image: + bg = Image.new("RGBA", (880, 110 + 64 + 10), (0, 0, 0, 110)) + header = header.resize((229, 86), Image.BICUBIC) + bg.paste(header, (10, 110 // 2 - header.height // 2)) + + draw = ImageDraw.Draw(bg) + + # 画游戏名 + draw.text( + (260, 10), + game_name, + font=get_font(font_regular_path, 26), + fill=(255, 255, 255), + ) + + # 画最后游玩时间 + font = get_font(font_light_path, 22) + display_text = last_play_time + draw.text( + (int(bg.width - font.getlength(display_text)) - 10, 75), + display_text, + font=font, + fill=(150, 150, 150), + ) + + # 画游戏时间 + font = get_font(font_light_path, 22) + display_text = f"总时数 {game_time}" + draw.text( + (int(bg.width - font.getlength(display_text)) - 10, 50), + display_text, + font=font, + fill=(150, 150, 150), + ) + + if completed_achievement_number is None or total_achievement_number is None: + return bg.crop((0, 0, bg.width, 110)) + + # 画成就 + 64 + 10 + achievement_bg = Image.new("RGBA", (860, 64), achievement_color) + draw_achievement = ImageDraw.Draw(achievement_bg) + + # 画成就进度 + font = get_font(font_light_path, 18) + x = 14 + draw_achievement.text( + (x, 20), + "成就进度", + font=font, + fill=(255, 255, 255, 255), + ) + x += font.getlength("成就进度") + 10 + draw_achievement.text( + (int(x), 20), + f"{completed_achievement_number} / {total_achievement_number}", + font=font, + fill=(130, 130, 130), + ) + x += ( + font.getlength(f"{completed_achievement_number} / {total_achievement_number}") + + 10 + ) + progress_bar = create_progress_bar( + completed_achievement_number / total_achievement_number, achievement_color + ) + achievement_bg.paste(progress_bar, (int(x), 24), progress_bar) + + # 画成就图标 + x = 860 - 48 * 6 - 10 * 6 + for achievement in achievements: + achievement_image = Image.open(BytesIO(achievement["image"])).resize((48, 48)) + achievement_bg.paste(achievement_image, (x, 8)) + x += 48 + 10 + + if completed_achievement_number > 6: + font = get_font(font_regular_path, 22) + display_text = f"+{completed_achievement_number - 5}" + draw_achievement.rectangle((x, 8, x + 48, 56), fill=(34, 34, 34)) + draw_achievement.text( + (x + 24 - font.getlength(display_text) // 2, 18), + display_text, + font=font, + fill=(255, 255, 255), + ) + + bg.paste(achievement_bg, (10, 110), achievement_bg) + return bg + + +def draw_player_status( + player_bg: Image.Image, + player_avatar: Image.Image, + player_name: str, + player_id: str, + player_description: str, + player_last_two_weeks_time: str, # e.g. 10.2 小时 + player_games: List[DrawPlayerStatusData], +): + if isinstance(player_bg, bytes): + player_bg = Image.open(BytesIO(player_bg)) + if isinstance(player_avatar, bytes): + player_avatar = Image.open(BytesIO(player_avatar)) + + bg = recolor_image( + player_bg.crop( + ( + (player_bg.width - 960) // 2, + 0, + (player_bg.width + 960) // 2, + player_bg.height, + ) + ), + 10, + 10, + ) + # 调暗背景 + enhancer = ImageEnhance.Brightness(bg) + bg = enhancer.enhance(0.7) + # bg.size = (960, 1020) + player_avatar = player_avatar.resize((200, 200)) + bg.paste(player_avatar, (40, 40)) + + draw = ImageDraw.Draw(bg) + + # 画头像外框 + draw.rectangle((40, 40, 240, 240), outline=(83, 164, 196), width=3) + + # 画昵称 + draw.text( + (280, 48), + player_name, + font=get_font(font_light_path, 40), + fill=(255, 255, 255), + ) + + # 画ID + draw.text( + (280, 100), + f"好友代码: {player_id}", + font=get_font(font_regular_path, 19), + fill=(191, 191, 191), + ) + + # 画简介 + line_width = 0 + offset = 0 + line = "" + for idx, char in enumerate(player_description): + line += char + line_width += get_font(font_light_path, 22).getlength(char) + if line_width > 640 or idx == len(player_description) - 1 or char == "\n": + draw.text( + (280, 132 + offset), + line, + font=get_font(font_light_path, 22), + fill=(255, 255, 255), + ) + line = "" + offset += 25 + line_width = 0 + if offset >= 25 * 4: + break + + # 画游戏 + + brightest_color, darkest_color = get_brightest_and_darkest_color(player_bg) + brightest_color = tuple(map(lambda x: x - 30 if x >= 30 else 0, brightest_color)) + darkest_color = tuple( + map(lambda x: x + 30 if x <= 255 - 30 else 255, darkest_color) + ) + brightest_color = (brightest_color[0], brightest_color[1], brightest_color[2], 128) + brightest_color = random_color_offset(brightest_color, 20) + darkest_color = (darkest_color[0], darkest_color[1], darkest_color[2], 128) + darkest_color = random_color_offset(darkest_color, 20) + + # 画游戏信息 + hsv_achievement_color = rgb_to_hsv(*brightest_color[:3]) + achievement_color = tuple( + map( + int, + hsv_to_rgb( + hsv_achievement_color[0], + hsv_achievement_color[1] * 0.85, + hsv_achievement_color[2] * 0.6, + ), + ) + ) + game_images: List[Image.Image] = [] + for idx, game in enumerate(player_games): + game_image = Image.open(BytesIO(game["game_header"])) + game_info = draw_game_info( + game_image, + game["game_name"], + game["game_time"], + game["last_play_time"], + game["achievements"], + game["completed_achievement_number"], + game["total_achievement_number"], + achievement_color, + ) + game_images.append(game_info) + + # 画半透明黑色背景 + bg_game = Image.new( + "RGBA", (920, 106 + sum([game_image.height + 26 for game_image in game_images])) + ) + draw_game = ImageDraw.Draw(bg_game) + draw_game.rectangle( + ( + 0, + 0, + 920, + bg_game.height, + ), + fill=(0, 0, 0, 120), + ) + bg.paste(bg_game, (20, 272), bg_game) + + # 画渐变条 + gradient = create_gradient_image((920, 50), brightest_color, darkest_color) + bg.paste(gradient, (20, 272), gradient) + + # 画渐变条的文字:最新动态,最近游戏 + draw.text( + (34, 279), + "最新动态", + font=get_font(font_light_path, 26), + fill=(255, 255, 255), + ) + if player_last_two_weeks_time is not None: + width = get_font(font_light_path, 26).getlength( + player_last_two_weeks_time + ) + draw.text( + (960 - width - 34, 279), + player_last_two_weeks_time, + font=get_font(font_light_path, 26), + fill=(255, 255, 255), + ) + + y = 350 + for idx, game_image in enumerate(game_images): + bg.paste( + game_image, + ((920 - game_image.width) // 2 + 20, y), + game_image.convert("RGBA"), + ) + y += game_image.height + 26 + + player_bg.paste(bg, ((player_bg.width - 960) // 2, 0), bg.convert("RGBA")) + + return player_bg + + +def rounded_rectangle( + image: Image.Image, + radius: int, + border=False, + border_width=0, + border_color=(0, 0, 0), +): + """ + 将给定的Image.Image对象切割为圆角矩形。 + + Args: + image: 一个PIL Image对象。 + radius: 圆角半径,单位为像素。 + border: 是否需要边框,默认为False。 + border_width: 边框宽度,单位为像素,默认为0。 + border_color: 边框颜色,RGB元组,默认为黑色(0, 0, 0)。 + + Returns: + 一个PIL Image对象,表示切割后的圆角矩形图像。 + """ + + width, height = image.size + + image_ = Image.new("RGBA", (width + 1, height + 1), (0, 0, 0, 0)) + image_.paste(image, (0, 0), image.convert("RGBA")) + + # 创建一个圆角矩形的遮罩 + result = Image.new("RGBA", (width + 1, height + 1), (0, 0, 0, 0)) + mask = Image.new("L", (width + 1, height + 1), 0) + draw = ImageDraw.Draw(mask) + image_draw = ImageDraw.Draw(result) + + # 绘制圆角矩形 + draw.rounded_rectangle((0, 0, width, height), radius=radius, fill=255) + + # 应用遮罩到原始图像 + result.paste(image_, (0, 0), mask) + + # 添加边框 (如果需要) + if border: + image_draw.rounded_rectangle( + (0, 0, width, height), + radius=radius, + outline=border_color, + width=border_width, + ) + + return result + + +def create_progress_bar( + progress: float, color: Tuple[int, int, int], width=186, height=16 +): + color_hsv = rgb_to_hsv(*color) + + # 外条 + bar_color = tuple( + map(int, hsv_to_rgb(color_hsv[0], color_hsv[1], color_hsv[2] * 0.8)) + ) + border_color = tuple(map(lambda x: max(x - 20, 0), color)) + border_image = rounded_rectangle( + Image.new("RGBA", (width, height), bar_color), + 8, + border=True, + border_width=1, + border_color=border_color, + ) + + # 内条 + bar_color_top = tuple( + map(int, hsv_to_rgb(color_hsv[0], color_hsv[1] / 2, color_hsv[2] * 5 / 2)) + ) + bar_color_bottem = tuple( + map(int, hsv_to_rgb(color_hsv[0], color_hsv[1] / 2, color_hsv[2])) + ) + + bar_image = create_vertical_gradient_rect( + int(width * progress) - 6, height - 4, bar_color_top, bar_color_bottem + ) + bar_image = rounded_rectangle(bar_image, 6) + + # 合并 + border_image.paste(bar_image, (3, 2), bar_image) + + return border_image diff --git a/hexi/plugins/nonebot_plugin_steam_info/html_playtime.py b/hexi/plugins/nonebot_plugin_steam_info/html_playtime.py new file mode 100644 index 0000000..febb7d4 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_steam_info/html_playtime.py @@ -0,0 +1,338 @@ +"""使用 Playwright 渲染 HTML 模板生成游玩时长表图片 + +浏览器为进程级单例,首次调用时懒加载; +任何一步失败都会抛出异常,由调用方(命令处理器)回退到文本格式。 +""" + +import asyncio +import base64 +import datetime +import html +import json +import math +import os +import tempfile +from io import BytesIO +from pathlib import Path +from typing import Any, List, Optional + +from PIL import Image +from nonebot.log import logger + +from . import draw as draw_util + +TEMPLATE_PATH = Path(__file__).parent / "res" / "playtime_template.html" +ECHARTS_PATH = Path(__file__).parent / "res" / "echarts.min.js" + +# ---- 主题色板:CSS 变量注入模板 :root,ECharts 颜色同样读 CSS 变量 ---- +# 亮色在 #f6f6f7 表面上通过 dataviz 校验;暗色与插件旧卡片风格一致 +THEMES: dict[str, dict] = { + "light": { + "--surface": "#f6f6f7", + "--card": "#ffffff", + "--hairline": "#e3e3e6", + "--text-primary": "#1a1a1a", + "--text-secondary": "#52514e", + "--text-muted": "#898781", + "--axis": "#c3c2b7", + "--bar": "#2a78d6", + "--bar-fill-top": "#5598e7", + "--accent": "#2a78d6", + "--game-text": "#242424", + "--fallback-bg": "#f0f0f2", + "pie_colors": [ + "#2a78d6", "#eb6834", "#1baf7a", "#eda100", + "#e87ba4", "#008300", "#4a3aa7", "#e34948", + ], + "other_color": "#898781", + "badge_colors": ["#c98500", "#898781", "#d95926"], # 金/银/铜 + }, + "dark": { + "--surface": "#333439", + "--card": "#2e2e33", + "--hairline": "#46464a", + "--text-primary": "#ffffff", + "--text-secondary": "#c3c2b7", + "--text-muted": "#898781", + "--axis": "#383835", + "--bar": "#3987e5", + "--bar-fill-top": "#6aa9e8", + "--accent": "#53a4c4", + "--game-text": "#e8e8e8", + "--fallback-bg": "#2e2e33", + "pie_colors": [ + "#3987e5", "#d95926", "#199e70", "#c98500", + "#d55181", "#008300", "#9085e9", "#e66767", + ], + "other_color": "#898781", + "badge_colors": ["#c98500", "#898781", "#d95926"], # 金/银/铜 + }, +} + +# 柱状图分桶标签:0 时长(未游玩)单独一桶,便于全库统计 +BUCKET_LABELS = ["0", "<1", "1~10", "10~50", "50~100", "100~500", "500+"] + +CANVAS_W = 1400 +TABLE_ROWS = 20 +PIE_TOP = 8 + +_pw: Optional[Any] = None +_browser: Optional[Any] = None +_browser_lock: Optional[asyncio.Lock] = None + + +def format_hours(hours: float) -> str: + """时长人性化:>=100h 取整加千分位, >=1h 保留一位小数, <1h 显示分钟""" + if hours >= 100: + # 四舍五入取整(round 是银行家舍入,1842.5 会得到 1842) + return f"{int(math.floor(hours + 0.5)):,} 小时" + if hours >= 1: + return f"{hours:.1f} 小时" + return f"{max(1, int(round(hours * 60)))} 分钟" + + +def _truncate_chars(text: str, max_len: int) -> str: + """按字符数截断,超长以省略号结尾(用于图例等紧凑场景)""" + return text if len(text) <= max_len else text[: max_len - 1] + "…" + + +def _font_faces() -> str: + """注入 MiSans 字体(file:// 绝对路径,由 draw.set_font_paths 解析)""" + faces = [] + for family, path in ( + ("MiSansR", draw_util.font_regular_path), + ("MiSansB", draw_util.font_bold_path), + ): + if path and Path(path).exists(): + faces.append( + f"@font-face{{font-family:'{family}';src:url('{Path(path).as_uri()}');}}" + ) + return "\n".join(faces) + + +def _avatar_html(avatar: Optional[Any], nickname: str) -> str: + """头像转 data URI 内联;缺失时用昵称首字符的占位圆块""" + if avatar is not None: + try: + if isinstance(avatar, Image.Image): + buf = BytesIO() + avatar.convert("RGB").save(buf, format="PNG") + mime, data = "image/png", buf.getvalue() + else: + mime, data = "image/jpeg", bytes(avatar) + uri = "data:" + mime + ";base64," + base64.b64encode(data).decode() + return f'' + except Exception: + pass + char = html.escape(nickname[:1], quote=False) if nickname else "?" + return f'
    {char}
    ' + + +def _theme_css(theme: str) -> str: + """主题 CSS 变量块,覆盖模板 :root 默认(亮色)值""" + t = THEMES.get(theme, THEMES["light"]) + vars_css = "".join( + f"{k}:{v};" for k, v in t.items() if k.startswith("--") + ) + return f":root{{{vars_css}}}" + + +def _table_rows( + games: List[dict], start_rank: int, badge_colors: List[str] +) -> str: + """生成单列表格行(排名徽章 + 游戏名 + 时长)""" + rows = [] + for i, g in enumerate(games, start_rank): + if i <= 3: + badge = ( + f'' + f"{i}" + ) + else: + badge = f'{i}' + rows.append( + "" + f'{badge}' + f'{html.escape(g["name"], quote=False)}' + f'{format_hours(g["playtime_hours"])}' + "" + ) + return "\n".join(rows) + + +def _build_html( + games: List[dict], + all_games: Optional[List[dict]] = None, + steam_name: str = "", + plugin_nick: str = "", + avatar: Optional[Any] = None, + theme: str = "light", +) -> str: + """把游戏数据填入模板,返回完整 HTML 字符串 + + Args: + games: 已游玩游戏(playtime_hours > 0, 已排序),用于表格与饼图。 + all_games: 全库游戏(含 0 时长),用于柱状图分段统计与总数;缺省时用 games。 + steam_name: Steam 昵称(常显)。 + plugin_nick: 插件内设置的昵称,设置了才显示。 + avatar: 头像图片(PIL Image 或 JPEG bytes),缺失时显示占位块。 + theme: 主题 light / dark,默认亮色。 + """ + t = THEMES.get(theme, THEMES["light"]) + all_games = all_games if all_games is not None else games + total_hours = sum(g["playtime_hours"] for g in games) + top_games = games[:TABLE_ROWS] + + rows_left = _table_rows(top_games[:10], 1, t["badge_colors"]) + rows_right = _table_rows(top_games[10:], 11, t["badge_colors"]) + right_table = ( + "" + "" + '' + "" + "" + '' + "" + f"{rows_right}
    排名游戏时长
    " + if rows_right + else "" + ) + + pie_games = games[:PIE_TOP] + other_hours = sum(g["playtime_hours"] for g in games[PIE_TOP:]) + pie_items = [ + {"name": _truncate_chars(g["name"], 16), "value": round(g["playtime_hours"], 2)} + for g in pie_games + ] + if other_hours > 0: + pie_items.append({"name": "其他", "value": round(other_hours, 2)}) + pie_colors = t["pie_colors"][: len(pie_games)] + ( + [t["other_color"]] if other_hours > 0 else [] + ) + + # 全库按时长分段:0 时长单独一桶,数量差异大时对数坐标避免小桶被压扁 + counts = [ + sum(1 for g in all_games if g["playtime_hours"] == 0), + sum(1 for g in all_games if 0 < g["playtime_hours"] < 1), + sum(1 for g in all_games if 1 <= g["playtime_hours"] < 10), + sum(1 for g in all_games if 10 <= g["playtime_hours"] < 50), + sum(1 for g in all_games if 50 <= g["playtime_hours"] < 100), + sum(1 for g in all_games if 100 <= g["playtime_hours"] < 500), + sum(1 for g in all_games if g["playtime_hours"] >= 500), + ] + data = { + "pie": {"items": pie_items, "total": round(total_hours, 2), "colors": pie_colors}, + "bar": {"names": BUCKET_LABELS, "counts": counts}, + } + + template = TEMPLATE_PATH.read_text(encoding="utf-8") + generated = datetime.datetime.now( + datetime.timezone(datetime.timedelta(hours=8)) + ).strftime("%Y-%m-%d %H:%M:%S") + footer_parts = [] + if len(games) > TABLE_ROWS: + footer_parts.append(f"仅展示 Top {TABLE_ROWS},共 {len(games)} 款游戏") + footer_parts.append(f"生成时间:{generated}") + # 群内昵称:小字挂在 Steam 名后,超长截断,避免画出图片外 + plugin_tag = ( + f'{html.escape(_truncate_chars(plugin_nick, 18), quote=False)}' + if plugin_nick + else "" + ) + return ( + template.replace("__THEME_CSS__", _theme_css(theme)) + .replace("__ECHARTS__", ECHARTS_PATH.as_uri()) + .replace("__FONT_REGULAR__", _font_url(draw_util.font_regular_path)) + .replace("__FONT_BOLD__", _font_url(draw_util.font_bold_path)) + .replace("__AVATAR__", _avatar_html(avatar, steam_name)) + .replace("__STEAM_NAME__", html.escape(steam_name, quote=False)) + .replace("__PLUGIN_TAG__", plugin_tag) + .replace("__GAME_COUNT__", str(len(all_games))) + .replace("__TOTAL_HOURS__", format_hours(total_hours)) + .replace("__ROWS_LEFT__", rows_left) + .replace("__RIGHT_TABLE__", right_table) + .replace("__FOOTER__", " · ".join(footer_parts)) + # 防注入:JSON 中的 及 < 均被转义 + .replace( + "__DATA__", + json.dumps(data, ensure_ascii=False).replace("<", "\\u003c"), + ) + ) + + +def _font_url(path: Optional[str]) -> str: + """字体 file:// URL;不可用时留空使 @font-face 失效,回退系统字体""" + if path and Path(path).exists(): + return Path(path).as_uri() + return "" + + +async def _ensure_browser(): + """获取进程级单例浏览器(线程安全,幂等)""" + global _pw, _browser, _browser_lock + if _browser_lock is None: + _browser_lock = asyncio.Lock() + async with _browser_lock: + if _browser is None or not _browser.is_connected(): + from playwright.async_api import async_playwright + + _pw = await async_playwright().start() + _browser = await _pw.chromium.launch( + args=["--force-color-profile=srgb"], + ) + return _browser + + +async def render_play_time_table( + games: List[dict], + all_games: Optional[List[dict]] = None, + steam_name: str = "", + plugin_nick: str = "", + avatar: Optional[Any] = None, + theme: str = "light", +) -> bytes: + """渲染游玩时长表为 PNG 字节;任何失败抛异常,由调用方提示失败 + + Args: + games: 已游玩游戏(playtime_hours > 0, 降序),用于表格与饼图。 + all_games: 全库游戏(含 0 时长),用于柱状图分段统计与总数;缺省时用 games。 + steam_name: Steam 昵称(常显)。 + plugin_nick: 插件内设置的昵称,设置了才显示。 + avatar: 头像图片(PIL Image 或 JPEG bytes),缺失时显示占位块。 + theme: 主题 light / dark,默认亮色。 + """ + logger.info(f"游玩时长表:构建 HTML 模板, theme={theme}") + html = _build_html(games, all_games, steam_name, plugin_nick, avatar, theme) + logger.info("游玩时长表:获取浏览器实例") + browser = await _ensure_browser() + page = await browser.new_page( + viewport={"width": CANVAS_W, "height": 1700}, + device_scale_factor=2, + ) + # 捕获页面 JS 错误,便于定位图表渲染问题 + page.on("pageerror", lambda exc: logger.error(f"游玩时长表页面 JS 异常: {exc}")) + page.on( + "console", + lambda msg: logger.error(f"游玩时长表页面 console: {msg.text}") + if msg.type == "error" + else None, + ) + tmp_path: Optional[str] = None + try: + fd, tmp_path = tempfile.mkstemp(suffix=".html", prefix="playtime_") + with os.fdopen(fd, "w", encoding="utf-8") as f: + f.write(html) + logger.info("游玩时长表:页面加载中") + await page.goto(Path(tmp_path).as_uri(), wait_until="load") + await page.wait_for_function("window.__rendered === true", timeout=15000) + await page.evaluate("document.fonts.ready") + img_bytes = await page.screenshot(full_page=True) + logger.info(f"游玩时长表:截图完成, {len(img_bytes)} bytes") + return img_bytes + finally: + await page.close() + if tmp_path: + try: + os.unlink(tmp_path) + except OSError: + pass diff --git a/hexi/plugins/nonebot_plugin_steam_info/models.py b/hexi/plugins/nonebot_plugin_steam_info/models.py new file mode 100644 index 0000000..c1d80d0 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_steam_info/models.py @@ -0,0 +1,82 @@ +from typing import TypedDict, List + + +class Player(TypedDict): + steamid: str + communityvisibilitystate: int + profilestate: int + personaname: str + profileurl: str + avatar: str + avatarmedium: str + avatarfull: str + avatarhash: str + lastlogoff: int + personastate: int + realname: str + primaryclanid: str + timecreated: int + personastateflags: int + gameextrainfo: str + gameid: str + + +class PlayerSummariesResponse(TypedDict): + players: List[Player] + + +class PlayerSummaries(TypedDict): + response: PlayerSummariesResponse + + +class ProcessedPlayer(Player): + game_start_time: int # Unix timestamp + + +class PlayerSummariesProcessedResponse(TypedDict): + players: List[ProcessedPlayer] + + +class Achievements(TypedDict): + name: str + image: bytes + + +class GameData(TypedDict): + game_name: str + play_time: str # e.g. 10.2 + last_played: str # e.g. 10 月 2 日 + game_image: bytes + achievements: List[Achievements] + completed_achievement_number: int + total_achievement_number: int + + +class PlayerData(TypedDict): + steamid: str + player_name: str + background: bytes + avatar: bytes + description: str + recent_2_week_play_time: str + game_data: List[GameData] + + +class DrawPlayerStatusData(TypedDict): + game_name: str + game_time: str # e.g. 10.2 小时(过去 2 周) + last_play_time: str # e.g. 10 月 2 日 + game_header: bytes + achievements: List[Achievements] + completed_achievement_number: int + total_achievement_number: int + + +__all__ = [ + "Player", + "PlayerSummaries", + "PlayerSummariesResponse", + "ProcessedPlayer", + "PlayerSummariesProcessedResponse", + "DrawPlayerStatusData", +] diff --git a/hexi/plugins/nonebot_plugin_steam_info/res/bg_dots.png b/hexi/plugins/nonebot_plugin_steam_info/res/bg_dots.png new file mode 100644 index 0000000..75881d4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_steam_info/res/bg_dots.png differ diff --git a/hexi/plugins/nonebot_plugin_steam_info/res/busy.png b/hexi/plugins/nonebot_plugin_steam_info/res/busy.png new file mode 100644 index 0000000..c045303 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_steam_info/res/busy.png differ diff --git a/hexi/plugins/nonebot_plugin_steam_info/res/default_achievement_image.png b/hexi/plugins/nonebot_plugin_steam_info/res/default_achievement_image.png new file mode 100644 index 0000000..73424d4 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_steam_info/res/default_achievement_image.png differ diff --git a/hexi/plugins/nonebot_plugin_steam_info/res/default_header_image.jpg b/hexi/plugins/nonebot_plugin_steam_info/res/default_header_image.jpg new file mode 100644 index 0000000..e27e2ad Binary files /dev/null and b/hexi/plugins/nonebot_plugin_steam_info/res/default_header_image.jpg differ diff --git a/hexi/plugins/nonebot_plugin_steam_info/res/echarts.min.js b/hexi/plugins/nonebot_plugin_steam_info/res/echarts.min.js new file mode 100644 index 0000000..835966f --- /dev/null +++ b/hexi/plugins/nonebot_plugin_steam_info/res/echarts.min.js @@ -0,0 +1,45 @@ + +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).echarts={})}(this,(function(t){"use strict"; +/*! ***************************************************************************** + Copyright (c) Microsoft Corporation. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + ***************************************************************************** */var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])},e(t,n)};function n(t,n){if("function"!=typeof n&&null!==n)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");function i(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(i.prototype=n.prototype,new i)}var i=function(){this.firefox=!1,this.ie=!1,this.edge=!1,this.newEdge=!1,this.weChat=!1},r=new function(){this.browser=new i,this.node=!1,this.wxa=!1,this.worker=!1,this.svgSupported=!1,this.touchEventsSupported=!1,this.pointerEventsSupported=!1,this.domSupported=!1,this.transformSupported=!1,this.transform3dSupported=!1,this.hasGlobalWindow="undefined"!=typeof window};"object"==typeof wx&&"function"==typeof wx.getSystemInfoSync?(r.wxa=!0,r.touchEventsSupported=!0):"undefined"==typeof document&&"undefined"!=typeof self?r.worker=!0:"undefined"==typeof navigator||0===navigator.userAgent.indexOf("Node.js")?(r.node=!0,r.svgSupported=!0):function(t,e){var n=e.browser,i=t.match(/Firefox\/([\d.]+)/),r=t.match(/MSIE\s([\d.]+)/)||t.match(/Trident\/.+?rv:(([\d.]+))/),o=t.match(/Edge?\/([\d.]+)/),a=/micromessenger/i.test(t);i&&(n.firefox=!0,n.version=i[1]);r&&(n.ie=!0,n.version=r[1]);o&&(n.edge=!0,n.version=o[1],n.newEdge=+o[1].split(".")[0]>18);a&&(n.weChat=!0);e.svgSupported="undefined"!=typeof SVGRect,e.touchEventsSupported="ontouchstart"in window&&!n.ie&&!n.edge,e.pointerEventsSupported="onpointerdown"in window&&(n.edge||n.ie&&+n.version>=11),e.domSupported="undefined"!=typeof document;var s=document.documentElement.style;e.transform3dSupported=(n.ie&&"transition"in s||n.edge||"WebKitCSSMatrix"in window&&"m11"in new WebKitCSSMatrix||"MozPerspective"in s)&&!("OTransition"in s),e.transformSupported=e.transform3dSupported||n.ie&&+n.version>=9}(navigator.userAgent,r);var o="sans-serif",a="12px "+o;var s,l,u=function(t){var e={};if("undefined"==typeof JSON)return e;for(var n=0;n=0)o=r*t.length;else for(var c=0;c>1)%2;a.style.cssText=["position: absolute","visibility: hidden","padding: 0","margin: 0","border-width: 0","user-select: none","width:0","height:0",i[s]+":0",r[l]+":0",i[1-s]+":auto",r[1-l]+":auto",""].join("!important;"),t.appendChild(a),n.push(a)}return n}(e,a),l=function(t,e,n){for(var i=n?"invTrans":"trans",r=e[i],o=e.srcCoords,a=[],s=[],l=!0,u=0;u<4;u++){var h=t[u].getBoundingClientRect(),c=2*u,p=h.left,d=h.top;a.push(p,d),l=l&&o&&p===o[c]&&d===o[c+1],s.push(t[u].offsetLeft,t[u].offsetTop)}return l&&r?r:(e.srcCoords=a,e[i]=n?$t(s,a):$t(a,s))}(s,a,o);if(l)return l(t,n,i),!0}return!1}function ee(t){return"CANVAS"===t.nodeName.toUpperCase()}var ne=/([&<>"'])/g,ie={"&":"&","<":"<",">":">",'"':""","'":"'"};function re(t){return null==t?"":(t+"").replace(ne,(function(t,e){return ie[e]}))}var oe=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ae=[],se=r.browser.firefox&&+r.browser.version.split(".")[0]<39;function le(t,e,n,i){return n=n||{},i?ue(t,e,n):se&&null!=e.layerX&&e.layerX!==e.offsetX?(n.zrX=e.layerX,n.zrY=e.layerY):null!=e.offsetX?(n.zrX=e.offsetX,n.zrY=e.offsetY):ue(t,e,n),n}function ue(t,e,n){if(r.domSupported&&t.getBoundingClientRect){var i=e.clientX,o=e.clientY;if(ee(t)){var a=t.getBoundingClientRect();return n.zrX=i-a.left,void(n.zrY=o-a.top)}if(te(ae,t,i,o))return n.zrX=ae[0],void(n.zrY=ae[1])}n.zrX=n.zrY=0}function he(t){return t||window.event}function ce(t,e,n){if(null!=(e=he(e)).zrX)return e;var i=e.type;if(i&&i.indexOf("touch")>=0){var r="touchend"!==i?e.targetTouches[0]:e.changedTouches[0];r&&le(t,r,e,n)}else{le(t,e,e,n);var o=function(t){var e=t.wheelDelta;if(e)return e;var n=t.deltaX,i=t.deltaY;if(null==n||null==i)return e;return 3*(0!==i?Math.abs(i):Math.abs(n))*(i>0?-1:i<0?1:n>0?-1:1)}(e);e.zrDelta=o?o/120:-(e.detail||0)/3}var a=e.button;return null==e.which&&void 0!==a&&oe.test(e.type)&&(e.which=1&a?1:2&a?3:4&a?2:0),e}function pe(t,e,n,i){t.addEventListener(e,n,i)}var de=function(t){t.preventDefault(),t.stopPropagation(),t.cancelBubble=!0};function fe(t){return 2===t.which||3===t.which}var ge=function(){function t(){this._track=[]}return t.prototype.recognize=function(t,e,n){return this._doTrack(t,e,n),this._recognize(t)},t.prototype.clear=function(){return this._track.length=0,this},t.prototype._doTrack=function(t,e,n){var i=t.touches;if(i){for(var r={points:[],touches:[],target:e,event:t},o=0,a=i.length;o1&&r&&r.length>1){var a=ye(r)/ye(o);!isFinite(a)&&(a=1),e.pinchScale=a;var s=[((i=r)[0][0]+i[1][0])/2,(i[0][1]+i[1][1])/2];return e.pinchX=s[0],e.pinchY=s[1],{type:"pinch",target:t[0].target,event:e}}}}};function me(){return[1,0,0,1,0,0]}function xe(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t}function _e(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t}function be(t,e,n){var i=e[0]*n[0]+e[2]*n[1],r=e[1]*n[0]+e[3]*n[1],o=e[0]*n[2]+e[2]*n[3],a=e[1]*n[2]+e[3]*n[3],s=e[0]*n[4]+e[2]*n[5]+e[4],l=e[1]*n[4]+e[3]*n[5]+e[5];return t[0]=i,t[1]=r,t[2]=o,t[3]=a,t[4]=s,t[5]=l,t}function we(t,e,n){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4]+n[0],t[5]=e[5]+n[1],t}function Se(t,e,n,i){void 0===i&&(i=[0,0]);var r=e[0],o=e[2],a=e[4],s=e[1],l=e[3],u=e[5],h=Math.sin(n),c=Math.cos(n);return t[0]=r*c+s*h,t[1]=-r*h+s*c,t[2]=o*c+l*h,t[3]=-o*h+c*l,t[4]=c*(a-i[0])+h*(u-i[1])+i[0],t[5]=c*(u-i[1])-h*(a-i[0])+i[1],t}function Me(t,e,n){var i=n[0],r=n[1];return t[0]=e[0]*i,t[1]=e[1]*r,t[2]=e[2]*i,t[3]=e[3]*r,t[4]=e[4]*i,t[5]=e[5]*r,t}function Ie(t,e){var n=e[0],i=e[2],r=e[4],o=e[1],a=e[3],s=e[5],l=n*a-o*i;return l?(l=1/l,t[0]=a*l,t[1]=-o*l,t[2]=-i*l,t[3]=n*l,t[4]=(i*s-a*r)*l,t[5]=(o*r-n*s)*l,t):null}function Te(t){var e=[1,0,0,1,0,0];return _e(e,t),e}var Ce=Object.freeze({__proto__:null,create:me,identity:xe,copy:_e,mul:be,translate:we,rotate:Se,scale:Me,invert:Ie,clone:Te}),De=function(){function t(t,e){this.x=t||0,this.y=e||0}return t.prototype.copy=function(t){return this.x=t.x,this.y=t.y,this},t.prototype.clone=function(){return new t(this.x,this.y)},t.prototype.set=function(t,e){return this.x=t,this.y=e,this},t.prototype.equal=function(t){return t.x===this.x&&t.y===this.y},t.prototype.add=function(t){return this.x+=t.x,this.y+=t.y,this},t.prototype.scale=function(t){this.x*=t,this.y*=t},t.prototype.scaleAndAdd=function(t,e){this.x+=t.x*e,this.y+=t.y*e},t.prototype.sub=function(t){return this.x-=t.x,this.y-=t.y,this},t.prototype.dot=function(t){return this.x*t.x+this.y*t.y},t.prototype.len=function(){return Math.sqrt(this.x*this.x+this.y*this.y)},t.prototype.lenSquare=function(){return this.x*this.x+this.y*this.y},t.prototype.normalize=function(){var t=this.len();return this.x/=t,this.y/=t,this},t.prototype.distance=function(t){var e=this.x-t.x,n=this.y-t.y;return Math.sqrt(e*e+n*n)},t.prototype.distanceSquare=function(t){var e=this.x-t.x,n=this.y-t.y;return e*e+n*n},t.prototype.negate=function(){return this.x=-this.x,this.y=-this.y,this},t.prototype.transform=function(t){if(t){var e=this.x,n=this.y;return this.x=t[0]*e+t[2]*n+t[4],this.y=t[1]*e+t[3]*n+t[5],this}},t.prototype.toArray=function(t){return t[0]=this.x,t[1]=this.y,t},t.prototype.fromArray=function(t){this.x=t[0],this.y=t[1]},t.set=function(t,e,n){t.x=e,t.y=n},t.copy=function(t,e){t.x=e.x,t.y=e.y},t.len=function(t){return Math.sqrt(t.x*t.x+t.y*t.y)},t.lenSquare=function(t){return t.x*t.x+t.y*t.y},t.dot=function(t,e){return t.x*e.x+t.y*e.y},t.add=function(t,e,n){t.x=e.x+n.x,t.y=e.y+n.y},t.sub=function(t,e,n){t.x=e.x-n.x,t.y=e.y-n.y},t.scale=function(t,e,n){t.x=e.x*n,t.y=e.y*n},t.scaleAndAdd=function(t,e,n,i){t.x=e.x+n.x*i,t.y=e.y+n.y*i},t.lerp=function(t,e,n,i){var r=1-i;t.x=r*e.x+i*n.x,t.y=r*e.y+i*n.y},t}(),Ae=Math.min,ke=Math.max,Le=new De,Pe=new De,Oe=new De,Re=new De,Ne=new De,Ee=new De,ze=function(){function t(t,e,n,i){n<0&&(t+=n,n=-n),i<0&&(e+=i,i=-i),this.x=t,this.y=e,this.width=n,this.height=i}return t.prototype.union=function(t){var e=Ae(t.x,this.x),n=Ae(t.y,this.y);isFinite(this.x)&&isFinite(this.width)?this.width=ke(t.x+t.width,this.x+this.width)-e:this.width=t.width,isFinite(this.y)&&isFinite(this.height)?this.height=ke(t.y+t.height,this.y+this.height)-n:this.height=t.height,this.x=e,this.y=n},t.prototype.applyTransform=function(e){t.applyTransform(this,this,e)},t.prototype.calculateTransform=function(t){var e=this,n=t.width/e.width,i=t.height/e.height,r=[1,0,0,1,0,0];return we(r,r,[-e.x,-e.y]),Me(r,r,[n,i]),we(r,r,[t.x,t.y]),r},t.prototype.intersect=function(e,n){if(!e)return!1;e instanceof t||(e=t.create(e));var i=this,r=i.x,o=i.x+i.width,a=i.y,s=i.y+i.height,l=e.x,u=e.x+e.width,h=e.y,c=e.y+e.height,p=!(of&&(f=x,gf&&(f=_,v=n.x&&t<=n.x+n.width&&e>=n.y&&e<=n.y+n.height},t.prototype.clone=function(){return new t(this.x,this.y,this.width,this.height)},t.prototype.copy=function(e){t.copy(this,e)},t.prototype.plain=function(){return{x:this.x,y:this.y,width:this.width,height:this.height}},t.prototype.isFinite=function(){return isFinite(this.x)&&isFinite(this.y)&&isFinite(this.width)&&isFinite(this.height)},t.prototype.isZero=function(){return 0===this.width||0===this.height},t.create=function(e){return new t(e.x,e.y,e.width,e.height)},t.copy=function(t,e){t.x=e.x,t.y=e.y,t.width=e.width,t.height=e.height},t.applyTransform=function(e,n,i){if(i){if(i[1]<1e-5&&i[1]>-1e-5&&i[2]<1e-5&&i[2]>-1e-5){var r=i[0],o=i[3],a=i[4],s=i[5];return e.x=n.x*r+a,e.y=n.y*o+s,e.width=n.width*r,e.height=n.height*o,e.width<0&&(e.x+=e.width,e.width=-e.width),void(e.height<0&&(e.y+=e.height,e.height=-e.height))}Le.x=Oe.x=n.x,Le.y=Re.y=n.y,Pe.x=Re.x=n.x+n.width,Pe.y=Oe.y=n.y+n.height,Le.transform(i),Re.transform(i),Pe.transform(i),Oe.transform(i),e.x=Ae(Le.x,Pe.x,Oe.x,Re.x),e.y=Ae(Le.y,Pe.y,Oe.y,Re.y);var l=ke(Le.x,Pe.x,Oe.x,Re.x),u=ke(Le.y,Pe.y,Oe.y,Re.y);e.width=l-e.x,e.height=u-e.y}else e!==n&&t.copy(e,n)},t}(),Ve="silent";function Be(){de(this.event)}var Fe=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.handler=null,e}return n(e,t),e.prototype.dispose=function(){},e.prototype.setCursor=function(){},e}(jt),Ge=function(t,e){this.x=t,this.y=e},We=["click","dblclick","mousewheel","mouseout","mouseup","mousedown","mousemove","contextmenu"],He=new ze(0,0,0,0),Ye=function(t){function e(e,n,i,r,o){var a=t.call(this)||this;return a._hovered=new Ge(0,0),a.storage=e,a.painter=n,a.painterRoot=r,a._pointerSize=o,i=i||new Fe,a.proxy=null,a.setHandlerProxy(i),a._draggingMgr=new Zt(a),a}return n(e,t),e.prototype.setHandlerProxy=function(t){this.proxy&&this.proxy.dispose(),t&&(E(We,(function(e){t.on&&t.on(e,this[e],this)}),this),t.handler=this),this.proxy=t},e.prototype.mousemove=function(t){var e=t.zrX,n=t.zrY,i=Ze(this,e,n),r=this._hovered,o=r.target;o&&!o.__zr&&(o=(r=this.findHover(r.x,r.y)).target);var a=this._hovered=i?new Ge(e,n):this.findHover(e,n),s=a.target,l=this.proxy;l.setCursor&&l.setCursor(s?s.cursor:"default"),o&&s!==o&&this.dispatchToElement(r,"mouseout",t),this.dispatchToElement(a,"mousemove",t),s&&s!==o&&this.dispatchToElement(a,"mouseover",t)},e.prototype.mouseout=function(t){var e=t.zrEventControl;"only_globalout"!==e&&this.dispatchToElement(this._hovered,"mouseout",t),"no_globalout"!==e&&this.trigger("globalout",{type:"globalout",event:t})},e.prototype.resize=function(){this._hovered=new Ge(0,0)},e.prototype.dispatch=function(t,e){var n=this[t];n&&n.call(this,e)},e.prototype.dispose=function(){this.proxy.dispose(),this.storage=null,this.proxy=null,this.painter=null},e.prototype.setCursorStyle=function(t){var e=this.proxy;e.setCursor&&e.setCursor(t)},e.prototype.dispatchToElement=function(t,e,n){var i=(t=t||{}).target;if(!i||!i.silent){for(var r="on"+e,o=function(t,e,n){return{type:t,event:n,target:e.target,topTarget:e.topTarget,cancelBubble:!1,offsetX:n.zrX,offsetY:n.zrY,gestureEvent:n.gestureEvent,pinchX:n.pinchX,pinchY:n.pinchY,pinchScale:n.pinchScale,wheelDelta:n.zrDelta,zrByTouch:n.zrByTouch,which:n.which,stop:Be}}(e,t,n);i&&(i[r]&&(o.cancelBubble=!!i[r].call(i,o)),i.trigger(e,o),i=i.__hostTarget?i.__hostTarget:i.parent,!o.cancelBubble););o.cancelBubble||(this.trigger(e,o),this.painter&&this.painter.eachOtherLayer&&this.painter.eachOtherLayer((function(t){"function"==typeof t[r]&&t[r].call(t,o),t.trigger&&t.trigger(e,o)})))}},e.prototype.findHover=function(t,e,n){var i=this.storage.getDisplayList(),r=new Ge(t,e);if(Ue(i,r,t,e,n),this._pointerSize&&!r.target){for(var o=[],a=this._pointerSize,s=a/2,l=new ze(t-s,e-s,a,a),u=i.length-1;u>=0;u--){var h=i[u];h===n||h.ignore||h.ignoreCoarsePointer||h.parent&&h.parent.ignoreCoarsePointer||(He.copy(h.getBoundingRect()),h.transform&&He.applyTransform(h.transform),He.intersect(l)&&o.push(h))}if(o.length)for(var c=Math.PI/12,p=2*Math.PI,d=0;d=0;o--){var a=t[o],s=void 0;if(a!==r&&!a.ignore&&(s=Xe(a,n,i))&&(!e.topTarget&&(e.topTarget=a),s!==Ve)){e.target=a;break}}}function Ze(t,e,n){var i=t.painter;return e<0||e>i.getWidth()||n<0||n>i.getHeight()}E(["click","mousedown","mouseup","mousewheel","dblclick","contextmenu"],(function(t){Ye.prototype[t]=function(e){var n,i,r=e.zrX,o=e.zrY,a=Ze(this,r,o);if("mouseup"===t&&a||(i=(n=this.findHover(r,o)).target),"mousedown"===t)this._downEl=i,this._downPoint=[e.zrX,e.zrY],this._upEl=i;else if("mouseup"===t)this._upEl=i;else if("click"===t){if(this._downEl!==this._upEl||!this._downPoint||Vt(this._downPoint,[e.zrX,e.zrY])>4)return;this._downPoint=null}this.dispatchToElement(n,t,e)}}));function je(t,e,n,i){var r=e+1;if(r===n)return 1;if(i(t[r++],t[e])<0){for(;r=0;)r++;return r-e}function qe(t,e,n,i,r){for(i===e&&i++;i>>1])<0?l=o:s=o+1;var u=i-s;switch(u){case 3:t[s+3]=t[s+2];case 2:t[s+2]=t[s+1];case 1:t[s+1]=t[s];break;default:for(;u>0;)t[s+u]=t[s+u-1],u--}t[s]=a}}function Ke(t,e,n,i,r,o){var a=0,s=0,l=1;if(o(t,e[n+r])>0){for(s=i-r;l0;)a=l,(l=1+(l<<1))<=0&&(l=s);l>s&&(l=s),a+=r,l+=r}else{for(s=r+1;ls&&(l=s);var u=a;a=r-l,l=r-u}for(a++;a>>1);o(t,e[n+h])>0?a=h+1:l=h}return l}function $e(t,e,n,i,r,o){var a=0,s=0,l=1;if(o(t,e[n+r])<0){for(s=r+1;ls&&(l=s);var u=a;a=r-l,l=r-u}else{for(s=i-r;l=0;)a=l,(l=1+(l<<1))<=0&&(l=s);l>s&&(l=s),a+=r,l+=r}for(a++;a>>1);o(t,e[n+h])<0?l=h:a=h+1}return l}function Je(t,e){var n,i,r=7,o=0,a=[];function s(s){var l=n[s],u=i[s],h=n[s+1],c=i[s+1];i[s]=u+c,s===o-3&&(n[s+1]=n[s+2],i[s+1]=i[s+2]),o--;var p=$e(t[h],t,l,u,0,e);l+=p,0!==(u-=p)&&0!==(c=Ke(t[l+u-1],t,h,c,c-1,e))&&(u<=c?function(n,i,o,s){var l=0;for(l=0;l=7||d>=7);if(f)break;g<0&&(g=0),g+=2}if((r=g)<1&&(r=1),1===i){for(l=0;l=0;l--)t[d+l]=t[p+l];return void(t[c]=a[h])}var f=r;for(;;){var g=0,y=0,v=!1;do{if(e(a[h],t[u])<0){if(t[c--]=t[u--],g++,y=0,0==--i){v=!0;break}}else if(t[c--]=a[h--],y++,g=0,1==--s){v=!0;break}}while((g|y)=0;l--)t[d+l]=t[p+l];if(0===i){v=!0;break}}if(t[c--]=a[h--],1==--s){v=!0;break}if(0!==(y=s-Ke(t[u],a,0,s,s-1,e))){for(s-=y,d=(c-=y)+1,p=(h-=y)+1,l=0;l=7||y>=7);if(v)break;f<0&&(f=0),f+=2}(r=f)<1&&(r=1);if(1===s){for(d=(c-=i)+1,p=(u-=i)+1,l=i-1;l>=0;l--)t[d+l]=t[p+l];t[c]=a[h]}else{if(0===s)throw new Error;for(p=c-(s-1),l=0;l1;){var t=o-2;if(t>=1&&i[t-1]<=i[t]+i[t+1]||t>=2&&i[t-2]<=i[t]+i[t-1])i[t-1]i[t+1])break;s(t)}},forceMergeRuns:function(){for(;o>1;){var t=o-2;t>0&&i[t-1]=32;)e|=1&t,t>>=1;return t+e}(r);do{if((o=je(t,n,i,e))s&&(l=s),qe(t,n,n+l,n+o,e),o=l}a.pushRun(n,o),a.mergeRuns(),r-=o,n+=o}while(0!==r);a.forceMergeRuns()}}}var tn=!1;function en(){tn||(tn=!0,console.warn("z / z2 / zlevel of displayable is invalid, which may cause unexpected errors"))}function nn(t,e){return t.zlevel===e.zlevel?t.z===e.z?t.z2-e.z2:t.z-e.z:t.zlevel-e.zlevel}var rn=function(){function t(){this._roots=[],this._displayList=[],this._displayListLen=0,this.displayableSortFunc=nn}return t.prototype.traverse=function(t,e){for(var n=0;n0&&(u.__clipPaths=[]),isNaN(u.z)&&(en(),u.z=0),isNaN(u.z2)&&(en(),u.z2=0),isNaN(u.zlevel)&&(en(),u.zlevel=0),this._displayList[this._displayListLen++]=u}var h=t.getDecalElement&&t.getDecalElement();h&&this._updateAndAddDisplayable(h,e,n);var c=t.getTextGuideLine();c&&this._updateAndAddDisplayable(c,e,n);var p=t.getTextContent();p&&this._updateAndAddDisplayable(p,e,n)}},t.prototype.addRoot=function(t){t.__zr&&t.__zr.storage===this||this._roots.push(t)},t.prototype.delRoot=function(t){if(t instanceof Array)for(var e=0,n=t.length;e=0&&this._roots.splice(i,1)}},t.prototype.delAllRoots=function(){this._roots=[],this._displayList=[],this._displayListLen=0},t.prototype.getRoots=function(){return this._roots},t.prototype.dispose=function(){this._displayList=null,this._roots=null},t}(),on=r.hasGlobalWindow&&(window.requestAnimationFrame&&window.requestAnimationFrame.bind(window)||window.msRequestAnimationFrame&&window.msRequestAnimationFrame.bind(window)||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame)||function(t){return setTimeout(t,16)},an={linear:function(t){return t},quadraticIn:function(t){return t*t},quadraticOut:function(t){return t*(2-t)},quadraticInOut:function(t){return(t*=2)<1?.5*t*t:-.5*(--t*(t-2)-1)},cubicIn:function(t){return t*t*t},cubicOut:function(t){return--t*t*t+1},cubicInOut:function(t){return(t*=2)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},quarticIn:function(t){return t*t*t*t},quarticOut:function(t){return 1- --t*t*t*t},quarticInOut:function(t){return(t*=2)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)},quinticIn:function(t){return t*t*t*t*t},quinticOut:function(t){return--t*t*t*t*t+1},quinticInOut:function(t){return(t*=2)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},sinusoidalIn:function(t){return 1-Math.cos(t*Math.PI/2)},sinusoidalOut:function(t){return Math.sin(t*Math.PI/2)},sinusoidalInOut:function(t){return.5*(1-Math.cos(Math.PI*t))},exponentialIn:function(t){return 0===t?0:Math.pow(1024,t-1)},exponentialOut:function(t){return 1===t?1:1-Math.pow(2,-10*t)},exponentialInOut:function(t){return 0===t?0:1===t?1:(t*=2)<1?.5*Math.pow(1024,t-1):.5*(2-Math.pow(2,-10*(t-1)))},circularIn:function(t){return 1-Math.sqrt(1-t*t)},circularOut:function(t){return Math.sqrt(1- --t*t)},circularInOut:function(t){return(t*=2)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},elasticIn:function(t){var e,n=.1;return 0===t?0:1===t?1:(!n||n<1?(n=1,e=.1):e=.4*Math.asin(1/n)/(2*Math.PI),-n*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/.4))},elasticOut:function(t){var e,n=.1;return 0===t?0:1===t?1:(!n||n<1?(n=1,e=.1):e=.4*Math.asin(1/n)/(2*Math.PI),n*Math.pow(2,-10*t)*Math.sin((t-e)*(2*Math.PI)/.4)+1)},elasticInOut:function(t){var e,n=.1,i=.4;return 0===t?0:1===t?1:(!n||n<1?(n=1,e=.1):e=i*Math.asin(1/n)/(2*Math.PI),(t*=2)<1?n*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/i)*-.5:n*Math.pow(2,-10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/i)*.5+1)},backIn:function(t){var e=1.70158;return t*t*((e+1)*t-e)},backOut:function(t){var e=1.70158;return--t*t*((e+1)*t+e)+1},backInOut:function(t){var e=2.5949095;return(t*=2)<1?t*t*((e+1)*t-e)*.5:.5*((t-=2)*t*((e+1)*t+e)+2)},bounceIn:function(t){return 1-an.bounceOut(1-t)},bounceOut:function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},bounceInOut:function(t){return t<.5?.5*an.bounceIn(2*t):.5*an.bounceOut(2*t-1)+.5}},sn=Math.pow,ln=Math.sqrt,un=1e-8,hn=1e-4,cn=ln(3),pn=1/3,dn=Mt(),fn=Mt(),gn=Mt();function yn(t){return t>-1e-8&&tun||t<-1e-8}function mn(t,e,n,i,r){var o=1-r;return o*o*(o*t+3*r*e)+r*r*(r*i+3*o*n)}function xn(t,e,n,i,r){var o=1-r;return 3*(((e-t)*o+2*(n-e)*r)*o+(i-n)*r*r)}function _n(t,e,n,i,r,o){var a=i+3*(e-n)-t,s=3*(n-2*e+t),l=3*(e-t),u=t-r,h=s*s-3*a*l,c=s*l-9*a*u,p=l*l-3*s*u,d=0;if(yn(h)&&yn(c)){if(yn(s))o[0]=0;else(M=-l/s)>=0&&M<=1&&(o[d++]=M)}else{var f=c*c-4*h*p;if(yn(f)){var g=c/h,y=-g/2;(M=-s/a+g)>=0&&M<=1&&(o[d++]=M),y>=0&&y<=1&&(o[d++]=y)}else if(f>0){var v=ln(f),m=h*s+1.5*a*(-c+v),x=h*s+1.5*a*(-c-v);(M=(-s-((m=m<0?-sn(-m,pn):sn(m,pn))+(x=x<0?-sn(-x,pn):sn(x,pn))))/(3*a))>=0&&M<=1&&(o[d++]=M)}else{var _=(2*h*s-3*a*c)/(2*ln(h*h*h)),b=Math.acos(_)/3,w=ln(h),S=Math.cos(b),M=(-s-2*w*S)/(3*a),I=(y=(-s+w*(S+cn*Math.sin(b)))/(3*a),(-s+w*(S-cn*Math.sin(b)))/(3*a));M>=0&&M<=1&&(o[d++]=M),y>=0&&y<=1&&(o[d++]=y),I>=0&&I<=1&&(o[d++]=I)}}return d}function bn(t,e,n,i,r){var o=6*n-12*e+6*t,a=9*e+3*i-3*t-9*n,s=3*e-3*t,l=0;if(yn(a)){if(vn(o))(h=-s/o)>=0&&h<=1&&(r[l++]=h)}else{var u=o*o-4*a*s;if(yn(u))r[0]=-o/(2*a);else if(u>0){var h,c=ln(u),p=(-o-c)/(2*a);(h=(-o+c)/(2*a))>=0&&h<=1&&(r[l++]=h),p>=0&&p<=1&&(r[l++]=p)}}return l}function wn(t,e,n,i,r,o){var a=(e-t)*r+t,s=(n-e)*r+e,l=(i-n)*r+n,u=(s-a)*r+a,h=(l-s)*r+s,c=(h-u)*r+u;o[0]=t,o[1]=a,o[2]=u,o[3]=c,o[4]=c,o[5]=h,o[6]=l,o[7]=i}function Sn(t,e,n,i,r,o,a,s,l,u,h){var c,p,d,f,g,y=.005,v=1/0;dn[0]=l,dn[1]=u;for(var m=0;m<1;m+=.05)fn[0]=mn(t,n,r,a,m),fn[1]=mn(e,i,o,s,m),(f=Ft(dn,fn))=0&&f=0&&y=1?1:_n(0,i,o,1,t,s)&&mn(0,r,a,1,s[0])}}}var On=function(){function t(t){this._inited=!1,this._startTime=0,this._pausedTime=0,this._paused=!1,this._life=t.life||1e3,this._delay=t.delay||0,this.loop=t.loop||!1,this.onframe=t.onframe||bt,this.ondestroy=t.ondestroy||bt,this.onrestart=t.onrestart||bt,t.easing&&this.setEasing(t.easing)}return t.prototype.step=function(t,e){if(this._inited||(this._startTime=t+this._delay,this._inited=!0),!this._paused){var n=this._life,i=t-this._startTime-this._pausedTime,r=i/n;r<0&&(r=0),r=Math.min(r,1);var o=this.easingFunc,a=o?o(r):r;if(this.onframe(a),1===r){if(!this.loop)return!0;var s=i%n;this._startTime=t-s,this._pausedTime=0,this.onrestart()}return!1}this._pausedTime+=e},t.prototype.pause=function(){this._paused=!0},t.prototype.resume=function(){this._paused=!1},t.prototype.setEasing=function(t){this.easing=t,this.easingFunc=X(t)?t:an[t]||Pn(t)},t}(),Rn=function(t){this.value=t},Nn=function(){function t(){this._len=0}return t.prototype.insert=function(t){var e=new Rn(t);return this.insertEntry(e),e},t.prototype.insertEntry=function(t){this.head?(this.tail.next=t,t.prev=this.tail,t.next=null,this.tail=t):this.head=this.tail=t,this._len++},t.prototype.remove=function(t){var e=t.prev,n=t.next;e?e.next=n:this.head=n,n?n.prev=e:this.tail=e,t.next=t.prev=null,this._len--},t.prototype.len=function(){return this._len},t.prototype.clear=function(){this.head=this.tail=null,this._len=0},t}(),En=function(){function t(t){this._list=new Nn,this._maxSize=10,this._map={},this._maxSize=t}return t.prototype.put=function(t,e){var n=this._list,i=this._map,r=null;if(null==i[t]){var o=n.len(),a=this._lastRemovedEntry;if(o>=this._maxSize&&o>0){var s=n.head;n.remove(s),delete i[s.key],r=s.value,this._lastRemovedEntry=s}a?a.value=e:a=new Rn(e),a.key=t,n.insertEntry(a),i[t]=a}return r},t.prototype.get=function(t){var e=this._map[t],n=this._list;if(null!=e)return e!==n.tail&&(n.remove(e),n.insertEntry(e)),e.value},t.prototype.clear=function(){this._list.clear(),this._map={}},t.prototype.len=function(){return this._list.len()},t}(),zn={transparent:[0,0,0,0],aliceblue:[240,248,255,1],antiquewhite:[250,235,215,1],aqua:[0,255,255,1],aquamarine:[127,255,212,1],azure:[240,255,255,1],beige:[245,245,220,1],bisque:[255,228,196,1],black:[0,0,0,1],blanchedalmond:[255,235,205,1],blue:[0,0,255,1],blueviolet:[138,43,226,1],brown:[165,42,42,1],burlywood:[222,184,135,1],cadetblue:[95,158,160,1],chartreuse:[127,255,0,1],chocolate:[210,105,30,1],coral:[255,127,80,1],cornflowerblue:[100,149,237,1],cornsilk:[255,248,220,1],crimson:[220,20,60,1],cyan:[0,255,255,1],darkblue:[0,0,139,1],darkcyan:[0,139,139,1],darkgoldenrod:[184,134,11,1],darkgray:[169,169,169,1],darkgreen:[0,100,0,1],darkgrey:[169,169,169,1],darkkhaki:[189,183,107,1],darkmagenta:[139,0,139,1],darkolivegreen:[85,107,47,1],darkorange:[255,140,0,1],darkorchid:[153,50,204,1],darkred:[139,0,0,1],darksalmon:[233,150,122,1],darkseagreen:[143,188,143,1],darkslateblue:[72,61,139,1],darkslategray:[47,79,79,1],darkslategrey:[47,79,79,1],darkturquoise:[0,206,209,1],darkviolet:[148,0,211,1],deeppink:[255,20,147,1],deepskyblue:[0,191,255,1],dimgray:[105,105,105,1],dimgrey:[105,105,105,1],dodgerblue:[30,144,255,1],firebrick:[178,34,34,1],floralwhite:[255,250,240,1],forestgreen:[34,139,34,1],fuchsia:[255,0,255,1],gainsboro:[220,220,220,1],ghostwhite:[248,248,255,1],gold:[255,215,0,1],goldenrod:[218,165,32,1],gray:[128,128,128,1],green:[0,128,0,1],greenyellow:[173,255,47,1],grey:[128,128,128,1],honeydew:[240,255,240,1],hotpink:[255,105,180,1],indianred:[205,92,92,1],indigo:[75,0,130,1],ivory:[255,255,240,1],khaki:[240,230,140,1],lavender:[230,230,250,1],lavenderblush:[255,240,245,1],lawngreen:[124,252,0,1],lemonchiffon:[255,250,205,1],lightblue:[173,216,230,1],lightcoral:[240,128,128,1],lightcyan:[224,255,255,1],lightgoldenrodyellow:[250,250,210,1],lightgray:[211,211,211,1],lightgreen:[144,238,144,1],lightgrey:[211,211,211,1],lightpink:[255,182,193,1],lightsalmon:[255,160,122,1],lightseagreen:[32,178,170,1],lightskyblue:[135,206,250,1],lightslategray:[119,136,153,1],lightslategrey:[119,136,153,1],lightsteelblue:[176,196,222,1],lightyellow:[255,255,224,1],lime:[0,255,0,1],limegreen:[50,205,50,1],linen:[250,240,230,1],magenta:[255,0,255,1],maroon:[128,0,0,1],mediumaquamarine:[102,205,170,1],mediumblue:[0,0,205,1],mediumorchid:[186,85,211,1],mediumpurple:[147,112,219,1],mediumseagreen:[60,179,113,1],mediumslateblue:[123,104,238,1],mediumspringgreen:[0,250,154,1],mediumturquoise:[72,209,204,1],mediumvioletred:[199,21,133,1],midnightblue:[25,25,112,1],mintcream:[245,255,250,1],mistyrose:[255,228,225,1],moccasin:[255,228,181,1],navajowhite:[255,222,173,1],navy:[0,0,128,1],oldlace:[253,245,230,1],olive:[128,128,0,1],olivedrab:[107,142,35,1],orange:[255,165,0,1],orangered:[255,69,0,1],orchid:[218,112,214,1],palegoldenrod:[238,232,170,1],palegreen:[152,251,152,1],paleturquoise:[175,238,238,1],palevioletred:[219,112,147,1],papayawhip:[255,239,213,1],peachpuff:[255,218,185,1],peru:[205,133,63,1],pink:[255,192,203,1],plum:[221,160,221,1],powderblue:[176,224,230,1],purple:[128,0,128,1],red:[255,0,0,1],rosybrown:[188,143,143,1],royalblue:[65,105,225,1],saddlebrown:[139,69,19,1],salmon:[250,128,114,1],sandybrown:[244,164,96,1],seagreen:[46,139,87,1],seashell:[255,245,238,1],sienna:[160,82,45,1],silver:[192,192,192,1],skyblue:[135,206,235,1],slateblue:[106,90,205,1],slategray:[112,128,144,1],slategrey:[112,128,144,1],snow:[255,250,250,1],springgreen:[0,255,127,1],steelblue:[70,130,180,1],tan:[210,180,140,1],teal:[0,128,128,1],thistle:[216,191,216,1],tomato:[255,99,71,1],turquoise:[64,224,208,1],violet:[238,130,238,1],wheat:[245,222,179,1],white:[255,255,255,1],whitesmoke:[245,245,245,1],yellow:[255,255,0,1],yellowgreen:[154,205,50,1]};function Vn(t){return(t=Math.round(t))<0?0:t>255?255:t}function Bn(t){return t<0?0:t>1?1:t}function Fn(t){var e=t;return e.length&&"%"===e.charAt(e.length-1)?Vn(parseFloat(e)/100*255):Vn(parseInt(e,10))}function Gn(t){var e=t;return e.length&&"%"===e.charAt(e.length-1)?Bn(parseFloat(e)/100):Bn(parseFloat(e))}function Wn(t,e,n){return n<0?n+=1:n>1&&(n-=1),6*n<1?t+(e-t)*n*6:2*n<1?e:3*n<2?t+(e-t)*(2/3-n)*6:t}function Hn(t,e,n){return t+(e-t)*n}function Yn(t,e,n,i,r){return t[0]=e,t[1]=n,t[2]=i,t[3]=r,t}function Xn(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t}var Un=new En(20),Zn=null;function jn(t,e){Zn&&Xn(Zn,e),Zn=Un.put(t,Zn||e.slice())}function qn(t,e){if(t){e=e||[];var n=Un.get(t);if(n)return Xn(e,n);var i=(t+="").replace(/ /g,"").toLowerCase();if(i in zn)return Xn(e,zn[i]),jn(t,e),e;var r,o=i.length;if("#"===i.charAt(0))return 4===o||5===o?(r=parseInt(i.slice(1,4),16))>=0&&r<=4095?(Yn(e,(3840&r)>>4|(3840&r)>>8,240&r|(240&r)>>4,15&r|(15&r)<<4,5===o?parseInt(i.slice(4),16)/15:1),jn(t,e),e):void Yn(e,0,0,0,1):7===o||9===o?(r=parseInt(i.slice(1,7),16))>=0&&r<=16777215?(Yn(e,(16711680&r)>>16,(65280&r)>>8,255&r,9===o?parseInt(i.slice(7),16)/255:1),jn(t,e),e):void Yn(e,0,0,0,1):void 0;var a=i.indexOf("("),s=i.indexOf(")");if(-1!==a&&s+1===o){var l=i.substr(0,a),u=i.substr(a+1,s-(a+1)).split(","),h=1;switch(l){case"rgba":if(4!==u.length)return 3===u.length?Yn(e,+u[0],+u[1],+u[2],1):Yn(e,0,0,0,1);h=Gn(u.pop());case"rgb":return u.length>=3?(Yn(e,Fn(u[0]),Fn(u[1]),Fn(u[2]),3===u.length?h:Gn(u[3])),jn(t,e),e):void Yn(e,0,0,0,1);case"hsla":return 4!==u.length?void Yn(e,0,0,0,1):(u[3]=Gn(u[3]),Kn(u,e),jn(t,e),e);case"hsl":return 3!==u.length?void Yn(e,0,0,0,1):(Kn(u,e),jn(t,e),e);default:return}}Yn(e,0,0,0,1)}}function Kn(t,e){var n=(parseFloat(t[0])%360+360)%360/360,i=Gn(t[1]),r=Gn(t[2]),o=r<=.5?r*(i+1):r+i-r*i,a=2*r-o;return Yn(e=e||[],Vn(255*Wn(a,o,n+1/3)),Vn(255*Wn(a,o,n)),Vn(255*Wn(a,o,n-1/3)),1),4===t.length&&(e[3]=t[3]),e}function $n(t,e){var n=qn(t);if(n){for(var i=0;i<3;i++)n[i]=e<0?n[i]*(1-e)|0:(255-n[i])*e+n[i]|0,n[i]>255?n[i]=255:n[i]<0&&(n[i]=0);return ri(n,4===n.length?"rgba":"rgb")}}function Jn(t,e,n){if(e&&e.length&&t>=0&&t<=1){n=n||[];var i=t*(e.length-1),r=Math.floor(i),o=Math.ceil(i),a=e[r],s=e[o],l=i-r;return n[0]=Vn(Hn(a[0],s[0],l)),n[1]=Vn(Hn(a[1],s[1],l)),n[2]=Vn(Hn(a[2],s[2],l)),n[3]=Bn(Hn(a[3],s[3],l)),n}}var Qn=Jn;function ti(t,e,n){if(e&&e.length&&t>=0&&t<=1){var i=t*(e.length-1),r=Math.floor(i),o=Math.ceil(i),a=qn(e[r]),s=qn(e[o]),l=i-r,u=ri([Vn(Hn(a[0],s[0],l)),Vn(Hn(a[1],s[1],l)),Vn(Hn(a[2],s[2],l)),Bn(Hn(a[3],s[3],l))],"rgba");return n?{color:u,leftIndex:r,rightIndex:o,value:i}:u}}var ei=ti;function ni(t,e,n,i){var r=qn(t);if(t)return r=function(t){if(t){var e,n,i=t[0]/255,r=t[1]/255,o=t[2]/255,a=Math.min(i,r,o),s=Math.max(i,r,o),l=s-a,u=(s+a)/2;if(0===l)e=0,n=0;else{n=u<.5?l/(s+a):l/(2-s-a);var h=((s-i)/6+l/2)/l,c=((s-r)/6+l/2)/l,p=((s-o)/6+l/2)/l;i===s?e=p-c:r===s?e=1/3+h-p:o===s&&(e=2/3+c-h),e<0&&(e+=1),e>1&&(e-=1)}var d=[360*e,n,u];return null!=t[3]&&d.push(t[3]),d}}(r),null!=e&&(r[0]=function(t){return(t=Math.round(t))<0?0:t>360?360:t}(e)),null!=n&&(r[1]=Gn(n)),null!=i&&(r[2]=Gn(i)),ri(Kn(r),"rgba")}function ii(t,e){var n=qn(t);if(n&&null!=e)return n[3]=Bn(e),ri(n,"rgba")}function ri(t,e){if(t&&t.length){var n=t[0]+","+t[1]+","+t[2];return"rgba"!==e&&"hsva"!==e&&"hsla"!==e||(n+=","+t[3]),e+"("+n+")"}}function oi(t,e){var n=qn(t);return n?(.299*n[0]+.587*n[1]+.114*n[2])*n[3]/255+(1-n[3])*e:0}var ai=new En(100);function si(t){if(U(t)){var e=ai.get(t);return e||(e=$n(t,-.1),ai.put(t,e)),e}if(Q(t)){var n=A({},t);return n.colorStops=z(t.colorStops,(function(t){return{offset:t.offset,color:$n(t.color,-.1)}})),n}return t}var li=Object.freeze({__proto__:null,parse:qn,lift:$n,toHex:function(t){var e=qn(t);if(e)return((1<<24)+(e[0]<<16)+(e[1]<<8)+ +e[2]).toString(16).slice(1)},fastLerp:Jn,fastMapToColor:Qn,lerp:ti,mapToColor:ei,modifyHSL:ni,modifyAlpha:ii,stringify:ri,lum:oi,random:function(){return ri([Math.round(255*Math.random()),Math.round(255*Math.random()),Math.round(255*Math.random())],"rgb")},liftColor:si}),ui=Math.round;function hi(t){var e;if(t&&"transparent"!==t){if("string"==typeof t&&t.indexOf("rgba")>-1){var n=qn(t);n&&(t="rgb("+n[0]+","+n[1]+","+n[2]+")",e=n[3])}}else t="none";return{color:t,opacity:null==e?1:e}}var ci=1e-4;function pi(t){return t-1e-4}function di(t){return ui(1e3*t)/1e3}function fi(t){return ui(1e4*t)/1e4}var gi={left:"start",right:"end",center:"middle",middle:"middle"};function yi(t){return t&&!!t.image}function vi(t){return yi(t)||function(t){return t&&!!t.svgElement}(t)}function mi(t){return"linear"===t.type}function xi(t){return"radial"===t.type}function _i(t){return t&&("linear"===t.type||"radial"===t.type)}function bi(t){return"url(#"+t+")"}function wi(t){var e=t.getGlobalScale(),n=Math.max(e[0],e[1]);return Math.max(Math.ceil(Math.log(n)/Math.log(10)),1)}function Si(t){var e=t.x||0,n=t.y||0,i=(t.rotation||0)*wt,r=rt(t.scaleX,1),o=rt(t.scaleY,1),a=t.skewX||0,s=t.skewY||0,l=[];return(e||n)&&l.push("translate("+e+"px,"+n+"px)"),i&&l.push("rotate("+i+")"),1===r&&1===o||l.push("scale("+r+","+o+")"),(a||s)&&l.push("skew("+ui(a*wt)+"deg, "+ui(s*wt)+"deg)"),l.join(" ")}var Mi=r.hasGlobalWindow&&X(window.btoa)?function(t){return window.btoa(unescape(encodeURIComponent(t)))}:"undefined"!=typeof Buffer?function(t){return Buffer.from(t).toString("base64")}:function(t){return null},Ii=Array.prototype.slice;function Ti(t,e,n){return(e-t)*n+t}function Ci(t,e,n,i){for(var r=e.length,o=0;oi?e:t,o=Math.min(n,i),a=r[o-1]||{color:[0,0,0,0],offset:0},s=o;sa)i.length=a;else for(var s=o;s=1},t.prototype.getAdditiveTrack=function(){return this._additiveTrack},t.prototype.addKeyframe=function(t,e,n){this._needsSort=!0;var i=this.keyframes,r=i.length,o=!1,a=6,s=e;if(N(e)){var l=function(t){return N(t&&t[0])?2:1}(e);a=l,(1===l&&!j(e[0])||2===l&&!j(e[0][0]))&&(o=!0)}else if(j(e)&&!nt(e))a=0;else if(U(e))if(isNaN(+e)){var u=qn(e);u&&(s=u,a=3)}else a=0;else if(Q(e)){var h=A({},s);h.colorStops=z(e.colorStops,(function(t){return{offset:t.offset,color:qn(t.color)}})),mi(e)?a=4:xi(e)&&(a=5),s=h}0===r?this.valType=a:a===this.valType&&6!==a||(o=!0),this.discrete=this.discrete||o;var c={time:t,value:s,rawValue:e,percent:0};return n&&(c.easing=n,c.easingFunc=X(n)?n:an[n]||Pn(n)),i.push(c),c},t.prototype.prepare=function(t,e){var n=this.keyframes;this._needsSort&&n.sort((function(t,e){return t.time-e.time}));for(var i=this.valType,r=n.length,o=n[r-1],a=this.discrete,s=Ni(i),l=Ri(i),u=0;u=0&&!(l[n].percent<=e);n--);n=d(n,u-2)}else{for(n=p;ne);n++);n=d(n-1,u-2)}r=l[n+1],i=l[n]}if(i&&r){this._lastFr=n,this._lastFrP=e;var f=r.percent-i.percent,g=0===f?1:d((e-i.percent)/f,1);r.easingFunc&&(g=r.easingFunc(g));var y=o?this._additiveValue:c?Ei:t[h];if(!Ni(s)&&!c||y||(y=this._additiveValue=[]),this.discrete)t[h]=g<1?i.rawValue:r.rawValue;else if(Ni(s))1===s?Ci(y,i[a],r[a],g):function(t,e,n,i){for(var r=e.length,o=r&&e[0].length,a=0;a0&&s.addKeyframe(0,Pi(l),i),this._trackKeys.push(a)}s.addKeyframe(t,Pi(e[a]),i)}return this._maxTime=Math.max(this._maxTime,t),this},t.prototype.pause=function(){this._clip.pause(),this._paused=!0},t.prototype.resume=function(){this._clip.resume(),this._paused=!1},t.prototype.isPaused=function(){return!!this._paused},t.prototype.duration=function(t){return this._maxTime=t,this._force=!0,this},t.prototype._doneCallback=function(){this._setTracksFinished(),this._clip=null;var t=this._doneCbs;if(t)for(var e=t.length,n=0;n0)){this._started=1;for(var e=this,n=[],i=this._maxTime||0,r=0;r1){var a=o.pop();r.addKeyframe(a.time,t[i]),r.prepare(this._maxTime,r.getAdditiveTrack())}}}},t}();function Bi(){return(new Date).getTime()}var Fi,Gi,Wi=function(t){function e(e){var n=t.call(this)||this;return n._running=!1,n._time=0,n._pausedTime=0,n._pauseStart=0,n._paused=!1,e=e||{},n.stage=e.stage||{},n}return n(e,t),e.prototype.addClip=function(t){t.animation&&this.removeClip(t),this._head?(this._tail.next=t,t.prev=this._tail,t.next=null,this._tail=t):this._head=this._tail=t,t.animation=this},e.prototype.addAnimator=function(t){t.animation=this;var e=t.getClip();e&&this.addClip(e)},e.prototype.removeClip=function(t){if(t.animation){var e=t.prev,n=t.next;e?e.next=n:this._head=n,n?n.prev=e:this._tail=e,t.next=t.prev=t.animation=null}},e.prototype.removeAnimator=function(t){var e=t.getClip();e&&this.removeClip(e),t.animation=null},e.prototype.update=function(t){for(var e=Bi()-this._pausedTime,n=e-this._time,i=this._head;i;){var r=i.next;i.step(e,n)?(i.ondestroy(),this.removeClip(i),i=r):i=r}this._time=e,t||(this.trigger("frame",n),this.stage.update&&this.stage.update())},e.prototype._startLoop=function(){var t=this;this._running=!0,on((function e(){t._running&&(on(e),!t._paused&&t.update())}))},e.prototype.start=function(){this._running||(this._time=Bi(),this._pausedTime=0,this._startLoop())},e.prototype.stop=function(){this._running=!1},e.prototype.pause=function(){this._paused||(this._pauseStart=Bi(),this._paused=!0)},e.prototype.resume=function(){this._paused&&(this._pausedTime+=Bi()-this._pauseStart,this._paused=!1)},e.prototype.clear=function(){for(var t=this._head;t;){var e=t.next;t.prev=t.next=t.animation=null,t=e}this._head=this._tail=null},e.prototype.isFinished=function(){return null==this._head},e.prototype.animate=function(t,e){e=e||{},this.start();var n=new Vi(t,e.loop);return this.addAnimator(n),n},e}(jt),Hi=r.domSupported,Yi=(Gi={pointerdown:1,pointerup:1,pointermove:1,pointerout:1},{mouse:Fi=["click","dblclick","mousewheel","wheel","mouseout","mouseup","mousedown","mousemove","contextmenu"],touch:["touchstart","touchend","touchmove"],pointer:z(Fi,(function(t){var e=t.replace("mouse","pointer");return Gi.hasOwnProperty(e)?e:t}))}),Xi=["mousemove","mouseup"],Ui=["pointermove","pointerup"],Zi=!1;function ji(t){var e=t.pointerType;return"pen"===e||"touch"===e}function qi(t){t&&(t.zrByTouch=!0)}function Ki(t,e){for(var n=e,i=!1;n&&9!==n.nodeType&&!(i=n.domBelongToZr||n!==e&&n===t.painterRoot);)n=n.parentNode;return i}var $i=function(t,e){this.stopPropagation=bt,this.stopImmediatePropagation=bt,this.preventDefault=bt,this.type=e.type,this.target=this.currentTarget=t.dom,this.pointerType=e.pointerType,this.clientX=e.clientX,this.clientY=e.clientY},Ji={mousedown:function(t){t=ce(this.dom,t),this.__mayPointerCapture=[t.zrX,t.zrY],this.trigger("mousedown",t)},mousemove:function(t){t=ce(this.dom,t);var e=this.__mayPointerCapture;!e||t.zrX===e[0]&&t.zrY===e[1]||this.__togglePointerCapture(!0),this.trigger("mousemove",t)},mouseup:function(t){t=ce(this.dom,t),this.__togglePointerCapture(!1),this.trigger("mouseup",t)},mouseout:function(t){Ki(this,(t=ce(this.dom,t)).toElement||t.relatedTarget)||(this.__pointerCapturing&&(t.zrEventControl="no_globalout"),this.trigger("mouseout",t))},wheel:function(t){Zi=!0,t=ce(this.dom,t),this.trigger("mousewheel",t)},mousewheel:function(t){Zi||(t=ce(this.dom,t),this.trigger("mousewheel",t))},touchstart:function(t){qi(t=ce(this.dom,t)),this.__lastTouchMoment=new Date,this.handler.processGesture(t,"start"),Ji.mousemove.call(this,t),Ji.mousedown.call(this,t)},touchmove:function(t){qi(t=ce(this.dom,t)),this.handler.processGesture(t,"change"),Ji.mousemove.call(this,t)},touchend:function(t){qi(t=ce(this.dom,t)),this.handler.processGesture(t,"end"),Ji.mouseup.call(this,t),+new Date-+this.__lastTouchMoment<300&&Ji.click.call(this,t)},pointerdown:function(t){Ji.mousedown.call(this,t)},pointermove:function(t){ji(t)||Ji.mousemove.call(this,t)},pointerup:function(t){Ji.mouseup.call(this,t)},pointerout:function(t){ji(t)||Ji.mouseout.call(this,t)}};E(["click","dblclick","contextmenu"],(function(t){Ji[t]=function(e){e=ce(this.dom,e),this.trigger(t,e)}}));var Qi={pointermove:function(t){ji(t)||Qi.mousemove.call(this,t)},pointerup:function(t){Qi.mouseup.call(this,t)},mousemove:function(t){this.trigger("mousemove",t)},mouseup:function(t){var e=this.__pointerCapturing;this.__togglePointerCapture(!1),this.trigger("mouseup",t),e&&(t.zrEventControl="only_globalout",this.trigger("mouseout",t))}};function tr(t,e){var n=e.domHandlers;r.pointerEventsSupported?E(Yi.pointer,(function(i){nr(e,i,(function(e){n[i].call(t,e)}))})):(r.touchEventsSupported&&E(Yi.touch,(function(i){nr(e,i,(function(r){n[i].call(t,r),function(t){t.touching=!0,null!=t.touchTimer&&(clearTimeout(t.touchTimer),t.touchTimer=null),t.touchTimer=setTimeout((function(){t.touching=!1,t.touchTimer=null}),700)}(e)}))})),E(Yi.mouse,(function(i){nr(e,i,(function(r){r=he(r),e.touching||n[i].call(t,r)}))})))}function er(t,e){function n(n){nr(e,n,(function(i){i=he(i),Ki(t,i.target)||(i=function(t,e){return ce(t.dom,new $i(t,e),!0)}(t,i),e.domHandlers[n].call(t,i))}),{capture:!0})}r.pointerEventsSupported?E(Ui,n):r.touchEventsSupported||E(Xi,n)}function nr(t,e,n,i){t.mounted[e]=n,t.listenerOpts[e]=i,pe(t.domTarget,e,n,i)}function ir(t){var e,n,i,r,o=t.mounted;for(var a in o)o.hasOwnProperty(a)&&(e=t.domTarget,n=a,i=o[a],r=t.listenerOpts[a],e.removeEventListener(n,i,r));t.mounted={}}var rr=function(t,e){this.mounted={},this.listenerOpts={},this.touching=!1,this.domTarget=t,this.domHandlers=e},or=function(t){function e(e,n){var i=t.call(this)||this;return i.__pointerCapturing=!1,i.dom=e,i.painterRoot=n,i._localHandlerScope=new rr(e,Ji),Hi&&(i._globalHandlerScope=new rr(document,Qi)),tr(i,i._localHandlerScope),i}return n(e,t),e.prototype.dispose=function(){ir(this._localHandlerScope),Hi&&ir(this._globalHandlerScope)},e.prototype.setCursor=function(t){this.dom.style&&(this.dom.style.cursor=t||"default")},e.prototype.__togglePointerCapture=function(t){if(this.__mayPointerCapture=null,Hi&&+this.__pointerCapturing^+t){this.__pointerCapturing=t;var e=this._globalHandlerScope;t?er(this,e):ir(e)}},e}(jt),ar=1;r.hasGlobalWindow&&(ar=Math.max(window.devicePixelRatio||window.screen&&window.screen.deviceXDPI/window.screen.logicalXDPI||1,1));var sr=ar,lr="#333",ur="#ccc",hr=xe,cr=5e-5;function pr(t){return t>cr||t<-5e-5}var dr=[],fr=[],gr=[1,0,0,1,0,0],yr=Math.abs,vr=function(){function t(){}return t.prototype.getLocalTransform=function(e){return t.getLocalTransform(this,e)},t.prototype.setPosition=function(t){this.x=t[0],this.y=t[1]},t.prototype.setScale=function(t){this.scaleX=t[0],this.scaleY=t[1]},t.prototype.setSkew=function(t){this.skewX=t[0],this.skewY=t[1]},t.prototype.setOrigin=function(t){this.originX=t[0],this.originY=t[1]},t.prototype.needLocalTransform=function(){return pr(this.rotation)||pr(this.x)||pr(this.y)||pr(this.scaleX-1)||pr(this.scaleY-1)||pr(this.skewX)||pr(this.skewY)},t.prototype.updateTransform=function(){var t=this.parent&&this.parent.transform,e=this.needLocalTransform(),n=this.transform;e||t?(n=n||[1,0,0,1,0,0],e?this.getLocalTransform(n):hr(n),t&&(e?be(n,t,n):_e(n,t)),this.transform=n,this._resolveGlobalScaleRatio(n)):n&&(hr(n),this.invTransform=null)},t.prototype._resolveGlobalScaleRatio=function(t){var e=this.globalScaleRatio;if(null!=e&&1!==e){this.getGlobalScale(dr);var n=dr[0]<0?-1:1,i=dr[1]<0?-1:1,r=((dr[0]-n)*e+n)/dr[0]||0,o=((dr[1]-i)*e+i)/dr[1]||0;t[0]*=r,t[1]*=r,t[2]*=o,t[3]*=o}this.invTransform=this.invTransform||[1,0,0,1,0,0],Ie(this.invTransform,t)},t.prototype.getComputedTransform=function(){for(var t=this,e=[];t;)e.push(t),t=t.parent;for(;t=e.pop();)t.updateTransform();return this.transform},t.prototype.setLocalTransform=function(t){if(t){var e=t[0]*t[0]+t[1]*t[1],n=t[2]*t[2]+t[3]*t[3],i=Math.atan2(t[1],t[0]),r=Math.PI/2+i-Math.atan2(t[3],t[2]);n=Math.sqrt(n)*Math.cos(r),e=Math.sqrt(e),this.skewX=r,this.skewY=0,this.rotation=-i,this.x=+t[4],this.y=+t[5],this.scaleX=e,this.scaleY=n,this.originX=0,this.originY=0}},t.prototype.decomposeTransform=function(){if(this.transform){var t=this.parent,e=this.transform;t&&t.transform&&(t.invTransform=t.invTransform||[1,0,0,1,0,0],be(fr,t.invTransform,e),e=fr);var n=this.originX,i=this.originY;(n||i)&&(gr[4]=n,gr[5]=i,be(fr,e,gr),fr[4]-=n,fr[5]-=i,e=fr),this.setLocalTransform(e)}},t.prototype.getGlobalScale=function(t){var e=this.transform;return t=t||[],e?(t[0]=Math.sqrt(e[0]*e[0]+e[1]*e[1]),t[1]=Math.sqrt(e[2]*e[2]+e[3]*e[3]),e[0]<0&&(t[0]=-t[0]),e[3]<0&&(t[1]=-t[1]),t):(t[0]=1,t[1]=1,t)},t.prototype.transformCoordToLocal=function(t,e){var n=[t,e],i=this.invTransform;return i&&Wt(n,n,i),n},t.prototype.transformCoordToGlobal=function(t,e){var n=[t,e],i=this.transform;return i&&Wt(n,n,i),n},t.prototype.getLineScale=function(){var t=this.transform;return t&&yr(t[0]-1)>1e-10&&yr(t[3]-1)>1e-10?Math.sqrt(yr(t[0]*t[3]-t[2]*t[1])):1},t.prototype.copyTransform=function(t){xr(this,t)},t.getLocalTransform=function(t,e){e=e||[];var n=t.originX||0,i=t.originY||0,r=t.scaleX,o=t.scaleY,a=t.anchorX,s=t.anchorY,l=t.rotation||0,u=t.x,h=t.y,c=t.skewX?Math.tan(t.skewX):0,p=t.skewY?Math.tan(-t.skewY):0;if(n||i||a||s){var d=n+a,f=i+s;e[4]=-d*r-c*f*o,e[5]=-f*o-p*d*r}else e[4]=e[5]=0;return e[0]=r,e[3]=o,e[1]=p*r,e[2]=c*o,l&&Se(e,e,l),e[4]+=n+u,e[5]+=i+h,e},t.initDefaultProps=function(){var e=t.prototype;e.scaleX=e.scaleY=e.globalScaleRatio=1,e.x=e.y=e.originX=e.originY=e.skewX=e.skewY=e.rotation=e.anchorX=e.anchorY=0}(),t}(),mr=["x","y","originX","originY","anchorX","anchorY","rotation","scaleX","scaleY","skewX","skewY"];function xr(t,e){for(var n=0;n=0?parseFloat(t)/100*e:parseFloat(t):t}function Dr(t,e,n){var i=e.position||"inside",r=null!=e.distance?e.distance:5,o=n.height,a=n.width,s=o/2,l=n.x,u=n.y,h="left",c="top";if(i instanceof Array)l+=Cr(i[0],n.width),u+=Cr(i[1],n.height),h=null,c=null;else switch(i){case"left":l-=r,u+=s,h="right",c="middle";break;case"right":l+=r+a,u+=s,c="middle";break;case"top":l+=a/2,u-=r,h="center",c="bottom";break;case"bottom":l+=a/2,u+=o+r,h="center";break;case"inside":l+=a/2,u+=s,h="center",c="middle";break;case"insideLeft":l+=r,u+=s,c="middle";break;case"insideRight":l+=a-r,u+=s,h="right",c="middle";break;case"insideTop":l+=a/2,u+=r,h="center";break;case"insideBottom":l+=a/2,u+=o-r,h="center",c="bottom";break;case"insideTopLeft":l+=r,u+=r;break;case"insideTopRight":l+=a-r,u+=r,h="right";break;case"insideBottomLeft":l+=r,u+=o-r,c="bottom";break;case"insideBottomRight":l+=a-r,u+=o-r,h="right",c="bottom"}return(t=t||{}).x=l,t.y=u,t.align=h,t.verticalAlign=c,t}var Ar="__zr_normal__",kr=mr.concat(["ignore"]),Lr=V(mr,(function(t,e){return t[e]=!0,t}),{ignore:!1}),Pr={},Or=new ze(0,0,0,0),Rr=function(){function t(t){this.id=M(),this.animators=[],this.currentStates=[],this.states={},this._init(t)}return t.prototype._init=function(t){this.attr(t)},t.prototype.drift=function(t,e,n){switch(this.draggable){case"horizontal":e=0;break;case"vertical":t=0}var i=this.transform;i||(i=this.transform=[1,0,0,1,0,0]),i[4]+=t,i[5]+=e,this.decomposeTransform(),this.markRedraw()},t.prototype.beforeUpdate=function(){},t.prototype.afterUpdate=function(){},t.prototype.update=function(){this.updateTransform(),this.__dirty&&this.updateInnerText()},t.prototype.updateInnerText=function(t){var e=this._textContent;if(e&&(!e.ignore||t)){this.textConfig||(this.textConfig={});var n=this.textConfig,i=n.local,r=e.innerTransformable,o=void 0,a=void 0,s=!1;r.parent=i?this:null;var l=!1;if(r.copyTransform(e),null!=n.position){var u=Or;n.layoutRect?u.copy(n.layoutRect):u.copy(this.getBoundingRect()),i||u.applyTransform(this.transform),this.calculateTextPosition?this.calculateTextPosition(Pr,n,u):Dr(Pr,n,u),r.x=Pr.x,r.y=Pr.y,o=Pr.align,a=Pr.verticalAlign;var h=n.origin;if(h&&null!=n.rotation){var c=void 0,p=void 0;"center"===h?(c=.5*u.width,p=.5*u.height):(c=Cr(h[0],u.width),p=Cr(h[1],u.height)),l=!0,r.originX=-r.x+c+(i?0:u.x),r.originY=-r.y+p+(i?0:u.y)}}null!=n.rotation&&(r.rotation=n.rotation);var d=n.offset;d&&(r.x+=d[0],r.y+=d[1],l||(r.originX=-d[0],r.originY=-d[1]));var f=null==n.inside?"string"==typeof n.position&&n.position.indexOf("inside")>=0:n.inside,g=this._innerTextDefaultStyle||(this._innerTextDefaultStyle={}),y=void 0,v=void 0,m=void 0;f&&this.canBeInsideText()?(y=n.insideFill,v=n.insideStroke,null!=y&&"auto"!==y||(y=this.getInsideTextFill()),null!=v&&"auto"!==v||(v=this.getInsideTextStroke(y),m=!0)):(y=n.outsideFill,v=n.outsideStroke,null!=y&&"auto"!==y||(y=this.getOutsideFill()),null!=v&&"auto"!==v||(v=this.getOutsideStroke(y),m=!0)),(y=y||"#000")===g.fill&&v===g.stroke&&m===g.autoStroke&&o===g.align&&a===g.verticalAlign||(s=!0,g.fill=y,g.stroke=v,g.autoStroke=m,g.align=o,g.verticalAlign=a,e.setDefaultTextStyle(g)),e.__dirty|=1,s&&e.dirtyStyle(!0)}},t.prototype.canBeInsideText=function(){return!0},t.prototype.getInsideTextFill=function(){return"#fff"},t.prototype.getInsideTextStroke=function(t){return"#000"},t.prototype.getOutsideFill=function(){return this.__zr&&this.__zr.isDarkMode()?ur:lr},t.prototype.getOutsideStroke=function(t){var e=this.__zr&&this.__zr.getBackgroundColor(),n="string"==typeof e&&qn(e);n||(n=[255,255,255,1]);for(var i=n[3],r=this.__zr.isDarkMode(),o=0;o<3;o++)n[o]=n[o]*i+(r?0:255)*(1-i);return n[3]=1,ri(n,"rgba")},t.prototype.traverse=function(t,e){},t.prototype.attrKV=function(t,e){"textConfig"===t?this.setTextConfig(e):"textContent"===t?this.setTextContent(e):"clipPath"===t?this.setClipPath(e):"extra"===t?(this.extra=this.extra||{},A(this.extra,e)):this[t]=e},t.prototype.hide=function(){this.ignore=!0,this.markRedraw()},t.prototype.show=function(){this.ignore=!1,this.markRedraw()},t.prototype.attr=function(t,e){if("string"==typeof t)this.attrKV(t,e);else if(q(t))for(var n=G(t),i=0;i0},t.prototype.getState=function(t){return this.states[t]},t.prototype.ensureState=function(t){var e=this.states;return e[t]||(e[t]={}),e[t]},t.prototype.clearStates=function(t){this.useState(Ar,!1,t)},t.prototype.useState=function(t,e,n,i){var r=t===Ar;if(this.hasState()||!r){var o=this.currentStates,a=this.stateTransition;if(!(P(o,t)>=0)||!e&&1!==o.length){var s;if(this.stateProxy&&!r&&(s=this.stateProxy(t)),s||(s=this.states&&this.states[t]),s||r){r||this.saveCurrentToNormalState(s);var l=!!(s&&s.hoverLayer||i);l&&this._toggleHoverLayerFlag(!0),this._applyStateObj(t,s,this._normalState,e,!n&&!this.__inHover&&a&&a.duration>0,a);var u=this._textContent,h=this._textGuide;return u&&u.useState(t,e,n,l),h&&h.useState(t,e,n,l),r?(this.currentStates=[],this._normalState={}):e?this.currentStates.push(t):this.currentStates=[t],this._updateAnimationTargets(),this.markRedraw(),!l&&this.__inHover&&(this._toggleHoverLayerFlag(!1),this.__dirty&=-2),s}I("State "+t+" not exists.")}}},t.prototype.useStates=function(t,e,n){if(t.length){var i=[],r=this.currentStates,o=t.length,a=o===r.length;if(a)for(var s=0;s0,d);var f=this._textContent,g=this._textGuide;f&&f.useStates(t,e,c),g&&g.useStates(t,e,c),this._updateAnimationTargets(),this.currentStates=t.slice(),this.markRedraw(),!c&&this.__inHover&&(this._toggleHoverLayerFlag(!1),this.__dirty&=-2)}else this.clearStates()},t.prototype.isSilent=function(){for(var t=this.silent,e=this.parent;!t&&e;){if(e.silent){t=!0;break}e=e.parent}return t},t.prototype._updateAnimationTargets=function(){for(var t=0;t=0){var n=this.currentStates.slice();n.splice(e,1),this.useStates(n)}},t.prototype.replaceState=function(t,e,n){var i=this.currentStates.slice(),r=P(i,t),o=P(i,e)>=0;r>=0?o?i.splice(r,1):i[r]=e:n&&!o&&i.push(e),this.useStates(i)},t.prototype.toggleState=function(t,e){e?this.useState(t,!0):this.removeState(t)},t.prototype._mergeStates=function(t){for(var e,n={},i=0;i=0&&e.splice(n,1)})),this.animators.push(t),n&&n.animation.addAnimator(t),n&&n.wakeUp()},t.prototype.updateDuringAnimation=function(t){this.markRedraw()},t.prototype.stopAnimation=function(t,e){for(var n=this.animators,i=n.length,r=[],o=0;o0&&n.during&&o[0].during((function(t,e){n.during(e)}));for(var p=0;p0||r.force&&!a.length){var w,S=void 0,M=void 0,I=void 0;if(s){M={},p&&(S={});for(_=0;_=0&&(n.splice(i,0,t),this._doAdd(t))}return this},e.prototype.replace=function(t,e){var n=P(this._children,t);return n>=0&&this.replaceAt(e,n),this},e.prototype.replaceAt=function(t,e){var n=this._children,i=n[e];if(t&&t!==this&&t.parent!==this&&t!==i){n[e]=t,i.parent=null;var r=this.__zr;r&&i.removeSelfFromZr(r),this._doAdd(t)}return this},e.prototype._doAdd=function(t){t.parent&&t.parent.remove(t),t.parent=this;var e=this.__zr;e&&e!==t.__zr&&t.addSelfToZr(e),e&&e.refresh()},e.prototype.remove=function(t){var e=this.__zr,n=this._children,i=P(n,t);return i<0||(n.splice(i,1),t.parent=null,e&&t.removeSelfFromZr(e),e&&e.refresh()),this},e.prototype.removeAll=function(){for(var t=this._children,e=this.__zr,n=0;n0&&(this._stillFrameAccum++,this._stillFrameAccum>this._sleepAfterStill&&this.animation.stop())},t.prototype.setSleepAfterStill=function(t){this._sleepAfterStill=t},t.prototype.wakeUp=function(){this._disposed||(this.animation.start(),this._stillFrameAccum=0)},t.prototype.refreshHover=function(){this._needsRefreshHover=!0},t.prototype.refreshHoverImmediately=function(){this._disposed||(this._needsRefreshHover=!1,this.painter.refreshHover&&"canvas"===this.painter.getType()&&this.painter.refreshHover())},t.prototype.resize=function(t){this._disposed||(t=t||{},this.painter.resize(t.width,t.height),this.handler.resize())},t.prototype.clearAnimation=function(){this._disposed||this.animation.clear()},t.prototype.getWidth=function(){if(!this._disposed)return this.painter.getWidth()},t.prototype.getHeight=function(){if(!this._disposed)return this.painter.getHeight()},t.prototype.setCursorStyle=function(t){this._disposed||this.handler.setCursorStyle(t)},t.prototype.findHover=function(t,e){if(!this._disposed)return this.handler.findHover(t,e)},t.prototype.on=function(t,e,n){return this._disposed||this.handler.on(t,e,n),this},t.prototype.off=function(t,e){this._disposed||this.handler.off(t,e)},t.prototype.trigger=function(t,e){this._disposed||this.handler.trigger(t,e)},t.prototype.clear=function(){if(!this._disposed){for(var t=this.storage.getRoots(),e=0;e0){if(t<=r)return a;if(t>=o)return s}else{if(t>=r)return a;if(t<=o)return s}else{if(t===r)return a;if(t===o)return s}return(t-r)/l*u+a}function $r(t,e){switch(t){case"center":case"middle":t="50%";break;case"left":case"top":t="0%";break;case"right":case"bottom":t="100%"}return U(t)?(n=t,n.replace(/^\s+|\s+$/g,"")).match(/%$/)?parseFloat(t)/100*e:parseFloat(t):null==t?NaN:+t;var n}function Jr(t,e,n){return null==e&&(e=10),e=Math.min(Math.max(0,e),20),t=(+t).toFixed(e),n?t:+t}function Qr(t){return t.sort((function(t,e){return t-e})),t}function to(t){if(t=+t,isNaN(t))return 0;if(t>1e-14)for(var e=1,n=0;n<15;n++,e*=10)if(Math.round(t*e)/e===t)return n;return eo(t)}function eo(t){var e=t.toString().toLowerCase(),n=e.indexOf("e"),i=n>0?+e.slice(n+1):0,r=n>0?n:e.length,o=e.indexOf("."),a=o<0?0:r-1-o;return Math.max(0,a-i)}function no(t,e){var n=Math.log,i=Math.LN10,r=Math.floor(n(t[1]-t[0])/i),o=Math.round(n(Math.abs(e[1]-e[0]))/i),a=Math.min(Math.max(-r+o,0),20);return isFinite(a)?a:20}function io(t,e){var n=V(t,(function(t,e){return t+(isNaN(e)?0:e)}),0);if(0===n)return[];for(var i=Math.pow(10,e),r=z(t,(function(t){return(isNaN(t)?0:t)/n*i*100})),o=100*i,a=z(r,(function(t){return Math.floor(t)})),s=V(a,(function(t,e){return t+e}),0),l=z(r,(function(t,e){return t-a[e]}));su&&(u=l[c],h=c);++a[h],l[h]=0,++s}return z(a,(function(t){return t/i}))}function ro(t,e){var n=Math.max(to(t),to(e)),i=t+e;return n>20?i:Jr(i,n)}var oo=9007199254740991;function ao(t){var e=2*Math.PI;return(t%e+e)%e}function so(t){return t>-1e-4&&t=10&&e++,e}function po(t,e){var n=co(t),i=Math.pow(10,n),r=t/i;return t=(e?r<1.5?1:r<2.5?2:r<4?3:r<7?5:10:r<1?1:r<2?2:r<3?3:r<5?5:10)*i,n>=-20?+t.toFixed(n<0?-n:0):t}function fo(t,e){var n=(t.length-1)*e+1,i=Math.floor(n),r=+t[i-1],o=n-i;return o?r+o*(t[i]-r):r}function go(t){t.sort((function(t,e){return s(t,e,0)?-1:1}));for(var e=-1/0,n=1,i=0;i=0||r&&P(r,s)<0)){var l=n.getShallow(s,e);null!=l&&(o[t[a][0]]=l)}}return o}}var ra=ia([["fill","color"],["shadowBlur"],["shadowOffsetX"],["shadowOffsetY"],["opacity"],["shadowColor"]]),oa=function(){function t(){}return t.prototype.getAreaStyle=function(t,e){return ra(this,t,e)},t}(),aa=new En(50);function sa(t){if("string"==typeof t){var e=aa.get(t);return e&&e.image}return t}function la(t,e,n,i,r){if(t){if("string"==typeof t){if(e&&e.__zrImageSrc===t||!n)return e;var o=aa.get(t),a={hostEl:n,cb:i,cbPayload:r};return o?!ha(e=o.image)&&o.pending.push(a):((e=h.loadImage(t,ua,ua)).__zrImageSrc=t,aa.put(t,e.__cachedImgObj={image:e,pending:[a]})),e}return t}return e}function ua(){var t=this.__cachedImgObj;this.onload=this.onerror=this.__cachedImgObj=null;for(var e=0;e=a;l++)s-=a;var u=br(n,e);return u>s&&(n="",u=0),s=t-u,r.ellipsis=n,r.ellipsisWidth=u,r.contentWidth=s,r.containerWidth=t,r}function fa(t,e){var n=e.containerWidth,i=e.font,r=e.contentWidth;if(!n)return"";var o=br(t,i);if(o<=n)return t;for(var a=0;;a++){if(o<=r||a>=e.maxIterations){t+=e.ellipsis;break}var s=0===a?ga(t,r,e.ascCharWidth,e.cnCharWidth):o>0?Math.floor(t.length*r/o):0;o=br(t=t.substr(0,s),i)}return""===t&&(t=e.placeholder),t}function ga(t,e,n,i){for(var r=0,o=0,a=t.length;o0&&f+i.accumWidth>i.width&&(o=e.split("\n"),c=!0),i.accumWidth=f}else{var g=wa(e,h,i.width,i.breakAll,i.accumWidth);i.accumWidth=g.accumWidth+d,a=g.linesWidths,o=g.lines}}else o=e.split("\n");for(var y=0;y=32&&e<=591||e>=880&&e<=4351||e>=4608&&e<=5119||e>=7680&&e<=8303}(t)||!!_a[t]}function wa(t,e,n,i,r){for(var o=[],a=[],s="",l="",u=0,h=0,c=0;cn:r+h+d>n)?h?(s||l)&&(f?(s||(s=l,l="",h=u=0),o.push(s),a.push(h-u),l+=p,s="",h=u+=d):(l&&(s+=l,l="",u=0),o.push(s),a.push(h),s=p,h=d)):f?(o.push(l),a.push(u),l=p,u=d):(o.push(p),a.push(d)):(h+=d,f?(l+=p,u+=d):(l&&(s+=l,l="",u=0),s+=p))}else l&&(s+=l,h+=u),o.push(s),a.push(h),s="",l="",u=0,h=0}return o.length||s||(s=t,l="",u=0),l&&(s+=l),s&&(o.push(s),a.push(h)),1===o.length&&(h+=r),{accumWidth:h,lines:o,linesWidths:a}}var Sa="__zr_style_"+Math.round(10*Math.random()),Ma={shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,shadowColor:"#000",opacity:1,blend:"source-over"},Ia={style:{shadowBlur:!0,shadowOffsetX:!0,shadowOffsetY:!0,shadowColor:!0,opacity:!0}};Ma[Sa]=!0;var Ta=["z","z2","invisible"],Ca=["invisible"],Da=function(t){function e(e){return t.call(this,e)||this}var i;return n(e,t),e.prototype._init=function(e){for(var n=G(e),i=0;i1e-4)return s[0]=t-n,s[1]=e-i,l[0]=t+n,void(l[1]=e+i);if(Ea[0]=Ra(r)*n+t,Ea[1]=Oa(r)*i+e,za[0]=Ra(o)*n+t,za[1]=Oa(o)*i+e,u(s,Ea,za),h(l,Ea,za),(r%=Na)<0&&(r+=Na),(o%=Na)<0&&(o+=Na),r>o&&!a?o+=Na:rr&&(Va[0]=Ra(d)*n+t,Va[1]=Oa(d)*i+e,u(s,Va,s),h(l,Va,l))}var Ua={M:1,L:2,C:3,Q:4,A:5,Z:6,R:7},Za=[],ja=[],qa=[],Ka=[],$a=[],Ja=[],Qa=Math.min,ts=Math.max,es=Math.cos,ns=Math.sin,is=Math.abs,rs=Math.PI,os=2*rs,as="undefined"!=typeof Float32Array,ss=[];function ls(t){return Math.round(t/rs*1e8)/1e8%2*rs}function us(t,e){var n=ls(t[0]);n<0&&(n+=os);var i=n-t[0],r=t[1];r+=i,!e&&r-n>=os?r=n+os:e&&n-r>=os?r=n-os:!e&&n>r?r=n+(os-ls(n-r)):e&&n0&&(this._ux=is(n/sr/t)||0,this._uy=is(n/sr/e)||0)},t.prototype.setDPR=function(t){this.dpr=t},t.prototype.setContext=function(t){this._ctx=t},t.prototype.getContext=function(){return this._ctx},t.prototype.beginPath=function(){return this._ctx&&this._ctx.beginPath(),this.reset(),this},t.prototype.reset=function(){this._saveData&&(this._len=0),this._pathSegLen&&(this._pathSegLen=null,this._pathLen=0),this._version++},t.prototype.moveTo=function(t,e){return this._drawPendingPt(),this.addData(Ua.M,t,e),this._ctx&&this._ctx.moveTo(t,e),this._x0=t,this._y0=e,this._xi=t,this._yi=e,this},t.prototype.lineTo=function(t,e){var n=is(t-this._xi),i=is(e-this._yi),r=n>this._ux||i>this._uy;if(this.addData(Ua.L,t,e),this._ctx&&r&&this._ctx.lineTo(t,e),r)this._xi=t,this._yi=e,this._pendingPtDist=0;else{var o=n*n+i*i;o>this._pendingPtDist&&(this._pendingPtX=t,this._pendingPtY=e,this._pendingPtDist=o)}return this},t.prototype.bezierCurveTo=function(t,e,n,i,r,o){return this._drawPendingPt(),this.addData(Ua.C,t,e,n,i,r,o),this._ctx&&this._ctx.bezierCurveTo(t,e,n,i,r,o),this._xi=r,this._yi=o,this},t.prototype.quadraticCurveTo=function(t,e,n,i){return this._drawPendingPt(),this.addData(Ua.Q,t,e,n,i),this._ctx&&this._ctx.quadraticCurveTo(t,e,n,i),this._xi=n,this._yi=i,this},t.prototype.arc=function(t,e,n,i,r,o){this._drawPendingPt(),ss[0]=i,ss[1]=r,us(ss,o),i=ss[0];var a=(r=ss[1])-i;return this.addData(Ua.A,t,e,n,n,i,a,0,o?0:1),this._ctx&&this._ctx.arc(t,e,n,i,r,o),this._xi=es(r)*n+t,this._yi=ns(r)*n+e,this},t.prototype.arcTo=function(t,e,n,i,r){return this._drawPendingPt(),this._ctx&&this._ctx.arcTo(t,e,n,i,r),this},t.prototype.rect=function(t,e,n,i){return this._drawPendingPt(),this._ctx&&this._ctx.rect(t,e,n,i),this.addData(Ua.R,t,e,n,i),this},t.prototype.closePath=function(){this._drawPendingPt(),this.addData(Ua.Z);var t=this._ctx,e=this._x0,n=this._y0;return t&&t.closePath(),this._xi=e,this._yi=n,this},t.prototype.fill=function(t){t&&t.fill(),this.toStatic()},t.prototype.stroke=function(t){t&&t.stroke(),this.toStatic()},t.prototype.len=function(){return this._len},t.prototype.setData=function(t){var e=t.length;this.data&&this.data.length===e||!as||(this.data=new Float32Array(e));for(var n=0;nu.length&&(this._expandData(),u=this.data);for(var h=0;h0&&(this._ctx&&this._ctx.lineTo(this._pendingPtX,this._pendingPtY),this._pendingPtDist=0)},t.prototype._expandData=function(){if(!(this.data instanceof Array)){for(var t=[],e=0;e11&&(this.data=new Float32Array(t)))}},t.prototype.getBoundingRect=function(){qa[0]=qa[1]=$a[0]=$a[1]=Number.MAX_VALUE,Ka[0]=Ka[1]=Ja[0]=Ja[1]=-Number.MAX_VALUE;var t,e=this.data,n=0,i=0,r=0,o=0;for(t=0;tn||is(y)>i||c===e-1)&&(f=Math.sqrt(A*A+y*y),r=g,o=x);break;case Ua.C:var v=t[c++],m=t[c++],x=(g=t[c++],t[c++]),_=t[c++],b=t[c++];f=Mn(r,o,v,m,g,x,_,b,10),r=_,o=b;break;case Ua.Q:f=kn(r,o,v=t[c++],m=t[c++],g=t[c++],x=t[c++],10),r=g,o=x;break;case Ua.A:var w=t[c++],S=t[c++],M=t[c++],I=t[c++],T=t[c++],C=t[c++],D=C+T;c+=1,d&&(a=es(T)*M+w,s=ns(T)*I+S),f=ts(M,I)*Qa(os,Math.abs(C)),r=es(D)*M+w,o=ns(D)*I+S;break;case Ua.R:a=r=t[c++],s=o=t[c++],f=2*t[c++]+2*t[c++];break;case Ua.Z:var A=a-r;y=s-o;f=Math.sqrt(A*A+y*y),r=a,o=s}f>=0&&(l[h++]=f,u+=f)}return this._pathLen=u,u},t.prototype.rebuildPath=function(t,e){var n,i,r,o,a,s,l,u,h,c,p=this.data,d=this._ux,f=this._uy,g=this._len,y=e<1,v=0,m=0,x=0;if(!y||(this._pathSegLen||this._calculateLength(),l=this._pathSegLen,u=e*this._pathLen))t:for(var _=0;_0&&(t.lineTo(h,c),x=0),b){case Ua.M:n=r=p[_++],i=o=p[_++],t.moveTo(r,o);break;case Ua.L:a=p[_++],s=p[_++];var S=is(a-r),M=is(s-o);if(S>d||M>f){if(y){if(v+(j=l[m++])>u){var I=(u-v)/j;t.lineTo(r*(1-I)+a*I,o*(1-I)+s*I);break t}v+=j}t.lineTo(a,s),r=a,o=s,x=0}else{var T=S*S+M*M;T>x&&(h=a,c=s,x=T)}break;case Ua.C:var C=p[_++],D=p[_++],A=p[_++],k=p[_++],L=p[_++],P=p[_++];if(y){if(v+(j=l[m++])>u){wn(r,C,A,L,I=(u-v)/j,Za),wn(o,D,k,P,I,ja),t.bezierCurveTo(Za[1],ja[1],Za[2],ja[2],Za[3],ja[3]);break t}v+=j}t.bezierCurveTo(C,D,A,k,L,P),r=L,o=P;break;case Ua.Q:C=p[_++],D=p[_++],A=p[_++],k=p[_++];if(y){if(v+(j=l[m++])>u){Dn(r,C,A,I=(u-v)/j,Za),Dn(o,D,k,I,ja),t.quadraticCurveTo(Za[1],ja[1],Za[2],ja[2]);break t}v+=j}t.quadraticCurveTo(C,D,A,k),r=A,o=k;break;case Ua.A:var O=p[_++],R=p[_++],N=p[_++],E=p[_++],z=p[_++],V=p[_++],B=p[_++],F=!p[_++],G=N>E?N:E,W=is(N-E)>.001,H=z+V,Y=!1;if(y)v+(j=l[m++])>u&&(H=z+V*(u-v)/j,Y=!0),v+=j;if(W&&t.ellipse?t.ellipse(O,R,N,E,B,z,H,F):t.arc(O,R,G,z,H,F),Y)break t;w&&(n=es(z)*N+O,i=ns(z)*E+R),r=es(H)*N+O,o=ns(H)*E+R;break;case Ua.R:n=r=p[_],i=o=p[_+1],a=p[_++],s=p[_++];var X=p[_++],U=p[_++];if(y){if(v+(j=l[m++])>u){var Z=u-v;t.moveTo(a,s),t.lineTo(a+Qa(Z,X),s),(Z-=X)>0&&t.lineTo(a+X,s+Qa(Z,U)),(Z-=U)>0&&t.lineTo(a+ts(X-Z,0),s+U),(Z-=X)>0&&t.lineTo(a,s+ts(U-Z,0));break t}v+=j}t.rect(a,s,X,U);break;case Ua.Z:if(y){var j;if(v+(j=l[m++])>u){I=(u-v)/j;t.lineTo(r*(1-I)+n*I,o*(1-I)+i*I);break t}v+=j}t.closePath(),r=n,o=i}}},t.prototype.clone=function(){var e=new t,n=this.data;return e.data=n.slice?n.slice():Array.prototype.slice.call(n),e._len=this._len,e},t.CMD=Ua,t.initDefaultProps=function(){var e=t.prototype;e._saveData=!0,e._ux=0,e._uy=0,e._pendingPtDist=0,e._version=0}(),t}();function cs(t,e,n,i,r,o,a){if(0===r)return!1;var s=r,l=0;if(a>e+s&&a>i+s||at+s&&o>n+s||oe+c&&h>i+c&&h>o+c&&h>s+c||ht+c&&u>n+c&&u>r+c&&u>a+c||ue+u&&l>i+u&&l>o+u||lt+u&&s>n+u&&s>r+u||sn||h+ur&&(r+=ys);var p=Math.atan2(l,s);return p<0&&(p+=ys),p>=i&&p<=r||p+ys>=i&&p+ys<=r}function ms(t,e,n,i,r,o){if(o>e&&o>i||or?s:0}var xs=hs.CMD,_s=2*Math.PI;var bs=[-1,-1,-1],ws=[-1,-1];function Ss(t,e,n,i,r,o,a,s,l,u){if(u>e&&u>i&&u>o&&u>s||u1&&(h=void 0,h=ws[0],ws[0]=ws[1],ws[1]=h),f=mn(e,i,o,s,ws[0]),d>1&&(g=mn(e,i,o,s,ws[1]))),2===d?ve&&s>i&&s>o||s=0&&h<=1&&(r[l++]=h);else{var u=a*a-4*o*s;if(yn(u))(h=-a/(2*o))>=0&&h<=1&&(r[l++]=h);else if(u>0){var h,c=ln(u),p=(-a-c)/(2*o);(h=(-a+c)/(2*o))>=0&&h<=1&&(r[l++]=h),p>=0&&p<=1&&(r[l++]=p)}}return l}(e,i,o,s,bs);if(0===l)return 0;var u=Cn(e,i,o);if(u>=0&&u<=1){for(var h=0,c=In(e,i,o,u),p=0;pn||s<-n)return 0;var l=Math.sqrt(n*n-s*s);bs[0]=-l,bs[1]=l;var u=Math.abs(i-r);if(u<1e-4)return 0;if(u>=_s-1e-4){i=0,r=_s;var h=o?1:-1;return a>=bs[0]+t&&a<=bs[1]+t?h:0}if(i>r){var c=i;i=r,r=c}i<0&&(i+=_s,r+=_s);for(var p=0,d=0;d<2;d++){var f=bs[d];if(f+t>a){var g=Math.atan2(s,f);h=o?1:-1;g<0&&(g=_s+g),(g>=i&&g<=r||g+_s>=i&&g+_s<=r)&&(g>Math.PI/2&&g<1.5*Math.PI&&(h=-h),p+=h)}}return p}function Ts(t,e,n,i,r){for(var o,a,s,l,u=t.data,h=t.len(),c=0,p=0,d=0,f=0,g=0,y=0;y1&&(n||(c+=ms(p,d,f,g,i,r))),m&&(f=p=u[y],g=d=u[y+1]),v){case xs.M:p=f=u[y++],d=g=u[y++];break;case xs.L:if(n){if(cs(p,d,u[y],u[y+1],e,i,r))return!0}else c+=ms(p,d,u[y],u[y+1],i,r)||0;p=u[y++],d=u[y++];break;case xs.C:if(n){if(ps(p,d,u[y++],u[y++],u[y++],u[y++],u[y],u[y+1],e,i,r))return!0}else c+=Ss(p,d,u[y++],u[y++],u[y++],u[y++],u[y],u[y+1],i,r)||0;p=u[y++],d=u[y++];break;case xs.Q:if(n){if(ds(p,d,u[y++],u[y++],u[y],u[y+1],e,i,r))return!0}else c+=Ms(p,d,u[y++],u[y++],u[y],u[y+1],i,r)||0;p=u[y++],d=u[y++];break;case xs.A:var x=u[y++],_=u[y++],b=u[y++],w=u[y++],S=u[y++],M=u[y++];y+=1;var I=!!(1-u[y++]);o=Math.cos(S)*b+x,a=Math.sin(S)*w+_,m?(f=o,g=a):c+=ms(p,d,o,a,i,r);var T=(i-x)*w/b+x;if(n){if(vs(x,_,w,S,S+M,I,e,T,r))return!0}else c+=Is(x,_,w,S,S+M,I,T,r);p=Math.cos(S+M)*b+x,d=Math.sin(S+M)*w+_;break;case xs.R:if(f=p=u[y++],g=d=u[y++],o=f+u[y++],a=g+u[y++],n){if(cs(f,g,o,g,e,i,r)||cs(o,g,o,a,e,i,r)||cs(o,a,f,a,e,i,r)||cs(f,a,f,g,e,i,r))return!0}else c+=ms(o,g,o,a,i,r),c+=ms(f,a,f,g,i,r);break;case xs.Z:if(n){if(cs(p,d,f,g,e,i,r))return!0}else c+=ms(p,d,f,g,i,r);p=f,d=g}}return n||(s=d,l=g,Math.abs(s-l)<1e-4)||(c+=ms(p,d,f,g,i,r)||0),0!==c}var Cs=k({fill:"#000",stroke:null,strokePercent:1,fillOpacity:1,strokeOpacity:1,lineDashOffset:0,lineWidth:1,lineCap:"butt",miterLimit:10,strokeNoScale:!1,strokeFirst:!1},Ma),Ds={style:k({fill:!0,stroke:!0,strokePercent:!0,fillOpacity:!0,strokeOpacity:!0,lineDashOffset:!0,lineWidth:!0,miterLimit:!0},Ia.style)},As=mr.concat(["invisible","culling","z","z2","zlevel","parent"]),ks=function(t){function e(e){return t.call(this,e)||this}var i;return n(e,t),e.prototype.update=function(){var n=this;t.prototype.update.call(this);var i=this.style;if(i.decal){var r=this._decalEl=this._decalEl||new e;r.buildPath===e.prototype.buildPath&&(r.buildPath=function(t){n.buildPath(t,n.shape)}),r.silent=!0;var o=r.style;for(var a in i)o[a]!==i[a]&&(o[a]=i[a]);o.fill=i.fill?i.decal:null,o.decal=null,o.shadowColor=null,i.strokeFirst&&(o.stroke=null);for(var s=0;s.5?lr:e>.2?"#eee":ur}if(t)return ur}return lr},e.prototype.getInsideTextStroke=function(t){var e=this.style.fill;if(U(e)){var n=this.__zr;if(!(!n||!n.isDarkMode())===oi(t,0)<.4)return e}},e.prototype.buildPath=function(t,e,n){},e.prototype.pathUpdated=function(){this.__dirty&=-5},e.prototype.getUpdatedPathProxy=function(t){return!this.path&&this.createPathProxy(),this.path.beginPath(),this.buildPath(this.path,this.shape,t),this.path},e.prototype.createPathProxy=function(){this.path=new hs(!1)},e.prototype.hasStroke=function(){var t=this.style,e=t.stroke;return!(null==e||"none"===e||!(t.lineWidth>0))},e.prototype.hasFill=function(){var t=this.style.fill;return null!=t&&"none"!==t},e.prototype.getBoundingRect=function(){var t=this._rect,e=this.style,n=!t;if(n){var i=!1;this.path||(i=!0,this.createPathProxy());var r=this.path;(i||4&this.__dirty)&&(r.beginPath(),this.buildPath(r,this.shape,!1),this.pathUpdated()),t=r.getBoundingRect()}if(this._rect=t,this.hasStroke()&&this.path&&this.path.len()>0){var o=this._rectStroke||(this._rectStroke=t.clone());if(this.__dirty||n){o.copy(t);var a=e.strokeNoScale?this.getLineScale():1,s=e.lineWidth;if(!this.hasFill()){var l=this.strokeContainThreshold;s=Math.max(s,null==l?4:l)}a>1e-10&&(o.width+=s/a,o.height+=s/a,o.x-=s/a/2,o.y-=s/a/2)}return o}return t},e.prototype.contain=function(t,e){var n=this.transformCoordToLocal(t,e),i=this.getBoundingRect(),r=this.style;if(t=n[0],e=n[1],i.contain(t,e)){var o=this.path;if(this.hasStroke()){var a=r.lineWidth,s=r.strokeNoScale?this.getLineScale():1;if(s>1e-10&&(this.hasFill()||(a=Math.max(a,this.strokeContainThreshold)),function(t,e,n,i){return Ts(t,e,!0,n,i)}(o,a/s,t,e)))return!0}if(this.hasFill())return function(t,e,n){return Ts(t,0,!1,e,n)}(o,t,e)}return!1},e.prototype.dirtyShape=function(){this.__dirty|=4,this._rect&&(this._rect=null),this._decalEl&&this._decalEl.dirtyShape(),this.markRedraw()},e.prototype.dirty=function(){this.dirtyStyle(),this.dirtyShape()},e.prototype.animateShape=function(t){return this.animate("shape",t)},e.prototype.updateDuringAnimation=function(t){"style"===t?this.dirtyStyle():"shape"===t?this.dirtyShape():this.markRedraw()},e.prototype.attrKV=function(e,n){"shape"===e?this.setShape(n):t.prototype.attrKV.call(this,e,n)},e.prototype.setShape=function(t,e){var n=this.shape;return n||(n=this.shape={}),"string"==typeof t?n[t]=e:A(n,t),this.dirtyShape(),this},e.prototype.shapeChanged=function(){return!!(4&this.__dirty)},e.prototype.createStyle=function(t){return mt(Cs,t)},e.prototype._innerSaveToNormal=function(e){t.prototype._innerSaveToNormal.call(this,e);var n=this._normalState;e.shape&&!n.shape&&(n.shape=A({},this.shape))},e.prototype._applyStateObj=function(e,n,i,r,o,a){t.prototype._applyStateObj.call(this,e,n,i,r,o,a);var s,l=!(n&&r);if(n&&n.shape?o?r?s=n.shape:(s=A({},i.shape),A(s,n.shape)):(s=A({},r?this.shape:i.shape),A(s,n.shape)):l&&(s=i.shape),s)if(o){this.shape=A({},this.shape);for(var u={},h=G(s),c=0;c0},e.prototype.hasFill=function(){var t=this.style.fill;return null!=t&&"none"!==t},e.prototype.createStyle=function(t){return mt(Ls,t)},e.prototype.setBoundingRect=function(t){this._rect=t},e.prototype.getBoundingRect=function(){var t=this.style;if(!this._rect){var e=t.text;null!=e?e+="":e="";var n=Sr(e,t.font,t.textAlign,t.textBaseline);if(n.x+=t.x||0,n.y+=t.y||0,this.hasStroke()){var i=t.lineWidth;n.x-=i/2,n.y-=i/2,n.width+=i,n.height+=i}this._rect=n}return this._rect},e.initDefaultProps=void(e.prototype.dirtyRectTolerance=10),e}(Da);Ps.prototype.type="tspan";var Os=k({x:0,y:0},Ma),Rs={style:k({x:!0,y:!0,width:!0,height:!0,sx:!0,sy:!0,sWidth:!0,sHeight:!0},Ia.style)};var Ns=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.createStyle=function(t){return mt(Os,t)},e.prototype._getSize=function(t){var e=this.style,n=e[t];if(null!=n)return n;var i,r=(i=e.image)&&"string"!=typeof i&&i.width&&i.height?e.image:this.__image;if(!r)return 0;var o="width"===t?"height":"width",a=e[o];return null==a?r[t]:r[t]/r[o]*a},e.prototype.getWidth=function(){return this._getSize("width")},e.prototype.getHeight=function(){return this._getSize("height")},e.prototype.getAnimationStyleProps=function(){return Rs},e.prototype.getBoundingRect=function(){var t=this.style;return this._rect||(this._rect=new ze(t.x||0,t.y||0,this.getWidth(),this.getHeight())),this._rect},e}(Da);Ns.prototype.type="image";var Es=Math.round;function zs(t,e,n){if(e){var i=e.x1,r=e.x2,o=e.y1,a=e.y2;t.x1=i,t.x2=r,t.y1=o,t.y2=a;var s=n&&n.lineWidth;return s?(Es(2*i)===Es(2*r)&&(t.x1=t.x2=Bs(i,s,!0)),Es(2*o)===Es(2*a)&&(t.y1=t.y2=Bs(o,s,!0)),t):t}}function Vs(t,e,n){if(e){var i=e.x,r=e.y,o=e.width,a=e.height;t.x=i,t.y=r,t.width=o,t.height=a;var s=n&&n.lineWidth;return s?(t.x=Bs(i,s,!0),t.y=Bs(r,s,!0),t.width=Math.max(Bs(i+o,s,!1)-t.x,0===o?0:1),t.height=Math.max(Bs(r+a,s,!1)-t.y,0===a?0:1),t):t}}function Bs(t,e,n){if(!e)return t;var i=Es(2*t);return(i+Es(e))%2==0?i/2:(i+(n?1:-1))/2}var Fs=function(){this.x=0,this.y=0,this.width=0,this.height=0},Gs={},Ws=function(t){function e(e){return t.call(this,e)||this}return n(e,t),e.prototype.getDefaultShape=function(){return new Fs},e.prototype.buildPath=function(t,e){var n,i,r,o;if(this.subPixelOptimize){var a=Vs(Gs,e,this.style);n=a.x,i=a.y,r=a.width,o=a.height,a.r=e.r,e=a}else n=e.x,i=e.y,r=e.width,o=e.height;e.r?function(t,e){var n,i,r,o,a,s=e.x,l=e.y,u=e.width,h=e.height,c=e.r;u<0&&(s+=u,u=-u),h<0&&(l+=h,h=-h),"number"==typeof c?n=i=r=o=c:c instanceof Array?1===c.length?n=i=r=o=c[0]:2===c.length?(n=r=c[0],i=o=c[1]):3===c.length?(n=c[0],i=o=c[1],r=c[2]):(n=c[0],i=c[1],r=c[2],o=c[3]):n=i=r=o=0,n+i>u&&(n*=u/(a=n+i),i*=u/a),r+o>u&&(r*=u/(a=r+o),o*=u/a),i+r>h&&(i*=h/(a=i+r),r*=h/a),n+o>h&&(n*=h/(a=n+o),o*=h/a),t.moveTo(s+n,l),t.lineTo(s+u-i,l),0!==i&&t.arc(s+u-i,l+i,i,-Math.PI/2,0),t.lineTo(s+u,l+h-r),0!==r&&t.arc(s+u-r,l+h-r,r,0,Math.PI/2),t.lineTo(s+o,l+h),0!==o&&t.arc(s+o,l+h-o,o,Math.PI/2,Math.PI),t.lineTo(s,l+n),0!==n&&t.arc(s+n,l+n,n,Math.PI,1.5*Math.PI)}(t,e):t.rect(n,i,r,o)},e.prototype.isZeroArea=function(){return!this.shape.width||!this.shape.height},e}(ks);Ws.prototype.type="rect";var Hs={fill:"#000"},Ys={style:k({fill:!0,stroke:!0,fillOpacity:!0,strokeOpacity:!0,lineWidth:!0,fontSize:!0,lineHeight:!0,width:!0,height:!0,textShadowColor:!0,textShadowBlur:!0,textShadowOffsetX:!0,textShadowOffsetY:!0,backgroundColor:!0,padding:!0,borderColor:!0,borderWidth:!0,borderRadius:!0},Ia.style)},Xs=function(t){function e(e){var n=t.call(this)||this;return n.type="text",n._children=[],n._defaultStyle=Hs,n.attr(e),n}return n(e,t),e.prototype.childrenRef=function(){return this._children},e.prototype.update=function(){t.prototype.update.call(this),this.styleChanged()&&this._updateSubTexts();for(var e=0;ed&&h){var f=Math.floor(d/l);n=n.slice(0,f)}if(t&&a&&null!=c)for(var g=da(c,o,e.ellipsis,{minChar:e.truncateMinChar,placeholder:e.placeholder}),y=0;y0,T=null!=t.width&&("truncate"===t.overflow||"break"===t.overflow||"breakAll"===t.overflow),C=i.calculatedLineHeight,D=0;Dl&&xa(n,t.substring(l,u),e,s),xa(n,i[2],e,s,i[1]),l=ca.lastIndex}lo){b>0?(m.tokens=m.tokens.slice(0,b),y(m,_,x),n.lines=n.lines.slice(0,v+1)):n.lines=n.lines.slice(0,v);break t}var C=w.width,D=null==C||"auto"===C;if("string"==typeof C&&"%"===C.charAt(C.length-1))P.percentWidth=C,h.push(P),P.contentWidth=br(P.text,I);else{if(D){var A=w.backgroundColor,k=A&&A.image;k&&ha(k=sa(k))&&(P.width=Math.max(P.width,k.width*T/k.height))}var L=f&&null!=r?r-_:null;null!=L&&L=0&&"right"===(C=x[T]).align;)this._placeToken(C,t,b,f,I,"right",y),w-=C.width,I-=C.width,T--;for(M+=(n-(M-d)-(g-I)-w)/2;S<=T;)C=x[S],this._placeToken(C,t,b,f,M+C.width/2,"center",y),M+=C.width,S++;f+=b}},e.prototype._placeToken=function(t,e,n,i,r,o,s){var l=e.rich[t.styleName]||{};l.text=t.text;var u=t.verticalAlign,h=i+n/2;"top"===u?h=i+t.height/2:"bottom"===u&&(h=i+n-t.height/2),!t.isLineHolder&&il(l)&&this._renderBackground(l,e,"right"===o?r-t.width:"center"===o?r-t.width/2:r,h-t.height/2,t.width,t.height);var c=!!l.backgroundColor,p=t.textPadding;p&&(r=el(r,o,p),h-=t.height/2-p[0]-t.innerHeight/2);var d=this._getOrCreateChild(Ps),f=d.createStyle();d.useStyle(f);var g=this._defaultStyle,y=!1,v=0,m=tl("fill"in l?l.fill:"fill"in e?e.fill:(y=!0,g.fill)),x=Qs("stroke"in l?l.stroke:"stroke"in e?e.stroke:c||s||g.autoStroke&&!y?null:(v=2,g.stroke)),_=l.textShadowBlur>0||e.textShadowBlur>0;f.text=t.text,f.x=r,f.y=h,_&&(f.shadowBlur=l.textShadowBlur||e.textShadowBlur||0,f.shadowColor=l.textShadowColor||e.textShadowColor||"transparent",f.shadowOffsetX=l.textShadowOffsetX||e.textShadowOffsetX||0,f.shadowOffsetY=l.textShadowOffsetY||e.textShadowOffsetY||0),f.textAlign=o,f.textBaseline="middle",f.font=t.font||a,f.opacity=ot(l.opacity,e.opacity,1),Ks(f,l),x&&(f.lineWidth=ot(l.lineWidth,e.lineWidth,v),f.lineDash=rt(l.lineDash,e.lineDash),f.lineDashOffset=e.lineDashOffset||0,f.stroke=x),m&&(f.fill=m);var b=t.contentWidth,w=t.contentHeight;d.setBoundingRect(new ze(Mr(f.x,b,f.textAlign),Ir(f.y,w,f.textBaseline),b,w))},e.prototype._renderBackground=function(t,e,n,i,r,o){var a,s,l,u=t.backgroundColor,h=t.borderWidth,c=t.borderColor,p=u&&u.image,d=u&&!p,f=t.borderRadius,g=this;if(d||t.lineHeight||h&&c){(a=this._getOrCreateChild(Ws)).useStyle(a.createStyle()),a.style.fill=null;var y=a.shape;y.x=n,y.y=i,y.width=r,y.height=o,y.r=f,a.dirtyShape()}if(d)(l=a.style).fill=u||null,l.fillOpacity=rt(t.fillOpacity,1);else if(p){(s=this._getOrCreateChild(Ns)).onload=function(){g.dirtyStyle()};var v=s.style;v.image=u.image,v.x=n,v.y=i,v.width=r,v.height=o}h&&c&&((l=a.style).lineWidth=h,l.stroke=c,l.strokeOpacity=rt(t.strokeOpacity,1),l.lineDash=t.borderDash,l.lineDashOffset=t.borderDashOffset||0,a.strokeContainThreshold=0,a.hasFill()&&a.hasStroke()&&(l.strokeFirst=!0,l.lineWidth*=2));var m=(a||s).style;m.shadowBlur=t.shadowBlur||0,m.shadowColor=t.shadowColor||"transparent",m.shadowOffsetX=t.shadowOffsetX||0,m.shadowOffsetY=t.shadowOffsetY||0,m.opacity=ot(t.opacity,e.opacity,1)},e.makeFont=function(t){var e="";return $s(t)&&(e=[t.fontStyle,t.fontWeight,qs(t.fontSize),t.fontFamily||"sans-serif"].join(" ")),e&&ut(e)||t.textFont||t.font},e}(Da),Us={left:!0,right:1,center:1},Zs={top:1,bottom:1,middle:1},js=["fontStyle","fontWeight","fontSize","fontFamily"];function qs(t){return"string"!=typeof t||-1===t.indexOf("px")&&-1===t.indexOf("rem")&&-1===t.indexOf("em")?isNaN(+t)?"12px":t+"px":t}function Ks(t,e){for(var n=0;n=0,o=!1;if(t instanceof ks){var a=ll(t),s=r&&a.selectFill||a.normalFill,l=r&&a.selectStroke||a.normalStroke;if(ml(s)||ml(l)){var u=(i=i||{}).style||{};"inherit"===u.fill?(o=!0,i=A({},i),(u=A({},u)).fill=s):!ml(u.fill)&&ml(s)?(o=!0,i=A({},i),(u=A({},u)).fill=si(s)):!ml(u.stroke)&&ml(l)&&(o||(i=A({},i),u=A({},u)),u.stroke=si(l)),i.style=u}}if(i&&null==i.z2){o||(i=A({},i));var h=t.z2EmphasisLift;i.z2=t.z2+(null!=h?h:pl)}return i}(this,0,e,n);if("blur"===t)return function(t,e,n){var i=P(t.currentStates,e)>=0,r=t.style.opacity,o=i?null:function(t,e,n,i){for(var r=t.style,o={},a=0;a0){var o={dataIndex:r,seriesIndex:t.seriesIndex};null!=i&&(o.dataType=i),e.push(o)}}))})),e}function Ul(t,e,n){Jl(t,!0),Cl(t,kl),jl(t,e,n)}function Zl(t,e,n,i){i?function(t){Jl(t,!1)}(t):Ul(t,e,n)}function jl(t,e,n){var i=rl(t);null!=e?(i.focus=e,i.blurScope=n):i.focus&&(i.focus=null)}var ql=["emphasis","blur","select"],Kl={itemStyle:"getItemStyle",lineStyle:"getLineStyle",areaStyle:"getAreaStyle"};function $l(t,e,n,i){n=n||"itemStyle";for(var r=0;r1&&(a*=su(f),s*=su(f));var g=(r===o?-1:1)*su((a*a*(s*s)-a*a*(d*d)-s*s*(p*p))/(a*a*(d*d)+s*s*(p*p)))||0,y=g*a*d/s,v=g*-s*p/a,m=(t+n)/2+uu(c)*y-lu(c)*v,x=(e+i)/2+lu(c)*y+uu(c)*v,_=du([1,0],[(p-y)/a,(d-v)/s]),b=[(p-y)/a,(d-v)/s],w=[(-1*p-y)/a,(-1*d-v)/s],S=du(b,w);if(pu(b,w)<=-1&&(S=hu),pu(b,w)>=1&&(S=0),S<0){var M=Math.round(S/hu*1e6)/1e6;S=2*hu+M%2*hu}h.addData(u,m,x,a,s,_,S,c,o)}var gu=/([mlvhzcqtsa])([^mlvhzcqtsa]*)/gi,yu=/-?([0-9]*\.)?[0-9]+([eE]-?[0-9]+)?/g;var vu=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.applyTransform=function(t){},e}(ks);function mu(t){return null!=t.setData}function xu(t,e){var n=function(t){var e=new hs;if(!t)return e;var n,i=0,r=0,o=i,a=r,s=hs.CMD,l=t.match(gu);if(!l)return e;for(var u=0;uk*k+L*L&&(M=T,I=C),{cx:M,cy:I,x0:-h,y0:-c,x1:M*(r/b-1),y1:I*(r/b-1)}}function Vu(t,e){var n,i=Ru(e.r,0),r=Ru(e.r0||0,0),o=i>0;if(o||r>0){if(o||(i=r,r=0),r>i){var a=i;i=r,r=a}var s=e.startAngle,l=e.endAngle;if(!isNaN(s)&&!isNaN(l)){var u=e.cx,h=e.cy,c=!!e.clockwise,p=Pu(l-s),d=p>Cu&&p%Cu;if(d>Eu&&(p=d),i>Eu)if(p>Cu-Eu)t.moveTo(u+i*Au(s),h+i*Du(s)),t.arc(u,h,i,s,l,!c),r>Eu&&(t.moveTo(u+r*Au(l),h+r*Du(l)),t.arc(u,h,r,l,s,c));else{var f=void 0,g=void 0,y=void 0,v=void 0,m=void 0,x=void 0,_=void 0,b=void 0,w=void 0,S=void 0,M=void 0,I=void 0,T=void 0,C=void 0,D=void 0,A=void 0,k=i*Au(s),L=i*Du(s),P=r*Au(l),O=r*Du(l),R=p>Eu;if(R){var N=e.cornerRadius;N&&(n=function(t){var e;if(Y(t)){var n=t.length;if(!n)return t;e=1===n?[t[0],t[0],0,0]:2===n?[t[0],t[0],t[1],t[1]]:3===n?t.concat(t[2]):t}else e=[t,t,t,t];return e}(N),f=n[0],g=n[1],y=n[2],v=n[3]);var E=Pu(i-r)/2;if(m=Nu(E,y),x=Nu(E,v),_=Nu(E,f),b=Nu(E,g),M=w=Ru(m,x),I=S=Ru(_,b),(w>Eu||S>Eu)&&(T=i*Au(l),C=i*Du(l),D=r*Au(s),A=r*Du(s),pEu){var X=Nu(y,M),U=Nu(v,M),Z=zu(D,A,k,L,i,X,c),j=zu(T,C,P,O,i,U,c);t.moveTo(u+Z.cx+Z.x0,h+Z.cy+Z.y0),M0&&t.arc(u+Z.cx,h+Z.cy,X,Lu(Z.y0,Z.x0),Lu(Z.y1,Z.x1),!c),t.arc(u,h,i,Lu(Z.cy+Z.y1,Z.cx+Z.x1),Lu(j.cy+j.y1,j.cx+j.x1),!c),U>0&&t.arc(u+j.cx,h+j.cy,U,Lu(j.y1,j.x1),Lu(j.y0,j.x0),!c))}else t.moveTo(u+k,h+L),t.arc(u,h,i,s,l,!c);else t.moveTo(u+k,h+L);if(r>Eu&&R)if(I>Eu){X=Nu(f,I),Z=zu(P,O,T,C,r,-(U=Nu(g,I)),c),j=zu(k,L,D,A,r,-X,c);t.lineTo(u+Z.cx+Z.x0,h+Z.cy+Z.y0),I0&&t.arc(u+Z.cx,h+Z.cy,U,Lu(Z.y0,Z.x0),Lu(Z.y1,Z.x1),!c),t.arc(u,h,r,Lu(Z.cy+Z.y1,Z.cx+Z.x1),Lu(j.cy+j.y1,j.cx+j.x1),c),X>0&&t.arc(u+j.cx,h+j.cy,X,Lu(j.y1,j.x1),Lu(j.y0,j.x0),!c))}else t.lineTo(u+P,h+O),t.arc(u,h,r,l,s,c);else t.lineTo(u+P,h+O)}else t.moveTo(u,h);t.closePath()}}}var Bu=function(){this.cx=0,this.cy=0,this.r0=0,this.r=0,this.startAngle=0,this.endAngle=2*Math.PI,this.clockwise=!0,this.cornerRadius=0},Fu=function(t){function e(e){return t.call(this,e)||this}return n(e,t),e.prototype.getDefaultShape=function(){return new Bu},e.prototype.buildPath=function(t,e){Vu(t,e)},e.prototype.isZeroArea=function(){return this.shape.startAngle===this.shape.endAngle||this.shape.r===this.shape.r0},e}(ks);Fu.prototype.type="sector";var Gu=function(){this.cx=0,this.cy=0,this.r=0,this.r0=0},Wu=function(t){function e(e){return t.call(this,e)||this}return n(e,t),e.prototype.getDefaultShape=function(){return new Gu},e.prototype.buildPath=function(t,e){var n=e.cx,i=e.cy,r=2*Math.PI;t.moveTo(n+e.r,i),t.arc(n,i,e.r,0,r,!1),t.moveTo(n+e.r0,i),t.arc(n,i,e.r0,0,r,!0)},e}(ks);function Hu(t,e,n){var i=e.smooth,r=e.points;if(r&&r.length>=2){if(i){var o=function(t,e,n,i){var r,o,a,s,l=[],u=[],h=[],c=[];if(i){a=[1/0,1/0],s=[-1/0,-1/0];for(var p=0,d=t.length;plh[1]){if(a=!1,r)return a;var u=Math.abs(lh[0]-sh[1]),h=Math.abs(sh[0]-lh[1]);Math.min(u,h)>i.len()&&(u0){var c={duration:h.duration,delay:h.delay||0,easing:h.easing,done:o,force:!!o||!!a,setToFinal:!u,scope:t,during:a};l?e.animateFrom(n,c):e.animateTo(n,c)}else e.stopAnimation(),!l&&e.attr(n),a&&a(1),o&&o()}function vh(t,e,n,i,r,o){yh("update",t,e,n,i,r,o)}function mh(t,e,n,i,r,o){yh("enter",t,e,n,i,r,o)}function xh(t){if(!t.__zr)return!0;for(var e=0;eMath.abs(o[1])?o[0]>0?"right":"left":o[1]>0?"bottom":"top"}function Wh(t){return!t.isGroup}function Hh(t,e,n){if(t&&e){var i,r=(i={},t.traverse((function(t){Wh(t)&&t.anid&&(i[t.anid]=t)})),i);e.traverse((function(t){if(Wh(t)&&t.anid){var e=r[t.anid];if(e){var i=o(t);t.attr(o(e)),vh(t,i,n,rl(t).dataIndex)}}}))}function o(t){var e={x:t.x,y:t.y,rotation:t.rotation};return function(t){return null!=t.shape}(t)&&(e.shape=A({},t.shape)),e}}function Yh(t,e){return z(t,(function(t){var n=t[0];n=Mh(n,e.x),n=Ih(n,e.x+e.width);var i=t[1];return i=Mh(i,e.y),[n,i=Ih(i,e.y+e.height)]}))}function Xh(t,e){var n=Mh(t.x,e.x),i=Ih(t.x+t.width,e.x+e.width),r=Mh(t.y,e.y),o=Ih(t.y+t.height,e.y+e.height);if(i>=n&&o>=r)return{x:n,y:r,width:i-n,height:o-r}}function Uh(t,e,n){var i=A({rectHover:!0},e),r=i.style={strokeNoScale:!0};if(n=n||{x:-1,y:-1,width:2,height:2},t)return 0===t.indexOf("image://")?(r.image=t.slice(8),k(r,n),new Ns(i)):Ph(t.replace("path://",""),i,n,"center")}function Zh(t,e,n,i,r){for(var o=0,a=r[r.length-1];o=-1e-6)return!1;var f=t-r,g=e-o,y=qh(f,g,u,h)/d;if(y<0||y>1)return!1;var v=qh(f,g,c,p)/d;return!(v<0||v>1)}function qh(t,e,n,i){return t*i-n*e}function Kh(t){var e=t.itemTooltipOption,n=t.componentModel,i=t.itemName,r=U(e)?{formatter:e}:e,o=n.mainType,a=n.componentIndex,s={componentType:o,name:i,$vars:["name"]};s[o+"Index"]=a;var l=t.formatterParamsExtra;l&&E(G(l),(function(t){_t(s,t)||(s[t]=l[t],s.$vars.push(t))}));var u=rl(t.el);u.componentMainType=o,u.componentIndex=a,u.tooltipConfig={name:i,option:k({content:i,encodeHTMLContent:!0,formatterParams:s},r)}}function $h(t,e){var n;t.isGroup&&(n=e(t)),n||t.traverse(e)}function Jh(t,e){if(t)if(Y(t))for(var n=0;n-1?Lc:Oc;function zc(t,e){t=t.toUpperCase(),Nc[t]=new Cc(e),Rc[t]=e}function Vc(t){return Nc[t]}zc(Pc,{time:{month:["January","February","March","April","May","June","July","August","September","October","November","December"],monthAbbr:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayOfWeek:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayOfWeekAbbr:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]},legend:{selector:{all:"All",inverse:"Inv"}},toolbox:{brush:{title:{rect:"Box Select",polygon:"Lasso Select",lineX:"Horizontally Select",lineY:"Vertically Select",keep:"Keep Selections",clear:"Clear Selections"}},dataView:{title:"Data View",lang:["Data View","Close","Refresh"]},dataZoom:{title:{zoom:"Zoom",back:"Zoom Reset"}},magicType:{title:{line:"Switch to Line Chart",bar:"Switch to Bar Chart",stack:"Stack",tiled:"Tile"}},restore:{title:"Restore"},saveAsImage:{title:"Save as Image",lang:["Right Click to Save Image"]}},series:{typeNames:{pie:"Pie chart",bar:"Bar chart",line:"Line chart",scatter:"Scatter plot",effectScatter:"Ripple scatter plot",radar:"Radar chart",tree:"Tree",treemap:"Treemap",boxplot:"Boxplot",candlestick:"Candlestick",k:"K line chart",heatmap:"Heat map",map:"Map",parallel:"Parallel coordinate map",lines:"Line graph",graph:"Relationship graph",sankey:"Sankey diagram",funnel:"Funnel chart",gauge:"Gauge",pictorialBar:"Pictorial bar",themeRiver:"Theme River Map",sunburst:"Sunburst",custom:"Custom chart",chart:"Chart"}},aria:{general:{withTitle:'This is a chart about "{title}"',withoutTitle:"This is a chart"},series:{single:{prefix:"",withName:" with type {seriesType} named {seriesName}.",withoutName:" with type {seriesType}."},multiple:{prefix:". It consists of {seriesCount} series count.",withName:" The {seriesId} series is a {seriesType} representing {seriesName}.",withoutName:" The {seriesId} series is a {seriesType}.",separator:{middle:"",end:""}}},data:{allData:"The data is as follows: ",partialData:"The first {displayCnt} items are: ",withName:"the data for {name} is {value}",withoutName:"{value}",separator:{middle:", ",end:". "}}}}),zc(Lc,{time:{month:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],monthAbbr:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],dayOfWeek:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],dayOfWeekAbbr:["日","一","二","三","四","五","六"]},legend:{selector:{all:"全选",inverse:"反选"}},toolbox:{brush:{title:{rect:"矩形选择",polygon:"圈选",lineX:"横向选择",lineY:"纵向选择",keep:"保持选择",clear:"清除选择"}},dataView:{title:"数据视图",lang:["数据视图","关闭","刷新"]},dataZoom:{title:{zoom:"区域缩放",back:"区域缩放还原"}},magicType:{title:{line:"切换为折线图",bar:"切换为柱状图",stack:"切换为堆叠",tiled:"切换为平铺"}},restore:{title:"还原"},saveAsImage:{title:"保存为图片",lang:["右键另存为图片"]}},series:{typeNames:{pie:"饼图",bar:"柱状图",line:"折线图",scatter:"散点图",effectScatter:"涟漪散点图",radar:"雷达图",tree:"树图",treemap:"矩形树图",boxplot:"箱型图",candlestick:"K线图",k:"K线图",heatmap:"热力图",map:"地图",parallel:"平行坐标图",lines:"线图",graph:"关系图",sankey:"桑基图",funnel:"漏斗图",gauge:"仪表盘图",pictorialBar:"象形柱图",themeRiver:"主题河流图",sunburst:"旭日图",custom:"自定义图表",chart:"图表"}},aria:{general:{withTitle:"这是一个关于“{title}”的图表。",withoutTitle:"这是一个图表,"},series:{single:{prefix:"",withName:"图表类型是{seriesType},表示{seriesName}。",withoutName:"图表类型是{seriesType}。"},multiple:{prefix:"它由{seriesCount}个图表系列组成。",withName:"第{seriesId}个系列是一个表示{seriesName}的{seriesType},",withoutName:"第{seriesId}个系列是一个{seriesType},",separator:{middle:";",end:"。"}}},data:{allData:"其数据是——",partialData:"其中,前{displayCnt}项是——",withName:"{name}的数据是{value}",withoutName:"{value}",separator:{middle:",",end:""}}}});var Bc=1e3,Fc=6e4,Gc=36e5,Wc=864e5,Hc=31536e6,Yc={year:"{yyyy}",month:"{MMM}",day:"{d}",hour:"{HH}:{mm}",minute:"{HH}:{mm}",second:"{HH}:{mm}:{ss}",millisecond:"{HH}:{mm}:{ss} {SSS}",none:"{yyyy}-{MM}-{dd} {HH}:{mm}:{ss} {SSS}"},Xc="{yyyy}-{MM}-{dd}",Uc={year:"{yyyy}",month:"{yyyy}-{MM}",day:Xc,hour:Xc+" "+Yc.hour,minute:Xc+" "+Yc.minute,second:Xc+" "+Yc.second,millisecond:Yc.none},Zc=["year","month","day","hour","minute","second","millisecond"],jc=["year","half-year","quarter","month","week","half-week","day","half-day","quarter-day","hour","minute","second","millisecond"];function qc(t,e){return"0000".substr(0,e-(t+="").length)+t}function Kc(t){switch(t){case"half-year":case"quarter":return"month";case"week":case"half-week":return"day";case"half-day":case"quarter-day":return"hour";default:return t}}function $c(t){return t===Kc(t)}function Jc(t,e,n,i){var r=uo(t),o=r[ep(n)](),a=r[np(n)]()+1,s=Math.floor((a-1)/3)+1,l=r[ip(n)](),u=r["get"+(n?"UTC":"")+"Day"](),h=r[rp(n)](),c=(h-1)%12+1,p=r[op(n)](),d=r[ap(n)](),f=r[sp(n)](),g=h>=12?"pm":"am",y=g.toUpperCase(),v=(i instanceof Cc?i:Vc(i||Ec)||Nc[Oc]).getModel("time"),m=v.get("month"),x=v.get("monthAbbr"),_=v.get("dayOfWeek"),b=v.get("dayOfWeekAbbr");return(e||"").replace(/{a}/g,g+"").replace(/{A}/g,y+"").replace(/{yyyy}/g,o+"").replace(/{yy}/g,qc(o%100+"",2)).replace(/{Q}/g,s+"").replace(/{MMMM}/g,m[a-1]).replace(/{MMM}/g,x[a-1]).replace(/{MM}/g,qc(a,2)).replace(/{M}/g,a+"").replace(/{dd}/g,qc(l,2)).replace(/{d}/g,l+"").replace(/{eeee}/g,_[u]).replace(/{ee}/g,b[u]).replace(/{e}/g,u+"").replace(/{HH}/g,qc(h,2)).replace(/{H}/g,h+"").replace(/{hh}/g,qc(c+"",2)).replace(/{h}/g,c+"").replace(/{mm}/g,qc(p,2)).replace(/{m}/g,p+"").replace(/{ss}/g,qc(d,2)).replace(/{s}/g,d+"").replace(/{SSS}/g,qc(f,3)).replace(/{S}/g,f+"")}function Qc(t,e){var n=uo(t),i=n[np(e)]()+1,r=n[ip(e)](),o=n[rp(e)](),a=n[op(e)](),s=n[ap(e)](),l=0===n[sp(e)](),u=l&&0===s,h=u&&0===a,c=h&&0===o,p=c&&1===r;return p&&1===i?"year":p?"month":c?"day":h?"hour":u?"minute":l?"second":"millisecond"}function tp(t,e,n){var i=j(t)?uo(t):t;switch(e=e||Qc(t,n)){case"year":return i[ep(n)]();case"half-year":return i[np(n)]()>=6?1:0;case"quarter":return Math.floor((i[np(n)]()+1)/4);case"month":return i[np(n)]();case"day":return i[ip(n)]();case"half-day":return i[rp(n)]()/24;case"hour":return i[rp(n)]();case"minute":return i[op(n)]();case"second":return i[ap(n)]();case"millisecond":return i[sp(n)]()}}function ep(t){return t?"getUTCFullYear":"getFullYear"}function np(t){return t?"getUTCMonth":"getMonth"}function ip(t){return t?"getUTCDate":"getDate"}function rp(t){return t?"getUTCHours":"getHours"}function op(t){return t?"getUTCMinutes":"getMinutes"}function ap(t){return t?"getUTCSeconds":"getSeconds"}function sp(t){return t?"getUTCMilliseconds":"getMilliseconds"}function lp(t){return t?"setUTCFullYear":"setFullYear"}function up(t){return t?"setUTCMonth":"setMonth"}function hp(t){return t?"setUTCDate":"setDate"}function cp(t){return t?"setUTCHours":"setHours"}function pp(t){return t?"setUTCMinutes":"setMinutes"}function dp(t){return t?"setUTCSeconds":"setSeconds"}function fp(t){return t?"setUTCMilliseconds":"setMilliseconds"}function gp(t){if(!vo(t))return U(t)?t:"-";var e=(t+"").split(".");return e[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g,"$1,")+(e.length>1?"."+e[1]:"")}function yp(t,e){return t=(t||"").toLowerCase().replace(/-(.)/g,(function(t,e){return e.toUpperCase()})),e&&t&&(t=t.charAt(0).toUpperCase()+t.slice(1)),t}var vp=st;function mp(t,e,n){function i(t){return t&&ut(t)?t:"-"}function r(t){return!(null==t||isNaN(t)||!isFinite(t))}var o="time"===e,a=t instanceof Date;if(o||a){var s=o?uo(t):t;if(!isNaN(+s))return Jc(s,"{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}",n);if(a)return"-"}if("ordinal"===e)return Z(t)?i(t):j(t)&&r(t)?t+"":"-";var l=yo(t);return r(l)?gp(l):Z(t)?i(t):"boolean"==typeof t?t+"":"-"}var xp=["a","b","c","d","e","f","g"],_p=function(t,e){return"{"+t+(null==e?"":e)+"}"};function bp(t,e,n){Y(e)||(e=[e]);var i=e.length;if(!i)return"";for(var r=e[0].$vars||[],o=0;o':'':{renderMode:o,content:"{"+(n.markerId||"markerX")+"|} ",style:"subItem"===r?{width:4,height:4,borderRadius:2,backgroundColor:i}:{width:10,height:10,borderRadius:5,backgroundColor:i}}:""}function Sp(t,e){return e=e||"transparent",U(t)?t:q(t)&&t.colorStops&&(t.colorStops[0]||{}).color||e}function Mp(t,e){if("_blank"===e||"blank"===e){var n=window.open();n.opener=null,n.location.href=t}else window.open(t,e)}var Ip=E,Tp=["left","right","top","bottom","width","height"],Cp=[["width","left","right"],["height","top","bottom"]];function Dp(t,e,n,i,r){var o=0,a=0;null==i&&(i=1/0),null==r&&(r=1/0);var s=0;e.eachChild((function(l,u){var h,c,p=l.getBoundingRect(),d=e.childAt(u+1),f=d&&d.getBoundingRect();if("horizontal"===t){var g=p.width+(f?-f.x+p.x:0);(h=o+g)>i||l.newline?(o=0,h=g,a+=s+n,s=p.height):s=Math.max(s,p.height)}else{var y=p.height+(f?-f.y+p.y:0);(c=a+y)>r||l.newline?(o+=s+n,a=0,c=y,s=p.width):s=Math.max(s,p.width)}l.newline||(l.x=o,l.y=a,l.markRedraw(),"horizontal"===t?o=h+n:a=c+n)}))}var Ap=Dp;H(Dp,"vertical"),H(Dp,"horizontal");function kp(t,e,n){n=vp(n||0);var i=e.width,r=e.height,o=$r(t.left,i),a=$r(t.top,r),s=$r(t.right,i),l=$r(t.bottom,r),u=$r(t.width,i),h=$r(t.height,r),c=n[2]+n[0],p=n[1]+n[3],d=t.aspect;switch(isNaN(u)&&(u=i-s-p-o),isNaN(h)&&(h=r-l-c-a),null!=d&&(isNaN(u)&&isNaN(h)&&(d>i/r?u=.8*i:h=.8*r),isNaN(u)&&(u=d*h),isNaN(h)&&(h=u/d)),isNaN(o)&&(o=i-s-u-p),isNaN(a)&&(a=r-l-h-c),t.left||t.right){case"center":o=i/2-u/2-n[3];break;case"right":o=i-u-p}switch(t.top||t.bottom){case"middle":case"center":a=r/2-h/2-n[0];break;case"bottom":a=r-h-c}o=o||0,a=a||0,isNaN(u)&&(u=i-p-o-(s||0)),isNaN(h)&&(h=r-c-a-(l||0));var f=new ze(o+n[3],a+n[0],u,h);return f.margin=n,f}function Lp(t,e,n,i,r,o){var a,s=!r||!r.hv||r.hv[0],l=!r||!r.hv||r.hv[1],u=r&&r.boundingMode||"all";if((o=o||t).x=t.x,o.y=t.y,!s&&!l)return!1;if("raw"===u)a="group"===t.type?new ze(0,0,+e.width||0,+e.height||0):t.getBoundingRect();else if(a=t.getBoundingRect(),t.needLocalTransform()){var h=t.getLocalTransform();(a=a.clone()).applyTransform(h)}var c=kp(k({width:a.width,height:a.height},e),n,i),p=s?c.x-a.x:0,d=l?c.y-a.y:0;return"raw"===u?(o.x=p,o.y=d):(o.x+=p,o.y+=d),o===t&&t.markRedraw(),!0}function Pp(t){var e=t.layoutMode||t.constructor.layoutMode;return q(e)?e:e?{type:e}:null}function Op(t,e,n){var i=n&&n.ignoreSize;!Y(i)&&(i=[i,i]);var r=a(Cp[0],0),o=a(Cp[1],1);function a(n,r){var o={},a=0,u={},h=0;if(Ip(n,(function(e){u[e]=t[e]})),Ip(n,(function(t){s(e,t)&&(o[t]=u[t]=e[t]),l(o,t)&&a++,l(u,t)&&h++})),i[r])return l(e,n[1])?u[n[2]]=null:l(e,n[2])&&(u[n[1]]=null),u;if(2!==h&&a){if(a>=2)return o;for(var c=0;c=0;a--)o=C(o,n[a],!0);e.defaultOption=o}return e.defaultOption},e.prototype.getReferringComponents=function(t,e){var n=t+"Index",i=t+"Id";return Yo(this.ecModel,t,{index:this.get(n,!0),id:this.get(i,!0)},e)},e.prototype.getBoxLayoutParams=function(){var t=this;return{left:t.get("left"),top:t.get("top"),right:t.get("right"),bottom:t.get("bottom"),width:t.get("width"),height:t.get("height")}},e.prototype.getZLevelKey=function(){return""},e.prototype.setZLevel=function(t){this.option.zlevel=t},e.protoInitialize=function(){var t=e.prototype;t.type="component",t.id="",t.name="",t.mainType="",t.subType="",t.componentIndex=0}(),e}(Cc);Jo(zp,Cc),na(zp),function(t){var e={};t.registerSubTypeDefaulter=function(t,n){var i=Ko(t);e[i.main]=n},t.determineSubType=function(n,i){var r=i.type;if(!r){var o=Ko(n).main;t.hasSubTypes(n)&&e[o]&&(r=e[o](i))}return r}}(zp),function(t,e){function n(t,e){return t[e]||(t[e]={predecessor:[],successor:[]}),t[e]}t.topologicalTravel=function(t,i,r,o){if(t.length){var a=function(t){var i={},r=[];return E(t,(function(o){var a=n(i,o),s=function(t,e){var n=[];return E(t,(function(t){P(e,t)>=0&&n.push(t)})),n}(a.originalDeps=e(o),t);a.entryCount=s.length,0===a.entryCount&&r.push(o),E(s,(function(t){P(a.predecessor,t)<0&&a.predecessor.push(t);var e=n(i,t);P(e.successor,t)<0&&e.successor.push(o)}))})),{graph:i,noEntryList:r}}(i),s=a.graph,l=a.noEntryList,u={};for(E(t,(function(t){u[t]=!0}));l.length;){var h=l.pop(),c=s[h],p=!!u[h];p&&(r.call(o,h,c.originalDeps.slice()),delete u[h]),E(c.successor,p?f:d)}E(u,(function(){var t="";throw new Error(t)}))}function d(t){s[t].entryCount--,0===s[t].entryCount&&l.push(t)}function f(t){u[t]=!0,d(t)}}}(zp,(function(t){var e=[];E(zp.getClassesByMainType(t),(function(t){e=e.concat(t.dependencies||t.prototype.dependencies||[])})),e=z(e,(function(t){return Ko(t).main})),"dataset"!==t&&P(e,"dataset")<=0&&e.unshift("dataset");return e}));var Vp="";"undefined"!=typeof navigator&&(Vp=navigator.platform||"");var Bp="rgba(0, 0, 0, 0.2)",Fp={darkMode:"auto",colorBy:"series",color:["#5470c6","#91cc75","#fac858","#ee6666","#73c0de","#3ba272","#fc8452","#9a60b4","#ea7ccc"],gradientColor:["#f6efa6","#d88273","#bf444c"],aria:{decal:{decals:[{color:Bp,dashArrayX:[1,0],dashArrayY:[2,5],symbolSize:1,rotation:Math.PI/6},{color:Bp,symbol:"circle",dashArrayX:[[8,8],[0,8,8,0]],dashArrayY:[6,0],symbolSize:.8},{color:Bp,dashArrayX:[1,0],dashArrayY:[4,3],rotation:-Math.PI/4},{color:Bp,dashArrayX:[[6,6],[0,6,6,0]],dashArrayY:[6,0]},{color:Bp,dashArrayX:[[1,0],[1,6]],dashArrayY:[1,0,6,0],rotation:Math.PI/4},{color:Bp,symbol:"triangle",dashArrayX:[[9,9],[0,9,9,0]],dashArrayY:[7,2],symbolSize:.75}]}},textStyle:{fontFamily:Vp.match(/^Win/)?"Microsoft YaHei":"sans-serif",fontSize:12,fontStyle:"normal",fontWeight:"normal"},blendMode:null,stateAnimation:{duration:300,easing:"cubicOut"},animation:"auto",animationDuration:1e3,animationDurationUpdate:500,animationEasing:"cubicInOut",animationEasingUpdate:"cubicInOut",animationThreshold:2e3,progressiveThreshold:3e3,progressive:400,hoverLayerThreshold:3e3,useUTC:!1},Gp=yt(["tooltip","label","itemName","itemId","itemGroupId","itemChildGroupId","seriesName"]),Wp="original",Hp="arrayRows",Yp="objectRows",Xp="keyedColumns",Up="typedArray",Zp="unknown",jp="column",qp="row",Kp=1,$p=2,Jp=3,Qp=Vo();function td(t,e,n){var i={},r=nd(e);if(!r||!t)return i;var o,a,s=[],l=[],u=e.ecModel,h=Qp(u).datasetMap,c=r.uid+"_"+n.seriesLayoutBy;E(t=t.slice(),(function(e,n){var r=q(e)?e:t[n]={name:e};"ordinal"===r.type&&null==o&&(o=n,a=f(r)),i[r.name]=[]}));var p=h.get(c)||h.set(c,{categoryWayDim:a,valueWayDim:0});function d(t,e,n){for(var i=0;ie)return t[i];return t[n-1]}(i,a):n;if((h=h||n)&&h.length){var c=h[l];return r&&(u[r]=c),s.paletteIdx=(l+1)%h.length,c}}var fd="\0_ec_inner";var gd=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.init=function(t,e,n,i,r,o){i=i||{},this.option=null,this._theme=new Cc(i),this._locale=new Cc(r),this._optionManager=o},e.prototype.setOption=function(t,e,n){var i=md(e);this._optionManager.setOption(t,n,i),this._resetOption(null,i)},e.prototype.resetOption=function(t,e){return this._resetOption(t,md(e))},e.prototype._resetOption=function(t,e){var n=!1,i=this._optionManager;if(!t||"recreate"===t){var r=i.mountOption("recreate"===t);0,this.option&&"recreate"!==t?(this.restoreData(),this._mergeOption(r,e)):ld(this,r),n=!0}if("timeline"!==t&&"media"!==t||this.restoreData(),!t||"recreate"===t||"timeline"===t){var o=i.getTimelineOption(this);o&&(n=!0,this._mergeOption(o,e))}if(!t||"recreate"===t||"media"===t){var a=i.getMediaOption(this);a.length&&E(a,(function(t){n=!0,this._mergeOption(t,e)}),this)}return n},e.prototype.mergeOption=function(t){this._mergeOption(t,null)},e.prototype._mergeOption=function(t,e){var n=this.option,i=this._componentsMap,r=this._componentsCount,o=[],a=yt(),s=e&&e.replaceMergeMainTypeMap;Qp(this).datasetMap=yt(),E(t,(function(t,e){null!=t&&(zp.hasClass(e)?e&&(o.push(e),a.set(e,!0)):n[e]=null==n[e]?T(t):C(n[e],t,!0))})),s&&s.each((function(t,e){zp.hasClass(e)&&!a.get(e)&&(o.push(e),a.set(e,!0))})),zp.topologicalTravel(o,zp.getAllClassMainTypes(),(function(e){var o=function(t,e,n){var i=od.get(e);if(!i)return n;var r=i(t);return r?n.concat(r):n}(this,e,To(t[e])),a=i.get(e),l=a?s&&s.get(e)?"replaceMerge":"normalMerge":"replaceAll",u=Lo(a,o,l);(function(t,e,n){E(t,(function(t){var i=t.newOption;q(i)&&(t.keyInfo.mainType=e,t.keyInfo.subType=function(t,e,n,i){return e.type?e.type:n?n.subType:i.determineSubType(t,e)}(e,i,t.existing,n))}))})(u,e,zp),n[e]=null,i.set(e,null),r.set(e,0);var h,c=[],p=[],d=0;E(u,(function(t,n){var i=t.existing,r=t.newOption;if(r){var o="series"===e,a=zp.getClass(e,t.keyInfo.subType,!o);if(!a)return;if("tooltip"===e){if(h)return void 0;h=!0}if(i&&i.constructor===a)i.name=t.keyInfo.name,i.mergeOption(r,this),i.optionUpdated(r,!1);else{var s=A({componentIndex:n},t.keyInfo);A(i=new a(r,this,this,s),s),t.brandNew&&(i.__requireNewView=!0),i.init(r,this,this),i.optionUpdated(null,!0)}}else i&&(i.mergeOption({},this),i.optionUpdated({},!1));i?(c.push(i.option),p.push(i),d++):(c.push(void 0),p.push(void 0))}),this),n[e]=c,i.set(e,p),r.set(e,d),"series"===e&&ad(this)}),this),this._seriesIndices||ad(this)},e.prototype.getOption=function(){var t=T(this.option);return E(t,(function(e,n){if(zp.hasClass(n)){for(var i=To(e),r=i.length,o=!1,a=r-1;a>=0;a--)i[a]&&!Eo(i[a])?o=!0:(i[a]=null,!o&&r--);i.length=r,t[n]=i}})),delete t[fd],t},e.prototype.getTheme=function(){return this._theme},e.prototype.getLocaleModel=function(){return this._locale},e.prototype.setUpdatePayload=function(t){this._payload=t},e.prototype.getUpdatePayload=function(){return this._payload},e.prototype.getComponent=function(t,e){var n=this._componentsMap.get(t);if(n){var i=n[e||0];if(i)return i;if(null==e)for(var r=0;r=e:"max"===n?t<=e:t===e})(i[a],t,o)||(r=!1)}})),r}var Td=E,Cd=q,Dd=["areaStyle","lineStyle","nodeStyle","linkStyle","chordStyle","label","labelLine"];function Ad(t){var e=t&&t.itemStyle;if(e)for(var n=0,i=Dd.length;n=0;g--){var y=t[g];if(s||(p=y.data.rawIndexOf(y.stackedByDimension,c)),p>=0){var v=y.data.getByRawIndex(y.stackResultDimension,p);if("all"===l||"positive"===l&&v>0||"negative"===l&&v<0||"samesign"===l&&d>=0&&v>0||"samesign"===l&&d<=0&&v<0){d=ro(d,v),f=v;break}}}return i[0]=d,i[1]=f,i}))}))}var Zd,jd,qd,Kd,$d,Jd=function(t){this.data=t.data||(t.sourceFormat===Xp?{}:[]),this.sourceFormat=t.sourceFormat||Zp,this.seriesLayoutBy=t.seriesLayoutBy||jp,this.startIndex=t.startIndex||0,this.dimensionsDetectedCount=t.dimensionsDetectedCount,this.metaRawOption=t.metaRawOption;var e=this.dimensionsDefine=t.dimensionsDefine;if(e)for(var n=0;nu&&(u=d)}s[0]=l,s[1]=u}},i=function(){return this._data?this._data.length/this._dimSize:0};function r(t){for(var e=0;e=0&&(s=o.interpolatedValue[l])}return null!=s?s+"":""})):void 0},t.prototype.getRawValue=function(t,e){return mf(this.getData(e),t)},t.prototype.formatTooltip=function(t,e,n){},t}();function bf(t){var e,n;return q(t)?t.type&&(n=t):e=t,{text:e,frag:n}}function wf(t){return new Sf(t)}var Sf=function(){function t(t){t=t||{},this._reset=t.reset,this._plan=t.plan,this._count=t.count,this._onDirty=t.onDirty,this._dirty=!0}return t.prototype.perform=function(t){var e,n=this._upstream,i=t&&t.skip;if(this._dirty&&n){var r=this.context;r.data=r.outputData=n.context.outputData}this.__pipeline&&(this.__pipeline.currentTask=this),this._plan&&!i&&(e=this._plan(this.context));var o,a=h(this._modBy),s=this._modDataCount||0,l=h(t&&t.modBy),u=t&&t.modDataCount||0;function h(t){return!(t>=1)&&(t=1),t}a===l&&s===u||(e="reset"),(this._dirty||"reset"===e)&&(this._dirty=!1,o=this._doReset(i)),this._modBy=l,this._modDataCount=u;var c=t&&t.step;if(this._dueEnd=n?n._outputDueEnd:this._count?this._count(this.context):1/0,this._progress){var p=this._dueIndex,d=Math.min(null!=c?this._dueIndex+c:1/0,this._dueEnd);if(!i&&(o||p1&&i>0?s:a}};return o;function a(){return e=t?null:oe},gte:function(t,e){return t>=e}},Af=function(){function t(t,e){if(!j(e)){var n="";0,wo(n)}this._opFn=Df[t],this._rvalFloat=yo(e)}return t.prototype.evaluate=function(t){return j(t)?this._opFn(t,this._rvalFloat):this._opFn(yo(t),this._rvalFloat)},t}(),kf=function(){function t(t,e){var n="desc"===t;this._resultLT=n?1:-1,null==e&&(e=n?"min":"max"),this._incomparable="min"===e?-1/0:1/0}return t.prototype.evaluate=function(t,e){var n=j(t)?t:yo(t),i=j(e)?e:yo(e),r=isNaN(n),o=isNaN(i);if(r&&(n=this._incomparable),o&&(i=this._incomparable),r&&o){var a=U(t),s=U(e);a&&(n=s?t:0),s&&(i=a?e:0)}return ni?-this._resultLT:0},t}(),Lf=function(){function t(t,e){this._rval=e,this._isEQ=t,this._rvalTypeof=typeof e,this._rvalFloat=yo(e)}return t.prototype.evaluate=function(t){var e=t===this._rval;if(!e){var n=typeof t;n===this._rvalTypeof||"number"!==n&&"number"!==this._rvalTypeof||(e=yo(t)===this._rvalFloat)}return this._isEQ?e:!e},t}();function Pf(t,e){return"eq"===t||"ne"===t?new Lf("eq"===t,e):_t(Df,t)?new Af(t,e):null}var Of=function(){function t(){}return t.prototype.getRawData=function(){throw new Error("not supported")},t.prototype.getRawDataItem=function(t){throw new Error("not supported")},t.prototype.cloneRawData=function(){},t.prototype.getDimensionInfo=function(t){},t.prototype.cloneAllDimensionInfo=function(){},t.prototype.count=function(){},t.prototype.retrieveValue=function(t,e){},t.prototype.retrieveValueFromItem=function(t,e){},t.prototype.convertValue=function(t,e){return If(t,e)},t}();function Rf(t){var e=t.sourceFormat;if(!Ff(e)){var n="";0,wo(n)}return t.data}function Nf(t){var e=t.sourceFormat,n=t.data;if(!Ff(e)){var i="";0,wo(i)}if(e===Hp){for(var r=[],o=0,a=n.length;o65535?Hf:Yf}function qf(t,e,n,i,r){var o=Zf[n||"float"];if(r){var a=t[e],s=a&&a.length;if(s!==i){for(var l=new o(i),u=0;ug[1]&&(g[1]=f)}return this._rawCount=this._count=s,{start:a,end:s}},t.prototype._initDataFromProvider=function(t,e,n){for(var i=this._provider,r=this._chunks,o=this._dimensions,a=o.length,s=this._rawExtent,l=z(o,(function(t){return t.property})),u=0;uy[1]&&(y[1]=g)}}!i.persistent&&i.clean&&i.clean(),this._rawCount=this._count=e,this._extent=[]},t.prototype.count=function(){return this._count},t.prototype.get=function(t,e){if(!(e>=0&&e=0&&e=this._rawCount||t<0)return-1;if(!this._indices)return t;var e=this._indices,n=e[t];if(null!=n&&nt))return o;r=o-1}}return-1},t.prototype.indicesOfNearest=function(t,e,n){var i=this._chunks[t],r=[];if(!i)return r;null==n&&(n=1/0);for(var o=1/0,a=-1,s=0,l=0,u=this.count();l=0&&a<0)&&(o=c,a=h,s=0),h===a&&(r[s++]=l))}return r.length=s,r},t.prototype.getIndices=function(){var t,e=this._indices;if(e){var n=e.constructor,i=this._count;if(n===Array){t=new n(i);for(var r=0;r=u&&x<=h||isNaN(x))&&(a[s++]=d),d++}p=!0}else if(2===r){f=c[i[0]];var y=c[i[1]],v=t[i[1]][0],m=t[i[1]][1];for(g=0;g=u&&x<=h||isNaN(x))&&(_>=v&&_<=m||isNaN(_))&&(a[s++]=d),d++}p=!0}}if(!p)if(1===r)for(g=0;g=u&&x<=h||isNaN(x))&&(a[s++]=b)}else for(g=0;gt[M][1])&&(w=!1)}w&&(a[s++]=e.getRawIndex(g))}return sy[1]&&(y[1]=g)}}}},t.prototype.lttbDownSample=function(t,e){var n,i,r,o=this.clone([t],!0),a=o._chunks[t],s=this.count(),l=0,u=Math.floor(1/e),h=this.getRawIndex(0),c=new(jf(this._rawCount))(Math.min(2*(Math.ceil(s/u)+2),s));c[l++]=h;for(var p=1;pn&&(n=i,r=I)}M>0&&M<_-x&&(c[l++]=Math.min(S,r),r=Math.max(S,r)),c[l++]=r,h=r}return c[l++]=this.getRawIndex(s-1),o._count=l,o._indices=c,o.getRawIndex=this._getRawIdx,o},t.prototype.downSample=function(t,e,n,i){for(var r=this.clone([t],!0),o=r._chunks,a=[],s=Math.floor(1/e),l=o[t],u=this.count(),h=r._rawExtent[t]=[1/0,-1/0],c=new(jf(this._rawCount))(Math.ceil(u/s)),p=0,d=0;du-d&&(s=u-d,a.length=s);for(var f=0;fh[1]&&(h[1]=y),c[p++]=v}return r._count=p,r._indices=c,r._updateGetRawIdx(),r},t.prototype.each=function(t,e){if(this._count)for(var n=t.length,i=this._chunks,r=0,o=this.count();ra&&(a=l)}return i=[o,a],this._extent[t]=i,i},t.prototype.getRawDataItem=function(t){var e=this.getRawIndex(t);if(this._provider.persistent)return this._provider.getItem(e);for(var n=[],i=this._chunks,r=0;r=0?this._indices[t]:-1},t.prototype._updateGetRawIdx=function(){this.getRawIndex=this._indices?this._getRawIdx:this._getRawIdxIdentity},t.internalField=function(){function t(t,e,n,i){return If(t[i],this._dimensions[i])}Gf={arrayRows:t,objectRows:function(t,e,n,i){return If(t[e],this._dimensions[i])},keyedColumns:t,original:function(t,e,n,i){var r=t&&(null==t.value?t:t.value);return If(r instanceof Array?r[i]:r,this._dimensions[i])},typedArray:function(t,e,n,i){return t[i]}}}(),t}(),$f=function(){function t(t){this._sourceList=[],this._storeList=[],this._upstreamSignList=[],this._versionSignBase=0,this._dirty=!0,this._sourceHost=t}return t.prototype.dirty=function(){this._setLocalSource([],[]),this._storeList=[],this._dirty=!0},t.prototype._setLocalSource=function(t,e){this._sourceList=t,this._upstreamSignList=e,this._versionSignBase++,this._versionSignBase>9e10&&(this._versionSignBase=0)},t.prototype._getVersionSign=function(){return this._sourceHost.uid+"_"+this._versionSignBase},t.prototype.prepareSource=function(){this._isDirty()&&(this._createSource(),this._dirty=!1)},t.prototype._createSource=function(){this._setLocalSource([],[]);var t,e,n=this._sourceHost,i=this._getUpstreamSourceManagers(),r=!!i.length;if(Qf(n)){var o=n,a=void 0,s=void 0,l=void 0;if(r){var u=i[0];u.prepareSource(),a=(l=u.getSource()).data,s=l.sourceFormat,e=[u._getVersionSign()]}else s=$(a=o.get("data",!0))?Up:Wp,e=[];var h=this._getSourceMetaRawOption()||{},c=l&&l.metaRawOption||{},p=rt(h.seriesLayoutBy,c.seriesLayoutBy)||null,d=rt(h.sourceHeader,c.sourceHeader),f=rt(h.dimensions,c.dimensions);t=p!==c.seriesLayoutBy||!!d!=!!c.sourceHeader||f?[tf(a,{seriesLayoutBy:p,sourceHeader:d,dimensions:f},s)]:[]}else{var g=n;if(r){var y=this._applyTransform(i);t=y.sourceList,e=y.upstreamSignList}else{t=[tf(g.get("source",!0),this._getSourceMetaRawOption(),null)],e=[]}}this._setLocalSource(t,e)},t.prototype._applyTransform=function(t){var e,n=this._sourceHost,i=n.get("transform",!0),r=n.get("fromTransformResult",!0);if(null!=r){var o="";1!==t.length&&tg(o)}var a,s=[],l=[];return E(t,(function(t){t.prepareSource();var e=t.getSource(r||0),n="";null==r||e||tg(n),s.push(e),l.push(t._getVersionSign())})),i?e=function(t,e,n){var i=To(t),r=i.length,o="";r||wo(o);for(var a=0,s=r;a1||n>0&&!t.noHeader;return E(t.blocks,(function(t){var n=lg(t);n>=e&&(e=n+ +(i&&(!n||ag(t)&&!t.noHeader)))})),e}return 0}function ug(t,e,n,i){var r,o=e.noHeader,a=(r=lg(e),{html:ig[r],richText:rg[r]}),s=[],l=e.blocks||[];lt(!l||Y(l)),l=l||[];var u=t.orderMode;if(e.sortBlocks&&u){l=l.slice();var h={valueAsc:"asc",valueDesc:"desc"};if(_t(h,u)){var c=new kf(h[u],null);l.sort((function(t,e){return c.evaluate(t.sortParam,e.sortParam)}))}else"seriesDesc"===u&&l.reverse()}E(l,(function(n,r){var o=e.valueFormatter,l=sg(n)(o?A(A({},t),{valueFormatter:o}):t,n,r>0?a.html:0,i);null!=l&&s.push(l)}));var p="richText"===t.renderMode?s.join(a.richText):pg(s.join(""),o?n:a.html);if(o)return p;var d=mp(e.header,"ordinal",t.useUTC),f=ng(i,t.renderMode).nameStyle;return"richText"===t.renderMode?dg(t,d,f)+a.richText+p:pg('
    '+re(d)+"
    "+p,n)}function hg(t,e,n,i){var r=t.renderMode,o=e.noName,a=e.noValue,s=!e.markerType,l=e.name,u=t.useUTC,h=e.valueFormatter||t.valueFormatter||function(t){return z(t=Y(t)?t:[t],(function(t,e){return mp(t,Y(d)?d[e]:d,u)}))};if(!o||!a){var c=s?"":t.markupStyleCreator.makeTooltipMarker(e.markerType,e.markerColor||"#333",r),p=o?"":mp(l,"ordinal",u),d=e.valueType,f=a?[]:h(e.value,e.dataIndex),g=!s||!o,y=!s&&o,v=ng(i,r),m=v.nameStyle,x=v.valueStyle;return"richText"===r?(s?"":c)+(o?"":dg(t,p,m))+(a?"":function(t,e,n,i,r){var o=[r],a=i?10:20;return n&&o.push({padding:[0,0,0,a],align:"right"}),t.markupStyleCreator.wrapRichTextStyle(Y(e)?e.join(" "):e,o)}(t,f,g,y,x)):pg((s?"":c)+(o?"":function(t,e,n){return''+re(t)+""}(p,!s,m))+(a?"":function(t,e,n,i){var r=n?"10px":"20px",o=e?"float:right;margin-left:"+r:"";return t=Y(t)?t:[t],''+z(t,(function(t){return re(t)})).join("  ")+""}(f,g,y,x)),n)}}function cg(t,e,n,i,r,o){if(t)return sg(t)({useUTC:r,renderMode:n,orderMode:i,markupStyleCreator:e,valueFormatter:t.valueFormatter},t,0,o)}function pg(t,e){return'
    '+t+'
    '}function dg(t,e,n){return t.markupStyleCreator.wrapRichTextStyle(e,n)}function fg(t,e){return Sp(t.getData().getItemVisual(e,"style")[t.visualDrawType])}function gg(t,e){var n=t.get("padding");return null!=n?n:"richText"===e?[8,10]:10}var yg=function(){function t(){this.richTextStyles={},this._nextStyleNameId=mo()}return t.prototype._generateStyleName=function(){return"__EC_aUTo_"+this._nextStyleNameId++},t.prototype.makeTooltipMarker=function(t,e,n){var i="richText"===n?this._generateStyleName():null,r=wp({color:e,type:t,renderMode:n,markerId:i});return U(r)?r:(this.richTextStyles[i]=r.style,r.content)},t.prototype.wrapRichTextStyle=function(t,e){var n={};Y(e)?E(e,(function(t){return A(n,t)})):A(n,e);var i=this._generateStyleName();return this.richTextStyles[i]=n,"{"+i+"|"+t+"}"},t}();function vg(t){var e,n,i,r,o=t.series,a=t.dataIndex,s=t.multipleSeries,l=o.getData(),u=l.mapDimensionsAll("defaultedTooltip"),h=u.length,c=o.getRawValue(a),p=Y(c),d=fg(o,a);if(h>1||p&&!h){var f=function(t,e,n,i,r){var o=e.getData(),a=V(t,(function(t,e,n){var i=o.getDimensionInfo(n);return t||i&&!1!==i.tooltip&&null!=i.displayName}),!1),s=[],l=[],u=[];function h(t,e){var n=o.getDimensionInfo(e);n&&!1!==n.otherDims.tooltip&&(a?u.push(og("nameValue",{markerType:"subItem",markerColor:r,name:n.displayName,value:t,valueType:n.type})):(s.push(t),l.push(n.type)))}return i.length?E(i,(function(t){h(mf(o,n,t),t)})):E(t,h),{inlineValues:s,inlineValueTypes:l,blocks:u}}(c,o,a,u,d);e=f.inlineValues,n=f.inlineValueTypes,i=f.blocks,r=f.inlineValues[0]}else if(h){var g=l.getDimensionInfo(u[0]);r=e=mf(l,a,u[0]),n=g.type}else r=e=p?c[0]:c;var y=No(o),v=y&&o.name||"",m=l.getName(a),x=s?v:m;return og("section",{header:v,noHeader:s||!y,sortParam:r,blocks:[og("nameValue",{markerType:"item",markerColor:d,name:x,noName:!ut(x),value:e,valueType:n,dataIndex:a})].concat(i||[])})}var mg=Vo();function xg(t,e){return t.getName(e)||t.getId(e)}var _g="__universalTransitionEnabled",bg=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e._selectedDataIndicesMap={},e}return n(e,t),e.prototype.init=function(t,e,n){this.seriesIndex=this.componentIndex,this.dataTask=wf({count:Sg,reset:Mg}),this.dataTask.context={model:this},this.mergeDefaultAndTheme(t,n),(mg(this).sourceManager=new $f(this)).prepareSource();var i=this.getInitialData(t,n);Tg(i,this),this.dataTask.context.data=i,mg(this).dataBeforeProcessed=i,wg(this),this._initSelectedMapFromData(i)},e.prototype.mergeDefaultAndTheme=function(t,e){var n=Pp(this),i=n?Rp(t):{},r=this.subType;zp.hasClass(r)&&(r+="Series"),C(t,e.getTheme().get(this.subType)),C(t,this.getDefaultOption()),Co(t,"label",["show"]),this.fillDataTextStyle(t.data),n&&Op(t,i,n)},e.prototype.mergeOption=function(t,e){t=C(this.option,t,!0),this.fillDataTextStyle(t.data);var n=Pp(this);n&&Op(this.option,t,n);var i=mg(this).sourceManager;i.dirty(),i.prepareSource();var r=this.getInitialData(t,e);Tg(r,this),this.dataTask.dirty(),this.dataTask.context.data=r,mg(this).dataBeforeProcessed=r,wg(this),this._initSelectedMapFromData(r)},e.prototype.fillDataTextStyle=function(t){if(t&&!$(t))for(var e=["show"],n=0;nthis.getShallow("animationThreshold")&&(e=!1),!!e},e.prototype.restoreData=function(){this.dataTask.dirty()},e.prototype.getColorFromPalette=function(t,e,n){var i=this.ecModel,r=cd.prototype.getColorFromPalette.call(this,t,e,n);return r||(r=i.getColorFromPalette(t,e,n)),r},e.prototype.coordDimToDataDim=function(t){return this.getRawData().mapDimensionsAll(t)},e.prototype.getProgressive=function(){return this.get("progressive")},e.prototype.getProgressiveThreshold=function(){return this.get("progressiveThreshold")},e.prototype.select=function(t,e){this._innerSelect(this.getData(e),t)},e.prototype.unselect=function(t,e){var n=this.option.selectedMap;if(n){var i=this.option.selectedMode,r=this.getData(e);if("series"===i||"all"===n)return this.option.selectedMap={},void(this._selectedDataIndicesMap={});for(var o=0;o=0&&n.push(r)}return n},e.prototype.isSelected=function(t,e){var n=this.option.selectedMap;if(!n)return!1;var i=this.getData(e);return("all"===n||n[xg(i,t)])&&!i.getItemModel(t).get(["select","disabled"])},e.prototype.isUniversalTransitionEnabled=function(){if(this[_g])return!0;var t=this.option.universalTransition;return!!t&&(!0===t||t&&t.enabled)},e.prototype._innerSelect=function(t,e){var n,i,r=this.option,o=r.selectedMode,a=e.length;if(o&&a)if("series"===o)r.selectedMap="all";else if("multiple"===o){q(r.selectedMap)||(r.selectedMap={});for(var s=r.selectedMap,l=0;l0&&this._innerSelect(t,e)}},e.registerClass=function(t){return zp.registerClass(t)},e.protoInitialize=function(){var t=e.prototype;t.type="series.__base__",t.seriesIndex=0,t.ignoreStyleOnData=!1,t.hasSymbolVisual=!1,t.defaultSymbol="circle",t.visualStyleAccessPath="itemStyle",t.visualDrawType="fill"}(),e}(zp);function wg(t){var e=t.name;No(t)||(t.name=function(t){var e=t.getRawData(),n=e.mapDimensionsAll("seriesName"),i=[];return E(n,(function(t){var n=e.getDimensionInfo(t);n.displayName&&i.push(n.displayName)})),i.join(" ")}(t)||e)}function Sg(t){return t.model.getRawData().count()}function Mg(t){var e=t.model;return e.setData(e.getRawData().cloneShallow()),Ig}function Ig(t,e){e.outputData&&t.end>e.outputData.count()&&e.model.getRawData().cloneShallow(e.outputData)}function Tg(t,e){E(vt(t.CHANGABLE_METHODS,t.DOWNSAMPLE_METHODS),(function(n){t.wrapMethod(n,H(Cg,e))}))}function Cg(t,e){var n=Dg(t);return n&&n.setOutputEnd((e||this).count()),e}function Dg(t){var e=(t.ecModel||{}).scheduler,n=e&&e.getPipeline(t.uid);if(n){var i=n.currentTask;if(i){var r=i.agentStubMap;r&&(i=r.get(t.uid))}return i}}R(bg,_f),R(bg,cd),Jo(bg,zp);var Ag=function(){function t(){this.group=new Br,this.uid=Ac("viewComponent")}return t.prototype.init=function(t,e){},t.prototype.render=function(t,e,n,i){},t.prototype.dispose=function(t,e){},t.prototype.updateView=function(t,e,n,i){},t.prototype.updateLayout=function(t,e,n,i){},t.prototype.updateVisual=function(t,e,n,i){},t.prototype.toggleBlurSeries=function(t,e,n){},t.prototype.eachRendered=function(t){var e=this.group;e&&e.traverse(t)},t}();function kg(){var t=Vo();return function(e){var n=t(e),i=e.pipelineContext,r=!!n.large,o=!!n.progressiveRender,a=n.large=!(!i||!i.large),s=n.progressiveRender=!(!i||!i.progressiveRender);return!(r===a&&o===s)&&"reset"}}$o(Ag),na(Ag);var Lg=Vo(),Pg=kg(),Og=function(){function t(){this.group=new Br,this.uid=Ac("viewChart"),this.renderTask=wf({plan:Eg,reset:zg}),this.renderTask.context={view:this}}return t.prototype.init=function(t,e){},t.prototype.render=function(t,e,n,i){0},t.prototype.highlight=function(t,e,n,i){var r=t.getData(i&&i.dataType);r&&Ng(r,i,"emphasis")},t.prototype.downplay=function(t,e,n,i){var r=t.getData(i&&i.dataType);r&&Ng(r,i,"normal")},t.prototype.remove=function(t,e){this.group.removeAll()},t.prototype.dispose=function(t,e){},t.prototype.updateView=function(t,e,n,i){this.render(t,e,n,i)},t.prototype.updateLayout=function(t,e,n,i){this.render(t,e,n,i)},t.prototype.updateVisual=function(t,e,n,i){this.render(t,e,n,i)},t.prototype.eachRendered=function(t){Jh(this.group,t)},t.markUpdateMethod=function(t,e){Lg(t).updateMethod=e},t.protoInitialize=void(t.prototype.type="chart"),t}();function Rg(t,e,n){t&&Ql(t)&&("emphasis"===e?Ol:Rl)(t,n)}function Ng(t,e,n){var i=zo(t,e),r=e&&null!=e.highlightKey?function(t){var e=sl[t];return null==e&&al<=32&&(e=sl[t]=al++),e}(e.highlightKey):null;null!=i?E(To(i),(function(e){Rg(t.getItemGraphicEl(e),n,r)})):t.eachItemGraphicEl((function(t){Rg(t,n,r)}))}function Eg(t){return Pg(t.model)}function zg(t){var e=t.model,n=t.ecModel,i=t.api,r=t.payload,o=e.pipelineContext.progressiveRender,a=t.view,s=r&&Lg(r).updateMethod,l=o?"incrementalPrepareRender":s&&a[s]?s:"render";return"render"!==l&&a[l](e,n,i,r),Vg[l]}$o(Og),na(Og);var Vg={incrementalPrepareRender:{progress:function(t,e){e.view.incrementalRender(t,e.model,e.ecModel,e.api,e.payload)}},render:{forceFirstProgress:!0,progress:function(t,e){e.view.render(e.model,e.ecModel,e.api,e.payload)}}},Bg="\0__throttleOriginMethod",Fg="\0__throttleRate",Gg="\0__throttleType";function Wg(t,e,n){var i,r,o,a,s,l=0,u=0,h=null;function c(){u=(new Date).getTime(),h=null,t.apply(o,a||[])}e=e||0;var p=function(){for(var t=[],p=0;p=0?c():h=setTimeout(c,-r),l=i};return p.clear=function(){h&&(clearTimeout(h),h=null)},p.debounceNextCall=function(t){s=t},p}function Hg(t,e,n,i){var r=t[e];if(r){var o=r[Bg]||r,a=r[Gg];if(r[Fg]!==n||a!==i){if(null==n||!i)return t[e]=o;(r=t[e]=Wg(o,n,"debounce"===i))[Bg]=o,r[Gg]=i,r[Fg]=n}return r}}function Yg(t,e){var n=t[e];n&&n[Bg]&&(n.clear&&n.clear(),t[e]=n[Bg])}var Xg=Vo(),Ug={itemStyle:ia(Mc,!0),lineStyle:ia(bc,!0)},Zg={lineStyle:"stroke",itemStyle:"fill"};function jg(t,e){var n=t.visualStyleMapper||Ug[e];return n||(console.warn("Unknown style type '"+e+"'."),Ug.itemStyle)}function qg(t,e){var n=t.visualDrawType||Zg[e];return n||(console.warn("Unknown style type '"+e+"'."),"fill")}var Kg={createOnAllSeries:!0,performRawSeries:!0,reset:function(t,e){var n=t.getData(),i=t.visualStyleAccessPath||"itemStyle",r=t.getModel(i),o=jg(t,i)(r),a=r.getShallow("decal");a&&(n.setVisual("decal",a),a.dirty=!0);var s=qg(t,i),l=o[s],u=X(l)?l:null,h="auto"===o.fill||"auto"===o.stroke;if(!o[s]||u||h){var c=t.getColorFromPalette(t.name,null,e.getSeriesCount());o[s]||(o[s]=c,n.setVisual("colorFromPalette",!0)),o.fill="auto"===o.fill||X(o.fill)?c:o.fill,o.stroke="auto"===o.stroke||X(o.stroke)?c:o.stroke}if(n.setVisual("style",o),n.setVisual("drawType",s),!e.isSeriesFiltered(t)&&u)return n.setVisual("colorFromPalette",!1),{dataEach:function(e,n){var i=t.getDataParams(n),r=A({},o);r[s]=u(i),e.setItemVisual(n,"style",r)}}}},$g=new Cc,Jg={createOnAllSeries:!0,performRawSeries:!0,reset:function(t,e){if(!t.ignoreStyleOnData&&!e.isSeriesFiltered(t)){var n=t.getData(),i=t.visualStyleAccessPath||"itemStyle",r=jg(t,i),o=n.getVisual("drawType");return{dataEach:n.hasItemOption?function(t,e){var n=t.getRawDataItem(e);if(n&&n[i]){$g.option=n[i];var a=r($g);A(t.ensureUniqueItemVisual(e,"style"),a),$g.option.decal&&(t.setItemVisual(e,"decal",$g.option.decal),$g.option.decal.dirty=!0),o in a&&t.setItemVisual(e,"colorFromPalette",!1)}}:null}}}},Qg={performRawSeries:!0,overallReset:function(t){var e=yt();t.eachSeries((function(t){var n=t.getColorBy();if(!t.isColorBySeries()){var i=t.type+"-"+n,r=e.get(i);r||(r={},e.set(i,r)),Xg(t).scope=r}})),t.eachSeries((function(e){if(!e.isColorBySeries()&&!t.isSeriesFiltered(e)){var n=e.getRawData(),i={},r=e.getData(),o=Xg(e).scope,a=e.visualStyleAccessPath||"itemStyle",s=qg(e,a);r.each((function(t){var e=r.getRawIndex(t);i[e]=t})),n.each((function(t){var a=i[t];if(r.getItemVisual(a,"colorFromPalette")){var l=r.ensureUniqueItemVisual(a,"style"),u=n.getName(t)||t+"",h=n.count();l[s]=e.getColorFromPalette(u,o,h)}}))}}))}},ty=Math.PI;var ey=function(){function t(t,e,n,i){this._stageTaskMap=yt(),this.ecInstance=t,this.api=e,n=this._dataProcessorHandlers=n.slice(),i=this._visualHandlers=i.slice(),this._allHandlers=n.concat(i)}return t.prototype.restoreData=function(t,e){t.restoreData(e),this._stageTaskMap.each((function(t){var e=t.overallTask;e&&e.dirty()}))},t.prototype.getPerformArgs=function(t,e){if(t.__pipeline){var n=this._pipelineMap.get(t.__pipeline.id),i=n.context,r=!e&&n.progressiveEnabled&&(!i||i.progressiveRender)&&t.__idxInPipeline>n.blockIndex?n.step:null,o=i&&i.modDataCount;return{step:r,modBy:null!=o?Math.ceil(o/r):null,modDataCount:o}}},t.prototype.getPipeline=function(t){return this._pipelineMap.get(t)},t.prototype.updateStreamModes=function(t,e){var n=this._pipelineMap.get(t.uid),i=t.getData().count(),r=n.progressiveEnabled&&e.incrementalPrepareRender&&i>=n.threshold,o=t.get("large")&&i>=t.get("largeThreshold"),a="mod"===t.get("progressiveChunkMode")?i:null;t.pipelineContext=n.context={progressiveRender:r,modDataCount:a,large:o}},t.prototype.restorePipelines=function(t){var e=this,n=e._pipelineMap=yt();t.eachSeries((function(t){var i=t.getProgressive(),r=t.uid;n.set(r,{id:r,head:null,tail:null,threshold:t.getProgressiveThreshold(),progressiveEnabled:i&&!(t.preventIncremental&&t.preventIncremental()),blockIndex:-1,step:Math.round(i||700),count:0}),e._pipe(t,t.dataTask)}))},t.prototype.prepareStageTasks=function(){var t=this._stageTaskMap,e=this.api.getModel(),n=this.api;E(this._allHandlers,(function(i){var r=t.get(i.uid)||t.set(i.uid,{}),o="";lt(!(i.reset&&i.overallReset),o),i.reset&&this._createSeriesStageTask(i,r,e,n),i.overallReset&&this._createOverallStageTask(i,r,e,n)}),this)},t.prototype.prepareView=function(t,e,n,i){var r=t.renderTask,o=r.context;o.model=e,o.ecModel=n,o.api=i,r.__block=!t.incrementalPrepareRender,this._pipe(e,r)},t.prototype.performDataProcessorTasks=function(t,e){this._performStageTasks(this._dataProcessorHandlers,t,e,{block:!0})},t.prototype.performVisualTasks=function(t,e,n){this._performStageTasks(this._visualHandlers,t,e,n)},t.prototype._performStageTasks=function(t,e,n,i){i=i||{};var r=!1,o=this;function a(t,e){return t.setDirty&&(!t.dirtyMap||t.dirtyMap.get(e.__pipeline.id))}E(t,(function(t,s){if(!i.visualType||i.visualType===t.visualType){var l=o._stageTaskMap.get(t.uid),u=l.seriesTaskMap,h=l.overallTask;if(h){var c,p=h.agentStubMap;p.each((function(t){a(i,t)&&(t.dirty(),c=!0)})),c&&h.dirty(),o.updatePayload(h,n);var d=o.getPerformArgs(h,i.block);p.each((function(t){t.perform(d)})),h.perform(d)&&(r=!0)}else u&&u.each((function(s,l){a(i,s)&&s.dirty();var u=o.getPerformArgs(s,i.block);u.skip=!t.performRawSeries&&e.isSeriesFiltered(s.context.model),o.updatePayload(s,n),s.perform(u)&&(r=!0)}))}})),this.unfinished=r||this.unfinished},t.prototype.performSeriesTasks=function(t){var e;t.eachSeries((function(t){e=t.dataTask.perform()||e})),this.unfinished=e||this.unfinished},t.prototype.plan=function(){this._pipelineMap.each((function(t){var e=t.tail;do{if(e.__block){t.blockIndex=e.__idxInPipeline;break}e=e.getUpstream()}while(e)}))},t.prototype.updatePayload=function(t,e){"remain"!==e&&(t.context.payload=e)},t.prototype._createSeriesStageTask=function(t,e,n,i){var r=this,o=e.seriesTaskMap,a=e.seriesTaskMap=yt(),s=t.seriesType,l=t.getTargetSeries;function u(e){var s=e.uid,l=a.set(s,o&&o.get(s)||wf({plan:ay,reset:sy,count:hy}));l.context={model:e,ecModel:n,api:i,useClearVisual:t.isVisual&&!t.isLayout,plan:t.plan,reset:t.reset,scheduler:r},r._pipe(e,l)}t.createOnAllSeries?n.eachRawSeries(u):s?n.eachRawSeriesByType(s,u):l&&l(n,i).each(u)},t.prototype._createOverallStageTask=function(t,e,n,i){var r=this,o=e.overallTask=e.overallTask||wf({reset:ny});o.context={ecModel:n,api:i,overallReset:t.overallReset,scheduler:r};var a=o.agentStubMap,s=o.agentStubMap=yt(),l=t.seriesType,u=t.getTargetSeries,h=!0,c=!1,p="";function d(t){var e=t.uid,n=s.set(e,a&&a.get(e)||(c=!0,wf({reset:iy,onDirty:oy})));n.context={model:t,overallProgress:h},n.agent=o,n.__block=h,r._pipe(t,n)}lt(!t.createOnAllSeries,p),l?n.eachRawSeriesByType(l,d):u?u(n,i).each(d):(h=!1,E(n.getSeries(),d)),c&&o.dirty()},t.prototype._pipe=function(t,e){var n=t.uid,i=this._pipelineMap.get(n);!i.head&&(i.head=e),i.tail&&i.tail.pipe(e),i.tail=e,e.__idxInPipeline=i.count++,e.__pipeline=i},t.wrapStageHandler=function(t,e){return X(t)&&(t={overallReset:t,seriesType:cy(t)}),t.uid=Ac("stageHandler"),e&&(t.visualType=e),t},t}();function ny(t){t.overallReset(t.ecModel,t.api,t.payload)}function iy(t){return t.overallProgress&&ry}function ry(){this.agent.dirty(),this.getDownstream().dirty()}function oy(){this.agent&&this.agent.dirty()}function ay(t){return t.plan?t.plan(t.model,t.ecModel,t.api,t.payload):null}function sy(t){t.useClearVisual&&t.data.clearAllVisual();var e=t.resetDefines=To(t.reset(t.model,t.ecModel,t.api,t.payload));return e.length>1?z(e,(function(t,e){return uy(e)})):ly}var ly=uy(0);function uy(t){return function(e,n){var i=n.data,r=n.resetDefines[t];if(r&&r.dataEach)for(var o=e.start;o0&&h===r.length-u.length){var c=r.slice(0,h);"data"!==c&&(e.mainType=c,e[u.toLowerCase()]=t,s=!0)}}a.hasOwnProperty(r)&&(n[r]=t,s=!0),s||(i[r]=t)}))}return{cptQuery:e,dataQuery:n,otherQuery:i}},t.prototype.filter=function(t,e){var n=this.eventInfo;if(!n)return!0;var i=n.targetEl,r=n.packedEvent,o=n.model,a=n.view;if(!o||!a)return!0;var s=e.cptQuery,l=e.dataQuery;return u(s,o,"mainType")&&u(s,o,"subType")&&u(s,o,"index","componentIndex")&&u(s,o,"name")&&u(s,o,"id")&&u(l,r,"name")&&u(l,r,"dataIndex")&&u(l,r,"dataType")&&(!a.filterForExposedEvent||a.filterForExposedEvent(t,e.otherQuery,i,r));function u(t,e,n,i){return null==t[n]||e[i||n]===t[n]}},t.prototype.afterTrigger=function(){this.eventInfo=null},t}(),My=["symbol","symbolSize","symbolRotate","symbolOffset"],Iy=My.concat(["symbolKeepAspect"]),Ty={createOnAllSeries:!0,performRawSeries:!0,reset:function(t,e){var n=t.getData();if(t.legendIcon&&n.setVisual("legendIcon",t.legendIcon),t.hasSymbolVisual){for(var i={},r={},o=!1,a=0;a=0&&jy(l)?l:.5,t.createRadialGradient(a,s,0,a,s,l)}(t,e,n):function(t,e,n){var i=null==e.x?0:e.x,r=null==e.x2?1:e.x2,o=null==e.y?0:e.y,a=null==e.y2?0:e.y2;return e.global||(i=i*n.width+n.x,r=r*n.width+n.x,o=o*n.height+n.y,a=a*n.height+n.y),i=jy(i)?i:0,r=jy(r)?r:1,o=jy(o)?o:0,a=jy(a)?a:0,t.createLinearGradient(i,o,r,a)}(t,e,n),r=e.colorStops,o=0;o0&&(e=i.lineDash,n=i.lineWidth,e&&"solid"!==e&&n>0?"dashed"===e?[4*n,2*n]:"dotted"===e?[n]:j(e)?[e]:Y(e)?e:null:null),o=i.lineDashOffset;if(r){var a=i.strokeNoScale&&t.getLineScale?t.getLineScale():1;a&&1!==a&&(r=z(r,(function(t){return t/a})),o/=a)}return[r,o]}var Qy=new hs(!0);function tv(t){var e=t.stroke;return!(null==e||"none"===e||!(t.lineWidth>0))}function ev(t){return"string"==typeof t&&"none"!==t}function nv(t){var e=t.fill;return null!=e&&"none"!==e}function iv(t,e){if(null!=e.fillOpacity&&1!==e.fillOpacity){var n=t.globalAlpha;t.globalAlpha=e.fillOpacity*e.opacity,t.fill(),t.globalAlpha=n}else t.fill()}function rv(t,e){if(null!=e.strokeOpacity&&1!==e.strokeOpacity){var n=t.globalAlpha;t.globalAlpha=e.strokeOpacity*e.opacity,t.stroke(),t.globalAlpha=n}else t.stroke()}function ov(t,e,n){var i=la(e.image,e.__image,n);if(ha(i)){var r=t.createPattern(i,e.repeat||"repeat");if("function"==typeof DOMMatrix&&r&&r.setTransform){var o=new DOMMatrix;o.translateSelf(e.x||0,e.y||0),o.rotateSelf(0,0,(e.rotation||0)*wt),o.scaleSelf(e.scaleX||1,e.scaleY||1),r.setTransform(o)}return r}}var av=["shadowBlur","shadowOffsetX","shadowOffsetY"],sv=[["lineCap","butt"],["lineJoin","miter"],["miterLimit",10]];function lv(t,e,n,i,r){var o=!1;if(!i&&e===(n=n||{}))return!1;if(i||e.opacity!==n.opacity){cv(t,r),o=!0;var a=Math.max(Math.min(e.opacity,1),0);t.globalAlpha=isNaN(a)?Ma.opacity:a}(i||e.blend!==n.blend)&&(o||(cv(t,r),o=!0),t.globalCompositeOperation=e.blend||Ma.blend);for(var s=0;s0&&t.unfinished);t.unfinished||this._zr.flush()}}},e.prototype.getDom=function(){return this._dom},e.prototype.getId=function(){return this.id},e.prototype.getZr=function(){return this._zr},e.prototype.isSSR=function(){return this._ssr},e.prototype.setOption=function(t,e,n){if(!this[Dv])if(this._disposed)om(this.id);else{var i,r,o;if(q(e)&&(n=e.lazyUpdate,i=e.silent,r=e.replaceMerge,o=e.transition,e=e.notMerge),this[Dv]=!0,!this._model||e){var a=new Md(this._api),s=this._theme,l=this._model=new gd;l.scheduler=this._scheduler,l.ssr=this._ssr,l.init(null,null,null,s,this._locale,a)}this._model.setOption(t,{replaceMerge:r},um);var u={seriesTransition:o,optionChanged:!0};if(n)this[Av]={silent:i,updateParams:u},this[Dv]=!1,this.getZr().wakeUp();else{try{Ev(this),Bv.update.call(this,null,u)}catch(t){throw this[Av]=null,this[Dv]=!1,t}this._ssr||this._zr.flush(),this[Av]=null,this[Dv]=!1,Hv.call(this,i),Yv.call(this,i)}}},e.prototype.setTheme=function(){bo()},e.prototype.getModel=function(){return this._model},e.prototype.getOption=function(){return this._model&&this._model.getOption()},e.prototype.getWidth=function(){return this._zr.getWidth()},e.prototype.getHeight=function(){return this._zr.getHeight()},e.prototype.getDevicePixelRatio=function(){return this._zr.painter.dpr||r.hasGlobalWindow&&window.devicePixelRatio||1},e.prototype.getRenderedCanvas=function(t){return this.renderToCanvas(t)},e.prototype.renderToCanvas=function(t){t=t||{};var e=this._zr.painter;return e.getRenderedCanvas({backgroundColor:t.backgroundColor||this._model.get("backgroundColor"),pixelRatio:t.pixelRatio||this.getDevicePixelRatio()})},e.prototype.renderToSVGString=function(t){t=t||{};var e=this._zr.painter;return e.renderToString({useViewBox:t.useViewBox})},e.prototype.getSvgDataURL=function(){if(r.svgSupported){var t=this._zr;return E(t.storage.getDisplayList(),(function(t){t.stopAnimation(null,!0)})),t.painter.toDataURL()}},e.prototype.getDataURL=function(t){if(!this._disposed){var e=(t=t||{}).excludeComponents,n=this._model,i=[],r=this;E(e,(function(t){n.eachComponent({mainType:t},(function(t){var e=r._componentsMap[t.__viewId];e.group.ignore||(i.push(e),e.group.ignore=!0)}))}));var o="svg"===this._zr.painter.getType()?this.getSvgDataURL():this.renderToCanvas(t).toDataURL("image/"+(t&&t.type||"png"));return E(i,(function(t){t.group.ignore=!1})),o}om(this.id)},e.prototype.getConnectedDataURL=function(t){if(!this._disposed){var e="svg"===t.type,n=this.group,i=Math.min,r=Math.max,o=1/0;if(fm[n]){var a=o,s=o,l=-1/0,u=-1/0,c=[],p=t&&t.pixelRatio||this.getDevicePixelRatio();E(dm,(function(o,h){if(o.group===n){var p=e?o.getZr().painter.getSvgDom().innerHTML:o.renderToCanvas(T(t)),d=o.getDom().getBoundingClientRect();a=i(d.left,a),s=i(d.top,s),l=r(d.right,l),u=r(d.bottom,u),c.push({dom:p,left:d.left,top:d.top})}}));var d=(l*=p)-(a*=p),f=(u*=p)-(s*=p),g=h.createCanvas(),y=Yr(g,{renderer:e?"svg":"canvas"});if(y.resize({width:d,height:f}),e){var v="";return E(c,(function(t){var e=t.left-a,n=t.top-s;v+=''+t.dom+""})),y.painter.getSvgRoot().innerHTML=v,t.connectedBackgroundColor&&y.painter.setBackgroundColor(t.connectedBackgroundColor),y.refreshImmediately(),y.painter.toDataURL()}return t.connectedBackgroundColor&&y.add(new Ws({shape:{x:0,y:0,width:d,height:f},style:{fill:t.connectedBackgroundColor}})),E(c,(function(t){var e=new Ns({style:{x:t.left*p-a,y:t.top*p-s,image:t.dom}});y.add(e)})),y.refreshImmediately(),g.toDataURL("image/"+(t&&t.type||"png"))}return this.getDataURL(t)}om(this.id)},e.prototype.convertToPixel=function(t,e){return Fv(this,"convertToPixel",t,e)},e.prototype.convertFromPixel=function(t,e){return Fv(this,"convertFromPixel",t,e)},e.prototype.containPixel=function(t,e){var n;if(!this._disposed)return E(Fo(this._model,t),(function(t,i){i.indexOf("Models")>=0&&E(t,(function(t){var r=t.coordinateSystem;if(r&&r.containPoint)n=n||!!r.containPoint(e);else if("seriesModels"===i){var o=this._chartsMap[t.__viewId];o&&o.containPoint&&(n=n||o.containPoint(e,t))}else 0}),this)}),this),!!n;om(this.id)},e.prototype.getVisual=function(t,e){var n=Fo(this._model,t,{defaultMainType:"series"}),i=n.seriesModel;var r=i.getData(),o=n.hasOwnProperty("dataIndexInside")?n.dataIndexInside:n.hasOwnProperty("dataIndex")?r.indexOfRawIndex(n.dataIndex):null;return null!=o?Dy(r,o,e):Ay(r,e)},e.prototype.getViewOfComponentModel=function(t){return this._componentsMap[t.__viewId]},e.prototype.getViewOfSeriesModel=function(t){return this._chartsMap[t.__viewId]},e.prototype._initEvents=function(){var t,e,n,i=this;E(rm,(function(t){var e=function(e){var n,r=i.getModel(),o=e.target,a="globalout"===t;if(a?n={}:o&&Oy(o,(function(t){var e=rl(t);if(e&&null!=e.dataIndex){var i=e.dataModel||r.getSeriesByIndex(e.seriesIndex);return n=i&&i.getDataParams(e.dataIndex,e.dataType,o)||{},!0}if(e.eventData)return n=A({},e.eventData),!0}),!0),n){var s=n.componentType,l=n.componentIndex;"markLine"!==s&&"markPoint"!==s&&"markArea"!==s||(s="series",l=n.seriesIndex);var u=s&&null!=l&&r.getComponent(s,l),h=u&&i["series"===u.mainType?"_chartsMap":"_componentsMap"][u.__viewId];0,n.event=e,n.type=t,i._$eventProcessor.eventInfo={targetEl:o,packedEvent:n,model:u,view:h},i.trigger(t,n)}};e.zrEventfulCallAtLast=!0,i._zr.on(t,e,i)})),E(sm,(function(t,e){i._messageCenter.on(e,(function(t){this.trigger(e,t)}),i)})),E(["selectchanged"],(function(t){i._messageCenter.on(t,(function(e){this.trigger(t,e)}),i)})),t=this._messageCenter,e=this,n=this._api,t.on("selectchanged",(function(t){var i=n.getModel();t.isFromClick?(Py("map","selectchanged",e,i,t),Py("pie","selectchanged",e,i,t)):"select"===t.fromAction?(Py("map","selected",e,i,t),Py("pie","selected",e,i,t)):"unselect"===t.fromAction&&(Py("map","unselected",e,i,t),Py("pie","unselected",e,i,t))}))},e.prototype.isDisposed=function(){return this._disposed},e.prototype.clear=function(){this._disposed?om(this.id):this.setOption({series:[]},!0)},e.prototype.dispose=function(){if(this._disposed)om(this.id);else{this._disposed=!0,this.getDom()&&Xo(this.getDom(),vm,"");var t=this,e=t._api,n=t._model;E(t._componentsViews,(function(t){t.dispose(n,e)})),E(t._chartsViews,(function(t){t.dispose(n,e)})),t._zr.dispose(),t._dom=t._model=t._chartsMap=t._componentsMap=t._chartsViews=t._componentsViews=t._scheduler=t._api=t._zr=t._throttledZrFlush=t._theme=t._coordSysMgr=t._messageCenter=null,delete dm[t.id]}},e.prototype.resize=function(t){if(!this[Dv])if(this._disposed)om(this.id);else{this._zr.resize(t);var e=this._model;if(this._loadingFX&&this._loadingFX.resize(),e){var n=e.resetOption("media"),i=t&&t.silent;this[Av]&&(null==i&&(i=this[Av].silent),n=!0,this[Av]=null),this[Dv]=!0;try{n&&Ev(this),Bv.update.call(this,{type:"resize",animation:A({duration:0},t&&t.animation)})}catch(t){throw this[Dv]=!1,t}this[Dv]=!1,Hv.call(this,i),Yv.call(this,i)}}},e.prototype.showLoading=function(t,e){if(this._disposed)om(this.id);else if(q(t)&&(e=t,t=""),t=t||"default",this.hideLoading(),pm[t]){var n=pm[t](this._api,e),i=this._zr;this._loadingFX=n,i.add(n)}},e.prototype.hideLoading=function(){this._disposed?om(this.id):(this._loadingFX&&this._zr.remove(this._loadingFX),this._loadingFX=null)},e.prototype.makeActionFromEvent=function(t){var e=A({},t);return e.type=sm[t.type],e},e.prototype.dispatchAction=function(t,e){if(this._disposed)om(this.id);else if(q(e)||(e={silent:!!e}),am[t.type]&&this._model)if(this[Dv])this._pendingActions.push(t);else{var n=e.silent;Wv.call(this,t,n);var i=e.flush;i?this._zr.flush():!1!==i&&r.browser.weChat&&this._throttledZrFlush(),Hv.call(this,n),Yv.call(this,n)}},e.prototype.updateLabelLayout=function(){wv.trigger("series:layoutlabels",this._model,this._api,{updatedSeries:[]})},e.prototype.appendData=function(t){if(this._disposed)om(this.id);else{var e=t.seriesIndex,n=this.getModel().getSeriesByIndex(e);0,n.appendData(t),this._scheduler.unfinished=!0,this.getZr().wakeUp()}},e.internalField=function(){function t(t){t.clearColorPalette(),t.eachSeries((function(t){t.clearColorPalette()}))}function e(t){for(var e=[],n=t.currentStates,i=0;i0?{duration:o,delay:i.get("delay"),easing:i.get("easing")}:null;n.eachRendered((function(t){if(t.states&&t.states.emphasis){if(xh(t))return;if(t instanceof ks&&function(t){var e=ll(t);e.normalFill=t.style.fill,e.normalStroke=t.style.stroke;var n=t.states.select||{};e.selectFill=n.style&&n.style.fill||null,e.selectStroke=n.style&&n.style.stroke||null}(t),t.__dirty){var n=t.prevStates;n&&t.useStates(n)}if(r){t.stateTransition=a;var i=t.getTextContent(),o=t.getTextGuideLine();i&&(i.stateTransition=a),o&&(o.stateTransition=a)}t.__dirty&&e(t)}}))}Ev=function(t){var e=t._scheduler;e.restorePipelines(t._model),e.prepareStageTasks(),zv(t,!0),zv(t,!1),e.plan()},zv=function(t,e){for(var n=t._model,i=t._scheduler,r=e?t._componentsViews:t._chartsViews,o=e?t._componentsMap:t._chartsMap,a=t._zr,s=t._api,l=0;le.get("hoverLayerThreshold")&&!r.node&&!r.worker&&e.eachSeries((function(e){if(!e.preventUsingHoverLayer){var n=t._chartsMap[e.__viewId];n.__alive&&n.eachRendered((function(t){t.states.emphasis&&(t.states.emphasis.hoverLayer=!0)}))}}))}(t,e),wv.trigger("series:afterupdate",e,n,l)},Jv=function(t){t[kv]=!0,t.getZr().wakeUp()},Qv=function(t){t[kv]&&(t.getZr().storage.traverse((function(t){xh(t)||e(t)})),t[kv]=!1)},Kv=function(t){return new(function(e){function i(){return null!==e&&e.apply(this,arguments)||this}return n(i,e),i.prototype.getCoordinateSystems=function(){return t._coordSysMgr.getCoordinateSystems()},i.prototype.getComponentByElement=function(e){for(;e;){var n=e.__ecComponentInfo;if(null!=n)return t._model.getComponent(n.mainType,n.index);e=e.parent}},i.prototype.enterEmphasis=function(e,n){Ol(e,n),Jv(t)},i.prototype.leaveEmphasis=function(e,n){Rl(e,n),Jv(t)},i.prototype.enterBlur=function(e){Nl(e),Jv(t)},i.prototype.leaveBlur=function(e){El(e),Jv(t)},i.prototype.enterSelect=function(e){zl(e),Jv(t)},i.prototype.leaveSelect=function(e){Vl(e),Jv(t)},i.prototype.getModel=function(){return t.getModel()},i.prototype.getViewOfComponentModel=function(e){return t.getViewOfComponentModel(e)},i.prototype.getViewOfSeriesModel=function(e){return t.getViewOfSeriesModel(e)},i}(_d))(t)},$v=function(t){function e(t,e){for(var n=0;n=0)){Lm.push(n);var o=ey.wrapStageHandler(n,r);o.__prio=e,o.__raw=n,t.push(o)}}function Om(t,e){pm[t]=e}function Rm(t,e,n){var i=Mv("registerMap");i&&i(t,e,n)}var Nm=function(t){var e=(t=T(t)).type,n="";e||wo(n);var i=e.split(":");2!==i.length&&wo(n);var r=!1;"echarts"===i[0]&&(e=i[1],r=!0),t.__isBuiltIn=r,Vf.set(e,t)};km(Iv,Kg),km(Tv,Jg),km(Tv,Qg),km(Iv,Ty),km(Tv,Cy),km(7e3,(function(t,e){t.eachRawSeries((function(n){if(!t.isSeriesFiltered(n)){var i=n.getData();i.hasItemVisual()&&i.each((function(t){var n=i.getItemVisual(t,"decal");n&&(i.ensureUniqueItemVisual(t,"style").decal=mv(n,e))}));var r=i.getVisual("decal");if(r)i.getVisual("style").decal=mv(r,e)}}))})),wm(Xd),Sm(900,(function(t){var e=yt();t.eachSeries((function(t){var n=t.get("stack");if(n){var i=e.get(n)||e.set(n,[]),r=t.getData(),o={stackResultDimension:r.getCalculationInfo("stackResultDimension"),stackedOverDimension:r.getCalculationInfo("stackedOverDimension"),stackedDimension:r.getCalculationInfo("stackedDimension"),stackedByDimension:r.getCalculationInfo("stackedByDimension"),isStackedByIndex:r.getCalculationInfo("isStackedByIndex"),data:r,seriesModel:t};if(!o.stackedDimension||!o.isStackedByIndex&&!o.stackedByDimension)return;i.length&&r.setCalculationInfo("stackedOnSeries",i[i.length-1].seriesModel),i.push(o)}})),e.each(Ud)})),Om("default",(function(t,e){k(e=e||{},{text:"loading",textColor:"#000",fontSize:12,fontWeight:"normal",fontStyle:"normal",fontFamily:"sans-serif",maskColor:"rgba(255, 255, 255, 0.8)",showSpinner:!0,color:"#5470c6",spinnerRadius:10,lineWidth:5,zlevel:0});var n=new Br,i=new Ws({style:{fill:e.maskColor},zlevel:e.zlevel,z:1e4});n.add(i);var r,o=new Xs({style:{text:e.text,fill:e.textColor,fontSize:e.fontSize,fontWeight:e.fontWeight,fontStyle:e.fontStyle,fontFamily:e.fontFamily},zlevel:e.zlevel,z:10001}),a=new Ws({style:{fill:"none"},textContent:o,textConfig:{position:"right",distance:10},zlevel:e.zlevel,z:10001});return n.add(a),e.showSpinner&&((r=new nh({shape:{startAngle:-ty/2,endAngle:-ty/2+.1,r:e.spinnerRadius},style:{stroke:e.color,lineCap:"round",lineWidth:e.lineWidth},zlevel:e.zlevel,z:10001})).animateShape(!0).when(1e3,{endAngle:3*ty/2}).start("circularInOut"),r.animateShape(!0).when(1e3,{startAngle:3*ty/2}).delay(300).start("circularInOut"),n.add(r)),n.resize=function(){var n=o.getBoundingRect().width,s=e.showSpinner?e.spinnerRadius:0,l=(t.getWidth()-2*s-(e.showSpinner&&n?10:0)-n)/2-(e.showSpinner&&n?0:5+n/2)+(e.showSpinner?0:n/2)+(n?0:s),u=t.getHeight()/2;e.showSpinner&&r.setShape({cx:l,cy:u}),a.setShape({x:l-s,y:u-s,width:2*s,height:2*s}),i.setShape({x:0,y:0,width:t.getWidth(),height:t.getHeight()})},n.resize(),n})),Cm({type:dl,event:dl,update:dl},bt),Cm({type:fl,event:fl,update:fl},bt),Cm({type:gl,event:gl,update:gl},bt),Cm({type:yl,event:yl,update:yl},bt),Cm({type:vl,event:vl,update:vl},bt),bm("light",vy),bm("dark",wy);var Em=[],zm={registerPreprocessor:wm,registerProcessor:Sm,registerPostInit:Mm,registerPostUpdate:Im,registerUpdateLifecycle:Tm,registerAction:Cm,registerCoordinateSystem:Dm,registerLayout:Am,registerVisual:km,registerTransform:Nm,registerLoading:Om,registerMap:Rm,registerImpl:function(t,e){Sv[t]=e},PRIORITY:Cv,ComponentModel:zp,ComponentView:Ag,SeriesModel:bg,ChartView:Og,registerComponentModel:function(t){zp.registerClass(t)},registerComponentView:function(t){Ag.registerClass(t)},registerSeriesModel:function(t){bg.registerClass(t)},registerChartView:function(t){Og.registerClass(t)},registerSubTypeDefaulter:function(t,e){zp.registerSubTypeDefaulter(t,e)},registerPainter:function(t,e){Xr(t,e)}};function Vm(t){Y(t)?E(t,(function(t){Vm(t)})):P(Em,t)>=0||(Em.push(t),X(t)&&(t={install:t}),t.install(zm))}function Bm(t){return null==t?0:t.length||1}function Fm(t){return t}var Gm=function(){function t(t,e,n,i,r,o){this._old=t,this._new=e,this._oldKeyGetter=n||Fm,this._newKeyGetter=i||Fm,this.context=r,this._diffModeMultiple="multiple"===o}return t.prototype.add=function(t){return this._add=t,this},t.prototype.update=function(t){return this._update=t,this},t.prototype.updateManyToOne=function(t){return this._updateManyToOne=t,this},t.prototype.updateOneToMany=function(t){return this._updateOneToMany=t,this},t.prototype.updateManyToMany=function(t){return this._updateManyToMany=t,this},t.prototype.remove=function(t){return this._remove=t,this},t.prototype.execute=function(){this[this._diffModeMultiple?"_executeMultiple":"_executeOneToOne"]()},t.prototype._executeOneToOne=function(){var t=this._old,e=this._new,n={},i=new Array(t.length),r=new Array(e.length);this._initIndexMap(t,null,i,"_oldKeyGetter"),this._initIndexMap(e,n,r,"_newKeyGetter");for(var o=0;o1){var u=s.shift();1===s.length&&(n[a]=s[0]),this._update&&this._update(u,o)}else 1===l?(n[a]=null,this._update&&this._update(s,o)):this._remove&&this._remove(o)}this._performRestAdd(r,n)},t.prototype._executeMultiple=function(){var t=this._old,e=this._new,n={},i={},r=[],o=[];this._initIndexMap(t,n,r,"_oldKeyGetter"),this._initIndexMap(e,i,o,"_newKeyGetter");for(var a=0;a1&&1===c)this._updateManyToOne&&this._updateManyToOne(u,l),i[s]=null;else if(1===h&&c>1)this._updateOneToMany&&this._updateOneToMany(u,l),i[s]=null;else if(1===h&&1===c)this._update&&this._update(u,l),i[s]=null;else if(h>1&&c>1)this._updateManyToMany&&this._updateManyToMany(u,l),i[s]=null;else if(h>1)for(var p=0;p1)for(var a=0;a30}var Qm,tx,ex,nx,ix,rx,ox,ax=q,sx=z,lx="undefined"==typeof Int32Array?Array:Int32Array,ux=["hasItemOption","_nameList","_idList","_invertedIndicesMap","_dimSummary","userOutput","_rawData","_dimValueGetter","_nameDimIdx","_idDimIdx","_nameRepeatCount"],hx=["_approximateExtent"],cx=function(){function t(t,e){var n;this.type="list",this._dimOmitted=!1,this._nameList=[],this._idList=[],this._visual={},this._layout={},this._itemVisuals=[],this._itemLayouts=[],this._graphicEls=[],this._approximateExtent={},this._calculationInfo={},this.hasItemOption=!1,this.TRANSFERABLE_METHODS=["cloneShallow","downSample","lttbDownSample","map"],this.CHANGABLE_METHODS=["filterSelf","selectRange"],this.DOWNSAMPLE_METHODS=["downSample","lttbDownSample"];var i=!1;qm(t)?(n=t.dimensions,this._dimOmitted=t.isDimensionOmitted(),this._schema=t):(i=!0,n=t),n=n||["x","y"];for(var r={},o=[],a={},s=!1,l={},u=0;u=e)){var n=this._store.getProvider();this._updateOrdinalMeta();var i=this._nameList,r=this._idList;if(n.getSource().sourceFormat===Wp&&!n.pure)for(var o=[],a=t;a0},t.prototype.ensureUniqueItemVisual=function(t,e){var n=this._itemVisuals,i=n[t];i||(i=n[t]={});var r=i[e];return null==r&&(Y(r=this.getVisual(e))?r=r.slice():ax(r)&&(r=A({},r)),i[e]=r),r},t.prototype.setItemVisual=function(t,e,n){var i=this._itemVisuals[t]||{};this._itemVisuals[t]=i,ax(e)?A(i,e):i[e]=n},t.prototype.clearAllVisual=function(){this._visual={},this._itemVisuals=[]},t.prototype.setLayout=function(t,e){ax(t)?A(this._layout,t):this._layout[t]=e},t.prototype.getLayout=function(t){return this._layout[t]},t.prototype.getItemLayout=function(t){return this._itemLayouts[t]},t.prototype.setItemLayout=function(t,e,n){this._itemLayouts[t]=n?A(this._itemLayouts[t]||{},e):e},t.prototype.clearItemLayouts=function(){this._itemLayouts.length=0},t.prototype.setItemGraphicEl=function(t,e){var n=this.hostModel&&this.hostModel.seriesIndex;ol(n,this.dataType,t,e),this._graphicEls[t]=e},t.prototype.getItemGraphicEl=function(t){return this._graphicEls[t]},t.prototype.eachItemGraphicEl=function(t,e){E(this._graphicEls,(function(n,i){n&&t&&t.call(e,n,i)}))},t.prototype.cloneShallow=function(e){return e||(e=new t(this._schema?this._schema:sx(this.dimensions,this._getDimInfo,this),this.hostModel)),ix(e,this),e._store=this._store,e},t.prototype.wrapMethod=function(t,e){var n=this[t];X(n)&&(this.__wrappedMethods=this.__wrappedMethods||[],this.__wrappedMethods.push(t),this[t]=function(){var t=n.apply(this,arguments);return e.apply(this,[t].concat(at(arguments)))})},t.internalField=(Qm=function(t){var e=t._invertedIndicesMap;E(e,(function(n,i){var r=t._dimInfos[i],o=r.ordinalMeta,a=t._store;if(o){n=e[i]=new lx(o.categories.length);for(var s=0;s1&&(s+="__ec__"+u),i[e]=s}})),t}();function px(t,e){Qd(t)||(t=ef(t));var n=(e=e||{}).coordDimensions||[],i=e.dimensionsDefine||t.dimensionsDefine||[],r=yt(),o=[],a=function(t,e,n,i){var r=Math.max(t.dimensionsDetectedCount||1,e.length,n.length,i||0);return E(e,(function(t){var e;q(t)&&(e=t.dimsDef)&&(r=Math.max(r,e.length))})),r}(t,n,i,e.dimensionsCount),s=e.canOmitUnusedDimensions&&Jm(a),l=i===t.dimensionsDefine,u=l?$m(t):Km(i),h=e.encodeDefine;!h&&e.encodeDefaulter&&(h=e.encodeDefaulter(t,a));for(var c=yt(h),p=new Xf(a),d=0;d0&&(i.name=r+(o-1)),o++,e.set(r,o)}}(o),new jm({source:t,dimensions:o,fullDimensionCount:a,dimensionOmitted:s})}function dx(t,e,n){if(n||e.hasKey(t)){for(var i=0;e.hasKey(t+i);)i++;t+=i}return e.set(t,!0),t}var fx=function(t){this.coordSysDims=[],this.axisMap=yt(),this.categoryAxisMap=yt(),this.coordSysName=t};var gx={cartesian2d:function(t,e,n,i){var r=t.getReferringComponents("xAxis",Wo).models[0],o=t.getReferringComponents("yAxis",Wo).models[0];e.coordSysDims=["x","y"],n.set("x",r),n.set("y",o),yx(r)&&(i.set("x",r),e.firstCategoryDimIndex=0),yx(o)&&(i.set("y",o),null==e.firstCategoryDimIndex&&(e.firstCategoryDimIndex=1))},singleAxis:function(t,e,n,i){var r=t.getReferringComponents("singleAxis",Wo).models[0];e.coordSysDims=["single"],n.set("single",r),yx(r)&&(i.set("single",r),e.firstCategoryDimIndex=0)},polar:function(t,e,n,i){var r=t.getReferringComponents("polar",Wo).models[0],o=r.findAxisModel("radiusAxis"),a=r.findAxisModel("angleAxis");e.coordSysDims=["radius","angle"],n.set("radius",o),n.set("angle",a),yx(o)&&(i.set("radius",o),e.firstCategoryDimIndex=0),yx(a)&&(i.set("angle",a),null==e.firstCategoryDimIndex&&(e.firstCategoryDimIndex=1))},geo:function(t,e,n,i){e.coordSysDims=["lng","lat"]},parallel:function(t,e,n,i){var r=t.ecModel,o=r.getComponent("parallel",t.get("parallelIndex")),a=e.coordSysDims=o.dimensions.slice();E(o.parallelAxisIndex,(function(t,o){var s=r.getComponent("parallelAxis",t),l=a[o];n.set(l,s),yx(s)&&(i.set(l,s),null==e.firstCategoryDimIndex&&(e.firstCategoryDimIndex=o))}))}};function yx(t){return"category"===t.get("type")}function vx(t,e,n){var i,r,o,a=(n=n||{}).byIndex,s=n.stackedCoordDimension;!function(t){return!qm(t.schema)}(e)?(r=e.schema,i=r.dimensions,o=e.store):i=e;var l,u,h,c,p=!(!t||!t.get("stack"));if(E(i,(function(t,e){U(t)&&(i[e]=t={name:t}),p&&!t.isExtraCoord&&(a||l||!t.ordinalMeta||(l=t),u||"ordinal"===t.type||"time"===t.type||s&&s!==t.coordDim||(u=t))})),!u||a||l||(a=!0),u){h="__\0ecstackresult_"+t.id,c="__\0ecstackedover_"+t.id,l&&(l.createInvertedIndices=!0);var d=u.coordDim,f=u.type,g=0;E(i,(function(t){t.coordDim===d&&g++}));var y={name:h,coordDim:d,coordDimIndex:g,type:f,isExtraCoord:!0,isCalculationCoord:!0,storeDimIndex:i.length},v={name:c,coordDim:c,coordDimIndex:g+1,type:f,isExtraCoord:!0,isCalculationCoord:!0,storeDimIndex:i.length+1};r?(o&&(y.storeDimIndex=o.ensureCalculationDimension(c,f),v.storeDimIndex=o.ensureCalculationDimension(h,f)),r.appendCalculationDimension(y),r.appendCalculationDimension(v)):(i.push(y),i.push(v))}return{stackedDimension:u&&u.name,stackedByDimension:l&&l.name,isStackedByIndex:a,stackedOverDimension:c,stackResultDimension:h}}function mx(t,e){return!!e&&e===t.getCalculationInfo("stackedDimension")}function xx(t,e){return mx(t,e)?t.getCalculationInfo("stackResultDimension"):e}function _x(t,e,n){n=n||{};var i,r=e.getSourceManager(),o=!1;t?(o=!0,i=ef(t)):o=(i=r.getSource()).sourceFormat===Wp;var a=function(t){var e=t.get("coordinateSystem"),n=new fx(e),i=gx[e];if(i)return i(t,n,n.axisMap,n.categoryAxisMap),n}(e),s=function(t,e){var n,i=t.get("coordinateSystem"),r=wd.get(i);return e&&e.coordSysDims&&(n=z(e.coordSysDims,(function(t){var n={name:t},i=e.axisMap.get(t);if(i){var r=i.get("type");n.type=Ym(r)}return n}))),n||(n=r&&(r.getDimensionsInfo?r.getDimensionsInfo():r.dimensions.slice())||["x","y"]),n}(e,a),l=n.useEncodeDefaulter,u=X(l)?l:l?H(td,s,e):null,h=px(i,{coordDimensions:s,generateCoord:n.generateCoord,encodeDefine:e.getEncode(),encodeDefaulter:u,canOmitUnusedDimensions:!o}),c=function(t,e,n){var i,r;return n&&E(t,(function(t,o){var a=t.coordDim,s=n.categoryAxisMap.get(a);s&&(null==i&&(i=o),t.ordinalMeta=s.getOrdinalMeta(),e&&(t.createInvertedIndices=!0)),null!=t.otherDims.itemName&&(r=!0)})),r||null==i||(t[i].otherDims.itemName=0),i}(h.dimensions,n.createInvertedIndices,a),p=o?null:r.getSharedDataStore(h),d=vx(e,{schema:h,store:p}),f=new cx(h,e);f.setCalculationInfo(d);var g=null!=c&&function(t){if(t.sourceFormat===Wp){var e=function(t){var e=0;for(;ee[1]&&(e[1]=t[1])},t.prototype.unionExtentFromData=function(t,e){this.unionExtent(t.getApproximateExtent(e))},t.prototype.getExtent=function(){return this._extent.slice()},t.prototype.setExtent=function(t,e){var n=this._extent;isNaN(t)||(n[0]=t),isNaN(e)||(n[1]=e)},t.prototype.isInExtentRange=function(t){return this._extent[0]<=t&&this._extent[1]>=t},t.prototype.isBlank=function(){return this._isBlank},t.prototype.setBlank=function(t){this._isBlank=t},t}();na(bx);var Sx=0,Mx=function(){function t(t){this.categories=t.categories||[],this._needCollect=t.needCollect,this._deduplication=t.deduplication,this.uid=++Sx}return t.createByAxisModel=function(e){var n=e.option,i=n.data,r=i&&z(i,Ix);return new t({categories:r,needCollect:!r,deduplication:!1!==n.dedplication})},t.prototype.getOrdinal=function(t){return this._getOrCreateMap().get(t)},t.prototype.parseAndCollect=function(t){var e,n=this._needCollect;if(!U(t)&&!n)return t;if(n&&!this._deduplication)return e=this.categories.length,this.categories[e]=t,e;var i=this._getOrCreateMap();return null==(e=i.get(t))&&(n?(e=this.categories.length,this.categories[e]=t,i.set(t,e)):e=NaN),e},t.prototype._getOrCreateMap=function(){return this._map||(this._map=yt(this.categories))},t}();function Ix(t){return q(t)&&null!=t.value?t.value:t+""}function Tx(t){return"interval"===t.type||"log"===t.type}function Cx(t,e,n,i){var r={},o=t[1]-t[0],a=r.interval=po(o/e,!0);null!=n&&ai&&(a=r.interval=i);var s=r.intervalPrecision=Ax(a);return function(t,e){!isFinite(t[0])&&(t[0]=e[0]),!isFinite(t[1])&&(t[1]=e[1]),kx(t,0,e),kx(t,1,e),t[0]>t[1]&&(t[0]=t[1])}(r.niceTickExtent=[Jr(Math.ceil(t[0]/a)*a,s),Jr(Math.floor(t[1]/a)*a,s)],t),r}function Dx(t){var e=Math.pow(10,co(t)),n=t/e;return n?2===n?n=3:3===n?n=5:n*=2:n=1,Jr(n*e)}function Ax(t){return to(t)+2}function kx(t,e,n){t[e]=Math.max(Math.min(t[e],n[1]),n[0])}function Lx(t,e){return t>=e[0]&&t<=e[1]}function Px(t,e){return e[1]===e[0]?.5:(t-e[0])/(e[1]-e[0])}function Ox(t,e){return t*(e[1]-e[0])+e[0]}var Rx=function(t){function e(e){var n=t.call(this,e)||this;n.type="ordinal";var i=n.getSetting("ordinalMeta");return i||(i=new Mx({})),Y(i)&&(i=new Mx({categories:z(i,(function(t){return q(t)?t.value:t}))})),n._ordinalMeta=i,n._extent=n.getSetting("extent")||[0,i.categories.length-1],n}return n(e,t),e.prototype.parse=function(t){return null==t?NaN:U(t)?this._ordinalMeta.getOrdinal(t):Math.round(t)},e.prototype.contain=function(t){return Lx(t=this.parse(t),this._extent)&&null!=this._ordinalMeta.categories[t]},e.prototype.normalize=function(t){return Px(t=this._getTickNumber(this.parse(t)),this._extent)},e.prototype.scale=function(t){return t=Math.round(Ox(t,this._extent)),this.getRawOrdinalNumber(t)},e.prototype.getTicks=function(){for(var t=[],e=this._extent,n=e[0];n<=e[1];)t.push({value:n}),n++;return t},e.prototype.getMinorTicks=function(t){},e.prototype.setSortInfo=function(t){if(null!=t){for(var e=t.ordinalNumbers,n=this._ordinalNumbersByTick=[],i=this._ticksByOrdinalNumber=[],r=0,o=this._ordinalMeta.categories.length,a=Math.min(o,e.length);r=0&&t=0&&t=t},e.prototype.getOrdinalMeta=function(){return this._ordinalMeta},e.prototype.calcNiceTicks=function(){},e.prototype.calcNiceExtent=function(){},e.type="ordinal",e}(bx);bx.registerClass(Rx);var Nx=Jr,Ex=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.type="interval",e._interval=0,e._intervalPrecision=2,e}return n(e,t),e.prototype.parse=function(t){return t},e.prototype.contain=function(t){return Lx(t,this._extent)},e.prototype.normalize=function(t){return Px(t,this._extent)},e.prototype.scale=function(t){return Ox(t,this._extent)},e.prototype.setExtent=function(t,e){var n=this._extent;isNaN(t)||(n[0]=parseFloat(t)),isNaN(e)||(n[1]=parseFloat(e))},e.prototype.unionExtent=function(t){var e=this._extent;t[0]e[1]&&(e[1]=t[1]),this.setExtent(e[0],e[1])},e.prototype.getInterval=function(){return this._interval},e.prototype.setInterval=function(t){this._interval=t,this._niceExtent=this._extent.slice(),this._intervalPrecision=Ax(t)},e.prototype.getTicks=function(t){var e=this._interval,n=this._extent,i=this._niceExtent,r=this._intervalPrecision,o=[];if(!e)return o;n[0]1e4)return[];var s=o.length?o[o.length-1].value:i[1];return n[1]>s&&(t?o.push({value:Nx(s+e,r)}):o.push({value:n[1]})),o},e.prototype.getMinorTicks=function(t){for(var e=this.getTicks(!0),n=[],i=this.getExtent(),r=1;ri[0]&&h0&&(o=null===o?s:Math.min(o,s))}n[i]=o}}return n}(t),n=[];return E(t,(function(t){var i,r=t.coordinateSystem.getBaseAxis(),o=r.getExtent();if("category"===r.type)i=r.getBandWidth();else if("value"===r.type||"time"===r.type){var a=r.dim+"_"+r.index,s=e[a],l=Math.abs(o[1]-o[0]),u=r.scale.getExtent(),h=Math.abs(u[1]-u[0]);i=s?l/h*s:l}else{var c=t.getData();i=Math.abs(o[1]-o[0])/c.count()}var p=$r(t.get("barWidth"),i),d=$r(t.get("barMaxWidth"),i),f=$r(t.get("barMinWidth")||(qx(t)?.5:1),i),g=t.get("barGap"),y=t.get("barCategoryGap");n.push({bandWidth:i,barWidth:p,barMaxWidth:d,barMinWidth:f,barGap:g,barCategoryGap:y,axisKey:Wx(r),stackId:Gx(t)})})),Xx(n)}function Xx(t){var e={};E(t,(function(t,n){var i=t.axisKey,r=t.bandWidth,o=e[i]||{bandWidth:r,remainedWidth:r,autoWidthCount:0,categoryGap:null,gap:"20%",stacks:{}},a=o.stacks;e[i]=o;var s=t.stackId;a[s]||o.autoWidthCount++,a[s]=a[s]||{width:0,maxWidth:0};var l=t.barWidth;l&&!a[s].width&&(a[s].width=l,l=Math.min(o.remainedWidth,l),o.remainedWidth-=l);var u=t.barMaxWidth;u&&(a[s].maxWidth=u);var h=t.barMinWidth;h&&(a[s].minWidth=h);var c=t.barGap;null!=c&&(o.gap=c);var p=t.barCategoryGap;null!=p&&(o.categoryGap=p)}));var n={};return E(e,(function(t,e){n[e]={};var i=t.stacks,r=t.bandWidth,o=t.categoryGap;if(null==o){var a=G(i).length;o=Math.max(35-4*a,15)+"%"}var s=$r(o,r),l=$r(t.gap,1),u=t.remainedWidth,h=t.autoWidthCount,c=(u-s)/(h+(h-1)*l);c=Math.max(c,0),E(i,(function(t){var e=t.maxWidth,n=t.minWidth;if(t.width){i=t.width;e&&(i=Math.min(i,e)),n&&(i=Math.max(i,n)),t.width=i,u-=i+l*i,h--}else{var i=c;e&&ei&&(i=n),i!==c&&(t.width=i,u-=i+l*i,h--)}})),c=(u-s)/(h+(h-1)*l),c=Math.max(c,0);var p,d=0;E(i,(function(t,e){t.width||(t.width=c),p=t,d+=t.width*(1+l)})),p&&(d-=p.width*l);var f=-d/2;E(i,(function(t,i){n[e][i]=n[e][i]||{bandWidth:r,offset:f,width:t.width},f+=t.width*(1+l)}))})),n}function Ux(t,e){var n=Hx(t,e),i=Yx(n);E(n,(function(t){var e=t.getData(),n=t.coordinateSystem.getBaseAxis(),r=Gx(t),o=i[Wx(n)][r],a=o.offset,s=o.width;e.setLayout({bandWidth:o.bandWidth,offset:a,size:s})}))}function Zx(t){return{seriesType:t,plan:kg(),reset:function(t){if(jx(t)){var e=t.getData(),n=t.coordinateSystem,i=n.getBaseAxis(),r=n.getOtherAxis(i),o=e.getDimensionIndex(e.mapDimension(r.dim)),a=e.getDimensionIndex(e.mapDimension(i.dim)),s=t.get("showBackground",!0),l=e.mapDimension(r.dim),u=e.getCalculationInfo("stackResultDimension"),h=mx(e,l)&&!!e.getCalculationInfo("stackedOnSeries"),c=r.isHorizontal(),p=function(t,e){var n=e.model.get("startValue");n||(n=0);return e.toGlobalCoord(e.dataToCoord("log"===e.type?n>0?n:1:n))}(0,r),d=qx(t),f=t.get("barMinHeight")||0,g=u&&e.getDimensionIndex(u),y=e.getLayout("size"),v=e.getLayout("offset");return{progress:function(t,e){for(var i,r=t.count,l=d&&Bx(3*r),u=d&&s&&Bx(3*r),m=d&&Bx(r),x=n.master.getRect(),_=c?x.width:x.height,b=e.getStore(),w=0;null!=(i=t.next());){var S=b.get(h?g:o,i),M=b.get(a,i),I=p,T=void 0;h&&(T=+S-b.get(o,i));var C=void 0,D=void 0,A=void 0,k=void 0;if(c){var L=n.dataToPoint([S,M]);if(h)I=n.dataToPoint([T,M])[0];C=I,D=L[1]+v,A=L[0]-I,k=y,Math.abs(A)0)for(var s=0;s=0;--s)if(l[u]){o=l[u];break}o=o||a.none}if(Y(o)){var h=null==t.level?0:t.level>=0?t.level:o.length+t.level;o=o[h=Math.min(h,o.length-1)]}}return Jc(new Date(t.value),o,r,i)}(t,e,n,this.getSetting("locale"),i)},e.prototype.getTicks=function(){var t=this._interval,e=this._extent,n=[];if(!t)return n;n.push({value:e[0],level:0});var i=this.getSetting("useUTC"),r=function(t,e,n,i){var r=1e4,o=jc,a=0;function s(t,e,n,r,o,a,s){for(var l=new Date(e),u=e,h=l[r]();u1&&0===u&&o.unshift({value:o[0].value-p})}}for(u=0;u=i[0]&&v<=i[1]&&c++)}var m=(i[1]-i[0])/e;if(c>1.5*m&&p>m/1.5)break;if(u.push(g),c>m||t===o[d])break}h=[]}}0;var x=B(z(u,(function(t){return B(t,(function(t){return t.value>=i[0]&&t.value<=i[1]&&!t.notAdd}))})),(function(t){return t.length>0})),_=[],b=x.length-1;for(d=0;dn&&(this._approxInterval=n);var o=$x.length,a=Math.min(function(t,e,n,i){for(;n>>1;t[r][1]16?16:t>7.5?7:t>3.5?4:t>1.5?2:1}function Qx(t){return(t/=2592e6)>6?6:t>3?3:t>2?2:1}function t_(t){return(t/=Gc)>12?12:t>6?6:t>3.5?4:t>2?2:1}function e_(t,e){return(t/=e?Fc:Bc)>30?30:t>20?20:t>15?15:t>10?10:t>5?5:t>2?2:1}function n_(t){return po(t,!0)}function i_(t,e,n){var i=new Date(t);switch(Kc(e)){case"year":case"month":i[up(n)](0);case"day":i[hp(n)](1);case"hour":i[cp(n)](0);case"minute":i[pp(n)](0);case"second":i[dp(n)](0),i[fp(n)](0)}return i.getTime()}bx.registerClass(Kx);var r_=bx.prototype,o_=Ex.prototype,a_=Jr,s_=Math.floor,l_=Math.ceil,u_=Math.pow,h_=Math.log,c_=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.type="log",e.base=10,e._originalScale=new Ex,e._interval=0,e}return n(e,t),e.prototype.getTicks=function(t){var e=this._originalScale,n=this._extent,i=e.getExtent();return z(o_.getTicks.call(this,t),(function(t){var e=t.value,r=Jr(u_(this.base,e));return r=e===n[0]&&this._fixMin?d_(r,i[0]):r,{value:r=e===n[1]&&this._fixMax?d_(r,i[1]):r}}),this)},e.prototype.setExtent=function(t,e){var n=h_(this.base);t=h_(Math.max(0,t))/n,e=h_(Math.max(0,e))/n,o_.setExtent.call(this,t,e)},e.prototype.getExtent=function(){var t=this.base,e=r_.getExtent.call(this);e[0]=u_(t,e[0]),e[1]=u_(t,e[1]);var n=this._originalScale.getExtent();return this._fixMin&&(e[0]=d_(e[0],n[0])),this._fixMax&&(e[1]=d_(e[1],n[1])),e},e.prototype.unionExtent=function(t){this._originalScale.unionExtent(t);var e=this.base;t[0]=h_(t[0])/h_(e),t[1]=h_(t[1])/h_(e),r_.unionExtent.call(this,t)},e.prototype.unionExtentFromData=function(t,e){this.unionExtent(t.getApproximateExtent(e))},e.prototype.calcNiceTicks=function(t){t=t||10;var e=this._extent,n=e[1]-e[0];if(!(n===1/0||n<=0)){var i=ho(n);for(t/n*i<=.5&&(i*=10);!isNaN(i)&&Math.abs(i)<1&&Math.abs(i)>0;)i*=10;var r=[Jr(l_(e[0]/i)*i),Jr(s_(e[1]/i)*i)];this._interval=i,this._niceExtent=r}},e.prototype.calcNiceExtent=function(t){o_.calcNiceExtent.call(this,t),this._fixMin=t.fixMin,this._fixMax=t.fixMax},e.prototype.parse=function(t){return t},e.prototype.contain=function(t){return Lx(t=h_(t)/h_(this.base),this._extent)},e.prototype.normalize=function(t){return Px(t=h_(t)/h_(this.base),this._extent)},e.prototype.scale=function(t){return t=Ox(t,this._extent),u_(this.base,t)},e.type="log",e}(bx),p_=c_.prototype;function d_(t,e){return a_(t,to(e))}p_.getMinorTicks=o_.getMinorTicks,p_.getLabel=o_.getLabel,bx.registerClass(c_);var f_=function(){function t(t,e,n){this._prepareParams(t,e,n)}return t.prototype._prepareParams=function(t,e,n){n[1]0&&s>0&&!l&&(a=0),a<0&&s<0&&!u&&(s=0));var c=this._determinedMin,p=this._determinedMax;return null!=c&&(a=c,l=!0),null!=p&&(s=p,u=!0),{min:a,max:s,minFixed:l,maxFixed:u,isBlank:h}},t.prototype.modifyDataMinMax=function(t,e){this[y_[t]]=e},t.prototype.setDeterminedMinMax=function(t,e){var n=g_[t];this[n]=e},t.prototype.freeze=function(){this.frozen=!0},t}(),g_={min:"_determinedMin",max:"_determinedMax"},y_={min:"_dataMin",max:"_dataMax"};function v_(t,e,n){var i=t.rawExtentInfo;return i||(i=new f_(t,e,n),t.rawExtentInfo=i,i)}function m_(t,e){return null==e?null:nt(e)?NaN:t.parse(e)}function x_(t,e){var n=t.type,i=v_(t,e,t.getExtent()).calculate();t.setBlank(i.isBlank);var r=i.min,o=i.max,a=e.ecModel;if(a&&"time"===n){var s=Hx("bar",a),l=!1;if(E(s,(function(t){l=l||t.getBaseAxis()===e.axis})),l){var u=Yx(s),h=function(t,e,n,i){var r=n.axis.getExtent(),o=r[1]-r[0],a=function(t,e,n){if(t&&e){var i=t[Wx(e)];return null!=i&&null!=n?i[Gx(n)]:i}}(i,n.axis);if(void 0===a)return{min:t,max:e};var s=1/0;E(a,(function(t){s=Math.min(t.offset,s)}));var l=-1/0;E(a,(function(t){l=Math.max(t.offset+t.width,l)})),s=Math.abs(s),l=Math.abs(l);var u=s+l,h=e-t,c=h/(1-(s+l)/o)-h;return e+=c*(l/u),t-=c*(s/u),{min:t,max:e}}(r,o,e,u);r=h.min,o=h.max}}return{extent:[r,o],fixMin:i.minFixed,fixMax:i.maxFixed}}function __(t,e){var n=e,i=x_(t,n),r=i.extent,o=n.get("splitNumber");t instanceof c_&&(t.base=n.get("logBase"));var a=t.type,s=n.get("interval"),l="interval"===a||"time"===a;t.setExtent(r[0],r[1]),t.calcNiceExtent({splitNumber:o,fixMin:i.fixMin,fixMax:i.fixMax,minInterval:l?n.get("minInterval"):null,maxInterval:l?n.get("maxInterval"):null}),null!=s&&t.setInterval&&t.setInterval(s)}function b_(t,e){if(e=e||t.get("type"))switch(e){case"category":return new Rx({ordinalMeta:t.getOrdinalMeta?t.getOrdinalMeta():t.getCategories(),extent:[1/0,-1/0]});case"time":return new Kx({locale:t.ecModel.getLocaleModel(),useUTC:t.ecModel.get("useUTC")});default:return new(bx.getClass(e)||Ex)}}function w_(t){var e,n,i=t.getLabelModel().get("formatter"),r="category"===t.type?t.scale.getExtent()[0]:null;return"time"===t.scale.type?(n=i,function(e,i){return t.scale.getFormattedLabel(e,i,n)}):U(i)?function(e){return function(n){var i=t.scale.getLabel(n);return e.replace("{value}",null!=i?i:"")}}(i):X(i)?(e=i,function(n,i){return null!=r&&(i=n.value-r),e(S_(t,n),i,null!=n.level?{level:n.level}:null)}):function(e){return t.scale.getLabel(e)}}function S_(t,e){return"category"===t.type?t.scale.getLabel(e):e.value}function M_(t,e){var n=e*Math.PI/180,i=t.width,r=t.height,o=i*Math.abs(Math.cos(n))+Math.abs(r*Math.sin(n)),a=i*Math.abs(Math.sin(n))+Math.abs(r*Math.cos(n));return new ze(t.x,t.y,o,a)}function I_(t){var e=t.get("interval");return null==e?"auto":e}function T_(t){return"category"===t.type&&0===I_(t.getLabelModel())}function C_(t,e){var n={};return E(t.mapDimensionsAll(e),(function(e){n[xx(t,e)]=!0})),G(n)}var D_=function(){function t(){}return t.prototype.getNeedCrossZero=function(){return!this.option.scale},t.prototype.getCoordSysModel=function(){},t}();var A_={isDimensionStacked:mx,enableDataStack:vx,getStackedDimension:xx};var k_=Object.freeze({__proto__:null,createList:function(t){return _x(null,t)},getLayoutRect:kp,dataStack:A_,createScale:function(t,e){var n=e;e instanceof Cc||(n=new Cc(e));var i=b_(n);return i.setExtent(t[0],t[1]),__(i,n),i},mixinAxisModelCommonMethods:function(t){R(t,D_)},getECData:rl,createTextStyle:function(t,e){return oc(t,null,null,"normal"!==(e=e||{}).state)},createDimensions:function(t,e){return px(t,e).dimensions},createSymbol:Xy,enableHoverEmphasis:Ul});function L_(t,e){return Math.abs(t-e)<1e-8}function P_(t,e,n){var i=0,r=t[0];if(!r)return!1;for(var o=1;on&&(t=r,n=a)}if(t)return function(t){for(var e=0,n=0,i=0,r=t.length,o=t[r-1][0],a=t[r-1][1],s=0;s>1^-(1&s),l=l>>1^-(1&l),r=s+=r,o=l+=o,i.push([s/n,l/n])}return i}function H_(t,e){return z(B((t=function(t){if(!t.UTF8Encoding)return t;var e=t,n=e.UTF8Scale;return null==n&&(n=1024),E(e.features,(function(t){var e=t.geometry,i=e.encodeOffsets,r=e.coordinates;if(i)switch(e.type){case"LineString":e.coordinates=W_(r,i,n);break;case"Polygon":case"MultiLineString":G_(r,i,n);break;case"MultiPolygon":E(r,(function(t,e){return G_(t,i[e],n)}))}})),e.UTF8Encoding=!1,e}(t)).features,(function(t){return t.geometry&&t.properties&&t.geometry.coordinates.length>0})),(function(t){var n=t.properties,i=t.geometry,r=[];switch(i.type){case"Polygon":var o=i.coordinates;r.push(new z_(o[0],o.slice(1)));break;case"MultiPolygon":E(i.coordinates,(function(t){t[0]&&r.push(new z_(t[0],t.slice(1)))}));break;case"LineString":r.push(new V_([i.coordinates]));break;case"MultiLineString":r.push(new V_(i.coordinates))}var a=new B_(n[e||"name"],r,n.cp);return a.properties=n,a}))}var Y_=Object.freeze({__proto__:null,linearMap:Kr,round:Jr,asc:Qr,getPrecision:to,getPrecisionSafe:eo,getPixelPrecision:no,getPercentWithPrecision:function(t,e,n){return t[e]&&io(t,n)[e]||0},MAX_SAFE_INTEGER:oo,remRadian:ao,isRadianAroundZero:so,parseDate:uo,quantity:ho,quantityExponent:co,nice:po,quantile:fo,reformIntervals:go,isNumeric:vo,numericToNumber:yo}),X_=Object.freeze({__proto__:null,parse:uo,format:Jc}),U_=Object.freeze({__proto__:null,extendShape:Ch,extendPath:Ah,makePath:Ph,makeImage:Oh,mergePath:Nh,resizePath:Eh,createIcon:Uh,updateProps:vh,initProps:mh,getTransform:Bh,clipPointsByRect:Yh,clipRectByRect:Xh,registerShape:kh,getShapeClass:Lh,Group:Br,Image:Ns,Text:Xs,Circle:Su,Ellipse:Iu,Sector:Fu,Ring:Wu,Polygon:Xu,Polyline:Zu,Rect:Ws,Line:Ku,BezierCurve:th,Arc:nh,IncrementalDisplayable:dh,CompoundPath:ih,LinearGradient:oh,RadialGradient:ah,BoundingRect:ze}),Z_=Object.freeze({__proto__:null,addCommas:gp,toCamelCase:yp,normalizeCssArray:vp,encodeHTML:re,formatTpl:bp,getTooltipMarker:wp,formatTime:function(t,e,n){"week"!==t&&"month"!==t&&"quarter"!==t&&"half-year"!==t&&"year"!==t||(t="MM-dd\nyyyy");var i=uo(e),r=n?"getUTC":"get",o=i[r+"FullYear"](),a=i[r+"Month"]()+1,s=i[r+"Date"](),l=i[r+"Hours"](),u=i[r+"Minutes"](),h=i[r+"Seconds"](),c=i[r+"Milliseconds"]();return t=t.replace("MM",qc(a,2)).replace("M",a).replace("yyyy",o).replace("yy",qc(o%100+"",2)).replace("dd",qc(s,2)).replace("d",s).replace("hh",qc(l,2)).replace("h",l).replace("mm",qc(u,2)).replace("m",u).replace("ss",qc(h,2)).replace("s",h).replace("SSS",qc(c,3))},capitalFirst:function(t){return t?t.charAt(0).toUpperCase()+t.substr(1):t},truncateText:pa,getTextRect:function(t,e,n,i,r,o,a,s){return new Xs({style:{text:t,font:e,align:n,verticalAlign:i,padding:r,rich:o,overflow:a?"truncate":null,lineHeight:s}}).getBoundingRect()}}),j_=Object.freeze({__proto__:null,map:z,each:E,indexOf:P,inherits:O,reduce:V,filter:B,bind:W,curry:H,isArray:Y,isString:U,isObject:q,isFunction:X,extend:A,defaults:k,clone:T,merge:C}),q_=Vo();function K_(t,e){var n=z(e,(function(e){return t.scale.parse(e)}));return"time"===t.type&&n.length>0&&(n.sort(),n.unshift(n[0]),n.push(n[n.length-1])),n}function $_(t){var e=t.getLabelModel().get("customValues");if(e){var n=w_(t);return{labels:K_(t,e).map((function(e){var i={value:e};return{formattedLabel:n(i),rawLabel:t.scale.getLabel(i),tickValue:e}}))}}return"category"===t.type?function(t){var e=t.getLabelModel(),n=Q_(t,e);return!e.get("show")||t.scale.isBlank()?{labels:[],labelCategoryInterval:n.labelCategoryInterval}:n}(t):function(t){var e=t.scale.getTicks(),n=w_(t);return{labels:z(e,(function(e,i){return{level:e.level,formattedLabel:n(e,i),rawLabel:t.scale.getLabel(e),tickValue:e.value}}))}}(t)}function J_(t,e){var n=t.getTickModel().get("customValues");return n?{ticks:K_(t,n)}:"category"===t.type?function(t,e){var n,i,r=tb(t,"ticks"),o=I_(e),a=eb(r,o);if(a)return a;e.get("show")&&!t.scale.isBlank()||(n=[]);if(X(o))n=rb(t,o,!0);else if("auto"===o){var s=Q_(t,t.getLabelModel());i=s.labelCategoryInterval,n=z(s.labels,(function(t){return t.tickValue}))}else n=ib(t,i=o,!0);return nb(r,o,{ticks:n,tickCategoryInterval:i})}(t,e):{ticks:z(t.scale.getTicks(),(function(t){return t.value}))}}function Q_(t,e){var n,i,r=tb(t,"labels"),o=I_(e),a=eb(r,o);return a||(X(o)?n=rb(t,o):(i="auto"===o?function(t){var e=q_(t).autoInterval;return null!=e?e:q_(t).autoInterval=t.calculateCategoryInterval()}(t):o,n=ib(t,i)),nb(r,o,{labels:n,labelCategoryInterval:i}))}function tb(t,e){return q_(t)[e]||(q_(t)[e]=[])}function eb(t,e){for(var n=0;n1&&h/l>2&&(u=Math.round(Math.ceil(u/l)*l));var c=T_(t),p=a.get("showMinLabel")||c,d=a.get("showMaxLabel")||c;p&&u!==o[0]&&g(o[0]);for(var f=u;f<=o[1];f+=l)g(f);function g(t){var e={value:t};s.push(n?t:{formattedLabel:i(e),rawLabel:r.getLabel(e),tickValue:t})}return d&&f-l!==o[1]&&g(o[1]),s}function rb(t,e,n){var i=t.scale,r=w_(t),o=[];return E(i.getTicks(),(function(t){var a=i.getLabel(t),s=t.value;e(t.value,a)&&o.push(n?s:{formattedLabel:r(t),rawLabel:a,tickValue:s})})),o}var ob=[0,1],ab=function(){function t(t,e,n){this.onBand=!1,this.inverse=!1,this.dim=t,this.scale=e,this._extent=n||[0,0]}return t.prototype.contain=function(t){var e=this._extent,n=Math.min(e[0],e[1]),i=Math.max(e[0],e[1]);return t>=n&&t<=i},t.prototype.containData=function(t){return this.scale.contain(t)},t.prototype.getExtent=function(){return this._extent.slice()},t.prototype.getPixelPrecision=function(t){return no(t||this.scale.getExtent(),this._extent)},t.prototype.setExtent=function(t,e){var n=this._extent;n[0]=t,n[1]=e},t.prototype.dataToCoord=function(t,e){var n=this._extent,i=this.scale;return t=i.normalize(t),this.onBand&&"ordinal"===i.type&&sb(n=n.slice(),i.count()),Kr(t,ob,n,e)},t.prototype.coordToData=function(t,e){var n=this._extent,i=this.scale;this.onBand&&"ordinal"===i.type&&sb(n=n.slice(),i.count());var r=Kr(t,n,ob,e);return this.scale.scale(r)},t.prototype.pointToData=function(t,e){},t.prototype.getTicksCoords=function(t){var e=(t=t||{}).tickModel||this.getTickModel(),n=z(J_(this,e).ticks,(function(t){return{coord:this.dataToCoord("ordinal"===this.scale.type?this.scale.getRawOrdinalNumber(t):t),tickValue:t}}),this);return function(t,e,n,i){var r=e.length;if(!t.onBand||n||!r)return;var o,a,s=t.getExtent();if(1===r)e[0].coord=s[0],o=e[1]={coord:s[1]};else{var l=e[r-1].tickValue-e[0].tickValue,u=(e[r-1].coord-e[0].coord)/l;E(e,(function(t){t.coord-=u/2})),a=1+t.scale.getExtent()[1]-e[r-1].tickValue,o={coord:e[r-1].coord+u*a},e.push(o)}var h=s[0]>s[1];c(e[0].coord,s[0])&&(i?e[0].coord=s[0]:e.shift());i&&c(s[0],e[0].coord)&&e.unshift({coord:s[0]});c(s[1],o.coord)&&(i?o.coord=s[1]:e.pop());i&&c(o.coord,s[1])&&e.push({coord:s[1]});function c(t,e){return t=Jr(t),e=Jr(e),h?t>e:t0&&t<100||(t=5),z(this.scale.getMinorTicks(t),(function(t){return z(t,(function(t){return{coord:this.dataToCoord(t),tickValue:t}}),this)}),this)},t.prototype.getViewLabels=function(){return $_(this).labels},t.prototype.getLabelModel=function(){return this.model.getModel("axisLabel")},t.prototype.getTickModel=function(){return this.model.getModel("axisTick")},t.prototype.getBandWidth=function(){var t=this._extent,e=this.scale.getExtent(),n=e[1]-e[0]+(this.onBand?1:0);0===n&&(n=1);var i=Math.abs(t[1]-t[0]);return Math.abs(i)/n},t.prototype.calculateCategoryInterval=function(){return function(t){var e=function(t){var e=t.getLabelModel();return{axisRotate:t.getRotate?t.getRotate():t.isHorizontal&&!t.isHorizontal()?90:0,labelRotate:e.get("rotate")||0,font:e.getFont()}}(t),n=w_(t),i=(e.axisRotate-e.labelRotate)/180*Math.PI,r=t.scale,o=r.getExtent(),a=r.count();if(o[1]-o[0]<1)return 0;var s=1;a>40&&(s=Math.max(1,Math.floor(a/40)));for(var l=o[0],u=t.dataToCoord(l+1)-t.dataToCoord(l),h=Math.abs(u*Math.cos(i)),c=Math.abs(u*Math.sin(i)),p=0,d=0;l<=o[1];l+=s){var f,g,y=Sr(n({value:l}),e.font,"center","top");f=1.3*y.width,g=1.3*y.height,p=Math.max(p,f,7),d=Math.max(d,g,7)}var v=p/h,m=d/c;isNaN(v)&&(v=1/0),isNaN(m)&&(m=1/0);var x=Math.max(0,Math.floor(Math.min(v,m))),_=q_(t.model),b=t.getExtent(),w=_.lastAutoInterval,S=_.lastTickCount;return null!=w&&null!=S&&Math.abs(w-x)<=1&&Math.abs(S-a)<=1&&w>x&&_.axisExtent0===b[0]&&_.axisExtent1===b[1]?x=w:(_.lastTickCount=a,_.lastAutoInterval=x,_.axisExtent0=b[0],_.axisExtent1=b[1]),x}(this)},t}();function sb(t,e){var n=(t[1]-t[0])/e/2;t[0]+=n,t[1]-=n}var lb=2*Math.PI,ub=hs.CMD,hb=["top","right","bottom","left"];function cb(t,e,n,i,r){var o=n.width,a=n.height;switch(t){case"top":i.set(n.x+o/2,n.y-e),r.set(0,-1);break;case"bottom":i.set(n.x+o/2,n.y+a+e),r.set(0,1);break;case"left":i.set(n.x-e,n.y+a/2),r.set(-1,0);break;case"right":i.set(n.x+o+e,n.y+a/2),r.set(1,0)}}function pb(t,e,n,i,r,o,a,s,l){a-=t,s-=e;var u=Math.sqrt(a*a+s*s),h=(a/=u)*n+t,c=(s/=u)*n+e;if(Math.abs(i-r)%lb<1e-4)return l[0]=h,l[1]=c,u-n;if(o){var p=i;i=gs(r),r=gs(p)}else i=gs(i),r=gs(r);i>r&&(r+=lb);var d=Math.atan2(s,a);if(d<0&&(d+=lb),d>=i&&d<=r||d+lb>=i&&d+lb<=r)return l[0]=h,l[1]=c,u-n;var f=n*Math.cos(i)+t,g=n*Math.sin(i)+e,y=n*Math.cos(r)+t,v=n*Math.sin(r)+e,m=(f-a)*(f-a)+(g-s)*(g-s),x=(y-a)*(y-a)+(v-s)*(v-s);return m0){e=e/180*Math.PI,mb.fromArray(t[0]),xb.fromArray(t[1]),_b.fromArray(t[2]),De.sub(bb,mb,xb),De.sub(wb,_b,xb);var n=bb.len(),i=wb.len();if(!(n<.001||i<.001)){bb.scale(1/n),wb.scale(1/i);var r=bb.dot(wb);if(Math.cos(e)1&&De.copy(Ib,_b),Ib.toArray(t[1])}}}}function Cb(t,e,n){if(n<=180&&n>0){n=n/180*Math.PI,mb.fromArray(t[0]),xb.fromArray(t[1]),_b.fromArray(t[2]),De.sub(bb,xb,mb),De.sub(wb,_b,xb);var i=bb.len(),r=wb.len();if(!(i<.001||r<.001))if(bb.scale(1/i),wb.scale(1/r),bb.dot(e)=a)De.copy(Ib,_b);else{Ib.scaleAndAdd(wb,o/Math.tan(Math.PI/2-s));var l=_b.x!==xb.x?(Ib.x-xb.x)/(_b.x-xb.x):(Ib.y-xb.y)/(_b.y-xb.y);if(isNaN(l))return;l<0?De.copy(Ib,xb):l>1&&De.copy(Ib,_b)}Ib.toArray(t[1])}}}function Db(t,e,n,i){var r="normal"===n,o=r?t:t.ensureState(n);o.ignore=e;var a=i.get("smooth");a&&!0===a&&(a=.3),o.shape=o.shape||{},a>0&&(o.shape.smooth=a);var s=i.getModel("lineStyle").getLineStyle();r?t.useStyle(s):o.style=s}function Ab(t,e){var n=e.smooth,i=e.points;if(i)if(t.moveTo(i[0][0],i[0][1]),n>0&&i.length>=3){var r=Vt(i[0],i[1]),o=Vt(i[1],i[2]);if(!r||!o)return t.lineTo(i[1][0],i[1][1]),void t.lineTo(i[2][0],i[2][1]);var a=Math.min(r,o)*n,s=Gt([],i[1],i[0],a/r),l=Gt([],i[1],i[2],a/o),u=Gt([],s,l,.5);t.bezierCurveTo(s[0],s[1],s[0],s[1],u[0],u[1]),t.bezierCurveTo(l[0],l[1],l[0],l[1],i[2][0],i[2][1])}else for(var h=1;h0&&o&&_(-h/a,0,a);var f,g,y=t[0],v=t[a-1];return m(),f<0&&b(-f,.8),g<0&&b(g,.8),m(),x(f,g,1),x(g,f,-1),m(),f<0&&w(-f),g<0&&w(g),u}function m(){f=y.rect[e]-i,g=r-v.rect[e]-v.rect[n]}function x(t,e,n){if(t<0){var i=Math.min(e,-t);if(i>0){_(i*n,0,a);var r=i+t;r<0&&b(-r*n,1)}else b(-t*n,1)}}function _(n,i,r){0!==n&&(u=!0);for(var o=i;o0)for(l=0;l0;l--){_(-(o[l-1]*c),l,a)}}}function w(t){var e=t<0?-1:1;t=Math.abs(t);for(var n=Math.ceil(t/(a-1)),i=0;i0?_(n,0,i+1):_(-n,a-i-1,a),(t-=n)<=0)return}}function Rb(t,e,n,i){return Ob(t,"y","height",e,n,i)}function Nb(t){var e=[];t.sort((function(t,e){return e.priority-t.priority}));var n=new ze(0,0,0,0);function i(t){if(!t.ignore){var e=t.ensureState("emphasis");null==e.ignore&&(e.ignore=!1)}t.ignore=!0}for(var r=0;r=0&&n.attr(d.oldLayoutSelect),P(u,"emphasis")>=0&&n.attr(d.oldLayoutEmphasis)),vh(n,s,e,a)}else if(n.attr(s),!pc(n).valueAnimation){var h=rt(n.style.opacity,1);n.style.opacity=0,mh(n,{style:{opacity:h}},e,a)}if(d.oldLayout=s,n.states.select){var c=d.oldLayoutSelect={};Wb(c,s,Hb),Wb(c,n.states.select,Hb)}if(n.states.emphasis){var p=d.oldLayoutEmphasis={};Wb(p,s,Hb),Wb(p,n.states.emphasis,Hb)}fc(n,a,l,e,e)}if(i&&!i.ignore&&!i.invisible){r=(d=Gb(i)).oldLayout;var d,f={points:i.shape.points};r?(i.attr({shape:r}),vh(i,{shape:f},e)):(i.setShape(f),i.style.strokePercent=0,mh(i,{style:{strokePercent:1}},e)),d.oldLayout=f}},t}(),Xb=Vo();var Ub=Math.sin,Zb=Math.cos,jb=Math.PI,qb=2*Math.PI,Kb=180/jb,$b=function(){function t(){}return t.prototype.reset=function(t){this._start=!0,this._d=[],this._str="",this._p=Math.pow(10,t||4)},t.prototype.moveTo=function(t,e){this._add("M",t,e)},t.prototype.lineTo=function(t,e){this._add("L",t,e)},t.prototype.bezierCurveTo=function(t,e,n,i,r,o){this._add("C",t,e,n,i,r,o)},t.prototype.quadraticCurveTo=function(t,e,n,i){this._add("Q",t,e,n,i)},t.prototype.arc=function(t,e,n,i,r,o){this.ellipse(t,e,n,n,0,i,r,o)},t.prototype.ellipse=function(t,e,n,i,r,o,a,s){var l=a-o,u=!s,h=Math.abs(l),c=pi(h-qb)||(u?l>=qb:-l>=qb),p=l>0?l%qb:l%qb+qb,d=!1;d=!!c||!pi(h)&&p>=jb==!!u;var f=t+n*Zb(o),g=e+i*Ub(o);this._start&&this._add("M",f,g);var y=Math.round(r*Kb);if(c){var v=1/this._p,m=(u?1:-1)*(qb-v);this._add("A",n,i,y,1,+u,t+n*Zb(o+m),e+i*Ub(o+m)),v>.01&&this._add("A",n,i,y,0,+u,f,g)}else{var x=t+n*Zb(a),_=e+i*Ub(a);this._add("A",n,i,y,+d,+u,x,_)}},t.prototype.rect=function(t,e,n,i){this._add("M",t,e),this._add("l",n,0),this._add("l",0,i),this._add("l",-n,0),this._add("Z")},t.prototype.closePath=function(){this._d.length>0&&this._add("Z")},t.prototype._add=function(t,e,n,i,r,o,a,s,l){for(var u=[],h=this._p,c=1;c"}(r,o)+("style"!==r?re(a):a||"")+(i?""+n+z(i,(function(e){return t(e)})).join(n)+n:"")+("")}(t)}function uw(t){return{zrId:t,shadowCache:{},patternCache:{},gradientCache:{},clipPathCache:{},defs:{},cssNodes:{},cssAnims:{},cssStyleCache:{},cssAnimIdx:0,shadowIdx:0,gradientIdx:0,patternIdx:0,clipPathIdx:0}}function hw(t,e,n,i){return sw("svg","root",{width:t,height:e,xmlns:iw,"xmlns:xlink":rw,version:"1.1",baseProfile:"full",viewBox:!!i&&"0 0 "+t+" "+e},n)}var cw=0;function pw(){return cw++}var dw={cubicIn:"0.32,0,0.67,0",cubicOut:"0.33,1,0.68,1",cubicInOut:"0.65,0,0.35,1",quadraticIn:"0.11,0,0.5,0",quadraticOut:"0.5,1,0.89,1",quadraticInOut:"0.45,0,0.55,1",quarticIn:"0.5,0,0.75,0",quarticOut:"0.25,1,0.5,1",quarticInOut:"0.76,0,0.24,1",quinticIn:"0.64,0,0.78,0",quinticOut:"0.22,1,0.36,1",quinticInOut:"0.83,0,0.17,1",sinusoidalIn:"0.12,0,0.39,0",sinusoidalOut:"0.61,1,0.88,1",sinusoidalInOut:"0.37,0,0.63,1",exponentialIn:"0.7,0,0.84,0",exponentialOut:"0.16,1,0.3,1",exponentialInOut:"0.87,0,0.13,1",circularIn:"0.55,0,1,0.45",circularOut:"0,0.55,0.45,1",circularInOut:"0.85,0,0.15,1"},fw="transform-origin";function gw(t,e,n){var i=A({},t.shape);A(i,e),t.buildPath(n,i);var r=new $b;return r.reset(wi(t)),n.rebuildPath(r,1),r.generateStr(),r.getStr()}function yw(t,e){var n=e.originX,i=e.originY;(n||i)&&(t[fw]=n+"px "+i+"px")}var vw={fill:"fill",opacity:"opacity",lineWidth:"stroke-width",lineDashOffset:"stroke-dashoffset"};function mw(t,e){var n=e.zrId+"-ani-"+e.cssAnimIdx++;return e.cssAnims[n]=t,n}function xw(t){return U(t)?dw[t]?"cubic-bezier("+dw[t]+")":Pn(t)?t:"":""}function _w(t,e,n,i){var r=t.animators,o=r.length,a=[];if(t instanceof ih){var s=function(t,e,n){var i,r,o=t.shape.paths,a={};if(E(o,(function(t){var e=uw(n.zrId);e.animation=!0,_w(t,{},e,!0);var o=e.cssAnims,s=e.cssNodes,l=G(o),u=l.length;if(u){var h=o[r=l[u-1]];for(var c in h){var p=h[c];a[c]=a[c]||{d:""},a[c].d+=p.d||""}for(var d in s){var f=s[d].animation;f.indexOf(r)>=0&&(i=f)}}})),i){e.d=!1;var s=mw(a,n);return i.replace(r,s)}}(t,e,n);if(s)a.push(s);else if(!o)return}else if(!o)return;for(var l={},u=0;u0})).length)return mw(h,n)+" "+r[0]+" both"}for(var y in l){(s=g(l[y]))&&a.push(s)}if(a.length){var v=n.zrId+"-cls-"+pw();n.cssNodes["."+v]={animation:a.join(",")},e.class=v}}function bw(t,e,n,i){var r=JSON.stringify(t),o=n.cssStyleCache[r];o||(o=n.zrId+"-cls-"+pw(),n.cssStyleCache[r]=o,n.cssNodes["."+o+(i?":hover":"")]=t),e.class=e.class?e.class+" "+o:o}var ww=Math.round;function Sw(t){return t&&U(t.src)}function Mw(t){return t&&X(t.toDataURL)}function Iw(t,e,n,i){nw((function(r,o){var a="fill"===r||"stroke"===r;a&&_i(o)?Ew(e,t,r,i):a&&vi(o)?zw(n,t,r,i):t[r]=a&&"none"===o?"transparent":o}),e,n,!1),function(t,e,n){var i=t.style;if(function(t){return t&&(t.shadowBlur||t.shadowOffsetX||t.shadowOffsetY)}(i)){var r=function(t){var e=t.style,n=t.getGlobalScale();return[e.shadowColor,(e.shadowBlur||0).toFixed(2),(e.shadowOffsetX||0).toFixed(2),(e.shadowOffsetY||0).toFixed(2),n[0],n[1]].join(",")}(t),o=n.shadowCache,a=o[r];if(!a){var s=t.getGlobalScale(),l=s[0],u=s[1];if(!l||!u)return;var h=i.shadowOffsetX||0,c=i.shadowOffsetY||0,p=i.shadowBlur,d=hi(i.shadowColor),f=d.opacity,g=d.color,y=p/2/l+" "+p/2/u;a=n.zrId+"-s"+n.shadowIdx++,n.defs[a]=sw("filter",a,{id:a,x:"-100%",y:"-100%",width:"300%",height:"300%"},[sw("feDropShadow","",{dx:h/l,dy:c/u,stdDeviation:y,"flood-color":g,"flood-opacity":f})]),o[r]=a}e.filter=bi(a)}}(n,t,i)}function Tw(t,e){var n=Ur(e);n&&(n.each((function(e,n){null!=e&&(t[(ow+n).toLowerCase()]=e+"")})),e.isSilent()&&(t[ow+"silent"]="true"))}function Cw(t){return pi(t[0]-1)&&pi(t[1])&&pi(t[2])&&pi(t[3]-1)}function Dw(t,e,n){if(e&&(!function(t){return pi(t[4])&&pi(t[5])}(e)||!Cw(e))){var i=n?10:1e4;t.transform=Cw(e)?"translate("+ww(e[4]*i)/i+" "+ww(e[5]*i)/i+")":function(t){return"matrix("+di(t[0])+","+di(t[1])+","+di(t[2])+","+di(t[3])+","+fi(t[4])+","+fi(t[5])+")"}(e)}}function Aw(t,e,n){for(var i=t.points,r=[],o=0;o=0&&a||o;s&&(r=si(s))}var l=i.lineWidth;l&&(l/=!i.strokeNoScale&&t.transform?t.transform[0]:1);var u={cursor:"pointer"};r&&(u.fill=r),i.stroke&&(u.stroke=i.stroke),l&&(u["stroke-width"]=l),bw(u,e,n,!0)}}(t,o,e),sw(s,t.id+"",o)}function Nw(t,e){return t instanceof ks?Rw(t,e):t instanceof Ns?function(t,e){var n=t.style,i=n.image;if(i&&!U(i)&&(Sw(i)?i=i.src:Mw(i)&&(i=i.toDataURL())),i){var r=n.x||0,o=n.y||0,a={href:i,width:n.width,height:n.height};return r&&(a.x=r),o&&(a.y=o),Dw(a,t.transform),Iw(a,n,t,e),Tw(a,t),e.animation&&_w(t,a,e),sw("image",t.id+"",a)}}(t,e):t instanceof Ps?function(t,e){var n=t.style,i=n.text;if(null!=i&&(i+=""),i&&!isNaN(n.x)&&!isNaN(n.y)){var r=n.font||a,s=n.x||0,l=function(t,e,n){return"top"===n?t+=e/2:"bottom"===n&&(t-=e/2),t}(n.y||0,Tr(r),n.textBaseline),u={"dominant-baseline":"central","text-anchor":gi[n.textAlign]||n.textAlign};if($s(n)){var h="",c=n.fontStyle,p=qs(n.fontSize);if(!parseFloat(p))return;var d=n.fontFamily||o,f=n.fontWeight;h+="font-size:"+p+";font-family:"+d+";",c&&"normal"!==c&&(h+="font-style:"+c+";"),f&&"normal"!==f&&(h+="font-weight:"+f+";"),u.style=h}else u.style="font: "+r;return i.match(/\s/)&&(u["xml:space"]="preserve"),s&&(u.x=s),l&&(u.y=l),Dw(u,t.transform),Iw(u,n,t,e),Tw(u,t),e.animation&&_w(t,u,e),sw("text",t.id+"",u,void 0,i)}}(t,e):void 0}function Ew(t,e,n,i){var r,o=t[n],a={gradientUnits:o.global?"userSpaceOnUse":"objectBoundingBox"};if(mi(o))r="linearGradient",a.x1=o.x,a.y1=o.y,a.x2=o.x2,a.y2=o.y2;else{if(!xi(o))return void 0;r="radialGradient",a.cx=rt(o.x,.5),a.cy=rt(o.y,.5),a.r=rt(o.r,.5)}for(var s=o.colorStops,l=[],u=0,h=s.length;ul?Jw(t,null==n[c+1]?null:n[c+1].elm,n,s,c):Qw(t,e,a,l))}(n,i,r):jw(r)?(jw(t.text)&&Xw(n,""),Jw(n,null,r,0,r.length-1)):jw(i)?Qw(n,i,0,i.length-1):jw(t.text)&&Xw(n,""):t.text!==e.text&&(jw(i)&&Qw(n,i,0,i.length-1),Xw(n,e.text)))}var nS=0,iS=function(){function t(t,e,n){if(this.type="svg",this.refreshHover=rS("refreshHover"),this.configLayer=rS("configLayer"),this.storage=e,this._opts=n=A({},n),this.root=t,this._id="zr"+nS++,this._oldVNode=hw(n.width,n.height),t&&!n.ssr){var i=this._viewport=document.createElement("div");i.style.cssText="position:relative;overflow:hidden";var r=this._svgDom=this._oldVNode.elm=aw("svg");tS(null,this._oldVNode),i.appendChild(r),t.appendChild(i)}this.resize(n.width,n.height)}return t.prototype.getType=function(){return this.type},t.prototype.getViewportRoot=function(){return this._viewport},t.prototype.getViewportRootOffset=function(){var t=this.getViewportRoot();if(t)return{offsetLeft:t.offsetLeft||0,offsetTop:t.offsetTop||0}},t.prototype.getSvgDom=function(){return this._svgDom},t.prototype.refresh=function(){if(this.root){var t=this.renderToVNode({willUpdate:!0});t.attrs.style="position:absolute;left:0;top:0;user-select:none",function(t,e){if(Kw(t,e))eS(t,e);else{var n=t.elm,i=Hw(n);$w(e),null!==i&&(Fw(i,e.elm,Yw(n)),Qw(i,[t],0,0))}}(this._oldVNode,t),this._oldVNode=t}},t.prototype.renderOneToVNode=function(t){return Nw(t,uw(this._id))},t.prototype.renderToVNode=function(t){t=t||{};var e=this.storage.getDisplayList(!0),n=this._width,i=this._height,r=uw(this._id);r.animation=t.animation,r.willUpdate=t.willUpdate,r.compress=t.compress,r.emphasis=t.emphasis;var o=[],a=this._bgVNode=function(t,e,n,i){var r;if(n&&"none"!==n)if(r=sw("rect","bg",{width:t,height:e,x:"0",y:"0"}),_i(n))Ew({fill:n},r.attrs,"fill",i);else if(vi(n))zw({style:{fill:n},dirty:bt,getBoundingRect:function(){return{width:t,height:e}}},r.attrs,"fill",i);else{var o=hi(n),a=o.color,s=o.opacity;r.attrs.fill=a,s<1&&(r.attrs["fill-opacity"]=s)}return r}(n,i,this._backgroundColor,r);a&&o.push(a);var s=t.compress?null:this._mainVNode=sw("g","main",{},[]);this._paintList(e,r,s?s.children:o),s&&o.push(s);var l=z(G(r.defs),(function(t){return r.defs[t]}));if(l.length&&o.push(sw("defs","defs",{},l)),t.animation){var u=function(t,e,n){var i=(n=n||{}).newline?"\n":"",r=" {"+i,o=i+"}",a=z(G(t),(function(e){return e+r+z(G(t[e]),(function(n){return n+":"+t[e][n]+";"})).join(i)+o})).join(i),s=z(G(e),(function(t){return"@keyframes "+t+r+z(G(e[t]),(function(n){return n+r+z(G(e[t][n]),(function(i){var r=e[t][n][i];return"d"===i&&(r='path("'+r+'")'),i+":"+r+";"})).join(i)+o})).join(i)+o})).join(i);return a||s?[""].join(i):""}(r.cssNodes,r.cssAnims,{newline:!0});if(u){var h=sw("style","stl",{},[],u);o.push(h)}}return hw(n,i,o,t.useViewBox)},t.prototype.renderToString=function(t){return t=t||{},lw(this.renderToVNode({animation:rt(t.cssAnimation,!0),emphasis:rt(t.cssEmphasis,!0),willUpdate:!1,compress:!0,useViewBox:rt(t.useViewBox,!0)}),{newline:!0})},t.prototype.setBackgroundColor=function(t){this._backgroundColor=t},t.prototype.getSvgRoot=function(){return this._mainVNode&&this._mainVNode.elm},t.prototype._paintList=function(t,e,n){for(var i,r,o=t.length,a=[],s=0,l=0,u=0;u=0&&(!c||!r||c[f]!==r[f]);f--);for(var g=d-1;g>f;g--)i=a[--s-1];for(var y=f+1;y=a)}}for(var h=this.__startIndex;h15)break}n.prevElClipPaths&&u.restore()};if(p)if(0===p.length)s=l.__endIndex;else for(var _=d.dpr,b=0;b0&&t>i[0]){for(s=0;st);s++);a=n[i[s]]}if(i.splice(s+1,0,t),n[t]=e,!e.virtual)if(a){var l=a.dom;l.nextSibling?o.insertBefore(e.dom,l.nextSibling):o.appendChild(e.dom)}else o.firstChild?o.insertBefore(e.dom,o.firstChild):o.appendChild(e.dom);e.painter||(e.painter=this)}},t.prototype.eachLayer=function(t,e){for(var n=this._zlevelList,i=0;i0?uS:0),this._needsManuallyCompositing),u.__builtin__||I("ZLevel "+l+" has been used by unkown layer "+u.id),u!==o&&(u.__used=!0,u.__startIndex!==r&&(u.__dirty=!0),u.__startIndex=r,u.incremental?u.__drawIndex=-1:u.__drawIndex=r,e(r),o=u),1&s.__dirty&&!s.__inHover&&(u.__dirty=!0,u.incremental&&u.__drawIndex<0&&(u.__drawIndex=r))}e(r),this.eachBuiltinLayer((function(t,e){!t.__used&&t.getElementCount()>0&&(t.__dirty=!0,t.__startIndex=t.__endIndex=t.__drawIndex=0),t.__dirty&&t.__drawIndex<0&&(t.__drawIndex=t.__startIndex)}))},t.prototype.clear=function(){return this.eachBuiltinLayer(this._clearLayer),this},t.prototype._clearLayer=function(t){t.clear()},t.prototype.setBackgroundColor=function(t){this._backgroundColor=t,E(this._layers,(function(t){t.setUnpainted()}))},t.prototype.configLayer=function(t,e){if(e){var n=this._layerConfig;n[t]?C(n[t],e,!0):n[t]=e;for(var i=0;i-1&&(s.style.stroke=s.style.fill,s.style.fill="#fff",s.style.lineWidth=2),e},e.type="series.line",e.dependencies=["grid","polar"],e.defaultOption={z:3,coordinateSystem:"cartesian2d",legendHoverLink:!0,clip:!0,label:{position:"top"},endLabel:{show:!1,valueAnimation:!0,distance:8},lineStyle:{width:2,type:"solid"},emphasis:{scale:!0},step:!1,smooth:!1,smoothMonotone:null,symbol:"emptyCircle",symbolSize:4,symbolRotate:null,showSymbol:!0,showAllSymbol:"auto",connectNulls:!1,sampling:"none",animationEasing:"linear",progressive:0,hoverLayerThreshold:1/0,universalTransition:{divideShape:"clone"},triggerLineEvent:!1},e}(bg);function pS(t,e){var n=t.mapDimensionsAll("defaultedLabel"),i=n.length;if(1===i){var r=mf(t,e,n[0]);return null!=r?r+"":null}if(i){for(var o=[],a=0;a=0&&i.push(e[o])}return i.join(" ")}var fS=function(t){function e(e,n,i,r){var o=t.call(this)||this;return o.updateData(e,n,i,r),o}return n(e,t),e.prototype._createSymbol=function(t,e,n,i,r){this.removeAll();var o=Xy(t,-1,-1,2,2,null,r);o.attr({z2:100,culling:!0,scaleX:i[0]/2,scaleY:i[1]/2}),o.drift=gS,this._symbolType=t,this.add(o)},e.prototype.stopSymbolAnimation=function(t){this.childAt(0).stopAnimation(null,t)},e.prototype.getSymbolType=function(){return this._symbolType},e.prototype.getSymbolPath=function(){return this.childAt(0)},e.prototype.highlight=function(){Ol(this.childAt(0))},e.prototype.downplay=function(){Rl(this.childAt(0))},e.prototype.setZ=function(t,e){var n=this.childAt(0);n.zlevel=t,n.z=e},e.prototype.setDraggable=function(t,e){var n=this.childAt(0);n.draggable=t,n.cursor=!e&&t?"move":n.cursor},e.prototype.updateData=function(t,n,i,r){this.silent=!1;var o=t.getItemVisual(n,"symbol")||"circle",a=t.hostModel,s=e.getSymbolSize(t,n),l=o!==this._symbolType,u=r&&r.disableAnimation;if(l){var h=t.getItemVisual(n,"symbolKeepAspect");this._createSymbol(o,t,n,s,h)}else{(p=this.childAt(0)).silent=!1;var c={scaleX:s[0]/2,scaleY:s[1]/2};u?p.attr(c):vh(p,c,a,n),Sh(p)}if(this._updateCommon(t,n,s,i,r),l){var p=this.childAt(0);if(!u){c={scaleX:this._sizeX,scaleY:this._sizeY,style:{opacity:p.style.opacity}};p.scaleX=p.scaleY=0,p.style.opacity=0,mh(p,c,a,n)}}u&&this.childAt(0).stopAnimation("leave")},e.prototype._updateCommon=function(t,e,n,i,r){var o,a,s,l,u,h,c,p,d,f=this.childAt(0),g=t.hostModel;if(i&&(o=i.emphasisItemStyle,a=i.blurItemStyle,s=i.selectItemStyle,l=i.focus,u=i.blurScope,c=i.labelStatesModels,p=i.hoverScale,d=i.cursorStyle,h=i.emphasisDisabled),!i||t.hasItemOption){var y=i&&i.itemModel?i.itemModel:t.getItemModel(e),v=y.getModel("emphasis");o=v.getModel("itemStyle").getItemStyle(),s=y.getModel(["select","itemStyle"]).getItemStyle(),a=y.getModel(["blur","itemStyle"]).getItemStyle(),l=v.get("focus"),u=v.get("blurScope"),h=v.get("disabled"),c=rc(y),p=v.getShallow("scale"),d=y.getShallow("cursor")}var m=t.getItemVisual(e,"symbolRotate");f.attr("rotation",(m||0)*Math.PI/180||0);var x=Zy(t.getItemVisual(e,"symbolOffset"),n);x&&(f.x=x[0],f.y=x[1]),d&&f.attr("cursor",d);var _=t.getItemVisual(e,"style"),b=_.fill;if(f instanceof Ns){var w=f.style;f.useStyle(A({image:w.image,x:w.x,y:w.y,width:w.width,height:w.height},_))}else f.__isEmptyBrush?f.useStyle(A({},_)):f.useStyle(_),f.style.decal=null,f.setColor(b,r&&r.symbolInnerColor),f.style.strokeNoScale=!0;var S=t.getItemVisual(e,"liftZ"),M=this._z2;null!=S?null==M&&(this._z2=f.z2,f.z2+=S):null!=M&&(f.z2=M,this._z2=null);var I=r&&r.useNameLabel;ic(f,c,{labelFetcher:g,labelDataIndex:e,defaultText:function(e){return I?t.getName(e):pS(t,e)},inheritColor:b,defaultOpacity:_.opacity}),this._sizeX=n[0]/2,this._sizeY=n[1]/2;var T=f.ensureState("emphasis");T.style=o,f.ensureState("select").style=s,f.ensureState("blur").style=a;var C=null==p||!0===p?Math.max(1.1,3/this._sizeY):isFinite(p)&&p>0?+p:1;T.scaleX=this._sizeX*C,T.scaleY=this._sizeY*C,this.setSymbolScale(1),Zl(this,l,u,h)},e.prototype.setSymbolScale=function(t){this.scaleX=this.scaleY=t},e.prototype.fadeOut=function(t,e,n){var i=this.childAt(0),r=rl(this).dataIndex,o=n&&n.animation;if(this.silent=i.silent=!0,n&&n.fadeLabel){var a=i.getTextContent();a&&_h(a,{style:{opacity:0}},e,{dataIndex:r,removeOpt:o,cb:function(){i.removeTextContent()}})}else i.removeTextContent();_h(i,{style:{opacity:0},scaleX:0,scaleY:0},e,{dataIndex:r,cb:t,removeOpt:o})},e.getSymbolSize=function(t,e){return Uy(t.getItemVisual(e,"symbolSize"))},e}(Br);function gS(t,e){this.parent.drift(t,e)}function yS(t,e,n,i){return e&&!isNaN(e[0])&&!isNaN(e[1])&&!(i.isIgnore&&i.isIgnore(n))&&!(i.clipShape&&!i.clipShape.contain(e[0],e[1]))&&"none"!==t.getItemVisual(n,"symbol")}function vS(t){return null==t||q(t)||(t={isIgnore:t}),t||{}}function mS(t){var e=t.hostModel,n=e.getModel("emphasis");return{emphasisItemStyle:n.getModel("itemStyle").getItemStyle(),blurItemStyle:e.getModel(["blur","itemStyle"]).getItemStyle(),selectItemStyle:e.getModel(["select","itemStyle"]).getItemStyle(),focus:n.get("focus"),blurScope:n.get("blurScope"),emphasisDisabled:n.get("disabled"),hoverScale:n.get("scale"),labelStatesModels:rc(e),cursorStyle:e.get("cursor")}}var xS=function(){function t(t){this.group=new Br,this._SymbolCtor=t||fS}return t.prototype.updateData=function(t,e){this._progressiveEls=null,e=vS(e);var n=this.group,i=t.hostModel,r=this._data,o=this._SymbolCtor,a=e.disableAnimation,s=mS(t),l={disableAnimation:a},u=e.getSymbolPoint||function(e){return t.getItemLayout(e)};r||n.removeAll(),t.diff(r).add((function(i){var r=u(i);if(yS(t,r,i,e)){var a=new o(t,i,s,l);a.setPosition(r),t.setItemGraphicEl(i,a),n.add(a)}})).update((function(h,c){var p=r.getItemGraphicEl(c),d=u(h);if(yS(t,d,h,e)){var f=t.getItemVisual(h,"symbol")||"circle",g=p&&p.getSymbolType&&p.getSymbolType();if(!p||g&&g!==f)n.remove(p),(p=new o(t,h,s,l)).setPosition(d);else{p.updateData(t,h,s,l);var y={x:d[0],y:d[1]};a?p.attr(y):vh(p,y,i)}n.add(p),t.setItemGraphicEl(h,p)}else n.remove(p)})).remove((function(t){var e=r.getItemGraphicEl(t);e&&e.fadeOut((function(){n.remove(e)}),i)})).execute(),this._getSymbolPoint=u,this._data=t},t.prototype.updateLayout=function(){var t=this,e=this._data;e&&e.eachItemGraphicEl((function(e,n){var i=t._getSymbolPoint(n);e.setPosition(i),e.markRedraw()}))},t.prototype.incrementalPrepareUpdate=function(t){this._seriesScope=mS(t),this._data=null,this.group.removeAll()},t.prototype.incrementalUpdate=function(t,e,n){function i(t){t.isGroup||(t.incremental=!0,t.ensureState("emphasis").hoverLayer=!0)}this._progressiveEls=[],n=vS(n);for(var r=t.start;r0?n=i[0]:i[1]<0&&(n=i[1]);return n}(r,n),a=i.dim,s=r.dim,l=e.mapDimension(s),u=e.mapDimension(a),h="x"===s||"radius"===s?1:0,c=z(t.dimensions,(function(t){return e.mapDimension(t)})),p=!1,d=e.getCalculationInfo("stackResultDimension");return mx(e,c[0])&&(p=!0,c[0]=d),mx(e,c[1])&&(p=!0,c[1]=d),{dataDimsForPoint:c,valueStart:o,valueAxisDim:s,baseAxisDim:a,stacked:!!p,valueDim:l,baseDim:u,baseDataOffset:h,stackedOverDimension:e.getCalculationInfo("stackedOverDimension")}}function bS(t,e,n,i){var r=NaN;t.stacked&&(r=n.get(n.getCalculationInfo("stackedOverDimension"),i)),isNaN(r)&&(r=t.valueStart);var o=t.baseDataOffset,a=[];return a[o]=n.get(t.baseDim,i),a[1-o]=r,e.dataToPoint(a)}var wS=Math.min,SS=Math.max;function MS(t,e){return isNaN(t)||isNaN(e)}function IS(t,e,n,i,r,o,a,s,l){for(var u,h,c,p,d,f,g=n,y=0;y=r||g<0)break;if(MS(v,m)){if(l){g+=o;continue}break}if(g===n)t[o>0?"moveTo":"lineTo"](v,m),c=v,p=m;else{var x=v-u,_=m-h;if(x*x+_*_<.5){g+=o;continue}if(a>0){for(var b=g+o,w=e[2*b],S=e[2*b+1];w===v&&S===m&&y=i||MS(w,S))d=v,f=m;else{T=w-u,C=S-h;var k=v-u,L=w-v,P=m-h,O=S-m,R=void 0,N=void 0;if("x"===s){var E=T>0?1:-1;d=v-E*(R=Math.abs(k))*a,f=m,D=v+E*(N=Math.abs(L))*a,A=m}else if("y"===s){var z=C>0?1:-1;d=v,f=m-z*(R=Math.abs(P))*a,D=v,A=m+z*(N=Math.abs(O))*a}else R=Math.sqrt(k*k+P*P),d=v-T*a*(1-(I=(N=Math.sqrt(L*L+O*O))/(N+R))),f=m-C*a*(1-I),A=m+C*a*I,D=wS(D=v+T*a*I,SS(w,v)),A=wS(A,SS(S,m)),D=SS(D,wS(w,v)),f=m-(C=(A=SS(A,wS(S,m)))-m)*R/N,d=wS(d=v-(T=D-v)*R/N,SS(u,v)),f=wS(f,SS(h,m)),D=v+(T=v-(d=SS(d,wS(u,v))))*N/R,A=m+(C=m-(f=SS(f,wS(h,m))))*N/R}t.bezierCurveTo(c,p,d,f,v,m),c=D,p=A}else t.lineTo(v,m)}u=v,h=m,g+=o}return y}var TS=function(){this.smooth=0,this.smoothConstraint=!0},CS=function(t){function e(e){var n=t.call(this,e)||this;return n.type="ec-polyline",n}return n(e,t),e.prototype.getDefaultStyle=function(){return{stroke:"#000",fill:null}},e.prototype.getDefaultShape=function(){return new TS},e.prototype.buildPath=function(t,e){var n=e.points,i=0,r=n.length/2;if(e.connectNulls){for(;r>0&&MS(n[2*r-2],n[2*r-1]);r--);for(;i=0){var y=a?(h-i)*g+i:(u-n)*g+n;return a?[t,y]:[y,t]}n=u,i=h;break;case o.C:u=r[l++],h=r[l++],c=r[l++],p=r[l++],d=r[l++],f=r[l++];var v=a?_n(n,u,c,d,t,s):_n(i,h,p,f,t,s);if(v>0)for(var m=0;m=0){y=a?mn(i,h,p,f,x):mn(n,u,c,d,x);return a?[t,y]:[y,t]}}n=d,i=f}}},e}(ks),DS=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e}(TS),AS=function(t){function e(e){var n=t.call(this,e)||this;return n.type="ec-polygon",n}return n(e,t),e.prototype.getDefaultShape=function(){return new DS},e.prototype.buildPath=function(t,e){var n=e.points,i=e.stackedOnPoints,r=0,o=n.length/2,a=e.smoothMonotone;if(e.connectNulls){for(;o>0&&MS(n[2*o-2],n[2*o-1]);o--);for(;r=0;a--){var s=t.getDimensionInfo(i[a].dimension);if("x"===(r=s&&s.coordDim)||"y"===r){o=i[a];break}}if(o){var l=e.getAxis(r),u=z(o.stops,(function(t){return{coord:l.toGlobalCoord(l.dataToCoord(t.value)),color:t.color}})),h=u.length,c=o.outerColors.slice();h&&u[0].coord>u[h-1].coord&&(u.reverse(),c.reverse());var p=function(t,e){var n,i,r=[],o=t.length;function a(t,e,n){var i=t.coord;return{coord:n,color:ti((n-i)/(e.coord-i),[t.color,e.color])}}for(var s=0;se){i?r.push(a(i,l,e)):n&&r.push(a(n,l,0),a(n,l,e));break}n&&(r.push(a(n,l,0)),n=null),r.push(l),i=l}}return r}(u,"x"===r?n.getWidth():n.getHeight()),d=p.length;if(!d&&h)return u[0].coord<0?c[1]?c[1]:u[h-1].color:c[0]?c[0]:u[0].color;var f=p[0].coord-10,g=p[d-1].coord+10,y=g-f;if(y<.001)return"transparent";E(p,(function(t){t.offset=(t.coord-f)/y})),p.push({offset:d?p[d-1].offset:.5,color:c[1]||"transparent"}),p.unshift({offset:d?p[0].offset:.5,color:c[0]||"transparent"});var v=new oh(0,0,0,0,p,!0);return v[r]=f,v[r+"2"]=g,v}}}function FS(t,e,n){var i=t.get("showAllSymbol"),r="auto"===i;if(!i||r){var o=n.getAxesByScale("ordinal")[0];if(o&&(!r||!function(t,e){var n=t.getExtent(),i=Math.abs(n[1]-n[0])/t.scale.count();isNaN(i)&&(i=0);for(var r=e.count(),o=Math.max(1,Math.round(r/5)),a=0;ai)return!1;return!0}(o,e))){var a=e.mapDimension(o.dim),s={};return E(o.getViewLabels(),(function(t){var e=o.scale.getRawOrdinalNumber(t.tickValue);s[e]=1})),function(t){return!s.hasOwnProperty(e.get(a,t))}}}}function GS(t,e){return[t[2*e],t[2*e+1]]}function WS(t){if(t.get(["endLabel","show"]))return!0;for(var e=0;e0&&"bolder"===t.get(["emphasis","lineStyle","width"]))&&(d.getState("emphasis").style.lineWidth=+d.style.lineWidth+1);rl(d).seriesIndex=t.seriesIndex,Zl(d,L,P,O);var R=zS(t.get("smooth")),N=t.get("smoothMonotone");if(d.setShape({smooth:R,smoothMonotone:N,connectNulls:w}),f){var E=a.getCalculationInfo("stackedOnSeries"),z=0;f.useStyle(k(l.getAreaStyle(),{fill:C,opacity:.7,lineJoin:"bevel",decal:a.getVisual("style").decal})),E&&(z=zS(E.get("smooth"))),f.setShape({smooth:R,stackedOnSmooth:z,smoothMonotone:N,connectNulls:w}),$l(f,t,"areaStyle"),rl(f).seriesIndex=t.seriesIndex,Zl(f,L,P,O)}var V=function(t){i._changePolyState(t)};a.eachItemGraphicEl((function(t){t&&(t.onHoverStateChange=V)})),this._polyline.onHoverStateChange=V,this._data=a,this._coordSys=r,this._stackedOnPoints=_,this._points=u,this._step=T,this._valueOrigin=m,t.get("triggerLineEvent")&&(this.packEventData(t,d),f&&this.packEventData(t,f))},e.prototype.packEventData=function(t,e){rl(e).eventData={componentType:"series",componentSubType:"line",componentIndex:t.componentIndex,seriesIndex:t.seriesIndex,seriesName:t.name,seriesType:"line"}},e.prototype.highlight=function(t,e,n,i){var r=t.getData(),o=zo(r,i);if(this._changePolyState("emphasis"),!(o instanceof Array)&&null!=o&&o>=0){var a=r.getLayout("points"),s=r.getItemGraphicEl(o);if(!s){var l=a[2*o],u=a[2*o+1];if(isNaN(l)||isNaN(u))return;if(this._clipShapeForSymbol&&!this._clipShapeForSymbol.contain(l,u))return;var h=t.get("zlevel")||0,c=t.get("z")||0;(s=new fS(r,o)).x=l,s.y=u,s.setZ(h,c);var p=s.getSymbolPath().getTextContent();p&&(p.zlevel=h,p.z=c,p.z2=this._polyline.z2+1),s.__temp=!0,r.setItemGraphicEl(o,s),s.stopSymbolAnimation(!0),this.group.add(s)}s.highlight()}else Og.prototype.highlight.call(this,t,e,n,i)},e.prototype.downplay=function(t,e,n,i){var r=t.getData(),o=zo(r,i);if(this._changePolyState("normal"),null!=o&&o>=0){var a=r.getItemGraphicEl(o);a&&(a.__temp?(r.setItemGraphicEl(o,null),this.group.remove(a)):a.downplay())}else Og.prototype.downplay.call(this,t,e,n,i)},e.prototype._changePolyState=function(t){var e=this._polygon;Dl(this._polyline,t),e&&Dl(e,t)},e.prototype._newPolyline=function(t){var e=this._polyline;return e&&this._lineGroup.remove(e),e=new CS({shape:{points:t},segmentIgnoreThreshold:2,z2:10}),this._lineGroup.add(e),this._polyline=e,e},e.prototype._newPolygon=function(t,e){var n=this._polygon;return n&&this._lineGroup.remove(n),n=new AS({shape:{points:t,stackedOnPoints:e},segmentIgnoreThreshold:2}),this._lineGroup.add(n),this._polygon=n,n},e.prototype._initSymbolLabelAnimation=function(t,e,n){var i,r,o=e.getBaseAxis(),a=o.inverse;"cartesian2d"===e.type?(i=o.isHorizontal(),r=!1):"polar"===e.type&&(i="angle"===o.dim,r=!0);var s=t.hostModel,l=s.get("animationDuration");X(l)&&(l=l(null));var u=s.get("animationDelay")||0,h=X(u)?u(null):u;t.eachItemGraphicEl((function(t,o){var s=t;if(s){var c=[t.x,t.y],p=void 0,d=void 0,f=void 0;if(n)if(r){var g=n,y=e.pointToCoord(c);i?(p=g.startAngle,d=g.endAngle,f=-y[1]/180*Math.PI):(p=g.r0,d=g.r,f=y[0])}else{var v=n;i?(p=v.x,d=v.x+v.width,f=t.x):(p=v.y+v.height,d=v.y,f=t.y)}var m=d===p?0:(f-p)/(d-p);a&&(m=1-m);var x=X(u)?u(o):l*m+h,_=s.getSymbolPath(),b=_.getTextContent();s.attr({scaleX:0,scaleY:0}),s.animateTo({scaleX:1,scaleY:1},{duration:200,setToFinal:!0,delay:x}),b&&b.animateFrom({style:{opacity:0}},{duration:300,delay:x}),_.disableLabelAnimation=!0}}))},e.prototype._initOrUpdateEndLabel=function(t,e,n){var i=t.getModel("endLabel");if(WS(t)){var r=t.getData(),o=this._polyline,a=r.getLayout("points");if(!a)return o.removeTextContent(),void(this._endLabel=null);var s=this._endLabel;s||((s=this._endLabel=new Xs({z2:200})).ignoreClip=!0,o.setTextContent(this._endLabel),o.disableLabelAnimation=!0);var l=function(t){for(var e,n,i=t.length/2;i>0&&(e=t[2*i-2],n=t[2*i-1],isNaN(e)||isNaN(n));i--);return i-1}(a);l>=0&&(ic(o,rc(t,"endLabel"),{inheritColor:n,labelFetcher:t,labelDataIndex:l,defaultText:function(t,e,n){return null!=n?dS(r,n):pS(r,t)},enableTextSetter:!0},function(t,e){var n=e.getBaseAxis(),i=n.isHorizontal(),r=n.inverse,o=i?r?"right":"left":"center",a=i?"middle":r?"top":"bottom";return{normal:{align:t.get("align")||o,verticalAlign:t.get("verticalAlign")||a}}}(i,e)),o.textConfig.position=null)}else this._endLabel&&(this._polyline.removeTextContent(),this._endLabel=null)},e.prototype._endLabelOnDuring=function(t,e,n,i,r,o,a){var s=this._endLabel,l=this._polyline;if(s){t<1&&null==i.originalX&&(i.originalX=s.x,i.originalY=s.y);var u=n.getLayout("points"),h=n.hostModel,c=h.get("connectNulls"),p=o.get("precision"),d=o.get("distance")||0,f=a.getBaseAxis(),g=f.isHorizontal(),y=f.inverse,v=e.shape,m=y?g?v.x:v.y+v.height:g?v.x+v.width:v.y,x=(g?d:0)*(y?-1:1),_=(g?0:-d)*(y?-1:1),b=g?"x":"y",w=function(t,e,n){for(var i,r,o=t.length/2,a="x"===n?0:1,s=0,l=-1,u=0;u=e||i>=e&&r<=e){l=u;break}s=u,i=r}else i=r;return{range:[s,l],t:(e-i)/(r-i)}}(u,m,b),S=w.range,M=S[1]-S[0],I=void 0;if(M>=1){if(M>1&&!c){var T=GS(u,S[0]);s.attr({x:T[0]+x,y:T[1]+_}),r&&(I=h.getRawValue(S[0]))}else{(T=l.getPointOn(m,b))&&s.attr({x:T[0]+x,y:T[1]+_});var C=h.getRawValue(S[0]),D=h.getRawValue(S[1]);r&&(I=Zo(n,p,C,D,w.t))}i.lastFrameIndex=S[0]}else{var A=1===t||i.lastFrameIndex>0?S[0]:0;T=GS(u,A);r&&(I=h.getRawValue(A)),s.attr({x:T[0]+x,y:T[1]+_})}if(r){var k=pc(s);"function"==typeof k.setLabelText&&k.setLabelText(I)}}},e.prototype._doUpdateAnimation=function(t,e,n,i,r,o,a){var s=this._polyline,l=this._polygon,u=t.hostModel,h=function(t,e,n,i,r,o,a,s){for(var l=function(t,e){var n=[];return e.diff(t).add((function(t){n.push({cmd:"+",idx:t})})).update((function(t,e){n.push({cmd:"=",idx:e,idx1:t})})).remove((function(t){n.push({cmd:"-",idx:t})})).execute(),n}(t,e),u=[],h=[],c=[],p=[],d=[],f=[],g=[],y=_S(r,e,a),v=t.getLayout("points")||[],m=e.getLayout("points")||[],x=0;x3e3||l&&ES(p,f)>3e3)return s.stopAnimation(),s.setShape({points:d}),void(l&&(l.stopAnimation(),l.setShape({points:d,stackedOnPoints:f})));s.shape.__points=h.current,s.shape.points=c;var g={shape:{points:d}};h.current!==c&&(g.shape.__points=h.next),s.stopAnimation(),vh(s,g,u),l&&(l.setShape({points:c,stackedOnPoints:p}),l.stopAnimation(),vh(l,{shape:{stackedOnPoints:f}},u),s.shape.points!==l.shape.points&&(l.shape.points=s.shape.points));for(var y=[],v=h.status,m=0;me&&(e=t[n]);return isFinite(e)?e:NaN},min:function(t){for(var e=1/0,n=0;ne&&(e=o,n=r)}return isFinite(n)?n:NaN},nearest:function(t){return t[0]}},ZS=function(t){return Math.round(t.length/2)};function jS(t){return{seriesType:t,reset:function(t,e,n){var i=t.getData(),r=t.get("sampling"),o=t.coordinateSystem,a=i.count();if(a>10&&"cartesian2d"===o.type&&r){var s=o.getBaseAxis(),l=o.getOtherAxis(s),u=s.getExtent(),h=n.getDevicePixelRatio(),c=Math.abs(u[1]-u[0])*(h||1),p=Math.round(a/c);if(isFinite(p)&&p>1){"lttb"===r&&t.setData(i.lttbDownSample(i.mapDimension(l.dim),1/p));var d=void 0;U(r)?d=US[r]:X(r)&&(d=r),d&&t.setData(i.downSample(i.mapDimension(l.dim),1/p,d,ZS))}}}}}var qS=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.getInitialData=function(t,e){return _x(null,this,{useEncodeDefaulter:!0})},e.prototype.getMarkerPosition=function(t,e,n){var i=this.coordinateSystem;if(i&&i.clampData){var r=i.clampData(t),o=i.dataToPoint(r);if(n)E(i.getAxes(),(function(t,n){if("category"===t.type&&null!=e){var i=t.getTicksCoords(),a=t.getTickModel().get("alignWithLabel"),s=r[n],l="x1"===e[n]||"y1"===e[n];if(l&&!a&&(s+=1),i.length<2)return;if(2===i.length)return void(o[n]=t.toGlobalCoord(t.getExtent()[l?1:0]));for(var u=void 0,h=void 0,c=1,p=0;ps){h=(d+u)/2;break}1===p&&(c=f-i[0].tickValue)}null==h&&(u?u&&(h=i[i.length-1].coord):h=i[0].coord),o[n]=t.toGlobalCoord(h)}}));else{var a=this.getData(),s=a.getLayout("offset"),l=a.getLayout("size"),u=i.getBaseAxis().isHorizontal()?0:1;o[u]+=s+l/2}return o}return[NaN,NaN]},e.type="series.__base_bar__",e.defaultOption={z:2,coordinateSystem:"cartesian2d",legendHoverLink:!0,barMinHeight:0,barMinAngle:0,large:!1,largeThreshold:400,progressive:3e3,progressiveChunkMode:"mod"},e}(bg);bg.registerClass(qS);var KS=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.getInitialData=function(){return _x(null,this,{useEncodeDefaulter:!0,createInvertedIndices:!!this.get("realtimeSort",!0)||null})},e.prototype.getProgressive=function(){return!!this.get("large")&&this.get("progressive")},e.prototype.getProgressiveThreshold=function(){var t=this.get("progressiveThreshold"),e=this.get("largeThreshold");return e>t&&(t=e),t},e.prototype.brushSelector=function(t,e,n){return n.rect(e.getItemLayout(t))},e.type="series.bar",e.dependencies=["grid","polar"],e.defaultOption=kc(qS.defaultOption,{clip:!0,roundCap:!1,showBackground:!1,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0,opacity:1},select:{itemStyle:{borderColor:"#212121"}},realtimeSort:!1}),e}(qS),$S=function(){this.cx=0,this.cy=0,this.r0=0,this.r=0,this.startAngle=0,this.endAngle=2*Math.PI,this.clockwise=!0},JS=function(t){function e(e){var n=t.call(this,e)||this;return n.type="sausage",n}return n(e,t),e.prototype.getDefaultShape=function(){return new $S},e.prototype.buildPath=function(t,e){var n=e.cx,i=e.cy,r=Math.max(e.r0||0,0),o=Math.max(e.r,0),a=.5*(o-r),s=r+a,l=e.startAngle,u=e.endAngle,h=e.clockwise,c=2*Math.PI,p=h?u-lo)return!0;o=u}return!1},e.prototype._isOrderDifferentInView=function(t,e){for(var n=e.scale,i=n.getExtent(),r=Math.max(0,i[0]),o=Math.min(i[1],n.getOrdinalMeta().categories.length-1);r<=o;++r)if(t.ordinalNumbers[r]!==n.getRawOrdinalNumber(r))return!0},e.prototype._updateSortWithinSameData=function(t,e,n,i){if(this._isOrderChangedWithinSameData(t,e,n)){var r=this._dataSort(t,n,e);this._isOrderDifferentInView(r,n)&&(this._removeOnRenderedListener(i),i.dispatchAction({type:"changeAxisOrder",componentType:n.dim+"Axis",axisId:n.index,sortInfo:r}))}},e.prototype._dispatchInitSort=function(t,e,n){var i=e.baseAxis,r=this._dataSort(t,i,(function(n){return t.get(t.mapDimension(e.otherAxis.dim),n)}));n.dispatchAction({type:"changeAxisOrder",componentType:i.dim+"Axis",isInitSort:!0,axisId:i.index,sortInfo:r})},e.prototype.remove=function(t,e){this._clear(this._model),this._removeOnRenderedListener(e)},e.prototype.dispose=function(t,e){this._removeOnRenderedListener(e)},e.prototype._removeOnRenderedListener=function(t){this._onRendered&&(t.getZr().off("rendered",this._onRendered),this._onRendered=null)},e.prototype._clear=function(t){var e=this.group,n=this._data;t&&t.isAnimationEnabled()&&n&&!this._isLargeDraw?(this._removeBackground(),this._backgroundEls=[],n.eachItemGraphicEl((function(e){wh(e,t,rl(e).dataIndex)}))):e.removeAll(),this._data=null,this._isFirstFrame=!0},e.prototype._removeBackground=function(){this.group.remove(this._backgroundGroup),this._backgroundGroup=null},e.type="bar",e}(Og),oM={cartesian2d:function(t,e){var n=e.width<0?-1:1,i=e.height<0?-1:1;n<0&&(e.x+=e.width,e.width=-e.width),i<0&&(e.y+=e.height,e.height=-e.height);var r=t.x+t.width,o=t.y+t.height,a=nM(e.x,t.x),s=iM(e.x+e.width,r),l=nM(e.y,t.y),u=iM(e.y+e.height,o),h=sr?s:a,e.y=c&&l>o?u:l,e.width=h?0:s-a,e.height=c?0:u-l,n<0&&(e.x+=e.width,e.width=-e.width),i<0&&(e.y+=e.height,e.height=-e.height),h||c},polar:function(t,e){var n=e.r0<=e.r?1:-1;if(n<0){var i=e.r;e.r=e.r0,e.r0=i}var r=iM(e.r,t.r),o=nM(e.r0,t.r0);e.r=r,e.r0=o;var a=r-o<0;if(n<0){i=e.r;e.r=e.r0,e.r0=i}return a}},aM={cartesian2d:function(t,e,n,i,r,o,a,s,l){var u=new Ws({shape:A({},i),z2:1});(u.__dataIndex=n,u.name="item",o)&&(u.shape[r?"height":"width"]=0);return u},polar:function(t,e,n,i,r,o,a,s,l){var u=!r&&l?JS:Fu,h=new u({shape:i,z2:1});h.name="item";var c,p,d=dM(r);if(h.calculateTextPosition=(c=d,p=({isRoundCap:u===JS}||{}).isRoundCap,function(t,e,n){var i=e.position;if(!i||i instanceof Array)return Dr(t,e,n);var r=c(i),o=null!=e.distance?e.distance:5,a=this.shape,s=a.cx,l=a.cy,u=a.r,h=a.r0,d=(u+h)/2,f=a.startAngle,g=a.endAngle,y=(f+g)/2,v=p?Math.abs(u-h)/2:0,m=Math.cos,x=Math.sin,_=s+u*m(f),b=l+u*x(f),w="left",S="top";switch(r){case"startArc":_=s+(h-o)*m(y),b=l+(h-o)*x(y),w="center",S="top";break;case"insideStartArc":_=s+(h+o)*m(y),b=l+(h+o)*x(y),w="center",S="bottom";break;case"startAngle":_=s+d*m(f)+QS(f,o+v,!1),b=l+d*x(f)+tM(f,o+v,!1),w="right",S="middle";break;case"insideStartAngle":_=s+d*m(f)+QS(f,-o+v,!1),b=l+d*x(f)+tM(f,-o+v,!1),w="left",S="middle";break;case"middle":_=s+d*m(y),b=l+d*x(y),w="center",S="middle";break;case"endArc":_=s+(u+o)*m(y),b=l+(u+o)*x(y),w="center",S="bottom";break;case"insideEndArc":_=s+(u-o)*m(y),b=l+(u-o)*x(y),w="center",S="top";break;case"endAngle":_=s+d*m(g)+QS(g,o+v,!0),b=l+d*x(g)+tM(g,o+v,!0),w="left",S="middle";break;case"insideEndAngle":_=s+d*m(g)+QS(g,-o+v,!0),b=l+d*x(g)+tM(g,-o+v,!0),w="right",S="middle";break;default:return Dr(t,e,n)}return(t=t||{}).x=_,t.y=b,t.align=w,t.verticalAlign=S,t}),o){var f=r?"r":"endAngle",g={};h.shape[f]=r?i.r0:i.startAngle,g[f]=i[f],(s?vh:mh)(h,{shape:g},o)}return h}};function sM(t,e,n,i,r,o,a,s){var l,u;o?(u={x:i.x,width:i.width},l={y:i.y,height:i.height}):(u={y:i.y,height:i.height},l={x:i.x,width:i.width}),s||(a?vh:mh)(n,{shape:l},e,r,null),(a?vh:mh)(n,{shape:u},e?t.baseAxis.model:null,r)}function lM(t,e){for(var n=0;n0?1:-1,a=i.height>0?1:-1;return{x:i.x+o*r/2,y:i.y+a*r/2,width:i.width-o*r,height:i.height-a*r}},polar:function(t,e,n){var i=t.getItemLayout(e);return{cx:i.cx,cy:i.cy,r0:i.r0,r:i.r,startAngle:i.startAngle,endAngle:i.endAngle,clockwise:i.clockwise}}};function dM(t){return function(t){var e=t?"Arc":"Angle";return function(t){switch(t){case"start":case"insideStart":case"end":case"insideEnd":return t+e;default:return t}}}(t)}function fM(t,e,n,i,r,o,a,s){var l=e.getItemVisual(n,"style");if(s){if(!o.get("roundCap")){var u=t.shape;A(u,eM(i.getModel("itemStyle"),u,!0)),t.setShape(u)}}else{var h=i.get(["itemStyle","borderRadius"])||0;t.setShape("r",h)}t.useStyle(l);var c=i.getShallow("cursor");c&&t.attr("cursor",c);var p=s?a?r.r>=r.r0?"endArc":"startArc":r.endAngle>=r.startAngle?"endAngle":"startAngle":a?r.height>=0?"bottom":"top":r.width>=0?"right":"left",d=rc(i);ic(t,d,{labelFetcher:o,labelDataIndex:n,defaultText:pS(o.getData(),n),inheritColor:l.fill,defaultOpacity:l.opacity,defaultOutsidePosition:p});var f=t.getTextContent();if(s&&f){var g=i.get(["label","position"]);t.textConfig.inside="middle"===g||null,function(t,e,n,i){if(j(i))t.setTextConfig({rotation:i});else if(Y(e))t.setTextConfig({rotation:0});else{var r,o=t.shape,a=o.clockwise?o.startAngle:o.endAngle,s=o.clockwise?o.endAngle:o.startAngle,l=(a+s)/2,u=n(e);switch(u){case"startArc":case"insideStartArc":case"middle":case"insideEndArc":case"endArc":r=l;break;case"startAngle":case"insideStartAngle":r=a;break;case"endAngle":case"insideEndAngle":r=s;break;default:return void t.setTextConfig({rotation:0})}var h=1.5*Math.PI-r;"middle"===u&&h>Math.PI/2&&h<1.5*Math.PI&&(h-=Math.PI),t.setTextConfig({rotation:h})}}(t,"outside"===g?p:g,dM(a),i.get(["label","rotate"]))}dc(f,d,o.getRawValue(n),(function(t){return dS(e,t)}));var y=i.getModel(["emphasis"]);Zl(t,y.get("focus"),y.get("blurScope"),y.get("disabled")),$l(t,i),function(t){return null!=t.startAngle&&null!=t.endAngle&&t.startAngle===t.endAngle}(r)&&(t.style.fill="none",t.style.stroke="none",E(t.states,(function(t){t.style&&(t.style.fill=t.style.stroke="none")})))}var gM=function(){},yM=function(t){function e(e){var n=t.call(this,e)||this;return n.type="largeBar",n}return n(e,t),e.prototype.getDefaultShape=function(){return new gM},e.prototype.buildPath=function(t,e){for(var n=e.points,i=this.baseDimIdx,r=1-this.baseDimIdx,o=[],a=[],s=this.barWidth,l=0;l=s[0]&&e<=s[0]+l[0]&&n>=s[1]&&n<=s[1]+l[1])return a[h]}return-1}(this,t.offsetX,t.offsetY);rl(this).dataIndex=e>=0?e:null}),30,!1);function xM(t,e,n){if(OS(n,"cartesian2d")){var i=e,r=n.getArea();return{x:t?i.x:r.x,y:t?r.y:i.y,width:t?i.width:r.width,height:t?r.height:i.height}}var o=e;return{cx:(r=n.getArea()).cx,cy:r.cy,r0:t?r.r0:o.r0,r:t?r.r:o.r,startAngle:t?o.startAngle:0,endAngle:t?o.endAngle:2*Math.PI}}var _M=2*Math.PI,bM=Math.PI/180;function wM(t,e){return kp(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()})}function SM(t,e){var n=wM(t,e),i=t.get("center"),r=t.get("radius");Y(r)||(r=[0,r]);var o,a,s=$r(n.width,e.getWidth()),l=$r(n.height,e.getHeight()),u=Math.min(s,l),h=$r(r[0],u/2),c=$r(r[1],u/2),p=t.coordinateSystem;if(p){var d=p.dataToPoint(i);o=d[0]||0,a=d[1]||0}else Y(i)||(i=[i,i]),o=$r(i[0],s)+n.x,a=$r(i[1],l)+n.y;return{cx:o,cy:a,r0:h,r:c}}function MM(t,e,n){e.eachSeriesByType(t,(function(t){var e=t.getData(),i=e.mapDimension("value"),r=wM(t,n),o=SM(t,n),a=o.cx,s=o.cy,l=o.r,u=o.r0,h=-t.get("startAngle")*bM,c=t.get("endAngle"),p=t.get("padAngle")*bM;c="auto"===c?h-_M:-c*bM;var d=t.get("minAngle")*bM+p,f=0;e.each(i,(function(t){!isNaN(t)&&f++}));var g=e.getSum(i),y=Math.PI/(g||f)*2,v=t.get("clockwise"),m=t.get("roseType"),x=t.get("stillShowZeroSum"),_=e.getDataExtent(i);_[0]=0;var b=v?1:-1,w=[h,c],S=b*p/2;us(w,!v),h=w[0],c=w[1];var M=IM(t);M.startAngle=h,M.endAngle=c,M.clockwise=v;var I=Math.abs(c-h),T=I,C=0,D=h;if(e.setLayout({viewRect:r,r:l}),e.each(i,(function(t,n){var i;if(isNaN(t))e.setItemLayout(n,{angle:NaN,startAngle:NaN,endAngle:NaN,clockwise:v,cx:a,cy:s,r0:u,r:m?NaN:l});else{(i="area"!==m?0===g&&x?y:t*y:I/f)i?h=o=D+b*i/2:(o=D+S,h=r-S),e.setItemLayout(n,{angle:i,startAngle:o,endAngle:h,clockwise:v,cx:a,cy:s,r0:u,r:m?Kr(t,_,[u,l]):l}),D=r}})),T<_M&&f)if(T<=.001){var A=I/f;e.each(i,(function(t,n){if(!isNaN(t)){var i=e.getItemLayout(n);i.angle=A;var r=0,o=0;An?a:o,h=Math.abs(l.label.y-n);if(h>=u.maxY){var c=l.label.x-e-l.len2*r,p=i+l.len,f=Math.abs(c)t.unconstrainedWidth?null:d:null;i.setStyle("width",f)}var g=i.getBoundingRect();o.width=g.width;var y=(i.style.margin||0)+2.1;o.height=g.height+y,o.y-=(o.height-c)/2}}}function kM(t){return"center"===t.position}function LM(t){var e,n,i=t.getData(),r=[],o=!1,a=(t.get("minShowLabelAngle")||0)*CM,s=i.getLayout("viewRect"),l=i.getLayout("r"),u=s.width,h=s.x,c=s.y,p=s.height;function d(t){t.ignore=!0}i.each((function(t){var s=i.getItemGraphicEl(t),c=s.shape,p=s.getTextContent(),f=s.getTextGuideLine(),g=i.getItemModel(t),y=g.getModel("label"),v=y.get("position")||g.get(["emphasis","label","position"]),m=y.get("distanceToLabelLine"),x=y.get("alignTo"),_=$r(y.get("edgeDistance"),u),b=y.get("bleedMargin"),w=g.getModel("labelLine"),S=w.get("length");S=$r(S,u);var M=w.get("length2");if(M=$r(M,u),Math.abs(c.endAngle-c.startAngle)0?"right":"left":k>0?"left":"right"}var B=Math.PI,F=0,G=y.get("rotate");if(j(G))F=G*(B/180);else if("center"===v)F=0;else if("radial"===G||!0===G){F=k<0?-A+B:-A}else if("tangential"===G&&"outside"!==v&&"outer"!==v){var W=Math.atan2(k,L);W<0&&(W=2*B+W),L>0&&(W=B+W),F=W-B}if(o=!!F,p.x=I,p.y=T,p.rotation=F,p.setStyle({verticalAlign:"middle"}),P){p.setStyle({align:D});var H=p.states.select;H&&(H.x+=p.x,H.y+=p.y)}else{var Y=p.getBoundingRect().clone();Y.applyTransform(p.getComputedTransform());var X=(p.style.margin||0)+2.1;Y.y-=X/2,Y.height+=X,r.push({label:p,labelLine:f,position:v,len:S,len2:M,minTurnAngle:w.get("minTurnAngle"),maxSurfaceAngle:w.get("maxSurfaceAngle"),surfaceNormal:new De(k,L),linePoints:C,textAlign:D,labelDistance:m,labelAlignTo:x,edgeDistance:_,bleedMargin:b,rect:Y,unconstrainedWidth:Y.width,labelStyleWidth:p.style.width})}s.setTextConfig({inside:P})}})),!o&&t.get("avoidLabelOverlap")&&function(t,e,n,i,r,o,a,s){for(var l=[],u=[],h=Number.MAX_VALUE,c=-Number.MAX_VALUE,p=0;p0){for(var l=o.getItemLayout(0),u=1;isNaN(l&&l.startAngle)&&u=n.r0}},e.type="pie",e}(Og);function RM(t,e,n){e=Y(e)&&{coordDimensions:e}||A({encodeDefine:t.getEncode()},e);var i=t.getSource(),r=px(i,e).dimensions,o=new cx(r,t);return o.initData(i,n),o}var NM=function(){function t(t,e){this._getDataWithEncodedVisual=t,this._getRawData=e}return t.prototype.getAllNames=function(){var t=this._getRawData();return t.mapArray(t.getName)},t.prototype.containName=function(t){return this._getRawData().indexOfName(t)>=0},t.prototype.indexOfName=function(t){return this._getDataWithEncodedVisual().indexOfName(t)},t.prototype.getItemVisual=function(t,e){return this._getDataWithEncodedVisual().getItemVisual(t,e)},t}(),EM=Vo(),zM=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.init=function(e){t.prototype.init.apply(this,arguments),this.legendVisualProvider=new NM(W(this.getData,this),W(this.getRawData,this)),this._defaultLabelLine(e)},e.prototype.mergeOption=function(){t.prototype.mergeOption.apply(this,arguments)},e.prototype.getInitialData=function(){return RM(this,{coordDimensions:["value"],encodeDefaulter:H(ed,this)})},e.prototype.getDataParams=function(e){var n=this.getData(),i=EM(n),r=i.seats;if(!r){var o=[];n.each(n.mapDimension("value"),(function(t){o.push(t)})),r=i.seats=io(o,n.hostModel.get("percentPrecision"))}var a=t.prototype.getDataParams.call(this,e);return a.percent=r[e]||0,a.$vars.push("percent"),a},e.prototype._defaultLabelLine=function(t){Co(t,"labelLine",["show"]);var e=t.labelLine,n=t.emphasis.labelLine;e.show=e.show&&t.label.show,n.show=n.show&&t.emphasis.label.show},e.type="series.pie",e.defaultOption={z:2,legendHoverLink:!0,colorBy:"data",center:["50%","50%"],radius:[0,"75%"],clockwise:!0,startAngle:90,endAngle:"auto",padAngle:0,minAngle:0,minShowLabelAngle:0,selectedOffset:10,percentPrecision:2,stillShowZeroSum:!0,left:0,top:0,right:0,bottom:0,width:null,height:null,label:{rotate:0,show:!0,overflow:"truncate",position:"outer",alignTo:"none",edgeDistance:"25%",bleedMargin:10,distanceToLabelLine:5},labelLine:{show:!0,length:15,length2:15,smooth:!1,minTurnAngle:90,maxSurfaceAngle:90,lineStyle:{width:1,type:"solid"}},itemStyle:{borderWidth:1,borderJoin:"round"},showEmptyCircle:!0,emptyCircleStyle:{color:"lightgray",opacity:1},labelLayout:{hideOverlap:!0},emphasis:{scale:!0,scaleSize:5},avoidLabelOverlap:!0,animationType:"expansion",animationDuration:1e3,animationTypeUpdate:"transition",animationEasingUpdate:"cubicInOut",animationDurationUpdate:500,animationEasing:"cubicInOut"},e}(bg);var VM=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.hasSymbolVisual=!0,n}return n(e,t),e.prototype.getInitialData=function(t,e){return _x(null,this,{useEncodeDefaulter:!0})},e.prototype.getProgressive=function(){var t=this.option.progressive;return null==t?this.option.large?5e3:this.get("progressive"):t},e.prototype.getProgressiveThreshold=function(){var t=this.option.progressiveThreshold;return null==t?this.option.large?1e4:this.get("progressiveThreshold"):t},e.prototype.brushSelector=function(t,e,n){return n.point(e.getItemLayout(t))},e.prototype.getZLevelKey=function(){return this.getData().count()>this.getProgressiveThreshold()?this.id:""},e.type="series.scatter",e.dependencies=["grid","polar","geo","singleAxis","calendar"],e.defaultOption={coordinateSystem:"cartesian2d",z:2,legendHoverLink:!0,symbolSize:10,large:!1,largeThreshold:2e3,itemStyle:{opacity:.8},emphasis:{scale:!0},clip:!0,select:{itemStyle:{borderColor:"#212121"}},universalTransition:{divideShape:"clone"}},e}(bg),BM=function(){},FM=function(t){function e(e){var n=t.call(this,e)||this;return n._off=0,n.hoverDataIdx=-1,n}return n(e,t),e.prototype.getDefaultShape=function(){return new BM},e.prototype.reset=function(){this.notClear=!1,this._off=0},e.prototype.buildPath=function(t,e){var n,i=e.points,r=e.size,o=this.symbolProxy,a=o.shape,s=t.getContext?t.getContext():t,l=s&&r[0]<4,u=this.softClipShape;if(l)this._ctx=s;else{for(this._ctx=null,n=this._off;n=0;s--){var l=2*s,u=i[l]-o/2,h=i[l+1]-a/2;if(t>=u&&e>=h&&t<=u+o&&e<=h+a)return s}return-1},e.prototype.contain=function(t,e){var n=this.transformCoordToLocal(t,e),i=this.getBoundingRect();return t=n[0],e=n[1],i.contain(t,e)?(this.hoverDataIdx=this.findDataIndex(t,e))>=0:(this.hoverDataIdx=-1,!1)},e.prototype.getBoundingRect=function(){var t=this._rect;if(!t){for(var e=this.shape,n=e.points,i=e.size,r=i[0],o=i[1],a=1/0,s=1/0,l=-1/0,u=-1/0,h=0;h=0&&(l.dataIndex=n+(t.startIndex||0))}))},t.prototype.remove=function(){this._clear()},t.prototype._clear=function(){this._newAdded=[],this.group.removeAll()},t}(),WM=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){var i=t.getData();this._updateSymbolDraw(i,t).updateData(i,{clipShape:this._getClipShape(t)}),this._finished=!0},e.prototype.incrementalPrepareRender=function(t,e,n){var i=t.getData();this._updateSymbolDraw(i,t).incrementalPrepareUpdate(i),this._finished=!1},e.prototype.incrementalRender=function(t,e,n){this._symbolDraw.incrementalUpdate(t,e.getData(),{clipShape:this._getClipShape(e)}),this._finished=t.end===e.getData().count()},e.prototype.updateTransform=function(t,e,n){var i=t.getData();if(this.group.dirty(),!this._finished||i.count()>1e4)return{update:!0};var r=XS("").reset(t,e,n);r.progress&&r.progress({start:0,end:i.count(),count:i.count()},i),this._symbolDraw.updateLayout(i)},e.prototype.eachRendered=function(t){this._symbolDraw&&this._symbolDraw.eachRendered(t)},e.prototype._getClipShape=function(t){if(t.get("clip",!0)){var e=t.coordinateSystem;return e&&e.getArea&&e.getArea(.1)}},e.prototype._updateSymbolDraw=function(t,e){var n=this._symbolDraw,i=e.pipelineContext.large;return n&&i===this._isLargeDraw||(n&&n.remove(),n=this._symbolDraw=i?new GM:new xS,this._isLargeDraw=i,this.group.removeAll()),this.group.add(n.group),n},e.prototype.remove=function(t,e){this._symbolDraw&&this._symbolDraw.remove(!0),this._symbolDraw=null},e.prototype.dispose=function(){},e.type="scatter",e}(Og),HM=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.type="grid",e.dependencies=["xAxis","yAxis"],e.layoutMode="box",e.defaultOption={show:!1,z:0,left:"10%",top:60,right:"10%",bottom:70,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},e}(zp),YM=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.getCoordSysModel=function(){return this.getReferringComponents("grid",Wo).models[0]},e.type="cartesian2dAxis",e}(zp);R(YM,D_);var XM={show:!0,z:0,inverse:!1,name:"",nameLocation:"end",nameRotate:null,nameTruncate:{maxWidth:null,ellipsis:"...",placeholder:"."},nameTextStyle:{},nameGap:15,silent:!1,triggerEvent:!1,tooltip:{show:!1},axisPointer:{},axisLine:{show:!0,onZero:!0,onZeroAxisIndex:null,lineStyle:{color:"#6E7079",width:1,type:"solid"},symbol:["none","none"],symbolSize:[10,15]},axisTick:{show:!0,inside:!1,length:5,lineStyle:{width:1}},axisLabel:{show:!0,inside:!1,rotate:0,showMinLabel:null,showMaxLabel:null,margin:8,fontSize:12},splitLine:{show:!0,lineStyle:{color:["#E0E6F1"],width:1,type:"solid"}},splitArea:{show:!1,areaStyle:{color:["rgba(250,250,250,0.2)","rgba(210,219,238,0.2)"]}}},UM=C({boundaryGap:!0,deduplication:null,splitLine:{show:!1},axisTick:{alignWithLabel:!1,interval:"auto"},axisLabel:{interval:"auto"}},XM),ZM=C({boundaryGap:[0,0],axisLine:{show:"auto"},axisTick:{show:"auto"},splitNumber:5,minorTick:{show:!1,splitNumber:5,length:3,lineStyle:{}},minorSplitLine:{show:!1,lineStyle:{color:"#F4F7FD",width:1}}},XM),jM={category:UM,value:ZM,time:C({splitNumber:6,axisLabel:{showMinLabel:!1,showMaxLabel:!1,rich:{primary:{fontWeight:"bold"}}},splitLine:{show:!1}},ZM),log:k({logBase:10},ZM)},qM={value:1,category:1,time:1,log:1};function KM(t,e,i,r){E(qM,(function(o,a){var s=C(C({},jM[a],!0),r,!0),l=function(t){function i(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e+"Axis."+a,n}return n(i,t),i.prototype.mergeDefaultAndTheme=function(t,e){var n=Pp(this),i=n?Rp(t):{};C(t,e.getTheme().get(a+"Axis")),C(t,this.getDefaultOption()),t.type=$M(t),n&&Op(t,i,n)},i.prototype.optionUpdated=function(){"category"===this.option.type&&(this.__ordinalMeta=Mx.createByAxisModel(this))},i.prototype.getCategories=function(t){var e=this.option;if("category"===e.type)return t?e.data:this.__ordinalMeta.categories},i.prototype.getOrdinalMeta=function(){return this.__ordinalMeta},i.type=e+"Axis."+a,i.defaultOption=s,i}(i);t.registerComponentModel(l)})),t.registerSubTypeDefaulter(e+"Axis",$M)}function $M(t){return t.type||(t.data?"category":"value")}var JM=function(){function t(t){this.type="cartesian",this._dimList=[],this._axes={},this.name=t||""}return t.prototype.getAxis=function(t){return this._axes[t]},t.prototype.getAxes=function(){return z(this._dimList,(function(t){return this._axes[t]}),this)},t.prototype.getAxesByScale=function(t){return t=t.toLowerCase(),B(this.getAxes(),(function(e){return e.scale.type===t}))},t.prototype.addAxis=function(t){var e=t.dim;this._axes[e]=t,this._dimList.push(e)},t}(),QM=["x","y"];function tI(t){return"interval"===t.type||"time"===t.type}var eI=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.type="cartesian2d",e.dimensions=QM,e}return n(e,t),e.prototype.calcAffineTransform=function(){this._transform=this._invTransform=null;var t=this.getAxis("x").scale,e=this.getAxis("y").scale;if(tI(t)&&tI(e)){var n=t.getExtent(),i=e.getExtent(),r=this.dataToPoint([n[0],i[0]]),o=this.dataToPoint([n[1],i[1]]),a=n[1]-n[0],s=i[1]-i[0];if(a&&s){var l=(o[0]-r[0])/a,u=(o[1]-r[1])/s,h=r[0]-n[0]*l,c=r[1]-i[0]*u,p=this._transform=[l,0,0,u,h,c];this._invTransform=Ie([],p)}}},e.prototype.getBaseAxis=function(){return this.getAxesByScale("ordinal")[0]||this.getAxesByScale("time")[0]||this.getAxis("x")},e.prototype.containPoint=function(t){var e=this.getAxis("x"),n=this.getAxis("y");return e.contain(e.toLocalCoord(t[0]))&&n.contain(n.toLocalCoord(t[1]))},e.prototype.containData=function(t){return this.getAxis("x").containData(t[0])&&this.getAxis("y").containData(t[1])},e.prototype.containZone=function(t,e){var n=this.dataToPoint(t),i=this.dataToPoint(e),r=this.getArea(),o=new ze(n[0],n[1],i[0]-n[0],i[1]-n[1]);return r.intersect(o)},e.prototype.dataToPoint=function(t,e,n){n=n||[];var i=t[0],r=t[1];if(this._transform&&null!=i&&isFinite(i)&&null!=r&&isFinite(r))return Wt(n,t,this._transform);var o=this.getAxis("x"),a=this.getAxis("y");return n[0]=o.toGlobalCoord(o.dataToCoord(i,e)),n[1]=a.toGlobalCoord(a.dataToCoord(r,e)),n},e.prototype.clampData=function(t,e){var n=this.getAxis("x").scale,i=this.getAxis("y").scale,r=n.getExtent(),o=i.getExtent(),a=n.parse(t[0]),s=i.parse(t[1]);return(e=e||[])[0]=Math.min(Math.max(Math.min(r[0],r[1]),a),Math.max(r[0],r[1])),e[1]=Math.min(Math.max(Math.min(o[0],o[1]),s),Math.max(o[0],o[1])),e},e.prototype.pointToData=function(t,e){var n=[];if(this._invTransform)return Wt(n,t,this._invTransform);var i=this.getAxis("x"),r=this.getAxis("y");return n[0]=i.coordToData(i.toLocalCoord(t[0]),e),n[1]=r.coordToData(r.toLocalCoord(t[1]),e),n},e.prototype.getOtherAxis=function(t){return this.getAxis("x"===t.dim?"y":"x")},e.prototype.getArea=function(t){t=t||0;var e=this.getAxis("x").getGlobalExtent(),n=this.getAxis("y").getGlobalExtent(),i=Math.min(e[0],e[1])-t,r=Math.min(n[0],n[1])-t,o=Math.max(e[0],e[1])-i+t,a=Math.max(n[0],n[1])-r+t;return new ze(i,r,o,a)},e}(JM),nI=function(t){function e(e,n,i,r,o){var a=t.call(this,e,n,i)||this;return a.index=0,a.type=r||"value",a.position=o||"bottom",a}return n(e,t),e.prototype.isHorizontal=function(){var t=this.position;return"top"===t||"bottom"===t},e.prototype.getGlobalExtent=function(t){var e=this.getExtent();return e[0]=this.toGlobalCoord(e[0]),e[1]=this.toGlobalCoord(e[1]),t&&e[0]>e[1]&&e.reverse(),e},e.prototype.pointToData=function(t,e){return this.coordToData(this.toLocalCoord(t["x"===this.dim?0:1]),e)},e.prototype.setCategorySortInfo=function(t){if("category"!==this.type)return!1;this.model.option.categorySortInfo=t,this.scale.setSortInfo(t)},e}(ab);function iI(t,e,n){n=n||{};var i=t.coordinateSystem,r=e.axis,o={},a=r.getAxesOnZeroOf()[0],s=r.position,l=a?"onZero":s,u=r.dim,h=i.getRect(),c=[h.x,h.x+h.width,h.y,h.y+h.height],p={left:0,right:1,top:0,bottom:1,onZero:2},d=e.get("offset")||0,f="x"===u?[c[2]-d,c[3]+d]:[c[0]-d,c[1]+d];if(a){var g=a.toGlobalCoord(a.dataToCoord(0));f[p.onZero]=Math.max(Math.min(g,f[1]),f[0])}o.position=["y"===u?f[p[l]]:c[0],"x"===u?f[p[l]]:c[3]],o.rotation=Math.PI/2*("x"===u?0:1);o.labelDirection=o.tickDirection=o.nameDirection={top:-1,bottom:1,left:-1,right:1}[s],o.labelOffset=a?f[p[s]]-f[p.onZero]:0,e.get(["axisTick","inside"])&&(o.tickDirection=-o.tickDirection),it(n.labelInside,e.get(["axisLabel","inside"]))&&(o.labelDirection=-o.labelDirection);var y=e.get(["axisLabel","rotate"]);return o.labelRotate="top"===l?-y:y,o.z2=1,o}function rI(t){return"cartesian2d"===t.get("coordinateSystem")}function oI(t){var e={xAxisModel:null,yAxisModel:null};return E(e,(function(n,i){var r=i.replace(/Model$/,""),o=t.getReferringComponents(r,Wo).models[0];e[i]=o})),e}var aI=Math.log;function sI(t,e,n){var i=Ex.prototype,r=i.getTicks.call(n),o=i.getTicks.call(n,!0),a=r.length-1,s=i.getInterval.call(n),l=x_(t,e),u=l.extent,h=l.fixMin,c=l.fixMax;if("log"===t.type){var p=aI(t.base);u=[aI(u[0])/p,aI(u[1])/p]}t.setExtent(u[0],u[1]),t.calcNiceExtent({splitNumber:a,fixMin:h,fixMax:c});var d=i.getExtent.call(t);h&&(u[0]=d[0]),c&&(u[1]=d[1]);var f=i.getInterval.call(t),g=u[0],y=u[1];if(h&&c)f=(y-g)/a;else if(h)for(y=u[0]+f*a;yu[0]&&isFinite(g)&&isFinite(u[0]);)f=Dx(f),g=u[1]-f*a;else{t.getTicks().length-1>a&&(f=Dx(f));var v=f*a;(g=Jr((y=Math.ceil(u[1]/f)*f)-v))<0&&u[0]>=0?(g=0,y=Jr(v)):y>0&&u[1]<=0&&(y=0,g=-Jr(v))}var m=(r[0].value-o[0].value)/s,x=(r[a].value-o[a].value)/s;i.setExtent.call(t,g+f*m,y+f*x),i.setInterval.call(t,f),(m||x)&&i.setNiceExtent.call(t,g+f,y-f)}var lI=function(){function t(t,e,n){this.type="grid",this._coordsMap={},this._coordsList=[],this._axesMap={},this._axesList=[],this.axisPointerEnabled=!0,this.dimensions=QM,this._initCartesian(t,e,n),this.model=t}return t.prototype.getRect=function(){return this._rect},t.prototype.update=function(t,e){var n=this._axesMap;function i(t){var e,n=G(t),i=n.length;if(i){for(var r=[],o=i-1;o>=0;o--){var a=t[+n[o]],s=a.model,l=a.scale;Tx(l)&&s.get("alignTicks")&&null==s.get("interval")?r.push(a):(__(l,s),Tx(l)&&(e=a))}r.length&&(e||__((e=r.pop()).scale,e.model),E(r,(function(t){sI(t.scale,t.model,e.scale)})))}}this._updateScale(t,this.model),i(n.x),i(n.y);var r={};E(n.x,(function(t){hI(n,"y",t,r)})),E(n.y,(function(t){hI(n,"x",t,r)})),this.resize(this.model,e)},t.prototype.resize=function(t,e,n){var i=t.getBoxLayoutParams(),r=!n&&t.get("containLabel"),o=kp(i,{width:e.getWidth(),height:e.getHeight()});this._rect=o;var a=this._axesList;function s(){E(a,(function(t){var e=t.isHorizontal(),n=e?[0,o.width]:[0,o.height],i=t.inverse?1:0;t.setExtent(n[i],n[1-i]),function(t,e){var n=t.getExtent(),i=n[0]+n[1];t.toGlobalCoord="x"===t.dim?function(t){return t+e}:function(t){return i-t+e},t.toLocalCoord="x"===t.dim?function(t){return t-e}:function(t){return i-t+e}}(t,e?o.x:o.y)}))}s(),r&&(E(a,(function(t){if(!t.model.get(["axisLabel","inside"])){var e=function(t){var e=t.model,n=t.scale;if(e.get(["axisLabel","show"])&&!n.isBlank()){var i,r,o=n.getExtent();r=n instanceof Rx?n.count():(i=n.getTicks()).length;var a,s=t.getLabelModel(),l=w_(t),u=1;r>40&&(u=Math.ceil(r/40));for(var h=0;h0&&i>0||n<0&&i<0)}(t)}var pI=Math.PI,dI=function(){function t(t,e){this.group=new Br,this.opt=e,this.axisModel=t,k(e,{labelOffset:0,nameDirection:1,tickDirection:1,labelDirection:1,silent:!0,handleAutoShown:function(){return!0}});var n=new Br({x:e.position[0],y:e.position[1],rotation:e.rotation});n.updateTransform(),this._transformGroup=n}return t.prototype.hasBuilder=function(t){return!!fI[t]},t.prototype.add=function(t){fI[t](this.opt,this.axisModel,this.group,this._transformGroup)},t.prototype.getGroup=function(){return this.group},t.innerTextLayout=function(t,e,n){var i,r,o=ao(e-t);return so(o)?(r=n>0?"top":"bottom",i="center"):so(o-pI)?(r=n>0?"bottom":"top",i="center"):(r="middle",i=o>0&&o0?"right":"left":n>0?"left":"right"),{rotation:o,textAlign:i,textVerticalAlign:r}},t.makeAxisEventDataBase=function(t){var e={componentType:t.mainType,componentIndex:t.componentIndex};return e[t.mainType+"Index"]=t.componentIndex,e},t.isLabelSilent=function(t){var e=t.get("tooltip");return t.get("silent")||!(t.get("triggerEvent")||e&&e.show)},t}(),fI={axisLine:function(t,e,n,i){var r=e.get(["axisLine","show"]);if("auto"===r&&t.handleAutoShown&&(r=t.handleAutoShown("axisLine")),r){var o=e.axis.getExtent(),a=i.transform,s=[o[0],0],l=[o[1],0],u=s[0]>l[0];a&&(Wt(s,s,a),Wt(l,l,a));var h=A({lineCap:"round"},e.getModel(["axisLine","lineStyle"]).getLineStyle()),c=new Ku({shape:{x1:s[0],y1:s[1],x2:l[0],y2:l[1]},style:h,strokeContainThreshold:t.strokeContainThreshold||5,silent:!0,z2:1});zh(c.shape,c.style.lineWidth),c.anid="line",n.add(c);var p=e.get(["axisLine","symbol"]);if(null!=p){var d=e.get(["axisLine","symbolSize"]);U(p)&&(p=[p,p]),(U(d)||j(d))&&(d=[d,d]);var f=Zy(e.get(["axisLine","symbolOffset"])||0,d),g=d[0],y=d[1];E([{rotate:t.rotation+Math.PI/2,offset:f[0],r:0},{rotate:t.rotation-Math.PI/2,offset:f[1],r:Math.sqrt((s[0]-l[0])*(s[0]-l[0])+(s[1]-l[1])*(s[1]-l[1]))}],(function(e,i){if("none"!==p[i]&&null!=p[i]){var r=Xy(p[i],-g/2,-y/2,g,y,h.stroke,!0),o=e.r+e.offset,a=u?l:s;r.attr({rotation:e.rotate,x:a[0]+o*Math.cos(t.rotation),y:a[1]-o*Math.sin(t.rotation),silent:!0,z2:11}),n.add(r)}}))}}},axisTickLabel:function(t,e,n,i){var r=function(t,e,n,i){var r=n.axis,o=n.getModel("axisTick"),a=o.get("show");"auto"===a&&i.handleAutoShown&&(a=i.handleAutoShown("axisTick"));if(!a||r.scale.isBlank())return;for(var s=o.getModel("lineStyle"),l=i.tickDirection*o.get("length"),u=mI(r.getTicksCoords(),e.transform,l,k(s.getLineStyle(),{stroke:n.get(["axisLine","lineStyle","color"])}),"ticks"),h=0;hc[1]?-1:1,d=["start"===s?c[0]-p*h:"end"===s?c[1]+p*h:(c[0]+c[1])/2,vI(s)?t.labelOffset+l*h:0],f=e.get("nameRotate");null!=f&&(f=f*pI/180),vI(s)?o=dI.innerTextLayout(t.rotation,null!=f?f:t.rotation,l):(o=function(t,e,n,i){var r,o,a=ao(n-t),s=i[0]>i[1],l="start"===e&&!s||"start"!==e&&s;so(a-pI/2)?(o=l?"bottom":"top",r="center"):so(a-1.5*pI)?(o=l?"top":"bottom",r="center"):(o="middle",r=a<1.5*pI&&a>pI/2?l?"left":"right":l?"right":"left");return{rotation:a,textAlign:r,textVerticalAlign:o}}(t.rotation,s,f||0,c),null!=(a=t.axisNameAvailableWidth)&&(a=Math.abs(a/Math.sin(o.rotation)),!isFinite(a)&&(a=null)));var g=u.getFont(),y=e.get("nameTruncate",!0)||{},v=y.ellipsis,m=it(t.nameTruncateMaxWidth,y.maxWidth,a),x=new Xs({x:d[0],y:d[1],rotation:o.rotation,silent:dI.isLabelSilent(e),style:oc(u,{text:r,font:g,overflow:"truncate",width:m,ellipsis:v,fill:u.getTextColor()||e.get(["axisLine","lineStyle","color"]),align:u.get("align")||o.textAlign,verticalAlign:u.get("verticalAlign")||o.textVerticalAlign}),z2:1});if(Kh({el:x,componentModel:e,itemName:r}),x.__fullText=r,x.anid="name",e.get("triggerEvent")){var _=dI.makeAxisEventDataBase(e);_.targetType="axisName",_.name=r,rl(x).eventData=_}i.add(x),x.updateTransform(),n.add(x),x.decomposeTransform()}}};function gI(t){t&&(t.ignore=!0)}function yI(t,e){var n=t&&t.getBoundingRect().clone(),i=e&&e.getBoundingRect().clone();if(n&&i){var r=xe([]);return Se(r,r,-t.rotation),n.applyTransform(be([],r,t.getLocalTransform())),i.applyTransform(be([],r,e.getLocalTransform())),n.intersect(i)}}function vI(t){return"middle"===t||"center"===t}function mI(t,e,n,i,r){for(var o=[],a=[],s=[],l=0;l=0||t===e}function bI(t){var e=wI(t);if(e){var n=e.axisPointerModel,i=e.axis.scale,r=n.option,o=n.get("status"),a=n.get("value");null!=a&&(a=i.parse(a));var s=SI(n);null==o&&(r.status=s?"show":"hide");var l=i.getExtent().slice();l[0]>l[1]&&l.reverse(),(null==a||a>l[1])&&(a=l[1]),a0&&!c.min?c.min=0:null!=c.min&&c.min<0&&!c.max&&(c.max=0);var p=a;null!=c.color&&(p=k({color:c.color},a));var d=C(T(c),{boundaryGap:t,splitNumber:e,scale:n,axisLine:i,axisTick:r,axisLabel:o,name:c.text,showName:s,nameLocation:"end",nameGap:u,nameTextStyle:p,triggerEvent:h},!1);if(U(l)){var f=d.name;d.name=l.replace("{value}",null!=f?f:"")}else X(l)&&(d.name=l(d.name,d));var g=new Cc(d,null,this.ecModel);return R(g,D_.prototype),g.mainType="radar",g.componentIndex=this.componentIndex,g}),this);this._indicatorModels=c},e.prototype.getIndicatorModels=function(){return this._indicatorModels},e.type="radar",e.defaultOption={z:0,center:["50%","50%"],radius:"75%",startAngle:90,axisName:{show:!0},boundaryGap:[0,0],splitNumber:5,axisNameGap:15,scale:!1,shape:"polygon",axisLine:C({lineStyle:{color:"#bbb"}},XI.axisLine),axisLabel:UI(XI.axisLabel,!1),axisTick:UI(XI.axisTick,!1),splitLine:UI(XI.splitLine,!0),splitArea:UI(XI.splitArea,!0),indicator:[]},e}(zp),jI=["axisLine","axisTickLabel","axisName"],qI=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){this.group.removeAll(),this._buildAxes(t),this._buildSplitLineAndArea(t)},e.prototype._buildAxes=function(t){var e=t.coordinateSystem;E(z(e.getIndicatorAxes(),(function(t){var n=t.model.get("showName")?t.name:"";return new dI(t.model,{axisName:n,position:[e.cx,e.cy],rotation:t.angle,labelDirection:-1,tickDirection:-1,nameDirection:1})})),(function(t){E(jI,t.add,t),this.group.add(t.getGroup())}),this)},e.prototype._buildSplitLineAndArea=function(t){var e=t.coordinateSystem,n=e.getIndicatorAxes();if(n.length){var i=t.get("shape"),r=t.getModel("splitLine"),o=t.getModel("splitArea"),a=r.getModel("lineStyle"),s=o.getModel("areaStyle"),l=r.get("show"),u=o.get("show"),h=a.get("color"),c=s.get("color"),p=Y(h)?h:[h],d=Y(c)?c:[c],f=[],g=[];if("circle"===i)for(var y=n[0].getTicksCoords(),v=e.cx,m=e.cy,x=0;x3?1.4:r>1?1.2:1.1;iT(this,"zoom","zoomOnMouseWheel",t,{scale:i>0?s:1/s,originX:o,originY:a,isAvailableBehavior:null})}if(n){var l=Math.abs(i);iT(this,"scrollMove","moveOnMouseWheel",t,{scrollDelta:(i>0?1:-1)*(l>3?.4:l>1?.15:.05),originX:o,originY:a,isAvailableBehavior:null})}}},e.prototype._pinchHandler=function(t){tT(this._zr,"globalPan")||iT(this,"zoom",null,t,{scale:t.pinchScale>1?1.1:1/1.1,originX:t.pinchX,originY:t.pinchY,isAvailableBehavior:null})},e}(jt);function iT(t,e,n,i,r){t.pointerChecker&&t.pointerChecker(i,r.originX,r.originY)&&(de(i.event),rT(t,e,n,i,r))}function rT(t,e,n,i,r){r.isAvailableBehavior=W(oT,null,n,i),t.trigger(e,r)}function oT(t,e,n){var i=n[t];return!t||i&&(!U(i)||e.event[i+"Key"])}function aT(t,e,n){var i=t.target;i.x+=e,i.y+=n,i.dirty()}function sT(t,e,n,i){var r=t.target,o=t.zoomLimit,a=t.zoom=t.zoom||1;if(a*=e,o){var s=o.min||0,l=o.max||1/0;a=Math.max(Math.min(l,a),s)}var u=a/t.zoom;t.zoom=a,r.x-=(n-r.x)*(u-1),r.y-=(i-r.y)*(u-1),r.scaleX*=u,r.scaleY*=u,r.dirty()}var lT,uT={axisPointer:1,tooltip:1,brush:1};function hT(t,e,n){var i=e.getComponentByElement(t.topTarget),r=i&&i.coordinateSystem;return i&&i!==n&&!uT.hasOwnProperty(i.mainType)&&r&&r.model!==n}function cT(t){U(t)&&(t=(new DOMParser).parseFromString(t,"text/xml"));var e=t;for(9===e.nodeType&&(e=e.firstChild);"svg"!==e.nodeName.toLowerCase()||1!==e.nodeType;)e=e.nextSibling;return e}var pT={fill:"fill",stroke:"stroke","stroke-width":"lineWidth",opacity:"opacity","fill-opacity":"fillOpacity","stroke-opacity":"strokeOpacity","stroke-dasharray":"lineDash","stroke-dashoffset":"lineDashOffset","stroke-linecap":"lineCap","stroke-linejoin":"lineJoin","stroke-miterlimit":"miterLimit","font-family":"fontFamily","font-size":"fontSize","font-style":"fontStyle","font-weight":"fontWeight","text-anchor":"textAlign",visibility:"visibility",display:"display"},dT=G(pT),fT={"alignment-baseline":"textBaseline","stop-color":"stopColor"},gT=G(fT),yT=function(){function t(){this._defs={},this._root=null}return t.prototype.parse=function(t,e){e=e||{};var n=cT(t);this._defsUsePending=[];var i=new Br;this._root=i;var r=[],o=n.getAttribute("viewBox")||"",a=parseFloat(n.getAttribute("width")||e.width),s=parseFloat(n.getAttribute("height")||e.height);isNaN(a)&&(a=null),isNaN(s)&&(s=null),wT(n,i,null,!0,!1);for(var l,u,h=n.firstChild;h;)this._parseNode(h,i,r,null,!1,!1),h=h.nextSibling;if(function(t,e){for(var n=0;n=4&&(l={x:parseFloat(c[0]||0),y:parseFloat(c[1]||0),width:parseFloat(c[2]),height:parseFloat(c[3])})}if(l&&null!=a&&null!=s&&(u=LT(l,{x:0,y:0,width:a,height:s}),!e.ignoreViewBox)){var p=i;(i=new Br).add(p),p.scaleX=p.scaleY=u.scale,p.x=u.x,p.y=u.y}return e.ignoreRootClip||null==a||null==s||i.setClipPath(new Ws({shape:{x:0,y:0,width:a,height:s}})),{root:i,width:a,height:s,viewBoxRect:l,viewBoxTransform:u,named:r}},t.prototype._parseNode=function(t,e,n,i,r,o){var a,s=t.nodeName.toLowerCase(),l=i;if("defs"===s&&(r=!0),"text"===s&&(o=!0),"defs"===s||"switch"===s)a=e;else{if(!r){var u=lT[s];if(u&&_t(lT,s)){a=u.call(this,t,e);var h=t.getAttribute("name");if(h){var c={name:h,namedFrom:null,svgNodeTagLower:s,el:a};n.push(c),"g"===s&&(l=c)}else i&&n.push({name:i.name,namedFrom:i,svgNodeTagLower:s,el:a});e.add(a)}}var p=vT[s];if(p&&_t(vT,s)){var d=p.call(this,t),f=t.getAttribute("id");f&&(this._defs[f]=d)}}if(a&&a.isGroup)for(var g=t.firstChild;g;)1===g.nodeType?this._parseNode(g,a,n,l,r,o):3===g.nodeType&&o&&this._parseText(g,a),g=g.nextSibling},t.prototype._parseText=function(t,e){var n=new Ps({style:{text:t.textContent},silent:!0,x:this._textX||0,y:this._textY||0});_T(e,n),wT(t,n,this._defsUsePending,!1,!1),function(t,e){var n=e.__selfStyle;if(n){var i=n.textBaseline,r=i;i&&"auto"!==i?"baseline"===i?r="alphabetic":"before-edge"===i||"text-before-edge"===i?r="top":"after-edge"===i||"text-after-edge"===i?r="bottom":"central"!==i&&"mathematical"!==i||(r="middle"):r="alphabetic",t.style.textBaseline=r}var o=e.__inheritedStyle;if(o){var a=o.textAlign,s=a;a&&("middle"===a&&(s="center"),t.style.textAlign=s)}}(n,e);var i=n.style,r=i.fontSize;r&&r<9&&(i.fontSize=9,n.scaleX*=r/9,n.scaleY*=r/9);var o=(i.fontSize||i.fontFamily)&&[i.fontStyle,i.fontWeight,(i.fontSize||12)+"px",i.fontFamily||"sans-serif"].join(" ");i.font=o;var a=n.getBoundingRect();return this._textX+=a.width,e.add(n),n},t.internalField=void(lT={g:function(t,e){var n=new Br;return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n},rect:function(t,e){var n=new Ws;return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n.setShape({x:parseFloat(t.getAttribute("x")||"0"),y:parseFloat(t.getAttribute("y")||"0"),width:parseFloat(t.getAttribute("width")||"0"),height:parseFloat(t.getAttribute("height")||"0")}),n.silent=!0,n},circle:function(t,e){var n=new Su;return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n.setShape({cx:parseFloat(t.getAttribute("cx")||"0"),cy:parseFloat(t.getAttribute("cy")||"0"),r:parseFloat(t.getAttribute("r")||"0")}),n.silent=!0,n},line:function(t,e){var n=new Ku;return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n.setShape({x1:parseFloat(t.getAttribute("x1")||"0"),y1:parseFloat(t.getAttribute("y1")||"0"),x2:parseFloat(t.getAttribute("x2")||"0"),y2:parseFloat(t.getAttribute("y2")||"0")}),n.silent=!0,n},ellipse:function(t,e){var n=new Iu;return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n.setShape({cx:parseFloat(t.getAttribute("cx")||"0"),cy:parseFloat(t.getAttribute("cy")||"0"),rx:parseFloat(t.getAttribute("rx")||"0"),ry:parseFloat(t.getAttribute("ry")||"0")}),n.silent=!0,n},polygon:function(t,e){var n,i=t.getAttribute("points");i&&(n=bT(i));var r=new Xu({shape:{points:n||[]},silent:!0});return _T(e,r),wT(t,r,this._defsUsePending,!1,!1),r},polyline:function(t,e){var n,i=t.getAttribute("points");i&&(n=bT(i));var r=new Zu({shape:{points:n||[]},silent:!0});return _T(e,r),wT(t,r,this._defsUsePending,!1,!1),r},image:function(t,e){var n=new Ns;return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n.setStyle({image:t.getAttribute("xlink:href")||t.getAttribute("href"),x:+t.getAttribute("x"),y:+t.getAttribute("y"),width:+t.getAttribute("width"),height:+t.getAttribute("height")}),n.silent=!0,n},text:function(t,e){var n=t.getAttribute("x")||"0",i=t.getAttribute("y")||"0",r=t.getAttribute("dx")||"0",o=t.getAttribute("dy")||"0";this._textX=parseFloat(n)+parseFloat(r),this._textY=parseFloat(i)+parseFloat(o);var a=new Br;return _T(e,a),wT(t,a,this._defsUsePending,!1,!0),a},tspan:function(t,e){var n=t.getAttribute("x"),i=t.getAttribute("y");null!=n&&(this._textX=parseFloat(n)),null!=i&&(this._textY=parseFloat(i));var r=t.getAttribute("dx")||"0",o=t.getAttribute("dy")||"0",a=new Br;return _T(e,a),wT(t,a,this._defsUsePending,!1,!0),this._textX+=parseFloat(r),this._textY+=parseFloat(o),a},path:function(t,e){var n=_u(t.getAttribute("d")||"");return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n.silent=!0,n}}),t}(),vT={lineargradient:function(t){var e=parseInt(t.getAttribute("x1")||"0",10),n=parseInt(t.getAttribute("y1")||"0",10),i=parseInt(t.getAttribute("x2")||"10",10),r=parseInt(t.getAttribute("y2")||"0",10),o=new oh(e,n,i,r);return mT(t,o),xT(t,o),o},radialgradient:function(t){var e=parseInt(t.getAttribute("cx")||"0",10),n=parseInt(t.getAttribute("cy")||"0",10),i=parseInt(t.getAttribute("r")||"0",10),r=new ah(e,n,i);return mT(t,r),xT(t,r),r}};function mT(t,e){"userSpaceOnUse"===t.getAttribute("gradientUnits")&&(e.global=!0)}function xT(t,e){for(var n=t.firstChild;n;){if(1===n.nodeType&&"stop"===n.nodeName.toLocaleLowerCase()){var i=n.getAttribute("offset"),r=void 0;r=i&&i.indexOf("%")>0?parseInt(i,10)/100:i?parseFloat(i):0;var o={};kT(n,o,o);var a=o.stopColor||n.getAttribute("stop-color")||"#000000";e.colorStops.push({offset:r,color:a})}n=n.nextSibling}}function _T(t,e){t&&t.__inheritedStyle&&(e.__inheritedStyle||(e.__inheritedStyle={}),k(e.__inheritedStyle,t.__inheritedStyle))}function bT(t){for(var e=TT(t),n=[],i=0;i0;o-=2){var a=i[o],s=i[o-1],l=TT(a);switch(r=r||[1,0,0,1,0,0],s){case"translate":we(r,r,[parseFloat(l[0]),parseFloat(l[1]||"0")]);break;case"scale":Me(r,r,[parseFloat(l[0]),parseFloat(l[1]||l[0])]);break;case"rotate":Se(r,r,-parseFloat(l[0])*DT,[parseFloat(l[1]||"0"),parseFloat(l[2]||"0")]);break;case"skewX":be(r,[1,0,Math.tan(parseFloat(l[0])*DT),1,0,0],r);break;case"skewY":be(r,[1,Math.tan(parseFloat(l[0])*DT),0,1,0,0],r);break;case"matrix":r[0]=parseFloat(l[0]),r[1]=parseFloat(l[1]),r[2]=parseFloat(l[2]),r[3]=parseFloat(l[3]),r[4]=parseFloat(l[4]),r[5]=parseFloat(l[5])}}e.setLocalTransform(r)}}(t,e),kT(t,a,s),i||function(t,e,n){for(var i=0;i0,f={api:n,geo:s,mapOrGeoModel:t,data:a,isVisualEncodedByVisualMap:d,isGeo:o,transformInfoRaw:c};"geoJSON"===s.resourceType?this._buildGeoJSON(f):"geoSVG"===s.resourceType&&this._buildSVG(f),this._updateController(t,e,n),this._updateMapSelectHandler(t,l,n,i)},t.prototype._buildGeoJSON=function(t){var e=this._regionsGroupByName=yt(),n=yt(),i=this._regionsGroup,r=t.transformInfoRaw,o=t.mapOrGeoModel,a=t.data,s=t.geo.projection,l=s&&s.stream;function u(t,e){return e&&(t=e(t)),t&&[t[0]*r.scaleX+r.x,t[1]*r.scaleY+r.y]}function h(t){for(var e=[],n=!l&&s&&s.project,i=0;i=0)&&(p=r);var d=a?{normal:{align:"center",verticalAlign:"middle"}}:null;ic(e,rc(i),{labelFetcher:p,labelDataIndex:c,defaultText:n},d);var f=e.getTextContent();if(f&&(JT(f).ignore=f.ignore,e.textConfig&&a)){var g=e.getBoundingRect().clone();e.textConfig.layoutRect=g,e.textConfig.position=[(a[0]-g.x)/g.width*100+"%",(a[1]-g.y)/g.height*100+"%"]}e.disableLabelAnimation=!0}else e.removeTextContent(),e.removeTextConfig(),e.disableLabelAnimation=null}function rC(t,e,n,i,r,o){t.data?t.data.setItemGraphicEl(o,e):rl(e).eventData={componentType:"geo",componentIndex:r.componentIndex,geoIndex:r.componentIndex,name:n,region:i&&i.option||{}}}function oC(t,e,n,i,r){t.data||Kh({el:e,componentModel:r,itemName:n,itemTooltipOption:i.get("tooltip")})}function aC(t,e,n,i,r){e.highDownSilentOnTouch=!!r.get("selectedMode");var o=i.getModel("emphasis"),a=o.get("focus");return Zl(e,a,o.get("blurScope"),o.get("disabled")),t.isGeo&&function(t,e,n){var i=rl(t);i.componentMainType=e.mainType,i.componentIndex=e.componentIndex,i.componentHighDownName=n}(e,r,n),a}function sC(t,e,n){var i,r=[];function o(){i=[]}function a(){i.length&&(r.push(i),i=[])}var s=e({polygonStart:o,polygonEnd:a,lineStart:o,lineEnd:a,point:function(t,e){isFinite(t)&&isFinite(e)&&i.push([t,e])},sphere:function(){}});return!n&&s.polygonStart(),E(t,(function(t){s.lineStart();for(var e=0;e-1&&(n.style.stroke=n.style.fill,n.style.fill="#fff",n.style.lineWidth=2),n},e.type="series.map",e.dependencies=["geo"],e.layoutMode="box",e.defaultOption={z:2,coordinateSystem:"geo",map:"",left:"center",top:"center",aspectScale:null,showLegendSymbol:!0,boundingCoords:null,center:null,zoom:1,scaleLimit:null,selectedMode:!0,label:{show:!1,color:"#000"},itemStyle:{borderWidth:.5,borderColor:"#444",areaColor:"#eee"},emphasis:{label:{show:!0,color:"rgb(100,0,0)"},itemStyle:{areaColor:"rgba(255,215,0,0.8)"}},select:{label:{show:!0,color:"rgb(100,0,0)"},itemStyle:{color:"rgba(255,215,0,0.8)"}},nameProperty:"name"},e}(bg);function hC(t){var e={};t.eachSeriesByType("map",(function(t){var n=t.getHostGeoModel(),i=n?"o"+n.id:"i"+t.getMapType();(e[i]=e[i]||[]).push(t)})),E(e,(function(t,e){for(var n,i,r,o=(n=z(t,(function(t){return t.getData()})),i=t[0].get("mapValueCalculation"),r={},E(n,(function(t){t.each(t.mapDimension("value"),(function(e,n){var i="ec-"+t.getName(n);r[i]=r[i]||[],isNaN(e)||r[i].push(e)}))})),n[0].map(n[0].mapDimension("value"),(function(t,e){for(var o="ec-"+n[0].getName(e),a=0,s=1/0,l=-1/0,u=r[o].length,h=0;h1?(d.width=p,d.height=p/x):(d.height=p,d.width=p*x),d.y=c[1]-d.height/2,d.x=c[0]-d.width/2;else{var b=t.getBoxLayoutParams();b.aspect=x,d=kp(b,{width:v,height:m})}this.setViewRect(d.x,d.y,d.width,d.height),this.setCenter(t.get("center"),e),this.setZoom(t.get("zoom"))}R(vC,dC);var _C=function(){function t(){this.dimensions=yC}return t.prototype.create=function(t,e){var n=[];function i(t){return{nameProperty:t.get("nameProperty"),aspectScale:t.get("aspectScale"),projection:t.get("projection")}}t.eachComponent("geo",(function(t,r){var o=t.get("map"),a=new vC(o+r,o,A({nameMap:t.get("nameMap")},i(t)));a.zoomLimit=t.get("scaleLimit"),n.push(a),t.coordinateSystem=a,a.model=t,a.resize=xC,a.resize(t,e)})),t.eachSeries((function(t){if("geo"===t.get("coordinateSystem")){var e=t.get("geoIndex")||0;t.coordinateSystem=n[e]}}));var r={};return t.eachSeriesByType("map",(function(t){if(!t.getHostGeoModel()){var e=t.getMapType();r[e]=r[e]||[],r[e].push(t)}})),E(r,(function(t,r){var o=z(t,(function(t){return t.get("nameMap")})),a=new vC(r,r,A({nameMap:D(o)},i(t[0])));a.zoomLimit=it.apply(null,z(t,(function(t){return t.get("scaleLimit")}))),n.push(a),a.resize=xC,a.resize(t[0],e),E(t,(function(t){t.coordinateSystem=a,function(t,e){E(e.get("geoCoord"),(function(e,n){t.addGeoCoord(n,e)}))}(a,t)}))})),n},t.prototype.getFilledRegions=function(t,e,n,i){for(var r=(t||[]).slice(),o=yt(),a=0;a=0;){var o=e[n];o.hierNode.prelim+=i,o.hierNode.modifier+=i,r+=o.hierNode.change,i+=o.hierNode.shift+r}}(t);var o=(n[0].hierNode.prelim+n[n.length-1].hierNode.prelim)/2;r?(t.hierNode.prelim=r.hierNode.prelim+e(t,r),t.hierNode.modifier=t.hierNode.prelim-o):t.hierNode.prelim=o}else r&&(t.hierNode.prelim=r.hierNode.prelim+e(t,r));t.parentNode.hierNode.defaultAncestor=function(t,e,n,i){if(e){for(var r=t,o=t,a=o.parentNode.children[0],s=e,l=r.hierNode.modifier,u=o.hierNode.modifier,h=a.hierNode.modifier,c=s.hierNode.modifier;s=PC(s),o=OC(o),s&&o;){r=PC(r),a=OC(a),r.hierNode.ancestor=t;var p=s.hierNode.prelim+c-o.hierNode.prelim-u+i(s,o);p>0&&(NC(RC(s,t,n),t,p),u+=p,l+=p),c+=s.hierNode.modifier,u+=o.hierNode.modifier,l+=r.hierNode.modifier,h+=a.hierNode.modifier}s&&!PC(r)&&(r.hierNode.thread=s,r.hierNode.modifier+=c-l),o&&!OC(a)&&(a.hierNode.thread=o,a.hierNode.modifier+=u-h,n=t)}return n}(t,r,t.parentNode.hierNode.defaultAncestor||i[0],e)}function AC(t){var e=t.hierNode.prelim+t.parentNode.hierNode.modifier;t.setLayout({x:e},!0),t.hierNode.modifier+=t.parentNode.hierNode.modifier}function kC(t){return arguments.length?t:EC}function LC(t,e){return t-=Math.PI/2,{x:e*Math.cos(t),y:e*Math.sin(t)}}function PC(t){var e=t.children;return e.length&&t.isExpand?e[e.length-1]:t.hierNode.thread}function OC(t){var e=t.children;return e.length&&t.isExpand?e[0]:t.hierNode.thread}function RC(t,e,n){return t.hierNode.ancestor.parentNode===e.parentNode?t.hierNode.ancestor:n}function NC(t,e,n){var i=n/(e.hierNode.i-t.hierNode.i);e.hierNode.change-=i,e.hierNode.shift+=n,e.hierNode.modifier+=n,e.hierNode.prelim+=n,t.hierNode.change+=i}function EC(t,e){return t.parentNode===e.parentNode?1:2}var zC=function(){this.parentPoint=[],this.childPoints=[]},VC=function(t){function e(e){return t.call(this,e)||this}return n(e,t),e.prototype.getDefaultStyle=function(){return{stroke:"#000",fill:null}},e.prototype.getDefaultShape=function(){return new zC},e.prototype.buildPath=function(t,e){var n=e.childPoints,i=n.length,r=e.parentPoint,o=n[0],a=n[i-1];if(1===i)return t.moveTo(r[0],r[1]),void t.lineTo(o[0],o[1]);var s=e.orient,l="TB"===s||"BT"===s?0:1,u=1-l,h=$r(e.forkPosition,1),c=[];c[l]=r[l],c[u]=r[u]+(a[u]-r[u])*h,t.moveTo(r[0],r[1]),t.lineTo(c[0],c[1]),t.moveTo(o[0],o[1]),c[l]=o[l],t.lineTo(c[0],c[1]),c[l]=a[l],t.lineTo(c[0],c[1]),t.lineTo(a[0],a[1]);for(var p=1;pm.x)||(_-=Math.PI);var S=b?"left":"right",M=s.getModel("label"),I=M.get("rotate"),T=I*(Math.PI/180),C=y.getTextContent();C&&(y.setTextConfig({position:M.get("position")||S,rotation:null==I?-_:T,origin:"center"}),C.setStyle("verticalAlign","middle"))}var D=s.get(["emphasis","focus"]),A="relative"===D?vt(a.getAncestorsIndices(),a.getDescendantIndices()):"ancestor"===D?a.getAncestorsIndices():"descendant"===D?a.getDescendantIndices():null;A&&(rl(n).focus=A),function(t,e,n,i,r,o,a,s){var l=e.getModel(),u=t.get("edgeShape"),h=t.get("layout"),c=t.getOrient(),p=t.get(["lineStyle","curveness"]),d=t.get("edgeForkPosition"),f=l.getModel("lineStyle").getLineStyle(),g=i.__edge;if("curve"===u)e.parentNode&&e.parentNode!==n&&(g||(g=i.__edge=new th({shape:XC(h,c,p,r,r)})),vh(g,{shape:XC(h,c,p,o,a)},t));else if("polyline"===u)if("orthogonal"===h){if(e!==n&&e.children&&0!==e.children.length&&!0===e.isExpand){for(var y=e.children,v=[],m=0;me&&(e=i.height)}this.height=e+1},t.prototype.getNodeById=function(t){if(this.getId()===t)return this;for(var e=0,n=this.children,i=n.length;e=0&&this.hostTree.data.setItemLayout(this.dataIndex,t,e)},t.prototype.getLayout=function(){return this.hostTree.data.getItemLayout(this.dataIndex)},t.prototype.getModel=function(t){if(!(this.dataIndex<0))return this.hostTree.data.getItemModel(this.dataIndex).getModel(t)},t.prototype.getLevelModel=function(){return(this.hostTree.levelModels||[])[this.depth]},t.prototype.setVisual=function(t,e){this.dataIndex>=0&&this.hostTree.data.setItemVisual(this.dataIndex,t,e)},t.prototype.getVisual=function(t){return this.hostTree.data.getItemVisual(this.dataIndex,t)},t.prototype.getRawIndex=function(){return this.hostTree.data.getRawIndex(this.dataIndex)},t.prototype.getId=function(){return this.hostTree.data.getId(this.dataIndex)},t.prototype.getChildIndex=function(){if(this.parentNode){for(var t=this.parentNode.children,e=0;e=0){var i=n.getData().tree.root,r=t.targetNode;if(U(r)&&(r=i.getNodeById(r)),r&&i.contains(r))return{node:r};var o=t.targetNodeId;if(null!=o&&(r=i.getNodeById(o)))return{node:r}}}function rD(t){for(var e=[];t;)(t=t.parentNode)&&e.push(t);return e.reverse()}function oD(t,e){return P(rD(t),e)>=0}function aD(t,e){for(var n=[];t;){var i=t.dataIndex;n.push({name:t.name,dataIndex:i,value:e.getRawValue(i)}),t=t.parentNode}return n.reverse(),n}var sD=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.hasSymbolVisual=!0,e.ignoreStyleOnData=!0,e}return n(e,t),e.prototype.getInitialData=function(t){var e={name:t.name,children:t.data},n=t.leaves||{},i=new Cc(n,this,this.ecModel),r=nD.createTree(e,this,(function(t){t.wrapMethod("getItemModel",(function(t,e){var n=r.getNodeByDataIndex(e);return n&&n.children.length&&n.isExpand||(t.parentModel=i),t}))}));var o=0;r.eachNode("preorder",(function(t){t.depth>o&&(o=t.depth)}));var a=t.expandAndCollapse&&t.initialTreeDepth>=0?t.initialTreeDepth:o;return r.root.eachNode("preorder",(function(t){var e=t.hostTree.data.getRawDataItem(t.dataIndex);t.isExpand=e&&null!=e.collapsed?!e.collapsed:t.depth<=a})),r.data},e.prototype.getOrient=function(){var t=this.get("orient");return"horizontal"===t?t="LR":"vertical"===t&&(t="TB"),t},e.prototype.setZoom=function(t){this.option.zoom=t},e.prototype.setCenter=function(t){this.option.center=t},e.prototype.formatTooltip=function(t,e,n){for(var i=this.getData().tree,r=i.root.children[0],o=i.getNodeByDataIndex(t),a=o.getValue(),s=o.name;o&&o!==r;)s=o.parentNode.name+"."+s,o=o.parentNode;return og("nameValue",{name:s,value:a,noValue:isNaN(a)||null==a})},e.prototype.getDataParams=function(e){var n=t.prototype.getDataParams.apply(this,arguments),i=this.getData().tree.getNodeByDataIndex(e);return n.treeAncestors=aD(i,this),n.collapsed=!i.isExpand,n},e.type="series.tree",e.layoutMode="box",e.defaultOption={z:2,coordinateSystem:"view",left:"12%",top:"12%",right:"12%",bottom:"12%",layout:"orthogonal",edgeShape:"curve",edgeForkPosition:"50%",roam:!1,nodeScaleRatio:.4,center:null,zoom:1,orient:"LR",symbol:"emptyCircle",symbolSize:7,expandAndCollapse:!0,initialTreeDepth:2,lineStyle:{color:"#ccc",width:1.5,curveness:.5},itemStyle:{color:"lightsteelblue",borderWidth:1.5},label:{show:!0},animationEasing:"linear",animationDuration:700,animationDurationUpdate:500},e}(bg);function lD(t,e){for(var n,i=[t];n=i.pop();)if(e(n),n.isExpand){var r=n.children;if(r.length)for(var o=r.length-1;o>=0;o--)i.push(r[o])}}function uD(t,e){t.eachSeriesByType("tree",(function(t){!function(t,e){var n=function(t,e){return kp(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()})}(t,e);t.layoutInfo=n;var i=t.get("layout"),r=0,o=0,a=null;"radial"===i?(r=2*Math.PI,o=Math.min(n.height,n.width)/2,a=kC((function(t,e){return(t.parentNode===e.parentNode?1:2)/t.depth}))):(r=n.width,o=n.height,a=kC());var s=t.getData().tree.root,l=s.children[0];if(l){!function(t){var e=t;e.hierNode={defaultAncestor:null,ancestor:e,prelim:0,modifier:0,change:0,shift:0,i:0,thread:null};for(var n,i,r=[e];n=r.pop();)if(i=n.children,n.isExpand&&i.length)for(var o=i.length-1;o>=0;o--){var a=i[o];a.hierNode={defaultAncestor:null,ancestor:a,prelim:0,modifier:0,change:0,shift:0,i:o,thread:null},r.push(a)}}(s),function(t,e,n){for(var i,r=[t],o=[];i=r.pop();)if(o.push(i),i.isExpand){var a=i.children;if(a.length)for(var s=0;sh.getLayout().x&&(h=t),t.depth>c.depth&&(c=t)}));var p=u===h?1:a(u,h)/2,d=p-u.getLayout().x,f=0,g=0,y=0,v=0;if("radial"===i)f=r/(h.getLayout().x+p+d),g=o/(c.depth-1||1),lD(l,(function(t){y=(t.getLayout().x+d)*f,v=(t.depth-1)*g;var e=LC(y,v);t.setLayout({x:e.x,y:e.y,rawX:y,rawY:v},!0)}));else{var m=t.getOrient();"RL"===m||"LR"===m?(g=o/(h.getLayout().x+p+d),f=r/(c.depth-1||1),lD(l,(function(t){v=(t.getLayout().x+d)*g,y="LR"===m?(t.depth-1)*f:r-(t.depth-1)*f,t.setLayout({x:y,y:v},!0)}))):"TB"!==m&&"BT"!==m||(f=r/(h.getLayout().x+p+d),g=o/(c.depth-1||1),lD(l,(function(t){y=(t.getLayout().x+d)*f,v="TB"===m?(t.depth-1)*g:o-(t.depth-1)*g,t.setLayout({x:y,y:v},!0)})))}}}(t,e)}))}function hD(t){t.eachSeriesByType("tree",(function(t){var e=t.getData();e.tree.eachNode((function(t){var n=t.getModel().getModel("itemStyle").getItemStyle();A(e.ensureUniqueItemVisual(t.dataIndex,"style"),n)}))}))}var cD=["treemapZoomToNode","treemapRender","treemapMove"];function pD(t){var e=t.getData().tree,n={};e.eachNode((function(e){for(var i=e;i&&i.depth>1;)i=i.parentNode;var r=pd(t.ecModel,i.name||i.dataIndex+"",n);e.setVisual("decal",r)}))}var dD=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.preventUsingHoverLayer=!0,n}return n(e,t),e.prototype.getInitialData=function(t,e){var n={name:t.name,children:t.data};fD(n);var i=t.levels||[],r=this.designatedVisualItemStyle={},o=new Cc({itemStyle:r},this,e);i=t.levels=function(t,e){var n,i,r=To(e.get("color")),o=To(e.get(["aria","decal","decals"]));if(!r)return;t=t||[],E(t,(function(t){var e=new Cc(t),r=e.get("color"),o=e.get("decal");(e.get(["itemStyle","color"])||r&&"none"!==r)&&(n=!0),(e.get(["itemStyle","decal"])||o&&"none"!==o)&&(i=!0)}));var a=t[0]||(t[0]={});n||(a.color=r.slice());!i&&o&&(a.decal=o.slice());return t}(i,e);var a=z(i||[],(function(t){return new Cc(t,o,e)}),this),s=nD.createTree(n,this,(function(t){t.wrapMethod("getItemModel",(function(t,e){var n=s.getNodeByDataIndex(e),i=n?a[n.depth]:null;return t.parentModel=i||o,t}))}));return s.data},e.prototype.optionUpdated=function(){this.resetViewRoot()},e.prototype.formatTooltip=function(t,e,n){var i=this.getData(),r=this.getRawValue(t);return og("nameValue",{name:i.getName(t),value:r})},e.prototype.getDataParams=function(e){var n=t.prototype.getDataParams.apply(this,arguments),i=this.getData().tree.getNodeByDataIndex(e);return n.treeAncestors=aD(i,this),n.treePathInfo=n.treeAncestors,n},e.prototype.setLayoutInfo=function(t){this.layoutInfo=this.layoutInfo||{},A(this.layoutInfo,t)},e.prototype.mapIdToIndex=function(t){var e=this._idIndexMap;e||(e=this._idIndexMap=yt(),this._idIndexMapCount=0);var n=e.get(t);return null==n&&e.set(t,n=this._idIndexMapCount++),n},e.prototype.getViewRoot=function(){return this._viewRoot},e.prototype.resetViewRoot=function(t){t?this._viewRoot=t:t=this._viewRoot;var e=this.getRawData().tree.root;t&&(t===e||e.contains(t))||(this._viewRoot=e)},e.prototype.enableAriaDecal=function(){pD(this)},e.type="series.treemap",e.layoutMode="box",e.defaultOption={progressive:0,left:"center",top:"middle",width:"80%",height:"80%",sort:!0,clipWindow:"origin",squareRatio:.5*(1+Math.sqrt(5)),leafDepth:null,drillDownIcon:"▶",zoomToNodeRatio:.1024,scaleLimit:null,roam:!0,nodeClick:"zoomToNode",animation:!0,animationDurationUpdate:900,animationEasing:"quinticInOut",breadcrumb:{show:!0,height:22,left:"center",top:"bottom",emptyItemWidth:25,itemStyle:{color:"rgba(0,0,0,0.7)",textStyle:{color:"#fff"}},emphasis:{itemStyle:{color:"rgba(0,0,0,0.9)"}}},label:{show:!0,distance:0,padding:5,position:"inside",color:"#fff",overflow:"truncate"},upperLabel:{show:!1,position:[0,"50%"],height:20,overflow:"truncate",verticalAlign:"middle"},itemStyle:{color:null,colorAlpha:null,colorSaturation:null,borderWidth:0,gapWidth:0,borderColor:"#fff",borderColorSaturation:null},emphasis:{upperLabel:{show:!0,position:[0,"50%"],overflow:"truncate",verticalAlign:"middle"}},visualDimension:0,visualMin:null,visualMax:null,color:[],colorAlpha:null,colorSaturation:null,colorMappingBy:"index",visibleMin:10,childrenVisibleMin:null,levels:[]},e}(bg);function fD(t){var e=0;E(t.children,(function(t){fD(t);var n=t.value;Y(n)&&(n=n[0]),e+=n}));var n=t.value;Y(n)&&(n=n[0]),(null==n||isNaN(n))&&(n=e),n<0&&(n=0),Y(t.value)?t.value[0]=n:t.value=n}var gD=function(){function t(t){this.group=new Br,t.add(this.group)}return t.prototype.render=function(t,e,n,i){var r=t.getModel("breadcrumb"),o=this.group;if(o.removeAll(),r.get("show")&&n){var a=r.getModel("itemStyle"),s=r.getModel("emphasis"),l=a.getModel("textStyle"),u=s.getModel(["itemStyle","textStyle"]),h={pos:{left:r.get("left"),right:r.get("right"),top:r.get("top"),bottom:r.get("bottom")},box:{width:e.getWidth(),height:e.getHeight()},emptyItemWidth:r.get("emptyItemWidth"),totalWidth:0,renderList:[]};this._prepare(n,h,l),this._renderContent(t,h,a,s,l,u,i),Lp(o,h.pos,h.box)}},t.prototype._prepare=function(t,e,n){for(var i=t;i;i=i.parentNode){var r=Ro(i.getModel().get("name"),""),o=n.getTextRect(r),a=Math.max(o.width+16,e.emptyItemWidth);e.totalWidth+=a+8,e.renderList.push({node:i,text:r,width:a})}},t.prototype._renderContent=function(t,e,n,i,r,o,a){for(var s,l,u,h,c,p,d,f,g,y=0,v=e.emptyItemWidth,m=t.get(["breadcrumb","height"]),x=(s=e.pos,l=e.box,h=l.width,c=l.height,p=$r(s.left,h),d=$r(s.top,c),f=$r(s.right,h),g=$r(s.bottom,c),(isNaN(p)||isNaN(parseFloat(s.left)))&&(p=0),(isNaN(f)||isNaN(parseFloat(s.right)))&&(f=h),(isNaN(d)||isNaN(parseFloat(s.top)))&&(d=0),(isNaN(g)||isNaN(parseFloat(s.bottom)))&&(g=c),u=vp(u||0),{width:Math.max(f-p-u[1]-u[3],0),height:Math.max(g-d-u[0]-u[2],0)}),_=e.totalWidth,b=e.renderList,w=i.getModel("itemStyle").getItemStyle(),S=b.length-1;S>=0;S--){var M=b[S],I=M.node,T=M.width,C=M.text;_>x.width&&(_-=T-v,T=v,C=null);var D=new Xu({shape:{points:yD(y,0,T,m,S===b.length-1,0===S)},style:k(n.getItemStyle(),{lineJoin:"bevel"}),textContent:new Xs({style:oc(r,{text:C})}),textConfig:{position:"inside"},z2:1e5,onclick:H(a,I)});D.disableLabelAnimation=!0,D.getTextContent().ensureState("emphasis").style=oc(o,{text:C}),D.ensureState("emphasis").style=w,Zl(D,i.get("focus"),i.get("blurScope"),i.get("disabled")),this.group.add(D),vD(D,t,I),y+=T+8}},t.prototype.remove=function(){this.group.removeAll()},t}();function yD(t,e,n,i,r,o){var a=[[r?t:t-5,e],[t+n,e],[t+n,e+i],[r?t:t-5,e+i]];return!o&&a.splice(2,0,[t+n+5,e+i/2]),!r&&a.push([t,e+i/2]),a}function vD(t,e,n){rl(t).eventData={componentType:"series",componentSubType:"treemap",componentIndex:e.componentIndex,seriesIndex:e.seriesIndex,seriesName:e.name,seriesType:"treemap",selfType:"breadcrumb",nodeData:{dataIndex:n&&n.dataIndex,name:n&&n.name},treePathInfo:n&&aD(n,e)}}var mD=function(){function t(){this._storage=[],this._elExistsMap={}}return t.prototype.add=function(t,e,n,i,r){return!this._elExistsMap[t.id]&&(this._elExistsMap[t.id]=!0,this._storage.push({el:t,target:e,duration:n,delay:i,easing:r}),!0)},t.prototype.finished=function(t){return this._finishedCallback=t,this},t.prototype.start=function(){for(var t=this,e=this._storage.length,n=function(){--e<=0&&(t._storage.length=0,t._elExistsMap={},t._finishedCallback&&t._finishedCallback())},i=0,r=this._storage.length;i3||Math.abs(t.dy)>3)){var e=this.seriesModel.getData().tree.root;if(!e)return;var n=e.getLayout();if(!n)return;this.api.dispatchAction({type:"treemapMove",from:this.uid,seriesId:this.seriesModel.id,rootRect:{x:n.x+t.dx,y:n.y+t.dy,width:n.width,height:n.height}})}},e.prototype._onZoom=function(t){var e=t.originX,n=t.originY,i=t.scale;if("animating"!==this._state){var r=this.seriesModel.getData().tree.root;if(!r)return;var o=r.getLayout();if(!o)return;var a,s=new ze(o.x,o.y,o.width,o.height),l=this._controllerHost;a=l.zoomLimit;var u=l.zoom=l.zoom||1;if(u*=i,a){var h=a.min||0,c=a.max||1/0;u=Math.max(Math.min(c,u),h)}var p=u/l.zoom;l.zoom=u;var d=this.seriesModel.layoutInfo,f=[1,0,0,1,0,0];we(f,f,[-(e-=d.x),-(n-=d.y)]),Me(f,f,[p,p]),we(f,f,[e,n]),s.applyTransform(f),this.api.dispatchAction({type:"treemapRender",from:this.uid,seriesId:this.seriesModel.id,rootRect:{x:s.x,y:s.y,width:s.width,height:s.height}})}},e.prototype._initEvents=function(t){var e=this;t.on("click",(function(t){if("ready"===e._state){var n=e.seriesModel.get("nodeClick",!0);if(n){var i=e.findTarget(t.offsetX,t.offsetY);if(i){var r=i.node;if(r.getLayout().isLeafRoot)e._rootToNode(i);else if("zoomToNode"===n)e._zoomToNode(i);else if("link"===n){var o=r.hostTree.data.getItemModel(r.dataIndex),a=o.get("link",!0),s=o.get("target",!0)||"blank";a&&Mp(a,s)}}}}}),this)},e.prototype._renderBreadcrumb=function(t,e,n){var i=this;n||(n=null!=t.get("leafDepth",!0)?{node:t.getViewRoot()}:this.findTarget(e.getWidth()/2,e.getHeight()/2))||(n={node:t.getData().tree.root}),(this._breadcrumb||(this._breadcrumb=new gD(this.group))).render(t,e,n.node,(function(e){"animating"!==i._state&&(oD(t.getViewRoot(),e)?i._rootToNode({node:e}):i._zoomToNode({node:e}))}))},e.prototype.remove=function(){this._clearController(),this._containerGroup&&this._containerGroup.removeAll(),this._storage={nodeGroup:[],background:[],content:[]},this._state="ready",this._breadcrumb&&this._breadcrumb.remove()},e.prototype.dispose=function(){this._clearController()},e.prototype._zoomToNode=function(t){this.api.dispatchAction({type:"treemapZoomToNode",from:this.uid,seriesId:this.seriesModel.id,targetNode:t.node})},e.prototype._rootToNode=function(t){this.api.dispatchAction({type:"treemapRootToNode",from:this.uid,seriesId:this.seriesModel.id,targetNode:t.node})},e.prototype.findTarget=function(t,e){var n;return this.seriesModel.getViewRoot().eachNode({attr:"viewChildren",order:"preorder"},(function(i){var r=this._storage.background[i.getRawIndex()];if(r){var o=r.transformCoordToLocal(t,e),a=r.shape;if(!(a.x<=o[0]&&o[0]<=a.x+a.width&&a.y<=o[1]&&o[1]<=a.y+a.height))return!1;n={node:i,offsetX:o[0],offsetY:o[1]}}}),this),n},e.type="treemap",e}(Og);var CD=E,DD=q,AD=-1,kD=function(){function t(e){var n=e.mappingMethod,i=e.type,r=this.option=T(e);this.type=i,this.mappingMethod=n,this._normalizeData=FD[n];var o=t.visualHandlers[i];this.applyVisual=o.applyVisual,this.getColorMapper=o.getColorMapper,this._normalizedToVisual=o._normalizedToVisual[n],"piecewise"===n?(LD(r),function(t){var e=t.pieceList;t.hasSpecialVisual=!1,E(e,(function(e,n){e.originIndex=n,null!=e.visual&&(t.hasSpecialVisual=!0)}))}(r)):"category"===n?r.categories?function(t){var e=t.categories,n=t.categoryMap={},i=t.visual;if(CD(e,(function(t,e){n[t]=e})),!Y(i)){var r=[];q(i)?CD(i,(function(t,e){var i=n[e];r[null!=i?i:AD]=t})):r[-1]=i,i=BD(t,r)}for(var o=e.length-1;o>=0;o--)null==i[o]&&(delete n[e[o]],e.pop())}(r):LD(r,!0):(lt("linear"!==n||r.dataExtent),LD(r))}return t.prototype.mapValueToVisual=function(t){var e=this._normalizeData(t);return this._normalizedToVisual(e,t)},t.prototype.getNormalizer=function(){return W(this._normalizeData,this)},t.listVisualTypes=function(){return G(t.visualHandlers)},t.isValidType=function(e){return t.visualHandlers.hasOwnProperty(e)},t.eachVisual=function(t,e,n){q(t)?E(t,e,n):e.call(n,t)},t.mapVisual=function(e,n,i){var r,o=Y(e)?[]:q(e)?{}:(r=!0,null);return t.eachVisual(e,(function(t,e){var a=n.call(i,t,e);r?o=a:o[e]=a})),o},t.retrieveVisuals=function(e){var n,i={};return e&&CD(t.visualHandlers,(function(t,r){e.hasOwnProperty(r)&&(i[r]=e[r],n=!0)})),n?i:null},t.prepareVisualTypes=function(t){if(Y(t))t=t.slice();else{if(!DD(t))return[];var e=[];CD(t,(function(t,n){e.push(n)})),t=e}return t.sort((function(t,e){return"color"===e&&"color"!==t&&0===t.indexOf("color")?1:-1})),t},t.dependsOn=function(t,e){return"color"===e?!(!t||0!==t.indexOf(e)):t===e},t.findPieceIndex=function(t,e,n){for(var i,r=1/0,o=0,a=e.length;ou[1]&&(u[1]=l);var h=e.get("colorMappingBy"),c={type:a.name,dataExtent:u,visual:a.range};"color"!==c.type||"index"!==h&&"id"!==h?c.mappingMethod="linear":(c.mappingMethod="category",c.loop=!0);var p=new kD(c);return WD(p).drColorMappingBy=h,p}(0,r,o,0,u,d);E(d,(function(t,e){if(t.depth>=n.length||t===n[t.depth]){var o=function(t,e,n,i,r,o){var a=A({},e);if(r){var s=r.type,l="color"===s&&WD(r).drColorMappingBy,u="index"===l?i:"id"===l?o.mapIdToIndex(n.getId()):n.getValue(t.get("visualDimension"));a[s]=r.mapValueToVisual(u)}return a}(r,u,t,e,f,i);YD(t,o,n,i)}}))}else s=XD(u),h.fill=s}}function XD(t){var e=UD(t,"color");if(e){var n=UD(t,"colorAlpha"),i=UD(t,"colorSaturation");return i&&(e=ni(e,null,null,i)),n&&(e=ii(e,n)),e}}function UD(t,e){var n=t[e];if(null!=n&&"none"!==n)return n}function ZD(t,e){var n=t.get(e);return Y(n)&&n.length?{name:e,range:n}:null}var jD=Math.max,qD=Math.min,KD=it,$D=E,JD=["itemStyle","borderWidth"],QD=["itemStyle","gapWidth"],tA=["upperLabel","show"],eA=["upperLabel","height"],nA={seriesType:"treemap",reset:function(t,e,n,i){var r=n.getWidth(),o=n.getHeight(),a=t.option,s=kp(t.getBoxLayoutParams(),{width:n.getWidth(),height:n.getHeight()}),l=a.size||[],u=$r(KD(s.width,l[0]),r),h=$r(KD(s.height,l[1]),o),c=i&&i.type,p=iD(i,["treemapZoomToNode","treemapRootToNode"],t),d="treemapRender"===c||"treemapMove"===c?i.rootRect:null,f=t.getViewRoot(),g=rD(f);if("treemapMove"!==c){var y="treemapZoomToNode"===c?function(t,e,n,i,r){var o,a=(e||{}).node,s=[i,r];if(!a||a===n)return s;var l=i*r,u=l*t.option.zoomToNodeRatio;for(;o=a.parentNode;){for(var h=0,c=o.children,p=0,d=c.length;poo&&(u=oo),a=o}ua[1]&&(a[1]=e)}))):a=[NaN,NaN];return{sum:i,dataExtent:a}}(e,a,s);if(0===u.sum)return t.viewChildren=[];if(u.sum=function(t,e,n,i,r){if(!i)return n;for(var o=t.get("visibleMin"),a=r.length,s=a,l=a-1;l>=0;l--){var u=r["asc"===i?a-l-1:l].getValue();u/n*ei&&(i=a));var l=t.area*t.area,u=e*e*n;return l?jD(u*i/l,l/(u*r)):1/0}function oA(t,e,n,i,r){var o=e===n.width?0:1,a=1-o,s=["x","y"],l=["width","height"],u=n[s[o]],h=e?t.area/e:0;(r||h>n[l[a]])&&(h=n[l[a]]);for(var c=0,p=t.length;ci&&(i=e);var o=i%2?i+2:i+3;r=[];for(var a=0;a0&&(m[0]=-m[0],m[1]=-m[1]);var _=v[0]<0?-1:1;if("start"!==i.__position&&"end"!==i.__position){var b=-Math.atan2(v[1],v[0]);u[0].8?"left":h[0]<-.8?"right":"center",p=h[1]>.8?"top":h[1]<-.8?"bottom":"middle";break;case"start":i.x=-h[0]*f+l[0],i.y=-h[1]*g+l[1],c=h[0]>.8?"right":h[0]<-.8?"left":"center",p=h[1]>.8?"bottom":h[1]<-.8?"top":"middle";break;case"insideStartTop":case"insideStart":case"insideStartBottom":i.x=f*_+l[0],i.y=l[1]+w,c=v[0]<0?"right":"left",i.originX=-f*_,i.originY=-w;break;case"insideMiddleTop":case"insideMiddle":case"insideMiddleBottom":case"middle":i.x=x[0],i.y=x[1]+w,c="center",i.originY=-w;break;case"insideEndTop":case"insideEnd":case"insideEndBottom":i.x=-f*_+u[0],i.y=u[1]+w,c=v[0]>=0?"right":"left",i.originX=f*_,i.originY=-w}i.scaleX=i.scaleY=r,i.setStyle({verticalAlign:i.__verticalAlign||p,align:i.__align||c})}}}function S(t,e){var n=t.__specifiedRotation;if(null==n){var i=a.tangentAt(e);t.attr("rotation",(1===e?-1:1)*Math.PI/2-Math.atan2(i[1],i[0]))}else t.attr("rotation",n)}},e}(Br),YA=function(){function t(t){this.group=new Br,this._LineCtor=t||HA}return t.prototype.updateData=function(t){var e=this;this._progressiveEls=null;var n=this,i=n.group,r=n._lineData;n._lineData=t,r||i.removeAll();var o=XA(t);t.diff(r).add((function(n){e._doAdd(t,n,o)})).update((function(n,i){e._doUpdate(r,t,i,n,o)})).remove((function(t){i.remove(r.getItemGraphicEl(t))})).execute()},t.prototype.updateLayout=function(){var t=this._lineData;t&&t.eachItemGraphicEl((function(e,n){e.updateLayout(t,n)}),this)},t.prototype.incrementalPrepareUpdate=function(t){this._seriesScope=XA(t),this._lineData=null,this.group.removeAll()},t.prototype.incrementalUpdate=function(t,e){function n(t){t.isGroup||function(t){return t.animators&&t.animators.length>0}(t)||(t.incremental=!0,t.ensureState("emphasis").hoverLayer=!0)}this._progressiveEls=[];for(var i=t.start;i=0?i+=u:i-=u:f>=0?i-=u:i+=u}return i}function ek(t,e){var n=[],i=Dn,r=[[],[],[]],o=[[],[]],a=[];e/=2,t.eachEdge((function(t,s){var l=t.getLayout(),u=t.getVisual("fromSymbol"),h=t.getVisual("toSymbol");l.__original||(l.__original=[Tt(l[0]),Tt(l[1])],l[2]&&l.__original.push(Tt(l[2])));var c=l.__original;if(null!=l[2]){if(It(r[0],c[0]),It(r[1],c[2]),It(r[2],c[1]),u&&"none"!==u){var p=SA(t.node1),d=tk(r,c[0],p*e);i(r[0][0],r[1][0],r[2][0],d,n),r[0][0]=n[3],r[1][0]=n[4],i(r[0][1],r[1][1],r[2][1],d,n),r[0][1]=n[3],r[1][1]=n[4]}if(h&&"none"!==h){p=SA(t.node2),d=tk(r,c[1],p*e);i(r[0][0],r[1][0],r[2][0],d,n),r[1][0]=n[1],r[2][0]=n[2],i(r[0][1],r[1][1],r[2][1],d,n),r[1][1]=n[1],r[2][1]=n[2]}It(l[0],r[0]),It(l[1],r[2]),It(l[2],r[1])}else{if(It(o[0],c[0]),It(o[1],c[1]),kt(a,o[1],o[0]),Et(a,a),u&&"none"!==u){p=SA(t.node1);At(o[0],o[0],a,p*e)}if(h&&"none"!==h){p=SA(t.node2);At(o[1],o[1],a,-p*e)}It(l[0],o[0]),It(l[1],o[1])}}))}function nk(t){return"view"===t.type}var ik=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(t,e){var n=new xS,i=new YA,r=this.group;this._controller=new nT(e.getZr()),this._controllerHost={target:r},r.add(n.group),r.add(i.group),this._symbolDraw=n,this._lineDraw=i,this._firstRender=!0},e.prototype.render=function(t,e,n){var i=this,r=t.coordinateSystem;this._model=t;var o=this._symbolDraw,a=this._lineDraw,s=this.group;if(nk(r)){var l={x:r.x,y:r.y,scaleX:r.scaleX,scaleY:r.scaleY};this._firstRender?s.attr(l):vh(s,l,t)}ek(t.getGraph(),wA(t));var u=t.getData();o.updateData(u);var h=t.getEdgeData();a.updateData(h),this._updateNodeAndLinkScale(),this._updateController(t,e,n),clearTimeout(this._layoutTimeout);var c=t.forceLayout,p=t.get(["force","layoutAnimation"]);c&&this._startForceLayoutIteration(c,p);var d=t.get("layout");u.graph.eachNode((function(e){var n=e.dataIndex,r=e.getGraphicEl(),o=e.getModel();if(r){r.off("drag").off("dragend");var a=o.get("draggable");a&&r.on("drag",(function(o){switch(d){case"force":c.warmUp(),!i._layouting&&i._startForceLayoutIteration(c,p),c.setFixed(n),u.setItemLayout(n,[r.x,r.y]);break;case"circular":u.setItemLayout(n,[r.x,r.y]),e.setLayout({fixed:!0},!0),TA(t,"symbolSize",e,[o.offsetX,o.offsetY]),i.updateLayout(t);break;default:u.setItemLayout(n,[r.x,r.y]),_A(t.getGraph(),t),i.updateLayout(t)}})).on("dragend",(function(){c&&c.setUnfixed(n)})),r.setDraggable(a,!!o.get("cursor")),"adjacency"===o.get(["emphasis","focus"])&&(rl(r).focus=e.getAdjacentDataIndices())}})),u.graph.eachEdge((function(t){var e=t.getGraphicEl(),n=t.getModel().get(["emphasis","focus"]);e&&"adjacency"===n&&(rl(e).focus={edge:[t.dataIndex],node:[t.node1.dataIndex,t.node2.dataIndex]})}));var f="circular"===t.get("layout")&&t.get(["circular","rotateLabel"]),g=u.getLayout("cx"),y=u.getLayout("cy");u.graph.eachNode((function(t){DA(t,f,g,y)})),this._firstRender=!1},e.prototype.dispose=function(){this.remove(),this._controller&&this._controller.dispose(),this._controllerHost=null},e.prototype._startForceLayoutIteration=function(t,e){var n=this;!function i(){t.step((function(t){n.updateLayout(n._model),(n._layouting=!t)&&(e?n._layoutTimeout=setTimeout(i,16):i())}))}()},e.prototype._updateController=function(t,e,n){var i=this,r=this._controller,o=this._controllerHost,a=this.group;r.setPointerChecker((function(e,i,r){var o=a.getBoundingRect();return o.applyTransform(a.transform),o.contain(i,r)&&!hT(e,n,t)})),nk(t.coordinateSystem)?(r.enable(t.get("roam")),o.zoomLimit=t.get("scaleLimit"),o.zoom=t.coordinateSystem.getZoom(),r.off("pan").off("zoom").on("pan",(function(e){aT(o,e.dx,e.dy),n.dispatchAction({seriesId:t.id,type:"graphRoam",dx:e.dx,dy:e.dy})})).on("zoom",(function(e){sT(o,e.scale,e.originX,e.originY),n.dispatchAction({seriesId:t.id,type:"graphRoam",zoom:e.scale,originX:e.originX,originY:e.originY}),i._updateNodeAndLinkScale(),ek(t.getGraph(),wA(t)),i._lineDraw.updateLayout(),n.updateLabelLayout()}))):r.disable()},e.prototype._updateNodeAndLinkScale=function(){var t=this._model,e=t.getData(),n=wA(t);e.eachItemGraphicEl((function(t,e){t&&t.setSymbolScale(n)}))},e.prototype.updateLayout=function(t){ek(t.getGraph(),wA(t)),this._symbolDraw.updateLayout(),this._lineDraw.updateLayout()},e.prototype.remove=function(){clearTimeout(this._layoutTimeout),this._layouting=!1,this._layoutTimeout=null,this._symbolDraw&&this._symbolDraw.remove(),this._lineDraw&&this._lineDraw.remove()},e.type="graph",e}(Og);function rk(t){return"_EC_"+t}var ok=function(){function t(t){this.type="graph",this.nodes=[],this.edges=[],this._nodesMap={},this._edgesMap={},this._directed=t||!1}return t.prototype.isDirected=function(){return this._directed},t.prototype.addNode=function(t,e){t=null==t?""+e:""+t;var n=this._nodesMap;if(!n[rk(t)]){var i=new ak(t,e);return i.hostGraph=this,this.nodes.push(i),n[rk(t)]=i,i}},t.prototype.getNodeByIndex=function(t){var e=this.data.getRawIndex(t);return this.nodes[e]},t.prototype.getNodeById=function(t){return this._nodesMap[rk(t)]},t.prototype.addEdge=function(t,e,n){var i=this._nodesMap,r=this._edgesMap;if(j(t)&&(t=this.nodes[t]),j(e)&&(e=this.nodes[e]),t instanceof ak||(t=i[rk(t)]),e instanceof ak||(e=i[rk(e)]),t&&e){var o=t.id+"-"+e.id,a=new sk(t,e,n);return a.hostGraph=this,this._directed&&(t.outEdges.push(a),e.inEdges.push(a)),t.edges.push(a),t!==e&&e.edges.push(a),this.edges.push(a),r[o]=a,a}},t.prototype.getEdgeByIndex=function(t){var e=this.edgeData.getRawIndex(t);return this.edges[e]},t.prototype.getEdge=function(t,e){t instanceof ak&&(t=t.id),e instanceof ak&&(e=e.id);var n=this._edgesMap;return this._directed?n[t+"-"+e]:n[t+"-"+e]||n[e+"-"+t]},t.prototype.eachNode=function(t,e){for(var n=this.nodes,i=n.length,r=0;r=0&&t.call(e,n[r],r)},t.prototype.eachEdge=function(t,e){for(var n=this.edges,i=n.length,r=0;r=0&&n[r].node1.dataIndex>=0&&n[r].node2.dataIndex>=0&&t.call(e,n[r],r)},t.prototype.breadthFirstTraverse=function(t,e,n,i){if(e instanceof ak||(e=this._nodesMap[rk(e)]),e){for(var r="out"===n?"outEdges":"in"===n?"inEdges":"edges",o=0;o=0&&n.node2.dataIndex>=0}));for(r=0,o=i.length;r=0&&this[t][e].setItemVisual(this.dataIndex,n,i)},getVisual:function(n){return this[t][e].getItemVisual(this.dataIndex,n)},setLayout:function(n,i){this.dataIndex>=0&&this[t][e].setItemLayout(this.dataIndex,n,i)},getLayout:function(){return this[t][e].getItemLayout(this.dataIndex)},getGraphicEl:function(){return this[t][e].getItemGraphicEl(this.dataIndex)},getRawIndex:function(){return this[t][e].getRawIndex(this.dataIndex)}}}function uk(t,e,n,i,r){for(var o=new ok(i),a=0;a "+p)),u++)}var d,f=n.get("coordinateSystem");if("cartesian2d"===f||"polar"===f)d=_x(t,n);else{var g=wd.get(f),y=g&&g.dimensions||[];P(y,"value")<0&&y.concat(["value"]);var v=px(t,{coordDimensions:y,encodeDefine:n.getEncode()}).dimensions;(d=new cx(v,n)).initData(t)}var m=new cx(["value"],n);return m.initData(l,s),r&&r(d,m),ZC({mainData:d,struct:o,structAttr:"graph",datas:{node:d,edge:m},datasAttr:{node:"data",edge:"edgeData"}}),o.update(),o}R(ak,lk("hostGraph","data")),R(sk,lk("hostGraph","edgeData"));var hk=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.hasSymbolVisual=!0,n}return n(e,t),e.prototype.init=function(e){t.prototype.init.apply(this,arguments);var n=this;function i(){return n._categoriesData}this.legendVisualProvider=new NM(i,i),this.fillDataTextStyle(e.edges||e.links),this._updateCategoriesData()},e.prototype.mergeOption=function(e){t.prototype.mergeOption.apply(this,arguments),this.fillDataTextStyle(e.edges||e.links),this._updateCategoriesData()},e.prototype.mergeDefaultAndTheme=function(e){t.prototype.mergeDefaultAndTheme.apply(this,arguments),Co(e,"edgeLabel",["show"])},e.prototype.getInitialData=function(t,e){var n,i=t.edges||t.links||[],r=t.data||t.nodes||[],o=this;if(r&&i){dA(n=this)&&(n.__curvenessList=[],n.__edgeMap={},fA(n));var a=uk(r,i,this,!0,(function(t,e){t.wrapMethod("getItemModel",(function(t){var e=o._categoriesModels[t.getShallow("category")];return e&&(e.parentModel=t.parentModel,t.parentModel=e),t}));var n=Cc.prototype.getModel;function i(t,e){var i=n.call(this,t,e);return i.resolveParentPath=r,i}function r(t){if(t&&("label"===t[0]||"label"===t[1])){var e=t.slice();return"label"===t[0]?e[0]="edgeLabel":"label"===t[1]&&(e[1]="edgeLabel"),e}return t}e.wrapMethod("getItemModel",(function(t){return t.resolveParentPath=r,t.getModel=i,t}))}));return E(a.edges,(function(t){!function(t,e,n,i){if(dA(n)){var r=gA(t,e,n),o=n.__edgeMap,a=o[yA(r)];o[r]&&!a?o[r].isForward=!0:a&&o[r]&&(a.isForward=!0,o[r].isForward=!1),o[r]=o[r]||[],o[r].push(i)}}(t.node1,t.node2,this,t.dataIndex)}),this),a.data}},e.prototype.getGraph=function(){return this.getData().graph},e.prototype.getEdgeData=function(){return this.getGraph().edgeData},e.prototype.getCategoriesData=function(){return this._categoriesData},e.prototype.formatTooltip=function(t,e,n){if("edge"===n){var i=this.getData(),r=this.getDataParams(t,n),o=i.graph.getEdgeByIndex(t),a=i.getName(o.node1.dataIndex),s=i.getName(o.node2.dataIndex),l=[];return null!=a&&l.push(a),null!=s&&l.push(s),og("nameValue",{name:l.join(" > "),value:r.value,noValue:null==r.value})}return vg({series:this,dataIndex:t,multipleSeries:e})},e.prototype._updateCategoriesData=function(){var t=z(this.option.categories||[],(function(t){return null!=t.value?t:A({value:0},t)})),e=new cx(["value"],this);e.initData(t),this._categoriesData=e,this._categoriesModels=e.mapArray((function(t){return e.getItemModel(t)}))},e.prototype.setZoom=function(t){this.option.zoom=t},e.prototype.setCenter=function(t){this.option.center=t},e.prototype.isAnimationEnabled=function(){return t.prototype.isAnimationEnabled.call(this)&&!("force"===this.get("layout")&&this.get(["force","layoutAnimation"]))},e.type="series.graph",e.dependencies=["grid","polar","geo","singleAxis","calendar"],e.defaultOption={z:2,coordinateSystem:"view",legendHoverLink:!0,layout:null,circular:{rotateLabel:!1},force:{initLayout:null,repulsion:[0,50],gravity:.1,friction:.6,edgeLength:30,layoutAnimation:!0},left:"center",top:"center",symbol:"circle",symbolSize:10,edgeSymbol:["none","none"],edgeSymbolSize:10,edgeLabel:{position:"middle",distance:5},draggable:!1,roam:!1,center:null,zoom:1,nodeScaleRatio:.6,label:{show:!1,formatter:"{b}"},itemStyle:{},lineStyle:{color:"#aaa",width:1,opacity:.5},emphasis:{scale:!0,label:{show:!0}},select:{itemStyle:{borderColor:"#212121"}}},e}(bg),ck={type:"graphRoam",event:"graphRoam",update:"none"};var pk=function(){this.angle=0,this.width=10,this.r=10,this.x=0,this.y=0},dk=function(t){function e(e){var n=t.call(this,e)||this;return n.type="pointer",n}return n(e,t),e.prototype.getDefaultShape=function(){return new pk},e.prototype.buildPath=function(t,e){var n=Math.cos,i=Math.sin,r=e.r,o=e.width,a=e.angle,s=e.x-n(a)*o*(o>=r/3?1:2),l=e.y-i(a)*o*(o>=r/3?1:2);a=e.angle-Math.PI/2,t.moveTo(s,l),t.lineTo(e.x+n(a)*o,e.y+i(a)*o),t.lineTo(e.x+n(e.angle)*r,e.y+i(e.angle)*r),t.lineTo(e.x-n(a)*o,e.y-i(a)*o),t.lineTo(s,l)},e}(ks);function fk(t,e){var n=null==t?"":t+"";return e&&(U(e)?n=e.replace("{value}",n):X(e)&&(n=e(t))),n}var gk=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){this.group.removeAll();var i=t.get(["axisLine","lineStyle","color"]),r=function(t,e){var n=t.get("center"),i=e.getWidth(),r=e.getHeight(),o=Math.min(i,r);return{cx:$r(n[0],e.getWidth()),cy:$r(n[1],e.getHeight()),r:$r(t.get("radius"),o/2)}}(t,n);this._renderMain(t,e,n,i,r),this._data=t.getData()},e.prototype.dispose=function(){},e.prototype._renderMain=function(t,e,n,i,r){var o=this.group,a=t.get("clockwise"),s=-t.get("startAngle")/180*Math.PI,l=-t.get("endAngle")/180*Math.PI,u=t.getModel("axisLine"),h=u.get("roundCap")?JS:Fu,c=u.get("show"),p=u.getModel("lineStyle"),d=p.get("width"),f=[s,l];us(f,!a);for(var g=(l=f[1])-(s=f[0]),y=s,v=[],m=0;c&&m=t&&(0===e?0:i[e-1][0])Math.PI/2&&(V+=Math.PI):"tangential"===z?V=-M-Math.PI/2:j(z)&&(V=z*Math.PI/180),0===V?c.add(new Xs({style:oc(x,{text:O,x:N,y:E,verticalAlign:h<-.8?"top":h>.8?"bottom":"middle",align:u<-.4?"left":u>.4?"right":"center"},{inheritColor:R}),silent:!0})):c.add(new Xs({style:oc(x,{text:O,x:N,y:E,verticalAlign:"middle",align:"center"},{inheritColor:R}),silent:!0,originX:N,originY:E,rotation:V}))}if(m.get("show")&&k!==_){P=(P=m.get("distance"))?P+l:l;for(var B=0;B<=b;B++){u=Math.cos(M),h=Math.sin(M);var F=new Ku({shape:{x1:u*(f-P)+p,y1:h*(f-P)+d,x2:u*(f-S-P)+p,y2:h*(f-S-P)+d},silent:!0,style:D});"auto"===D.stroke&&F.setStyle({stroke:i((k+B/b)/_)}),c.add(F),M+=T}M-=T}else M+=I}},e.prototype._renderPointer=function(t,e,n,i,r,o,a,s,l){var u=this.group,h=this._data,c=this._progressEls,p=[],d=t.get(["pointer","show"]),f=t.getModel("progress"),g=f.get("show"),y=t.getData(),v=y.mapDimension("value"),m=+t.get("min"),x=+t.get("max"),_=[m,x],b=[o,a];function w(e,n){var i,o=y.getItemModel(e).getModel("pointer"),a=$r(o.get("width"),r.r),s=$r(o.get("length"),r.r),l=t.get(["pointer","icon"]),u=o.get("offsetCenter"),h=$r(u[0],r.r),c=$r(u[1],r.r),p=o.get("keepAspect");return(i=l?Xy(l,h-a/2,c-s,a,s,null,p):new dk({shape:{angle:-Math.PI/2,width:a,r:s,x:h,y:c}})).rotation=-(n+Math.PI/2),i.x=r.cx,i.y=r.cy,i}function S(t,e){var n=f.get("roundCap")?JS:Fu,i=f.get("overlap"),a=i?f.get("width"):l/y.count(),u=i?r.r-a:r.r-(t+1)*a,h=i?r.r:r.r-t*a,c=new n({shape:{startAngle:o,endAngle:e,cx:r.cx,cy:r.cy,clockwise:s,r0:u,r:h}});return i&&(c.z2=x-y.get(v,t)%x),c}(g||d)&&(y.diff(h).add((function(e){var n=y.get(v,e);if(d){var i=w(e,o);mh(i,{rotation:-((isNaN(+n)?b[0]:Kr(n,_,b,!0))+Math.PI/2)},t),u.add(i),y.setItemGraphicEl(e,i)}if(g){var r=S(e,o),a=f.get("clip");mh(r,{shape:{endAngle:Kr(n,_,b,a)}},t),u.add(r),ol(t.seriesIndex,y.dataType,e,r),p[e]=r}})).update((function(e,n){var i=y.get(v,e);if(d){var r=h.getItemGraphicEl(n),a=r?r.rotation:o,s=w(e,a);s.rotation=a,vh(s,{rotation:-((isNaN(+i)?b[0]:Kr(i,_,b,!0))+Math.PI/2)},t),u.add(s),y.setItemGraphicEl(e,s)}if(g){var l=c[n],m=S(e,l?l.shape.endAngle:o),x=f.get("clip");vh(m,{shape:{endAngle:Kr(i,_,b,x)}},t),u.add(m),ol(t.seriesIndex,y.dataType,e,m),p[e]=m}})).execute(),y.each((function(t){var e=y.getItemModel(t),n=e.getModel("emphasis"),r=n.get("focus"),o=n.get("blurScope"),a=n.get("disabled");if(d){var s=y.getItemGraphicEl(t),l=y.getItemVisual(t,"style"),u=l.fill;if(s instanceof Ns){var h=s.style;s.useStyle(A({image:h.image,x:h.x,y:h.y,width:h.width,height:h.height},l))}else s.useStyle(l),"pointer"!==s.type&&s.setColor(u);s.setStyle(e.getModel(["pointer","itemStyle"]).getItemStyle()),"auto"===s.style.fill&&s.setStyle("fill",i(Kr(y.get(v,t),_,[0,1],!0))),s.z2EmphasisLift=0,$l(s,e),Zl(s,r,o,a)}if(g){var c=p[t];c.useStyle(y.getItemVisual(t,"style")),c.setStyle(e.getModel(["progress","itemStyle"]).getItemStyle()),c.z2EmphasisLift=0,$l(c,e),Zl(c,r,o,a)}})),this._progressEls=p)},e.prototype._renderAnchor=function(t,e){var n=t.getModel("anchor");if(n.get("show")){var i=n.get("size"),r=n.get("icon"),o=n.get("offsetCenter"),a=n.get("keepAspect"),s=Xy(r,e.cx-i/2+$r(o[0],e.r),e.cy-i/2+$r(o[1],e.r),i,i,null,a);s.z2=n.get("showAbove")?1:0,s.setStyle(n.getModel("itemStyle").getItemStyle()),this.group.add(s)}},e.prototype._renderTitleAndDetail=function(t,e,n,i,r){var o=this,a=t.getData(),s=a.mapDimension("value"),l=+t.get("min"),u=+t.get("max"),h=new Br,c=[],p=[],d=t.isAnimationEnabled(),f=t.get(["pointer","showAbove"]);a.diff(this._data).add((function(t){c[t]=new Xs({silent:!0}),p[t]=new Xs({silent:!0})})).update((function(t,e){c[t]=o._titleEls[e],p[t]=o._detailEls[e]})).execute(),a.each((function(e){var n=a.getItemModel(e),o=a.get(s,e),g=new Br,y=i(Kr(o,[l,u],[0,1],!0)),v=n.getModel("title");if(v.get("show")){var m=v.get("offsetCenter"),x=r.cx+$r(m[0],r.r),_=r.cy+$r(m[1],r.r);(D=c[e]).attr({z2:f?0:2,style:oc(v,{x:x,y:_,text:a.getName(e),align:"center",verticalAlign:"middle"},{inheritColor:y})}),g.add(D)}var b=n.getModel("detail");if(b.get("show")){var w=b.get("offsetCenter"),S=r.cx+$r(w[0],r.r),M=r.cy+$r(w[1],r.r),I=$r(b.get("width"),r.r),T=$r(b.get("height"),r.r),C=t.get(["progress","show"])?a.getItemVisual(e,"style").fill:y,D=p[e],A=b.get("formatter");D.attr({z2:f?0:2,style:oc(b,{x:S,y:M,text:fk(o,A),width:isNaN(I)?null:I,height:isNaN(T)?null:T,align:"center",verticalAlign:"middle"},{inheritColor:C})}),dc(D,{normal:b},o,(function(t){return fk(t,A)})),d&&fc(D,e,a,t,{getFormattedLabel:function(t,e,n,i,r,a){return fk(a?a.interpolatedValue:o,A)}}),g.add(D)}h.add(g)})),this.group.add(h),this._titleEls=c,this._detailEls=p},e.type="gauge",e}(Og),yk=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.visualStyleAccessPath="itemStyle",n}return n(e,t),e.prototype.getInitialData=function(t,e){return RM(this,["value"])},e.type="series.gauge",e.defaultOption={z:2,colorBy:"data",center:["50%","50%"],legendHoverLink:!0,radius:"75%",startAngle:225,endAngle:-45,clockwise:!0,min:0,max:100,splitNumber:10,axisLine:{show:!0,roundCap:!1,lineStyle:{color:[[1,"#E6EBF8"]],width:10}},progress:{show:!1,overlap:!0,width:10,roundCap:!1,clip:!0},splitLine:{show:!0,length:10,distance:10,lineStyle:{color:"#63677A",width:3,type:"solid"}},axisTick:{show:!0,splitNumber:5,length:6,distance:10,lineStyle:{color:"#63677A",width:1,type:"solid"}},axisLabel:{show:!0,distance:15,color:"#464646",fontSize:12,rotate:0},pointer:{icon:null,offsetCenter:[0,0],show:!0,showAbove:!0,length:"60%",width:6,keepAspect:!1},anchor:{show:!1,showAbove:!1,size:6,icon:"circle",offsetCenter:[0,0],keepAspect:!1,itemStyle:{color:"#fff",borderWidth:0,borderColor:"#5470c6"}},title:{show:!0,offsetCenter:[0,"20%"],color:"#464646",fontSize:16,valueAnimation:!1},detail:{show:!0,backgroundColor:"rgba(0,0,0,0)",borderWidth:0,borderColor:"#ccc",width:100,height:null,padding:[5,10],offsetCenter:[0,"40%"],color:"#464646",fontSize:30,fontWeight:"bold",lineHeight:30,valueAnimation:!1}},e}(bg);var vk=["itemStyle","opacity"],mk=function(t){function e(e,n){var i=t.call(this)||this,r=i,o=new Zu,a=new Xs;return r.setTextContent(a),i.setTextGuideLine(o),i.updateData(e,n,!0),i}return n(e,t),e.prototype.updateData=function(t,e,n){var i=this,r=t.hostModel,o=t.getItemModel(e),a=t.getItemLayout(e),s=o.getModel("emphasis"),l=o.get(vk);l=null==l?1:l,n||Sh(i),i.useStyle(t.getItemVisual(e,"style")),i.style.lineJoin="round",n?(i.setShape({points:a.points}),i.style.opacity=0,mh(i,{style:{opacity:l}},r,e)):vh(i,{style:{opacity:l},shape:{points:a.points}},r,e),$l(i,o),this._updateLabel(t,e),Zl(this,s.get("focus"),s.get("blurScope"),s.get("disabled"))},e.prototype._updateLabel=function(t,e){var n=this,i=this.getTextGuideLine(),r=n.getTextContent(),o=t.hostModel,a=t.getItemModel(e),s=t.getItemLayout(e).label,l=t.getItemVisual(e,"style"),u=l.fill;ic(r,rc(a),{labelFetcher:t.hostModel,labelDataIndex:e,defaultOpacity:l.opacity,defaultText:t.getName(e)},{normal:{align:s.textAlign,verticalAlign:s.verticalAlign}}),n.setTextConfig({local:!0,inside:!!s.inside,insideStroke:u,outsideFill:u});var h=s.linePoints;i.setShape({points:h}),n.textGuideLineConfig={anchor:h?new De(h[0][0],h[0][1]):null},vh(r,{style:{x:s.x,y:s.y}},o,e),r.attr({rotation:s.rotation,originX:s.x,originY:s.y,z2:10}),kb(n,Lb(a),{stroke:u})},e}(Xu),xk=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.ignoreLabelLineUpdate=!0,n}return n(e,t),e.prototype.render=function(t,e,n){var i=t.getData(),r=this._data,o=this.group;i.diff(r).add((function(t){var e=new mk(i,t);i.setItemGraphicEl(t,e),o.add(e)})).update((function(t,e){var n=r.getItemGraphicEl(e);n.updateData(i,t),o.add(n),i.setItemGraphicEl(t,n)})).remove((function(e){wh(r.getItemGraphicEl(e),t,e)})).execute(),this._data=i},e.prototype.remove=function(){this.group.removeAll(),this._data=null},e.prototype.dispose=function(){},e.type="funnel",e}(Og),_k=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(e){t.prototype.init.apply(this,arguments),this.legendVisualProvider=new NM(W(this.getData,this),W(this.getRawData,this)),this._defaultLabelLine(e)},e.prototype.getInitialData=function(t,e){return RM(this,{coordDimensions:["value"],encodeDefaulter:H(ed,this)})},e.prototype._defaultLabelLine=function(t){Co(t,"labelLine",["show"]);var e=t.labelLine,n=t.emphasis.labelLine;e.show=e.show&&t.label.show,n.show=n.show&&t.emphasis.label.show},e.prototype.getDataParams=function(e){var n=this.getData(),i=t.prototype.getDataParams.call(this,e),r=n.mapDimension("value"),o=n.getSum(r);return i.percent=o?+(n.get(r,e)/o*100).toFixed(2):0,i.$vars.push("percent"),i},e.type="series.funnel",e.defaultOption={z:2,legendHoverLink:!0,colorBy:"data",left:80,top:60,right:80,bottom:60,minSize:"0%",maxSize:"100%",sort:"descending",orient:"vertical",gap:0,funnelAlign:"center",label:{show:!0,position:"outer"},labelLine:{show:!0,length:20,lineStyle:{width:1}},itemStyle:{borderColor:"#fff",borderWidth:1},emphasis:{label:{show:!0}},select:{itemStyle:{borderColor:"#212121"}}},e}(bg);function bk(t,e){t.eachSeriesByType("funnel",(function(t){var n=t.getData(),i=n.mapDimension("value"),r=t.get("sort"),o=function(t,e){return kp(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()})}(t,e),a=t.get("orient"),s=o.width,l=o.height,u=function(t,e){for(var n=t.mapDimension("value"),i=t.mapArray(n,(function(t){return t})),r=[],o="ascending"===e,a=0,s=t.count();a5)return;var i=this._model.coordinateSystem.getSlidedAxisExpandWindow([t.offsetX,t.offsetY]);"none"!==i.behavior&&this._dispatchExpand({axisExpandWindow:i.axisExpandWindow})}this._mouseDownPoint=null},mousemove:function(t){if(!this._mouseDownPoint&&Rk(this,"mousemove")){var e=this._model,n=e.coordinateSystem.getSlidedAxisExpandWindow([t.offsetX,t.offsetY]),i=n.behavior;"jump"===i&&this._throttledDispatchExpand.debounceNextCall(e.get("axisExpandDebounce")),this._throttledDispatchExpand("none"===i?null:{axisExpandWindow:n.axisExpandWindow,animation:"jump"===i?null:{duration:0}})}}};function Rk(t,e){var n=t._model;return n.get("axisExpandable")&&n.get("axisExpandTriggerOn")===e}var Nk=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(){t.prototype.init.apply(this,arguments),this.mergeOption({})},e.prototype.mergeOption=function(t){var e=this.option;t&&C(e,t,!0),this._initDimensions()},e.prototype.contains=function(t,e){var n=t.get("parallelIndex");return null!=n&&e.getComponent("parallel",n)===this},e.prototype.setAxisExpand=function(t){E(["axisExpandable","axisExpandCenter","axisExpandCount","axisExpandWidth","axisExpandWindow"],(function(e){t.hasOwnProperty(e)&&(this.option[e]=t[e])}),this)},e.prototype._initDimensions=function(){var t=this.dimensions=[],e=this.parallelAxisIndex=[];E(B(this.ecModel.queryComponents({mainType:"parallelAxis"}),(function(t){return(t.get("parallelIndex")||0)===this.componentIndex}),this),(function(n){t.push("dim"+n.get("dim")),e.push(n.componentIndex)}))},e.type="parallel",e.dependencies=["parallelAxis"],e.layoutMode="box",e.defaultOption={z:0,left:80,top:60,right:80,bottom:60,layout:"horizontal",axisExpandable:!1,axisExpandCenter:null,axisExpandCount:0,axisExpandWidth:50,axisExpandRate:17,axisExpandDebounce:50,axisExpandSlideTriggerArea:[-.15,.05,.4],axisExpandTriggerOn:"click",parallelAxisDefault:null},e}(zp),Ek=function(t){function e(e,n,i,r,o){var a=t.call(this,e,n,i)||this;return a.type=r||"value",a.axisIndex=o,a}return n(e,t),e.prototype.isHorizontal=function(){return"horizontal"!==this.coordinateSystem.getModel().get("layout")},e}(ab);function zk(t,e,n,i,r,o){t=t||0;var a=n[1]-n[0];if(null!=r&&(r=Bk(r,[0,a])),null!=o&&(o=Math.max(o,null!=r?r:0)),"all"===i){var s=Math.abs(e[1]-e[0]);s=Bk(s,[0,a]),r=o=Bk(s,[r,o]),i=0}e[0]=Bk(e[0],n),e[1]=Bk(e[1],n);var l=Vk(e,i);e[i]+=t;var u,h=r||0,c=n.slice();return l.sign<0?c[0]+=h:c[1]-=h,e[i]=Bk(e[i],c),u=Vk(e,i),null!=r&&(u.sign!==l.sign||u.spano&&(e[1-i]=e[i]+u.sign*o),e}function Vk(t,e){var n=t[e]-t[1-e];return{span:Math.abs(n),sign:n>0?-1:n<0?1:e?-1:1}}function Bk(t,e){return Math.min(null!=e[1]?e[1]:1/0,Math.max(null!=e[0]?e[0]:-1/0,t))}var Fk=E,Gk=Math.min,Wk=Math.max,Hk=Math.floor,Yk=Math.ceil,Xk=Jr,Uk=Math.PI,Zk=function(){function t(t,e,n){this.type="parallel",this._axesMap=yt(),this._axesLayout={},this.dimensions=t.dimensions,this._model=t,this._init(t,e,n)}return t.prototype._init=function(t,e,n){var i=t.dimensions,r=t.parallelAxisIndex;Fk(i,(function(t,n){var i=r[n],o=e.getComponent("parallelAxis",i),a=this._axesMap.set(t,new Ek(t,b_(o),[0,0],o.get("type"),i)),s="category"===a.type;a.onBand=s&&o.get("boundaryGap"),a.inverse=o.get("inverse"),o.axis=a,a.model=o,a.coordinateSystem=o.coordinateSystem=this}),this)},t.prototype.update=function(t,e){this._updateAxesFromSeries(this._model,t)},t.prototype.containPoint=function(t){var e=this._makeLayoutInfo(),n=e.axisBase,i=e.layoutBase,r=e.pixelDimIndex,o=t[1-r],a=t[r];return o>=n&&o<=n+e.axisLength&&a>=i&&a<=i+e.layoutLength},t.prototype.getModel=function(){return this._model},t.prototype._updateAxesFromSeries=function(t,e){e.eachSeries((function(n){if(t.contains(n,e)){var i=n.getData();Fk(this.dimensions,(function(t){var e=this._axesMap.get(t);e.scale.unionExtentFromData(i,i.mapDimension(t)),__(e.scale,e.model)}),this)}}),this)},t.prototype.resize=function(t,e){this._rect=kp(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()}),this._layoutAxes()},t.prototype.getRect=function(){return this._rect},t.prototype._makeLayoutInfo=function(){var t,e=this._model,n=this._rect,i=["x","y"],r=["width","height"],o=e.get("layout"),a="horizontal"===o?0:1,s=n[r[a]],l=[0,s],u=this.dimensions.length,h=jk(e.get("axisExpandWidth"),l),c=jk(e.get("axisExpandCount")||0,[0,u]),p=e.get("axisExpandable")&&u>3&&u>c&&c>1&&h>0&&s>0,d=e.get("axisExpandWindow");d?(t=jk(d[1]-d[0],l),d[1]=d[0]+t):(t=jk(h*(c-1),l),(d=[h*(e.get("axisExpandCenter")||Hk(u/2))-t/2])[1]=d[0]+t);var f=(s-t)/(u-c);f<3&&(f=0);var g=[Hk(Xk(d[0]/h,1))+1,Yk(Xk(d[1]/h,1))-1],y=f/h*d[0];return{layout:o,pixelDimIndex:a,layoutBase:n[i[a]],layoutLength:s,axisBase:n[i[1-a]],axisLength:n[r[1-a]],axisExpandable:p,axisExpandWidth:h,axisCollapseWidth:f,axisExpandWindow:d,axisCount:u,winInnerIndices:g,axisExpandWindow0Pos:y}},t.prototype._layoutAxes=function(){var t=this._rect,e=this._axesMap,n=this.dimensions,i=this._makeLayoutInfo(),r=i.layout;e.each((function(t){var e=[0,i.axisLength],n=t.inverse?1:0;t.setExtent(e[n],e[1-n])})),Fk(n,(function(e,n){var o=(i.axisExpandable?Kk:qk)(n,i),a={horizontal:{x:o.position,y:i.axisLength},vertical:{x:0,y:o.position}},s={horizontal:Uk/2,vertical:0},l=[a[r].x+t.x,a[r].y+t.y],u=s[r],h=[1,0,0,1,0,0];Se(h,h,u),we(h,h,l),this._axesLayout[e]={position:l,rotation:u,transform:h,axisNameAvailableWidth:o.axisNameAvailableWidth,axisLabelShow:o.axisLabelShow,nameTruncateMaxWidth:o.nameTruncateMaxWidth,tickDirection:1,labelDirection:1}}),this)},t.prototype.getAxis=function(t){return this._axesMap.get(t)},t.prototype.dataToPoint=function(t,e){return this.axisCoordToPoint(this._axesMap.get(e).dataToCoord(t),e)},t.prototype.eachActiveState=function(t,e,n,i){null==n&&(n=0),null==i&&(i=t.count());var r=this._axesMap,o=this.dimensions,a=[],s=[];E(o,(function(e){a.push(t.mapDimension(e)),s.push(r.get(e).model)}));for(var l=this.hasAxisBrushed(),u=n;ur*(1-h[0])?(l="jump",a=s-r*(1-h[2])):(a=s-r*h[1])>=0&&(a=s-r*(1-h[1]))<=0&&(a=0),(a*=e.axisExpandWidth/u)?zk(a,i,o,"all"):l="none";else{var p=i[1]-i[0];(i=[Wk(0,o[1]*s/p-p/2)])[1]=Gk(o[1],i[0]+p),i[0]=i[1]-p}return{axisExpandWindow:i,behavior:l}},t}();function jk(t,e){return Gk(Wk(t,e[0]),e[1])}function qk(t,e){var n=e.layoutLength/(e.axisCount-1);return{position:n*t,axisNameAvailableWidth:n,axisLabelShow:!0}}function Kk(t,e){var n,i,r=e.layoutLength,o=e.axisExpandWidth,a=e.axisCount,s=e.axisCollapseWidth,l=e.winInnerIndices,u=s,h=!1;return t=0;n--)Qr(e[n])},e.prototype.getActiveState=function(t){var e=this.activeIntervals;if(!e.length)return"normal";if(null==t||isNaN(+t))return"inactive";if(1===e.length){var n=e[0];if(n[0]<=t&&t<=n[1])return"active"}else for(var i=0,r=e.length;i6}(t)||o){if(a&&!o){"single"===s.brushMode&&vL(t);var l=T(s);l.brushType=RL(l.brushType,a),l.panelId=a===Qk?null:a.panelId,o=t._creatingCover=uL(t,l),t._covers.push(o)}if(o){var u=zL[RL(t._brushType,a)];o.__brushOption.range=u.getCreatingRange(kL(t,o,t._track)),i&&(hL(t,o),u.updateCommon(t,o)),cL(t,o),r={isEnd:i}}}else i&&"single"===s.brushMode&&s.removeOnClick&&gL(t,e,n)&&vL(t)&&(r={isEnd:i,removeOnClick:!0});return r}function RL(t,e){return"auto"===t?e.defaultBrushType:t}var NL={mousedown:function(t){if(this._dragging)EL(this,t);else if(!t.target||!t.target.draggable){LL(t);var e=this.group.transformCoordToLocal(t.offsetX,t.offsetY);this._creatingCover=null,(this._creatingPanel=gL(this,t,e))&&(this._dragging=!0,this._track=[e.slice()])}},mousemove:function(t){var e=t.offsetX,n=t.offsetY,i=this.group.transformCoordToLocal(e,n);if(function(t,e,n){if(t._brushType&&!function(t,e,n){var i=t._zr;return e<0||e>i.getWidth()||n<0||n>i.getHeight()}(t,e.offsetX,e.offsetY)){var i=t._zr,r=t._covers,o=gL(t,e,n);if(!t._dragging)for(var a=0;a=0&&(o[r[a].depth]=new Cc(r[a],this,e));if(i&&n){var s=uk(i,n,this,!0,(function(t,e){t.wrapMethod("getItemModel",(function(t,e){var n=t.parentModel,i=n.getData().getItemLayout(e);if(i){var r=i.depth,o=n.levelModels[r];o&&(t.parentModel=o)}return t})),e.wrapMethod("getItemModel",(function(t,e){var n=t.parentModel,i=n.getGraph().getEdgeByIndex(e).node1.getLayout();if(i){var r=i.depth,o=n.levelModels[r];o&&(t.parentModel=o)}return t}))}));return s.data}},e.prototype.setNodePosition=function(t,e){var n=(this.option.data||this.option.nodes)[t];n.localX=e[0],n.localY=e[1]},e.prototype.getGraph=function(){return this.getData().graph},e.prototype.getEdgeData=function(){return this.getGraph().edgeData},e.prototype.formatTooltip=function(t,e,n){function i(t){return isNaN(t)||null==t}if("edge"===n){var r=this.getDataParams(t,n),o=r.data,a=r.value;return og("nameValue",{name:o.source+" -- "+o.target,value:a,noValue:i(a)})}var s=this.getGraph().getNodeByIndex(t).getLayout().value,l=this.getDataParams(t,n).data.name;return og("nameValue",{name:null!=l?l+"":null,value:s,noValue:i(s)})},e.prototype.optionUpdated=function(){},e.prototype.getDataParams=function(e,n){var i=t.prototype.getDataParams.call(this,e,n);if(null==i.value&&"node"===n){var r=this.getGraph().getNodeByIndex(e).getLayout().value;i.value=r}return i},e.type="series.sankey",e.defaultOption={z:2,coordinateSystem:"view",left:"5%",top:"5%",right:"20%",bottom:"5%",orient:"horizontal",nodeWidth:20,nodeGap:8,draggable:!0,layoutIterations:32,label:{show:!0,position:"right",fontSize:12},edgeLabel:{show:!1,fontSize:12},levels:[],nodeAlign:"justify",lineStyle:{color:"#314656",opacity:.2,curveness:.5},emphasis:{label:{show:!0},lineStyle:{opacity:.5}},select:{itemStyle:{borderColor:"#212121"}},animationEasing:"linear",animationDuration:1e3},e}(bg);function QL(t,e){t.eachSeriesByType("sankey",(function(t){var n=t.get("nodeWidth"),i=t.get("nodeGap"),r=function(t,e){return kp(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()})}(t,e);t.layoutInfo=r;var o=r.width,a=r.height,s=t.getGraph(),l=s.nodes,u=s.edges;!function(t){E(t,(function(t){var e=uP(t.outEdges,lP),n=uP(t.inEdges,lP),i=t.getValue()||0,r=Math.max(e,n,i);t.setLayout({value:r},!0)}))}(l),function(t,e,n,i,r,o,a,s,l){(function(t,e,n,i,r,o,a){for(var s=[],l=[],u=[],h=[],c=0,p=0;p=0;v&&y.depth>d&&(d=y.depth),g.setLayout({depth:v?y.depth:c},!0),"vertical"===o?g.setLayout({dy:n},!0):g.setLayout({dx:n},!0);for(var m=0;mc-1?d:c-1;a&&"left"!==a&&function(t,e,n,i){if("right"===e){for(var r=[],o=t,a=0;o.length;){for(var s=0;s0;o--)nP(s,l*=.99,a),eP(s,r,n,i,a),hP(s,l,a),eP(s,r,n,i,a)}(t,e,o,r,i,a,s),function(t,e){var n="vertical"===e?"x":"y";E(t,(function(t){t.outEdges.sort((function(t,e){return t.node2.getLayout()[n]-e.node2.getLayout()[n]})),t.inEdges.sort((function(t,e){return t.node1.getLayout()[n]-e.node1.getLayout()[n]}))})),E(t,(function(t){var e=0,n=0;E(t.outEdges,(function(t){t.setLayout({sy:e},!0),e+=t.getLayout().dy})),E(t.inEdges,(function(t){t.setLayout({ty:n},!0),n+=t.getLayout().dy}))}))}(t,s)}(l,u,n,i,o,a,0!==B(l,(function(t){return 0===t.getLayout().value})).length?0:t.get("layoutIterations"),t.get("orient"),t.get("nodeAlign"))}))}function tP(t){var e=t.hostGraph.data.getRawDataItem(t.dataIndex);return null!=e.depth&&e.depth>=0}function eP(t,e,n,i,r){var o="vertical"===r?"x":"y";E(t,(function(t){var a,s,l;t.sort((function(t,e){return t.getLayout()[o]-e.getLayout()[o]}));for(var u=0,h=t.length,c="vertical"===r?"dx":"dy",p=0;p0&&(a=s.getLayout()[o]+l,"vertical"===r?s.setLayout({x:a},!0):s.setLayout({y:a},!0)),u=s.getLayout()[o]+s.getLayout()[c]+e;if((l=u-e-("vertical"===r?i:n))>0){a=s.getLayout()[o]-l,"vertical"===r?s.setLayout({x:a},!0):s.setLayout({y:a},!0),u=a;for(p=h-2;p>=0;--p)(l=(s=t[p]).getLayout()[o]+s.getLayout()[c]+e-u)>0&&(a=s.getLayout()[o]-l,"vertical"===r?s.setLayout({x:a},!0):s.setLayout({y:a},!0)),u=s.getLayout()[o]}}))}function nP(t,e,n){E(t.slice().reverse(),(function(t){E(t,(function(t){if(t.outEdges.length){var i=uP(t.outEdges,iP,n)/uP(t.outEdges,lP);if(isNaN(i)){var r=t.outEdges.length;i=r?uP(t.outEdges,rP,n)/r:0}if("vertical"===n){var o=t.getLayout().x+(i-sP(t,n))*e;t.setLayout({x:o},!0)}else{var a=t.getLayout().y+(i-sP(t,n))*e;t.setLayout({y:a},!0)}}}))}))}function iP(t,e){return sP(t.node2,e)*t.getValue()}function rP(t,e){return sP(t.node2,e)}function oP(t,e){return sP(t.node1,e)*t.getValue()}function aP(t,e){return sP(t.node1,e)}function sP(t,e){return"vertical"===e?t.getLayout().x+t.getLayout().dx/2:t.getLayout().y+t.getLayout().dy/2}function lP(t){return t.getValue()}function uP(t,e,n){for(var i=0,r=t.length,o=-1;++oo&&(o=e)})),E(n,(function(e){var n=new kD({type:"color",mappingMethod:"linear",dataExtent:[r,o],visual:t.get("color")}).mapValueToVisual(e.getLayout().value),i=e.getModel().get(["itemStyle","color"]);null!=i?(e.setVisual("color",i),e.setVisual("style",{fill:i})):(e.setVisual("color",n),e.setVisual("style",{fill:n}))}))}i.length&&E(i,(function(t){var e=t.getModel().get("lineStyle");t.setVisual("style",e)}))}))}var pP=function(){function t(){}return t.prototype.getInitialData=function(t,e){var n,i,r=e.getComponent("xAxis",this.get("xAxisIndex")),o=e.getComponent("yAxis",this.get("yAxisIndex")),a=r.get("type"),s=o.get("type");"category"===a?(t.layout="horizontal",n=r.getOrdinalMeta(),i=!0):"category"===s?(t.layout="vertical",n=o.getOrdinalMeta(),i=!0):t.layout=t.layout||"horizontal";var l=["x","y"],u="horizontal"===t.layout?0:1,h=this._baseAxisDim=l[u],c=l[1-u],p=[r,o],d=p[u].get("type"),f=p[1-u].get("type"),g=t.data;if(g&&i){var y=[];E(g,(function(t,e){var n;Y(t)?(n=t.slice(),t.unshift(e)):Y(t.value)?((n=A({},t)).value=n.value.slice(),t.value.unshift(e)):n=t,y.push(n)})),t.data=y}var v=this.defaultValueDimensions,m=[{name:h,type:Ym(d),ordinalMeta:n,otherDims:{tooltip:!1,itemName:0},dimsDef:["base"]},{name:c,type:Ym(f),dimsDef:v.slice()}];return RM(this,{coordDimensions:m,dimensionsCount:v.length+1,encodeDefaulter:H(td,m,this)})},t.prototype.getBaseAxis=function(){var t=this._baseAxisDim;return this.ecModel.getComponent(t+"Axis",this.get(t+"AxisIndex")).axis},t}(),dP=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.defaultValueDimensions=[{name:"min",defaultTooltip:!0},{name:"Q1",defaultTooltip:!0},{name:"median",defaultTooltip:!0},{name:"Q3",defaultTooltip:!0},{name:"max",defaultTooltip:!0}],n.visualDrawType="stroke",n}return n(e,t),e.type="series.boxplot",e.dependencies=["xAxis","yAxis","grid"],e.defaultOption={z:2,coordinateSystem:"cartesian2d",legendHoverLink:!0,layout:null,boxWidth:[7,50],itemStyle:{color:"#fff",borderWidth:1},emphasis:{scale:!0,itemStyle:{borderWidth:2,shadowBlur:5,shadowOffsetX:1,shadowOffsetY:1,shadowColor:"rgba(0,0,0,0.2)"}},animationDuration:800},e}(bg);R(dP,pP,!0);var fP=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){var i=t.getData(),r=this.group,o=this._data;this._data||r.removeAll();var a="horizontal"===t.get("layout")?1:0;i.diff(o).add((function(t){if(i.hasValue(t)){var e=vP(i.getItemLayout(t),i,t,a,!0);i.setItemGraphicEl(t,e),r.add(e)}})).update((function(t,e){var n=o.getItemGraphicEl(e);if(i.hasValue(t)){var s=i.getItemLayout(t);n?(Sh(n),mP(s,n,i,t)):n=vP(s,i,t,a),r.add(n),i.setItemGraphicEl(t,n)}else r.remove(n)})).remove((function(t){var e=o.getItemGraphicEl(t);e&&r.remove(e)})).execute(),this._data=i},e.prototype.remove=function(t){var e=this.group,n=this._data;this._data=null,n&&n.eachItemGraphicEl((function(t){t&&e.remove(t)}))},e.type="boxplot",e}(Og),gP=function(){},yP=function(t){function e(e){var n=t.call(this,e)||this;return n.type="boxplotBoxPath",n}return n(e,t),e.prototype.getDefaultShape=function(){return new gP},e.prototype.buildPath=function(t,e){var n=e.points,i=0;for(t.moveTo(n[i][0],n[i][1]),i++;i<4;i++)t.lineTo(n[i][0],n[i][1]);for(t.closePath();ig){var _=[v,x];i.push(_)}}}return{boxData:n,outliers:i}}(e.getRawData(),t.config);return[{dimensions:["ItemName","Low","Q1","Q2","Q3","High"],data:i.boxData},{data:i.outliers}]}};var SP=["color","borderColor"],MP=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){this.group.removeClipPath(),this._progressiveEls=null,this._updateDrawMode(t),this._isLargeDraw?this._renderLarge(t):this._renderNormal(t)},e.prototype.incrementalPrepareRender=function(t,e,n){this._clear(),this._updateDrawMode(t)},e.prototype.incrementalRender=function(t,e,n,i){this._progressiveEls=[],this._isLargeDraw?this._incrementalRenderLarge(t,e):this._incrementalRenderNormal(t,e)},e.prototype.eachRendered=function(t){Jh(this._progressiveEls||this.group,t)},e.prototype._updateDrawMode=function(t){var e=t.pipelineContext.large;null!=this._isLargeDraw&&e===this._isLargeDraw||(this._isLargeDraw=e,this._clear())},e.prototype._renderNormal=function(t){var e=t.getData(),n=this._data,i=this.group,r=e.getLayout("isSimpleBox"),o=t.get("clip",!0),a=t.coordinateSystem,s=a.getArea&&a.getArea();this._data||i.removeAll(),e.diff(n).add((function(n){if(e.hasValue(n)){var a=e.getItemLayout(n);if(o&&DP(s,a))return;var l=CP(a,n,!0);mh(l,{shape:{points:a.ends}},t,n),AP(l,e,n,r),i.add(l),e.setItemGraphicEl(n,l)}})).update((function(a,l){var u=n.getItemGraphicEl(l);if(e.hasValue(a)){var h=e.getItemLayout(a);o&&DP(s,h)?i.remove(u):(u?(vh(u,{shape:{points:h.ends}},t,a),Sh(u)):u=CP(h),AP(u,e,a,r),i.add(u),e.setItemGraphicEl(a,u))}else i.remove(u)})).remove((function(t){var e=n.getItemGraphicEl(t);e&&i.remove(e)})).execute(),this._data=e},e.prototype._renderLarge=function(t){this._clear(),OP(t,this.group);var e=t.get("clip",!0)?PS(t.coordinateSystem,!1,t):null;e?this.group.setClipPath(e):this.group.removeClipPath()},e.prototype._incrementalRenderNormal=function(t,e){for(var n,i=e.getData(),r=i.getLayout("isSimpleBox");null!=(n=t.next());){var o=CP(i.getItemLayout(n));AP(o,i,n,r),o.incremental=!0,this.group.add(o),this._progressiveEls.push(o)}},e.prototype._incrementalRenderLarge=function(t,e){OP(e,this.group,this._progressiveEls,!0)},e.prototype.remove=function(t){this._clear()},e.prototype._clear=function(){this.group.removeAll(),this._data=null},e.type="candlestick",e}(Og),IP=function(){},TP=function(t){function e(e){var n=t.call(this,e)||this;return n.type="normalCandlestickBox",n}return n(e,t),e.prototype.getDefaultShape=function(){return new IP},e.prototype.buildPath=function(t,e){var n=e.points;this.__simpleBox?(t.moveTo(n[4][0],n[4][1]),t.lineTo(n[6][0],n[6][1])):(t.moveTo(n[0][0],n[0][1]),t.lineTo(n[1][0],n[1][1]),t.lineTo(n[2][0],n[2][1]),t.lineTo(n[3][0],n[3][1]),t.closePath(),t.moveTo(n[4][0],n[4][1]),t.lineTo(n[5][0],n[5][1]),t.moveTo(n[6][0],n[6][1]),t.lineTo(n[7][0],n[7][1]))},e}(ks);function CP(t,e,n){var i=t.ends;return new TP({shape:{points:n?kP(i,t):i},z2:100})}function DP(t,e){for(var n=!0,i=0;i0?"borderColor":"borderColor0"])||n.get(["itemStyle",t>0?"color":"color0"]);0===t&&(r=n.get(["itemStyle","borderColorDoji"]));var o=n.getModel("itemStyle").getItemStyle(SP);e.useStyle(o),e.style.fill=null,e.style.stroke=r}var NP=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.defaultValueDimensions=[{name:"open",defaultTooltip:!0},{name:"close",defaultTooltip:!0},{name:"lowest",defaultTooltip:!0},{name:"highest",defaultTooltip:!0}],n}return n(e,t),e.prototype.getShadowDim=function(){return"open"},e.prototype.brushSelector=function(t,e,n){var i=e.getItemLayout(t);return i&&n.rect(i.brushRect)},e.type="series.candlestick",e.dependencies=["xAxis","yAxis","grid"],e.defaultOption={z:2,coordinateSystem:"cartesian2d",legendHoverLink:!0,layout:null,clip:!0,itemStyle:{color:"#eb5454",color0:"#47b262",borderColor:"#eb5454",borderColor0:"#47b262",borderColorDoji:null,borderWidth:1},emphasis:{scale:!0,itemStyle:{borderWidth:2}},barMaxWidth:null,barMinWidth:null,barWidth:null,large:!0,largeThreshold:600,progressive:3e3,progressiveThreshold:1e4,progressiveChunkMode:"mod",animationEasing:"linear",animationDuration:300},e}(bg);function EP(t){t&&Y(t.series)&&E(t.series,(function(t){q(t)&&"k"===t.type&&(t.type="candlestick")}))}R(NP,pP,!0);var zP=["itemStyle","borderColor"],VP=["itemStyle","borderColor0"],BP=["itemStyle","borderColorDoji"],FP=["itemStyle","color"],GP=["itemStyle","color0"],WP={seriesType:"candlestick",plan:kg(),performRawSeries:!0,reset:function(t,e){function n(t,e){return e.get(t>0?FP:GP)}function i(t,e){return e.get(0===t?BP:t>0?zP:VP)}if(!e.isSeriesFiltered(t))return!t.pipelineContext.large&&{progress:function(t,e){for(var r;null!=(r=t.next());){var o=e.getItemModel(r),a=e.getItemLayout(r).sign,s=o.getItemStyle();s.fill=n(a,o),s.stroke=i(a,o)||s.fill,A(e.ensureUniqueItemVisual(r,"style"),s)}}}}},HP={seriesType:"candlestick",plan:kg(),reset:function(t){var e=t.coordinateSystem,n=t.getData(),i=function(t,e){var n,i=t.getBaseAxis(),r="category"===i.type?i.getBandWidth():(n=i.getExtent(),Math.abs(n[1]-n[0])/e.count()),o=$r(rt(t.get("barMaxWidth"),r),r),a=$r(rt(t.get("barMinWidth"),1),r),s=t.get("barWidth");return null!=s?$r(s,r):Math.max(Math.min(r/2,o),a)}(t,n),r=["x","y"],o=n.getDimensionIndex(n.mapDimension(r[0])),a=z(n.mapDimensionsAll(r[1]),n.getDimensionIndex,n),s=a[0],l=a[1],u=a[2],h=a[3];if(n.setLayout({candleWidth:i,isSimpleBox:i<=1.3}),!(o<0||a.length<4))return{progress:t.pipelineContext.large?function(n,i){var r,a,c=Bx(4*n.count),p=0,d=[],f=[],g=i.getStore(),y=!!t.get(["itemStyle","borderColorDoji"]);for(;null!=(a=n.next());){var v=g.get(o,a),m=g.get(s,a),x=g.get(l,a),_=g.get(u,a),b=g.get(h,a);isNaN(v)||isNaN(_)||isNaN(b)?(c[p++]=NaN,p+=3):(c[p++]=YP(g,a,m,x,l,y),d[0]=v,d[1]=_,r=e.dataToPoint(d,null,f),c[p++]=r?r[0]:NaN,c[p++]=r?r[1]:NaN,d[1]=b,r=e.dataToPoint(d,null,f),c[p++]=r?r[1]:NaN)}i.setLayout("largePoints",c)}:function(t,n){var r,a=n.getStore();for(;null!=(r=t.next());){var c=a.get(o,r),p=a.get(s,r),d=a.get(l,r),f=a.get(u,r),g=a.get(h,r),y=Math.min(p,d),v=Math.max(p,d),m=M(y,c),x=M(v,c),_=M(f,c),b=M(g,c),w=[];I(w,x,0),I(w,m,1),w.push(C(b),C(x),C(_),C(m));var S=!!n.getItemModel(r).get(["itemStyle","borderColorDoji"]);n.setItemLayout(r,{sign:YP(a,r,p,d,l,S),initBaseline:p>d?x[1]:m[1],ends:w,brushRect:T(f,g,c)})}function M(t,n){var i=[];return i[0]=n,i[1]=t,isNaN(n)||isNaN(t)?[NaN,NaN]:e.dataToPoint(i)}function I(t,e,n){var r=e.slice(),o=e.slice();r[0]=Vh(r[0]+i/2,1,!1),o[0]=Vh(o[0]-i/2,1,!0),n?t.push(r,o):t.push(o,r)}function T(t,e,n){var r=M(t,n),o=M(e,n);return r[0]-=i/2,o[0]-=i/2,{x:r[0],y:r[1],width:i,height:o[1]-r[1]}}function C(t){return t[0]=Vh(t[0],1),t}}}}};function YP(t,e,n,i,r,o){return n>i?-1:n0?t.get(r,e-1)<=i?1:-1:1}function XP(t,e){var n=e.rippleEffectColor||e.color;t.eachChild((function(t){t.attr({z:e.z,zlevel:e.zlevel,style:{stroke:"stroke"===e.brushType?n:null,fill:"fill"===e.brushType?n:null}})}))}var UP=function(t){function e(e,n){var i=t.call(this)||this,r=new fS(e,n),o=new Br;return i.add(r),i.add(o),i.updateData(e,n),i}return n(e,t),e.prototype.stopEffectAnimation=function(){this.childAt(1).removeAll()},e.prototype.startEffectAnimation=function(t){for(var e=t.symbolType,n=t.color,i=t.rippleNumber,r=this.childAt(1),o=0;o0&&(o=this._getLineLength(i)/l*1e3),o!==this._period||a!==this._loop||s!==this._roundTrip){i.stopAnimation();var h=void 0;h=X(u)?u(n):u,i.__t>0&&(h=-o*i.__t),this._animateSymbol(i,o,h,a,s)}this._period=o,this._loop=a,this._roundTrip=s}},e.prototype._animateSymbol=function(t,e,n,i,r){if(e>0){t.__t=0;var o=this,a=t.animate("",i).when(r?2*e:e,{__t:r?2:1}).delay(n).during((function(){o._updateSymbolPosition(t)}));i||a.done((function(){o.remove(t)})),a.start()}},e.prototype._getLineLength=function(t){return Vt(t.__p1,t.__cp1)+Vt(t.__cp1,t.__p2)},e.prototype._updateAnimationPoints=function(t,e){t.__p1=e[0],t.__p2=e[1],t.__cp1=e[2]||[(e[0][0]+e[1][0])/2,(e[0][1]+e[1][1])/2]},e.prototype.updateData=function(t,e,n){this.childAt(0).updateData(t,e,n),this._updateEffectSymbol(t,e)},e.prototype._updateSymbolPosition=function(t){var e=t.__p1,n=t.__p2,i=t.__cp1,r=t.__t<1?t.__t:2-t.__t,o=[t.x,t.y],a=o.slice(),s=In,l=Tn;o[0]=s(e[0],i[0],n[0],r),o[1]=s(e[1],i[1],n[1],r);var u=t.__t<1?l(e[0],i[0],n[0],r):l(n[0],i[0],e[0],1-r),h=t.__t<1?l(e[1],i[1],n[1],r):l(n[1],i[1],e[1],1-r);t.rotation=-Math.atan2(h,u)-Math.PI/2,"line"!==this._symbolType&&"rect"!==this._symbolType&&"roundRect"!==this._symbolType||(void 0!==t.__lastT&&t.__lastT=0&&!(i[o]<=e);o--);o=Math.min(o,r-2)}else{for(o=a;oe);o++);o=Math.min(o-1,r-2)}var s=(e-i[o])/(i[o+1]-i[o]),l=n[o],u=n[o+1];t.x=l[0]*(1-s)+s*u[0],t.y=l[1]*(1-s)+s*u[1];var h=t.__t<1?u[0]-l[0]:l[0]-u[0],c=t.__t<1?u[1]-l[1]:l[1]-u[1];t.rotation=-Math.atan2(c,h)-Math.PI/2,this._lastFrame=o,this._lastFramePercent=e,t.ignore=!1}},e}(qP),JP=function(){this.polyline=!1,this.curveness=0,this.segs=[]},QP=function(t){function e(e){var n=t.call(this,e)||this;return n._off=0,n.hoverDataIdx=-1,n}return n(e,t),e.prototype.reset=function(){this.notClear=!1,this._off=0},e.prototype.getDefaultStyle=function(){return{stroke:"#000",fill:null}},e.prototype.getDefaultShape=function(){return new JP},e.prototype.buildPath=function(t,e){var n,i=e.segs,r=e.curveness;if(e.polyline)for(n=this._off;n0){t.moveTo(i[n++],i[n++]);for(var a=1;a0){var c=(s+u)/2-(l-h)*r,p=(l+h)/2-(u-s)*r;t.quadraticCurveTo(c,p,u,h)}else t.lineTo(u,h)}this.incremental&&(this._off=n,this.notClear=!0)},e.prototype.findDataIndex=function(t,e){var n=this.shape,i=n.segs,r=n.curveness,o=this.style.lineWidth;if(n.polyline)for(var a=0,s=0;s0)for(var u=i[s++],h=i[s++],c=1;c0){if(ds(u,h,(u+p)/2-(h-d)*r,(h+d)/2-(p-u)*r,p,d,o,t,e))return a}else if(cs(u,h,p,d,o,t,e))return a;a++}return-1},e.prototype.contain=function(t,e){var n=this.transformCoordToLocal(t,e),i=this.getBoundingRect();return t=n[0],e=n[1],i.contain(t,e)?(this.hoverDataIdx=this.findDataIndex(t,e))>=0:(this.hoverDataIdx=-1,!1)},e.prototype.getBoundingRect=function(){var t=this._rect;if(!t){for(var e=this.shape.segs,n=1/0,i=1/0,r=-1/0,o=-1/0,a=0;a0&&(o.dataIndex=n+t.__startIndex)}))},t.prototype._clear=function(){this._newAdded=[],this.group.removeAll()},t}(),eO={seriesType:"lines",plan:kg(),reset:function(t){var e=t.coordinateSystem;if(e){var n=t.get("polyline"),i=t.pipelineContext.large;return{progress:function(r,o){var a=[];if(i){var s=void 0,l=r.end-r.start;if(n){for(var u=0,h=r.start;h0&&(l||s.configLayer(o,{motionBlur:!0,lastFrameAlpha:Math.max(Math.min(a/10+.9,1),0)})),r.updateData(i);var u=t.get("clip",!0)&&PS(t.coordinateSystem,!1,t);u?this.group.setClipPath(u):this.group.removeClipPath(),this._lastZlevel=o,this._finished=!0},e.prototype.incrementalPrepareRender=function(t,e,n){var i=t.getData();this._updateLineDraw(i,t).incrementalPrepareUpdate(i),this._clearLayer(n),this._finished=!1},e.prototype.incrementalRender=function(t,e,n){this._lineDraw.incrementalUpdate(t,e.getData()),this._finished=t.end===e.getData().count()},e.prototype.eachRendered=function(t){this._lineDraw&&this._lineDraw.eachRendered(t)},e.prototype.updateTransform=function(t,e,n){var i=t.getData(),r=t.pipelineContext;if(!this._finished||r.large||r.progressiveRender)return{update:!0};var o=eO.reset(t,e,n);o.progress&&o.progress({start:0,end:i.count(),count:i.count()},i),this._lineDraw.updateLayout(),this._clearLayer(n)},e.prototype._updateLineDraw=function(t,e){var n=this._lineDraw,i=this._showEffect(e),r=!!e.get("polyline"),o=e.pipelineContext.large;return n&&i===this._hasEffet&&r===this._isPolyline&&o===this._isLargeDraw||(n&&n.remove(),n=this._lineDraw=o?new tO:new YA(r?i?$P:KP:i?qP:HA),this._hasEffet=i,this._isPolyline=r,this._isLargeDraw=o),this.group.add(n.group),n},e.prototype._showEffect=function(t){return!!t.get(["effect","show"])},e.prototype._clearLayer=function(t){var e=t.getZr();"svg"===e.painter.getType()||null==this._lastZlevel||e.painter.getLayer(this._lastZlevel).clear(!0)},e.prototype.remove=function(t,e){this._lineDraw&&this._lineDraw.remove(),this._lineDraw=null,this._clearLayer(e)},e.prototype.dispose=function(t,e){this.remove(t,e)},e.type="lines",e}(Og),iO="undefined"==typeof Uint32Array?Array:Uint32Array,rO="undefined"==typeof Float64Array?Array:Float64Array;function oO(t){var e=t.data;e&&e[0]&&e[0][0]&&e[0][0].coord&&(t.data=z(e,(function(t){var e={coords:[t[0].coord,t[1].coord]};return t[0].name&&(e.fromName=t[0].name),t[1].name&&(e.toName=t[1].name),D([e,t[0],t[1]])})))}var aO=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.visualStyleAccessPath="lineStyle",n.visualDrawType="stroke",n}return n(e,t),e.prototype.init=function(e){e.data=e.data||[],oO(e);var n=this._processFlatCoordsArray(e.data);this._flatCoords=n.flatCoords,this._flatCoordsOffset=n.flatCoordsOffset,n.flatCoords&&(e.data=new Float32Array(n.count)),t.prototype.init.apply(this,arguments)},e.prototype.mergeOption=function(e){if(oO(e),e.data){var n=this._processFlatCoordsArray(e.data);this._flatCoords=n.flatCoords,this._flatCoordsOffset=n.flatCoordsOffset,n.flatCoords&&(e.data=new Float32Array(n.count))}t.prototype.mergeOption.apply(this,arguments)},e.prototype.appendData=function(t){var e=this._processFlatCoordsArray(t.data);e.flatCoords&&(this._flatCoords?(this._flatCoords=vt(this._flatCoords,e.flatCoords),this._flatCoordsOffset=vt(this._flatCoordsOffset,e.flatCoordsOffset)):(this._flatCoords=e.flatCoords,this._flatCoordsOffset=e.flatCoordsOffset),t.data=new Float32Array(e.count)),this.getRawData().appendData(t.data)},e.prototype._getCoordsFromItemModel=function(t){var e=this.getData().getItemModel(t),n=e.option instanceof Array?e.option:e.getShallow("coords");return n},e.prototype.getLineCoordsCount=function(t){return this._flatCoordsOffset?this._flatCoordsOffset[2*t+1]:this._getCoordsFromItemModel(t).length},e.prototype.getLineCoords=function(t,e){if(this._flatCoordsOffset){for(var n=this._flatCoordsOffset[2*t],i=this._flatCoordsOffset[2*t+1],r=0;r ")})},e.prototype.preventIncremental=function(){return!!this.get(["effect","show"])},e.prototype.getProgressive=function(){var t=this.option.progressive;return null==t?this.option.large?1e4:this.get("progressive"):t},e.prototype.getProgressiveThreshold=function(){var t=this.option.progressiveThreshold;return null==t?this.option.large?2e4:this.get("progressiveThreshold"):t},e.prototype.getZLevelKey=function(){var t=this.getModel("effect"),e=t.get("trailLength");return this.getData().count()>this.getProgressiveThreshold()?this.id:t.get("show")&&e>0?e+"":""},e.type="series.lines",e.dependencies=["grid","polar","geo","calendar"],e.defaultOption={coordinateSystem:"geo",z:2,legendHoverLink:!0,xAxisIndex:0,yAxisIndex:0,symbol:["none","none"],symbolSize:[10,10],geoIndex:0,effect:{show:!1,period:4,constantSpeed:0,symbol:"circle",symbolSize:3,loop:!0,trailLength:.2},large:!1,largeThreshold:2e3,polyline:!1,clip:!0,label:{show:!1,position:"end"},lineStyle:{opacity:.5}},e}(bg);function sO(t){return t instanceof Array||(t=[t,t]),t}var lO={seriesType:"lines",reset:function(t){var e=sO(t.get("symbol")),n=sO(t.get("symbolSize")),i=t.getData();return i.setVisual("fromSymbol",e&&e[0]),i.setVisual("toSymbol",e&&e[1]),i.setVisual("fromSymbolSize",n&&n[0]),i.setVisual("toSymbolSize",n&&n[1]),{dataEach:i.hasItemOption?function(t,e){var n=t.getItemModel(e),i=sO(n.getShallow("symbol",!0)),r=sO(n.getShallow("symbolSize",!0));i[0]&&t.setItemVisual(e,"fromSymbol",i[0]),i[1]&&t.setItemVisual(e,"toSymbol",i[1]),r[0]&&t.setItemVisual(e,"fromSymbolSize",r[0]),r[1]&&t.setItemVisual(e,"toSymbolSize",r[1])}:null}}};var uO=function(){function t(){this.blurSize=30,this.pointSize=20,this.maxOpacity=1,this.minOpacity=0,this._gradientPixels={inRange:null,outOfRange:null};var t=h.createCanvas();this.canvas=t}return t.prototype.update=function(t,e,n,i,r,o){var a=this._getBrush(),s=this._getGradient(r,"inRange"),l=this._getGradient(r,"outOfRange"),u=this.pointSize+this.blurSize,h=this.canvas,c=h.getContext("2d"),p=t.length;h.width=e,h.height=n;for(var d=0;d0){var I=o(v)?s:l;v>0&&(v=v*S+w),x[_++]=I[M],x[_++]=I[M+1],x[_++]=I[M+2],x[_++]=I[M+3]*v*256}else _+=4}return c.putImageData(m,0,0),h},t.prototype._getBrush=function(){var t=this._brushCanvas||(this._brushCanvas=h.createCanvas()),e=this.pointSize+this.blurSize,n=2*e;t.width=n,t.height=n;var i=t.getContext("2d");return i.clearRect(0,0,n,n),i.shadowOffsetX=n,i.shadowBlur=this.blurSize,i.shadowColor="#000",i.beginPath(),i.arc(-e,e,this.pointSize,0,2*Math.PI,!0),i.closePath(),i.fill(),t},t.prototype._getGradient=function(t,e){for(var n=this._gradientPixels,i=n[e]||(n[e]=new Uint8ClampedArray(1024)),r=[0,0,0,0],o=0,a=0;a<256;a++)t[e](a/255,!0,r),i[o++]=r[0],i[o++]=r[1],i[o++]=r[2],i[o++]=r[3];return i},t}();function hO(t){var e=t.dimensions;return"lng"===e[0]&&"lat"===e[1]}var cO=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){var i;e.eachComponent("visualMap",(function(e){e.eachTargetSeries((function(n){n===t&&(i=e)}))})),this._progressiveEls=null,this.group.removeAll();var r=t.coordinateSystem;"cartesian2d"===r.type||"calendar"===r.type?this._renderOnCartesianAndCalendar(t,n,0,t.getData().count()):hO(r)&&this._renderOnGeo(r,t,i,n)},e.prototype.incrementalPrepareRender=function(t,e,n){this.group.removeAll()},e.prototype.incrementalRender=function(t,e,n,i){var r=e.coordinateSystem;r&&(hO(r)?this.render(e,n,i):(this._progressiveEls=[],this._renderOnCartesianAndCalendar(e,i,t.start,t.end,!0)))},e.prototype.eachRendered=function(t){Jh(this._progressiveEls||this.group,t)},e.prototype._renderOnCartesianAndCalendar=function(t,e,n,i,r){var o,a,s,l,u=t.coordinateSystem,h=OS(u,"cartesian2d");if(h){var c=u.getAxis("x"),p=u.getAxis("y");0,o=c.getBandWidth()+.5,a=p.getBandWidth()+.5,s=c.scale.getExtent(),l=p.scale.getExtent()}for(var d=this.group,f=t.getData(),g=t.getModel(["emphasis","itemStyle"]).getItemStyle(),y=t.getModel(["blur","itemStyle"]).getItemStyle(),v=t.getModel(["select","itemStyle"]).getItemStyle(),m=t.get(["itemStyle","borderRadius"]),x=rc(t),_=t.getModel("emphasis"),b=_.get("focus"),w=_.get("blurScope"),S=_.get("disabled"),M=h?[f.mapDimension("x"),f.mapDimension("y"),f.mapDimension("value")]:[f.mapDimension("time"),f.mapDimension("value")],I=n;Is[1]||Al[1])continue;var k=u.dataToPoint([D,A]);T=new Ws({shape:{x:k[0]-o/2,y:k[1]-a/2,width:o,height:a},style:C})}else{if(isNaN(f.get(M[1],I)))continue;T=new Ws({z2:1,shape:u.dataToRect([f.get(M[0],I)]).contentShape,style:C})}if(f.hasItemOption){var L=f.getItemModel(I),P=L.getModel("emphasis");g=P.getModel("itemStyle").getItemStyle(),y=L.getModel(["blur","itemStyle"]).getItemStyle(),v=L.getModel(["select","itemStyle"]).getItemStyle(),m=L.get(["itemStyle","borderRadius"]),b=P.get("focus"),w=P.get("blurScope"),S=P.get("disabled"),x=rc(L)}T.shape.r=m;var O=t.getRawValue(I),R="-";O&&null!=O[2]&&(R=O[2]+""),ic(T,x,{labelFetcher:t,labelDataIndex:I,defaultOpacity:C.opacity,defaultText:R}),T.ensureState("emphasis").style=g,T.ensureState("blur").style=y,T.ensureState("select").style=v,Zl(T,b,w,S),T.incremental=r,r&&(T.states.emphasis.hoverLayer=!0),d.add(T),f.setItemGraphicEl(I,T),this._progressiveEls&&this._progressiveEls.push(T)}},e.prototype._renderOnGeo=function(t,e,n,i){var r=n.targetVisuals.inRange,o=n.targetVisuals.outOfRange,a=e.getData(),s=this._hmLayer||this._hmLayer||new uO;s.blurSize=e.get("blurSize"),s.pointSize=e.get("pointSize"),s.minOpacity=e.get("minOpacity"),s.maxOpacity=e.get("maxOpacity");var l=t.getViewRect().clone(),u=t.getRoamTransform();l.applyTransform(u);var h=Math.max(l.x,0),c=Math.max(l.y,0),p=Math.min(l.width+l.x,i.getWidth()),d=Math.min(l.height+l.y,i.getHeight()),f=p-h,g=d-c,y=[a.mapDimension("lng"),a.mapDimension("lat"),a.mapDimension("value")],v=a.mapArray(y,(function(e,n,i){var r=t.dataToPoint([e,n]);return r[0]-=h,r[1]-=c,r.push(i),r})),m=n.getExtent(),x="visualMap.continuous"===n.type?function(t,e){var n=t[1]-t[0];return e=[(e[0]-t[0])/n,(e[1]-t[0])/n],function(t){return t>=e[0]&&t<=e[1]}}(m,n.option.range):function(t,e,n){var i=t[1]-t[0],r=(e=z(e,(function(e){return{interval:[(e.interval[0]-t[0])/i,(e.interval[1]-t[0])/i]}}))).length,o=0;return function(t){var i;for(i=o;i=0;i--){var a;if((a=e[i].interval)[0]<=t&&t<=a[1]){o=i;break}}return i>=0&&i0?1:-1}(n,o,r,i,c),function(t,e,n,i,r,o,a,s,l,u){var h,c=l.valueDim,p=l.categoryDim,d=Math.abs(n[p.wh]),f=t.getItemVisual(e,"symbolSize");h=Y(f)?f.slice():null==f?["100%","100%"]:[f,f];h[p.index]=$r(h[p.index],d),h[c.index]=$r(h[c.index],i?d:Math.abs(o)),u.symbolSize=h;var g=u.symbolScale=[h[0]/s,h[1]/s];g[c.index]*=(l.isHorizontal?-1:1)*a}(t,e,r,o,0,c.boundingLength,c.pxSign,u,i,c),function(t,e,n,i,r){var o=t.get(dO)||0;o&&(gO.attr({scaleX:e[0],scaleY:e[1],rotation:n}),gO.updateTransform(),o/=gO.getLineScale(),o*=e[i.valueDim.index]);r.valueLineWidth=o||0}(n,c.symbolScale,l,i,c);var p=c.symbolSize,d=Zy(n.get("symbolOffset"),p);return function(t,e,n,i,r,o,a,s,l,u,h,c){var p=h.categoryDim,d=h.valueDim,f=c.pxSign,g=Math.max(e[d.index]+s,0),y=g;if(i){var v=Math.abs(l),m=it(t.get("symbolMargin"),"15%")+"",x=!1;m.lastIndexOf("!")===m.length-1&&(x=!0,m=m.slice(0,m.length-1));var _=$r(m,e[d.index]),b=Math.max(g+2*_,0),w=x?0:2*_,S=vo(i),M=S?i:OO((v+w)/b);b=g+2*(_=(v-M*g)/2/(x?M:Math.max(M-1,1))),w=x?0:2*_,S||"fixed"===i||(M=u?OO((Math.abs(u)+w)/b):0),y=M*b-w,c.repeatTimes=M,c.symbolMargin=_}var I=f*(y/2),T=c.pathPosition=[];T[p.index]=n[p.wh]/2,T[d.index]="start"===a?I:"end"===a?l-I:l/2,o&&(T[0]+=o[0],T[1]+=o[1]);var C=c.bundlePosition=[];C[p.index]=n[p.xy],C[d.index]=n[d.xy];var D=c.barRectShape=A({},n);D[d.wh]=f*Math.max(Math.abs(n[d.wh]),Math.abs(T[d.index]+I)),D[p.wh]=n[p.wh];var k=c.clipShape={};k[p.xy]=-n[p.xy],k[p.wh]=h.ecSize[p.wh],k[d.xy]=0,k[d.wh]=n[d.wh]}(n,p,r,o,0,d,s,c.valueLineWidth,c.boundingLength,c.repeatCutLength,i,c),c}function mO(t,e){return t.toGlobalCoord(t.dataToCoord(t.scale.parse(e)))}function xO(t){var e=t.symbolPatternSize,n=Xy(t.symbolType,-e/2,-e/2,e,e);return n.attr({culling:!0}),"image"!==n.type&&n.setStyle({strokeNoScale:!0}),n}function _O(t,e,n,i){var r=t.__pictorialBundle,o=n.symbolSize,a=n.valueLineWidth,s=n.pathPosition,l=e.valueDim,u=n.repeatTimes||0,h=0,c=o[e.valueDim.index]+a+2*n.symbolMargin;for(kO(t,(function(t){t.__pictorialAnimationIndex=h,t.__pictorialRepeatTimes=u,h0:i<0)&&(r=u-1-t),e[l.index]=c*(r-u/2+.5)+s[l.index],{x:e[0],y:e[1],scaleX:n.symbolScale[0],scaleY:n.symbolScale[1],rotation:n.rotation}}}function bO(t,e,n,i){var r=t.__pictorialBundle,o=t.__pictorialMainPath;o?LO(o,null,{x:n.pathPosition[0],y:n.pathPosition[1],scaleX:n.symbolScale[0],scaleY:n.symbolScale[1],rotation:n.rotation},n,i):(o=t.__pictorialMainPath=xO(n),r.add(o),LO(o,{x:n.pathPosition[0],y:n.pathPosition[1],scaleX:0,scaleY:0,rotation:n.rotation},{scaleX:n.symbolScale[0],scaleY:n.symbolScale[1]},n,i))}function wO(t,e,n){var i=A({},e.barRectShape),r=t.__pictorialBarRect;r?LO(r,null,{shape:i},e,n):((r=t.__pictorialBarRect=new Ws({z2:2,shape:i,silent:!0,style:{stroke:"transparent",fill:"transparent",lineWidth:0}})).disableMorphing=!0,t.add(r))}function SO(t,e,n,i){if(n.symbolClip){var r=t.__pictorialClipPath,o=A({},n.clipShape),a=e.valueDim,s=n.animationModel,l=n.dataIndex;if(r)vh(r,{shape:o},s,l);else{o[a.wh]=0,r=new Ws({shape:o}),t.__pictorialBundle.setClipPath(r),t.__pictorialClipPath=r;var u={};u[a.wh]=n.clipShape[a.wh],Qh[i?"updateProps":"initProps"](r,{shape:u},s,l)}}}function MO(t,e){var n=t.getItemModel(e);return n.getAnimationDelayParams=IO,n.isAnimationEnabled=TO,n}function IO(t){return{index:t.__pictorialAnimationIndex,count:t.__pictorialRepeatTimes}}function TO(){return this.parentModel.isAnimationEnabled()&&!!this.getShallow("animation")}function CO(t,e,n,i){var r=new Br,o=new Br;return r.add(o),r.__pictorialBundle=o,o.x=n.bundlePosition[0],o.y=n.bundlePosition[1],n.symbolRepeat?_O(r,e,n):bO(r,0,n),wO(r,n,i),SO(r,e,n,i),r.__pictorialShapeStr=AO(t,n),r.__pictorialSymbolMeta=n,r}function DO(t,e,n,i){var r=i.__pictorialBarRect;r&&r.removeTextContent();var o=[];kO(i,(function(t){o.push(t)})),i.__pictorialMainPath&&o.push(i.__pictorialMainPath),i.__pictorialClipPath&&(n=null),E(o,(function(t){_h(t,{scaleX:0,scaleY:0},n,e,(function(){i.parent&&i.parent.remove(i)}))})),t.setItemGraphicEl(e,null)}function AO(t,e){return[t.getItemVisual(e.dataIndex,"symbol")||"none",!!e.symbolRepeat,!!e.symbolClip].join(":")}function kO(t,e,n){E(t.__pictorialBundle.children(),(function(i){i!==t.__pictorialBarRect&&e.call(n,i)}))}function LO(t,e,n,i,r,o){e&&t.attr(e),i.symbolClip&&!r?n&&t.attr(n):n&&Qh[r?"updateProps":"initProps"](t,n,i.animationModel,i.dataIndex,o)}function PO(t,e,n){var i=n.dataIndex,r=n.itemModel,o=r.getModel("emphasis"),a=o.getModel("itemStyle").getItemStyle(),s=r.getModel(["blur","itemStyle"]).getItemStyle(),l=r.getModel(["select","itemStyle"]).getItemStyle(),u=r.getShallow("cursor"),h=o.get("focus"),c=o.get("blurScope"),p=o.get("scale");kO(t,(function(t){if(t instanceof Ns){var e=t.style;t.useStyle(A({image:e.image,x:e.x,y:e.y,width:e.width,height:e.height},n.style))}else t.useStyle(n.style);var i=t.ensureState("emphasis");i.style=a,p&&(i.scaleX=1.1*t.scaleX,i.scaleY=1.1*t.scaleY),t.ensureState("blur").style=s,t.ensureState("select").style=l,u&&(t.cursor=u),t.z2=n.z2}));var d=e.valueDim.posDesc[+(n.boundingLength>0)],f=t.__pictorialBarRect;f.ignoreClip=!0,ic(f,rc(r),{labelFetcher:e.seriesModel,labelDataIndex:i,defaultText:pS(e.seriesModel.getData(),i),inheritColor:n.style.fill,defaultOpacity:n.style.opacity,defaultOutsidePosition:d}),Zl(t,h,c,o.get("disabled"))}function OO(t){var e=Math.round(t);return Math.abs(t-e)<1e-4?e:Math.ceil(t)}var RO=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.hasSymbolVisual=!0,n.defaultSymbol="roundRect",n}return n(e,t),e.prototype.getInitialData=function(e){return e.stack=null,t.prototype.getInitialData.apply(this,arguments)},e.type="series.pictorialBar",e.dependencies=["grid"],e.defaultOption=kc(qS.defaultOption,{symbol:"circle",symbolSize:null,symbolRotate:null,symbolPosition:null,symbolOffset:null,symbolMargin:null,symbolRepeat:!1,symbolRepeatDirection:"end",symbolClip:!1,symbolBoundingData:null,symbolPatternSize:400,barGap:"-100%",clip:!1,progressive:0,emphasis:{scale:!1},select:{itemStyle:{borderColor:"#212121"}}}),e}(qS);var NO=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n._layers=[],n}return n(e,t),e.prototype.render=function(t,e,n){var i=t.getData(),r=this,o=this.group,a=t.getLayerSeries(),s=i.getLayout("layoutInfo"),l=s.rect,u=s.boundaryGap;function h(t){return t.name}o.x=0,o.y=l.y+u[0];var c=new Gm(this._layersSeries||[],a,h,h),p=[];function d(e,n,s){var l=r._layers;if("remove"!==e){for(var u,h,c=[],d=[],f=a[n].indices,g=0;go&&(o=s),i.push(s)}for(var u=0;uo&&(o=c)}return{y0:r,max:o}}(l),h=u.y0,c=n/u.max,p=o.length,d=o[0].indices.length,f=0;fI&&!so(C-I)&&C0?(r.virtualPiece?r.virtualPiece.updateData(!1,i,t,e,n):(r.virtualPiece=new BO(i,t,e,n),l.add(r.virtualPiece)),o.piece.off("click"),r.virtualPiece.on("click",(function(t){r._rootToNode(o.parentNode)}))):r.virtualPiece&&(l.remove(r.virtualPiece),r.virtualPiece=null)}(a,s),this._initEvents(),this._oldChildren=h},e.prototype._initEvents=function(){var t=this;this.group.off("click"),this.group.on("click",(function(e){var n=!1;t.seriesModel.getViewRoot().eachNode((function(i){if(!n&&i.piece&&i.piece===e.target){var r=i.getModel().get("nodeClick");if("rootToNode"===r)t._rootToNode(i);else if("link"===r){var o=i.getModel(),a=o.get("link");if(a)Mp(a,o.get("target",!0)||"_blank")}n=!0}}))}))},e.prototype._rootToNode=function(t){t!==this.seriesModel.getViewRoot()&&this.api.dispatchAction({type:FO,from:this.uid,seriesId:this.seriesModel.id,targetNode:t})},e.prototype.containPoint=function(t,e){var n=e.getData().getItemLayout(0);if(n){var i=t[0]-n.cx,r=t[1]-n.cy,o=Math.sqrt(i*i+r*r);return o<=n.r&&o>=n.r0}},e.type="sunburst",e}(Og),HO=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.ignoreStyleOnData=!0,n}return n(e,t),e.prototype.getInitialData=function(t,e){var n={name:t.name,children:t.data};YO(n);var i=this._levelModels=z(t.levels||[],(function(t){return new Cc(t,this,e)}),this),r=nD.createTree(n,this,(function(t){t.wrapMethod("getItemModel",(function(t,e){var n=r.getNodeByDataIndex(e),o=i[n.depth];return o&&(t.parentModel=o),t}))}));return r.data},e.prototype.optionUpdated=function(){this.resetViewRoot()},e.prototype.getDataParams=function(e){var n=t.prototype.getDataParams.apply(this,arguments),i=this.getData().tree.getNodeByDataIndex(e);return n.treePathInfo=aD(i,this),n},e.prototype.getLevelModel=function(t){return this._levelModels&&this._levelModels[t.depth]},e.prototype.getViewRoot=function(){return this._viewRoot},e.prototype.resetViewRoot=function(t){t?this._viewRoot=t:t=this._viewRoot;var e=this.getRawData().tree.root;t&&(t===e||e.contains(t))||(this._viewRoot=e)},e.prototype.enableAriaDecal=function(){pD(this)},e.type="series.sunburst",e.defaultOption={z:2,center:["50%","50%"],radius:[0,"75%"],clockwise:!0,startAngle:90,minAngle:0,stillShowZeroSum:!0,nodeClick:"rootToNode",renderLabelForZeroData:!1,label:{rotate:"radial",show:!0,opacity:1,align:"center",position:"inside",distance:5,silent:!0},itemStyle:{borderWidth:1,borderColor:"white",borderType:"solid",shadowBlur:0,shadowColor:"rgba(0, 0, 0, 0.2)",shadowOffsetX:0,shadowOffsetY:0,opacity:1},emphasis:{focus:"descendant"},blur:{itemStyle:{opacity:.2},label:{opacity:.1}},animationType:"expansion",animationDuration:1e3,animationDurationUpdate:500,data:[],sort:"desc"},e}(bg);function YO(t){var e=0;E(t.children,(function(t){YO(t);var n=t.value;Y(n)&&(n=n[0]),e+=n}));var n=t.value;Y(n)&&(n=n[0]),(null==n||isNaN(n))&&(n=e),n<0&&(n=0),Y(t.value)?t.value[0]=n:t.value=n}var XO=Math.PI/180;function UO(t,e,n){e.eachSeriesByType(t,(function(t){var e=t.get("center"),i=t.get("radius");Y(i)||(i=[0,i]),Y(e)||(e=[e,e]);var r=n.getWidth(),o=n.getHeight(),a=Math.min(r,o),s=$r(e[0],r),l=$r(e[1],o),u=$r(i[0],a/2),h=$r(i[1],a/2),c=-t.get("startAngle")*XO,p=t.get("minAngle")*XO,d=t.getData().tree.root,f=t.getViewRoot(),g=f.depth,y=t.get("sort");null!=y&&ZO(f,y);var v=0;E(f.children,(function(t){!isNaN(t.getValue())&&v++}));var m=f.getValue(),x=Math.PI/(m||v)*2,_=f.depth>0,b=f.height-(_?-1:1),w=(h-u)/(b||1),S=t.get("clockwise"),M=t.get("stillShowZeroSum"),I=S?1:-1,T=function(e,n){if(e){var i=n;if(e!==d){var r=e.getValue(),o=0===m&&M?x:r*x;o1;)r=r.parentNode;var o=n.getColorFromPalette(r.name||r.dataIndex+"",e);return t.depth>1&&U(o)&&(o=$n(o,(t.depth-1)/(i-1)*.5)),o}(r,t,i.root.height)),A(n.ensureUniqueItemVisual(r.dataIndex,"style"),o)}))}))}var qO={color:"fill",borderColor:"stroke"},KO={symbol:1,symbolSize:1,symbolKeepAspect:1,legendIcon:1,visualMeta:1,liftZ:1,decal:1},$O=Vo(),JO=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.optionUpdated=function(){this.currentZLevel=this.get("zlevel",!0),this.currentZ=this.get("z",!0)},e.prototype.getInitialData=function(t,e){return _x(null,this)},e.prototype.getDataParams=function(e,n,i){var r=t.prototype.getDataParams.call(this,e,n);return i&&(r.info=$O(i).info),r},e.type="series.custom",e.dependencies=["grid","polar","geo","singleAxis","calendar"],e.defaultOption={coordinateSystem:"cartesian2d",z:2,legendHoverLink:!0,clip:!1},e}(bg);function QO(t,e){return e=e||[0,0],z(["x","y"],(function(n,i){var r=this.getAxis(n),o=e[i],a=t[i]/2;return"category"===r.type?r.getBandWidth():Math.abs(r.dataToCoord(o-a)-r.dataToCoord(o+a))}),this)}function tR(t,e){return e=e||[0,0],z([0,1],(function(n){var i=e[n],r=t[n]/2,o=[],a=[];return o[n]=i-r,a[n]=i+r,o[1-n]=a[1-n]=e[1-n],Math.abs(this.dataToPoint(o)[n]-this.dataToPoint(a)[n])}),this)}function eR(t,e){var n=this.getAxis(),i=e instanceof Array?e[0]:e,r=(t instanceof Array?t[0]:t)/2;return"category"===n.type?n.getBandWidth():Math.abs(n.dataToCoord(i-r)-n.dataToCoord(i+r))}function nR(t,e){return e=e||[0,0],z(["Radius","Angle"],(function(n,i){var r=this["get"+n+"Axis"](),o=e[i],a=t[i]/2,s="category"===r.type?r.getBandWidth():Math.abs(r.dataToCoord(o-a)-r.dataToCoord(o+a));return"Angle"===n&&(s=s*Math.PI/180),s}),this)}function iR(t,e,n,i){return t&&(t.legacy||!1!==t.legacy&&!n&&!i&&"tspan"!==e&&("text"===e||_t(t,"text")))}function rR(t,e,n){var i,r,o,a=t;if("text"===e)o=a;else{o={},_t(a,"text")&&(o.text=a.text),_t(a,"rich")&&(o.rich=a.rich),_t(a,"textFill")&&(o.fill=a.textFill),_t(a,"textStroke")&&(o.stroke=a.textStroke),_t(a,"fontFamily")&&(o.fontFamily=a.fontFamily),_t(a,"fontSize")&&(o.fontSize=a.fontSize),_t(a,"fontStyle")&&(o.fontStyle=a.fontStyle),_t(a,"fontWeight")&&(o.fontWeight=a.fontWeight),r={type:"text",style:o,silent:!0},i={};var s=_t(a,"textPosition");n?i.position=s?a.textPosition:"inside":s&&(i.position=a.textPosition),_t(a,"textPosition")&&(i.position=a.textPosition),_t(a,"textOffset")&&(i.offset=a.textOffset),_t(a,"textRotation")&&(i.rotation=a.textRotation),_t(a,"textDistance")&&(i.distance=a.textDistance)}return oR(o,t),E(o.rich,(function(t){oR(t,t)})),{textConfig:i,textContent:r}}function oR(t,e){e&&(e.font=e.textFont||e.font,_t(e,"textStrokeWidth")&&(t.lineWidth=e.textStrokeWidth),_t(e,"textAlign")&&(t.align=e.textAlign),_t(e,"textVerticalAlign")&&(t.verticalAlign=e.textVerticalAlign),_t(e,"textLineHeight")&&(t.lineHeight=e.textLineHeight),_t(e,"textWidth")&&(t.width=e.textWidth),_t(e,"textHeight")&&(t.height=e.textHeight),_t(e,"textBackgroundColor")&&(t.backgroundColor=e.textBackgroundColor),_t(e,"textPadding")&&(t.padding=e.textPadding),_t(e,"textBorderColor")&&(t.borderColor=e.textBorderColor),_t(e,"textBorderWidth")&&(t.borderWidth=e.textBorderWidth),_t(e,"textBorderRadius")&&(t.borderRadius=e.textBorderRadius),_t(e,"textBoxShadowColor")&&(t.shadowColor=e.textBoxShadowColor),_t(e,"textBoxShadowBlur")&&(t.shadowBlur=e.textBoxShadowBlur),_t(e,"textBoxShadowOffsetX")&&(t.shadowOffsetX=e.textBoxShadowOffsetX),_t(e,"textBoxShadowOffsetY")&&(t.shadowOffsetY=e.textBoxShadowOffsetY))}function aR(t,e,n){var i=t;i.textPosition=i.textPosition||n.position||"inside",null!=n.offset&&(i.textOffset=n.offset),null!=n.rotation&&(i.textRotation=n.rotation),null!=n.distance&&(i.textDistance=n.distance);var r=i.textPosition.indexOf("inside")>=0,o=t.fill||"#000";sR(i,e);var a=null==i.textFill;return r?a&&(i.textFill=n.insideFill||"#fff",!i.textStroke&&n.insideStroke&&(i.textStroke=n.insideStroke),!i.textStroke&&(i.textStroke=o),null==i.textStrokeWidth&&(i.textStrokeWidth=2)):(a&&(i.textFill=t.fill||n.outsideFill||"#000"),!i.textStroke&&n.outsideStroke&&(i.textStroke=n.outsideStroke)),i.text=e.text,i.rich=e.rich,E(e.rich,(function(t){sR(t,t)})),i}function sR(t,e){e&&(_t(e,"fill")&&(t.textFill=e.fill),_t(e,"stroke")&&(t.textStroke=e.fill),_t(e,"lineWidth")&&(t.textStrokeWidth=e.lineWidth),_t(e,"font")&&(t.font=e.font),_t(e,"fontStyle")&&(t.fontStyle=e.fontStyle),_t(e,"fontWeight")&&(t.fontWeight=e.fontWeight),_t(e,"fontSize")&&(t.fontSize=e.fontSize),_t(e,"fontFamily")&&(t.fontFamily=e.fontFamily),_t(e,"align")&&(t.textAlign=e.align),_t(e,"verticalAlign")&&(t.textVerticalAlign=e.verticalAlign),_t(e,"lineHeight")&&(t.textLineHeight=e.lineHeight),_t(e,"width")&&(t.textWidth=e.width),_t(e,"height")&&(t.textHeight=e.height),_t(e,"backgroundColor")&&(t.textBackgroundColor=e.backgroundColor),_t(e,"padding")&&(t.textPadding=e.padding),_t(e,"borderColor")&&(t.textBorderColor=e.borderColor),_t(e,"borderWidth")&&(t.textBorderWidth=e.borderWidth),_t(e,"borderRadius")&&(t.textBorderRadius=e.borderRadius),_t(e,"shadowColor")&&(t.textBoxShadowColor=e.shadowColor),_t(e,"shadowBlur")&&(t.textBoxShadowBlur=e.shadowBlur),_t(e,"shadowOffsetX")&&(t.textBoxShadowOffsetX=e.shadowOffsetX),_t(e,"shadowOffsetY")&&(t.textBoxShadowOffsetY=e.shadowOffsetY),_t(e,"textShadowColor")&&(t.textShadowColor=e.textShadowColor),_t(e,"textShadowBlur")&&(t.textShadowBlur=e.textShadowBlur),_t(e,"textShadowOffsetX")&&(t.textShadowOffsetX=e.textShadowOffsetX),_t(e,"textShadowOffsetY")&&(t.textShadowOffsetY=e.textShadowOffsetY))}var lR={position:["x","y"],scale:["scaleX","scaleY"],origin:["originX","originY"]},uR=G(lR),hR=(V(mr,(function(t,e){return t[e]=1,t}),{}),mr.join(", "),["","style","shape","extra"]),cR=Vo();function pR(t,e,n,i,r){var o=t+"Animation",a=gh(t,i,r)||{},s=cR(e).userDuring;return a.duration>0&&(a.during=s?W(xR,{el:e,userDuring:s}):null,a.setToFinal=!0,a.scope=t),A(a,n[o]),a}function dR(t,e,n,i){var r=(i=i||{}).dataIndex,o=i.isInit,a=i.clearStyle,s=n.isAnimationEnabled(),l=cR(t),u=e.style;l.userDuring=e.during;var h={},c={};if(function(t,e,n){for(var i=0;i=0)){var c=t.getAnimationStyleProps(),p=c?c.style:null;if(p){!r&&(r=i.style={});var d=G(n);for(u=0;u0&&t.animateFrom(p,d)}else!function(t,e,n,i,r){if(r){var o=pR("update",t,e,i,n);o.duration>0&&t.animateFrom(r,o)}}(t,e,r||0,n,h);fR(t,e),u?t.dirty():t.markRedraw()}function fR(t,e){for(var n=cR(t).leaveToProps,i=0;i=0){!o&&(o=i[t]={});var p=G(a);for(h=0;hi[1]&&i.reverse(),{coordSys:{type:"polar",cx:t.cx,cy:t.cy,r:i[1],r0:i[0]},api:{coord:function(i){var r=e.dataToRadius(i[0]),o=n.dataToAngle(i[1]),a=t.coordToPoint([r,o]);return a.push(r,o*Math.PI/180),a},size:W(nR,t)}}},calendar:function(t){var e=t.getRect(),n=t.getRangeInfo();return{coordSys:{type:"calendar",x:e.x,y:e.y,width:e.width,height:e.height,cellWidth:t.getCellWidth(),cellHeight:t.getCellHeight(),rangeInfo:{start:n.start,end:n.end,weeks:n.weeks,dayCount:n.allDay}},api:{coord:function(e,n){return t.dataToPoint(e,n)}}}}};function zR(t){return t instanceof ks}function VR(t){return t instanceof Da}var BR=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n,i){this._progressiveEls=null;var r=this._data,o=t.getData(),a=this.group,s=YR(t,o,e,n);r||a.removeAll(),o.diff(r).add((function(e){UR(n,null,e,s(e,i),t,a,o)})).remove((function(e){var n=r.getItemGraphicEl(e);n&&gR(n,$O(n).option,t)})).update((function(e,l){var u=r.getItemGraphicEl(l);UR(n,u,e,s(e,i),t,a,o)})).execute();var l=t.get("clip",!0)?PS(t.coordinateSystem,!1,t):null;l?a.setClipPath(l):a.removeClipPath(),this._data=o},e.prototype.incrementalPrepareRender=function(t,e,n){this.group.removeAll(),this._data=null},e.prototype.incrementalRender=function(t,e,n,i,r){var o=e.getData(),a=YR(e,o,n,i),s=this._progressiveEls=[];function l(t){t.isGroup||(t.incremental=!0,t.ensureState("emphasis").hoverLayer=!0)}for(var u=t.start;u=0?e.getStore().get(r,n):void 0}var o=e.get(i.name,n),a=i&&i.ordinalMeta;return a?a.categories[o]:o},styleEmphasis:function(n,i){0;null==i&&(i=s);var r=m(i,CR).getItemStyle(),o=x(i,CR),a=oc(o,null,null,!0,!0);a.text=o.getShallow("show")?ot(t.getFormattedLabel(i,CR),t.getFormattedLabel(i,DR),pS(e,i)):null;var l=ac(o,null,!0);return b(n,r),r=aR(r,a,l),n&&_(r,n),r.legacy=!0,r},visual:function(t,n){if(null==n&&(n=s),_t(qO,t)){var i=e.getItemVisual(n,"style");return i?i[qO[t]]:null}if(_t(KO,t))return e.getItemVisual(n,t)},barLayout:function(t){if("cartesian2d"===o.type){return function(t){var e=[],n=t.axis,i="axis0";if("category"===n.type){for(var r=n.getBandWidth(),o=0;o=c;f--){var g=e.childAt(f);JR(e,g,r)}}(t,c,n,i,r),a>=0?o.replaceAt(c,a):o.add(c),c}function jR(t,e,n){var i,r=$O(t),o=e.type,a=e.shape,s=e.style;return n.isUniversalTransitionEnabled()||null!=o&&o!==r.customGraphicType||"path"===o&&((i=a)&&(_t(i,"pathData")||_t(i,"d")))&&nN(a)!==r.customPathData||"image"===o&&_t(s,"image")&&s.image!==r.customImagePath}function qR(t,e,n){var i=e?KR(t,e):t,r=e?$R(t,i,CR):t.style,o=t.type,a=i?i.textConfig:null,s=t.textContent,l=s?e?KR(s,e):s:null;if(r&&(n.isLegacy||iR(r,o,!!a,!!l))){n.isLegacy=!0;var u=rR(r,o,!e);!a&&u.textConfig&&(a=u.textConfig),!l&&u.textContent&&(l=u.textContent)}if(!e&&l){var h=l;!h.type&&(h.type="text")}var c=e?n[e]:n.normal;c.cfg=a,c.conOpt=l}function KR(t,e){return e?t?t[e]:null:t}function $R(t,e,n){var i=e&&e.style;return null==i&&n===CR&&t&&(i=t.styleEmphasis),i}function JR(t,e,n){e&&gR(e,$O(t).option,n)}function QR(t,e){var n=t&&t.name;return null!=n?n:"e\0\0"+e}function tN(t,e){var n=this.context,i=null!=t?n.newChildren[t]:null,r=null!=e?n.oldChildren[e]:null;ZR(n.api,r,n.dataIndex,i,n.seriesModel,n.group)}function eN(t){var e=this.context,n=e.oldChildren[t];n&&gR(n,$O(n).option,e.seriesModel)}function nN(t){return t&&(t.pathData||t.d)}var iN=Vo(),rN=T,oN=W,aN=function(){function t(){this._dragging=!1,this.animationThreshold=15}return t.prototype.render=function(t,e,n,i){var r=e.get("value"),o=e.get("status");if(this._axisModel=t,this._axisPointerModel=e,this._api=n,i||this._lastValue!==r||this._lastStatus!==o){this._lastValue=r,this._lastStatus=o;var a=this._group,s=this._handle;if(!o||"hide"===o)return a&&a.hide(),void(s&&s.hide());a&&a.show(),s&&s.show();var l={};this.makeElOption(l,r,t,e,n);var u=l.graphicKey;u!==this._lastGraphicKey&&this.clear(n),this._lastGraphicKey=u;var h=this._moveAnimation=this.determineAnimation(t,e);if(a){var c=H(sN,e,h);this.updatePointerEl(a,l,c),this.updateLabelEl(a,l,c,e)}else a=this._group=new Br,this.createPointerEl(a,l,t,e),this.createLabelEl(a,l,t,e),n.getZr().add(a);cN(a,e,!0),this._renderHandle(r)}},t.prototype.remove=function(t){this.clear(t)},t.prototype.dispose=function(t){this.clear(t)},t.prototype.determineAnimation=function(t,e){var n=e.get("animation"),i=t.axis,r="category"===i.type,o=e.get("snap");if(!o&&!r)return!1;if("auto"===n||null==n){var a=this.animationThreshold;if(r&&i.getBandWidth()>a)return!0;if(o){var s=wI(t).seriesDataCount,l=i.getExtent();return Math.abs(l[0]-l[1])/s>a}return!1}return!0===n},t.prototype.makeElOption=function(t,e,n,i,r){},t.prototype.createPointerEl=function(t,e,n,i){var r=e.pointer;if(r){var o=iN(t).pointerEl=new Qh[r.type](rN(e.pointer));t.add(o)}},t.prototype.createLabelEl=function(t,e,n,i){if(e.label){var r=iN(t).labelEl=new Xs(rN(e.label));t.add(r),uN(r,i)}},t.prototype.updatePointerEl=function(t,e,n){var i=iN(t).pointerEl;i&&e.pointer&&(i.setStyle(e.pointer.style),n(i,{shape:e.pointer.shape}))},t.prototype.updateLabelEl=function(t,e,n,i){var r=iN(t).labelEl;r&&(r.setStyle(e.label.style),n(r,{x:e.label.x,y:e.label.y}),uN(r,i))},t.prototype._renderHandle=function(t){if(!this._dragging&&this.updateHandleTransform){var e,n=this._axisPointerModel,i=this._api.getZr(),r=this._handle,o=n.getModel("handle"),a=n.get("status");if(!o.get("show")||!a||"hide"===a)return r&&i.remove(r),void(this._handle=null);this._handle||(e=!0,r=this._handle=Uh(o.get("icon"),{cursor:"move",draggable:!0,onmousemove:function(t){de(t.event)},onmousedown:oN(this._onHandleDragMove,this,0,0),drift:oN(this._onHandleDragMove,this),ondragend:oN(this._onHandleDragEnd,this)}),i.add(r)),cN(r,n,!1),r.setStyle(o.getItemStyle(null,["color","borderColor","borderWidth","opacity","shadowColor","shadowBlur","shadowOffsetX","shadowOffsetY"]));var s=o.get("size");Y(s)||(s=[s,s]),r.scaleX=s[0]/2,r.scaleY=s[1]/2,Hg(this,"_doDispatchAxisPointer",o.get("throttle")||0,"fixRate"),this._moveHandleToValue(t,e)}},t.prototype._moveHandleToValue=function(t,e){sN(this._axisPointerModel,!e&&this._moveAnimation,this._handle,hN(this.getHandleTransform(t,this._axisModel,this._axisPointerModel)))},t.prototype._onHandleDragMove=function(t,e){var n=this._handle;if(n){this._dragging=!0;var i=this.updateHandleTransform(hN(n),[t,e],this._axisModel,this._axisPointerModel);this._payloadInfo=i,n.stopAnimation(),n.attr(hN(i)),iN(n).lastProp=null,this._doDispatchAxisPointer()}},t.prototype._doDispatchAxisPointer=function(){if(this._handle){var t=this._payloadInfo,e=this._axisModel;this._api.dispatchAction({type:"updateAxisPointer",x:t.cursorPoint[0],y:t.cursorPoint[1],tooltipOption:t.tooltipOption,axesInfo:[{axisDim:e.axis.dim,axisIndex:e.componentIndex}]})}},t.prototype._onHandleDragEnd=function(){if(this._dragging=!1,this._handle){var t=this._axisPointerModel.get("value");this._moveHandleToValue(t),this._api.dispatchAction({type:"hideTip"})}},t.prototype.clear=function(t){this._lastValue=null,this._lastStatus=null;var e=t.getZr(),n=this._group,i=this._handle;e&&n&&(this._lastGraphicKey=null,n&&e.remove(n),i&&e.remove(i),this._group=null,this._handle=null,this._payloadInfo=null),Yg(this,"_doDispatchAxisPointer")},t.prototype.doClear=function(){},t.prototype.buildLabel=function(t,e,n){return{x:t[n=n||0],y:t[1-n],width:e[n],height:e[1-n]}},t}();function sN(t,e,n,i){lN(iN(n).lastProp,i)||(iN(n).lastProp=i,e?vh(n,i,t):(n.stopAnimation(),n.attr(i)))}function lN(t,e){if(q(t)&&q(e)){var n=!0;return E(e,(function(e,i){n=n&&lN(t[i],e)})),!!n}return t===e}function uN(t,e){t[e.get(["label","show"])?"show":"hide"]()}function hN(t){return{x:t.x||0,y:t.y||0,rotation:t.rotation||0}}function cN(t,e,n){var i=e.get("z"),r=e.get("zlevel");t&&t.traverse((function(t){"group"!==t.type&&(null!=i&&(t.z=i),null!=r&&(t.zlevel=r),t.silent=n)}))}function pN(t){var e,n=t.get("type"),i=t.getModel(n+"Style");return"line"===n?(e=i.getLineStyle()).fill=null:"shadow"===n&&((e=i.getAreaStyle()).stroke=null),e}function dN(t,e,n,i,r){var o=fN(n.get("value"),e.axis,e.ecModel,n.get("seriesDataIndices"),{precision:n.get(["label","precision"]),formatter:n.get(["label","formatter"])}),a=n.getModel("label"),s=vp(a.get("padding")||0),l=a.getFont(),u=Sr(o,l),h=r.position,c=u.width+s[1]+s[3],p=u.height+s[0]+s[2],d=r.align;"right"===d&&(h[0]-=c),"center"===d&&(h[0]-=c/2);var f=r.verticalAlign;"bottom"===f&&(h[1]-=p),"middle"===f&&(h[1]-=p/2),function(t,e,n,i){var r=i.getWidth(),o=i.getHeight();t[0]=Math.min(t[0]+e,r)-e,t[1]=Math.min(t[1]+n,o)-n,t[0]=Math.max(t[0],0),t[1]=Math.max(t[1],0)}(h,c,p,i);var g=a.get("backgroundColor");g&&"auto"!==g||(g=e.get(["axisLine","lineStyle","color"])),t.label={x:h[0],y:h[1],style:oc(a,{text:o,font:l,fill:a.getTextColor(),padding:s,backgroundColor:g}),z2:10}}function fN(t,e,n,i,r){t=e.scale.parse(t);var o=e.scale.getLabel({value:t},{precision:r.precision}),a=r.formatter;if(a){var s={value:S_(e,{value:t}),axisDimension:e.dim,axisIndex:e.index,seriesData:[]};E(i,(function(t){var e=n.getSeriesByIndex(t.seriesIndex),i=t.dataIndexInside,r=e&&e.getDataParams(i);r&&s.seriesData.push(r)})),U(a)?o=a.replace("{value}",o):X(a)&&(o=a(s))}return o}function gN(t,e,n){var i=[1,0,0,1,0,0];return Se(i,i,n.rotation),we(i,i,n.position),Fh([t.dataToCoord(e),(n.labelOffset||0)+(n.labelDirection||1)*(n.labelMargin||0)],i)}function yN(t,e,n,i,r,o){var a=dI.innerTextLayout(n.rotation,0,n.labelDirection);n.labelMargin=r.get(["label","margin"]),dN(e,i,r,o,{position:gN(i.axis,t,n),align:a.textAlign,verticalAlign:a.textVerticalAlign})}function vN(t,e,n){return{x1:t[n=n||0],y1:t[1-n],x2:e[n],y2:e[1-n]}}function mN(t,e,n){return{x:t[n=n||0],y:t[1-n],width:e[n],height:e[1-n]}}function xN(t,e,n,i,r,o){return{cx:t,cy:e,r0:n,r:i,startAngle:r,endAngle:o,clockwise:!0}}var _N=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.makeElOption=function(t,e,n,i,r){var o=n.axis,a=o.grid,s=i.get("type"),l=bN(a,o).getOtherAxis(o).getGlobalExtent(),u=o.toGlobalCoord(o.dataToCoord(e,!0));if(s&&"none"!==s){var h=pN(i),c=wN[s](o,u,l);c.style=h,t.graphicKey=c.type,t.pointer=c}yN(e,t,iI(a.model,n),n,i,r)},e.prototype.getHandleTransform=function(t,e,n){var i=iI(e.axis.grid.model,e,{labelInside:!1});i.labelMargin=n.get(["handle","margin"]);var r=gN(e.axis,t,i);return{x:r[0],y:r[1],rotation:i.rotation+(i.labelDirection<0?Math.PI:0)}},e.prototype.updateHandleTransform=function(t,e,n,i){var r=n.axis,o=r.grid,a=r.getGlobalExtent(!0),s=bN(o,r).getOtherAxis(r).getGlobalExtent(),l="x"===r.dim?0:1,u=[t.x,t.y];u[l]+=e[l],u[l]=Math.min(a[1],u[l]),u[l]=Math.max(a[0],u[l]);var h=(s[1]+s[0])/2,c=[h,h];c[l]=u[l];return{x:u[0],y:u[1],rotation:t.rotation,cursorPoint:c,tooltipOption:[{verticalAlign:"middle"},{align:"center"}][l]}},e}(aN);function bN(t,e){var n={};return n[e.dim+"AxisIndex"]=e.index,t.getCartesian(n)}var wN={line:function(t,e,n){return{type:"Line",subPixelOptimize:!0,shape:vN([e,n[0]],[e,n[1]],SN(t))}},shadow:function(t,e,n){var i=Math.max(1,t.getBandWidth()),r=n[1]-n[0];return{type:"Rect",shape:mN([e-i/2,n[0]],[i,r],SN(t))}}};function SN(t){return"x"===t.dim?0:1}var MN=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="axisPointer",e.defaultOption={show:"auto",z:50,type:"line",snap:!1,triggerTooltip:!0,triggerEmphasis:!0,value:null,status:null,link:[],animation:null,animationDurationUpdate:200,lineStyle:{color:"#B9BEC9",width:1,type:"dashed"},shadowStyle:{color:"rgba(210,219,238,0.2)"},label:{show:!0,formatter:null,precision:"auto",margin:3,color:"#fff",padding:[5,7,5,7],backgroundColor:"auto",borderColor:null,borderWidth:0,borderRadius:3},handle:{show:!1,icon:"M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z",size:45,margin:50,color:"#333",shadowBlur:3,shadowColor:"#aaa",shadowOffsetX:0,shadowOffsetY:2,throttle:40}},e}(zp),IN=Vo(),TN=E;function CN(t,e,n){if(!r.node){var i=e.getZr();IN(i).records||(IN(i).records={}),function(t,e){if(IN(t).initialized)return;function n(n,i){t.on(n,(function(n){var r=function(t){var e={showTip:[],hideTip:[]},n=function(i){var r=e[i.type];r?r.push(i):(i.dispatchAction=n,t.dispatchAction(i))};return{dispatchAction:n,pendings:e}}(e);TN(IN(t).records,(function(t){t&&i(t,n,r.dispatchAction)})),function(t,e){var n,i=t.showTip.length,r=t.hideTip.length;i?n=t.showTip[i-1]:r&&(n=t.hideTip[r-1]);n&&(n.dispatchAction=null,e.dispatchAction(n))}(r.pendings,e)}))}IN(t).initialized=!0,n("click",H(AN,"click")),n("mousemove",H(AN,"mousemove")),n("globalout",DN)}(i,e),(IN(i).records[t]||(IN(i).records[t]={})).handler=n}}function DN(t,e,n){t.handler("leave",null,n)}function AN(t,e,n,i){e.handler(t,n,i)}function kN(t,e){if(!r.node){var n=e.getZr();(IN(n).records||{})[t]&&(IN(n).records[t]=null)}}var LN=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){var i=e.getComponent("tooltip"),r=t.get("triggerOn")||i&&i.get("triggerOn")||"mousemove|click";CN("axisPointer",n,(function(t,e,n){"none"!==r&&("leave"===t||r.indexOf(t)>=0)&&n({type:"updateAxisPointer",currTrigger:t,x:e&&e.offsetX,y:e&&e.offsetY})}))},e.prototype.remove=function(t,e){kN("axisPointer",e)},e.prototype.dispose=function(t,e){kN("axisPointer",e)},e.type="axisPointer",e}(Ag);function PN(t,e){var n,i=[],r=t.seriesIndex;if(null==r||!(n=e.getSeriesByIndex(r)))return{point:[]};var o=n.getData(),a=zo(o,t);if(null==a||a<0||Y(a))return{point:[]};var s=o.getItemGraphicEl(a),l=n.coordinateSystem;if(n.getTooltipPosition)i=n.getTooltipPosition(a)||[];else if(l&&l.dataToPoint)if(t.isStacked){var u=l.getBaseAxis(),h=l.getOtherAxis(u).dim,c=u.dim,p="x"===h||"radius"===h?1:0,d=o.mapDimension(c),f=[];f[p]=o.get(d,a),f[1-p]=o.get(o.getCalculationInfo("stackResultDimension"),a),i=l.dataToPoint(f)||[]}else i=l.dataToPoint(o.getValues(z(l.dimensions,(function(t){return o.mapDimension(t)})),a))||[];else if(s){var g=s.getBoundingRect().clone();g.applyTransform(s.transform),i=[g.x+g.width/2,g.y+g.height/2]}return{point:i,el:s}}var ON=Vo();function RN(t,e,n){var i=t.currTrigger,r=[t.x,t.y],o=t,a=t.dispatchAction||W(n.dispatchAction,n),s=e.getComponent("axisPointer").coordSysAxesInfo;if(s){BN(r)&&(r=PN({seriesIndex:o.seriesIndex,dataIndex:o.dataIndex},e).point);var l=BN(r),u=o.axesInfo,h=s.axesInfo,c="leave"===i||BN(r),p={},d={},f={list:[],map:{}},g={showPointer:H(EN,d),showTooltip:H(zN,f)};E(s.coordSysMap,(function(t,e){var n=l||t.containPoint(r);E(s.coordSysAxesInfo[e],(function(t,e){var i=t.axis,o=function(t,e){for(var n=0;n<(t||[]).length;n++){var i=t[n];if(e.axis.dim===i.axisDim&&e.axis.model.componentIndex===i.axisIndex)return i}}(u,t);if(!c&&n&&(!u||o)){var a=o&&o.value;null!=a||l||(a=i.pointToData(r)),null!=a&&NN(t,a,g,!1,p)}}))}));var y={};return E(h,(function(t,e){var n=t.linkGroup;n&&!d[e]&&E(n.axesInfo,(function(e,i){var r=d[i];if(e!==t&&r){var o=r.value;n.mapper&&(o=t.axis.scale.parse(n.mapper(o,VN(e),VN(t)))),y[t.key]=o}}))})),E(y,(function(t,e){NN(h[e],t,g,!0,p)})),function(t,e,n){var i=n.axesInfo=[];E(e,(function(e,n){var r=e.axisPointerModel.option,o=t[n];o?(!e.useHandle&&(r.status="show"),r.value=o.value,r.seriesDataIndices=(o.payloadBatch||[]).slice()):!e.useHandle&&(r.status="hide"),"show"===r.status&&i.push({axisDim:e.axis.dim,axisIndex:e.axis.model.componentIndex,value:r.value})}))}(d,h,p),function(t,e,n,i){if(BN(e)||!t.list.length)return void i({type:"hideTip"});var r=((t.list[0].dataByAxis[0]||{}).seriesDataIndices||[])[0]||{};i({type:"showTip",escapeConnect:!0,x:e[0],y:e[1],tooltipOption:n.tooltipOption,position:n.position,dataIndexInside:r.dataIndexInside,dataIndex:r.dataIndex,seriesIndex:r.seriesIndex,dataByCoordSys:t.list})}(f,r,t,a),function(t,e,n){var i=n.getZr(),r="axisPointerLastHighlights",o=ON(i)[r]||{},a=ON(i)[r]={};E(t,(function(t,e){var n=t.axisPointerModel.option;"show"===n.status&&t.triggerEmphasis&&E(n.seriesDataIndices,(function(t){var e=t.seriesIndex+" | "+t.dataIndex;a[e]=t}))}));var s=[],l=[];E(o,(function(t,e){!a[e]&&l.push(t)})),E(a,(function(t,e){!o[e]&&s.push(t)})),l.length&&n.dispatchAction({type:"downplay",escapeConnect:!0,notBlur:!0,batch:l}),s.length&&n.dispatchAction({type:"highlight",escapeConnect:!0,notBlur:!0,batch:s})}(h,0,n),p}}function NN(t,e,n,i,r){var o=t.axis;if(!o.scale.isBlank()&&o.containData(e))if(t.involveSeries){var a=function(t,e){var n=e.axis,i=n.dim,r=t,o=[],a=Number.MAX_VALUE,s=-1;return E(e.seriesModels,(function(e,l){var u,h,c=e.getData().mapDimensionsAll(i);if(e.getAxisTooltipData){var p=e.getAxisTooltipData(c,t,n);h=p.dataIndices,u=p.nestestValue}else{if(!(h=e.getData().indicesOfNearest(c[0],t,"category"===n.type?.5:null)).length)return;u=e.getData().get(c[0],h[0])}if(null!=u&&isFinite(u)){var d=t-u,f=Math.abs(d);f<=a&&((f=0&&s<0)&&(a=f,s=d,r=u,o.length=0),E(h,(function(t){o.push({seriesIndex:e.seriesIndex,dataIndexInside:t,dataIndex:e.getData().getRawIndex(t)})})))}})),{payloadBatch:o,snapToValue:r}}(e,t),s=a.payloadBatch,l=a.snapToValue;s[0]&&null==r.seriesIndex&&A(r,s[0]),!i&&t.snap&&o.containData(l)&&null!=l&&(e=l),n.showPointer(t,e,s),n.showTooltip(t,a,l)}else n.showPointer(t,e)}function EN(t,e,n,i){t[e.key]={value:n,payloadBatch:i}}function zN(t,e,n,i){var r=n.payloadBatch,o=e.axis,a=o.model,s=e.axisPointerModel;if(e.triggerTooltip&&r.length){var l=e.coordSys.model,u=MI(l),h=t.map[u];h||(h=t.map[u]={coordSysId:l.id,coordSysIndex:l.componentIndex,coordSysType:l.type,coordSysMainType:l.mainType,dataByAxis:[]},t.list.push(h)),h.dataByAxis.push({axisDim:o.dim,axisIndex:a.componentIndex,axisType:a.type,axisId:a.id,value:i,valueLabelOpt:{precision:s.get(["label","precision"]),formatter:s.get(["label","formatter"])},seriesDataIndices:r.slice()})}}function VN(t){var e=t.axis.model,n={},i=n.axisDim=t.axis.dim;return n.axisIndex=n[i+"AxisIndex"]=e.componentIndex,n.axisName=n[i+"AxisName"]=e.name,n.axisId=n[i+"AxisId"]=e.id,n}function BN(t){return!t||null==t[0]||isNaN(t[0])||null==t[1]||isNaN(t[1])}function FN(t){TI.registerAxisPointerClass("CartesianAxisPointer",_N),t.registerComponentModel(MN),t.registerComponentView(LN),t.registerPreprocessor((function(t){if(t){(!t.axisPointer||0===t.axisPointer.length)&&(t.axisPointer={});var e=t.axisPointer.link;e&&!Y(e)&&(t.axisPointer.link=[e])}})),t.registerProcessor(t.PRIORITY.PROCESSOR.STATISTIC,(function(t,e){t.getComponent("axisPointer").coordSysAxesInfo=xI(t,e)})),t.registerAction({type:"updateAxisPointer",event:"updateAxisPointer",update:":updateAxisPointer"},RN)}var GN=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.makeElOption=function(t,e,n,i,r){var o=n.axis;"angle"===o.dim&&(this.animationThreshold=Math.PI/18);var a=o.polar,s=a.getOtherAxis(o).getExtent(),l=o.dataToCoord(e),u=i.get("type");if(u&&"none"!==u){var h=pN(i),c=WN[u](o,a,l,s);c.style=h,t.graphicKey=c.type,t.pointer=c}var p=function(t,e,n,i,r){var o=e.axis,a=o.dataToCoord(t),s=i.getAngleAxis().getExtent()[0];s=s/180*Math.PI;var l,u,h,c=i.getRadiusAxis().getExtent();if("radius"===o.dim){var p=[1,0,0,1,0,0];Se(p,p,s),we(p,p,[i.cx,i.cy]),l=Fh([a,-r],p);var d=e.getModel("axisLabel").get("rotate")||0,f=dI.innerTextLayout(s,d*Math.PI/180,-1);u=f.textAlign,h=f.textVerticalAlign}else{var g=c[1];l=i.coordToPoint([g+r,a]);var y=i.cx,v=i.cy;u=Math.abs(l[0]-y)/g<.3?"center":l[0]>y?"left":"right",h=Math.abs(l[1]-v)/g<.3?"middle":l[1]>v?"top":"bottom"}return{position:l,align:u,verticalAlign:h}}(e,n,0,a,i.get(["label","margin"]));dN(t,n,i,r,p)},e}(aN);var WN={line:function(t,e,n,i){return"angle"===t.dim?{type:"Line",shape:vN(e.coordToPoint([i[0],n]),e.coordToPoint([i[1],n]))}:{type:"Circle",shape:{cx:e.cx,cy:e.cy,r:n}}},shadow:function(t,e,n,i){var r=Math.max(1,t.getBandWidth()),o=Math.PI/180;return"angle"===t.dim?{type:"Sector",shape:xN(e.cx,e.cy,i[0],i[1],(-n-r/2)*o,(r/2-n)*o)}:{type:"Sector",shape:xN(e.cx,e.cy,n-r/2,n+r/2,0,2*Math.PI)}}},HN=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.findAxisModel=function(t){var e;return this.ecModel.eachComponent(t,(function(t){t.getCoordSysModel()===this&&(e=t)}),this),e},e.type="polar",e.dependencies=["radiusAxis","angleAxis"],e.defaultOption={z:0,center:["50%","50%"],radius:"80%"},e}(zp),YN=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.getCoordSysModel=function(){return this.getReferringComponents("polar",Wo).models[0]},e.type="polarAxis",e}(zp);R(YN,D_);var XN=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="angleAxis",e}(YN),UN=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="radiusAxis",e}(YN),ZN=function(t){function e(e,n){return t.call(this,"radius",e,n)||this}return n(e,t),e.prototype.pointToData=function(t,e){return this.polar.pointToData(t,e)["radius"===this.dim?0:1]},e}(ab);ZN.prototype.dataToRadius=ab.prototype.dataToCoord,ZN.prototype.radiusToData=ab.prototype.coordToData;var jN=Vo(),qN=function(t){function e(e,n){return t.call(this,"angle",e,n||[0,360])||this}return n(e,t),e.prototype.pointToData=function(t,e){return this.polar.pointToData(t,e)["radius"===this.dim?0:1]},e.prototype.calculateCategoryInterval=function(){var t=this,e=t.getLabelModel(),n=t.scale,i=n.getExtent(),r=n.count();if(i[1]-i[0]<1)return 0;var o=i[0],a=t.dataToCoord(o+1)-t.dataToCoord(o),s=Math.abs(a),l=Sr(null==o?"":o+"",e.getFont(),"center","top"),u=Math.max(l.height,7)/s;isNaN(u)&&(u=1/0);var h=Math.max(0,Math.floor(u)),c=jN(t.model),p=c.lastAutoInterval,d=c.lastTickCount;return null!=p&&null!=d&&Math.abs(p-h)<=1&&Math.abs(d-r)<=1&&p>h?h=p:(c.lastTickCount=r,c.lastAutoInterval=h),h},e}(ab);qN.prototype.dataToAngle=ab.prototype.dataToCoord,qN.prototype.angleToData=ab.prototype.coordToData;var KN=["radius","angle"],$N=function(){function t(t){this.dimensions=KN,this.type="polar",this.cx=0,this.cy=0,this._radiusAxis=new ZN,this._angleAxis=new qN,this.axisPointerEnabled=!0,this.name=t||"",this._radiusAxis.polar=this._angleAxis.polar=this}return t.prototype.containPoint=function(t){var e=this.pointToCoord(t);return this._radiusAxis.contain(e[0])&&this._angleAxis.contain(e[1])},t.prototype.containData=function(t){return this._radiusAxis.containData(t[0])&&this._angleAxis.containData(t[1])},t.prototype.getAxis=function(t){return this["_"+t+"Axis"]},t.prototype.getAxes=function(){return[this._radiusAxis,this._angleAxis]},t.prototype.getAxesByScale=function(t){var e=[],n=this._angleAxis,i=this._radiusAxis;return n.scale.type===t&&e.push(n),i.scale.type===t&&e.push(i),e},t.prototype.getAngleAxis=function(){return this._angleAxis},t.prototype.getRadiusAxis=function(){return this._radiusAxis},t.prototype.getOtherAxis=function(t){var e=this._angleAxis;return t===e?this._radiusAxis:e},t.prototype.getBaseAxis=function(){return this.getAxesByScale("ordinal")[0]||this.getAxesByScale("time")[0]||this.getAngleAxis()},t.prototype.getTooltipAxes=function(t){var e=null!=t&&"auto"!==t?this.getAxis(t):this.getBaseAxis();return{baseAxes:[e],otherAxes:[this.getOtherAxis(e)]}},t.prototype.dataToPoint=function(t,e){return this.coordToPoint([this._radiusAxis.dataToRadius(t[0],e),this._angleAxis.dataToAngle(t[1],e)])},t.prototype.pointToData=function(t,e){var n=this.pointToCoord(t);return[this._radiusAxis.radiusToData(n[0],e),this._angleAxis.angleToData(n[1],e)]},t.prototype.pointToCoord=function(t){var e=t[0]-this.cx,n=t[1]-this.cy,i=this.getAngleAxis(),r=i.getExtent(),o=Math.min(r[0],r[1]),a=Math.max(r[0],r[1]);i.inverse?o=a-360:a=o+360;var s=Math.sqrt(e*e+n*n);e/=s,n/=s;for(var l=Math.atan2(-n,e)/Math.PI*180,u=la;)l+=360*u;return[s,l]},t.prototype.coordToPoint=function(t){var e=t[0],n=t[1]/180*Math.PI;return[Math.cos(n)*e+this.cx,-Math.sin(n)*e+this.cy]},t.prototype.getArea=function(){var t=this.getAngleAxis(),e=this.getRadiusAxis().getExtent().slice();e[0]>e[1]&&e.reverse();var n=t.getExtent(),i=Math.PI/180;return{cx:this.cx,cy:this.cy,r0:e[0],r:e[1],startAngle:-n[0]*i,endAngle:-n[1]*i,clockwise:t.inverse,contain:function(t,e){var n=t-this.cx,i=e-this.cy,r=n*n+i*i-1e-4,o=this.r,a=this.r0;return r<=o*o&&r>=a*a}}},t.prototype.convertToPixel=function(t,e,n){return JN(e)===this?this.dataToPoint(n):null},t.prototype.convertFromPixel=function(t,e,n){return JN(e)===this?this.pointToData(n):null},t}();function JN(t){var e=t.seriesModel,n=t.polarModel;return n&&n.coordinateSystem||e&&e.coordinateSystem}function QN(t,e){var n=this,i=n.getAngleAxis(),r=n.getRadiusAxis();if(i.scale.setExtent(1/0,-1/0),r.scale.setExtent(1/0,-1/0),t.eachSeries((function(t){if(t.coordinateSystem===n){var e=t.getData();E(C_(e,"radius"),(function(t){r.scale.unionExtentFromData(e,t)})),E(C_(e,"angle"),(function(t){i.scale.unionExtentFromData(e,t)}))}})),__(i.scale,i.model),__(r.scale,r.model),"category"===i.type&&!i.onBand){var o=i.getExtent(),a=360/i.scale.count();i.inverse?o[1]+=a:o[1]-=a,i.setExtent(o[0],o[1])}}function tE(t,e){var n;if(t.type=e.get("type"),t.scale=b_(e),t.onBand=e.get("boundaryGap")&&"category"===t.type,t.inverse=e.get("inverse"),function(t){return"angleAxis"===t.mainType}(e)){t.inverse=t.inverse!==e.get("clockwise");var i=e.get("startAngle"),r=null!==(n=e.get("endAngle"))&&void 0!==n?n:i+(t.inverse?-360:360);t.setExtent(i,r)}e.axis=t,t.model=e}var eE={dimensions:KN,create:function(t,e){var n=[];return t.eachComponent("polar",(function(t,i){var r=new $N(i+"");r.update=QN;var o=r.getRadiusAxis(),a=r.getAngleAxis(),s=t.findAxisModel("radiusAxis"),l=t.findAxisModel("angleAxis");tE(o,s),tE(a,l),function(t,e,n){var i=e.get("center"),r=n.getWidth(),o=n.getHeight();t.cx=$r(i[0],r),t.cy=$r(i[1],o);var a=t.getRadiusAxis(),s=Math.min(r,o)/2,l=e.get("radius");null==l?l=[0,"100%"]:Y(l)||(l=[0,l]);var u=[$r(l[0],s),$r(l[1],s)];a.inverse?a.setExtent(u[1],u[0]):a.setExtent(u[0],u[1])}(r,t,e),n.push(r),t.coordinateSystem=r,r.model=t})),t.eachSeries((function(t){if("polar"===t.get("coordinateSystem")){var e=t.getReferringComponents("polar",Wo).models[0];0,t.coordinateSystem=e.coordinateSystem}})),n}},nE=["axisLine","axisLabel","axisTick","minorTick","splitLine","minorSplitLine","splitArea"];function iE(t,e,n){e[1]>e[0]&&(e=e.slice().reverse());var i=t.coordToPoint([e[0],n]),r=t.coordToPoint([e[1],n]);return{x1:i[0],y1:i[1],x2:r[0],y2:r[1]}}function rE(t){return t.getRadiusAxis().inverse?0:1}function oE(t){var e=t[0],n=t[t.length-1];e&&n&&Math.abs(Math.abs(e.coord-n.coord)-360)<1e-4&&t.pop()}var aE=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.axisPointerClass="PolarAxisPointer",n}return n(e,t),e.prototype.render=function(t,e){if(this.group.removeAll(),t.get("show")){var n=t.axis,i=n.polar,r=i.getRadiusAxis().getExtent(),o=n.getTicksCoords(),a=n.getMinorTicksCoords(),s=z(n.getViewLabels(),(function(t){t=T(t);var e=n.scale,i="ordinal"===e.type?e.getRawOrdinalNumber(t.tickValue):t.tickValue;return t.coord=n.dataToCoord(i),t}));oE(s),oE(o),E(nE,(function(e){!t.get([e,"show"])||n.scale.isBlank()&&"axisLine"!==e||sE[e](this.group,t,i,o,a,r,s)}),this)}},e.type="angleAxis",e}(TI),sE={axisLine:function(t,e,n,i,r,o){var a,s=e.getModel(["axisLine","lineStyle"]),l=n.getAngleAxis(),u=Math.PI/180,h=l.getExtent(),c=rE(n),p=c?0:1,d=360===Math.abs(h[1]-h[0])?"Circle":"Arc";(a=0===o[p]?new Qh[d]({shape:{cx:n.cx,cy:n.cy,r:o[c],startAngle:-h[0]*u,endAngle:-h[1]*u,clockwise:l.inverse},style:s.getLineStyle(),z2:1,silent:!0}):new Wu({shape:{cx:n.cx,cy:n.cy,r:o[c],r0:o[p]},style:s.getLineStyle(),z2:1,silent:!0})).style.fill=null,t.add(a)},axisTick:function(t,e,n,i,r,o){var a=e.getModel("axisTick"),s=(a.get("inside")?-1:1)*a.get("length"),l=o[rE(n)],u=z(i,(function(t){return new Ku({shape:iE(n,[l,l+s],t.coord)})}));t.add(Nh(u,{style:k(a.getModel("lineStyle").getLineStyle(),{stroke:e.get(["axisLine","lineStyle","color"])})}))},minorTick:function(t,e,n,i,r,o){if(r.length){for(var a=e.getModel("axisTick"),s=e.getModel("minorTick"),l=(a.get("inside")?-1:1)*s.get("length"),u=o[rE(n)],h=[],c=0;cf?"left":"right",v=Math.abs(d[1]-g)/p<.3?"middle":d[1]>g?"top":"bottom";if(s&&s[c]){var m=s[c];q(m)&&m.textStyle&&(a=new Cc(m.textStyle,l,l.ecModel))}var x=new Xs({silent:dI.isLabelSilent(e),style:oc(a,{x:d[0],y:d[1],fill:a.getTextColor()||e.get(["axisLine","lineStyle","color"]),text:i.formattedLabel,align:y,verticalAlign:v})});if(t.add(x),h){var _=dI.makeAxisEventDataBase(e);_.targetType="axisLabel",_.value=i.rawLabel,rl(x).eventData=_}}),this)},splitLine:function(t,e,n,i,r,o){var a=e.getModel("splitLine").getModel("lineStyle"),s=a.get("color"),l=0;s=s instanceof Array?s:[s];for(var u=[],h=0;h=0?"p":"n",C=b;m&&(i[s][I]||(i[s][I]={p:b,n:b}),C=i[s][I][T]);var D=void 0,A=void 0,k=void 0,L=void 0;if("radius"===c.dim){var P=c.dataToCoord(M)-b,O=o.dataToCoord(I);Math.abs(P)=L})}}}))}var gE={startAngle:90,clockwise:!0,splitNumber:12,axisLabel:{rotate:0}},yE={splitNumber:5},vE=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="polar",e}(Ag);function mE(t,e){e=e||{};var n=t.coordinateSystem,i=t.axis,r={},o=i.position,a=i.orient,s=n.getRect(),l=[s.x,s.x+s.width,s.y,s.y+s.height],u={horizontal:{top:l[2],bottom:l[3]},vertical:{left:l[0],right:l[1]}};r.position=["vertical"===a?u.vertical[o]:l[0],"horizontal"===a?u.horizontal[o]:l[3]];r.rotation=Math.PI/2*{horizontal:0,vertical:1}[a];r.labelDirection=r.tickDirection=r.nameDirection={top:-1,bottom:1,right:1,left:-1}[o],t.get(["axisTick","inside"])&&(r.tickDirection=-r.tickDirection),it(e.labelInside,t.get(["axisLabel","inside"]))&&(r.labelDirection=-r.labelDirection);var h=e.rotate;return null==h&&(h=t.get(["axisLabel","rotate"])),r.labelRotation="top"===o?-h:h,r.z2=1,r}var xE=["axisLine","axisTickLabel","axisName"],_E=["splitArea","splitLine"],bE=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.axisPointerClass="SingleAxisPointer",n}return n(e,t),e.prototype.render=function(e,n,i,r){var o=this.group;o.removeAll();var a=this._axisGroup;this._axisGroup=new Br;var s=mE(e),l=new dI(e,s);E(xE,l.add,l),o.add(this._axisGroup),o.add(l.getGroup()),E(_E,(function(t){e.get([t,"show"])&&wE[t](this,this.group,this._axisGroup,e)}),this),Hh(a,this._axisGroup,e),t.prototype.render.call(this,e,n,i,r)},e.prototype.remove=function(){AI(this)},e.type="singleAxis",e}(TI),wE={splitLine:function(t,e,n,i){var r=i.axis;if(!r.scale.isBlank()){var o=i.getModel("splitLine"),a=o.getModel("lineStyle"),s=a.get("color");s=s instanceof Array?s:[s];for(var l=a.get("width"),u=i.coordinateSystem.getRect(),h=r.isHorizontal(),c=[],p=0,d=r.getTicksCoords({tickModel:o}),f=[],g=[],y=0;y=e.y&&t[1]<=e.y+e.height:n.contain(n.toLocalCoord(t[1]))&&t[0]>=e.y&&t[0]<=e.y+e.height},t.prototype.pointToData=function(t){var e=this.getAxis();return[e.coordToData(e.toLocalCoord(t["horizontal"===e.orient?0:1]))]},t.prototype.dataToPoint=function(t){var e=this.getAxis(),n=this.getRect(),i=[],r="horizontal"===e.orient?0:1;return t instanceof Array&&(t=t[0]),i[r]=e.toGlobalCoord(e.dataToCoord(+t)),i[1-r]=0===r?n.y+n.height/2:n.x+n.width/2,i},t.prototype.convertToPixel=function(t,e,n){return CE(e)===this?this.dataToPoint(n):null},t.prototype.convertFromPixel=function(t,e,n){return CE(e)===this?this.pointToData(n):null},t}();function CE(t){var e=t.seriesModel,n=t.singleAxisModel;return n&&n.coordinateSystem||e&&e.coordinateSystem}var DE={create:function(t,e){var n=[];return t.eachComponent("singleAxis",(function(i,r){var o=new TE(i,t,e);o.name="single_"+r,o.resize(i,e),i.coordinateSystem=o,n.push(o)})),t.eachSeries((function(t){if("singleAxis"===t.get("coordinateSystem")){var e=t.getReferringComponents("singleAxis",Wo).models[0];t.coordinateSystem=e&&e.coordinateSystem}})),n},dimensions:IE},AE=["x","y"],kE=["width","height"],LE=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.makeElOption=function(t,e,n,i,r){var o=n.axis,a=o.coordinateSystem,s=RE(a,1-OE(o)),l=a.dataToPoint(e)[0],u=i.get("type");if(u&&"none"!==u){var h=pN(i),c=PE[u](o,l,s);c.style=h,t.graphicKey=c.type,t.pointer=c}yN(e,t,mE(n),n,i,r)},e.prototype.getHandleTransform=function(t,e,n){var i=mE(e,{labelInside:!1});i.labelMargin=n.get(["handle","margin"]);var r=gN(e.axis,t,i);return{x:r[0],y:r[1],rotation:i.rotation+(i.labelDirection<0?Math.PI:0)}},e.prototype.updateHandleTransform=function(t,e,n,i){var r=n.axis,o=r.coordinateSystem,a=OE(r),s=RE(o,a),l=[t.x,t.y];l[a]+=e[a],l[a]=Math.min(s[1],l[a]),l[a]=Math.max(s[0],l[a]);var u=RE(o,1-a),h=(u[1]+u[0])/2,c=[h,h];return c[a]=l[a],{x:l[0],y:l[1],rotation:t.rotation,cursorPoint:c,tooltipOption:{verticalAlign:"middle"}}},e}(aN),PE={line:function(t,e,n){return{type:"Line",subPixelOptimize:!0,shape:vN([e,n[0]],[e,n[1]],OE(t))}},shadow:function(t,e,n){var i=t.getBandWidth(),r=n[1]-n[0];return{type:"Rect",shape:mN([e-i/2,n[0]],[i,r],OE(t))}}};function OE(t){return t.isHorizontal()?0:1}function RE(t,e){var n=t.getRect();return[n[AE[e]],n[AE[e]]+n[kE[e]]]}var NE=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="single",e}(Ag);var EE=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(e,n,i){var r=Rp(e);t.prototype.init.apply(this,arguments),zE(e,r)},e.prototype.mergeOption=function(e){t.prototype.mergeOption.apply(this,arguments),zE(this.option,e)},e.prototype.getCellSize=function(){return this.option.cellSize},e.type="calendar",e.defaultOption={z:2,left:80,top:60,cellSize:20,orient:"horizontal",splitLine:{show:!0,lineStyle:{color:"#000",width:1,type:"solid"}},itemStyle:{color:"#fff",borderWidth:1,borderColor:"#ccc"},dayLabel:{show:!0,firstDay:0,position:"start",margin:"50%",color:"#000"},monthLabel:{show:!0,position:"start",margin:5,align:"center",formatter:null,color:"#000"},yearLabel:{show:!0,position:null,margin:30,formatter:null,color:"#ccc",fontFamily:"sans-serif",fontWeight:"bolder",fontSize:20}},e}(zp);function zE(t,e){var n,i=t.cellSize;1===(n=Y(i)?i:t.cellSize=[i,i]).length&&(n[1]=n[0]);var r=z([0,1],(function(t){return function(t,e){return null!=t[Cp[e][0]]||null!=t[Cp[e][1]]&&null!=t[Cp[e][2]]}(e,t)&&(n[t]="auto"),null!=n[t]&&"auto"!==n[t]}));Op(t,e,{type:"box",ignoreSize:r})}var VE=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){var i=this.group;i.removeAll();var r=t.coordinateSystem,o=r.getRangeInfo(),a=r.getOrient(),s=e.getLocaleModel();this._renderDayRect(t,o,i),this._renderLines(t,o,a,i),this._renderYearText(t,o,a,i),this._renderMonthText(t,s,a,i),this._renderWeekText(t,s,o,a,i)},e.prototype._renderDayRect=function(t,e,n){for(var i=t.coordinateSystem,r=t.getModel("itemStyle").getItemStyle(),o=i.getCellWidth(),a=i.getCellHeight(),s=e.start.time;s<=e.end.time;s=i.getNextNDay(s,1).time){var l=i.dataToRect([s],!1).tl,u=new Ws({shape:{x:l[0],y:l[1],width:o,height:a},cursor:"default",style:r});n.add(u)}},e.prototype._renderLines=function(t,e,n,i){var r=this,o=t.coordinateSystem,a=t.getModel(["splitLine","lineStyle"]).getLineStyle(),s=t.get(["splitLine","show"]),l=a.lineWidth;this._tlpoints=[],this._blpoints=[],this._firstDayOfMonth=[],this._firstDayPoints=[];for(var u=e.start,h=0;u.time<=e.end.time;h++){p(u.formatedDate),0===h&&(u=o.getDateInfo(e.start.y+"-"+e.start.m));var c=u.date;c.setMonth(c.getMonth()+1),u=o.getDateInfo(c)}function p(e){r._firstDayOfMonth.push(o.getDateInfo(e)),r._firstDayPoints.push(o.dataToRect([e],!1).tl);var l=r._getLinePointsOfOneWeek(t,e,n);r._tlpoints.push(l[0]),r._blpoints.push(l[l.length-1]),s&&r._drawSplitline(l,a,i)}p(o.getNextNDay(e.end.time,1).formatedDate),s&&this._drawSplitline(r._getEdgesPoints(r._tlpoints,l,n),a,i),s&&this._drawSplitline(r._getEdgesPoints(r._blpoints,l,n),a,i)},e.prototype._getEdgesPoints=function(t,e,n){var i=[t[0].slice(),t[t.length-1].slice()],r="horizontal"===n?0:1;return i[0][r]=i[0][r]-e/2,i[1][r]=i[1][r]+e/2,i},e.prototype._drawSplitline=function(t,e,n){var i=new Zu({z2:20,shape:{points:t},style:e});n.add(i)},e.prototype._getLinePointsOfOneWeek=function(t,e,n){for(var i=t.coordinateSystem,r=i.getDateInfo(e),o=[],a=0;a<7;a++){var s=i.getNextNDay(r.time,a),l=i.dataToRect([s.time],!1);o[2*s.day]=l.tl,o[2*s.day+1]=l["horizontal"===n?"bl":"tr"]}return o},e.prototype._formatterLabel=function(t,e){return U(t)&&t?(n=t,E(e,(function(t,e){n=n.replace("{"+e+"}",i?re(t):t)})),n):X(t)?t(e):e.nameMap;var n,i},e.prototype._yearTextPositionControl=function(t,e,n,i,r){var o=e[0],a=e[1],s=["center","bottom"];"bottom"===i?(a+=r,s=["center","top"]):"left"===i?o-=r:"right"===i?(o+=r,s=["center","top"]):a-=r;var l=0;return"left"!==i&&"right"!==i||(l=Math.PI/2),{rotation:l,x:o,y:a,style:{align:s[0],verticalAlign:s[1]}}},e.prototype._renderYearText=function(t,e,n,i){var r=t.getModel("yearLabel");if(r.get("show")){var o=r.get("margin"),a=r.get("position");a||(a="horizontal"!==n?"top":"left");var s=[this._tlpoints[this._tlpoints.length-1],this._blpoints[0]],l=(s[0][0]+s[1][0])/2,u=(s[0][1]+s[1][1])/2,h="horizontal"===n?0:1,c={top:[l,s[h][1]],bottom:[l,s[1-h][1]],left:[s[1-h][0],u],right:[s[h][0],u]},p=e.start.y;+e.end.y>+e.start.y&&(p=p+"-"+e.end.y);var d=r.get("formatter"),f={start:e.start.y,end:e.end.y,nameMap:p},g=this._formatterLabel(d,f),y=new Xs({z2:30,style:oc(r,{text:g})});y.attr(this._yearTextPositionControl(y,c[a],n,a,o)),i.add(y)}},e.prototype._monthTextPositionControl=function(t,e,n,i,r){var o="left",a="top",s=t[0],l=t[1];return"horizontal"===n?(l+=r,e&&(o="center"),"start"===i&&(a="bottom")):(s+=r,e&&(a="middle"),"start"===i&&(o="right")),{x:s,y:l,align:o,verticalAlign:a}},e.prototype._renderMonthText=function(t,e,n,i){var r=t.getModel("monthLabel");if(r.get("show")){var o=r.get("nameMap"),a=r.get("margin"),s=r.get("position"),l=r.get("align"),u=[this._tlpoints,this._blpoints];o&&!U(o)||(o&&(e=Vc(o)||e),o=e.get(["time","monthAbbr"])||[]);var h="start"===s?0:1,c="horizontal"===n?0:1;a="start"===s?-a:a;for(var p="center"===l,d=0;d=i.start.time&&n.timea.end.time&&t.reverse(),t},t.prototype._getRangeInfo=function(t){var e,n=[this.getDateInfo(t[0]),this.getDateInfo(t[1])];n[0].time>n[1].time&&(e=!0,n.reverse());var i=Math.floor(n[1].time/BE)-Math.floor(n[0].time/BE)+1,r=new Date(n[0].time),o=r.getDate(),a=n[1].date.getDate();r.setDate(o+i-1);var s=r.getDate();if(s!==a)for(var l=r.getTime()-n[1].time>0?1:-1;(s=r.getDate())!==a&&(r.getTime()-n[1].time)*l>0;)i-=l,r.setDate(s-l);var u=Math.floor((i+n[0].day+6)/7),h=e?1-u:u-1;return e&&n.reverse(),{range:[n[0].formatedDate,n[1].formatedDate],start:n[0],end:n[1],allDay:i,weeks:u,nthWeek:h,fweek:n[0].day,lweek:n[1].day}},t.prototype._getDateByWeeksAndDay=function(t,e,n){var i=this._getRangeInfo(n);if(t>i.weeks||0===t&&ei.lweek)return null;var r=7*(t-1)-i.fweek+e,o=new Date(i.start.time);return o.setDate(+i.start.d+r),this.getDateInfo(o)},t.create=function(e,n){var i=[];return e.eachComponent("calendar",(function(r){var o=new t(r,e,n);i.push(o),r.coordinateSystem=o})),e.eachSeries((function(t){"calendar"===t.get("coordinateSystem")&&(t.coordinateSystem=i[t.get("calendarIndex")||0])})),i},t.dimensions=["time","value"],t}();function GE(t){var e=t.calendarModel,n=t.seriesModel;return e?e.coordinateSystem:n?n.coordinateSystem:null}function WE(t,e){var n;return E(e,(function(e){null!=t[e]&&"auto"!==t[e]&&(n=!0)})),n}var HE=["transition","enterFrom","leaveTo"],YE=HE.concat(["enterAnimation","updateAnimation","leaveAnimation"]);function XE(t,e,n){if(n&&(!t[n]&&e[n]&&(t[n]={}),t=t[n],e=e[n]),t&&e)for(var i=n?HE:YE,r=0;r=0;l--){var p,d,f;if(f=null!=(d=Ro((p=n[l]).id,null))?r.get(d):null){var g=f.parent,y=(c=jE(g),{}),v=Lp(f,p,g===i?{width:o,height:a}:{width:c.width,height:c.height},null,{hv:p.hv,boundingMode:p.bounding},y);if(!jE(f).isNew&&v){for(var m=p.transition,x={},_=0;_=0)?x[b]=w:f[b]=w}vh(f,x,t,0)}else f.attr(y)}}},e.prototype._clear=function(){var t=this,e=this._elMap;e.each((function(n){JE(n,jE(n).option,e,t._lastGraphicModel)})),this._elMap=yt()},e.prototype.dispose=function(){this._clear()},e.type="graphic",e}(Ag);function KE(t){var e=_t(ZE,t)?ZE[t]:Lh(t);var n=new e({});return jE(n).type=t,n}function $E(t,e,n,i){var r=KE(n);return e.add(r),i.set(t,r),jE(r).id=t,jE(r).isNew=!0,r}function JE(t,e,n,i){t&&t.parent&&("group"===t.type&&t.traverse((function(t){JE(t,e,n,i)})),gR(t,e,i),n.removeKey(jE(t).id))}function QE(t,e,n,i){t.isGroup||E([["cursor",Da.prototype.cursor],["zlevel",i||0],["z",n||0],["z2",0]],(function(n){var i=n[0];_t(e,i)?t[i]=rt(e[i],n[1]):null==t[i]&&(t[i]=n[1])})),E(G(e),(function(n){if(0===n.indexOf("on")){var i=e[n];t[n]=X(i)?i:null}})),_t(e,"draggable")&&(t.draggable=e.draggable),null!=e.name&&(t.name=e.name),null!=e.id&&(t.id=e.id)}var tz=["x","y","radius","angle","single"],ez=["cartesian2d","polar","singleAxis"];function nz(t){return t+"Axis"}function iz(t,e){var n,i=yt(),r=[],o=yt();t.eachComponent({mainType:"dataZoom",query:e},(function(t){o.get(t.uid)||s(t)}));do{n=!1,t.eachComponent("dataZoom",a)}while(n);function a(t){!o.get(t.uid)&&function(t){var e=!1;return t.eachTargetAxis((function(t,n){var r=i.get(t);r&&r[n]&&(e=!0)})),e}(t)&&(s(t),n=!0)}function s(t){o.set(t.uid,!0),r.push(t),t.eachTargetAxis((function(t,e){(i.get(t)||i.set(t,[]))[e]=!0}))}return r}function rz(t){var e=t.ecModel,n={infoList:[],infoMap:yt()};return t.eachTargetAxis((function(t,i){var r=e.getComponent(nz(t),i);if(r){var o=r.getCoordSysModel();if(o){var a=o.uid,s=n.infoMap.get(a);s||(s={model:o,axisModels:[]},n.infoList.push(s),n.infoMap.set(a,s)),s.axisModels.push(r)}}})),n}var oz=function(){function t(){this.indexList=[],this.indexMap=[]}return t.prototype.add=function(t){this.indexMap[t]||(this.indexList.push(t),this.indexMap[t]=!0)},t}(),az=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n._autoThrottle=!0,n._noTarget=!0,n._rangePropMode=["percent","percent"],n}return n(e,t),e.prototype.init=function(t,e,n){var i=sz(t);this.settledOption=i,this.mergeDefaultAndTheme(t,n),this._doInit(i)},e.prototype.mergeOption=function(t){var e=sz(t);C(this.option,t,!0),C(this.settledOption,e,!0),this._doInit(e)},e.prototype._doInit=function(t){var e=this.option;this._setDefaultThrottle(t),this._updateRangeUse(t);var n=this.settledOption;E([["start","startValue"],["end","endValue"]],(function(t,i){"value"===this._rangePropMode[i]&&(e[t[0]]=n[t[0]]=null)}),this),this._resetTarget()},e.prototype._resetTarget=function(){var t=this.get("orient",!0),e=this._targetAxisInfoMap=yt();this._fillSpecifiedTargetAxis(e)?this._orient=t||this._makeAutoOrientByTargetAxis():(this._orient=t||"horizontal",this._fillAutoTargetAxisByOrient(e,this._orient)),this._noTarget=!0,e.each((function(t){t.indexList.length&&(this._noTarget=!1)}),this)},e.prototype._fillSpecifiedTargetAxis=function(t){var e=!1;return E(tz,(function(n){var i=this.getReferringComponents(nz(n),Ho);if(i.specified){e=!0;var r=new oz;E(i.models,(function(t){r.add(t.componentIndex)})),t.set(n,r)}}),this),e},e.prototype._fillAutoTargetAxisByOrient=function(t,e){var n=this.ecModel,i=!0;if(i){var r="vertical"===e?"y":"x";o(n.findComponents({mainType:r+"Axis"}),r)}i&&o(n.findComponents({mainType:"singleAxis",filter:function(t){return t.get("orient",!0)===e}}),"single");function o(e,n){var r=e[0];if(r){var o=new oz;if(o.add(r.componentIndex),t.set(n,o),i=!1,"x"===n||"y"===n){var a=r.getReferringComponents("grid",Wo).models[0];a&&E(e,(function(t){r.componentIndex!==t.componentIndex&&a===t.getReferringComponents("grid",Wo).models[0]&&o.add(t.componentIndex)}))}}}i&&E(tz,(function(e){if(i){var r=n.findComponents({mainType:nz(e),filter:function(t){return"category"===t.get("type",!0)}});if(r[0]){var o=new oz;o.add(r[0].componentIndex),t.set(e,o),i=!1}}}),this)},e.prototype._makeAutoOrientByTargetAxis=function(){var t;return this.eachTargetAxis((function(e){!t&&(t=e)}),this),"y"===t?"vertical":"horizontal"},e.prototype._setDefaultThrottle=function(t){if(t.hasOwnProperty("throttle")&&(this._autoThrottle=!1),this._autoThrottle){var e=this.ecModel.option;this.option.throttle=e.animation&&e.animationDurationUpdate>0?100:20}},e.prototype._updateRangeUse=function(t){var e=this._rangePropMode,n=this.get("rangeMode");E([["start","startValue"],["end","endValue"]],(function(i,r){var o=null!=t[i[0]],a=null!=t[i[1]];o&&!a?e[r]="percent":!o&&a?e[r]="value":n?e[r]=n[r]:o&&(e[r]="percent")}))},e.prototype.noTarget=function(){return this._noTarget},e.prototype.getFirstTargetAxisModel=function(){var t;return this.eachTargetAxis((function(e,n){null==t&&(t=this.ecModel.getComponent(nz(e),n))}),this),t},e.prototype.eachTargetAxis=function(t,e){this._targetAxisInfoMap.each((function(n,i){E(n.indexList,(function(n){t.call(e,i,n)}))}))},e.prototype.getAxisProxy=function(t,e){var n=this.getAxisModel(t,e);if(n)return n.__dzAxisProxy},e.prototype.getAxisModel=function(t,e){var n=this._targetAxisInfoMap.get(t);if(n&&n.indexMap[e])return this.ecModel.getComponent(nz(t),e)},e.prototype.setRawRange=function(t){var e=this.option,n=this.settledOption;E([["start","startValue"],["end","endValue"]],(function(i){null==t[i[0]]&&null==t[i[1]]||(e[i[0]]=n[i[0]]=t[i[0]],e[i[1]]=n[i[1]]=t[i[1]])}),this),this._updateRangeUse(t)},e.prototype.setCalculatedRange=function(t){var e=this.option;E(["start","startValue","end","endValue"],(function(n){e[n]=t[n]}))},e.prototype.getPercentRange=function(){var t=this.findRepresentativeAxisProxy();if(t)return t.getDataPercentWindow()},e.prototype.getValueRange=function(t,e){if(null!=t||null!=e)return this.getAxisProxy(t,e).getDataValueWindow();var n=this.findRepresentativeAxisProxy();return n?n.getDataValueWindow():void 0},e.prototype.findRepresentativeAxisProxy=function(t){if(t)return t.__dzAxisProxy;for(var e,n=this._targetAxisInfoMap.keys(),i=0;i=0}(e)){var n=nz(this._dimName),i=e.getReferringComponents(n,Wo).models[0];i&&this._axisIndex===i.componentIndex&&t.push(e)}}),this),t},t.prototype.getAxisModel=function(){return this.ecModel.getComponent(this._dimName+"Axis",this._axisIndex)},t.prototype.getMinMaxSpan=function(){return T(this._minMaxSpan)},t.prototype.calculateDataWindow=function(t){var e,n=this._dataExtent,i=this.getAxisModel().axis.scale,r=this._dataZoomModel.getRangePropMode(),o=[0,100],a=[],s=[];cz(["start","end"],(function(l,u){var h=t[l],c=t[l+"Value"];"percent"===r[u]?(null==h&&(h=o[u]),c=i.parse(Kr(h,o,n))):(e=!0,h=Kr(c=null==c?n[u]:i.parse(c),n,o)),s[u]=null==c||isNaN(c)?n[u]:c,a[u]=null==h||isNaN(h)?o[u]:h})),pz(s),pz(a);var l=this._minMaxSpan;function u(t,e,n,r,o){var a=o?"Span":"ValueSpan";zk(0,t,n,"all",l["min"+a],l["max"+a]);for(var s=0;s<2;s++)e[s]=Kr(t[s],n,r,!0),o&&(e[s]=i.parse(e[s]))}return e?u(s,a,n,o,!1):u(a,s,o,n,!0),{valueWindow:s,percentWindow:a}},t.prototype.reset=function(t){if(t===this._dataZoomModel){var e=this.getTargetSeriesModels();this._dataExtent=function(t,e,n){var i=[1/0,-1/0];cz(n,(function(t){!function(t,e,n){e&&E(C_(e,n),(function(n){var i=e.getApproximateExtent(n);i[0]t[1]&&(t[1]=i[1])}))}(i,t.getData(),e)}));var r=t.getAxisModel(),o=v_(r.axis.scale,r,i).calculate();return[o.min,o.max]}(this,this._dimName,e),this._updateMinMaxSpan();var n=this.calculateDataWindow(t.settledOption);this._valueWindow=n.valueWindow,this._percentWindow=n.percentWindow,this._setAxisModel()}},t.prototype.filterData=function(t,e){if(t===this._dataZoomModel){var n=this._dimName,i=this.getTargetSeriesModels(),r=t.get("filterMode"),o=this._valueWindow;"none"!==r&&cz(i,(function(t){var e=t.getData(),i=e.mapDimensionsAll(n);if(i.length){if("weakFilter"===r){var a=e.getStore(),s=z(i,(function(t){return e.getDimensionIndex(t)}),e);e.filterSelf((function(t){for(var e,n,r,l=0;lo[1];if(h&&!c&&!p)return!0;h&&(r=!0),c&&(e=!0),p&&(n=!0)}return r&&e&&n}))}else cz(i,(function(n){if("empty"===r)t.setData(e=e.map(n,(function(t){return function(t){return t>=o[0]&&t<=o[1]}(t)?t:NaN})));else{var i={};i[n]=o,e.selectRange(i)}}));cz(i,(function(t){e.setApproximateExtent(o,t)}))}}))}},t.prototype._updateMinMaxSpan=function(){var t=this._minMaxSpan={},e=this._dataZoomModel,n=this._dataExtent;cz(["min","max"],(function(i){var r=e.get(i+"Span"),o=e.get(i+"ValueSpan");null!=o&&(o=this.getAxisModel().axis.scale.parse(o)),null!=o?r=Kr(n[0]+o,n,[0,100],!0):null!=r&&(o=Kr(r,[0,100],n,!0)-n[0]),t[i+"Span"]=r,t[i+"ValueSpan"]=o}),this)},t.prototype._setAxisModel=function(){var t=this.getAxisModel(),e=this._percentWindow,n=this._valueWindow;if(e){var i=no(n,[0,500]);i=Math.min(i,20);var r=t.axis.scale.rawExtentInfo;0!==e[0]&&r.setDeterminedMinMax("min",+n[0].toFixed(i)),100!==e[1]&&r.setDeterminedMinMax("max",+n[1].toFixed(i)),r.freeze()}},t}();var fz={getTargetSeries:function(t){function e(e){t.eachComponent("dataZoom",(function(n){n.eachTargetAxis((function(i,r){var o=t.getComponent(nz(i),r);e(i,r,o,n)}))}))}e((function(t,e,n,i){n.__dzAxisProxy=null}));var n=[];e((function(e,i,r,o){r.__dzAxisProxy||(r.__dzAxisProxy=new dz(e,i,o,t),n.push(r.__dzAxisProxy))}));var i=yt();return E(n,(function(t){E(t.getTargetSeriesModels(),(function(t){i.set(t.uid,t)}))})),i},overallReset:function(t,e){t.eachComponent("dataZoom",(function(t){t.eachTargetAxis((function(e,n){t.getAxisProxy(e,n).reset(t)})),t.eachTargetAxis((function(n,i){t.getAxisProxy(n,i).filterData(t,e)}))})),t.eachComponent("dataZoom",(function(t){var e=t.findRepresentativeAxisProxy();if(e){var n=e.getDataPercentWindow(),i=e.getDataValueWindow();t.setCalculatedRange({start:n[0],end:n[1],startValue:i[0],endValue:i[1]})}}))}};var gz=!1;function yz(t){gz||(gz=!0,t.registerProcessor(t.PRIORITY.PROCESSOR.FILTER,fz),function(t){t.registerAction("dataZoom",(function(t,e){E(iz(e,t),(function(e){e.setRawRange({start:t.start,end:t.end,startValue:t.startValue,endValue:t.endValue})}))}))}(t),t.registerSubTypeDefaulter("dataZoom",(function(){return"slider"})))}function vz(t){t.registerComponentModel(lz),t.registerComponentView(hz),yz(t)}var mz=function(){},xz={};function _z(t,e){xz[t]=e}function bz(t){return xz[t]}var wz=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.optionUpdated=function(){t.prototype.optionUpdated.apply(this,arguments);var e=this.ecModel;E(this.option.feature,(function(t,n){var i=bz(n);i&&(i.getDefaultOption&&(i.defaultOption=i.getDefaultOption(e)),C(t,i.defaultOption))}))},e.type="toolbox",e.layoutMode={type:"box",ignoreSize:!0},e.defaultOption={show:!0,z:6,orient:"horizontal",left:"right",top:"top",backgroundColor:"transparent",borderColor:"#ccc",borderRadius:0,borderWidth:0,padding:5,itemSize:15,itemGap:8,showTitle:!0,iconStyle:{borderColor:"#666",color:"none"},emphasis:{iconStyle:{borderColor:"#3E98C5"}},tooltip:{show:!1,position:"bottom"}},e}(zp);function Sz(t,e){var n=vp(e.get("padding")),i=e.getItemStyle(["color","opacity"]);return i.fill=e.get("backgroundColor"),t=new Ws({shape:{x:t.x-n[3],y:t.y-n[0],width:t.width+n[1]+n[3],height:t.height+n[0]+n[2],r:e.get("borderRadius")},style:i,silent:!0,z2:-1})}var Mz=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.render=function(t,e,n,i){var r=this.group;if(r.removeAll(),t.get("show")){var o=+t.get("itemSize"),a="vertical"===t.get("orient"),s=t.get("feature")||{},l=this._features||(this._features={}),u=[];E(s,(function(t,e){u.push(e)})),new Gm(this._featureNames||[],u).add(h).update(h).remove(H(h,null)).execute(),this._featureNames=u,function(t,e,n){var i=e.getBoxLayoutParams(),r=e.get("padding"),o={width:n.getWidth(),height:n.getHeight()},a=kp(i,o,r);Ap(e.get("orient"),t,e.get("itemGap"),a.width,a.height),Lp(t,i,o,r)}(r,t,n),r.add(Sz(r.getBoundingRect(),t)),a||r.eachChild((function(t){var e=t.__title,i=t.ensureState("emphasis"),a=i.textConfig||(i.textConfig={}),s=t.getTextContent(),l=s&&s.ensureState("emphasis");if(l&&!X(l)&&e){var u=l.style||(l.style={}),h=Sr(e,Xs.makeFont(u)),c=t.x+r.x,p=!1;t.y+r.y+o+h.height>n.getHeight()&&(a.position="top",p=!0);var d=p?-5-h.height:o+10;c+h.width/2>n.getWidth()?(a.position=["100%",d],u.align="right"):c-h.width/2<0&&(a.position=[0,d],u.align="left")}}))}function h(h,c){var p,d=u[h],f=u[c],g=s[d],y=new Cc(g,t,t.ecModel);if(i&&null!=i.newTitle&&i.featureName===d&&(g.title=i.newTitle),d&&!f){if(function(t){return 0===t.indexOf("my")}(d))p={onclick:y.option.onclick,featureName:d};else{var v=bz(d);if(!v)return;p=new v}l[d]=p}else if(!(p=l[f]))return;p.uid=Ac("toolbox-feature"),p.model=y,p.ecModel=e,p.api=n;var m=p instanceof mz;d||!f?!y.get("show")||m&&p.unusable?m&&p.remove&&p.remove(e,n):(!function(i,s,l){var u,h,c=i.getModel("iconStyle"),p=i.getModel(["emphasis","iconStyle"]),d=s instanceof mz&&s.getIcons?s.getIcons():i.get("icon"),f=i.get("title")||{};U(d)?(u={})[l]=d:u=d;U(f)?(h={})[l]=f:h=f;var g=i.iconPaths={};E(u,(function(l,u){var d=Uh(l,{},{x:-o/2,y:-o/2,width:o,height:o});d.setStyle(c.getItemStyle()),d.ensureState("emphasis").style=p.getItemStyle();var f=new Xs({style:{text:h[u],align:p.get("textAlign"),borderRadius:p.get("textBorderRadius"),padding:p.get("textPadding"),fill:null,font:cc({fontStyle:p.get("textFontStyle"),fontFamily:p.get("textFontFamily"),fontSize:p.get("textFontSize"),fontWeight:p.get("textFontWeight")},e)},ignore:!0});d.setTextContent(f),Kh({el:d,componentModel:t,itemName:u,formatterParamsExtra:{title:h[u]}}),d.__title=h[u],d.on("mouseover",(function(){var e=p.getItemStyle(),i=a?null==t.get("right")&&"right"!==t.get("left")?"right":"left":null==t.get("bottom")&&"bottom"!==t.get("top")?"bottom":"top";f.setStyle({fill:p.get("textFill")||e.fill||e.stroke||"#000",backgroundColor:p.get("textBackgroundColor")}),d.setTextConfig({position:p.get("textPosition")||i}),f.ignore=!t.get("showTitle"),n.enterEmphasis(this)})).on("mouseout",(function(){"emphasis"!==i.get(["iconStatus",u])&&n.leaveEmphasis(this),f.hide()})),("emphasis"===i.get(["iconStatus",u])?Ol:Rl)(d),r.add(d),d.on("click",W(s.onclick,s,e,n,u)),g[u]=d}))}(y,p,d),y.setIconStatus=function(t,e){var n=this.option,i=this.iconPaths;n.iconStatus=n.iconStatus||{},n.iconStatus[t]=e,i[t]&&("emphasis"===e?Ol:Rl)(i[t])},p instanceof mz&&p.render&&p.render(y,e,n,i)):m&&p.dispose&&p.dispose(e,n)}},e.prototype.updateView=function(t,e,n,i){E(this._features,(function(t){t instanceof mz&&t.updateView&&t.updateView(t.model,e,n,i)}))},e.prototype.remove=function(t,e){E(this._features,(function(n){n instanceof mz&&n.remove&&n.remove(t,e)})),this.group.removeAll()},e.prototype.dispose=function(t,e){E(this._features,(function(n){n instanceof mz&&n.dispose&&n.dispose(t,e)}))},e.type="toolbox",e}(Ag);var Iz=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.onclick=function(t,e){var n=this.model,i=n.get("name")||t.get("title.0.text")||"echarts",o="svg"===e.getZr().painter.getType(),a=o?"svg":n.get("type",!0)||"png",s=e.getConnectedDataURL({type:a,backgroundColor:n.get("backgroundColor",!0)||t.get("backgroundColor")||"#fff",connectedBackgroundColor:n.get("connectedBackgroundColor"),excludeComponents:n.get("excludeComponents"),pixelRatio:n.get("pixelRatio")}),l=r.browser;if("function"!=typeof MouseEvent||!l.newEdge&&(l.ie||l.edge))if(window.navigator.msSaveOrOpenBlob||o){var u=s.split(","),h=u[0].indexOf("base64")>-1,c=o?decodeURIComponent(u[1]):u[1];h&&(c=window.atob(c));var p=i+"."+a;if(window.navigator.msSaveOrOpenBlob){for(var d=c.length,f=new Uint8Array(d);d--;)f[d]=c.charCodeAt(d);var g=new Blob([f]);window.navigator.msSaveOrOpenBlob(g,p)}else{var y=document.createElement("iframe");document.body.appendChild(y);var v=y.contentWindow,m=v.document;m.open("image/svg+xml","replace"),m.write(c),m.close(),v.focus(),m.execCommand("SaveAs",!0,p),document.body.removeChild(y)}}else{var x=n.get("lang"),_='',b=window.open();b.document.write(_),b.document.title=i}else{var w=document.createElement("a");w.download=i+"."+a,w.target="_blank",w.href=s;var S=new MouseEvent("click",{view:document.defaultView,bubbles:!0,cancelable:!1});w.dispatchEvent(S)}},e.getDefaultOption=function(t){return{show:!0,icon:"M4.7,22.9L29.3,45.5L54.7,23.4M4.6,43.6L4.6,58L53.8,58L53.8,43.6M29.2,45.1L29.2,0",title:t.getLocaleModel().get(["toolbox","saveAsImage","title"]),type:"png",connectedBackgroundColor:"#fff",name:"",excludeComponents:["toolbox"],lang:t.getLocaleModel().get(["toolbox","saveAsImage","lang"])}},e}(mz),Tz="__ec_magicType_stack__",Cz=[["line","bar"],["stack"]],Dz=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.getIcons=function(){var t=this.model,e=t.get("icon"),n={};return E(t.get("type"),(function(t){e[t]&&(n[t]=e[t])})),n},e.getDefaultOption=function(t){return{show:!0,type:[],icon:{line:"M4.1,28.9h7.1l9.3-22l7.4,38l9.7-19.7l3,12.8h14.9M4.1,58h51.4",bar:"M6.7,22.9h10V48h-10V22.9zM24.9,13h10v35h-10V13zM43.2,2h10v46h-10V2zM3.1,58h53.7",stack:"M8.2,38.4l-8.4,4.1l30.6,15.3L60,42.5l-8.1-4.1l-21.5,11L8.2,38.4z M51.9,30l-8.1,4.2l-13.4,6.9l-13.9-6.9L8.2,30l-8.4,4.2l8.4,4.2l22.2,11l21.5-11l8.1-4.2L51.9,30z M51.9,21.7l-8.1,4.2L35.7,30l-5.3,2.8L24.9,30l-8.4-4.1l-8.3-4.2l-8.4,4.2L8.2,30l8.3,4.2l13.9,6.9l13.4-6.9l8.1-4.2l8.1-4.1L51.9,21.7zM30.4,2.2L-0.2,17.5l8.4,4.1l8.3,4.2l8.4,4.2l5.5,2.7l5.3-2.7l8.1-4.2l8.1-4.2l8.1-4.1L30.4,2.2z"},title:t.getLocaleModel().get(["toolbox","magicType","title"]),option:{},seriesIndex:{}}},e.prototype.onclick=function(t,e,n){var i=this.model,r=i.get(["seriesIndex",n]);if(Az[n]){var o,a={series:[]};E(Cz,(function(t){P(t,n)>=0&&E(t,(function(t){i.setIconStatus(t,"normal")}))})),i.setIconStatus(n,"emphasis"),t.eachComponent({mainType:"series",query:null==r?null:{seriesIndex:r}},(function(t){var e=t.subType,r=t.id,o=Az[n](e,r,t,i);o&&(k(o,t.option),a.series.push(o));var s=t.coordinateSystem;if(s&&"cartesian2d"===s.type&&("line"===n||"bar"===n)){var l=s.getAxesByScale("ordinal")[0];if(l){var u=l.dim+"Axis",h=t.getReferringComponents(u,Wo).models[0].componentIndex;a[u]=a[u]||[];for(var c=0;c<=h;c++)a[u][h]=a[u][h]||{};a[u][h].boundaryGap="bar"===n}}}));var s=n;"stack"===n&&(o=C({stack:i.option.title.tiled,tiled:i.option.title.stack},i.option.title),"emphasis"!==i.get(["iconStatus",n])&&(s="tiled")),e.dispatchAction({type:"changeMagicType",currentType:s,newOption:a,newTitle:o,featureName:"magicType"})}},e}(mz),Az={line:function(t,e,n,i){if("bar"===t)return C({id:e,type:"line",data:n.get("data"),stack:n.get("stack"),markPoint:n.get("markPoint"),markLine:n.get("markLine")},i.get(["option","line"])||{},!0)},bar:function(t,e,n,i){if("line"===t)return C({id:e,type:"bar",data:n.get("data"),stack:n.get("stack"),markPoint:n.get("markPoint"),markLine:n.get("markLine")},i.get(["option","bar"])||{},!0)},stack:function(t,e,n,i){var r=n.get("stack")===Tz;if("line"===t||"bar"===t)return i.setIconStatus("stack",r?"normal":"emphasis"),C({id:e,stack:r?"":Tz},i.get(["option","stack"])||{},!0)}};Cm({type:"changeMagicType",event:"magicTypeChanged",update:"prepareAndUpdate"},(function(t,e){e.mergeOption(t.newOption)}));var kz=new Array(60).join("-"),Lz="\t";function Pz(t){return t.replace(/^\s\s*/,"").replace(/\s\s*$/,"")}var Oz=new RegExp("[\t]+","g");function Rz(t,e){var n=t.split(new RegExp("\n*"+kz+"\n*","g")),i={series:[]};return E(n,(function(t,n){if(function(t){if(t.slice(0,t.indexOf("\n")).indexOf(Lz)>=0)return!0}(t)){var r=function(t){for(var e=t.split(/\n+/g),n=[],i=z(Pz(e.shift()).split(Oz),(function(t){return{name:t,data:[]}})),r=0;r=0)&&t(r,i._targetInfoList)}))}return t.prototype.setOutputRanges=function(t,e){return this.matchOutputRanges(t,e,(function(t,e,n){if((t.coordRanges||(t.coordRanges=[])).push(e),!t.coordRange){t.coordRange=e;var i=jz[t.brushType](0,n,e);t.__rangeOffset={offset:Kz[t.brushType](i.values,t.range,[1,1]),xyMinMax:i.xyMinMax}}})),t},t.prototype.matchOutputRanges=function(t,e,n){E(t,(function(t){var i=this.findTargetInfo(t,e);i&&!0!==i&&E(i.coordSyses,(function(i){var r=jz[t.brushType](1,i,t.range,!0);n(t,r.values,i,e)}))}),this)},t.prototype.setInputRanges=function(t,e){E(t,(function(t){var n,i,r,o,a,s=this.findTargetInfo(t,e);if(t.range=t.range||[],s&&!0!==s){t.panelId=s.panelId;var l=jz[t.brushType](0,s.coordSys,t.coordRange),u=t.__rangeOffset;t.range=u?Kz[t.brushType](l.values,u.offset,(n=l.xyMinMax,i=u.xyMinMax,r=Jz(n),o=Jz(i),a=[r[0]/o[0],r[1]/o[1]],isNaN(a[0])&&(a[0]=1),isNaN(a[1])&&(a[1]=1),a)):l.values}}),this)},t.prototype.makePanelOpts=function(t,e){return z(this._targetInfoList,(function(n){var i=n.getPanelRect();return{panelId:n.panelId,defaultBrushType:e?e(n):null,clipPath:BL(i),isTargetByCursor:GL(i,t,n.coordSysModel),getLinearBrushOtherExtent:FL(i)}}))},t.prototype.controlSeries=function(t,e,n){var i=this.findTargetInfo(t,n);return!0===i||i&&P(i.coordSyses,e.coordinateSystem)>=0},t.prototype.findTargetInfo=function(t,e){for(var n=this._targetInfoList,i=Yz(e,t),r=0;rt[1]&&t.reverse(),t}function Yz(t,e){return Fo(t,e,{includeMainTypes:Gz})}var Xz={grid:function(t,e){var n=t.xAxisModels,i=t.yAxisModels,r=t.gridModels,o=yt(),a={},s={};(n||i||r)&&(E(n,(function(t){var e=t.axis.grid.model;o.set(e.id,e),a[e.id]=!0})),E(i,(function(t){var e=t.axis.grid.model;o.set(e.id,e),s[e.id]=!0})),E(r,(function(t){o.set(t.id,t),a[t.id]=!0,s[t.id]=!0})),o.each((function(t){var r=t.coordinateSystem,o=[];E(r.getCartesians(),(function(t,e){(P(n,t.getAxis("x").model)>=0||P(i,t.getAxis("y").model)>=0)&&o.push(t)})),e.push({panelId:"grid--"+t.id,gridModel:t,coordSysModel:t,coordSys:o[0],coordSyses:o,getPanelRect:Zz.grid,xAxisDeclared:a[t.id],yAxisDeclared:s[t.id]})})))},geo:function(t,e){E(t.geoModels,(function(t){var n=t.coordinateSystem;e.push({panelId:"geo--"+t.id,geoModel:t,coordSysModel:t,coordSys:n,coordSyses:[n],getPanelRect:Zz.geo})}))}},Uz=[function(t,e){var n=t.xAxisModel,i=t.yAxisModel,r=t.gridModel;return!r&&n&&(r=n.axis.grid.model),!r&&i&&(r=i.axis.grid.model),r&&r===e.gridModel},function(t,e){var n=t.geoModel;return n&&n===e.geoModel}],Zz={grid:function(){return this.coordSys.master.getRect().clone()},geo:function(){var t=this.coordSys,e=t.getBoundingRect().clone();return e.applyTransform(Bh(t)),e}},jz={lineX:H(qz,0),lineY:H(qz,1),rect:function(t,e,n,i){var r=t?e.pointToData([n[0][0],n[1][0]],i):e.dataToPoint([n[0][0],n[1][0]],i),o=t?e.pointToData([n[0][1],n[1][1]],i):e.dataToPoint([n[0][1],n[1][1]],i),a=[Hz([r[0],o[0]]),Hz([r[1],o[1]])];return{values:a,xyMinMax:a}},polygon:function(t,e,n,i){var r=[[1/0,-1/0],[1/0,-1/0]];return{values:z(n,(function(n){var o=t?e.pointToData(n,i):e.dataToPoint(n,i);return r[0][0]=Math.min(r[0][0],o[0]),r[1][0]=Math.min(r[1][0],o[1]),r[0][1]=Math.max(r[0][1],o[0]),r[1][1]=Math.max(r[1][1],o[1]),o})),xyMinMax:r}}};function qz(t,e,n,i){var r=n.getAxis(["x","y"][t]),o=Hz(z([0,1],(function(t){return e?r.coordToData(r.toLocalCoord(i[t]),!0):r.toGlobalCoord(r.dataToCoord(i[t]))}))),a=[];return a[t]=o,a[1-t]=[NaN,NaN],{values:o,xyMinMax:a}}var Kz={lineX:H($z,0),lineY:H($z,1),rect:function(t,e,n){return[[t[0][0]-n[0]*e[0][0],t[0][1]-n[0]*e[0][1]],[t[1][0]-n[1]*e[1][0],t[1][1]-n[1]*e[1][1]]]},polygon:function(t,e,n){return z(t,(function(t,i){return[t[0]-n[0]*e[i][0],t[1]-n[1]*e[i][1]]}))}};function $z(t,e,n,i){return[e[0]-i[t]*n[0],e[1]-i[t]*n[1]]}function Jz(t){return t?[t[0][1]-t[0][0],t[1][1]-t[1][0]]:[NaN,NaN]}var Qz,tV,eV=E,nV=Io+"toolbox-dataZoom_",iV=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.render=function(t,e,n,i){this._brushController||(this._brushController=new lL(n.getZr()),this._brushController.on("brush",W(this._onBrush,this)).mount()),function(t,e,n,i,r){var o=n._isZoomActive;i&&"takeGlobalCursor"===i.type&&(o="dataZoomSelect"===i.key&&i.dataZoomSelectActive);n._isZoomActive=o,t.setIconStatus("zoom",o?"emphasis":"normal");var a=new Wz(oV(t),e,{include:["grid"]}),s=a.makePanelOpts(r,(function(t){return t.xAxisDeclared&&!t.yAxisDeclared?"lineX":!t.xAxisDeclared&&t.yAxisDeclared?"lineY":"rect"}));n._brushController.setPanels(s).enableBrush(!(!o||!s.length)&&{brushType:"auto",brushStyle:t.getModel("brushStyle").getItemStyle()})}(t,e,this,i,n),function(t,e){t.setIconStatus("back",function(t){return Bz(t).length}(e)>1?"emphasis":"normal")}(t,e)},e.prototype.onclick=function(t,e,n){rV[n].call(this)},e.prototype.remove=function(t,e){this._brushController&&this._brushController.unmount()},e.prototype.dispose=function(t,e){this._brushController&&this._brushController.dispose()},e.prototype._onBrush=function(t){var e=t.areas;if(t.isEnd&&e.length){var n={},i=this.ecModel;this._brushController.updateCovers([]),new Wz(oV(this.model),i,{include:["grid"]}).matchOutputRanges(e,i,(function(t,e,n){if("cartesian2d"===n.type){var i=t.brushType;"rect"===i?(r("x",n,e[0]),r("y",n,e[1])):r({lineX:"x",lineY:"y"}[i],n,e)}})),function(t,e){var n=Bz(t);zz(e,(function(e,i){for(var r=n.length-1;r>=0&&!n[r][i];r--);if(r<0){var o=t.queryComponents({mainType:"dataZoom",subType:"select",id:i})[0];if(o){var a=o.getPercentRange();n[0][i]={dataZoomId:i,start:a[0],end:a[1]}}}})),n.push(e)}(i,n),this._dispatchZoomAction(n)}function r(t,e,r){var o=e.getAxis(t),a=o.model,s=function(t,e,n){var i;return n.eachComponent({mainType:"dataZoom",subType:"select"},(function(n){n.getAxisModel(t,e.componentIndex)&&(i=n)})),i}(t,a,i),l=s.findRepresentativeAxisProxy(a).getMinMaxSpan();null==l.minValueSpan&&null==l.maxValueSpan||(r=zk(0,r.slice(),o.scale.getExtent(),0,l.minValueSpan,l.maxValueSpan)),s&&(n[s.id]={dataZoomId:s.id,startValue:r[0],endValue:r[1]})}},e.prototype._dispatchZoomAction=function(t){var e=[];eV(t,(function(t,n){e.push(T(t))})),e.length&&this.api.dispatchAction({type:"dataZoom",from:this.uid,batch:e})},e.getDefaultOption=function(t){return{show:!0,filterMode:"filter",icon:{zoom:"M0,13.5h26.9 M13.5,26.9V0 M32.1,13.5H58V58H13.5 V32.1",back:"M22,1.4L9.9,13.5l12.3,12.3 M10.3,13.5H54.9v44.6 H10.3v-26"},title:t.getLocaleModel().get(["toolbox","dataZoom","title"]),brushStyle:{borderWidth:0,color:"rgba(210,219,238,0.2)"}}},e}(mz),rV={zoom:function(){var t=!this._isZoomActive;this.api.dispatchAction({type:"takeGlobalCursor",key:"dataZoomSelect",dataZoomSelectActive:t})},back:function(){this._dispatchZoomAction(function(t){var e=Bz(t),n=e[e.length-1];e.length>1&&e.pop();var i={};return zz(n,(function(t,n){for(var r=e.length-1;r>=0;r--)if(t=e[r][n]){i[n]=t;break}})),i}(this.ecModel))}};function oV(t){var e={xAxisIndex:t.get("xAxisIndex",!0),yAxisIndex:t.get("yAxisIndex",!0),xAxisId:t.get("xAxisId",!0),yAxisId:t.get("yAxisId",!0)};return null==e.xAxisIndex&&null==e.xAxisId&&(e.xAxisIndex="all"),null==e.yAxisIndex&&null==e.yAxisId&&(e.yAxisIndex="all"),e}Qz="dataZoom",tV=function(t){var e=t.getComponent("toolbox",0),n=["feature","dataZoom"];if(e&&null!=e.get(n)){var i=e.getModel(n),r=[],o=Fo(t,oV(i));return eV(o.xAxisModels,(function(t){return a(t,"xAxis","xAxisIndex")})),eV(o.yAxisModels,(function(t){return a(t,"yAxis","yAxisIndex")})),r}function a(t,e,n){var o=t.componentIndex,a={type:"select",$fromToolbox:!0,filterMode:i.get("filterMode",!0)||"filter",id:nV+e+o};a[n]=o,r.push(a)}},lt(null==od.get(Qz)&&tV),od.set(Qz,tV);var aV=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="tooltip",e.dependencies=["axisPointer"],e.defaultOption={z:60,show:!0,showContent:!0,trigger:"item",triggerOn:"mousemove|click",alwaysShowContent:!1,displayMode:"single",renderMode:"auto",confine:null,showDelay:0,hideDelay:100,transitionDuration:.4,enterable:!1,backgroundColor:"#fff",shadowBlur:10,shadowColor:"rgba(0, 0, 0, .2)",shadowOffsetX:1,shadowOffsetY:2,borderRadius:4,borderWidth:1,padding:null,extraCssText:"",axisPointer:{type:"line",axis:"auto",animation:"auto",animationDurationUpdate:200,animationEasingUpdate:"exponentialOut",crossStyle:{color:"#999",width:1,type:"dashed",textStyle:{}}},textStyle:{color:"#666",fontSize:14}},e}(zp);function sV(t){var e=t.get("confine");return null!=e?!!e:"richText"===t.get("renderMode")}function lV(t){if(r.domSupported)for(var e=document.documentElement.style,n=0,i=t.length;n-1?(u+="top:50%",h+="translateY(-50%) rotate("+(a="left"===s?-225:-45)+"deg)"):(u+="left:50%",h+="translateX(-50%) rotate("+(a="top"===s?225:45)+"deg)");var c=a*Math.PI/180,p=l+r,d=p*Math.abs(Math.cos(c))+p*Math.abs(Math.sin(c)),f=e+" solid "+r+"px;";return'
    '}(n,i,r)),U(t))o.innerHTML=t+a;else if(t){o.innerHTML="",Y(t)||(t=[t]);for(var s=0;s=0?this._tryShow(n,i):"leave"===e&&this._hide(i))}),this))},e.prototype._keepShow=function(){var t=this._tooltipModel,e=this._ecModel,n=this._api,i=t.get("triggerOn");if(null!=this._lastX&&null!=this._lastY&&"none"!==i&&"click"!==i){var r=this;clearTimeout(this._refreshUpdateTimeout),this._refreshUpdateTimeout=setTimeout((function(){!n.isDisposed()&&r.manuallyShowTip(t,e,n,{x:r._lastX,y:r._lastY,dataByCoordSys:r._lastDataByCoordSys})}))}},e.prototype.manuallyShowTip=function(t,e,n,i){if(i.from!==this.uid&&!r.node&&n.getDom()){var o=IV(i,n);this._ticket="";var a=i.dataByCoordSys,s=function(t,e,n){var i=Go(t).queryOptionMap,r=i.keys()[0];if(!r||"series"===r)return;var o=Yo(e,r,i.get(r),{useDefault:!1,enableAll:!1,enableNone:!1}),a=o.models[0];if(!a)return;var s,l=n.getViewOfComponentModel(a);if(l.group.traverse((function(e){var n=rl(e).tooltipConfig;if(n&&n.name===t.name)return s=e,!0})),s)return{componentMainType:r,componentIndex:a.componentIndex,el:s}}(i,e,n);if(s){var l=s.el.getBoundingRect().clone();l.applyTransform(s.el.transform),this._tryShow({offsetX:l.x+l.width/2,offsetY:l.y+l.height/2,target:s.el,position:i.position,positionDefault:"bottom"},o)}else if(i.tooltip&&null!=i.x&&null!=i.y){var u=wV;u.x=i.x,u.y=i.y,u.update(),rl(u).tooltipConfig={name:null,option:i.tooltip},this._tryShow({offsetX:i.x,offsetY:i.y,target:u},o)}else if(a)this._tryShow({offsetX:i.x,offsetY:i.y,position:i.position,dataByCoordSys:a,tooltipOption:i.tooltipOption},o);else if(null!=i.seriesIndex){if(this._manuallyAxisShowTip(t,e,n,i))return;var h=PN(i,e),c=h.point[0],p=h.point[1];null!=c&&null!=p&&this._tryShow({offsetX:c,offsetY:p,target:h.el,position:i.position,positionDefault:"bottom"},o)}else null!=i.x&&null!=i.y&&(n.dispatchAction({type:"updateAxisPointer",x:i.x,y:i.y}),this._tryShow({offsetX:i.x,offsetY:i.y,position:i.position,target:n.getZr().findHover(i.x,i.y).target},o))}},e.prototype.manuallyHideTip=function(t,e,n,i){var r=this._tooltipContent;this._tooltipModel&&r.hideLater(this._tooltipModel.get("hideDelay")),this._lastX=this._lastY=this._lastDataByCoordSys=null,i.from!==this.uid&&this._hide(IV(i,n))},e.prototype._manuallyAxisShowTip=function(t,e,n,i){var r=i.seriesIndex,o=i.dataIndex,a=e.getComponent("axisPointer").coordSysAxesInfo;if(null!=r&&null!=o&&null!=a){var s=e.getSeriesByIndex(r);if(s)if("axis"===MV([s.getData().getItemModel(o),s,(s.coordinateSystem||{}).model],this._tooltipModel).get("trigger"))return n.dispatchAction({type:"updateAxisPointer",seriesIndex:r,dataIndex:o,position:i.position}),!0}},e.prototype._tryShow=function(t,e){var n=t.target;if(this._tooltipModel){this._lastX=t.offsetX,this._lastY=t.offsetY;var i=t.dataByCoordSys;if(i&&i.length)this._showAxisTooltip(i,t);else if(n){var r,o;if("legend"===rl(n).ssrType)return;this._lastDataByCoordSys=null,Oy(n,(function(t){return null!=rl(t).dataIndex?(r=t,!0):null!=rl(t).tooltipConfig?(o=t,!0):void 0}),!0),r?this._showSeriesItemTooltip(t,r,e):o?this._showComponentItemTooltip(t,o,e):this._hide(e)}else this._lastDataByCoordSys=null,this._hide(e)}},e.prototype._showOrMove=function(t,e){var n=t.get("showDelay");e=W(e,this),clearTimeout(this._showTimout),n>0?this._showTimout=setTimeout(e,n):e()},e.prototype._showAxisTooltip=function(t,e){var n=this._ecModel,i=this._tooltipModel,r=[e.offsetX,e.offsetY],o=MV([e.tooltipOption],i),a=this._renderMode,s=[],l=og("section",{blocks:[],noHeader:!0}),u=[],h=new yg;E(t,(function(t){E(t.dataByAxis,(function(t){var e=n.getComponent(t.axisDim+"Axis",t.axisIndex),r=t.value;if(e&&null!=r){var o=fN(r,e.axis,n,t.seriesDataIndices,t.valueLabelOpt),c=og("section",{header:o,noHeader:!ut(o),sortBlocks:!0,blocks:[]});l.blocks.push(c),E(t.seriesDataIndices,(function(l){var p=n.getSeriesByIndex(l.seriesIndex),d=l.dataIndexInside,f=p.getDataParams(d);if(!(f.dataIndex<0)){f.axisDim=t.axisDim,f.axisIndex=t.axisIndex,f.axisType=t.axisType,f.axisId=t.axisId,f.axisValue=S_(e.axis,{value:r}),f.axisValueLabel=o,f.marker=h.makeTooltipMarker("item",Sp(f.color),a);var g=bf(p.formatTooltip(d,!0,null)),y=g.frag;if(y){var v=MV([p],i).get("valueFormatter");c.blocks.push(v?A({valueFormatter:v},y):y)}g.text&&u.push(g.text),s.push(f)}}))}}))})),l.blocks.reverse(),u.reverse();var c=e.position,p=o.get("order"),d=cg(l,h,a,p,n.get("useUTC"),o.get("textStyle"));d&&u.unshift(d);var f="richText"===a?"\n\n":"
    ",g=u.join(f);this._showOrMove(o,(function(){this._updateContentNotChangedOnAxis(t,s)?this._updatePosition(o,c,r[0],r[1],this._tooltipContent,s):this._showTooltipContent(o,g,s,Math.random()+"",r[0],r[1],c,null,h)}))},e.prototype._showSeriesItemTooltip=function(t,e,n){var i=this._ecModel,r=rl(e),o=r.seriesIndex,a=i.getSeriesByIndex(o),s=r.dataModel||a,l=r.dataIndex,u=r.dataType,h=s.getData(u),c=this._renderMode,p=t.positionDefault,d=MV([h.getItemModel(l),s,a&&(a.coordinateSystem||{}).model],this._tooltipModel,p?{position:p}:null),f=d.get("trigger");if(null==f||"item"===f){var g=s.getDataParams(l,u),y=new yg;g.marker=y.makeTooltipMarker("item",Sp(g.color),c);var v=bf(s.formatTooltip(l,!1,u)),m=d.get("order"),x=d.get("valueFormatter"),_=v.frag,b=_?cg(x?A({valueFormatter:x},_):_,y,c,m,i.get("useUTC"),d.get("textStyle")):v.text,w="item_"+s.name+"_"+l;this._showOrMove(d,(function(){this._showTooltipContent(d,b,g,w,t.offsetX,t.offsetY,t.position,t.target,y)})),n({type:"showTip",dataIndexInside:l,dataIndex:h.getRawIndex(l),seriesIndex:o,from:this.uid})}},e.prototype._showComponentItemTooltip=function(t,e,n){var i="html"===this._renderMode,r=rl(e),o=r.tooltipConfig.option||{},a=o.encodeHTMLContent;if(U(o)){o={content:o,formatter:o},a=!0}a&&i&&o.content&&((o=T(o)).content=re(o.content));var s=[o],l=this._ecModel.getComponent(r.componentMainType,r.componentIndex);l&&s.push(l),s.push({formatter:o.content});var u=t.positionDefault,h=MV(s,this._tooltipModel,u?{position:u}:null),c=h.get("content"),p=Math.random()+"",d=new yg;this._showOrMove(h,(function(){var n=T(h.get("formatterParams")||{});this._showTooltipContent(h,c,n,p,t.offsetX,t.offsetY,t.position,e,d)})),n({type:"showTip",from:this.uid})},e.prototype._showTooltipContent=function(t,e,n,i,r,o,a,s,l){if(this._ticket="",t.get("showContent")&&t.get("show")){var u=this._tooltipContent;u.setEnterable(t.get("enterable"));var h=t.get("formatter");a=a||t.get("position");var c=e,p=this._getNearestPoint([r,o],n,t.get("trigger"),t.get("borderColor")).color;if(h)if(U(h)){var d=t.ecModel.get("useUTC"),f=Y(n)?n[0]:n;c=h,f&&f.axisType&&f.axisType.indexOf("time")>=0&&(c=Jc(f.axisValue,c,d)),c=bp(c,n,!0)}else if(X(h)){var g=W((function(e,i){e===this._ticket&&(u.setContent(i,l,t,p,a),this._updatePosition(t,a,r,o,u,n,s))}),this);this._ticket=i,c=h(n,i,g)}else c=h;u.setContent(c,l,t,p,a),u.show(t,p),this._updatePosition(t,a,r,o,u,n,s)}},e.prototype._getNearestPoint=function(t,e,n,i){return"axis"===n||Y(e)?{color:i||("html"===this._renderMode?"#fff":"none")}:Y(e)?void 0:{color:i||e.color||e.borderColor}},e.prototype._updatePosition=function(t,e,n,i,r,o,a){var s=this._api.getWidth(),l=this._api.getHeight();e=e||t.get("position");var u=r.getSize(),h=t.get("align"),c=t.get("verticalAlign"),p=a&&a.getBoundingRect().clone();if(a&&p.applyTransform(a.transform),X(e)&&(e=e([n,i],o,r.el,p,{viewSize:[s,l],contentSize:u.slice()})),Y(e))n=$r(e[0],s),i=$r(e[1],l);else if(q(e)){var d=e;d.width=u[0],d.height=u[1];var f=kp(d,{width:s,height:l});n=f.x,i=f.y,h=null,c=null}else if(U(e)&&a){var g=function(t,e,n,i){var r=n[0],o=n[1],a=Math.ceil(Math.SQRT2*i)+8,s=0,l=0,u=e.width,h=e.height;switch(t){case"inside":s=e.x+u/2-r/2,l=e.y+h/2-o/2;break;case"top":s=e.x+u/2-r/2,l=e.y-o-a;break;case"bottom":s=e.x+u/2-r/2,l=e.y+h+a;break;case"left":s=e.x-r-a,l=e.y+h/2-o/2;break;case"right":s=e.x+u+a,l=e.y+h/2-o/2}return[s,l]}(e,p,u,t.get("borderWidth"));n=g[0],i=g[1]}else{g=function(t,e,n,i,r,o,a){var s=n.getSize(),l=s[0],u=s[1];null!=o&&(t+l+o+2>i?t-=l+o:t+=o);null!=a&&(e+u+a>r?e-=u+a:e+=a);return[t,e]}(n,i,r,s,l,h?null:20,c?null:20);n=g[0],i=g[1]}if(h&&(n-=TV(h)?u[0]/2:"right"===h?u[0]:0),c&&(i-=TV(c)?u[1]/2:"bottom"===c?u[1]:0),sV(t)){g=function(t,e,n,i,r){var o=n.getSize(),a=o[0],s=o[1];return t=Math.min(t+a,i)-a,e=Math.min(e+s,r)-s,t=Math.max(t,0),e=Math.max(e,0),[t,e]}(n,i,r,s,l);n=g[0],i=g[1]}r.moveTo(n,i)},e.prototype._updateContentNotChangedOnAxis=function(t,e){var n=this._lastDataByCoordSys,i=this._cbParamsList,r=!!n&&n.length===t.length;return r&&E(n,(function(n,o){var a=n.dataByAxis||[],s=(t[o]||{}).dataByAxis||[];(r=r&&a.length===s.length)&&E(a,(function(t,n){var o=s[n]||{},a=t.seriesDataIndices||[],l=o.seriesDataIndices||[];(r=r&&t.value===o.value&&t.axisType===o.axisType&&t.axisId===o.axisId&&a.length===l.length)&&E(a,(function(t,e){var n=l[e];r=r&&t.seriesIndex===n.seriesIndex&&t.dataIndex===n.dataIndex})),i&&E(t.seriesDataIndices,(function(t){var n=t.seriesIndex,o=e[n],a=i[n];o&&a&&a.data!==o.data&&(r=!1)}))}))})),this._lastDataByCoordSys=t,this._cbParamsList=e,!!r},e.prototype._hide=function(t){this._lastDataByCoordSys=null,t({type:"hideTip",from:this.uid})},e.prototype.dispose=function(t,e){!r.node&&e.getDom()&&(Yg(this,"_updatePosition"),this._tooltipContent.dispose(),kN("itemTooltip",e))},e.type="tooltip",e}(Ag);function MV(t,e,n){var i,r=e.ecModel;n?(i=new Cc(n,r,r),i=new Cc(e.option,i,r)):i=e;for(var o=t.length-1;o>=0;o--){var a=t[o];a&&(a instanceof Cc&&(a=a.get("tooltip",!0)),U(a)&&(a={formatter:a}),a&&(i=new Cc(a,i,r)))}return i}function IV(t,e){return t.dispatchAction||W(e.dispatchAction,e)}function TV(t){return"center"===t||"middle"===t}var CV=["rect","polygon","keep","clear"];function DV(t,e){var n=To(t?t.brush:[]);if(n.length){var i=[];E(n,(function(t){var e=t.hasOwnProperty("toolbox")?t.toolbox:[];e instanceof Array&&(i=i.concat(e))}));var r=t&&t.toolbox;Y(r)&&(r=r[0]),r||(r={feature:{}},t.toolbox=[r]);var o=r.feature||(r.feature={}),a=o.brush||(o.brush={}),s=a.type||(a.type=[]);s.push.apply(s,i),function(t){var e={};E(t,(function(t){e[t]=1})),t.length=0,E(e,(function(e,n){t.push(n)}))}(s),e&&!s.length&&s.push.apply(s,CV)}}var AV=E;function kV(t){if(t)for(var e in t)if(t.hasOwnProperty(e))return!0}function LV(t,e,n){var i={};return AV(e,(function(e){var r,o=i[e]=((r=function(){}).prototype.__hidden=r.prototype,new r);AV(t[e],(function(t,i){if(kD.isValidType(i)){var r={type:i,visual:t};n&&n(r,e),o[i]=new kD(r),"opacity"===i&&((r=T(r)).type="colorAlpha",o.__hidden.__alphaForOpacity=new kD(r))}}))})),i}function PV(t,e,n){var i;E(n,(function(t){e.hasOwnProperty(t)&&kV(e[t])&&(i=!0)})),i&&E(n,(function(n){e.hasOwnProperty(n)&&kV(e[n])?t[n]=T(e[n]):delete t[n]}))}var OV={lineX:RV(0),lineY:RV(1),rect:{point:function(t,e,n){return t&&n.boundingRect.contain(t[0],t[1])},rect:function(t,e,n){return t&&n.boundingRect.intersect(t)}},polygon:{point:function(t,e,n){return t&&n.boundingRect.contain(t[0],t[1])&&P_(n.range,t[0],t[1])},rect:function(t,e,n){var i=n.range;if(!t||i.length<=1)return!1;var r=t.x,o=t.y,a=t.width,s=t.height,l=i[0];return!!(P_(i,r,o)||P_(i,r+a,o)||P_(i,r,o+s)||P_(i,r+a,o+s)||ze.create(t).contain(l[0],l[1])||Zh(r,o,r+a,o,i)||Zh(r,o,r,o+s,i)||Zh(r+a,o,r+a,o+s,i)||Zh(r,o+s,r+a,o+s,i))||void 0}}};function RV(t){var e=["x","y"],n=["width","height"];return{point:function(e,n,i){if(e){var r=i.range;return NV(e[t],r)}},rect:function(i,r,o){if(i){var a=o.range,s=[i[e[t]],i[e[t]]+i[n[t]]];return s[1]e[0][1]&&(e[0][1]=o[0]),o[1]e[1][1]&&(e[1][1]=o[1])}return e&&YV(e)}};function YV(t){return new ze(t[0][0],t[1][0],t[0][1]-t[0][0],t[1][1]-t[1][0])}var XV=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(t,e){this.ecModel=t,this.api=e,this.model,(this._brushController=new lL(e.getZr())).on("brush",W(this._onBrush,this)).mount()},e.prototype.render=function(t,e,n,i){this.model=t,this._updateController(t,e,n,i)},e.prototype.updateTransform=function(t,e,n,i){BV(e),this._updateController(t,e,n,i)},e.prototype.updateVisual=function(t,e,n,i){this.updateTransform(t,e,n,i)},e.prototype.updateView=function(t,e,n,i){this._updateController(t,e,n,i)},e.prototype._updateController=function(t,e,n,i){(!i||i.$from!==t.id)&&this._brushController.setPanels(t.brushTargetManager.makePanelOpts(n)).enableBrush(t.brushOption).updateCovers(t.areas.slice())},e.prototype.dispose=function(){this._brushController.dispose()},e.prototype._onBrush=function(t){var e=this.model.id,n=this.model.brushTargetManager.setOutputRanges(t.areas,this.ecModel);(!t.isEnd||t.removeOnClick)&&this.api.dispatchAction({type:"brush",brushId:e,areas:T(n),$from:e}),t.isEnd&&this.api.dispatchAction({type:"brushEnd",brushId:e,areas:T(n),$from:e})},e.type="brush",e}(Ag),UV=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.areas=[],n.brushOption={},n}return n(e,t),e.prototype.optionUpdated=function(t,e){var n=this.option;!e&&PV(n,t,["inBrush","outOfBrush"]);var i=n.inBrush=n.inBrush||{};n.outOfBrush=n.outOfBrush||{color:"#ddd"},i.hasOwnProperty("liftZ")||(i.liftZ=5)},e.prototype.setAreas=function(t){t&&(this.areas=z(t,(function(t){return ZV(this.option,t)}),this))},e.prototype.setBrushOption=function(t){this.brushOption=ZV(this.option,t),this.brushType=this.brushOption.brushType},e.type="brush",e.dependencies=["geo","grid","xAxis","yAxis","parallel","series"],e.defaultOption={seriesIndex:"all",brushType:"rect",brushMode:"single",transformable:!0,brushStyle:{borderWidth:1,color:"rgba(210,219,238,0.3)",borderColor:"#D2DBEE"},throttleType:"fixRate",throttleDelay:0,removeOnClick:!0,z:1e4},e}(zp);function ZV(t,e){return C({brushType:t.brushType,brushMode:t.brushMode,transformable:t.transformable,brushStyle:new Cc(t.brushStyle).getItemStyle(),removeOnClick:t.removeOnClick,z:t.z},e,!0)}var jV=["rect","polygon","lineX","lineY","keep","clear"],qV=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.render=function(t,e,n){var i,r,o;e.eachComponent({mainType:"brush"},(function(t){i=t.brushType,r=t.brushOption.brushMode||"single",o=o||!!t.areas.length})),this._brushType=i,this._brushMode=r,E(t.get("type",!0),(function(e){t.setIconStatus(e,("keep"===e?"multiple"===r:"clear"===e?o:e===i)?"emphasis":"normal")}))},e.prototype.updateView=function(t,e,n){this.render(t,e,n)},e.prototype.getIcons=function(){var t=this.model,e=t.get("icon",!0),n={};return E(t.get("type",!0),(function(t){e[t]&&(n[t]=e[t])})),n},e.prototype.onclick=function(t,e,n){var i=this._brushType,r=this._brushMode;"clear"===n?(e.dispatchAction({type:"axisAreaSelect",intervals:[]}),e.dispatchAction({type:"brush",command:"clear",areas:[]})):e.dispatchAction({type:"takeGlobalCursor",key:"brush",brushOption:{brushType:"keep"===n?i:i!==n&&n,brushMode:"keep"===n?"multiple"===r?"single":"multiple":r}})},e.getDefaultOption=function(t){return{show:!0,type:jV.slice(),icon:{rect:"M7.3,34.7 M0.4,10V-0.2h9.8 M89.6,10V-0.2h-9.8 M0.4,60v10.2h9.8 M89.6,60v10.2h-9.8 M12.3,22.4V10.5h13.1 M33.6,10.5h7.8 M49.1,10.5h7.8 M77.5,22.4V10.5h-13 M12.3,31.1v8.2 M77.7,31.1v8.2 M12.3,47.6v11.9h13.1 M33.6,59.5h7.6 M49.1,59.5 h7.7 M77.5,47.6v11.9h-13",polygon:"M55.2,34.9c1.7,0,3.1,1.4,3.1,3.1s-1.4,3.1-3.1,3.1 s-3.1-1.4-3.1-3.1S53.5,34.9,55.2,34.9z M50.4,51c1.7,0,3.1,1.4,3.1,3.1c0,1.7-1.4,3.1-3.1,3.1c-1.7,0-3.1-1.4-3.1-3.1 C47.3,52.4,48.7,51,50.4,51z M55.6,37.1l1.5-7.8 M60.1,13.5l1.6-8.7l-7.8,4 M59,19l-1,5.3 M24,16.1l6.4,4.9l6.4-3.3 M48.5,11.6 l-5.9,3.1 M19.1,12.8L9.7,5.1l1.1,7.7 M13.4,29.8l1,7.3l6.6,1.6 M11.6,18.4l1,6.1 M32.8,41.9 M26.6,40.4 M27.3,40.2l6.1,1.6 M49.9,52.1l-5.6-7.6l-4.9-1.2",lineX:"M15.2,30 M19.7,15.6V1.9H29 M34.8,1.9H40.4 M55.3,15.6V1.9H45.9 M19.7,44.4V58.1H29 M34.8,58.1H40.4 M55.3,44.4 V58.1H45.9 M12.5,20.3l-9.4,9.6l9.6,9.8 M3.1,29.9h16.5 M62.5,20.3l9.4,9.6L62.3,39.7 M71.9,29.9H55.4",lineY:"M38.8,7.7 M52.7,12h13.2v9 M65.9,26.6V32 M52.7,46.3h13.2v-9 M24.9,12H11.8v9 M11.8,26.6V32 M24.9,46.3H11.8v-9 M48.2,5.1l-9.3-9l-9.4,9.2 M38.9-3.9V12 M48.2,53.3l-9.3,9l-9.4-9.2 M38.9,62.3V46.4",keep:"M4,10.5V1h10.3 M20.7,1h6.1 M33,1h6.1 M55.4,10.5V1H45.2 M4,17.3v6.6 M55.6,17.3v6.6 M4,30.5V40h10.3 M20.7,40 h6.1 M33,40h6.1 M55.4,30.5V40H45.2 M21,18.9h62.9v48.6H21V18.9z",clear:"M22,14.7l30.9,31 M52.9,14.7L22,45.7 M4.7,16.8V4.2h13.1 M26,4.2h7.8 M41.6,4.2h7.8 M70.3,16.8V4.2H57.2 M4.7,25.9v8.6 M70.3,25.9v8.6 M4.7,43.2v12.6h13.1 M26,55.8h7.8 M41.6,55.8h7.8 M70.3,43.2v12.6H57.2"},title:t.getLocaleModel().get(["toolbox","brush","title"])}},e}(mz);var KV=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.layoutMode={type:"box",ignoreSize:!0},n}return n(e,t),e.type="title",e.defaultOption={z:6,show:!0,text:"",target:"blank",subtext:"",subtarget:"blank",left:0,top:0,backgroundColor:"rgba(0,0,0,0)",borderColor:"#ccc",borderWidth:0,padding:5,itemGap:10,textStyle:{fontSize:18,fontWeight:"bold",color:"#464646"},subtextStyle:{fontSize:12,color:"#6E7079"}},e}(zp),$V=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){if(this.group.removeAll(),t.get("show")){var i=this.group,r=t.getModel("textStyle"),o=t.getModel("subtextStyle"),a=t.get("textAlign"),s=rt(t.get("textBaseline"),t.get("textVerticalAlign")),l=new Xs({style:oc(r,{text:t.get("text"),fill:r.getTextColor()},{disableBox:!0}),z2:10}),u=l.getBoundingRect(),h=t.get("subtext"),c=new Xs({style:oc(o,{text:h,fill:o.getTextColor(),y:u.height+t.get("itemGap"),verticalAlign:"top"},{disableBox:!0}),z2:10}),p=t.get("link"),d=t.get("sublink"),f=t.get("triggerEvent",!0);l.silent=!p&&!f,c.silent=!d&&!f,p&&l.on("click",(function(){Mp(p,"_"+t.get("target"))})),d&&c.on("click",(function(){Mp(d,"_"+t.get("subtarget"))})),rl(l).eventData=rl(c).eventData=f?{componentType:"title",componentIndex:t.componentIndex}:null,i.add(l),h&&i.add(c);var g=i.getBoundingRect(),y=t.getBoxLayoutParams();y.width=g.width,y.height=g.height;var v=kp(y,{width:n.getWidth(),height:n.getHeight()},t.get("padding"));a||("middle"===(a=t.get("left")||t.get("right"))&&(a="center"),"right"===a?v.x+=v.width:"center"===a&&(v.x+=v.width/2)),s||("center"===(s=t.get("top")||t.get("bottom"))&&(s="middle"),"bottom"===s?v.y+=v.height:"middle"===s&&(v.y+=v.height/2),s=s||"top"),i.x=v.x,i.y=v.y,i.markRedraw();var m={align:a,verticalAlign:s};l.setStyle(m),c.setStyle(m),g=i.getBoundingRect();var x=v.margin,_=t.getItemStyle(["color","opacity"]);_.fill=t.get("backgroundColor");var b=new Ws({shape:{x:g.x-x[3],y:g.y-x[0],width:g.width+x[1]+x[3],height:g.height+x[0]+x[2],r:t.get("borderRadius")},style:_,subPixelOptimize:!0,silent:!0});i.add(b)}},e.type="title",e}(Ag);var JV=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.layoutMode="box",n}return n(e,t),e.prototype.init=function(t,e,n){this.mergeDefaultAndTheme(t,n),this._initData()},e.prototype.mergeOption=function(e){t.prototype.mergeOption.apply(this,arguments),this._initData()},e.prototype.setCurrentIndex=function(t){null==t&&(t=this.option.currentIndex);var e=this._data.count();this.option.loop?t=(t%e+e)%e:(t>=e&&(t=e-1),t<0&&(t=0)),this.option.currentIndex=t},e.prototype.getCurrentIndex=function(){return this.option.currentIndex},e.prototype.isIndexMax=function(){return this.getCurrentIndex()>=this._data.count()-1},e.prototype.setPlayState=function(t){this.option.autoPlay=!!t},e.prototype.getPlayState=function(){return!!this.option.autoPlay},e.prototype._initData=function(){var t,e=this.option,n=e.data||[],i=e.axisType,r=this._names=[];"category"===i?(t=[],E(n,(function(e,n){var i,o=Ro(Ao(e),"");q(e)?(i=T(e)).value=n:i=n,t.push(i),r.push(o)}))):t=n;var o={category:"ordinal",time:"time",value:"number"}[i]||"number";(this._data=new cx([{name:"value",type:o}],this)).initData(t,r)},e.prototype.getData=function(){return this._data},e.prototype.getCategories=function(){if("category"===this.get("axisType"))return this._names.slice()},e.type="timeline",e.defaultOption={z:4,show:!0,axisType:"time",realtime:!0,left:"20%",top:null,right:"20%",bottom:0,width:null,height:40,padding:5,controlPosition:"left",autoPlay:!1,rewind:!1,loop:!0,playInterval:2e3,currentIndex:0,itemStyle:{},label:{color:"#000"},data:[]},e}(zp),QV=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="timeline.slider",e.defaultOption=kc(JV.defaultOption,{backgroundColor:"rgba(0,0,0,0)",borderColor:"#ccc",borderWidth:0,orient:"horizontal",inverse:!1,tooltip:{trigger:"item"},symbol:"circle",symbolSize:12,lineStyle:{show:!0,width:2,color:"#DAE1F5"},label:{position:"auto",show:!0,interval:"auto",rotate:0,color:"#A4B1D7"},itemStyle:{color:"#A4B1D7",borderWidth:1},checkpointStyle:{symbol:"circle",symbolSize:15,color:"#316bf3",borderColor:"#fff",borderWidth:2,shadowBlur:2,shadowOffsetX:1,shadowOffsetY:1,shadowColor:"rgba(0, 0, 0, 0.3)",animation:!0,animationDuration:300,animationEasing:"quinticInOut"},controlStyle:{show:!0,showPlayBtn:!0,showPrevBtn:!0,showNextBtn:!0,itemSize:24,itemGap:12,position:"left",playIcon:"path://M31.6,53C17.5,53,6,41.5,6,27.4S17.5,1.8,31.6,1.8C45.7,1.8,57.2,13.3,57.2,27.4S45.7,53,31.6,53z M31.6,3.3 C18.4,3.3,7.5,14.1,7.5,27.4c0,13.3,10.8,24.1,24.1,24.1C44.9,51.5,55.7,40.7,55.7,27.4C55.7,14.1,44.9,3.3,31.6,3.3z M24.9,21.3 c0-2.2,1.6-3.1,3.5-2l10.5,6.1c1.899,1.1,1.899,2.9,0,4l-10.5,6.1c-1.9,1.1-3.5,0.2-3.5-2V21.3z",stopIcon:"path://M30.9,53.2C16.8,53.2,5.3,41.7,5.3,27.6S16.8,2,30.9,2C45,2,56.4,13.5,56.4,27.6S45,53.2,30.9,53.2z M30.9,3.5C17.6,3.5,6.8,14.4,6.8,27.6c0,13.3,10.8,24.1,24.101,24.1C44.2,51.7,55,40.9,55,27.6C54.9,14.4,44.1,3.5,30.9,3.5z M36.9,35.8c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H36c0.5,0,0.9,0.4,0.9,1V35.8z M27.8,35.8 c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H27c0.5,0,0.9,0.4,0.9,1L27.8,35.8L27.8,35.8z",nextIcon:"M2,18.5A1.52,1.52,0,0,1,.92,18a1.49,1.49,0,0,1,0-2.12L7.81,9.36,1,3.11A1.5,1.5,0,1,1,3,.89l8,7.34a1.48,1.48,0,0,1,.49,1.09,1.51,1.51,0,0,1-.46,1.1L3,18.08A1.5,1.5,0,0,1,2,18.5Z",prevIcon:"M10,.5A1.52,1.52,0,0,1,11.08,1a1.49,1.49,0,0,1,0,2.12L4.19,9.64,11,15.89a1.5,1.5,0,1,1-2,2.22L1,10.77A1.48,1.48,0,0,1,.5,9.68,1.51,1.51,0,0,1,1,8.58L9,.92A1.5,1.5,0,0,1,10,.5Z",prevBtnSize:18,nextBtnSize:18,color:"#A4B1D7",borderColor:"#A4B1D7",borderWidth:1},emphasis:{label:{show:!0,color:"#6f778d"},itemStyle:{color:"#316BF3"},controlStyle:{color:"#316BF3",borderColor:"#316BF3",borderWidth:2}},progress:{lineStyle:{color:"#316BF3"},itemStyle:{color:"#316BF3"},label:{color:"#6f778d"}},data:[]}),e}(JV);R(QV,_f.prototype);var tB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="timeline",e}(Ag),eB=function(t){function e(e,n,i,r){var o=t.call(this,e,n,i)||this;return o.type=r||"value",o}return n(e,t),e.prototype.getLabelModel=function(){return this.model.getModel("label")},e.prototype.isHorizontal=function(){return"horizontal"===this.model.get("orient")},e}(ab),nB=Math.PI,iB=Vo(),rB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(t,e){this.api=e},e.prototype.render=function(t,e,n){if(this.model=t,this.api=n,this.ecModel=e,this.group.removeAll(),t.get("show",!0)){var i=this._layout(t,n),r=this._createGroup("_mainGroup"),o=this._createGroup("_labelGroup"),a=this._axis=this._createAxis(i,t);t.formatTooltip=function(t){return og("nameValue",{noName:!0,value:a.scale.getLabel({value:t})})},E(["AxisLine","AxisTick","Control","CurrentPointer"],(function(e){this["_render"+e](i,r,a,t)}),this),this._renderAxisLabel(i,o,a,t),this._position(i,t)}this._doPlayStop(),this._updateTicksStatus()},e.prototype.remove=function(){this._clearTimer(),this.group.removeAll()},e.prototype.dispose=function(){this._clearTimer()},e.prototype._layout=function(t,e){var n,i,r,o,a=t.get(["label","position"]),s=t.get("orient"),l=function(t,e){return kp(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()},t.get("padding"))}(t,e),u={horizontal:"center",vertical:(n=null==a||"auto"===a?"horizontal"===s?l.y+l.height/2=0||"+"===n?"left":"right"},h={horizontal:n>=0||"+"===n?"top":"bottom",vertical:"middle"},c={horizontal:0,vertical:nB/2},p="vertical"===s?l.height:l.width,d=t.getModel("controlStyle"),f=d.get("show",!0),g=f?d.get("itemSize"):0,y=f?d.get("itemGap"):0,v=g+y,m=t.get(["label","rotate"])||0;m=m*nB/180;var x=d.get("position",!0),_=f&&d.get("showPlayBtn",!0),b=f&&d.get("showPrevBtn",!0),w=f&&d.get("showNextBtn",!0),S=0,M=p;"left"===x||"bottom"===x?(_&&(i=[0,0],S+=v),b&&(r=[S,0],S+=v),w&&(o=[M-g,0],M-=v)):(_&&(i=[M-g,0],M-=v),b&&(r=[0,0],S+=v),w&&(o=[M-g,0],M-=v));var I=[S,M];return t.get("inverse")&&I.reverse(),{viewRect:l,mainLength:p,orient:s,rotation:c[s],labelRotation:m,labelPosOpt:n,labelAlign:t.get(["label","align"])||u[s],labelBaseline:t.get(["label","verticalAlign"])||t.get(["label","baseline"])||h[s],playPosition:i,prevBtnPosition:r,nextBtnPosition:o,axisExtent:I,controlSize:g,controlGap:y}},e.prototype._position=function(t,e){var n=this._mainGroup,i=this._labelGroup,r=t.viewRect;if("vertical"===t.orient){var o=[1,0,0,1,0,0],a=r.x,s=r.y+r.height;we(o,o,[-a,-s]),Se(o,o,-nB/2),we(o,o,[a,s]),(r=r.clone()).applyTransform(o)}var l=y(r),u=y(n.getBoundingRect()),h=y(i.getBoundingRect()),c=[n.x,n.y],p=[i.x,i.y];p[0]=c[0]=l[0][0];var d,f=t.labelPosOpt;null==f||U(f)?(v(c,u,l,1,d="+"===f?0:1),v(p,h,l,1,1-d)):(v(c,u,l,1,d=f>=0?0:1),p[1]=c[1]+f);function g(t){t.originX=l[0][0]-t.x,t.originY=l[1][0]-t.y}function y(t){return[[t.x,t.x+t.width],[t.y,t.y+t.height]]}function v(t,e,n,i,r){t[i]+=n[i][r]-e[i][r]}n.setPosition(c),i.setPosition(p),n.rotation=i.rotation=t.rotation,g(n),g(i)},e.prototype._createAxis=function(t,e){var n=e.getData(),i=e.get("axisType"),r=function(t,e){if(e=e||t.get("type"),e)switch(e){case"category":return new Rx({ordinalMeta:t.getCategories(),extent:[1/0,-1/0]});case"time":return new Kx({locale:t.ecModel.getLocaleModel(),useUTC:t.ecModel.get("useUTC")});default:return new Ex}}(e,i);r.getTicks=function(){return n.mapArray(["value"],(function(t){return{value:t}}))};var o=n.getDataExtent("value");r.setExtent(o[0],o[1]),r.calcNiceTicks();var a=new eB("value",r,t.axisExtent,i);return a.model=e,a},e.prototype._createGroup=function(t){var e=this[t]=new Br;return this.group.add(e),e},e.prototype._renderAxisLine=function(t,e,n,i){var r=n.getExtent();if(i.get(["lineStyle","show"])){var o=new Ku({shape:{x1:r[0],y1:0,x2:r[1],y2:0},style:A({lineCap:"round"},i.getModel("lineStyle").getLineStyle()),silent:!0,z2:1});e.add(o);var a=this._progressLine=new Ku({shape:{x1:r[0],x2:this._currentPointer?this._currentPointer.x:r[0],y1:0,y2:0},style:k({lineCap:"round",lineWidth:o.style.lineWidth},i.getModel(["progress","lineStyle"]).getLineStyle()),silent:!0,z2:1});e.add(a)}},e.prototype._renderAxisTick=function(t,e,n,i){var r=this,o=i.getData(),a=n.scale.getTicks();this._tickSymbols=[],E(a,(function(t){var a=n.dataToCoord(t.value),s=o.getItemModel(t.value),l=s.getModel("itemStyle"),u=s.getModel(["emphasis","itemStyle"]),h=s.getModel(["progress","itemStyle"]),c={x:a,y:0,onclick:W(r._changeTimeline,r,t.value)},p=oB(s,l,e,c);p.ensureState("emphasis").style=u.getItemStyle(),p.ensureState("progress").style=h.getItemStyle(),Ul(p);var d=rl(p);s.get("tooltip")?(d.dataIndex=t.value,d.dataModel=i):d.dataIndex=d.dataModel=null,r._tickSymbols.push(p)}))},e.prototype._renderAxisLabel=function(t,e,n,i){var r=this;if(n.getLabelModel().get("show")){var o=i.getData(),a=n.getViewLabels();this._tickLabels=[],E(a,(function(i){var a=i.tickValue,s=o.getItemModel(a),l=s.getModel("label"),u=s.getModel(["emphasis","label"]),h=s.getModel(["progress","label"]),c=n.dataToCoord(i.tickValue),p=new Xs({x:c,y:0,rotation:t.labelRotation-t.rotation,onclick:W(r._changeTimeline,r,a),silent:!1,style:oc(l,{text:i.formattedLabel,align:t.labelAlign,verticalAlign:t.labelBaseline})});p.ensureState("emphasis").style=oc(u),p.ensureState("progress").style=oc(h),e.add(p),Ul(p),iB(p).dataIndex=a,r._tickLabels.push(p)}))}},e.prototype._renderControl=function(t,e,n,i){var r=t.controlSize,o=t.rotation,a=i.getModel("controlStyle").getItemStyle(),s=i.getModel(["emphasis","controlStyle"]).getItemStyle(),l=i.getPlayState(),u=i.get("inverse",!0);function h(t,n,l,u){if(t){var h=Cr(rt(i.get(["controlStyle",n+"BtnSize"]),r),r),c=function(t,e,n,i){var r=i.style,o=Uh(t.get(["controlStyle",e]),i||{},new ze(n[0],n[1],n[2],n[3]));r&&o.setStyle(r);return o}(i,n+"Icon",[0,-h/2,h,h],{x:t[0],y:t[1],originX:r/2,originY:0,rotation:u?-o:0,rectHover:!0,style:a,onclick:l});c.ensureState("emphasis").style=s,e.add(c),Ul(c)}}h(t.nextBtnPosition,"next",W(this._changeTimeline,this,u?"-":"+")),h(t.prevBtnPosition,"prev",W(this._changeTimeline,this,u?"+":"-")),h(t.playPosition,l?"stop":"play",W(this._handlePlayClick,this,!l),!0)},e.prototype._renderCurrentPointer=function(t,e,n,i){var r=i.getData(),o=i.getCurrentIndex(),a=r.getItemModel(o).getModel("checkpointStyle"),s=this,l={onCreate:function(t){t.draggable=!0,t.drift=W(s._handlePointerDrag,s),t.ondragend=W(s._handlePointerDragend,s),aB(t,s._progressLine,o,n,i,!0)},onUpdate:function(t){aB(t,s._progressLine,o,n,i)}};this._currentPointer=oB(a,a,this._mainGroup,{},this._currentPointer,l)},e.prototype._handlePlayClick=function(t){this._clearTimer(),this.api.dispatchAction({type:"timelinePlayChange",playState:t,from:this.uid})},e.prototype._handlePointerDrag=function(t,e,n){this._clearTimer(),this._pointerChangeTimeline([n.offsetX,n.offsetY])},e.prototype._handlePointerDragend=function(t){this._pointerChangeTimeline([t.offsetX,t.offsetY],!0)},e.prototype._pointerChangeTimeline=function(t,e){var n=this._toAxisCoord(t)[0],i=Qr(this._axis.getExtent().slice());n>i[1]&&(n=i[1]),n=0&&(a[o]=+a[o].toFixed(c)),[a,h]}var vB={min:H(yB,"min"),max:H(yB,"max"),average:H(yB,"average"),median:H(yB,"median")};function mB(t,e){if(e){var n=t.getData(),i=t.coordinateSystem,r=i&&i.dimensions;if(!function(t){return!isNaN(parseFloat(t.x))&&!isNaN(parseFloat(t.y))}(e)&&!Y(e.coord)&&Y(r)){var o=xB(e,n,i,t);if((e=T(e)).type&&vB[e.type]&&o.baseAxis&&o.valueAxis){var a=P(r,o.baseAxis.dim),s=P(r,o.valueAxis.dim),l=vB[e.type](n,o.baseDataDim,o.valueDataDim,a,s);e.coord=l[0],e.value=l[1]}else e.coord=[null!=e.xAxis?e.xAxis:e.radiusAxis,null!=e.yAxis?e.yAxis:e.angleAxis]}if(null!=e.coord&&Y(r))for(var u=e.coord,h=0;h<2;h++)vB[u[h]]&&(u[h]=wB(n,n.mapDimension(r[h]),u[h]));else e.coord=[];return e}}function xB(t,e,n,i){var r={};return null!=t.valueIndex||null!=t.valueDim?(r.valueDataDim=null!=t.valueIndex?e.getDimension(t.valueIndex):t.valueDim,r.valueAxis=n.getAxis(function(t,e){var n=t.getData().getDimensionInfo(e);return n&&n.coordDim}(i,r.valueDataDim)),r.baseAxis=n.getOtherAxis(r.valueAxis),r.baseDataDim=e.mapDimension(r.baseAxis.dim)):(r.baseAxis=i.getBaseAxis(),r.valueAxis=n.getOtherAxis(r.baseAxis),r.baseDataDim=e.mapDimension(r.baseAxis.dim),r.valueDataDim=e.mapDimension(r.valueAxis.dim)),r}function _B(t,e){return!(t&&t.containData&&e.coord&&!gB(e))||t.containData(e.coord)}function bB(t,e){return t?function(t,n,i,r){return If(r<2?t.coord&&t.coord[r]:t.value,e[r])}:function(t,n,i,r){return If(t.value,e[r])}}function wB(t,e,n){if("average"===n){var i=0,r=0;return t.each(e,(function(t,e){isNaN(t)||(i+=t,r++)})),i/r}return"median"===n?t.getMedian(e):t.getDataExtent(e)["max"===n?1:0]}var SB=Vo(),MB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(){this.markerGroupMap=yt()},e.prototype.render=function(t,e,n){var i=this,r=this.markerGroupMap;r.each((function(t){SB(t).keep=!1})),e.eachSeries((function(t){var r=dB.getMarkerModelFromSeries(t,i.type);r&&i.renderSeries(t,r,e,n)})),r.each((function(t){!SB(t).keep&&i.group.remove(t.group)}))},e.prototype.markKeep=function(t){SB(t).keep=!0},e.prototype.toggleBlurSeries=function(t,e){var n=this;E(t,(function(t){var i=dB.getMarkerModelFromSeries(t,n.type);i&&i.getData().eachItemGraphicEl((function(t){t&&(e?Nl(t):El(t))}))}))},e.type="marker",e}(Ag);function IB(t,e,n){var i=e.coordinateSystem;t.each((function(r){var o,a=t.getItemModel(r),s=$r(a.get("x"),n.getWidth()),l=$r(a.get("y"),n.getHeight());if(isNaN(s)||isNaN(l)){if(e.getMarkerPosition)o=e.getMarkerPosition(t.getValues(t.dimensions,r));else if(i){var u=t.get(i.dimensions[0],r),h=t.get(i.dimensions[1],r);o=i.dataToPoint([u,h])}}else o=[s,l];isNaN(s)||(o[0]=s),isNaN(l)||(o[1]=l),t.setItemLayout(r,o)}))}var TB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.updateTransform=function(t,e,n){e.eachSeries((function(t){var e=dB.getMarkerModelFromSeries(t,"markPoint");e&&(IB(e.getData(),t,n),this.markerGroupMap.get(t.id).updateLayout())}),this)},e.prototype.renderSeries=function(t,e,n,i){var r=t.coordinateSystem,o=t.id,a=t.getData(),s=this.markerGroupMap,l=s.get(o)||s.set(o,new xS),u=function(t,e,n){var i;i=t?z(t&&t.dimensions,(function(t){return A(A({},e.getData().getDimensionInfo(e.getData().mapDimension(t))||{}),{name:t,ordinalMeta:null})})):[{name:"value",type:"float"}];var r=new cx(i,n),o=z(n.get("data"),H(mB,e));t&&(o=B(o,H(_B,t)));var a=bB(!!t,i);return r.initData(o,null,a),r}(r,t,e);e.setData(u),IB(e.getData(),t,i),u.each((function(t){var n=u.getItemModel(t),i=n.getShallow("symbol"),r=n.getShallow("symbolSize"),o=n.getShallow("symbolRotate"),s=n.getShallow("symbolOffset"),l=n.getShallow("symbolKeepAspect");if(X(i)||X(r)||X(o)||X(s)){var h=e.getRawValue(t),c=e.getDataParams(t);X(i)&&(i=i(h,c)),X(r)&&(r=r(h,c)),X(o)&&(o=o(h,c)),X(s)&&(s=s(h,c))}var p=n.getModel("itemStyle").getItemStyle(),d=Ay(a,"color");p.fill||(p.fill=d),u.setItemVisual(t,{symbol:i,symbolSize:r,symbolRotate:o,symbolOffset:s,symbolKeepAspect:l,style:p})})),l.updateData(u),this.group.add(l.group),u.eachItemGraphicEl((function(t){t.traverse((function(t){rl(t).dataModel=e}))})),this.markKeep(l),l.group.silent=e.get("silent")||t.get("silent")},e.type="markPoint",e}(MB);var CB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.createMarkerModelFromSeries=function(t,n,i){return new e(t,n,i)},e.type="markLine",e.defaultOption={z:5,symbol:["circle","arrow"],symbolSize:[8,16],symbolOffset:0,precision:2,tooltip:{trigger:"item"},label:{show:!0,position:"end",distance:5},lineStyle:{type:"dashed"},emphasis:{label:{show:!0},lineStyle:{width:3}},animationEasing:"linear"},e}(dB),DB=Vo(),AB=function(t,e,n,i){var r,o=t.getData();if(Y(i))r=i;else{var a=i.type;if("min"===a||"max"===a||"average"===a||"median"===a||null!=i.xAxis||null!=i.yAxis){var s=void 0,l=void 0;if(null!=i.yAxis||null!=i.xAxis)s=e.getAxis(null!=i.yAxis?"y":"x"),l=it(i.yAxis,i.xAxis);else{var u=xB(i,o,e,t);s=u.valueAxis,l=wB(o,xx(o,u.valueDataDim),a)}var h="x"===s.dim?0:1,c=1-h,p=T(i),d={coord:[]};p.type=null,p.coord=[],p.coord[c]=-1/0,d.coord[c]=1/0;var f=n.get("precision");f>=0&&j(l)&&(l=+l.toFixed(Math.min(f,20))),p.coord[h]=d.coord[h]=l,r=[p,d,{type:a,valueIndex:i.valueIndex,value:l}]}else r=[]}var g=[mB(t,r[0]),mB(t,r[1]),A({},r[2])];return g[2].type=g[2].type||null,C(g[2],g[0]),C(g[2],g[1]),g};function kB(t){return!isNaN(t)&&!isFinite(t)}function LB(t,e,n,i){var r=1-t,o=i.dimensions[t];return kB(e[r])&&kB(n[r])&&e[t]===n[t]&&i.getAxis(o).containData(e[t])}function PB(t,e){if("cartesian2d"===t.type){var n=e[0].coord,i=e[1].coord;if(n&&i&&(LB(1,n,i,t)||LB(0,n,i,t)))return!0}return _B(t,e[0])&&_B(t,e[1])}function OB(t,e,n,i,r){var o,a=i.coordinateSystem,s=t.getItemModel(e),l=$r(s.get("x"),r.getWidth()),u=$r(s.get("y"),r.getHeight());if(isNaN(l)||isNaN(u)){if(i.getMarkerPosition)o=i.getMarkerPosition(t.getValues(t.dimensions,e));else{var h=a.dimensions,c=t.get(h[0],e),p=t.get(h[1],e);o=a.dataToPoint([c,p])}if(OS(a,"cartesian2d")){var d=a.getAxis("x"),f=a.getAxis("y");h=a.dimensions;kB(t.get(h[0],e))?o[0]=d.toGlobalCoord(d.getExtent()[n?0:1]):kB(t.get(h[1],e))&&(o[1]=f.toGlobalCoord(f.getExtent()[n?0:1]))}isNaN(l)||(o[0]=l),isNaN(u)||(o[1]=u)}else o=[l,u];t.setItemLayout(e,o)}var RB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.updateTransform=function(t,e,n){e.eachSeries((function(t){var e=dB.getMarkerModelFromSeries(t,"markLine");if(e){var i=e.getData(),r=DB(e).from,o=DB(e).to;r.each((function(e){OB(r,e,!0,t,n),OB(o,e,!1,t,n)})),i.each((function(t){i.setItemLayout(t,[r.getItemLayout(t),o.getItemLayout(t)])})),this.markerGroupMap.get(t.id).updateLayout()}}),this)},e.prototype.renderSeries=function(t,e,n,i){var r=t.coordinateSystem,o=t.id,a=t.getData(),s=this.markerGroupMap,l=s.get(o)||s.set(o,new YA);this.group.add(l.group);var u=function(t,e,n){var i;i=t?z(t&&t.dimensions,(function(t){return A(A({},e.getData().getDimensionInfo(e.getData().mapDimension(t))||{}),{name:t,ordinalMeta:null})})):[{name:"value",type:"float"}];var r=new cx(i,n),o=new cx(i,n),a=new cx([],n),s=z(n.get("data"),H(AB,e,t,n));t&&(s=B(s,H(PB,t)));var l=bB(!!t,i);return r.initData(z(s,(function(t){return t[0]})),null,l),o.initData(z(s,(function(t){return t[1]})),null,l),a.initData(z(s,(function(t){return t[2]}))),a.hasItemOption=!0,{from:r,to:o,line:a}}(r,t,e),h=u.from,c=u.to,p=u.line;DB(e).from=h,DB(e).to=c,e.setData(p);var d=e.get("symbol"),f=e.get("symbolSize"),g=e.get("symbolRotate"),y=e.get("symbolOffset");function v(e,n,r){var o=e.getItemModel(n);OB(e,n,r,t,i);var s=o.getModel("itemStyle").getItemStyle();null==s.fill&&(s.fill=Ay(a,"color")),e.setItemVisual(n,{symbolKeepAspect:o.get("symbolKeepAspect"),symbolOffset:rt(o.get("symbolOffset",!0),y[r?0:1]),symbolRotate:rt(o.get("symbolRotate",!0),g[r?0:1]),symbolSize:rt(o.get("symbolSize"),f[r?0:1]),symbol:rt(o.get("symbol",!0),d[r?0:1]),style:s})}Y(d)||(d=[d,d]),Y(f)||(f=[f,f]),Y(g)||(g=[g,g]),Y(y)||(y=[y,y]),u.from.each((function(t){v(h,t,!0),v(c,t,!1)})),p.each((function(t){var e=p.getItemModel(t).getModel("lineStyle").getLineStyle();p.setItemLayout(t,[h.getItemLayout(t),c.getItemLayout(t)]),null==e.stroke&&(e.stroke=h.getItemVisual(t,"style").fill),p.setItemVisual(t,{fromSymbolKeepAspect:h.getItemVisual(t,"symbolKeepAspect"),fromSymbolOffset:h.getItemVisual(t,"symbolOffset"),fromSymbolRotate:h.getItemVisual(t,"symbolRotate"),fromSymbolSize:h.getItemVisual(t,"symbolSize"),fromSymbol:h.getItemVisual(t,"symbol"),toSymbolKeepAspect:c.getItemVisual(t,"symbolKeepAspect"),toSymbolOffset:c.getItemVisual(t,"symbolOffset"),toSymbolRotate:c.getItemVisual(t,"symbolRotate"),toSymbolSize:c.getItemVisual(t,"symbolSize"),toSymbol:c.getItemVisual(t,"symbol"),style:e})})),l.updateData(p),u.line.eachItemGraphicEl((function(t){rl(t).dataModel=e,t.traverse((function(t){rl(t).dataModel=e}))})),this.markKeep(l),l.group.silent=e.get("silent")||t.get("silent")},e.type="markLine",e}(MB);var NB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.createMarkerModelFromSeries=function(t,n,i){return new e(t,n,i)},e.type="markArea",e.defaultOption={z:1,tooltip:{trigger:"item"},animation:!1,label:{show:!0,position:"top"},itemStyle:{borderWidth:0},emphasis:{label:{show:!0,position:"top"}}},e}(dB),EB=Vo(),zB=function(t,e,n,i){var r=i[0],o=i[1];if(r&&o){var a=mB(t,r),s=mB(t,o),l=a.coord,u=s.coord;l[0]=it(l[0],-1/0),l[1]=it(l[1],-1/0),u[0]=it(u[0],1/0),u[1]=it(u[1],1/0);var h=D([{},a,s]);return h.coord=[a.coord,s.coord],h.x0=a.x,h.y0=a.y,h.x1=s.x,h.y1=s.y,h}};function VB(t){return!isNaN(t)&&!isFinite(t)}function BB(t,e,n,i){var r=1-t;return VB(e[r])&&VB(n[r])}function FB(t,e){var n=e.coord[0],i=e.coord[1],r={coord:n,x:e.x0,y:e.y0},o={coord:i,x:e.x1,y:e.y1};return OS(t,"cartesian2d")?!(!n||!i||!BB(1,n,i)&&!BB(0,n,i))||function(t,e,n){return!(t&&t.containZone&&e.coord&&n.coord&&!gB(e)&&!gB(n))||t.containZone(e.coord,n.coord)}(t,r,o):_B(t,r)||_B(t,o)}function GB(t,e,n,i,r){var o,a=i.coordinateSystem,s=t.getItemModel(e),l=$r(s.get(n[0]),r.getWidth()),u=$r(s.get(n[1]),r.getHeight());if(isNaN(l)||isNaN(u)){if(i.getMarkerPosition){var h=t.getValues(["x0","y0"],e),c=t.getValues(["x1","y1"],e),p=a.clampData(h),d=a.clampData(c),f=[];"x0"===n[0]?f[0]=p[0]>d[0]?c[0]:h[0]:f[0]=p[0]>d[0]?h[0]:c[0],"y0"===n[1]?f[1]=p[1]>d[1]?c[1]:h[1]:f[1]=p[1]>d[1]?h[1]:c[1],o=i.getMarkerPosition(f,n,!0)}else{var g=[m=t.get(n[0],e),x=t.get(n[1],e)];a.clampData&&a.clampData(g,g),o=a.dataToPoint(g,!0)}if(OS(a,"cartesian2d")){var y=a.getAxis("x"),v=a.getAxis("y"),m=t.get(n[0],e),x=t.get(n[1],e);VB(m)?o[0]=y.toGlobalCoord(y.getExtent()["x0"===n[0]?0:1]):VB(x)&&(o[1]=v.toGlobalCoord(v.getExtent()["y0"===n[1]?0:1]))}isNaN(l)||(o[0]=l),isNaN(u)||(o[1]=u)}else o=[l,u];return o}var WB=[["x0","y0"],["x1","y0"],["x1","y1"],["x0","y1"]],HB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.updateTransform=function(t,e,n){e.eachSeries((function(t){var e=dB.getMarkerModelFromSeries(t,"markArea");if(e){var i=e.getData();i.each((function(e){var r=z(WB,(function(r){return GB(i,e,r,t,n)}));i.setItemLayout(e,r),i.getItemGraphicEl(e).setShape("points",r)}))}}),this)},e.prototype.renderSeries=function(t,e,n,i){var r=t.coordinateSystem,o=t.id,a=t.getData(),s=this.markerGroupMap,l=s.get(o)||s.set(o,{group:new Br});this.group.add(l.group),this.markKeep(l);var u=function(t,e,n){var i,r,o=["x0","y0","x1","y1"];if(t){var a=z(t&&t.dimensions,(function(t){var n=e.getData();return A(A({},n.getDimensionInfo(n.mapDimension(t))||{}),{name:t,ordinalMeta:null})}));r=z(o,(function(t,e){return{name:t,type:a[e%2].type}})),i=new cx(r,n)}else i=new cx(r=[{name:"value",type:"float"}],n);var s=z(n.get("data"),H(zB,e,t,n));t&&(s=B(s,H(FB,t)));var l=t?function(t,e,n,i){return If(t.coord[Math.floor(i/2)][i%2],r[i])}:function(t,e,n,i){return If(t.value,r[i])};return i.initData(s,null,l),i.hasItemOption=!0,i}(r,t,e);e.setData(u),u.each((function(e){var n=z(WB,(function(n){return GB(u,e,n,t,i)})),o=r.getAxis("x").scale,s=r.getAxis("y").scale,l=o.getExtent(),h=s.getExtent(),c=[o.parse(u.get("x0",e)),o.parse(u.get("x1",e))],p=[s.parse(u.get("y0",e)),s.parse(u.get("y1",e))];Qr(c),Qr(p);var d=!!(l[0]>c[1]||l[1]p[1]||h[1]=0},e.prototype.getOrient=function(){return"vertical"===this.get("orient")?{index:1,name:"vertical"}:{index:0,name:"horizontal"}},e.type="legend.plain",e.dependencies=["series"],e.defaultOption={z:4,show:!0,orient:"horizontal",left:"center",top:0,align:"auto",backgroundColor:"rgba(0,0,0,0)",borderColor:"#ccc",borderRadius:0,borderWidth:0,padding:5,itemGap:10,itemWidth:25,itemHeight:14,symbolRotate:"inherit",symbolKeepAspect:!0,inactiveColor:"#ccc",inactiveBorderColor:"#ccc",inactiveBorderWidth:"auto",itemStyle:{color:"inherit",opacity:"inherit",borderColor:"inherit",borderWidth:"auto",borderCap:"inherit",borderJoin:"inherit",borderDashOffset:"inherit",borderMiterLimit:"inherit"},lineStyle:{width:"auto",color:"inherit",inactiveColor:"#ccc",inactiveWidth:2,opacity:"inherit",type:"inherit",cap:"inherit",join:"inherit",dashOffset:"inherit",miterLimit:"inherit"},textStyle:{color:"#333"},selectedMode:!0,selector:!1,selectorLabel:{show:!0,borderRadius:10,padding:[3,5,3,5],fontSize:12,fontFamily:"sans-serif",color:"#666",borderWidth:1,borderColor:"#666"},emphasis:{selectorLabel:{show:!0,color:"#eee",backgroundColor:"#666"}},selectorPosition:"auto",selectorItemGap:7,selectorButtonGap:10,tooltip:{show:!1}},e}(zp),XB=H,UB=E,ZB=Br,jB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.newlineDisabled=!1,n}return n(e,t),e.prototype.init=function(){this.group.add(this._contentGroup=new ZB),this.group.add(this._selectorGroup=new ZB),this._isFirstRender=!0},e.prototype.getContentGroup=function(){return this._contentGroup},e.prototype.getSelectorGroup=function(){return this._selectorGroup},e.prototype.render=function(t,e,n){var i=this._isFirstRender;if(this._isFirstRender=!1,this.resetInner(),t.get("show",!0)){var r=t.get("align"),o=t.get("orient");r&&"auto"!==r||(r="right"===t.get("left")&&"vertical"===o?"right":"left");var a=t.get("selector",!0),s=t.get("selectorPosition",!0);!a||s&&"auto"!==s||(s="horizontal"===o?"end":"start"),this.renderInner(r,t,e,n,a,o,s);var l=t.getBoxLayoutParams(),u={width:n.getWidth(),height:n.getHeight()},h=t.get("padding"),c=kp(l,u,h),p=this.layoutInner(t,r,c,i,a,s),d=kp(k({width:p.width,height:p.height},l),u,h);this.group.x=d.x-p.x,this.group.y=d.y-p.y,this.group.markRedraw(),this.group.add(this._backgroundEl=Sz(p,t))}},e.prototype.resetInner=function(){this.getContentGroup().removeAll(),this._backgroundEl&&this.group.remove(this._backgroundEl),this.getSelectorGroup().removeAll()},e.prototype.renderInner=function(t,e,n,i,r,o,a){var s=this.getContentGroup(),l=yt(),u=e.get("selectedMode"),h=[];n.eachRawSeries((function(t){!t.get("legendHoverLink")&&h.push(t.id)})),UB(e.getData(),(function(r,o){var a=r.get("name");if(!this.newlineDisabled&&(""===a||"\n"===a)){var c=new ZB;return c.newline=!0,void s.add(c)}var p=n.getSeriesByName(a)[0];if(!l.get(a)){if(p){var d=p.getData(),f=d.getVisual("legendLineStyle")||{},g=d.getVisual("legendIcon"),y=d.getVisual("style"),v=this._createItem(p,a,o,r,e,t,f,y,g,u,i);v.on("click",XB(qB,a,null,i,h)).on("mouseover",XB($B,p.name,null,i,h)).on("mouseout",XB(JB,p.name,null,i,h)),n.ssr&&v.eachChild((function(t){var e=rl(t);e.seriesIndex=p.seriesIndex,e.dataIndex=o,e.ssrType="legend"})),l.set(a,!0)}else n.eachRawSeries((function(s){if(!l.get(a)&&s.legendVisualProvider){var c=s.legendVisualProvider;if(!c.containName(a))return;var p=c.indexOfName(a),d=c.getItemVisual(p,"style"),f=c.getItemVisual(p,"legendIcon"),g=qn(d.fill);g&&0===g[3]&&(g[3]=.2,d=A(A({},d),{fill:ri(g,"rgba")}));var y=this._createItem(s,a,o,r,e,t,{},d,f,u,i);y.on("click",XB(qB,null,a,i,h)).on("mouseover",XB($B,null,a,i,h)).on("mouseout",XB(JB,null,a,i,h)),n.ssr&&y.eachChild((function(t){var e=rl(t);e.seriesIndex=s.seriesIndex,e.dataIndex=o,e.ssrType="legend"})),l.set(a,!0)}}),this);0}}),this),r&&this._createSelector(r,e,i,o,a)},e.prototype._createSelector=function(t,e,n,i,r){var o=this.getSelectorGroup();UB(t,(function(t){var i=t.type,r=new Xs({style:{x:0,y:0,align:"center",verticalAlign:"middle"},onclick:function(){n.dispatchAction({type:"all"===i?"legendAllSelect":"legendInverseSelect"})}});o.add(r),ic(r,{normal:e.getModel("selectorLabel"),emphasis:e.getModel(["emphasis","selectorLabel"])},{defaultText:t.title}),Ul(r)}))},e.prototype._createItem=function(t,e,n,i,r,o,a,s,l,u,h){var c=t.visualDrawType,p=r.get("itemWidth"),d=r.get("itemHeight"),f=r.isSelected(e),g=i.get("symbolRotate"),y=i.get("symbolKeepAspect"),v=i.get("icon"),m=function(t,e,n,i,r,o,a){function s(t,e){"auto"===t.lineWidth&&(t.lineWidth=e.lineWidth>0?2:0),UB(t,(function(n,i){"inherit"===t[i]&&(t[i]=e[i])}))}var l=e.getModel("itemStyle"),u=l.getItemStyle(),h=0===t.lastIndexOf("empty",0)?"fill":"stroke",c=l.getShallow("decal");u.decal=c&&"inherit"!==c?mv(c,a):i.decal,"inherit"===u.fill&&(u.fill=i[r]);"inherit"===u.stroke&&(u.stroke=i[h]);"inherit"===u.opacity&&(u.opacity=("fill"===r?i:n).opacity);s(u,i);var p=e.getModel("lineStyle"),d=p.getLineStyle();if(s(d,n),"auto"===u.fill&&(u.fill=i.fill),"auto"===u.stroke&&(u.stroke=i.fill),"auto"===d.stroke&&(d.stroke=i.fill),!o){var f=e.get("inactiveBorderWidth"),g=u[h];u.lineWidth="auto"===f?i.lineWidth>0&&g?2:0:u.lineWidth,u.fill=e.get("inactiveColor"),u.stroke=e.get("inactiveBorderColor"),d.stroke=p.get("inactiveColor"),d.lineWidth=p.get("inactiveWidth")}return{itemStyle:u,lineStyle:d}}(l=v||l||"roundRect",i,a,s,c,f,h),x=new ZB,_=i.getModel("textStyle");if(!X(t.getLegendIcon)||v&&"inherit"!==v){var b="inherit"===v&&t.getData().getVisual("symbol")?"inherit"===g?t.getData().getVisual("symbolRotate"):g:0;x.add(function(t){var e=t.icon||"roundRect",n=Xy(e,0,0,t.itemWidth,t.itemHeight,t.itemStyle.fill,t.symbolKeepAspect);n.setStyle(t.itemStyle),n.rotation=(t.iconRotate||0)*Math.PI/180,n.setOrigin([t.itemWidth/2,t.itemHeight/2]),e.indexOf("empty")>-1&&(n.style.stroke=n.style.fill,n.style.fill="#fff",n.style.lineWidth=2);return n}({itemWidth:p,itemHeight:d,icon:l,iconRotate:b,itemStyle:m.itemStyle,lineStyle:m.lineStyle,symbolKeepAspect:y}))}else x.add(t.getLegendIcon({itemWidth:p,itemHeight:d,icon:l,iconRotate:g,itemStyle:m.itemStyle,lineStyle:m.lineStyle,symbolKeepAspect:y}));var w="left"===o?p+5:-5,S=o,M=r.get("formatter"),I=e;U(M)&&M?I=M.replace("{name}",null!=e?e:""):X(M)&&(I=M(e));var T=f?_.getTextColor():i.get("inactiveColor");x.add(new Xs({style:oc(_,{text:I,x:w,y:d/2,fill:T,align:S,verticalAlign:"middle"},{inheritColor:T})}));var C=new Ws({shape:x.getBoundingRect(),style:{fill:"transparent"}}),D=i.getModel("tooltip");return D.get("show")&&Kh({el:C,componentModel:r,itemName:e,itemTooltipOption:D.option}),x.add(C),x.eachChild((function(t){t.silent=!0})),C.silent=!u,this.getContentGroup().add(x),Ul(x),x.__legendDataIndex=n,x},e.prototype.layoutInner=function(t,e,n,i,r,o){var a=this.getContentGroup(),s=this.getSelectorGroup();Ap(t.get("orient"),a,t.get("itemGap"),n.width,n.height);var l=a.getBoundingRect(),u=[-l.x,-l.y];if(s.markRedraw(),a.markRedraw(),r){Ap("horizontal",s,t.get("selectorItemGap",!0));var h=s.getBoundingRect(),c=[-h.x,-h.y],p=t.get("selectorButtonGap",!0),d=t.getOrient().index,f=0===d?"width":"height",g=0===d?"height":"width",y=0===d?"y":"x";"end"===o?c[d]+=l[f]+p:u[d]+=h[f]+p,c[1-d]+=l[g]/2-h[g]/2,s.x=c[0],s.y=c[1],a.x=u[0],a.y=u[1];var v={x:0,y:0};return v[f]=l[f]+p+h[f],v[g]=Math.max(l[g],h[g]),v[y]=Math.min(0,h[y]+c[1-d]),v}return a.x=u[0],a.y=u[1],this.group.getBoundingRect()},e.prototype.remove=function(){this.getContentGroup().removeAll(),this._isFirstRender=!0},e.type="legend.plain",e}(Ag);function qB(t,e,n,i){JB(t,e,n,i),n.dispatchAction({type:"legendToggleSelect",name:null!=t?t:e}),$B(t,e,n,i)}function KB(t){for(var e,n=t.getZr().storage.getDisplayList(),i=0,r=n.length;in[r],f=[-c.x,-c.y];e||(f[i]=l[s]);var g=[0,0],y=[-p.x,-p.y],v=rt(t.get("pageButtonGap",!0),t.get("itemGap",!0));d&&("end"===t.get("pageButtonPosition",!0)?y[i]+=n[r]-p[r]:g[i]+=p[r]+v);y[1-i]+=c[o]/2-p[o]/2,l.setPosition(f),u.setPosition(g),h.setPosition(y);var m={x:0,y:0};if(m[r]=d?n[r]:c[r],m[o]=Math.max(c[o],p[o]),m[a]=Math.min(0,p[a]+y[1-i]),u.__rectSize=n[r],d){var x={x:0,y:0};x[r]=Math.max(n[r]-p[r]-v,0),x[o]=m[o],u.setClipPath(new Ws({shape:x})),u.__rectSize=x[r]}else h.eachChild((function(t){t.attr({invisible:!0,silent:!0})}));var _=this._getPageInfo(t);return null!=_.pageIndex&&vh(l,{x:_.contentPosition[0],y:_.contentPosition[1]},d?t:null),this._updatePageInfoView(t,_),m},e.prototype._pageGo=function(t,e,n){var i=this._getPageInfo(e)[t];null!=i&&n.dispatchAction({type:"legendScroll",scrollDataIndex:i,legendId:e.id})},e.prototype._updatePageInfoView=function(t,e){var n=this._controllerGroup;E(["pagePrev","pageNext"],(function(i){var r=null!=e[i+"DataIndex"],o=n.childOfName(i);o&&(o.setStyle("fill",r?t.get("pageIconColor",!0):t.get("pageIconInactiveColor",!0)),o.cursor=r?"pointer":"default")}));var i=n.childOfName("pageText"),r=t.get("pageFormatter"),o=e.pageIndex,a=null!=o?o+1:0,s=e.pageCount;i&&r&&i.setStyle("text",U(r)?r.replace("{current}",null==a?"":a+"").replace("{total}",null==s?"":s+""):r({current:a,total:s}))},e.prototype._getPageInfo=function(t){var e=t.get("scrollDataIndex",!0),n=this.getContentGroup(),i=this._containerGroup.__rectSize,r=t.getOrient().index,o=oF[r],a=aF[r],s=this._findTargetItemIndex(e),l=n.children(),u=l[s],h=l.length,c=h?1:0,p={contentPosition:[n.x,n.y],pageCount:c,pageIndex:c-1,pagePrevDataIndex:null,pageNextDataIndex:null};if(!u)return p;var d=m(u);p.contentPosition[r]=-d.s;for(var f=s+1,g=d,y=d,v=null;f<=h;++f)(!(v=m(l[f]))&&y.e>g.s+i||v&&!x(v,g.s))&&(g=y.i>g.i?y:v)&&(null==p.pageNextDataIndex&&(p.pageNextDataIndex=g.i),++p.pageCount),y=v;for(f=s-1,g=d,y=d,v=null;f>=-1;--f)(v=m(l[f]))&&x(y,v.s)||!(g.i=e&&t.s<=e+i}},e.prototype._findTargetItemIndex=function(t){return this._showController?(this.getContentGroup().eachChild((function(i,r){var o=i.__legendDataIndex;null==n&&null!=o&&(n=r),o===t&&(e=r)})),null!=e?e:n):0;var e,n},e.type="legend.scroll",e}(jB);function lF(t){Vm(eF),t.registerComponentModel(nF),t.registerComponentView(sF),function(t){t.registerAction("legendScroll","legendscroll",(function(t,e){var n=t.scrollDataIndex;null!=n&&e.eachComponent({mainType:"legend",subType:"scroll",query:t},(function(t){t.setScrollDataIndex(n)}))}))}(t)}var uF=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="dataZoom.inside",e.defaultOption=kc(az.defaultOption,{disabled:!1,zoomLock:!1,zoomOnMouseWheel:!0,moveOnMouseMove:!0,moveOnMouseWheel:!1,preventDefaultMouseMove:!0}),e}(az),hF=Vo();function cF(t,e,n){hF(t).coordSysRecordMap.each((function(t){var i=t.dataZoomInfoMap.get(e.uid);i&&(i.getRange=n)}))}function pF(t,e){if(e){t.removeKey(e.model.uid);var n=e.controller;n&&n.dispose()}}function dF(t,e){t.isDisposed()||t.dispatchAction({type:"dataZoom",animation:{easing:"cubicOut",duration:100},batch:e})}function fF(t,e,n,i){return t.coordinateSystem.containPoint([n,i])}function gF(t){t.registerProcessor(t.PRIORITY.PROCESSOR.FILTER,(function(t,e){var n=hF(e),i=n.coordSysRecordMap||(n.coordSysRecordMap=yt());i.each((function(t){t.dataZoomInfoMap=null})),t.eachComponent({mainType:"dataZoom",subType:"inside"},(function(t){E(rz(t).infoList,(function(n){var r=n.model.uid,o=i.get(r)||i.set(r,function(t,e){var n={model:e,containsPoint:H(fF,e),dispatchAction:H(dF,t),dataZoomInfoMap:null,controller:null},i=n.controller=new nT(t.getZr());return E(["pan","zoom","scrollMove"],(function(t){i.on(t,(function(e){var i=[];n.dataZoomInfoMap.each((function(r){if(e.isAvailableBehavior(r.model.option)){var o=(r.getRange||{})[t],a=o&&o(r.dzReferCoordSysInfo,n.model.mainType,n.controller,e);!r.model.get("disabled",!0)&&a&&i.push({dataZoomId:r.model.id,start:a[0],end:a[1]})}})),i.length&&n.dispatchAction(i)}))})),n}(e,n.model));(o.dataZoomInfoMap||(o.dataZoomInfoMap=yt())).set(t.uid,{dzReferCoordSysInfo:n,model:t,getRange:null})}))})),i.each((function(t){var e,n=t.controller,r=t.dataZoomInfoMap;if(r){var o=r.keys()[0];null!=o&&(e=r.get(o))}if(e){var a=function(t){var e,n="type_",i={type_true:2,type_move:1,type_false:0,type_undefined:-1},r=!0;return t.each((function(t){var o=t.model,a=!o.get("disabled",!0)&&(!o.get("zoomLock",!0)||"move");i[n+a]>i[n+e]&&(e=a),r=r&&o.get("preventDefaultMouseMove",!0)})),{controlType:e,opt:{zoomOnMouseWheel:!0,moveOnMouseMove:!0,moveOnMouseWheel:!0,preventDefaultMouseMove:!!r}}}(r);n.enable(a.controlType,a.opt),n.setPointerChecker(t.containsPoint),Hg(t,"dispatchAction",e.model.get("throttle",!0),"fixRate")}else pF(i,t)}))}))}var yF=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.type="dataZoom.inside",e}return n(e,t),e.prototype.render=function(e,n,i){t.prototype.render.apply(this,arguments),e.noTarget()?this._clear():(this.range=e.getPercentRange(),cF(i,e,{pan:W(vF.pan,this),zoom:W(vF.zoom,this),scrollMove:W(vF.scrollMove,this)}))},e.prototype.dispose=function(){this._clear(),t.prototype.dispose.apply(this,arguments)},e.prototype._clear=function(){!function(t,e){for(var n=hF(t).coordSysRecordMap,i=n.keys(),r=0;r0?s.pixelStart+s.pixelLength-s.pixel:s.pixel-s.pixelStart)/s.pixelLength*(o[1]-o[0])+o[0],u=Math.max(1/i.scale,0);o[0]=(o[0]-l)*u+l,o[1]=(o[1]-l)*u+l;var h=this.dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();return zk(0,o,[0,100],0,h.minSpan,h.maxSpan),this.range=o,r[0]!==o[0]||r[1]!==o[1]?o:void 0}},pan:mF((function(t,e,n,i,r,o){var a=xF[i]([o.oldX,o.oldY],[o.newX,o.newY],e,r,n);return a.signal*(t[1]-t[0])*a.pixel/a.pixelLength})),scrollMove:mF((function(t,e,n,i,r,o){return xF[i]([0,0],[o.scrollDelta,o.scrollDelta],e,r,n).signal*(t[1]-t[0])*o.scrollDelta}))};function mF(t){return function(e,n,i,r){var o=this.range,a=o.slice(),s=e.axisModels[0];if(s)return zk(t(a,s,e,n,i,r),a,[0,100],"all"),this.range=a,o[0]!==a[0]||o[1]!==a[1]?a:void 0}}var xF={grid:function(t,e,n,i,r){var o=n.axis,a={},s=r.model.coordinateSystem.getRect();return t=t||[0,0],"x"===o.dim?(a.pixel=e[0]-t[0],a.pixelLength=s.width,a.pixelStart=s.x,a.signal=o.inverse?1:-1):(a.pixel=e[1]-t[1],a.pixelLength=s.height,a.pixelStart=s.y,a.signal=o.inverse?-1:1),a},polar:function(t,e,n,i,r){var o=n.axis,a={},s=r.model.coordinateSystem,l=s.getRadiusAxis().getExtent(),u=s.getAngleAxis().getExtent();return t=t?s.pointToCoord(t):[0,0],e=s.pointToCoord(e),"radiusAxis"===n.mainType?(a.pixel=e[0]-t[0],a.pixelLength=l[1]-l[0],a.pixelStart=l[0],a.signal=o.inverse?1:-1):(a.pixel=e[1]-t[1],a.pixelLength=u[1]-u[0],a.pixelStart=u[0],a.signal=o.inverse?-1:1),a},singleAxis:function(t,e,n,i,r){var o=n.axis,a=r.model.coordinateSystem.getRect(),s={};return t=t||[0,0],"horizontal"===o.orient?(s.pixel=e[0]-t[0],s.pixelLength=a.width,s.pixelStart=a.x,s.signal=o.inverse?1:-1):(s.pixel=e[1]-t[1],s.pixelLength=a.height,s.pixelStart=a.y,s.signal=o.inverse?-1:1),s}};function _F(t){yz(t),t.registerComponentModel(uF),t.registerComponentView(yF),gF(t)}var bF=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="dataZoom.slider",e.layoutMode="box",e.defaultOption=kc(az.defaultOption,{show:!0,right:"ph",top:"ph",width:"ph",height:"ph",left:null,bottom:null,borderColor:"#d2dbee",borderRadius:3,backgroundColor:"rgba(47,69,84,0)",dataBackground:{lineStyle:{color:"#d2dbee",width:.5},areaStyle:{color:"#d2dbee",opacity:.2}},selectedDataBackground:{lineStyle:{color:"#8fb0f7",width:.5},areaStyle:{color:"#8fb0f7",opacity:.2}},fillerColor:"rgba(135,175,274,0.2)",handleIcon:"path://M-9.35,34.56V42m0-40V9.5m-2,0h4a2,2,0,0,1,2,2v21a2,2,0,0,1-2,2h-4a2,2,0,0,1-2-2v-21A2,2,0,0,1-11.35,9.5Z",handleSize:"100%",handleStyle:{color:"#fff",borderColor:"#ACB8D1"},moveHandleSize:7,moveHandleIcon:"path://M-320.9-50L-320.9-50c18.1,0,27.1,9,27.1,27.1V85.7c0,18.1-9,27.1-27.1,27.1l0,0c-18.1,0-27.1-9-27.1-27.1V-22.9C-348-41-339-50-320.9-50z M-212.3-50L-212.3-50c18.1,0,27.1,9,27.1,27.1V85.7c0,18.1-9,27.1-27.1,27.1l0,0c-18.1,0-27.1-9-27.1-27.1V-22.9C-239.4-41-230.4-50-212.3-50z M-103.7-50L-103.7-50c18.1,0,27.1,9,27.1,27.1V85.7c0,18.1-9,27.1-27.1,27.1l0,0c-18.1,0-27.1-9-27.1-27.1V-22.9C-130.9-41-121.8-50-103.7-50z",moveHandleStyle:{color:"#D2DBEE",opacity:.7},showDetail:!0,showDataShadow:"auto",realtime:!0,zoomLock:!1,textStyle:{color:"#6E7079"},brushSelect:!0,brushStyle:{color:"rgba(135,175,274,0.15)"},emphasis:{handleStyle:{borderColor:"#8FB0F7"},moveHandleStyle:{color:"#8FB0F7"}}}),e}(az),wF=Ws,SF="horizontal",MF="vertical",IF=["line","bar","candlestick","scatter"],TF={easing:"cubicOut",duration:100,delay:0},CF=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n._displayables={},n}return n(e,t),e.prototype.init=function(t,e){this.api=e,this._onBrush=W(this._onBrush,this),this._onBrushEnd=W(this._onBrushEnd,this)},e.prototype.render=function(e,n,i,r){if(t.prototype.render.apply(this,arguments),Hg(this,"_dispatchZoomAction",e.get("throttle"),"fixRate"),this._orient=e.getOrient(),!1!==e.get("show")){if(e.noTarget())return this._clear(),void this.group.removeAll();r&&"dataZoom"===r.type&&r.from===this.uid||this._buildView(),this._updateView()}else this.group.removeAll()},e.prototype.dispose=function(){this._clear(),t.prototype.dispose.apply(this,arguments)},e.prototype._clear=function(){Yg(this,"_dispatchZoomAction");var t=this.api.getZr();t.off("mousemove",this._onBrush),t.off("mouseup",this._onBrushEnd)},e.prototype._buildView=function(){var t=this.group;t.removeAll(),this._brushing=!1,this._displayables.brushRect=null,this._resetLocation(),this._resetInterval();var e=this._displayables.sliderGroup=new Br;this._renderBackground(),this._renderHandle(),this._renderDataShadow(),t.add(e),this._positionGroup()},e.prototype._resetLocation=function(){var t=this.dataZoomModel,e=this.api,n=t.get("brushSelect")?7:0,i=this._findCoordRect(),r={width:e.getWidth(),height:e.getHeight()},o=this._orient===SF?{right:r.width-i.x-i.width,top:r.height-30-7-n,width:i.width,height:30}:{right:7,top:i.y,width:30,height:i.height},a=Rp(t.option);E(["right","top","width","height"],(function(t){"ph"===a[t]&&(a[t]=o[t])}));var s=kp(a,r);this._location={x:s.x,y:s.y},this._size=[s.width,s.height],this._orient===MF&&this._size.reverse()},e.prototype._positionGroup=function(){var t=this.group,e=this._location,n=this._orient,i=this.dataZoomModel.getFirstTargetAxisModel(),r=i&&i.get("inverse"),o=this._displayables.sliderGroup,a=(this._dataShadowInfo||{}).otherAxisInverse;o.attr(n!==SF||r?n===SF&&r?{scaleY:a?1:-1,scaleX:-1}:n!==MF||r?{scaleY:a?-1:1,scaleX:-1,rotation:Math.PI/2}:{scaleY:a?-1:1,scaleX:1,rotation:Math.PI/2}:{scaleY:a?1:-1,scaleX:1});var s=t.getBoundingRect([o]);t.x=e.x-s.x,t.y=e.y-s.y,t.markRedraw()},e.prototype._getViewExtent=function(){return[0,this._size[0]]},e.prototype._renderBackground=function(){var t=this.dataZoomModel,e=this._size,n=this._displayables.sliderGroup,i=t.get("brushSelect");n.add(new wF({silent:!0,shape:{x:0,y:0,width:e[0],height:e[1]},style:{fill:t.get("backgroundColor")},z2:-40}));var r=new wF({shape:{x:0,y:0,width:e[0],height:e[1]},style:{fill:"transparent"},z2:0,onclick:W(this._onClickPanel,this)}),o=this.api.getZr();i?(r.on("mousedown",this._onBrushStart,this),r.cursor="crosshair",o.on("mousemove",this._onBrush),o.on("mouseup",this._onBrushEnd)):(o.off("mousemove",this._onBrush),o.off("mouseup",this._onBrushEnd)),n.add(r)},e.prototype._renderDataShadow=function(){var t=this._dataShadowInfo=this._prepareDataShadowInfo();if(this._displayables.dataShadowSegs=[],t){var e=this._size,n=this._shadowSize||[],i=t.series,r=i.getRawData(),o=i.getShadowDim&&i.getShadowDim(),a=o&&r.getDimensionInfo(o)?i.getShadowDim():t.otherDim;if(null!=a){var s=this._shadowPolygonPts,l=this._shadowPolylinePts;if(r!==this._shadowData||a!==this._shadowDim||e[0]!==n[0]||e[1]!==n[1]){var u=r.getDataExtent(a),h=.3*(u[1]-u[0]);u=[u[0]-h,u[1]+h];var c,p=[0,e[1]],d=[0,e[0]],f=[[e[0],0],[0,0]],g=[],y=d[1]/(r.count()-1),v=0,m=Math.round(r.count()/e[0]);r.each([a],(function(t,e){if(m>0&&e%m)v+=y;else{var n=null==t||isNaN(t)||""===t,i=n?0:Kr(t,u,p,!0);n&&!c&&e?(f.push([f[f.length-1][0],0]),g.push([g[g.length-1][0],0])):!n&&c&&(f.push([v,0]),g.push([v,0])),f.push([v,i]),g.push([v,i]),v+=y,c=n}})),s=this._shadowPolygonPts=f,l=this._shadowPolylinePts=g}this._shadowData=r,this._shadowDim=a,this._shadowSize=[e[0],e[1]];for(var x=this.dataZoomModel,_=0;_<3;_++){var b=w(1===_);this._displayables.sliderGroup.add(b),this._displayables.dataShadowSegs.push(b)}}}function w(t){var e=x.getModel(t?"selectedDataBackground":"dataBackground"),n=new Br,i=new Xu({shape:{points:s},segmentIgnoreThreshold:1,style:e.getModel("areaStyle").getAreaStyle(),silent:!0,z2:-20}),r=new Zu({shape:{points:l},segmentIgnoreThreshold:1,style:e.getModel("lineStyle").getLineStyle(),silent:!0,z2:-19});return n.add(i),n.add(r),n}},e.prototype._prepareDataShadowInfo=function(){var t=this.dataZoomModel,e=t.get("showDataShadow");if(!1!==e){var n,i=this.ecModel;return t.eachTargetAxis((function(r,o){E(t.getAxisProxy(r,o).getTargetSeriesModels(),(function(t){if(!(n||!0!==e&&P(IF,t.get("type"))<0)){var a,s=i.getComponent(nz(r),o).axis,l=function(t){var e={x:"y",y:"x",radius:"angle",angle:"radius"};return e[t]}(r),u=t.coordinateSystem;null!=l&&u.getOtherAxis&&(a=u.getOtherAxis(s).inverse),l=t.getData().mapDimension(l),n={thisAxis:s,series:t,thisDim:r,otherDim:l,otherAxisInverse:a}}}),this)}),this),n}},e.prototype._renderHandle=function(){var t=this.group,e=this._displayables,n=e.handles=[null,null],i=e.handleLabels=[null,null],r=this._displayables.sliderGroup,o=this._size,a=this.dataZoomModel,s=this.api,l=a.get("borderRadius")||0,u=a.get("brushSelect"),h=e.filler=new wF({silent:u,style:{fill:a.get("fillerColor")},textConfig:{position:"inside"}});r.add(h),r.add(new wF({silent:!0,subPixelOptimize:!0,shape:{x:0,y:0,width:o[0],height:o[1],r:l},style:{stroke:a.get("dataBackgroundColor")||a.get("borderColor"),lineWidth:1,fill:"rgba(0,0,0,0)"}})),E([0,1],(function(e){var o=a.get("handleIcon");!Wy[o]&&o.indexOf("path://")<0&&o.indexOf("image://")<0&&(o="path://"+o);var s=Xy(o,-1,0,2,2,null,!0);s.attr({cursor:DF(this._orient),draggable:!0,drift:W(this._onDragMove,this,e),ondragend:W(this._onDragEnd,this),onmouseover:W(this._showDataInfo,this,!0),onmouseout:W(this._showDataInfo,this,!1),z2:5});var l=s.getBoundingRect(),u=a.get("handleSize");this._handleHeight=$r(u,this._size[1]),this._handleWidth=l.width/l.height*this._handleHeight,s.setStyle(a.getModel("handleStyle").getItemStyle()),s.style.strokeNoScale=!0,s.rectHover=!0,s.ensureState("emphasis").style=a.getModel(["emphasis","handleStyle"]).getItemStyle(),Ul(s);var h=a.get("handleColor");null!=h&&(s.style.fill=h),r.add(n[e]=s);var c=a.getModel("textStyle");t.add(i[e]=new Xs({silent:!0,invisible:!0,style:oc(c,{x:0,y:0,text:"",verticalAlign:"middle",align:"center",fill:c.getTextColor(),font:c.getFont()}),z2:10}))}),this);var c=h;if(u){var p=$r(a.get("moveHandleSize"),o[1]),d=e.moveHandle=new Ws({style:a.getModel("moveHandleStyle").getItemStyle(),silent:!0,shape:{r:[0,0,2,2],y:o[1]-.5,height:p}}),f=.8*p,g=e.moveHandleIcon=Xy(a.get("moveHandleIcon"),-f/2,-f/2,f,f,"#fff",!0);g.silent=!0,g.y=o[1]+p/2-.5,d.ensureState("emphasis").style=a.getModel(["emphasis","moveHandleStyle"]).getItemStyle();var y=Math.min(o[1]/2,Math.max(p,10));(c=e.moveZone=new Ws({invisible:!0,shape:{y:o[1]-y,height:p+y}})).on("mouseover",(function(){s.enterEmphasis(d)})).on("mouseout",(function(){s.leaveEmphasis(d)})),r.add(d),r.add(g),r.add(c)}c.attr({draggable:!0,cursor:DF(this._orient),drift:W(this._onDragMove,this,"all"),ondragstart:W(this._showDataInfo,this,!0),ondragend:W(this._onDragEnd,this),onmouseover:W(this._showDataInfo,this,!0),onmouseout:W(this._showDataInfo,this,!1)})},e.prototype._resetInterval=function(){var t=this._range=this.dataZoomModel.getPercentRange(),e=this._getViewExtent();this._handleEnds=[Kr(t[0],[0,100],e,!0),Kr(t[1],[0,100],e,!0)]},e.prototype._updateInterval=function(t,e){var n=this.dataZoomModel,i=this._handleEnds,r=this._getViewExtent(),o=n.findRepresentativeAxisProxy().getMinMaxSpan(),a=[0,100];zk(e,i,r,n.get("zoomLock")?"all":t,null!=o.minSpan?Kr(o.minSpan,a,r,!0):null,null!=o.maxSpan?Kr(o.maxSpan,a,r,!0):null);var s=this._range,l=this._range=Qr([Kr(i[0],r,a,!0),Kr(i[1],r,a,!0)]);return!s||s[0]!==l[0]||s[1]!==l[1]},e.prototype._updateView=function(t){var e=this._displayables,n=this._handleEnds,i=Qr(n.slice()),r=this._size;E([0,1],(function(t){var i=e.handles[t],o=this._handleHeight;i.attr({scaleX:o/2,scaleY:o/2,x:n[t]+(t?-1:1),y:r[1]/2-o/2})}),this),e.filler.setShape({x:i[0],y:0,width:i[1]-i[0],height:r[1]});var o={x:i[0],width:i[1]-i[0]};e.moveHandle&&(e.moveHandle.setShape(o),e.moveZone.setShape(o),e.moveZone.getBoundingRect(),e.moveHandleIcon&&e.moveHandleIcon.attr("x",o.x+o.width/2));for(var a=e.dataShadowSegs,s=[0,i[0],i[1],r[0]],l=0;le[0]||n[1]<0||n[1]>e[1])){var i=this._handleEnds,r=(i[0]+i[1])/2,o=this._updateInterval("all",n[0]-r);this._updateView(),o&&this._dispatchZoomAction(!1)}},e.prototype._onBrushStart=function(t){var e=t.offsetX,n=t.offsetY;this._brushStart=new De(e,n),this._brushing=!0,this._brushStartTime=+new Date},e.prototype._onBrushEnd=function(t){if(this._brushing){var e=this._displayables.brushRect;if(this._brushing=!1,e){e.attr("ignore",!0);var n=e.shape;if(!(+new Date-this._brushStartTime<200&&Math.abs(n.width)<5)){var i=this._getViewExtent(),r=[0,100];this._range=Qr([Kr(n.x,i,r,!0),Kr(n.x+n.width,i,r,!0)]),this._handleEnds=[n.x,n.x+n.width],this._updateView(),this._dispatchZoomAction(!1)}}}},e.prototype._onBrush=function(t){this._brushing&&(de(t.event),this._updateBrushRect(t.offsetX,t.offsetY))},e.prototype._updateBrushRect=function(t,e){var n=this._displayables,i=this.dataZoomModel,r=n.brushRect;r||(r=n.brushRect=new wF({silent:!0,style:i.getModel("brushStyle").getItemStyle()}),n.sliderGroup.add(r)),r.attr("ignore",!1);var o=this._brushStart,a=this._displayables.sliderGroup,s=a.transformCoordToLocal(t,e),l=a.transformCoordToLocal(o.x,o.y),u=this._size;s[0]=Math.max(Math.min(u[0],s[0]),0),r.setShape({x:l[0],y:0,width:s[0]-l[0],height:u[1]})},e.prototype._dispatchZoomAction=function(t){var e=this._range;this.api.dispatchAction({type:"dataZoom",from:this.uid,dataZoomId:this.dataZoomModel.id,animation:t?TF:null,start:e[0],end:e[1]})},e.prototype._findCoordRect=function(){var t,e=rz(this.dataZoomModel).infoList;if(!t&&e.length){var n=e[0].model.coordinateSystem;t=n.getRect&&n.getRect()}if(!t){var i=this.api.getWidth(),r=this.api.getHeight();t={x:.2*i,y:.2*r,width:.6*i,height:.6*r}}return t},e.type="dataZoom.slider",e}(uz);function DF(t){return"vertical"===t?"ns-resize":"ew-resize"}function AF(t){t.registerComponentModel(bF),t.registerComponentView(CF),yz(t)}var kF=function(t,e,n){var i=T((LF[t]||{})[e]);return n&&Y(i)?i[i.length-1]:i},LF={color:{active:["#006edd","#e0ffff"],inactive:["rgba(0,0,0,0)"]},colorHue:{active:[0,360],inactive:[0,0]},colorSaturation:{active:[.3,1],inactive:[0,0]},colorLightness:{active:[.9,.5],inactive:[0,0]},colorAlpha:{active:[.3,1],inactive:[0,0]},opacity:{active:[.3,1],inactive:[0,0]},symbol:{active:["circle","roundRect","diamond"],inactive:["none"]},symbolSize:{active:[10,50],inactive:[0,0]}},PF=kD.mapVisual,OF=kD.eachVisual,RF=Y,NF=E,EF=Qr,zF=Kr,VF=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.stateList=["inRange","outOfRange"],n.replacableOptionKeys=["inRange","outOfRange","target","controller","color"],n.layoutMode={type:"box",ignoreSize:!0},n.dataBound=[-1/0,1/0],n.targetVisuals={},n.controllerVisuals={},n}return n(e,t),e.prototype.init=function(t,e,n){this.mergeDefaultAndTheme(t,n)},e.prototype.optionUpdated=function(t,e){var n=this.option;!e&&PV(n,t,this.replacableOptionKeys),this.textStyleModel=this.getModel("textStyle"),this.resetItemSize(),this.completeVisualOption()},e.prototype.resetVisual=function(t){var e=this.stateList;t=W(t,this),this.controllerVisuals=LV(this.option.controller,e,t),this.targetVisuals=LV(this.option.target,e,t)},e.prototype.getItemSymbol=function(){return null},e.prototype.getTargetSeriesIndices=function(){var t=this.option.seriesIndex,e=[];return null==t||"all"===t?this.ecModel.eachSeries((function(t,n){e.push(n)})):e=To(t),e},e.prototype.eachTargetSeries=function(t,e){E(this.getTargetSeriesIndices(),(function(n){var i=this.ecModel.getSeriesByIndex(n);i&&t.call(e,i)}),this)},e.prototype.isTargetSeries=function(t){var e=!1;return this.eachTargetSeries((function(n){n===t&&(e=!0)})),e},e.prototype.formatValueText=function(t,e,n){var i,r=this.option,o=r.precision,a=this.dataBound,s=r.formatter;n=n||["<",">"],Y(t)&&(t=t.slice(),i=!0);var l=e?t:i?[u(t[0]),u(t[1])]:u(t);return U(s)?s.replace("{value}",i?l[0]:l).replace("{value2}",i?l[1]:l):X(s)?i?s(t[0],t[1]):s(t):i?t[0]===a[0]?n[0]+" "+l[1]:t[1]===a[1]?n[1]+" "+l[0]:l[0]+" - "+l[1]:l;function u(t){return t===a[0]?"min":t===a[1]?"max":(+t).toFixed(Math.min(o,20))}},e.prototype.resetExtent=function(){var t=this.option,e=EF([t.min,t.max]);this._dataExtent=e},e.prototype.getDataDimensionIndex=function(t){var e=this.option.dimension;if(null!=e)return t.getDimensionIndex(e);for(var n=t.dimensions,i=n.length-1;i>=0;i--){var r=n[i],o=t.getDimensionInfo(r);if(!o.isCalculationCoord)return o.storeDimIndex}},e.prototype.getExtent=function(){return this._dataExtent.slice()},e.prototype.completeVisualOption=function(){var t=this.ecModel,e=this.option,n={inRange:e.inRange,outOfRange:e.outOfRange},i=e.target||(e.target={}),r=e.controller||(e.controller={});C(i,n),C(r,n);var o=this.isCategory();function a(n){RF(e.color)&&!n.inRange&&(n.inRange={color:e.color.slice().reverse()}),n.inRange=n.inRange||{color:t.get("gradientColor")}}a.call(this,i),a.call(this,r),function(t,e,n){var i=t[e],r=t[n];i&&!r&&(r=t[n]={},NF(i,(function(t,e){if(kD.isValidType(e)){var n=kF(e,"inactive",o);null!=n&&(r[e]=n,"color"!==e||r.hasOwnProperty("opacity")||r.hasOwnProperty("colorAlpha")||(r.opacity=[0,0]))}})))}.call(this,i,"inRange","outOfRange"),function(t){var e=(t.inRange||{}).symbol||(t.outOfRange||{}).symbol,n=(t.inRange||{}).symbolSize||(t.outOfRange||{}).symbolSize,i=this.get("inactiveColor"),r=this.getItemSymbol()||"roundRect";NF(this.stateList,(function(a){var s=this.itemSize,l=t[a];l||(l=t[a]={color:o?i:[i]}),null==l.symbol&&(l.symbol=e&&T(e)||(o?r:[r])),null==l.symbolSize&&(l.symbolSize=n&&T(n)||(o?s[0]:[s[0],s[0]])),l.symbol=PF(l.symbol,(function(t){return"none"===t?r:t}));var u=l.symbolSize;if(null!=u){var h=-1/0;OF(u,(function(t){t>h&&(h=t)})),l.symbolSize=PF(u,(function(t){return zF(t,[0,h],[0,s[0]],!0)}))}}),this)}.call(this,r)},e.prototype.resetItemSize=function(){this.itemSize=[parseFloat(this.get("itemWidth")),parseFloat(this.get("itemHeight"))]},e.prototype.isCategory=function(){return!!this.option.categories},e.prototype.setSelected=function(t){},e.prototype.getSelected=function(){return null},e.prototype.getValueState=function(t){return null},e.prototype.getVisualMeta=function(t){return null},e.type="visualMap",e.dependencies=["series"],e.defaultOption={show:!0,z:4,seriesIndex:"all",min:0,max:200,left:0,right:null,top:null,bottom:0,itemWidth:null,itemHeight:null,inverse:!1,orient:"vertical",backgroundColor:"rgba(0,0,0,0)",borderColor:"#ccc",contentColor:"#5793f3",inactiveColor:"#aaa",borderWidth:0,padding:5,textGap:10,precision:0,textStyle:{color:"#333"}},e}(zp),BF=[20,140],FF=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.optionUpdated=function(e,n){t.prototype.optionUpdated.apply(this,arguments),this.resetExtent(),this.resetVisual((function(t){t.mappingMethod="linear",t.dataExtent=this.getExtent()})),this._resetRange()},e.prototype.resetItemSize=function(){t.prototype.resetItemSize.apply(this,arguments);var e=this.itemSize;(null==e[0]||isNaN(e[0]))&&(e[0]=BF[0]),(null==e[1]||isNaN(e[1]))&&(e[1]=BF[1])},e.prototype._resetRange=function(){var t=this.getExtent(),e=this.option.range;!e||e.auto?(t.auto=1,this.option.range=t):Y(e)&&(e[0]>e[1]&&e.reverse(),e[0]=Math.max(e[0],t[0]),e[1]=Math.min(e[1],t[1]))},e.prototype.completeVisualOption=function(){t.prototype.completeVisualOption.apply(this,arguments),E(this.stateList,(function(t){var e=this.option.controller[t].symbolSize;e&&e[0]!==e[1]&&(e[0]=e[1]/3)}),this)},e.prototype.setSelected=function(t){this.option.range=t.slice(),this._resetRange()},e.prototype.getSelected=function(){var t=this.getExtent(),e=Qr((this.get("range")||[]).slice());return e[0]>t[1]&&(e[0]=t[1]),e[1]>t[1]&&(e[1]=t[1]),e[0]=n[1]||t<=e[1])?"inRange":"outOfRange"},e.prototype.findTargetDataIndices=function(t){var e=[];return this.eachTargetSeries((function(n){var i=[],r=n.getData();r.each(this.getDataDimensionIndex(r),(function(e,n){t[0]<=e&&e<=t[1]&&i.push(n)}),this),e.push({seriesId:n.id,dataIndex:i})}),this),e},e.prototype.getVisualMeta=function(t){var e=GF(this,"outOfRange",this.getExtent()),n=GF(this,"inRange",this.option.range.slice()),i=[];function r(e,n){i.push({value:e,color:t(e,n)})}for(var o=0,a=0,s=n.length,l=e.length;at[1])break;n.push({color:this.getControllerVisual(o,"color",e),offset:r/100})}return n.push({color:this.getControllerVisual(t[1],"color",e),offset:1}),n},e.prototype._createBarPoints=function(t,e){var n=this.visualMapModel.itemSize;return[[n[0]-e[0],t[0]],[n[0],t[0]],[n[0],t[1]],[n[0]-e[1],t[1]]]},e.prototype._createBarGroup=function(t){var e=this._orient,n=this.visualMapModel.get("inverse");return new Br("horizontal"!==e||n?"horizontal"===e&&n?{scaleX:"bottom"===t?-1:1,rotation:-Math.PI/2}:"vertical"!==e||n?{scaleX:"left"===t?1:-1}:{scaleX:"left"===t?1:-1,scaleY:-1}:{scaleX:"bottom"===t?1:-1,rotation:Math.PI/2})},e.prototype._updateHandle=function(t,e){if(this._useHandle){var n=this._shapes,i=this.visualMapModel,r=n.handleThumbs,o=n.handleLabels,a=i.itemSize,s=i.getExtent();ZF([0,1],(function(l){var u=r[l];u.setStyle("fill",e.handlesColor[l]),u.y=t[l];var h=UF(t[l],[0,a[1]],s,!0),c=this.getControllerVisual(h,"symbolSize");u.scaleX=u.scaleY=c/a[0],u.x=a[0]-c/2;var p=Fh(n.handleLabelPoints[l],Bh(u,this.group));o[l].setStyle({x:p[0],y:p[1],text:i.formatValueText(this._dataInterval[l]),verticalAlign:"middle",align:"vertical"===this._orient?this._applyTransform("left",n.mainGroup):"center"})}),this)}},e.prototype._showIndicator=function(t,e,n,i){var r=this.visualMapModel,o=r.getExtent(),a=r.itemSize,s=[0,a[1]],l=this._shapes,u=l.indicator;if(u){u.attr("invisible",!1);var h=this.getControllerVisual(t,"color",{convertOpacityToAlpha:!0}),c=this.getControllerVisual(t,"symbolSize"),p=UF(t,o,s,!0),d=a[0]-c/2,f={x:u.x,y:u.y};u.y=p,u.x=d;var g=Fh(l.indicatorLabelPoint,Bh(u,this.group)),y=l.indicatorLabel;y.attr("invisible",!1);var v=this._applyTransform("left",l.mainGroup),m="horizontal"===this._orient;y.setStyle({text:(n||"")+r.formatValueText(e),verticalAlign:m?v:"middle",align:m?"center":v});var x={x:d,y:p,style:{fill:h}},_={style:{x:g[0],y:g[1]}};if(r.ecModel.isAnimationEnabled()&&!this._firstShowIndicator){var b={duration:100,easing:"cubicInOut",additive:!0};u.x=f.x,u.y=f.y,u.animateTo(x,b),y.animateTo(_,b)}else u.attr(x),y.attr(_);this._firstShowIndicator=!1;var w=this._shapes.handleLabels;if(w)for(var S=0;Sr[1]&&(u[1]=1/0),e&&(u[0]===-1/0?this._showIndicator(l,u[1],"< ",a):u[1]===1/0?this._showIndicator(l,u[0],"> ",a):this._showIndicator(l,l,"≈ ",a));var h=this._hoverLinkDataIndices,c=[];(e||JF(n))&&(c=this._hoverLinkDataIndices=n.findTargetDataIndices(u));var p=function(t,e){var n={},i={};return r(t||[],n),r(e||[],i,n),[o(n),o(i)];function r(t,e,n){for(var i=0,r=t.length;i=0&&(r.dimension=o,i.push(r))}})),t.getData().setVisual("visualMeta",i)}}];function iG(t,e,n,i){for(var r=e.targetVisuals[i],o=kD.prepareVisualTypes(r),a={color:Ay(t.getData(),"color")},s=0,l=o.length;s0:t.splitNumber>0)&&!t.calculable?"piecewise":"continuous"})),t.registerAction(tG,eG),E(nG,(function(e){t.registerVisual(t.PRIORITY.VISUAL.COMPONENT,e)})),t.registerPreprocessor(oG))}function uG(t){t.registerComponentModel(FF),t.registerComponentView(KF),lG(t)}var hG=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n._pieceList=[],n}return n(e,t),e.prototype.optionUpdated=function(e,n){t.prototype.optionUpdated.apply(this,arguments),this.resetExtent();var i=this._mode=this._determineMode();this._pieceList=[],cG[this._mode].call(this,this._pieceList),this._resetSelected(e,n);var r=this.option.categories;this.resetVisual((function(t,e){"categories"===i?(t.mappingMethod="category",t.categories=T(r)):(t.dataExtent=this.getExtent(),t.mappingMethod="piecewise",t.pieceList=z(this._pieceList,(function(t){return t=T(t),"inRange"!==e&&(t.visual=null),t})))}))},e.prototype.completeVisualOption=function(){var e=this.option,n={},i=kD.listVisualTypes(),r=this.isCategory();function o(t,e,n){return t&&t[e]&&t[e].hasOwnProperty(n)}E(e.pieces,(function(t){E(i,(function(e){t.hasOwnProperty(e)&&(n[e]=1)}))})),E(n,(function(t,n){var i=!1;E(this.stateList,(function(t){i=i||o(e,t,n)||o(e.target,t,n)}),this),!i&&E(this.stateList,(function(t){(e[t]||(e[t]={}))[n]=kF(n,"inRange"===t?"active":"inactive",r)}))}),this),t.prototype.completeVisualOption.apply(this,arguments)},e.prototype._resetSelected=function(t,e){var n=this.option,i=this._pieceList,r=(e?n:t).selected||{};if(n.selected=r,E(i,(function(t,e){var n=this.getSelectedMapKey(t);r.hasOwnProperty(n)||(r[n]=!0)}),this),"single"===n.selectedMode){var o=!1;E(i,(function(t,e){var n=this.getSelectedMapKey(t);r[n]&&(o?r[n]=!1:o=!0)}),this)}},e.prototype.getItemSymbol=function(){return this.get("itemSymbol")},e.prototype.getSelectedMapKey=function(t){return"categories"===this._mode?t.value+"":t.index+""},e.prototype.getPieceList=function(){return this._pieceList},e.prototype._determineMode=function(){var t=this.option;return t.pieces&&t.pieces.length>0?"pieces":this.option.categories?"categories":"splitNumber"},e.prototype.setSelected=function(t){this.option.selected=T(t)},e.prototype.getValueState=function(t){var e=kD.findPieceIndex(t,this._pieceList);return null!=e&&this.option.selected[this.getSelectedMapKey(this._pieceList[e])]?"inRange":"outOfRange"},e.prototype.findTargetDataIndices=function(t){var e=[],n=this._pieceList;return this.eachTargetSeries((function(i){var r=[],o=i.getData();o.each(this.getDataDimensionIndex(o),(function(e,i){kD.findPieceIndex(e,n)===t&&r.push(i)}),this),e.push({seriesId:i.id,dataIndex:r})}),this),e},e.prototype.getRepresentValue=function(t){var e;if(this.isCategory())e=t.value;else if(null!=t.value)e=t.value;else{var n=t.interval||[];e=n[0]===-1/0&&n[1]===1/0?0:(n[0]+n[1])/2}return e},e.prototype.getVisualMeta=function(t){if(!this.isCategory()){var e=[],n=["",""],i=this,r=this._pieceList.slice();if(r.length){var o=r[0].interval[0];o!==-1/0&&r.unshift({interval:[-1/0,o]}),(o=r[r.length-1].interval[1])!==1/0&&r.push({interval:[o,1/0]})}else r.push({interval:[-1/0,1/0]});var a=-1/0;return E(r,(function(t){var e=t.interval;e&&(e[0]>a&&s([a,e[0]],"outOfRange"),s(e.slice()),a=e[1])}),this),{stops:e,outerColors:n}}function s(r,o){var a=i.getRepresentValue({interval:r});o||(o=i.getValueState(a));var s=t(a,o);r[0]===-1/0?n[0]=s:r[1]===1/0?n[1]=s:e.push({value:r[0],color:s},{value:r[1],color:s})}},e.type="visualMap.piecewise",e.defaultOption=kc(VF.defaultOption,{selected:null,minOpen:!1,maxOpen:!1,align:"auto",itemWidth:20,itemHeight:14,itemSymbol:"roundRect",pieces:null,categories:null,splitNumber:5,selectedMode:"multiple",itemGap:10,hoverLink:!0}),e}(VF),cG={splitNumber:function(t){var e=this.option,n=Math.min(e.precision,20),i=this.getExtent(),r=e.splitNumber;r=Math.max(parseInt(r,10),1),e.splitNumber=r;for(var o=(i[1]-i[0])/r;+o.toFixed(n)!==o&&n<5;)n++;e.precision=n,o=+o.toFixed(n),e.minOpen&&t.push({interval:[-1/0,i[0]],close:[0,0]});for(var a=0,s=i[0];a","≥"][e[0]]];t.text=t.text||this.formatValueText(null!=t.value?t.value:t.interval,!1,n)}),this)}};function pG(t,e){var n=t.inverse;("vertical"===t.orient?!n:n)&&e.reverse()}var dG=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.doRender=function(){var t=this.group;t.removeAll();var e=this.visualMapModel,n=e.get("textGap"),i=e.textStyleModel,r=i.getFont(),o=i.getTextColor(),a=this._getItemAlign(),s=e.itemSize,l=this._getViewData(),u=l.endsText,h=it(e.get("showLabel",!0),!u);u&&this._renderEndsText(t,u[0],s,h,a),E(l.viewPieceList,(function(i){var l=i.piece,u=new Br;u.onclick=W(this._onItemClick,this,l),this._enableHoverLink(u,i.indexInModelPieceList);var c=e.getRepresentValue(l);if(this._createItemSymbol(u,c,[0,0,s[0],s[1]]),h){var p=this.visualMapModel.getValueState(c);u.add(new Xs({style:{x:"right"===a?-n:s[0]+n,y:s[1]/2,text:l.text,verticalAlign:"middle",align:a,font:r,fill:o,opacity:"outOfRange"===p?.5:1}}))}t.add(u)}),this),u&&this._renderEndsText(t,u[1],s,h,a),Ap(e.get("orient"),t,e.get("itemGap")),this.renderBackground(t),this.positionGroup(t)},e.prototype._enableHoverLink=function(t,e){var n=this;t.on("mouseover",(function(){return i("highlight")})).on("mouseout",(function(){return i("downplay")}));var i=function(t){var i=n.visualMapModel;i.option.hoverLink&&n.api.dispatchAction({type:t,batch:XF(i.findTargetDataIndices(e),i)})}},e.prototype._getItemAlign=function(){var t=this.visualMapModel,e=t.option;if("vertical"===e.orient)return YF(t,this.api,t.itemSize);var n=e.align;return n&&"auto"!==n||(n="left"),n},e.prototype._renderEndsText=function(t,e,n,i,r){if(e){var o=new Br,a=this.visualMapModel.textStyleModel;o.add(new Xs({style:oc(a,{x:i?"right"===r?n[0]:0:n[0]/2,y:n[1]/2,verticalAlign:"middle",align:i?r:"center",text:e})})),t.add(o)}},e.prototype._getViewData=function(){var t=this.visualMapModel,e=z(t.getPieceList(),(function(t,e){return{piece:t,indexInModelPieceList:e}})),n=t.get("text"),i=t.get("orient"),r=t.get("inverse");return("horizontal"===i?r:!r)?e.reverse():n&&(n=n.slice().reverse()),{viewPieceList:e,endsText:n}},e.prototype._createItemSymbol=function(t,e,n){t.add(Xy(this.getControllerVisual(e,"symbol"),n[0],n[1],n[2],n[3],this.getControllerVisual(e,"color")))},e.prototype._onItemClick=function(t){var e=this.visualMapModel,n=e.option,i=n.selectedMode;if(i){var r=T(n.selected),o=e.getSelectedMapKey(t);"single"===i||!0===i?(r[o]=!0,E(r,(function(t,e){r[e]=e===o}))):r[o]=!r[o],this.api.dispatchAction({type:"selectDataRange",from:this.uid,visualMapId:this.visualMapModel.id,selected:r})}},e.type="visualMap.piecewise",e}(WF);function fG(t){t.registerComponentModel(hG),t.registerComponentView(dG),lG(t)}var gG={label:{enabled:!0},decal:{show:!1}},yG=Vo(),vG={};function mG(t,e){var n=t.getModel("aria");if(n.get("enabled")){var i=T(gG);C(i.label,t.getLocaleModel().get("aria"),!1),C(n.option,i,!1),function(){if(n.getModel("decal").get("show")){var e=yt();t.eachSeries((function(t){if(!t.isColorBySeries()){var n=e.get(t.type);n||(n={},e.set(t.type,n)),yG(t).scope=n}})),t.eachRawSeries((function(e){if(!t.isSeriesFiltered(e))if(X(e.enableAriaDecal))e.enableAriaDecal();else{var n=e.getData();if(e.isColorBySeries()){var i=pd(e.ecModel,e.name,vG,t.getSeriesCount()),r=n.getVisual("decal");n.setVisual("decal",u(r,i))}else{var o=e.getRawData(),a={},s=yG(e).scope;n.each((function(t){var e=n.getRawIndex(t);a[e]=t}));var l=o.count();o.each((function(t){var i=a[t],r=o.getName(t)||t+"",h=pd(e.ecModel,r,s,l),c=n.getItemVisual(i,"decal");n.setItemVisual(i,"decal",u(c,h))}))}}function u(t,e){var n=t?A(A({},e),t):e;return n.dirty=!0,n}}))}}(),function(){var i=e.getZr().dom;if(!i)return;var o=t.getLocaleModel().get("aria"),a=n.getModel("label");if(a.option=k(a.option,o),!a.get("enabled"))return;if(a.get("description"))return void i.setAttribute("aria-label",a.get("description"));var s,l=t.getSeriesCount(),u=a.get(["data","maxCount"])||10,h=a.get(["series","maxCount"])||10,c=Math.min(l,h);if(l<1)return;var p=function(){var e=t.get("title");e&&e.length&&(e=e[0]);return e&&e.text}();s=p?r(a.get(["general","withTitle"]),{title:p}):a.get(["general","withoutTitle"]);var d=[];s+=r(l>1?a.get(["series","multiple","prefix"]):a.get(["series","single","prefix"]),{seriesCount:l}),t.eachSeries((function(e,n){if(n1?a.get(["series","multiple",o]):a.get(["series","single",o]),{seriesId:e.seriesIndex,seriesName:e.get("name"),seriesType:(x=e.subType,_=t.getLocaleModel().get(["series","typeNames"]),_[x]||_.chart)});var s=e.getData();if(s.count()>u)i+=r(a.get(["data","partialData"]),{displayCnt:u});else i+=a.get(["data","allData"]);for(var h=a.get(["data","separator","middle"]),p=a.get(["data","separator","end"]),f=[],g=0;g":"gt",">=":"gte","=":"eq","!=":"ne","<>":"ne"},bG=function(){function t(t){if(null==(this._condVal=U(t)?new RegExp(t):et(t)?t:null)){var e="";0,wo(e)}}return t.prototype.evaluate=function(t){var e=typeof t;return U(e)?this._condVal.test(t):!!j(e)&&this._condVal.test(t+"")},t}(),wG=function(){function t(){}return t.prototype.evaluate=function(){return this.value},t}(),SG=function(){function t(){}return t.prototype.evaluate=function(){for(var t=this.children,e=0;e2&&l.push(e),e=[t,n]}function f(t,n,i,r){EG(t,i)&&EG(n,r)||e.push(t,n,i,r,i,r)}function g(t,n,i,r,o,a){var s=Math.abs(n-t),l=4*Math.tan(s/4)/3,u=nM:C2&&l.push(e),l}function VG(t,e,n,i,r,o,a,s,l,u){if(EG(t,n)&&EG(e,i)&&EG(r,a)&&EG(o,s))l.push(a,s);else{var h=2/u,c=h*h,p=a-t,d=s-e,f=Math.sqrt(p*p+d*d);p/=f,d/=f;var g=n-t,y=i-e,v=r-a,m=o-s,x=g*g+y*y,_=v*v+m*m;if(x=0&&_-w*w=0)l.push(a,s);else{var S=[],M=[];wn(t,n,r,a,.5,S),wn(e,i,o,s,.5,M),VG(S[0],M[0],S[1],M[1],S[2],M[2],S[3],M[3],l,u),VG(S[4],M[4],S[5],M[5],S[6],M[6],S[7],M[7],l,u)}}}}function BG(t,e,n){var i=t[e],r=t[1-e],o=Math.abs(i/r),a=Math.ceil(Math.sqrt(o*n)),s=Math.floor(n/a);0===s&&(s=1,a=n);for(var l=[],u=0;u0)for(u=0;uMath.abs(u),c=BG([l,u],h?0:1,e),p=(h?s:u)/c.length,d=0;d1?null:new De(d*l+t,d*u+e)}function HG(t,e,n){var i=new De;De.sub(i,n,e),i.normalize();var r=new De;return De.sub(r,t,e),r.dot(i)}function YG(t,e){var n=t[t.length-1];n&&n[0]===e[0]&&n[1]===e[1]||t.push(e)}function XG(t){var e=t.points,n=[],i=[];Ba(e,n,i);var r=new ze(n[0],n[1],i[0]-n[0],i[1]-n[1]),o=r.width,a=r.height,s=r.x,l=r.y,u=new De,h=new De;return o>a?(u.x=h.x=s+o/2,u.y=l,h.y=l+a):(u.y=h.y=l+a/2,u.x=s,h.x=s+o),function(t,e,n){for(var i=t.length,r=[],o=0;or,a=BG([i,r],o?0:1,e),s=o?"width":"height",l=o?"height":"width",u=o?"x":"y",h=o?"y":"x",c=t[s]/a.length,p=0;p0)for(var b=i/n,w=-i/2;w<=i/2;w+=b){var S=Math.sin(w),M=Math.cos(w),I=0;for(x=0;x0;l/=2){var u=0,h=0;(t&l)>0&&(u=1),(e&l)>0&&(h=1),s+=l*l*(3*u^h),0===h&&(1===u&&(t=l-1-t,e=l-1-e),a=t,t=e,e=a)}return s}function lW(t){var e=1/0,n=1/0,i=-1/0,r=-1/0,o=z(t,(function(t){var o=t.getBoundingRect(),a=t.getComputedTransform(),s=o.x+o.width/2+(a?a[4]:0),l=o.y+o.height/2+(a?a[5]:0);return e=Math.min(s,e),n=Math.min(l,n),i=Math.max(s,i),r=Math.max(l,r),[s,l]}));return z(o,(function(o,a){return{cp:o,z:sW(o[0],o[1],e,n,i,r),path:t[a]}})).sort((function(t,e){return t.z-e.z})).map((function(t){return t.path}))}function uW(t){return jG(t.path,t.count)}function hW(t){return Y(t[0])}function cW(t,e){for(var n=[],i=t.length,r=0;r=0;r--)if(!n[r].many.length){var l=n[s].many;if(l.length<=1){if(!s)return n;s=0}o=l.length;var u=Math.ceil(o/2);n[r].many=l.slice(u,o),n[s].many=l.slice(0,u),s++}return n}var pW={clone:function(t){for(var e=[],n=1-Math.pow(1-t.path.style.opacity,1/t.count),i=0;i0){var s,l,u=i.getModel("universalTransition").get("delay"),h=Object.assign({setToFinal:!0},a);hW(t)&&(s=t,l=e),hW(e)&&(s=e,l=t);for(var c=s?s===t:t.length>e.length,p=s?cW(l,s):cW(c?e:t,[c?t:e]),d=0,f=0;f1e4))for(var r=n.getIndices(),o=0;o0&&i.group.traverse((function(t){t instanceof ks&&!t.animators.length&&t.animateFrom({style:{opacity:0}},r)}))}))}function SW(t){var e=t.getModel("universalTransition").get("seriesKey");return e||t.id}function MW(t){return Y(t)?t.sort().join(","):t}function IW(t){if(t.hostModel)return t.hostModel.getModel("universalTransition").get("divideShape")}function TW(t,e){for(var n=0;n=0&&r.push({dataGroupId:e.oldDataGroupIds[n],data:e.oldData[n],divide:IW(e.oldData[n]),groupIdDim:t.dimension})})),E(To(t.to),(function(t){var i=TW(n.updatedSeries,t);if(i>=0){var r=n.updatedSeries[i].getData();o.push({dataGroupId:e.oldDataGroupIds[i],data:r,divide:IW(r),groupIdDim:t.dimension})}})),r.length>0&&o.length>0&&wW(r,o,i)}(t,i,n,e)}));else{var o=function(t,e){var n=yt(),i=yt(),r=yt();return E(t.oldSeries,(function(e,n){var o=t.oldDataGroupIds[n],a=t.oldData[n],s=SW(e),l=MW(s);i.set(l,{dataGroupId:o,data:a}),Y(s)&&E(s,(function(t){r.set(t,{key:l,dataGroupId:o,data:a})}))})),E(e.updatedSeries,(function(t){if(t.isUniversalTransitionEnabled()&&t.isAnimationEnabled()){var e=t.get("dataGroupId"),o=t.getData(),a=SW(t),s=MW(a),l=i.get(s);if(l)n.set(s,{oldSeries:[{dataGroupId:l.dataGroupId,divide:IW(l.data),data:l.data}],newSeries:[{dataGroupId:e,divide:IW(o),data:o}]});else if(Y(a)){var u=[];E(a,(function(t){var e=i.get(t);e.data&&u.push({dataGroupId:e.dataGroupId,divide:IW(e.data),data:e.data})})),u.length&&n.set(s,{oldSeries:u,newSeries:[{dataGroupId:e,data:o,divide:IW(o)}]})}else{var h=r.get(a);if(h){var c=n.get(h.key);c||(c={oldSeries:[{dataGroupId:h.dataGroupId,data:h.data,divide:IW(h.data)}],newSeries:[]},n.set(h.key,c)),c.newSeries.push({dataGroupId:e,data:o,divide:IW(o)})}}}})),n}(i,n);E(o.keys(),(function(t){var n=o.get(t);wW(n.oldSeries,n.newSeries,e)}))}E(n.updatedSeries,(function(t){t[_g]&&(t[_g]=!1)}))}for(var a=t.getSeries(),s=i.oldSeries=[],l=i.oldDataGroupIds=[],u=i.oldData=[],h=0;h + + + + + + +
    + __AVATAR__ +
    +
    __STEAM_NAME____PLUGIN_TAG__
    +
    共 __GAME_COUNT__ 款游戏 · 总时长 __TOTAL_HOURS__
    +
    +
    + +
    +
    + + + + + + + + + + + + + + + __ROWS_LEFT__ + +
    排名游戏时长
    +
    +
    + __RIGHT_TABLE__ +
    +
    + +
    +
    各时长段游戏数量
    +
    全库按时长分段,0 = 未游玩 · 对数轴
    +
    +
    + +
    +
    时长占比
    +
    Top 8 游戏 + 其余聚合
    +
    +
    + + + + + + + diff --git a/hexi/plugins/nonebot_plugin_steam_info/res/unknown_avatar.jpg b/hexi/plugins/nonebot_plugin_steam_info/res/unknown_avatar.jpg new file mode 100644 index 0000000..aa490cb Binary files /dev/null and b/hexi/plugins/nonebot_plugin_steam_info/res/unknown_avatar.jpg differ diff --git a/hexi/plugins/nonebot_plugin_steam_info/res/zzz_gaming.png b/hexi/plugins/nonebot_plugin_steam_info/res/zzz_gaming.png new file mode 100644 index 0000000..ebc7bbd Binary files /dev/null and b/hexi/plugins/nonebot_plugin_steam_info/res/zzz_gaming.png differ diff --git a/hexi/plugins/nonebot_plugin_steam_info/res/zzz_online.png b/hexi/plugins/nonebot_plugin_steam_info/res/zzz_online.png new file mode 100644 index 0000000..02acf55 Binary files /dev/null and b/hexi/plugins/nonebot_plugin_steam_info/res/zzz_online.png differ diff --git a/hexi/plugins/nonebot_plugin_steam_info/steam.py b/hexi/plugins/nonebot_plugin_steam_info/steam.py new file mode 100644 index 0000000..b3484c9 --- /dev/null +++ b/hexi/plugins/nonebot_plugin_steam_info/steam.py @@ -0,0 +1,1019 @@ +import re +import sqlite3 +from contextlib import closing +import httpx +from pathlib import Path +from bs4 import BeautifulSoup +from nonebot.log import logger +from typing import List, Optional, Dict +from datetime import datetime, timezone +import asyncio +import json +from hexi.plugins.nonebot_plugin_hexi_core.rate_limit import acquire + +from .config import Config + +from .models import PlayerSummaries, PlayerData + +STEAM_ID_OFFSET = 76561197960265728 + +# Steam Web API 总限频:单 key 极限约 200 req/5min(40 req/min), +# 双 key 合计 400 req/5min;且相邻两次请求的间隔不能太短(限流按短窗口计)。 +# 保守取 1 req/2s(两 key 合计 150 req/5min,留 ~60% 余量), +# capacity=1 保证任意两次请求间隔 >= 2s,杜绝短窗口突发。 +# 所有端点(GetPlayerSummaries/GetOwnedGames/GetAppList)共享同一配额。 +STEAM_API_RATE = 1 / 2 +STEAM_API_CAPACITY = 1 + + +async def acquire_steam_quota(wait: bool = True, timeout: float = 60) -> bool: + """获取一次 Steam API 调用配额;wait=False 时超限立即返回 False""" + return await acquire( + "steam_api", + rate=STEAM_API_RATE, + capacity=STEAM_API_CAPACITY, + wait=wait, + timeout=timeout, + ) + + +class ApiKeyManager: + """API Key 状态管理器(SQLite 持久化,替换旧 JSON 状态文件)""" + + def __init__(self, api_keys: List[str], db_path: Path): + self.api_keys = api_keys + self._db_path = Path(db_path) + self._lock = asyncio.Lock() + self._init_state() + + def _connect(self) -> sqlite3.Connection: + self._db_path.parent.mkdir(parents=True, exist_ok=True) + # isolation_level=None:自动提交模式,确保写入持久化 + return sqlite3.connect(str(self._db_path), isolation_level=None) + + def _init_state(self): + """建表并同步 key 列表(旧 JSON 迁移由 init_api_key_manager 触发)""" + with closing(self._connect()) as conn: + conn.execute( + "CREATE TABLE IF NOT EXISTS api_key_state (" + "key TEXT PRIMARY KEY," + "call_count INTEGER NOT NULL DEFAULT 0," + "last_called TEXT," + "created_at TEXT)" + ) + self._sync_keys() + + def migrate_legacy_json(self, legacy_paths: List[Optional[Path]]) -> None: + """迁移旧 JSON 状态文件到 SQLite,成功后改名 .bak(只迁移第一个存在的)""" + for json_path in legacy_paths: + if json_path is None or not Path(json_path).is_file(): + continue + try: + data = json.loads(Path(json_path).read_text("utf-8")) + if not isinstance(data, dict): + continue + with closing(self._connect()) as conn: + for key, entry in data.items(): + conn.execute( + "INSERT OR REPLACE INTO api_key_state " + "(key, call_count, last_called, created_at) " + "VALUES (?, ?, ?, ?)", + (str(key), + int(entry.get("call_count", 0)), + entry.get("last_called"), + entry.get("created_at")), + ) + Path(json_path).rename(Path(json_path).with_suffix(".json.bak")) + logger.info(f"已迁移 API key 状态 {json_path} -> SQLite") + return + except Exception as e: + logger.error(f"迁移 API key 状态 {json_path} 失败: {e}") + + def _sync_keys(self): + """与配置同步:新增未记录的 key,移除已删除的 key""" + with closing(self._connect()) as conn: + existing = {r[0] for r in conn.execute("SELECT key FROM api_key_state")} + for key in self.api_keys: + if key not in existing: + conn.execute( + "INSERT INTO api_key_state (key, call_count, created_at) " + "VALUES (?, 0, ?)", + (key, datetime.now().isoformat()), + ) + logger.info(f"发现新的 API key,已添加: {key[:10]}...") + for key in existing - set(self.api_keys): + conn.execute("DELETE FROM api_key_state WHERE key = ?", (key,)) + logger.info(f"已移除不存在的 API key: {key[:10]}...") + + async def get_next_key(self) -> str: + """获取下一个 API key,优先未使用过的,然后选择最久未使用的""" + async with self._lock: + with closing(self._connect()) as conn: + state = { + k: lc + for k, lc in conn.execute( + "SELECT key, last_called FROM api_key_state" + ) + } + unused = [k for k in self.api_keys if state.get(k) is None] + if unused: + selected_key = unused[0] + logger.debug(f"📍 选择未使用过的 key: {selected_key[:10]}...") + else: + selected_key = min( + self.api_keys, + key=lambda k: state.get(k) or "1970-01-01", + ) + logger.debug(f"📍 选择最久未使用的 key: {selected_key[:10]}...") + conn.execute( + "UPDATE api_key_state SET call_count = call_count + 1, " + "last_called = ? WHERE key = ?", + (datetime.now().isoformat(), selected_key), + ) + return selected_key + + async def get_stats(self) -> Dict: + """获取使用统计""" + async with self._lock: + with closing(self._connect()) as conn: + rows = conn.execute( + "SELECT key, call_count, last_called FROM api_key_state" + ).fetchall() + return { + f"{k[:10]}...": {"call_count": c, "last_called": lc} + for k, c, lc in rows + } + + async def reset_stats(self): + """重置所有统计""" + async with self._lock: + with closing(self._connect()) as conn: + conn.execute("DELETE FROM api_key_state") + for key in self.api_keys: + conn.execute( + "INSERT INTO api_key_state (key, call_count, created_at) " + "VALUES (?, 0, ?)", + (key, datetime.now().isoformat()), + ) + logger.info("✓ 已重置所有 API key 统计") + + +# 全局 manager 实例 +_api_key_manager: Optional[ApiKeyManager] = None + + +def init_api_key_manager(config: Config, db_path: Path) -> ApiKeyManager: + """从配置初始化 API key 管理器(状态持久化到 SQLite)""" + logger.info(f"开始初始化 apikey: {config.steam_api_key}, 数据库: {db_path}") + global _api_key_manager + _api_key_manager = ApiKeyManager(api_keys=config.steam_api_key, db_path=db_path) + # 迁移旧 JSON 状态(配置路径 + 插件 data 目录常见位置),成功后自动改名 .bak + legacy_paths = [ + Path(config.steam_api_key_state_path) + if config.steam_api_key_state_path + else None, + Path(__file__).parent / "data" / "steam_config.json", + Path(__file__).parent / "data" / "api_keys_state.json", + ] + _api_key_manager.migrate_legacy_json(legacy_paths) + return _api_key_manager + + +def get_api_key_manager() -> ApiKeyManager: + """获取全局 API key 管理器""" + if _api_key_manager is None: + raise RuntimeError("API key manager 未初始化,请先调用 init_api_key_manager()") + return _api_key_manager + + +def get_steam_id(steam_id_or_steam_friends_code: str) -> str: + if not steam_id_or_steam_friends_code.isdigit(): + return None + + id_ = int(steam_id_or_steam_friends_code) + + if id_ < STEAM_ID_OFFSET: + return str(id_ + STEAM_ID_OFFSET) + + return steam_id_or_steam_friends_code + + +def format_api_key_stats(stats: Dict) -> str: + """格式化 API key 使用统计为可读日志文本 + + stats 结构: {key: {"call_count": int, "last_called": str | None}} + """ + lines = ["Steam API key 使用统计:"] + for key, info in stats.items(): + call_count = info.get("call_count", 0) + last_called = info.get("last_called") + if last_called: + last_called = str(last_called).replace("T", " ")[:19] + else: + last_called = "从未调用" + lines.append(f" {key}: 调用 {call_count} 次 | 最近调用: {last_called}") + return "\n".join(lines) + + +async def get_steam_users_info( + steam_ids: List[str], + steam_api_key: List[str], # 保留用于兼容,但实际会使用 manager + proxy: str = None, + wait: bool = True, # 无配额时是否等待;播报等得起,用户命令快速失败 +) -> PlayerSummaries: + """获取 Steam 用户信息;无 API 配额时返回 None(调用方自行提示)""" + + if not steam_ids: + return {"response": {"players": []}} + + if not await acquire_steam_quota(wait=wait): + logger.warning("Steam API 配额已满,本次查询被跳过") + return None + + manager = get_api_key_manager() # 从全局获取 + + if len(steam_ids) > 100: + result: dict = {"response": {"players": []}} + tasks = [] + + for i in range(0, len(steam_ids), 100): + if i > 0: + # 每批实际发一次请求:入口配额只买了第一批,后续批逐批购买 + if not await acquire_steam_quota(wait=wait): + logger.warning("Steam API 配额已满,剩余批次被跳过") + break + batch_ids = steam_ids[i:i + 100] + batch_key = await manager.get_next_key() + tasks.append( + _fetch_steam_batch(batch_ids, batch_key, proxy) + ) + + batch_results = await asyncio.gather(*tasks) + for batch_players in batch_results: + result["response"]["players"].extend(batch_players) + + stats = await manager.get_stats() + logger.info(format_api_key_stats(stats)) + return result + + api_key = await manager.get_next_key() + players = await _fetch_steam_batch(steam_ids, api_key, proxy) + stats = await manager.get_stats() + logger.info(format_api_key_stats(stats)) + return {"response": {"players": players}} + + +async def _fetch_steam_batch( + steam_ids: List[str], api_key: str, proxy: str = None +) -> List[dict]: + """获取单批 Steam 用户信息(≤100 个 ID),双端点重试""" + api_endpoints = [ + 'https://community.steam-api.com/ISteamUser/GetPlayerSummaries/v0002/', + 'https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/', + ] + + steamids_param = ",".join(steam_ids) + timeout = httpx.Timeout(30.0) + + async with httpx.AsyncClient(proxy=proxy, timeout=timeout) as client: + for endpoint in api_endpoints: + try: + response = await client.get( + endpoint, + params={"key": api_key, "steamids": steamids_param}, + ) + logger.info( + f"✓ Steam API 响应 {response.status_code}, " + f"key: {api_key[:10]}..." + ) + if response.status_code == 200: + data = response.json() + return data.get("response", {}).get("players", []) + else: + # Steam 错误响应体含明确原因(Access is denied / + # Rate limit exceeded 等),不打出来无法区分 key 问题与限流 + reason = (response.text or "").strip().replace("\n", " ")[:200] + logger.warning( + f"✗ key {api_key[:10]}... 端点 {endpoint} " + f"返回 {response.status_code} | {reason}" + ) + except httpx.RequestError as exc: + logger.warning( + f"✗ 请求错误 - key: {api_key[:10]}..., " + f"端点: {endpoint}, 错误: {exc}" + ) + except Exception as exc: + logger.error( + f"✗ 未预期错误 - key: {api_key[:10]}..., " + f"端点: {endpoint}, 错误: {exc}" + ) + logger.error("✗ 所有端点均失败") + return [] + + +async def _fetch( + url: str, default: bytes, cache_file: Optional[Path] = None, proxy: str = None +) -> bytes: + if cache_file is not None: + try: + if cache_file.exists(): + return await asyncio.to_thread(cache_file.read_bytes) + except Exception: + pass + try: + async with httpx.AsyncClient(proxy=proxy) as client: + response = await client.get(url) + if response.status_code == 200: + content = response.content + if cache_file is not None: + try: + await asyncio.to_thread(cache_file.write_bytes, content) + except Exception: + pass + return content + else: + response.raise_for_status() + except Exception as exc: + logger.error(f"Failed to get image: {exc}") + return default + + +async def get_user_data( + steam_id: int, cache_path: Path, proxy: str = None +) -> PlayerData: + url = f"https://steamcommunity.com/profiles/{steam_id}" + default_background = (Path(__file__).parent / "res/bg_dots.png").read_bytes() + default_avatar = (Path(__file__).parent / "res/unknown_avatar.jpg").read_bytes() + default_achievement_image = ( + Path(__file__).parent / "res/default_achievement_image.png" + ).read_bytes() + default_header_image = ( + Path(__file__).parent / "res/default_header_image.jpg" + ).read_bytes() + + result = { + "description": "No information given.", + "background": default_background, + "avatar": default_avatar, + "player_name": "Unknown", + "recent_2_week_play_time": None, + "game_data": [], + } + + local_time = datetime.now(timezone.utc).astimezone() + utc_offset_minutes = int(local_time.utcoffset().total_seconds() / 60) + timezone_cookie_value = f"{utc_offset_minutes},0" + + try: + async with httpx.AsyncClient( + proxy=proxy, + headers={ + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6" + }, + cookies={"timezoneOffset": timezone_cookie_value}, + ) as client: + response = await client.get(url) + if response.status_code == 200: + html = response.text + elif response.status_code == 302: + url = response.headers["Location"] + response = await client.get(url) + if response.status_code == 200: + html = response.text + else: + response.raise_for_status() + except httpx.RequestError as exc: + logger.error(f"Failed to get user data: {exc}") + return result + + # player name + player_name = re.search(r"Steam 社区 :: (.*?)", html) + if player_name: + result["player_name"] = player_name.group(1) + + # description t
    \r\n\t\t\t\t\t\t\t\t風が雨が激しくても
    思いだすんだ 僕らを照らす光があるよ
    今日もいっぱい
    明日もいっぱい 力を出しきってみるよ\t\t\t\t\t\t\t
    + description = re.search( + r'
    (.*?)
    ', html, re.DOTALL | re.MULTILINE + ) + if description: + description = description.group(1) + description = re.sub(r"
    ", "\n", description) + description = re.sub(r"\t", "", description) + result["description"] = description.strip() + + # remove emoji + result["description"] = re.sub(r"ː.*?ː", "", result["description"]) + + # remove xml + result["description"] = re.sub(r"<.*?>", "", result["description"]) + + # background + background_url = re.search(r"background-image: url\( \'(.*?)\' \)", html) + if background_url: + background_url = background_url.group(1) + result["background"] = await _fetch( + background_url, default_background, proxy=proxy + ) + + # avatar + # \t + avatar_url = re.search(r'\r\n\t\t\t\t\t\t\t\t\t
    15.5 小时(过去 2 周)
    + play_time_text = re.search( + r'