feat: support edit damage rule

This commit is contained in:
omg-xtao 2023-10-24 01:00:32 +08:00 committed by GitHub
parent eb65dae993
commit 97c8eea821
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1167 additions and 143 deletions

View File

@ -1,137 +1,141 @@
{
"胡桃": {
"skills": [
{
"name": "普通攻击·往生秘传枪法-重击蒸发伤害",
"index": "7",
"damage_key": "vaporize"
},
{
"name": "安神秘法-蒸发伤害",
"index": "12",
"damage_key": "vaporize"
},
{
"name": "安神秘法-低血量蒸发伤害",
"index": "13",
"damage_key": "vaporize"
}
],
"config_skill": {
"after_e": true
"胡桃": {
"skills": [
{
"name": "普通攻击·往生秘传枪法-重击蒸发伤害",
"index": 7,
"damage_key": "vaporize"
},
{
"name": "安神秘法-蒸发伤害",
"index": 12,
"damage_key": "vaporize"
},
{
"name": "安神秘法-低血量蒸发伤害",
"index": 13,
"damage_key": "vaporize"
}
],
"config": {
"le_50": true
},
"config_skill": {
"after_e": true
},
"config_weapon": {
"StaffOfHoma": {
"be50_rate": 1
}
},
"artifact_config": {
"config_crimson_witch_of_flames": {
"level": 1
}
}
},
"config": {
"le_50": true
"夜兰": {
"skills": [
{
"name": "普通攻击·潜形隐曜弓-破局矢伤害",
"index": 6,
"damage_key": "normal"
},
{
"name": "萦络纵命索-技能伤害",
"index": 11,
"damage_key": "normal"
},
{
"name": "渊图玲珑骰-技能伤害",
"index": 12,
"damage_key": "normal"
},
{
"name": "渊图玲珑骰-玄掷玲珑伤害",
"index": 13,
"damage_key": "normal"
}
],
"config": {
"team_element_count": 4
},
"config_skill": null,
"config_weapon": {
"AquaSimulacra": {
"is_enemy_around": true
}
},
"artifact_config": null
},
"config_weapon": {
"StaffOfHoma": {
"be50_rate": 1
}
},
"artifact_config": {
"config_crimson_witch_of_flames": {
"level": 1
}
"雷电将军": {
"skills": [
{
"name": "神变•恶曜开眼-技能伤害",
"index": 10,
"damage_key": "normal"
},
{
"name": "神变•恶曜开眼协-同攻击伤害",
"index": 11,
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-梦想一刀基础伤害",
"index": 12,
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-一段伤害",
"index": 13,
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-二段伤害",
"index": 14,
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-三段伤害",
"index": 15,
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-四段伤害-1",
"index": 16,
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-四段伤害-2",
"index": 17,
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-五段伤害",
"index": 18,
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-重击伤害-1",
"index": 19,
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-重击伤害-2",
"index": 20,
"damage_key": "normal"
}
],
"config": null,
"config_skill": {
"under_e": true,
"resolve_stack": 60
},
"config_weapon": {
"EngulfingLightning": {
"rate": 0
}
},
"artifact_config": null
}
},
"夜兰": {
"skills": [
{
"name": "普通攻击·潜形隐曜弓-破局矢伤害",
"index": "6",
"damage_key": "normal"
},
{
"name": "萦络纵命索-技能伤害",
"index": "11",
"damage_key": "normal"
},
{
"name": "渊图玲珑骰-技能伤害",
"index": "12",
"damage_key": "normal"
},
{
"name": "渊图玲珑骰-玄掷玲珑伤害",
"index": "13",
"damage_key": "normal"
}
],
"config": {
"team_element_count": 4
},
"config_weapon": {
"AquaSimulacra": {
"is_enemy_around": true
}
}
},
"雷电将军": {
"skills": [
{
"name": "神变•恶曜开眼-技能伤害",
"index": "10",
"damage_key": "normal"
},
{
"name": "神变•恶曜开眼协-同攻击伤害",
"index": "11",
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-梦想一刀基础伤害",
"index": "12",
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-一段伤害",
"index": "13",
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-二段伤害",
"index": "14",
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-三段伤害",
"index": "15",
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-四段伤害-1",
"index": "16",
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-四段伤害-2",
"index": "17",
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-五段伤害",
"index": "18",
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-重击伤害-1",
"index": "19",
"damage_key": "normal"
},
{
"name": "奥义•梦想真说-重击伤害-2",
"index": "20",
"damage_key": "normal"
}
],
"config_skill": {
"under_e": true,
"resolve_stack": 60
},
"config_weapon": {
"EngulfingLightning": {
"rate": 0
}
}
}
}
}

View File

@ -19,7 +19,7 @@ install:
- pip install -r requirements.txt
build_script:
- flet pack main.py --name FightPropRuleEditor --product-name FightPropRuleEditor
- flet pack main.py --name GramBotMetadataEditor --product-name GramBotMetadataEditor
test: off
@ -40,10 +40,10 @@ for:
- image: Visual Studio 2019
after_build:
- 7z a FightPropRuleEditor-windows.zip %CD%\dist\*.exe
- 7z a GramBotMetadataEditor-windows.zip %CD%\dist\*.exe
artifacts:
- path: FightPropRuleEditor-windows.zip
- path: GramBotMetadataEditor-windows.zip
#
# macOS package
@ -54,10 +54,10 @@ for:
- image: macOS
after_build:
- tar -czvf FightPropRuleEditor-macos.tar.gz -C dist FightPropRuleEditor.app
- tar -czvf GramBotMetadataEditor-macos.tar.gz -C dist GramBotMetadataEditor.app
artifacts:
- path: FightPropRuleEditor-macos.tar.gz
- path: GramBotMetadataEditor-macos.tar.gz
#
# Linux package
@ -68,7 +68,7 @@ for:
- image: Ubuntu
after_build:
- tar -czvf FightPropRuleEditor-linux.tar.gz -C dist FightPropRuleEditor
- tar -czvf GramBotMetadataEditor-linux.tar.gz -C dist GramBotMetadataEditor
artifacts:
- path: FightPropRuleEditor-linux.tar.gz
- path: GramBotMetadataEditor-linux.tar.gz

View File

@ -1,6 +1,7 @@
import flet as ft
from src.choose import choose_view
from src.damage.page import edit_damage_view
from src.data import Page
from src.edit import edit_view
@ -11,6 +12,8 @@ def main(page: Page):
choose_view(page)
if e.route == "/edit":
edit_view(page)
elif e.route == "/edit_damage":
edit_damage_view(page)
page.update()
def view_pop():
@ -18,7 +21,7 @@ def main(page: Page):
top_view = page.views[-1]
page.go(top_view.route)
page.title = "FightPropRuleEditor"
page.title = "GramBotMetadataEditor"
page.vertical_alignment = "center"
page.horizontal_alignment = "center"
page.on_route_change = on_route_change

View File

@ -1,3 +1,6 @@
flet
PyInstaller
httpx
Python-Genshin-Artifact
genshin-artifact-core
pydantic

View File

@ -13,6 +13,10 @@ def choose_view(page: Page):
page.go("/edit")
show_snack_bar(page, "开始编辑原神圣遗物有效词条", ft.colors.GREEN)
def genshin_damage(_e):
page.go("/edit_damage")
show_snack_bar(page, "开始编辑原神伤害计算规则", ft.colors.GREEN)
def starrail(_e):
page.core = Core(starrail_path, Starrail())
page.go("/edit")
@ -32,7 +36,7 @@ def choose_view(page: Page):
[
ft.Container(
content=ft.Text(
"FightPropRuleEditor",
"GramBotMetadataEditor",
size=50,
),
),
@ -46,6 +50,11 @@ def choose_view(page: Page):
icon=ft.icons.LOGIN,
on_click=starrail,
),
ft.FilledButton(
"GenshinDamage",
icon=ft.icons.LOGIN,
on_click=genshin_damage,
),
ft.FilledButton(
"Refresh avatars",
icon=ft.icons.LOGIN,

0
src/damage/__init__.py Normal file
View File

30
src/damage/artifact.py Normal file
View File

@ -0,0 +1,30 @@
import json
from typing import Dict, List
from .assets import assets, locale
from .models import Artifact as ArtifactModel, WeaponConfig
class Artifact:
def __init__(self):
artifacts: List[ArtifactModel] = []
artifact_config_map: Dict[str, ArtifactModel] = {}
for value in assets.artifact.values():
if not value["config4"]:
continue
cn_name = locale[value["name_locale"]]
config_key = ArtifactModel.get_config_name(value["name"])
config = []
for i in value["config4"]:
temp = json.loads(i)
temp["title"] = locale[temp["title"]]
temp["parent"] = config_key
config.append(WeaponConfig(**temp))
artifact_ = ArtifactModel(**value, cn_name=cn_name, config=config)
artifacts.append(artifact_)
artifact_config_map[config_key] = artifact_
self.artifacts = artifacts
self.artifact_config_map = artifact_config_map
artifact = Artifact()

4
src/damage/assets.py Normal file
View File

@ -0,0 +1,4 @@
from python_genshin_artifact.assets import Assets
assets = Assets()
locale = assets.locale["zh-cn"]

56
src/damage/character.py Normal file
View File

@ -0,0 +1,56 @@
import json
from typing import List, Dict
from .assets import assets, locale
from .models import CharacterConfig, CharacterSkill
class Character:
def __init__(self):
self.current_name = ""
self.characters_map = {}
self.skills_map = {}
self.config_map = {}
self.config_skill_map = {}
for value in assets.character.values():
character_name = locale[value["name_locale"]]
self.characters_map[character_name] = value
self.skills_map[character_name] = self.gen_skills_model(value)
self.config_map[character_name] = self.gen_config_model(value["config"])
self.config_skill_map[character_name] = self.gen_config_model(
value["config_skill"]
)
self.characters_name = list(self.characters_map.keys())
@staticmethod
def gen_skills_model(character_: Dict) -> List[CharacterSkill]:
skills = []
skill1_name = locale[character_.get("skill1_name_index")]
skill2_name = locale[character_.get("skill2_name_index")]
skill3_name = locale[character_.get("skill3_name_index")]
for skill_name, skill in [
(skill1_name, character_["skill_map1"]),
(skill2_name, character_["skill_map2"]),
(skill3_name, character_["skill_map3"]),
]:
for i in skill:
skills.append(
CharacterSkill(
name=locale[i["locale_index"]],
index=i["index"],
skill_name=skill_name,
)
)
return skills
@staticmethod
def gen_config_model(config: List[str]) -> List[CharacterConfig]:
data = []
for i in config:
temp = json.loads(i)
temp["title"] = locale[temp["title"]]
data.append(CharacterConfig(**temp))
return data
character = Character()

232
src/damage/data.py Normal file
View File

@ -0,0 +1,232 @@
import json
from typing import Dict, Any
from .character import character
from .models import CharacterDamage, CharacterSkill, CharacterConfig, WeaponConfig
class Data:
def __init__(self):
self.file_name = "GenshinDamageRule.json"
self.file_data: Dict[str, CharacterDamage] = self.load()
self.patch_character()
def load(self) -> Dict[str, CharacterDamage]:
with open(self.file_name, "r", encoding="utf-8") as f:
_data = json.load(f)
new_data = {}
for k, v in _data.items():
new_data[k] = CharacterDamage(**v)
return new_data
def patch_character(self):
for c_name, v in self.file_data.items():
custom_name_map = {}
damage_key_map = {}
for skill in v.skills:
custom_name_map[skill.index] = skill.name
damage_key_map[skill.index] = skill.damage_key
for skill in character.skills_map[c_name]:
if skill.index in custom_name_map:
skill.custom_name = custom_name_map[skill.index]
skill.damage_key = damage_key_map[skill.index]
def dump(self) -> Dict[str, Dict]:
new_data = {}
for k, v in self.file_data.items():
new_data[k] = v.dict()
return new_data
def save(self):
with open(self.file_name, "w", encoding="utf-8") as f:
json.dump(self.dump(), f, ensure_ascii=False, indent=4)
def first_init(self, character_name: str):
if character_name in self.file_data:
return
self.file_data[character_name] = CharacterDamage(skills=[])
def last_close(self, character_name: str):
if character_name not in self.file_data:
return
data_ = self.file_data[character_name]
def last_close_weapon_or_artifact():
if data_.config_weapon:
for k, v in data_.config_weapon.copy().items():
if not v:
del data_.config_weapon[k]
if data_.artifact_config:
for k, v in data_.artifact_config.copy().items():
if not v:
del data_.artifact_config[k]
last_close_weapon_or_artifact()
if len(data_.skills) != 0:
return
if data_.config is not None and data_.config:
return
if data_.config_skill is not None and data_.config_skill:
return
if data_.config_weapon is not None and data_.config_weapon:
return
if data_.artifact_config is not None and data_.artifact_config:
return
del self.file_data[character_name]
def get_skill_value(self, character_name: str, skill: CharacterSkill) -> bool:
if not self.file_data.get(character_name):
return False
skill_id = skill.index
for i in self.file_data[character_name].skills:
if i.index == skill_id:
return True
return False
def set_skill_value(self, character_name: str, skill: CharacterSkill, enable: bool):
self.first_init(character_name)
in_data = None
for i in self.file_data[character_name].skills:
if i.index == skill.index:
in_data = i
break
if enable:
if not in_data:
self.file_data[character_name].skills.append(skill.to_data())
else:
in_data.name = skill.custom_name or skill.show_name
in_data.damage_key = skill.damage_key
else:
if in_data:
self.file_data[character_name].skills.remove(in_data)
self.file_data[character_name].skills.sort(key=lambda x: x.index)
self.last_close(character_name)
def get_character_config_value(
self, character_name: str, config_: CharacterConfig
) -> Any:
if not self.file_data.get(character_name):
return None
if not self.file_data[character_name].config:
return None
return self.file_data[character_name].config.get(config_.name, None)
def set_character_config_value(
self, character_name: str, config: CharacterConfig, value: Any
):
self.first_init(character_name)
if not self.file_data[character_name].config:
self.file_data[character_name].config = {}
if isinstance(config.default, bool):
new_value = value == "true"
else:
value_class = type(config.default)
new_value = value_class(value)
self.file_data[character_name].config[config.name] = new_value
self.last_close(character_name)
def get_character_skill_config_value(
self, character_name: str, config_: CharacterConfig
) -> Any:
if not self.file_data.get(character_name):
return None
if not self.file_data[character_name].config_skill:
return None
return self.file_data[character_name].config_skill.get(config_.name, None)
def set_character_skill_config_value(
self, character_name: str, config: CharacterConfig, value: Any
):
self.first_init(character_name)
if not self.file_data[character_name].config_skill:
self.file_data[character_name].config_skill = {}
if isinstance(config.default, bool):
new_value = value == "true"
else:
value_class = type(config.default)
new_value = value_class(value)
self.file_data[character_name].config_skill[config.name] = new_value
self.last_close(character_name)
def get_character_weapon_config_value(
self, character_name: str, config_: WeaponConfig
) -> Any:
if not self.file_data.get(character_name):
return None
if not self.file_data[character_name].config_weapon:
return None
data_ = self.file_data[character_name].config_weapon.get(config_.parent, None)
if not data_:
return None
return data_.get(config_.name, None)
def set_character_weapon_config_value(
self, character_name: str, config: WeaponConfig, value: Any
):
self.first_init(character_name)
if not self.file_data[character_name].config_weapon:
self.file_data[character_name].config_weapon = {}
data_ = self.file_data[character_name].config_weapon.get(config.parent, {})
if value == "":
if config.name in data_:
del data_[config.name]
else:
if isinstance(config.default, bool):
new_value = value == "true"
else:
value_class = type(config.default)
new_value = value_class(value)
data_[config.name] = new_value
self.file_data[character_name].config_weapon[config.parent] = data_
self.last_close(character_name)
def get_weapon_config_enable(self, character_name: str, weapon_key: str) -> bool:
if not self.file_data.get(character_name):
return False
if not self.file_data[character_name].config_weapon:
return False
return weapon_key in self.file_data[character_name].config_weapon
def get_character_artifact_config_value(
self, character_name: str, config_: WeaponConfig
) -> Any:
if not self.file_data.get(character_name):
return None
if not self.file_data[character_name].artifact_config:
return None
data_ = self.file_data[character_name].artifact_config.get(config_.parent, None)
if not data_:
return None
return data_.get(config_.name, None)
def set_character_artifact_config_value(
self, character_name: str, config: WeaponConfig, value: Any
):
self.first_init(character_name)
if not self.file_data[character_name].artifact_config:
self.file_data[character_name].artifact_config = {}
data_ = self.file_data[character_name].artifact_config.get(config.parent, {})
if value == "":
if config.name in data_:
del data_[config.name]
else:
if isinstance(config.default, bool):
new_value = value == "true"
else:
value_class = type(config.default)
new_value = value_class(value)
data_[config.name] = new_value
self.file_data[character_name].artifact_config[config.parent] = data_
self.last_close(character_name)
def get_artifact_config_enable(
self, character_name: str, artifact_key: str
) -> bool:
if not self.file_data.get(character_name):
return False
if not self.file_data[character_name].artifact_config:
return False
return artifact_key in self.file_data[character_name].artifact_config
data = Data()

157
src/damage/models.py Normal file
View File

@ -0,0 +1,157 @@
import flet
from enum import Enum
from typing import List, Dict, Any, Optional
from pydantic import BaseModel
Element4OP = [
flet.dropdown.Option(key="Cyro", text="冰元素"),
flet.dropdown.Option(key="Electro", text="雷元素"),
flet.dropdown.Option(key="Hydro", text="水元素"),
flet.dropdown.Option(key="Pyro", text="火元素"),
]
Element8OP = Element4OP + [
flet.dropdown.Option(key="Anemo", text="风元素"),
flet.dropdown.Option(key="Dendro", text="草元素"),
flet.dropdown.Option(key="Geo", text="岩元素"),
flet.dropdown.Option(key="Physical", text="物理伤害"),
]
class Element4(str, Enum):
Cyro = "Cyro"
"""冰元素"""
Electro = "Electro"
"""雷元素"""
Hydro = "Hydro"
"""水元素"""
Pyro = "Pyro"
"""火元素"""
class Element8(str, Enum):
Cyro = "Cyro"
"""冰元素"""
Electro = "Electro"
"""雷元素"""
Hydro = "Hydro"
"""水元素"""
Pyro = "Pyro"
"""火元素"""
Anemo = "Anemo"
"""风元素"""
Dendro = "Dendro"
"""草元素"""
Geo = "Geo"
"""岩元素"""
Physical = "Physical"
"""物理伤害"""
class CharacterDamageSkillDamageKey(str, Enum):
normal = "normal"
"""普通伤害结果"""
melt = "melt"
"""融化伤害结果"""
vaporize = "vaporize"
"""蒸发伤害结果"""
@property
def data_map(self) -> Dict[str, str]:
return {"普通伤害结果": "normal", "融化伤害结果": "melt", "蒸发伤害结果": "vaporize"}
class CharacterDamageSkill(BaseModel):
name: str
index: int
damage_key: CharacterDamageSkillDamageKey
class Config:
frozen = False
class CharacterDamage(BaseModel):
skills: List[CharacterDamageSkill]
config: Optional[Dict[str, Any]] = None
config_skill: Optional[Dict[str, Any]] = None
config_weapon: Optional[Dict[str, Dict[str, Any]]] = None
artifact_config: Optional[Dict[str, Dict[str, Any]]] = None
class Config:
frozen = False
class CharacterConfig(BaseModel):
default: Any
name: str
title: str
type: str
class Config:
frozen = False
class CharacterSkill(BaseModel):
name: str
index: int
skill_name: str
custom_name: str = ""
damage_key: CharacterDamageSkillDamageKey = CharacterDamageSkillDamageKey.normal
@property
def show_name(self) -> str:
return f"{self.name} - {self.skill_name}"
def to_data(self) -> CharacterDamageSkill:
return CharacterDamageSkill(
name=self.custom_name or self.show_name,
index=self.index,
damage_key=self.damage_key,
)
class Config:
frozen = False
class WeaponConfig(CharacterConfig):
max: float = 0
min: float = 0
parent: str = ""
class Config:
frozen = False
class Weapon(BaseModel):
name: str
cn_name: str
star: int
t: str
config: List[WeaponConfig]
class Config:
frozen = False
class Artifact(BaseModel):
name: str
cn_name: str
min_star: int
max_star: int
config: List[WeaponConfig]
@property
def config_name(self) -> str:
return self.get_config_name(self.name)
@staticmethod
def get_config_name(name: str) -> str:
start = "config_"
# 将大写转换为下划线加小写
# 例如: MaxHp -> max_hp
convert_name = "".join(
[f"_{i.lower()}" if i.isupper() else i for i in name]
).lstrip("_")
return f"{start}{convert_name}"
class Config:
frozen = False

496
src/damage/page.py Normal file
View File

@ -0,0 +1,496 @@
from typing import List
from flet_core import MainAxisAlignment
import flet as ft
from src.data import Page
from .artifact import artifact
from .character import character
from .data import data
from .models import (
CharacterSkill,
CharacterDamageSkillDamageKey,
CharacterConfig,
Weapon as WeaponModel,
Element4OP,
Element8OP,
)
from .weapon import weapon
def edit_damage_view(page: "Page"):
name_list = ft.ListView(width=230)
skill_list = ft.ListView(expand=True)
weapon_list = ft.ListView(expand=True)
artifact_list = ft.ListView(expand=True)
character_control_list = ft.ListView(expand=True)
top_title = ft.Ref[ft.Text]()
def update_top_title(title: str):
"""更新当前页面标题"""
top_title.current.value = title
page.update()
def back_choose(_):
page.go("/")
page.update()
def save(_):
def close_alert(_):
success_dialog.open = False
top_title.current.value = ""
choose_character()
page.update()
data.save()
success_dialog = ft.AlertDialog(
modal=True,
title=ft.Text("保存成功"),
content=ft.Text("保存成功"),
actions=[
ft.TextButton("", on_click=close_alert),
],
actions_alignment=MainAxisAlignment.END,
)
page.dialog = success_dialog
success_dialog.open = True
page.update()
def update_skill_component():
ch_name = character.current_name
skill_list.controls.clear()
def search_skills(e: ft.ControlEvent = None):
temp = skill_list.controls[0]
skill_list.controls.clear()
skill_list.controls.append(temp)
for con in skill_list_data:
con: "ft.Container"
cb: "ft.Checkbox" = con.content # noqa
if e is None or e.data in cb.label:
skill_list.controls.append(con)
page.update()
skill_list.controls.append(
ft.Container(
content=ft.TextField(
label="技能配置",
on_change=search_skills,
),
)
)
for i in character.skills_map[ch_name]:
container = ft.Container(
content=ft.Checkbox(
label=i.show_name,
value=data.get_skill_value(ch_name, i),
disabled=True,
data=i,
),
on_click=choose_skill,
)
skill_list.controls.append(container)
skill_list_data = skill_list.controls[1:]
def update_weapon_component():
ch_name = character.current_name
character_ = character.characters_map[ch_name]
weapon_list.controls.clear()
def search_weapons(e: ft.ControlEvent = None):
temp = weapon_list.controls[0]
weapon_list.controls.clear()
weapon_list.controls.append(temp)
for con in weapon_list_data:
con: "ft.Container"
cb: "ft.Checkbox" = con.content # noqa
if e is None or e.data in cb.label:
weapon_list.controls.append(con)
page.update()
weapon_list.controls.append(
ft.Container(
content=ft.TextField(
label="武器配置",
on_change=search_weapons,
),
)
)
for i in weapon.weapon_map.get(character_.get("weapon", ""), []):
i: "WeaponModel"
container = ft.Container(
content=ft.Checkbox(
label=i.cn_name,
value=data.get_weapon_config_enable(ch_name, i.name),
disabled=True,
data=i,
),
on_click=choose_weapon,
)
weapon_list.controls.append(container)
weapon_list_data = weapon_list.controls[1:]
def update_artifact_component():
ch_name = character.current_name
artifact_list.controls.clear()
def search_artifacts(e: ft.ControlEvent = None):
temp = artifact_list.controls[0]
artifact_list.controls.clear()
artifact_list.controls.append(temp)
for con in artifact_list_data:
con: "ft.Container"
cb: "ft.Checkbox" = con.content # noqa
if e is None or e.data in cb.label:
artifact_list.controls.append(con)
page.update()
artifact_list.controls.append(
ft.Container(
content=ft.TextField(
label="圣遗物配置",
on_change=search_artifacts,
),
)
)
for i in artifact.artifacts:
container = ft.Container(
content=ft.Checkbox(
label=i.cn_name,
value=data.get_artifact_config_enable(ch_name, i.config_name),
disabled=True,
data=i,
),
on_click=choose_artifact,
)
artifact_list.controls.append(container)
artifact_list_data = artifact_list.controls[1:]
def gen_switch_or_text(
ch_name, config: CharacterConfig, get_config_value, on_change
):
ele = None
if isinstance(config.default, bool):
class_ = ft.Checkbox
elif config.type in ["element4", "element8"]:
class_ = ft.Dropdown
ele = Element4OP if config.type == "element4" else Element8OP
else:
class_ = ft.TextField
ins = class_(
label=config.title,
value=get_config_value(ch_name, config),
data=config,
on_change=on_change,
)
if class_ == ft.Dropdown:
ins.options = ele
return ins
def update_config_component(
com: List,
name: str,
config_map,
set_character_config_value,
get_character_config_value,
):
ch_name = character.current_name
if not character.config_map[ch_name]:
return
com.append(
ft.Container(
content=ft.Text(
name,
size=20,
),
),
)
def on_config_value_change(e: ft.ControlEvent = None):
set_character_config_value(ch_name, e.control.data, e.data)
def reset_all_config_value(_):
for config in configs:
config.value = config.data.default
set_character_config_value(ch_name, config.data, config.data.default)
page.update()
configs = []
for i in config_map[ch_name]:
content = gen_switch_or_text(
ch_name, i, get_character_config_value, on_config_value_change
)
configs.append(content)
com.append(
ft.Container(
content=content,
),
)
if len(configs) != 0:
com.append(
ft.Container(
content=ft.ElevatedButton(
"恢复到默认值", on_click=reset_all_config_value
),
)
)
return com
def choose_character(e: ft.ControlEvent = None):
if e is not None:
ch_name = e.control.data[0]
character.current_name = ch_name
else:
ch_name = character.current_name
page.update()
update_top_title(ch_name)
update_skill_component()
update_weapon_component()
update_artifact_component()
character_control_list.controls.clear()
com = []
character_control_list.controls.append(ft.Column(com))
update_config_component(
com,
" 角色配置",
character.config_map,
data.set_character_config_value,
data.get_character_config_value,
)
update_config_component(
com,
" 技能配置",
character.config_skill_map,
data.set_character_skill_config_value,
data.get_character_skill_config_value,
)
page.update()
def bs_dismissed(_: ft.ControlEvent = None):
choose_character()
def choose_skill(e: ft.ControlEvent = None):
checkbox: ft.Checkbox = e.control.content
skill: CharacterSkill = checkbox.data
page.overlay.clear()
def close_bs(_: ft.ControlEvent = None):
bs.open = False
bs.update()
def skill_status_change(e_: ft.ControlEvent = None):
value = e_.data == "true"
data.set_skill_value(character.current_name, skill, value)
def skill_custom_name_change(e_: ft.ControlEvent = None):
skill.custom_name = e_.data
data.set_skill_value(character.current_name, skill, True)
def skill_key_change(e_: ft.ControlEvent = None):
skill.damage_key = CharacterDamageSkillDamageKey(e_.data)
data.set_skill_value(character.current_name, skill, True)
bs = ft.BottomSheet(
ft.Container(
ft.Column(
[
ft.Text(skill.show_name),
ft.Switch(
label="显示此数值",
value=checkbox.value,
on_change=skill_status_change,
),
ft.TextField(
label="自定义显示名称",
value=skill.custom_name or skill.show_name,
on_change=skill_custom_name_change,
),
ft.Dropdown(
label="输出数据",
options=[
ft.dropdown.Option(key=v, text=k)
for k, v in CharacterDamageSkillDamageKey.normal.data_map.items()
],
value=skill.damage_key.value,
on_change=skill_key_change,
),
ft.ElevatedButton("关闭", on_click=close_bs),
],
tight=True,
),
padding=10,
),
open=True,
on_dismiss=bs_dismissed,
)
page.overlay.append(bs)
page.update()
bs.update()
def choose_weapon(e):
choose_weapon_or_artifact(
e,
data.get_character_weapon_config_value,
data.set_character_weapon_config_value,
)
def choose_artifact(e):
choose_weapon_or_artifact(
e,
data.get_character_artifact_config_value,
data.set_character_artifact_config_value,
)
def choose_weapon_or_artifact(
e: ft.ControlEvent,
get_config_value,
set_config_value,
):
ch_name = character.current_name
checkbox: ft.Checkbox = e.control.content
model: "WeaponModel" = checkbox.data
page.overlay.clear()
def close_bs(_: ft.ControlEvent = None):
bs.open = False
bs.update()
def on_config_value_change(e_: ft.ControlEvent = None):
set_config_value(ch_name, e_.control.data, e_.data)
def reset_all_config_value(_):
for config in configs:
config.value = config.data.default
set_config_value(ch_name, config.data, config.data.default)
page.update()
controls = [
ft.Text(model.cn_name),
]
configs = []
for i in model.config:
content = gen_switch_or_text(
ch_name, i, get_config_value, on_config_value_change
)
configs.append(content)
controls.append(content)
controls.append(
ft.Container(
content=ft.ElevatedButton("恢复到默认值", on_click=reset_all_config_value),
)
)
controls.append(ft.ElevatedButton("关闭", on_click=close_bs))
bs = ft.BottomSheet(
ft.Container(
ft.Column(
controls,
tight=True,
),
padding=10,
),
open=True,
on_dismiss=bs_dismissed,
)
page.overlay.append(bs)
page.update()
bs.update()
def load_names():
def search_names(e: ft.ControlEvent = None):
temp = name_list.controls[0]
name_list.controls.clear()
name_list.controls.append(temp)
for name_ in name_list_data:
if e is None or e.data in name_.text:
name_list.controls.append(name_)
page.update()
name_list.controls.append(
ft.Container(
content=ft.TextField(
label="搜索",
on_change=search_names,
),
)
)
for index, name in enumerate(character.characters_name):
name_list.controls.append(
ft.TextButton(
text=name,
tooltip=name,
style=ft.ButtonStyle(
shape={
"hovered": ft.RoundedRectangleBorder(),
"": ft.RoundedRectangleBorder(),
}
),
data=(name,),
on_click=choose_character,
disabled=False,
),
)
name_list_data = name_list.controls[1:]
load_names()
page.views.append(
ft.View(
"/edit_damage",
[
ft.Stack(
[
ft.Container(
content=ft.Row(
[
ft.Text(
ref=top_title,
value="请选择需要编辑的角色",
size=30,
),
ft.Row(
[
ft.ElevatedButton(
"返回",
icon=ft.icons.ARROW_BACK,
on_click=back_choose,
),
ft.ElevatedButton(
"保存",
icon=ft.icons.DONE,
on_click=save,
),
],
alignment=MainAxisAlignment.CENTER,
spacing=50,
),
],
alignment=MainAxisAlignment.SPACE_BETWEEN,
),
padding=10,
),
]
),
ft.Divider(
height=1,
),
ft.Row(
[
name_list,
ft.VerticalDivider(width=1),
skill_list,
ft.VerticalDivider(width=1),
weapon_list,
ft.VerticalDivider(width=1),
artifact_list,
ft.VerticalDivider(width=1),
character_control_list,
],
expand=True,
spacing=0,
),
],
padding=0,
spacing=0,
)
)

28
src/damage/weapon.py Normal file
View File

@ -0,0 +1,28 @@
import json
from typing import Dict
from .assets import assets, locale
from .models import Weapon as WeaponModel, WeaponConfig
class Weapon:
def __init__(self):
weapon_map: Dict[str, WeaponModel] = {}
for value in assets.weapon.values():
if not value["configs"]:
continue
cn_name = locale[value["name_index"]]
config = []
for i in value["configs"]:
temp = json.loads(i)
temp["title"] = locale[temp["title"]]
temp["parent"] = value["name"]
config.append(WeaponConfig(**temp))
weapon_ = WeaponModel(**value, cn_name=cn_name, config=config)
temp = weapon_map.get(value["t"], [])
temp.append(weapon_)
weapon_map[value["t"]] = temp
self.weapon_map = weapon_map
weapon = Weapon()

View File

@ -155,7 +155,9 @@ class Core:
return
if type_name not in self.data[ch_name]:
return
self.data[ch_name] = {k: v for k, v in self.data[ch_name].copy().items() if k != type_name}
self.data[ch_name] = {
k: v for k, v in self.data[ch_name].copy().items() if k != type_name
}
def save_value(self):
self.data = {k: v for k, v in self.data.copy().items() if v}