ango commited on
Commit
c145eab
1 Parent(s): 581e199

5.14 commit

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .github/workflows/nuitka-app.yml +2 -2
  2. .github/workflows/pyinstaller-app.yml +45 -4
  3. {qt → assets}/constant.py +1 -14
  4. {qt/assets → assets}/enchants/belt +0 -0
  5. {qt/assets → assets}/enchants/bottoms +0 -0
  6. {qt/assets → assets}/enchants/hat +0 -0
  7. {qt/assets → assets}/enchants/jacket +0 -0
  8. {qt/assets → assets}/enchants/necklace +0 -0
  9. {qt/assets → assets}/enchants/pendant +0 -0
  10. {qt/assets → assets}/enchants/primary_weapon +0 -0
  11. {qt/assets → assets}/enchants/ring +0 -0
  12. {qt/assets → assets}/enchants/secondary_weapon +0 -0
  13. {qt/assets → assets}/enchants/shoes +0 -0
  14. {qt/assets → assets}/enchants/tertiary_weapon +0 -0
  15. {qt/assets → assets}/enchants/wrist +0 -0
  16. {qt/assets → assets}/equipments/belt +0 -0
  17. {qt/assets → assets}/equipments/bottoms +0 -0
  18. {qt/assets → assets}/equipments/hat +0 -0
  19. {qt/assets → assets}/equipments/jacket +0 -0
  20. {qt/assets → assets}/equipments/necklace +0 -0
  21. {qt/assets → assets}/equipments/pendant +0 -0
  22. {qt/assets → assets}/equipments/primary_weapon +0 -0
  23. {qt/assets → assets}/equipments/ring +0 -0
  24. {qt/assets → assets}/equipments/secondary_weapon +0 -0
  25. {qt/assets → assets}/equipments/shoes +0 -0
  26. {qt/assets → assets}/equipments/tertiary_weapon +0 -0
  27. {qt/assets → assets}/equipments/wrist +0 -0
  28. assets/icon.icns +0 -0
  29. {qt/assets → assets}/icon.ico +0 -0
  30. assets/stones.json +0 -0
  31. get_assets.py +6 -5
  32. {qt → gr}/__init__.py +0 -0
  33. gr/app.py +42 -0
  34. {qt/scripts → gr/components}/__init__.py +0 -0
  35. gr/components/combat.py +32 -0
  36. gr/components/equipments.py +81 -0
  37. gr/components/recipes.py +24 -0
  38. gr/components/talents.py +25 -0
  39. gr/components/top.py +13 -0
  40. gr/scripts/__init__.py +0 -0
  41. gr/scripts/combat.py +151 -0
  42. {qt → gr}/scripts/equipments.py +132 -96
  43. {qt → gr}/scripts/recipes.py +12 -15
  44. {qt → gr}/scripts/talents.py +8 -13
  45. gr/scripts/top.py +174 -0
  46. qt/app.py +0 -94
  47. qt/assets/stones.json +0 -0
  48. qt/components/__init__.py +0 -208
  49. qt/components/bonuses.py +0 -239
  50. qt/components/config.py +0 -26
.github/workflows/nuitka-app.yml CHANGED
@@ -35,9 +35,9 @@ jobs:
35
  onefile: false
36
  enable-plugins: pyside6
37
  disable-console: true
38
- windows-icon-from-ico: qt/assets/icon.ico
39
  nofollow-import-to: http,email
40
- include-data-dir: qt/assets=qt/assets/
41
  - name: Upload Artifact
42
  uses: actions/upload-artifact@v4
43
  with:
 
35
  onefile: false
36
  enable-plugins: pyside6
37
  disable-console: true
38
+ windows-icon-from-ico: assets/icon.ico
39
  nofollow-import-to: http,email
40
+ include-data-dir: assets=assets/
41
  - name: Upload Artifact
42
  uses: actions/upload-artifact@v4
43
  with:
.github/workflows/pyinstaller-app.yml CHANGED
@@ -69,17 +69,16 @@ jobs:
69
  pip install pyside6
70
  - name: Build
71
  run: |
72
- pyinstaller -F -w -i qt/assets/icon.ico qt/app.py
73
  mv dist Formulator
74
- mkdir Formulator/qt
75
- mv qt/assets Formulator/qt/assets
76
  mkdir ${{ env.PACKAGENAME }}
77
  mv Formulator ${{ env.PACKAGENAME }}
78
  7z a -t7z -r "$($Env:PACKAGENAME + '.7z')" "Formulator"
79
  - name: Upload
80
  uses: actions/upload-artifact@v4
81
  with:
82
- name: Formulator
83
  path: ${{ env.PACKAGENAME }}
84
  - name: upload-win
85
  uses: actions/upload-release-asset@v1
@@ -90,3 +89,45 @@ jobs:
90
  asset_path: ${{ env.PACKAGENAME }}.7z
91
  asset_name: ${{ env.PACKAGENAME }}.7z
92
  asset_content_type: application/zip
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  pip install pyside6
70
  - name: Build
71
  run: |
72
+ pyinstaller -F -w -i assets/icon.ico qt/app.py
73
  mv dist Formulator
74
+ mv assets Formulator/assets
 
75
  mkdir ${{ env.PACKAGENAME }}
76
  mv Formulator ${{ env.PACKAGENAME }}
77
  7z a -t7z -r "$($Env:PACKAGENAME + '.7z')" "Formulator"
78
  - name: Upload
79
  uses: actions/upload-artifact@v4
80
  with:
81
+ name: ${{ env.PACKAGENAME }}
82
  path: ${{ env.PACKAGENAME }}
83
  - name: upload-win
84
  uses: actions/upload-release-asset@v1
 
89
  asset_path: ${{ env.PACKAGENAME }}.7z
90
  asset_name: ${{ env.PACKAGENAME }}.7z
91
  asset_content_type: application/zip
92
+
93
+ macos:
94
+ needs: [ setup, release ]
95
+ runs-on: macos-11
96
+ env:
97
+ PACKAGENAME: ${{ needs.setup.outputs.PACKAGE_PREFIX }}_macos_x64
98
+ steps:
99
+ - uses: actions/checkout@v4
100
+ - name: Set up Python 3.11
101
+ uses: actions/setup-python@v5
102
+ with:
103
+ python-version: "3.11"
104
+
105
+ - name: Install dependencies
106
+ run: |
107
+ python -m pip install --upgrade pip
108
+ pip install pyinstaller
109
+ pip install pyside6
110
+ brew install create-dmg
111
+ - name: Build
112
+ run: |
113
+ cp assets/icon.icns ./
114
+ pyinstaller --clean --onedir --name Formulator --strip --windowed -i icon.icns qt/app.py
115
+ rm -rf dist/Formulator
116
+ ln -s /Applications/ dist/Applications
117
+ xattr -cr dist/Formulator.app
118
+ create-dmg --volname "Formulator" ${{ env.PACKAGENAME }}.dmg dist/
119
+ zip -9 Formulator.zip ${{ env.PACKAGENAME }}.dmg
120
+ - name: Upload
121
+ uses: actions/upload-artifact@v2
122
+ with:
123
+ name: ${{ env.PACKAGENAME }}
124
+ path: Formulator.zip
125
+ - name: upload-macos
126
+ uses: actions/upload-release-asset@v1
127
+ env:
128
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
129
+ with:
130
+ upload_url: ${{ needs.release.outputs.Up_Url }}
131
+ asset_path: ${{ env.PACKAGENAME }}.dmg
132
+ asset_name: ${{ env.PACKAGENAME }}.dmg
133
+ asset_content_type: application/gzip
{qt → assets}/constant.py RENAMED
@@ -1,20 +1,7 @@
1
  import os
2
 
3
- from dataclasses import dataclass
4
- from typing import Type, List, Dict, Union, Tuple
5
-
6
- from base.attribute import Attribute
7
- from base.buff import Buff
8
- from base.gain import Gain
9
- from base.skill import Skill
10
-
11
- # from general.gains import equipment
12
-
13
- from schools import bei_ao_jue
14
-
15
  """ Directory """
16
- # ASSETS_DIR = os.path.join(os.getcwd(), "qt/assets")
17
- ASSETS_DIR = "qt/assets"
18
  EQUIPMENTS_DIR = os.path.join(ASSETS_DIR, "equipments")
19
  ENCHANTS_DIR = os.path.join(ASSETS_DIR, "enchants")
20
  STONES_DIR = os.path.join(ASSETS_DIR, "stones.json")
 
1
  import os
2
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  """ Directory """
4
+ ASSETS_DIR = "assets"
 
5
  EQUIPMENTS_DIR = os.path.join(ASSETS_DIR, "equipments")
6
  ENCHANTS_DIR = os.path.join(ASSETS_DIR, "enchants")
7
  STONES_DIR = os.path.join(ASSETS_DIR, "stones.json")
{qt/assets → assets}/enchants/belt RENAMED
File without changes
{qt/assets → assets}/enchants/bottoms RENAMED
File without changes
{qt/assets → assets}/enchants/hat RENAMED
File without changes
{qt/assets → assets}/enchants/jacket RENAMED
File without changes
{qt/assets → assets}/enchants/necklace RENAMED
File without changes
{qt/assets → assets}/enchants/pendant RENAMED
File without changes
{qt/assets → assets}/enchants/primary_weapon RENAMED
File without changes
{qt/assets → assets}/enchants/ring RENAMED
File without changes
{qt/assets → assets}/enchants/secondary_weapon RENAMED
File without changes
{qt/assets → assets}/enchants/shoes RENAMED
File without changes
{qt/assets → assets}/enchants/tertiary_weapon RENAMED
File without changes
{qt/assets → assets}/enchants/wrist RENAMED
File without changes
{qt/assets → assets}/equipments/belt RENAMED
File without changes
{qt/assets → assets}/equipments/bottoms RENAMED
File without changes
{qt/assets → assets}/equipments/hat RENAMED
File without changes
{qt/assets → assets}/equipments/jacket RENAMED
File without changes
{qt/assets → assets}/equipments/necklace RENAMED
File without changes
{qt/assets → assets}/equipments/pendant RENAMED
File without changes
{qt/assets → assets}/equipments/primary_weapon RENAMED
File without changes
{qt/assets → assets}/equipments/ring RENAMED
File without changes
{qt/assets → assets}/equipments/secondary_weapon RENAMED
File without changes
{qt/assets → assets}/equipments/shoes RENAMED
File without changes
{qt/assets → assets}/equipments/tertiary_weapon RENAMED
File without changes
{qt/assets → assets}/equipments/wrist RENAMED
File without changes
assets/icon.icns ADDED
Binary file (2.73 kB). View file
 
{qt/assets → assets}/icon.ico RENAMED
File without changes
assets/stones.json ADDED
The diff for this file is too large to render. See raw diff
 
get_assets.py CHANGED
@@ -5,10 +5,10 @@ from functools import cache
5
  import requests
6
  from tqdm import tqdm
7
 
8
- from qt.constant import MAX_BASE_ATTR, MAX_MAGIC_ATTR, MAX_EMBED_ATTR, MAX_ENCHANT_ATTR
9
- from qt.constant import ATTR_TYPE_TRANSLATE
10
- from qt.constant import MAX_STONE_ATTR, MAX_STONE_LEVEL
11
- from qt.constant import EQUIPMENTS_DIR, ENCHANTS_DIR, STONES_DIR
12
  from schools import SUPPORT_SCHOOL
13
 
14
  KINDS = set(sum([[school.kind, school.major] for school in SUPPORT_SCHOOL.values()], []))
@@ -320,6 +320,7 @@ def get_stones_list():
320
  if detail := get_stone_detail(row):
321
  current = result
322
  for attr in detail['attr']:
 
323
  if attr not in current:
324
  current[attr] = {}
325
  current = current[attr]
@@ -370,4 +371,4 @@ if __name__ == '__main__':
370
  json.dump(
371
  get_weapon_enchants(), open(os.path.join(ENCHANTS_DIR, "secondary_weapon"), "w", encoding="utf-8")
372
  )
373
- # json.dump(get_stones_list(), open(STONES_DIR, "w", encoding="utf-8"), ensure_ascii=False)
 
5
  import requests
6
  from tqdm import tqdm
7
 
8
+ from assets.constant import MAX_BASE_ATTR, MAX_MAGIC_ATTR, MAX_EMBED_ATTR, MAX_ENCHANT_ATTR, STONES_DIR
9
+ from assets.constant import ATTR_TYPE_TRANSLATE
10
+ from assets.constant import MAX_STONE_ATTR, MAX_STONE_LEVEL
11
+ from assets.constant import EQUIPMENTS_DIR, ENCHANTS_DIR
12
  from schools import SUPPORT_SCHOOL
13
 
14
  KINDS = set(sum([[school.kind, school.major] for school in SUPPORT_SCHOOL.values()], []))
 
320
  if detail := get_stone_detail(row):
321
  current = result
322
  for attr in detail['attr']:
323
+ attr = ATTR_TYPE_TRANSLATE[attr]
324
  if attr not in current:
325
  current[attr] = {}
326
  current = current[attr]
 
371
  json.dump(
372
  get_weapon_enchants(), open(os.path.join(ENCHANTS_DIR, "secondary_weapon"), "w", encoding="utf-8")
373
  )
374
+ json.dump(get_stones_list(), open(STONES_DIR, "w", encoding="utf-8"), ensure_ascii=False)
{qt → gr}/__init__.py RENAMED
File without changes
gr/app.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from gr.components.top import TopComponent
2
+ from gr.components.equipments import EquipmentsComponent
3
+ from gr.components.talents import TalentsComponent
4
+ from gr.components.recipes import RecipesComponent
5
+ from gr.components.combat import CombatComponent
6
+
7
+ from gr.scripts.top import top_script
8
+ from gr.scripts.equipments import equipments_script
9
+ from gr.scripts.talents import talents_script
10
+ from gr.scripts.recipes import recipes_script
11
+ from gr.scripts.combat import combat_script
12
+
13
+ import gradio as gr
14
+
15
+
16
+ def start():
17
+ with gr.Blocks(theme=gr.themes.Soft()) as app:
18
+ top_component = TopComponent()
19
+ with gr.Group(visible=False) as bottom_component:
20
+ with gr.Tab("装备"):
21
+ equipments_component = EquipmentsComponent()
22
+ with gr.Tab("奇穴"):
23
+ talents_component = TalentsComponent()
24
+ with gr.Tab("秘籍"):
25
+ recipes_component = RecipesComponent()
26
+ with gr.Tab("战斗"):
27
+ combat_component = CombatComponent()
28
+
29
+ parser = top_script(top_component, bottom_component,
30
+ equipments_component, talents_component, recipes_component,
31
+ combat_component)
32
+ equipments = equipments_script(equipments_component)
33
+ talents = talents_script(talents_component)
34
+ recipes = recipes_script(recipes_component)
35
+ combat_script(parser, talents, recipes, equipments, combat_component)
36
+
37
+ app.queue()
38
+ app.launch(allowed_paths=["."])
39
+
40
+
41
+ if __name__ == '__main__':
42
+ start()
{qt/scripts → gr/components}/__init__.py RENAMED
File without changes
gr/components/combat.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ from base.constant import SHIELD_BASE_MAP
4
+
5
+
6
+ class CombatComponent:
7
+ def __init__(self):
8
+ with gr.Row():
9
+ self.combat_duration = gr.Slider(label="战斗时长", step=0.01)
10
+ target_levels = list(SHIELD_BASE_MAP)
11
+ self.target_level = gr.Dropdown(choices=target_levels, value=target_levels[0], label="目标等级")
12
+ self.formulate = gr.Button("开始模拟")
13
+
14
+ with gr.Tab("属性"):
15
+ with gr.Row():
16
+ self.init_attribute = gr.Textbox("初始属性")
17
+ self.final_attribute = gr.Textbox("增益后属性")
18
+ with gr.Tab("伤害总结"):
19
+ self.skill_select = gr.Dropdown(label="选择技能")
20
+ self.status_select = gr.Dropdown(label="选择增益")
21
+ with gr.Row():
22
+ self.damage_detail = gr.Textbox(label="伤害细节")
23
+ self.gradient_detail = gr.Textbox(label="属性收益")
24
+ with gr.Tab("战斗统计"):
25
+ with gr.Row():
26
+ self.summary = gr.DataFrame(label="战斗总结", headers=["技能/次数", "命中/%", "会心/%", "伤害/%"], scale=3)
27
+ with gr.Column(scale=1):
28
+ self.dps = gr.Textbox("每秒伤害")
29
+ self.gradient = gr.Textbox("属性收益")
30
+
31
+
32
+
gr/components/equipments.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import os
3
+
4
+ from assets.constant import POSITION_MAP, STONES_POSITIONS, EQUIPMENTS_DIR, ENCHANTS_DIR, STONES_DIR, MAX_STONE_ATTR, \
5
+ ATTR_TYPE_TRANSLATE
6
+ from assets.constant import EMBED_POSITIONS, MAX_EMBED_LEVEL, MAX_STONE_LEVEL, SPECIAL_ENCHANT_POSITIONS
7
+ import gradio as gr
8
+
9
+
10
+ class EquipmentComponent:
11
+ def __init__(self, label):
12
+ self.position = POSITION_MAP[label]
13
+ self.equipment_json = json.load(open(os.path.join(EQUIPMENTS_DIR, self.position), encoding="utf-8"))
14
+ self.equipment_mapping = {v['id']: k for k, v in self.equipment_json.items()}
15
+ self.enchant_json = json.load(open(os.path.join(ENCHANTS_DIR, self.position), encoding="utf-8"))
16
+ self.enchant_mapping = {v['id']: k for k, v in self.enchant_json.items()}
17
+
18
+ self.equipment = gr.Dropdown(label="装备")
19
+ with gr.Row():
20
+ with gr.Column(scale=3) as self.detail:
21
+ with gr.Row():
22
+ if not self.enchant_json:
23
+ self.enchant = gr.Dropdown(visible=False)
24
+ else:
25
+ self.enchant = gr.Dropdown(choices=[""] + list(self.enchant_json), label="附魔")
26
+
27
+ if self.position not in SPECIAL_ENCHANT_POSITIONS:
28
+ self.special_enchant = gr.Checkbox(visible=False)
29
+ else:
30
+ self.special_enchant = gr.Checkbox(label="大附魔")
31
+
32
+ with gr.Row():
33
+ self.strength_level = gr.Dropdown(label="精炼等级")
34
+
35
+ self.embed_levels = []
36
+ for i in range(EMBED_POSITIONS[self.position]):
37
+ embed_level = gr.Dropdown(
38
+ choices=list(range(MAX_EMBED_LEVEL + 1)), value=MAX_EMBED_LEVEL, visible=False
39
+ )
40
+ self.embed_levels.append(embed_level)
41
+
42
+ with gr.Row():
43
+ if self.position not in STONES_POSITIONS:
44
+ self.stones_json = None
45
+ self.stone_level = gr.Dropdown(visible=False)
46
+ self.stone_attrs = [gr.Dropdown(visible=False)] * MAX_STONE_ATTR
47
+ else:
48
+ self.stones_json = json.load(open(STONES_DIR, encoding="utf-8"))
49
+
50
+ self.stone_level = gr.Dropdown(
51
+ choices=list(range(MAX_STONE_LEVEL + 1)), value=MAX_STONE_LEVEL, label="五彩石等级"
52
+ )
53
+ self.stone_attrs = []
54
+ for i in range(MAX_STONE_ATTR):
55
+ if i:
56
+ stone_attr = gr.Dropdown(label=f"五彩石属性-{i + 1}")
57
+ else:
58
+ stone_attr = gr.Dropdown(choices=list(self.stones_json), label=f"五彩石属性-{i + 1}")
59
+ self.stone_attrs.append(stone_attr)
60
+
61
+ self.base_attr = gr.Textbox(label="基本属性", visible=False, scale=1, lines=5)
62
+ self.magic_attr = gr.Textbox(label="精炼属性", visible=False, scale=1, lines=5)
63
+ self.embed_attr = gr.Textbox(label="镶嵌属性", visible=False, scale=1, lines=5)
64
+
65
+
66
+ class EquipmentsComponent:
67
+ def __init__(self):
68
+ super().__init__()
69
+ self.equipments = {}
70
+ for label in POSITION_MAP:
71
+ with gr.Tab(label):
72
+ self.equipments[label] = EquipmentComponent(label)
73
+
74
+ def __getitem__(self, item) -> EquipmentComponent:
75
+ return self.equipments[item]
76
+
77
+ def items(self):
78
+ return self.equipments.items()
79
+
80
+ def values(self):
81
+ return self.equipments.values()
gr/components/recipes.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ from assets.constant import MAX_RECIPE_SKILLS, MAX_RECIPES
4
+
5
+
6
+ class RecipesComponent:
7
+ def __init__(self):
8
+
9
+ self.recipes = []
10
+
11
+ columns = 6
12
+ rows = MAX_RECIPE_SKILLS // columns
13
+
14
+ for i in range(rows):
15
+ with gr.Row():
16
+ for j in range(columns):
17
+ recipe = gr.Dropdown(multiselect=True, max_choices=MAX_RECIPES, visible=False)
18
+ self.recipes.append(recipe)
19
+
20
+ def __getitem__(self, item) -> gr.Dropdown:
21
+ return self.recipes[item]
22
+
23
+ def values(self) -> list[gr.Dropdown]:
24
+ return self.recipes
gr/components/talents.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List
2
+
3
+ import gradio as gr
4
+
5
+ from assets.constant import MAX_TALENTS
6
+
7
+
8
+ class TalentsComponent:
9
+ def __init__(self):
10
+ self.talents = []
11
+
12
+ rows = 2
13
+ columns = MAX_TALENTS // rows
14
+
15
+ for i in range(rows):
16
+ with gr.Row():
17
+ for j in range(columns):
18
+ talent = gr.Dropdown(label=f"奇穴第{i * columns + j + 1}层")
19
+ self.talents.append(talent)
20
+
21
+ def __getitem__(self, item) -> gr.Dropdown:
22
+ return self.talents[item]
23
+
24
+ def values(self) -> List[gr.Dropdown]:
25
+ return self.talents
gr/components/top.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+
4
+ class TopComponent:
5
+ def __init__(self):
6
+ with gr.Row():
7
+ self.upload_log = gr.UploadButton("上传JCL")
8
+ with gr.Column():
9
+ self.upload_json = gr.UploadButton("上传JSON")
10
+ self.save_json = gr.DownloadButton("保存JSON", visible=False)
11
+ with gr.Column(scale=2):
12
+ self.player_select = gr.Dropdown(label="选择角色", visible=False)
13
+ self.target_select = gr.Dropdown(label="选择目标", visible=False)
gr/scripts/__init__.py ADDED
File without changes
gr/scripts/combat.py ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Dict
2
+
3
+ from gr.components.combat import CombatComponent
4
+ from assets.constant import ATTR_TYPE_TRANSLATE
5
+ # from gr.scripts.bonuses import Bonuses
6
+ # from gr.scripts.consumables import Consumables
7
+ from gr.scripts.top import Parser
8
+ from gr.scripts.equipments import Equipments
9
+ from gr.scripts.recipes import Recipes
10
+ from gr.scripts.talents import Talents
11
+ from utils.analyzer import analyze_details, Detail
12
+
13
+ import gradio as gr
14
+
15
+ FULL_SPACE = "\u3000"
16
+
17
+
18
+ def attribute_content(display_attrs, attribute):
19
+ content = []
20
+ for attr, name in display_attrs.items():
21
+ value = getattr(attribute, attr)
22
+ if isinstance(value, int):
23
+ content.append([name, f"{value}"])
24
+ else:
25
+ content.append([name, f"{round(value * 100, 2)}%"])
26
+ return content
27
+
28
+
29
+ def summary_content(summary: Dict[str, Detail], total_damage):
30
+ content = []
31
+ for skill in sorted(summary, key=lambda x: summary[x].expected_damage, reverse=True):
32
+ detail = summary[skill]
33
+ critical = round(detail.critical_count, 2)
34
+ critical_rate = round(detail.critical_count / detail.count * 100, 2)
35
+ hit = round(detail.count - critical, 2)
36
+ hit_rate = round(100 - critical_rate, 2)
37
+ damage = round(detail.expected_damage, 2)
38
+ damage_rate = round(damage / total_damage * 100, 2)
39
+ content.append(
40
+ [f"{skill}/{detail.count}",
41
+ f"{hit}/{hit_rate}%", f"{critical}/{critical_rate}%", f"{damage}/{damage_rate}%"]
42
+ )
43
+ return content
44
+
45
+
46
+ def gradient_content(gradients, total_damage):
47
+ return "\n".join(
48
+ ATTR_TYPE_TRANSLATE[k].ljust(10, FULL_SPACE) + f"{round(v / total_damage * 100, 2)}%"
49
+ for k, v in gradients.items()
50
+ )
51
+
52
+
53
+ def detail_content(detail: Detail):
54
+ damage_content = "\n".join([
55
+ "命中伤害\t" + f"{round(detail.damage)}",
56
+ "会心伤害\t" + f"{round(detail.critical_damage)}",
57
+ "期望伤害\t" + f"{round(detail.expected_damage)}",
58
+ "期望会心\t" + f"{round(detail.critical_strike * 100, 2)}%",
59
+ "实际会心\t" + f"{round(detail.actual_critical_strike * 100, 2)}%",
60
+ "统计数量\t" + f"{detail.count}"
61
+ ])
62
+
63
+ return damage_content, gradient_content(detail.gradients, detail.expected_damage)
64
+
65
+
66
+ def combat_script(
67
+ parser: Parser,
68
+ talents: Talents, recipes: Recipes, equipments: Equipments,
69
+ # consumables: Consumables, bonuses: Bonuses
70
+ combat_component: CombatComponent,
71
+ ):
72
+ def formulate(target_level, duration):
73
+ combat_update = {}
74
+ record = parser.current_records
75
+ school = parser.current_school
76
+
77
+ attribute = school.attribute()
78
+ attribute.target_level = target_level
79
+ for attr, value in equipments.attrs.items():
80
+ setattr(attribute, attr, getattr(attribute, attr) + value)
81
+ combat_update[combat_component.init_attribute] = gr.update(
82
+ value=attribute_content(school.display_attrs, attribute)
83
+ )
84
+ # for attr, value in consumables.attrs.items():
85
+ # setattr(attribute, attr, getattr(attribute, attr) + value)
86
+
87
+ equipment_gains = [school.gains[gain] for gain in equipments.gains]
88
+ talent_gains = [school.talent_gains[school.talent_encoder[talent]] for talent in talents.gains]
89
+ recipe_gains = [
90
+ school.recipe_gains[skill][recipe]
91
+ for i, skill in enumerate(school.recipe_gains)
92
+ for recipe in recipes.gains[i]
93
+ ]
94
+ gains = equipment_gains + talent_gains + recipe_gains # + bonuses.gains
95
+
96
+ for gain in gains:
97
+ gain.add(attribute, school.skills, school.buffs)
98
+
99
+ combat_update[combat_component.final_attribute] = gr.update(
100
+ value=attribute_content(school.display_attrs, attribute)
101
+ )
102
+ total, summary, details = analyze_details(record, duration, attribute, school)
103
+
104
+ for gain in gains:
105
+ gain.sub(attribute, school.skills, school.buffs)
106
+
107
+ combat_update[combat_component.dps] = gr.update(value=round(total.expected_damage / duration))
108
+
109
+ combat_update[combat_component.gradient] = gradient_content(total.gradients, total.expected_damage)
110
+ #
111
+ # dashboard_widget.detail_widget.details = details
112
+ # set_skills()
113
+
114
+ combat_update[combat_component.summary] = summary_content(summary, total.expected_damage)
115
+ return combat_update
116
+
117
+ combat_component.formulate.click(
118
+ formulate,
119
+ [combat_component.target_level, combat_component.combat_duration],
120
+ [combat_component.init_attribute, combat_component.final_attribute,
121
+ combat_component.dps, combat_component.gradient, combat_component.summary]
122
+ )
123
+
124
+ # def set_skills():
125
+ # detail_widget = dashboard_widget.detail_widget
126
+ # detail_widget.skill_combo.set_items(list(detail_widget.details), keep_index=True, default_index=-1)
127
+ # set_status(None)
128
+ #
129
+ # def set_status(_):
130
+ # detail_widget = dashboard_widget.detail_widget
131
+ # skill = detail_widget.skill_combo.combo_box.currentText()
132
+ # detail_widget.status_combo.set_items(
133
+ # list(detail_widget.details.get(skill, {})), keep_index=True, default_index=-1
134
+ # )
135
+ # set_detail(None)
136
+ #
137
+ # dashboard_widget.detail_widget.skill_combo.combo_box.currentTextChanged.connect(set_status)
138
+ #
139
+ # def set_detail(_):
140
+ # detail_widget = dashboard_widget.detail_widget
141
+ # skill = detail_widget.skill_combo.combo_box.currentText()
142
+ # status = detail_widget.status_combo.combo_box.currentText()
143
+ # if detail := detail_widget.details.get(skill, {}).get(status):
144
+ # damage_content, gradient_content = detail_content(detail)
145
+ # detail_widget.damage_detail.set_content(damage_content)
146
+ # detail_widget.gradient_detail.set_content(gradient_content)
147
+ # else:
148
+ # detail_widget.damage_detail.table.clear()
149
+ # detail_widget.gradient_detail.table.clear()
150
+ #
151
+ # dashboard_widget.detail_widget.status_combo.combo_box.currentTextChanged.connect(set_detail)
{qt → gr}/scripts/equipments.py RENAMED
@@ -1,11 +1,15 @@
1
  from collections import defaultdict
2
  from typing import Dict, List, Union, Tuple
3
 
 
 
4
  from general.gains.equipment import EQUIPMENT_GAINS
5
- from qt.components.equipments import EquipmentsWidget
6
- from qt.constant import POSITION_MAP, STONES_POSITIONS, EMBED_POSITIONS
7
- from qt.constant import ATTR_TYPE_TRANSLATE, ATTR_TYPE_TRANSLATE_REVERSE
8
- from qt.constant import STRENGTH_COF, EMBED_COF, MAX_STRENGTH_LEVEL, MAX_EMBED_LEVEL
 
 
9
 
10
 
11
  class Enchant:
@@ -97,18 +101,27 @@ class Equipment:
97
 
98
  @property
99
  def base_attr_content(self):
100
- return [[ATTR_TYPE_TRANSLATE[k], str(v)] for k, v in self.base_attr.items()]
 
 
101
 
102
  @property
103
  def magic_attr_content(self):
104
  if strength_attr := self.strength_attr:
105
- return [[ATTR_TYPE_TRANSLATE[k], f"{v}(+{strength_attr[k]})"] for k, v in self.magic_attr.items()]
 
 
 
106
  else:
107
- return [[ATTR_TYPE_TRANSLATE[k], f"{v}"] for k, v in self.magic_attr.items()]
 
 
108
 
109
  @property
110
  def embed_attr_content(self):
111
- return [[ATTR_TYPE_TRANSLATE[k], str(v)] for k, v in self.embed_attr.items()]
 
 
112
 
113
 
114
  class Equipments:
@@ -117,7 +130,7 @@ class Equipments:
117
 
118
  def __getitem__(self, item) -> Equipment:
119
  return self.equipments[item]
120
-
121
  @property
122
  def attrs(self):
123
  final_attrs = defaultdict(int)
@@ -177,67 +190,80 @@ class Equipments:
177
  return [tuple(gain) if isinstance(gain, list) else gain for gain in final_gains]
178
 
179
 
180
- def equipments_script(equipments_widget: EquipmentsWidget):
181
  equipments = Equipments()
182
 
183
- def equipment_update(label):
184
- widget = equipments_widget[label]
185
- equipment = equipments[label]
186
-
187
  def inner(equipment_name):
188
-
 
189
  if not equipment_name:
190
  equipment.clear()
191
- widget.detail_widget.hide()
192
- return
 
 
193
 
 
194
  if equipment.strength_level == equipment.max_strength:
195
  max_strength = True
196
  else:
197
  max_strength = False
198
 
199
  equipment.name = equipment_name
200
- equipment_detail = widget.equipment_json[equipment_name]
201
  for k, v in equipment_detail.items():
202
  setattr(equipment, k, v)
203
 
204
  if equipment.base:
205
- widget.base_attr.set_content(equipment.base_attr_content)
206
- widget.base_attr.show()
 
207
  else:
208
- widget.base_attr.hide()
 
 
 
 
 
 
 
 
209
 
210
  if max_strength:
211
  equipment.strength_level = equipment.max_strength
212
 
213
- widget.strength_level.set_items([str(i) for i in range(equipment.max_strength + 1)])
214
- widget.strength_level.combo_box.setCurrentIndex(equipment.strength_level)
 
 
 
 
215
 
216
  if equipment.embed:
217
- for i, (attr, value) in enumerate(equipment.embed.items()):
218
- widget.embed_levels[i].set_label(f"镶嵌等级-{ATTR_TYPE_TRANSLATE[attr]}\t")
219
- widget.embed_attr.set_content(equipment.embed_attr_content)
220
- widget.embed_attr.show()
 
 
 
 
221
  else:
222
- widget.embed_attr.hide()
 
223
 
224
- if isinstance(equipment.special_enchant, list):
225
- equipment.special_enchant = tuple(equipment.special_enchant)
226
-
227
- if equipment.special_enchant:
228
- widget.special_enchant.set_text(EQUIPMENT_GAINS[equipment.special_enchant].gain_name)
229
-
230
- widget.detail_widget.show()
231
 
232
  return inner
233
 
234
- def enchant_update(label):
235
- widget = equipments_widget.equipments[label]
236
- equipment = equipments[label]
237
-
238
  def inner(enchant_name):
 
 
239
  if enchant_name:
240
- enchant_detail = widget.enchant_json[enchant_name]
241
  equipment.enchant.name = enchant_name
242
  for k, v in enchant_detail.items():
243
  setattr(equipment.enchant, k, v)
@@ -246,89 +272,99 @@ def equipments_script(equipments_widget: EquipmentsWidget):
246
 
247
  return inner
248
 
249
- def special_enchant_update(label):
250
- widget = equipments_widget.equipments[label]
251
- equipment = equipments[label]
252
-
253
- def inner(_):
254
- if widget.special_enchant and widget.special_enchant.radio_button.isChecked():
255
  equipment.special_enchant_gain = [equipment.special_enchant]
256
  else:
257
  equipment.special_enchant_gain = []
258
 
259
  return inner
260
 
261
- def strength_level_update(label):
262
- widget = equipments_widget.equipments[label]
263
- equipment = equipments[label]
264
-
265
- def inner(index):
266
- equipment.strength_level = index
267
  if magic_attr_content := equipment.magic_attr_content:
268
- widget.magic_attr.set_content(magic_attr_content)
269
- widget.magic_attr.show()
270
  else:
271
- widget.magic_attr.hide()
272
 
273
  return inner
274
 
275
- def embed_level_update(i, label):
276
- widget = equipments_widget.equipments[label]
277
- equipment = equipments[label]
278
-
279
- def inner(index):
280
- equipment.embed_levels[i] = index
281
  if embed_attr_content := equipment.embed_attr_content:
282
- widget.embed_attr.set_content(embed_attr_content)
283
- widget.embed_attr.show()
284
  else:
285
- widget.embed_attr.hide()
286
 
287
  return inner
288
 
289
- def stone_update(label):
290
- widget = equipments_widget.equipments[label]
291
- equipment = equipments[label]
292
-
293
- def inner(_):
294
- level = widget.stone_level.combo_box.currentText()
295
 
296
- current = widget.stones_json
297
  i = 0
298
- while i < len(widget.stone_attrs):
299
- attr = ATTR_TYPE_TRANSLATE_REVERSE.get(widget.stone_attrs[i].combo_box.currentText())
300
- if attr in current:
301
- current = current[attr]
302
  i += 1
303
  else:
304
  break
305
- if level in current:
306
- for k, v in current[level].items():
 
 
 
307
  setattr(equipment.stone, k, v)
308
- else:
309
- widget.stone_attrs[i].set_items([""] + [ATTR_TYPE_TRANSLATE[k] for k in current])
310
- equipment.stone = Stone()
 
 
 
311
 
312
  i += 1
313
- while i < len(widget.stone_attrs):
314
- widget.stone_attrs[i].set_items([""])
 
 
315
  i += 1
 
316
 
317
  return inner
318
 
319
- for equipment_label, equipment_widget in equipments_widget.items():
320
-
321
- equipment_widget.equipment.combo_box.currentTextChanged.connect(equipment_update(equipment_label))
322
- if equipment_widget.special_enchant:
323
- equipment_widget.special_enchant.radio_button.clicked.connect(special_enchant_update(equipment_label))
324
- if equipment_widget.enchant:
325
- equipment_widget.enchant.combo_box.currentTextChanged.connect(enchant_update(equipment_label))
326
- equipment_widget.strength_level.combo_box.currentIndexChanged.connect(strength_level_update(equipment_label))
327
- for n, embed_widget in enumerate(equipment_widget.embed_levels):
328
- embed_widget.combo_box.currentIndexChanged.connect(embed_level_update(n, equipment_label))
329
- if equipment_widget.stones_json:
330
- equipment_widget.stone_level.combo_box.currentIndexChanged.connect(stone_update(equipment_label))
331
- for stone_attr in equipment_widget.stone_attrs:
332
- stone_attr.combo_box.currentIndexChanged.connect(stone_update(equipment_label))
 
 
 
 
 
 
 
 
 
 
 
333
 
334
  return equipments
 
1
  from collections import defaultdict
2
  from typing import Dict, List, Union, Tuple
3
 
4
+ import gradio as gr
5
+
6
  from general.gains.equipment import EQUIPMENT_GAINS
7
+ from gr.components.equipments import EquipmentsComponent
8
+ from assets.constant import POSITION_MAP, STONES_POSITIONS, EMBED_POSITIONS
9
+ from assets.constant import ATTR_TYPE_TRANSLATE
10
+ from assets.constant import STRENGTH_COF, EMBED_COF, MAX_STRENGTH_LEVEL, MAX_EMBED_LEVEL
11
+
12
+ FULL_SPACE = "\u3000"
13
 
14
 
15
  class Enchant:
 
101
 
102
  @property
103
  def base_attr_content(self):
104
+ return "\n".join(
105
+ ATTR_TYPE_TRANSLATE[k].ljust(10, FULL_SPACE) + str(v) for k, v in self.base_attr.items()
106
+ )
107
 
108
  @property
109
  def magic_attr_content(self):
110
  if strength_attr := self.strength_attr:
111
+ return "\n".join(
112
+ ATTR_TYPE_TRANSLATE[k].ljust(10, FULL_SPACE) + f"{v}(+{strength_attr[k]})"
113
+ for k, v in self.magic_attr.items()
114
+ )
115
  else:
116
+ return "\n".join(
117
+ ATTR_TYPE_TRANSLATE[k].ljust(10, FULL_SPACE) + str(v) for k, v in self.magic_attr.items()
118
+ )
119
 
120
  @property
121
  def embed_attr_content(self):
122
+ return "\n".join(
123
+ ATTR_TYPE_TRANSLATE[k].ljust(10, FULL_SPACE) + str(v) for k, v in self.embed_attr.items()
124
+ )
125
 
126
 
127
  class Equipments:
 
130
 
131
  def __getitem__(self, item) -> Equipment:
132
  return self.equipments[item]
133
+
134
  @property
135
  def attrs(self):
136
  final_attrs = defaultdict(int)
 
190
  return [tuple(gain) if isinstance(gain, list) else gain for gain in final_gains]
191
 
192
 
193
+ def equipments_script(equipments_component: EquipmentsComponent):
194
  equipments = Equipments()
195
 
196
+ def equipment_changed(label):
 
 
 
197
  def inner(equipment_name):
198
+ equipment = equipments[label]
199
+ component = equipments_component[label]
200
  if not equipment_name:
201
  equipment.clear()
202
+ return {
203
+ component.equipment: gr.update(value=""),
204
+ component.detail: gr.update(visible=False)
205
+ }
206
 
207
+ equipment_update = {}
208
  if equipment.strength_level == equipment.max_strength:
209
  max_strength = True
210
  else:
211
  max_strength = False
212
 
213
  equipment.name = equipment_name
214
+ equipment_detail = component.equipment_json[equipment_name]
215
  for k, v in equipment_detail.items():
216
  setattr(equipment, k, v)
217
 
218
  if equipment.base:
219
+ equipment_update[component.base_attr] = gr.update(
220
+ value=equipment.base_attr_content, visible=True
221
+ )
222
  else:
223
+ equipment_update[component.base_attr] = gr.update(visible=False)
224
+
225
+ if isinstance(equipment.special_enchant, list):
226
+ equipment.special_enchant = tuple(equipment.special_enchant)
227
+
228
+ if equipment.special_enchant:
229
+ equipment_update[component.special_enchant] = gr.update(
230
+ label=EQUIPMENT_GAINS[equipment.special_enchant].gain_name
231
+ )
232
 
233
  if max_strength:
234
  equipment.strength_level = equipment.max_strength
235
 
236
+ equipment_update[component.strength_level] = gr.update(
237
+ choices=list(range(equipment.max_strength + 1)), value=equipment.strength_level
238
+ )
239
+ equipment_update[component.magic_attr] = gr.update(
240
+ value=equipment.magic_attr_content, visible=True
241
+ )
242
 
243
  if equipment.embed:
244
+ for i, attr in enumerate(equipment.embed):
245
+ embed_level_component = component.embed_levels[i]
246
+ equipment_update[embed_level_component] = gr.update(
247
+ label=f"镶嵌等级-{ATTR_TYPE_TRANSLATE[attr]}", visible=True
248
+ )
249
+ equipment_update[component.embed_attr] = gr.update(
250
+ value=equipment.embed_attr_content, visible=True
251
+ )
252
  else:
253
+ for embed_level_component in component.embed_levels:
254
+ equipment_update[embed_level_component] = gr.update(visible=False)
255
 
256
+ equipment_update[component.detail] = gr.update(visible=True)
257
+ return equipment_update
 
 
 
 
 
258
 
259
  return inner
260
 
261
+ def enchant_changed(label):
 
 
 
262
  def inner(enchant_name):
263
+ equipment = equipments[label]
264
+ component = equipments_component[label]
265
  if enchant_name:
266
+ enchant_detail = component.enchant_json[enchant_name]
267
  equipment.enchant.name = enchant_name
268
  for k, v in enchant_detail.items():
269
  setattr(equipment.enchant, k, v)
 
272
 
273
  return inner
274
 
275
+ def special_enchant_changed(label):
276
+ def inner(special_enchant_check):
277
+ equipment = equipments[label]
278
+ component = equipments_component[label]
279
+ if component.special_enchant and special_enchant_check:
 
280
  equipment.special_enchant_gain = [equipment.special_enchant]
281
  else:
282
  equipment.special_enchant_gain = []
283
 
284
  return inner
285
 
286
+ def strength_level_changed(label):
287
+ def inner(strength_level):
288
+ equipment = equipments[label]
289
+ equipment.strength_level = strength_level
 
 
290
  if magic_attr_content := equipment.magic_attr_content:
291
+ return gr.update(value=magic_attr_content, visible=True)
 
292
  else:
293
+ return gr.update(visible=False)
294
 
295
  return inner
296
 
297
+ def embed_level_changed(i, label):
298
+ def inner(embed_level):
299
+ equipment = equipments[label]
300
+ equipment.embed_levels[i] = embed_level
 
 
301
  if embed_attr_content := equipment.embed_attr_content:
302
+ return gr.update(value=embed_attr_content, visible=True)
 
303
  else:
304
+ return gr.update(visible=False)
305
 
306
  return inner
307
 
308
+ def stone_changed(label):
309
+ def inner(stone_level, *stone_attrs):
310
+ equipment = equipments[label]
311
+ component = equipments_component[label]
 
 
312
 
313
+ current = component.stones_json
314
  i = 0
315
+ for stone_attr in stone_attrs:
316
+ if stone_attr in current:
317
+ current = current[stone_attr]
 
318
  i += 1
319
  else:
320
  break
321
+
322
+ stone_update = {component.stone_level: gr.update()}
323
+ stone_level = str(stone_level)
324
+ if stone_level in current:
325
+ for k, v in current[stone_level].items():
326
  setattr(equipment.stone, k, v)
327
+ return stone_update
328
+
329
+ equipment.stone = Stone()
330
+ stone_update[component.stone_attrs[i]] = gr.Dropdown(
331
+ choices=list(current)
332
+ )
333
 
334
  i += 1
335
+ while i < len(stone_attrs):
336
+ stone_update[component.stone_attrs[i]] = gr.Dropdown(
337
+ choices=[]
338
+ )
339
  i += 1
340
+ return stone_update
341
 
342
  return inner
343
 
344
+ for equipment_label, equipment_component in equipments_component.items():
345
+ equipment_component.equipment.change(
346
+ equipment_changed(equipment_label), equipment_component.equipment,
347
+ [equipment_component.detail, equipment_component.special_enchant,
348
+ equipment_component.base_attr, equipment_component.magic_attr, equipment_component.embed_attr,
349
+ equipment_component.strength_level, *equipment_component.embed_levels]
350
+ )
351
+ equipment_component.enchant.change(enchant_changed(equipment_label), equipment_component.enchant)
352
+ equipment_component.special_enchant.change(
353
+ special_enchant_changed(equipment_label), equipment_component.special_enchant
354
+ )
355
+ equipment_component.strength_level.change(
356
+ strength_level_changed(equipment_label), equipment_component.strength_level, equipment_component.magic_attr
357
+ )
358
+ for n, embed_component in enumerate(equipment_component.embed_levels):
359
+ embed_component.change(
360
+ embed_level_changed(n, equipment_label), embed_component, equipment_component.embed_attr)
361
+ stone_components = [equipment_component.stone_level] + equipment_component.stone_attrs
362
+ equipment_component.stone_level.change(
363
+ stone_changed(equipment_label), stone_components, stone_components
364
+ )
365
+ for stone_attr_component in equipment_component.stone_attrs:
366
+ stone_attr_component.change(
367
+ stone_changed(equipment_label), stone_components, stone_components
368
+ )
369
 
370
  return equipments
{qt → gr}/scripts/recipes.py RENAMED
@@ -1,6 +1,6 @@
1
- from qt.components.recipes import RecipesWidget
2
 
3
- from qt.constant import MAX_RECIPE_SKILLS, MAX_RECIPES
4
 
5
 
6
  class Recipes:
@@ -15,25 +15,22 @@ class Recipes:
15
 
16
  @property
17
  def gains(self):
18
- return [recipe for recipes in self.recipes for recipe in recipes]
19
 
20
 
21
- def recipes_script(recipes_widget: RecipesWidget):
22
  recipes = Recipes()
23
 
24
- def recipe_update(i):
25
- widget = recipes_widget[i]
26
-
27
- def inner():
28
- skill = widget.label.text()
29
- if selected_items := widget.list.selectedItems():
30
- while len(selected_items) > MAX_RECIPES:
31
- selected_items.pop().setSelected(False)
32
- recipes[i] = [(skill, item.text()) for item in selected_items]
33
 
34
  return inner
35
 
36
- for n, recipe_widget in enumerate(recipes_widget.values()):
37
- recipe_widget.list.itemSelectionChanged.connect(recipe_update(n))
38
 
39
  return recipes
 
1
+ from gr.components.recipes import RecipesComponent
2
 
3
+ from assets.constant import MAX_RECIPE_SKILLS
4
 
5
 
6
  class Recipes:
 
15
 
16
  @property
17
  def gains(self):
18
+ return self.recipes
19
 
20
 
21
+ def recipes_script(recipes_component: RecipesComponent):
22
  recipes = Recipes()
23
 
24
+ def recipe_changed(i):
25
+ def inner(recipe_list):
26
+ if recipe_list:
27
+ recipes[i] = recipe_list
28
+ else:
29
+ recipes[i] = []
 
 
 
30
 
31
  return inner
32
 
33
+ for n, recipe_component in enumerate(recipes_component.values()):
34
+ recipe_component.change(recipe_changed(n), recipe_component)
35
 
36
  return recipes
{qt → gr}/scripts/talents.py RENAMED
@@ -1,6 +1,6 @@
1
- from qt.components.talents import TalentsWidget
2
 
3
- from qt.constant import MAX_TALENTS
4
 
5
 
6
  class Talents:
@@ -18,21 +18,16 @@ class Talents:
18
  return [talent for talent in self.talents if talent]
19
 
20
 
21
- def talents_script(talents_widget: TalentsWidget):
22
  talents = Talents()
23
 
24
- def talent_update(i):
25
- widget = talents_widget[i]
26
-
27
- def inner(index):
28
- if talent := widget.combo_box.currentText():
29
- talents[i] = talent
30
- else:
31
- talents[i] = ""
32
 
33
  return inner
34
 
35
- for n, talent_widget in enumerate(talents_widget.values()):
36
- talent_widget.combo_box.currentIndexChanged.connect(talent_update(n))
37
 
38
  return talents
 
1
+ from gr.components.talents import TalentsComponent
2
 
3
+ from assets.constant import MAX_TALENTS
4
 
5
 
6
  class Talents:
 
18
  return [talent for talent in self.talents if talent]
19
 
20
 
21
+ def talents_script(talents_component: TalentsComponent):
22
  talents = Talents()
23
 
24
+ def talent_changed(i):
25
+ def inner(talent):
26
+ talents[i] = talent
 
 
 
 
 
27
 
28
  return inner
29
 
30
+ for n, talent_component in enumerate(talents_component.values()):
31
+ talent_component.change(talent_changed(n), talent_component)
32
 
33
  return talents
gr/scripts/top.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+ import gradio as gr
4
+
5
+ from general.consumables import FOODS, POTIONS, WEAPON_ENCHANTS, SNACKS, WINES, SPREADS
6
+ from general.gains.formation import FORMATIONS
7
+ from gr.components.top import TopComponent
8
+ from gr.components.equipments import EquipmentsComponent
9
+ from gr.components.talents import TalentsComponent
10
+ from gr.components.recipes import RecipesComponent
11
+ from gr.components.combat import CombatComponent
12
+ from assets.constant import MAX_RECIPES, MAX_EMBED_ATTR, MAX_EMBED_LEVEL
13
+ from schools import SUPPORT_SCHOOL
14
+ from utils.parser import Parser
15
+ from utils.io import serialize, unserialize
16
+
17
+
18
+ def top_script(
19
+ top_component: TopComponent, bottom_component: gr.Group,
20
+ equipments_component: EquipmentsComponent,
21
+ talents_component: TalentsComponent, recipes_component: RecipesComponent,
22
+ combat_component: CombatComponent
23
+ ):
24
+ parser = Parser()
25
+
26
+ def save_json():
27
+ result = dict(
28
+ records=serialize(parser.records),
29
+ file_name=parser.file_name,
30
+ start_frame=parser.start_frame,
31
+ end_frame=parser.end_frame,
32
+ id2name=parser.id2name,
33
+ name2id=parser.name2id,
34
+ players={player_id: school.id for player_id, school in parser.players.items()},
35
+ targets=parser.targets,
36
+ select_talents=parser.select_talents,
37
+ select_equipments=parser.select_equipments,
38
+ )
39
+ file_name = parser.file_name.split(".jcl")[0] + ".json"
40
+ json.dump(result, open(file_name, "w", encoding="utf-8"), ensure_ascii=False)
41
+ return file_name
42
+
43
+ def upload_log(file_path):
44
+ if not file_path:
45
+ return [None] * 4
46
+ parser(file_path)
47
+ players = [parser.id2name[player_id] for player_id in parser.players]
48
+ player_select_update = gr.update(choices=players, value=players[0], visible=True)
49
+ json_link = f"/file={save_json()}"
50
+ return player_select_update, gr.update(visible=True), gr.update(visible=True), gr.update(value=json_link)
51
+
52
+ top_component.upload_log.upload(
53
+ upload_log, top_component.upload_log,
54
+ [top_component.player_select, top_component.save_json, bottom_component, top_component.save_json]
55
+ )
56
+
57
+ def load_json(file_path):
58
+ if not file_path:
59
+ return [None] * 4
60
+ result = json.load(open(file_path, encoding="utf-8"))
61
+
62
+ file_name = result['file_name'].split(".jcl")[0] + ".json"
63
+ json.dump(result, open(file_name, "w", encoding="utf-8"), ensure_ascii=False)
64
+
65
+ result['records'] = unserialize(result['records'])
66
+ for player_id, school_id in result['players'].items():
67
+ result['players'][player_id] = SUPPORT_SCHOOL[school_id]
68
+ for k, v in result.items():
69
+ setattr(parser, k, v)
70
+
71
+ json_link = f"/file={save_json()}"
72
+
73
+ players = [parser.id2name[player_id] for player_id in parser.players]
74
+ player_select_update = gr.update(choices=players, value=players[0], visible=True)
75
+ return player_select_update, gr.update(visible=True), gr.update(visible=True), gr.update(value=json_link)
76
+
77
+ top_component.upload_json.upload(
78
+ load_json, top_component.upload_json,
79
+ [top_component.player_select, top_component.save_json, bottom_component, top_component.save_json]
80
+ )
81
+
82
+ def player_select(player_name):
83
+ if not player_name:
84
+ return {}
85
+ player_id = parser.name2id[player_name]
86
+ parser.current_player = player_id
87
+ school = parser.players[player_id]
88
+
89
+ top_update = {
90
+ top_component.target_select: gr.update(
91
+ choices=[""] + [parser.id2name[target_id] for target_id in parser.current_targets],
92
+ ),
93
+ combat_component.combat_duration: gr.update(value=parser.duration)
94
+ }
95
+
96
+ # """ Update config """
97
+ # config_choices = list(CONFIG.get(school.school, {}))
98
+ # config_widget.config_select.set_items(config_choices, default_index=-1)
99
+ # """ Update dashboard """
100
+ # dashboard_widget.duration.set_value(parser.duration)
101
+
102
+ """ Update talent options """
103
+ for i, talent_component in enumerate(talents_component.values()):
104
+ choices = [""] + [school.talent_decoder[talent] for talent in school.talents[i]]
105
+ value = school.talent_decoder[parser.select_talents[player_id][i]]
106
+ top_update[talent_component] = gr.update(choices=choices, value=value)
107
+
108
+ """ Update recipe options """
109
+ for recipe_component in recipes_component.values():
110
+ top_update[recipe_component] = gr.update(choices=[], visible=False)
111
+
112
+ for i, (skill, recipes) in enumerate(school.recipes.items()):
113
+ recipe_component = recipes_component[i]
114
+ values = recipes[:min(MAX_RECIPES, len(recipes))]
115
+ top_update[recipe_component] = gr.update(choices=recipes, value=values, label=skill, visible=True)
116
+
117
+ """ Update equipment options """
118
+ for label, equipment_component in equipments_component.items():
119
+ top_update[equipment_component.equipment] = equipment_update = gr.update()
120
+ top_update[equipment_component.enchant] = enchant_update = gr.update()
121
+ top_update[equipment_component.strength_level] = strength_level = gr.update()
122
+ embed_level_updates = [gr.update(value=MAX_EMBED_LEVEL)] * MAX_EMBED_ATTR
123
+ for i, embed_level in enumerate(equipment_component.embed_levels):
124
+ top_update[embed_level] = embed_level_updates[i]
125
+
126
+ equipment_update["choices"] = equipment_choices = [""]
127
+ for name, detail in equipment_component.equipment_json.items():
128
+ if detail['kind'] not in (school.kind, school.major):
129
+ continue
130
+ if detail['school'] not in ("精简", "通用", school.school):
131
+ continue
132
+ equipment_choices.append(name)
133
+ if select_equipment := parser.select_equipments[player_id].get(label, {}):
134
+ if equipment_name := equipment_component.equipment_mapping.get(select_equipment['equipment']):
135
+ equipment_update["value"] = equipment_name
136
+ if enchant := equipment_component.enchant_mapping.get(select_equipment['enchant']):
137
+ enchant_update["value"] = enchant
138
+ strength_level["value"] = select_equipment['strength_level']
139
+ for i, embed_level in enumerate(select_equipment['embed_levels']):
140
+ embed_level_updates[i] = gr.update(value=embed_level)
141
+
142
+ return top_update
143
+ #
144
+ # """ Update consumable options """
145
+ # consumables_widget.major_food.set_items([""] + FOODS[school.major], keep_index=True)
146
+ # consumables_widget.minor_food.set_items([""] + FOODS[school.kind] + FOODS[""], keep_index=True)
147
+ # consumables_widget.major_potion.set_items([""] + POTIONS[school.major], keep_index=True)
148
+ # consumables_widget.minor_potion.set_items([""] + POTIONS[school.kind] + POTIONS[""], keep_index=True)
149
+ # consumables_widget.weapon_enchant.set_items([""] + WEAPON_ENCHANTS[school.kind], keep_index=True)
150
+ # consumables_widget.home_snack.set_items([""] + SNACKS[school.kind] + SNACKS[""], keep_index=True)
151
+ # consumables_widget.home_wine.set_items([""] + WINES[school.major] + WINES[""], keep_index=True)
152
+ # consumables_widget.spread.set_items([""] + SPREADS[school.major] + SPREADS[school.kind], keep_index=True)
153
+ #
154
+ # """ Update bonus options """
155
+ # bonus_widget.formation.formation.set_items([""] + FORMATIONS[school.kind] + FORMATIONS[""], keep_index=True)
156
+ # config_widget.show()
157
+ # bottom_widget.show()
158
+
159
+ top_component.player_select.change(
160
+ player_select, top_component.player_select,
161
+ sum([[e.equipment, e.enchant, e.strength_level, *e.embed_levels] for e in equipments_component.values()], []) +
162
+ talents_component.talents + recipes_component.recipes +
163
+ [combat_component.combat_duration] + [top_component.target_select]
164
+ )
165
+
166
+ def target_select(target_name):
167
+ target_id = parser.name2id.get(target_name, "")
168
+ parser.current_target = target_id
169
+
170
+ top_component.target_select.change(
171
+ target_select, top_component.target_select
172
+ )
173
+
174
+ return parser
qt/app.py DELETED
@@ -1,94 +0,0 @@
1
- import sys
2
-
3
-
4
- from PySide6.QtGui import QIcon
5
-
6
- from qt.components.top import TopWidget
7
- from qt.scripts.config import config_script
8
- from qt.scripts.top import top_script
9
- from qt.components.config import ConfigWidget
10
- from qt.components.equipments import EquipmentsWidget
11
- from qt.scripts.equipments import equipments_script
12
- from qt.components.consumables import ConsumablesWidget
13
- from qt.scripts.consumables import consumables_script
14
- from qt.components.talents import TalentsWidget
15
- from qt.scripts.talents import talents_script
16
- from qt.components.recipes import RecipesWidget
17
- from qt.scripts.recipes import recipes_script
18
- from qt.components.bonuses import BonusesWidget
19
- from qt.scripts.bonuses import bonuses_script
20
- from qt.components.dashboard import DashboardWidget
21
- from qt.scripts.dashboard import dashboard_script
22
-
23
- from PySide6.QtWidgets import QApplication, QMainWindow, QStyleFactory
24
- from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QTabWidget
25
-
26
-
27
- class MainWindow(QMainWindow):
28
- def __init__(self):
29
- super().__init__()
30
-
31
- self.setWindowTitle("Formulator")
32
-
33
- icon = QIcon("qt/assets/icon.ico")
34
- self.setWindowIcon(icon)
35
-
36
- self.central_widget = QWidget(self)
37
- self.setCentralWidget(self.central_widget)
38
-
39
- self.showMaximized()
40
- layout = QVBoxLayout(self.central_widget)
41
-
42
- self.top_widget = TopWidget()
43
- layout.addWidget(self.top_widget, 1)
44
-
45
- self.config_widget = ConfigWidget()
46
- layout.addWidget(self.config_widget, 1)
47
- self.config_widget.hide()
48
-
49
- self.bottom_widget = QWidget()
50
- layout.addWidget(self.bottom_widget, 8)
51
- self.bottom_widget.hide()
52
-
53
- bottom_layout = QHBoxLayout(self.bottom_widget)
54
- self.detail_widget = QTabWidget()
55
- self.dashboard_widget = DashboardWidget()
56
- bottom_layout.addWidget(self.detail_widget, 1)
57
- bottom_layout.addWidget(self.dashboard_widget, 1)
58
-
59
- self.equipments_widget = EquipmentsWidget()
60
- self.detail_widget.addTab(self.equipments_widget, "配装")
61
- self.consumable_widget = ConsumablesWidget()
62
- self.detail_widget.addTab(self.consumable_widget, "消耗品")
63
- self.bonus_widget = BonusesWidget()
64
- self.detail_widget.addTab(self.bonus_widget, "增益")
65
- self.talents_widget = TalentsWidget()
66
- self.detail_widget.addTab(self.talents_widget, "奇穴")
67
- self.recipes_widget = RecipesWidget()
68
- self.detail_widget.addTab(self.recipes_widget, "秘籍")
69
-
70
- parser = top_script(
71
- self.top_widget, self.config_widget, self.bottom_widget,
72
- self.dashboard_widget, self.talents_widget, self.recipes_widget,
73
- self.equipments_widget, self.consumable_widget, self.bonus_widget
74
- )
75
- config_script(
76
- parser, self.config_widget,
77
- self.talents_widget, self.recipes_widget,
78
- self.equipments_widget, self.consumable_widget, self.bonus_widget
79
- )
80
- talents = talents_script(self.talents_widget)
81
- recipes = recipes_script(self.recipes_widget)
82
- equipments = equipments_script(self.equipments_widget)
83
- consumables = consumables_script(self.consumable_widget)
84
- bonuses = bonuses_script(parser, self.bonus_widget)
85
- dashboard_script(parser, self.dashboard_widget,
86
- talents, recipes, equipments, consumables, bonuses)
87
-
88
-
89
- if __name__ == "__main__":
90
- app = QApplication(sys.argv)
91
- app.setStyle(QStyleFactory.create('Fusion'))
92
- window = MainWindow()
93
- window.show()
94
- sys.exit(app.exec())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
qt/assets/stones.json DELETED
The diff for this file is too large to render. See raw diff
 
qt/components/__init__.py DELETED
@@ -1,208 +0,0 @@
1
- from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel
2
- from PySide6.QtWidgets import QAbstractItemView, QTableWidgetItem, QHeaderView, QListView
3
- from PySide6.QtWidgets import QComboBox, QRadioButton, QLineEdit, QSpinBox, QDoubleSpinBox, QListWidget, QTableWidget
4
-
5
-
6
- class LabelWidget(QWidget):
7
- def __init__(self, label, info: str = ""):
8
- super().__init__()
9
- if info:
10
- self.label = QLabel(f"{label} - {info}")
11
- else:
12
- self.label = QLabel(label)
13
-
14
- def set_label(self, label):
15
- self.label.setText(label)
16
-
17
-
18
- class TableWithLabel(LabelWidget):
19
- def __init__(self, label, row_count: int = 0, column_count: int = 0, headers: list = None):
20
- super().__init__(label)
21
- layout = QVBoxLayout()
22
- self.setLayout(layout)
23
-
24
- self.table = QTableWidget()
25
-
26
- if row_count:
27
- self.table.setRowCount(row_count)
28
- if column_count:
29
- self.table.setColumnCount(column_count)
30
- if headers:
31
- self.table.setColumnCount(len(headers))
32
- self.table.setHorizontalHeaderLabels(headers)
33
- else:
34
- self.table.horizontalHeader().setVisible(False)
35
-
36
- self.table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
37
- self.table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
38
- self.table.verticalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
39
- self.table.verticalHeader().setVisible(False)
40
-
41
- layout.addWidget(self.label)
42
- layout.addWidget(self.table)
43
-
44
- def set_content(self, content):
45
- self.table.setRowCount(len(content))
46
-
47
- for i, row in enumerate(content):
48
- for j, e in enumerate(row):
49
- self.table.setItem(i, j, QTableWidgetItem(e))
50
-
51
-
52
- class ListWithLabel(LabelWidget):
53
- def __init__(self, label, max_select: int = 4, items: list = None):
54
- super().__init__(label)
55
- layout = QVBoxLayout(self)
56
-
57
- self.max_select = max_select
58
-
59
- self.list = QListWidget()
60
- self.list.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection)
61
- self.list.setResizeMode(QListView.ResizeMode.Adjust)
62
-
63
- if items:
64
- self.set_items(items)
65
- layout.addWidget(self.label)
66
- layout.addWidget(self.list)
67
-
68
- def set_items(self, items):
69
- self.list.clear()
70
- self.list.addItems(items)
71
-
72
-
73
- class ComboWithLabel(LabelWidget):
74
- def __init__(self, label, info: str = "", items: list = None, index=None):
75
- super().__init__(label, info)
76
- layout = QVBoxLayout()
77
- self.setLayout(layout)
78
-
79
- self.combo_box = QComboBox()
80
- self.items = []
81
- if items:
82
- self.set_items(items)
83
- if index:
84
- self.combo_box.setCurrentIndex(index)
85
-
86
- layout.addWidget(self.label)
87
- layout.addWidget(self.combo_box)
88
-
89
- layout.addStretch()
90
-
91
- def set_items(self, items, keep_index=False, default_index=0):
92
- self.items = items
93
- self.combo_box.blockSignals(True)
94
- current_text = self.combo_box.currentText()
95
- self.combo_box.clear()
96
- self.combo_box.addItems(items)
97
- self.combo_box.blockSignals(False)
98
- if keep_index and current_text and current_text in items:
99
- self.combo_box.setCurrentIndex(items.index(current_text))
100
- else:
101
- self.combo_box.setCurrentIndex(default_index)
102
-
103
-
104
- class RadioWithLabel(LabelWidget):
105
- def __init__(self, label, text: str = None):
106
- super().__init__(label)
107
- layout = QVBoxLayout()
108
- self.setLayout(layout)
109
-
110
- self.radio_button = QRadioButton()
111
- if text:
112
- self.radio_button.setText(text)
113
-
114
- layout.addWidget(self.label)
115
- layout.addWidget(self.radio_button)
116
-
117
- layout.addStretch()
118
-
119
- def set_text(self, text):
120
- self.radio_button.setText(text)
121
-
122
-
123
- class SpinWithLabel(LabelWidget):
124
- def __init__(self, label, info="", minimum=None, maximum=None, value=None):
125
- super().__init__(label, info)
126
- layout = QVBoxLayout()
127
- self.setLayout(layout)
128
-
129
- self.spin_box = QSpinBox()
130
- if minimum:
131
- self.spin_box.setMinimum(minimum)
132
-
133
- if maximum:
134
- self.spin_box.setMaximum(maximum + 1)
135
- else:
136
- self.spin_box.setMaximum(10 ** 8)
137
-
138
- if value:
139
- self.spin_box.setValue(value)
140
-
141
- layout.addWidget(self.label)
142
- layout.addWidget(self.spin_box)
143
-
144
- layout.addStretch()
145
-
146
- def set_value(self, value):
147
- self.spin_box.setValue(value)
148
-
149
-
150
- class DoubleSpinWithLabel(LabelWidget):
151
- def __init__(self, label, info="", minimum=None, maximum=None, value=None):
152
- super().__init__(label, info)
153
- layout = QVBoxLayout()
154
- self.setLayout(layout)
155
-
156
- self.spin_box = QDoubleSpinBox()
157
- if minimum:
158
- self.spin_box.setMinimum(minimum)
159
-
160
- if maximum:
161
- self.spin_box.setMaximum(maximum + 1)
162
- else:
163
- self.spin_box.setMaximum(10 ** 8)
164
-
165
- if value:
166
- self.spin_box.setValue(value)
167
-
168
- layout.addWidget(self.label)
169
- layout.addWidget(self.spin_box)
170
-
171
- layout.addStretch()
172
-
173
- def set_value(self, value):
174
- self.spin_box.setValue(value)
175
-
176
- class TextWithLabel(LabelWidget):
177
- def __init__(self, label):
178
- super().__init__(label)
179
- layout = QVBoxLayout(self)
180
-
181
- self.text_browser = QLineEdit()
182
-
183
- layout.addWidget(self.label)
184
- layout.addWidget(self.text_browser)
185
-
186
- layout.addStretch()
187
-
188
- def set_text(self, text):
189
- self.text_browser.setText(text)
190
-
191
-
192
- class LabelWithLabel(QWidget):
193
- def __init__(self, label):
194
- super().__init__()
195
- layout = QHBoxLayout()
196
- self.setLayout(layout)
197
-
198
- self.label = QLabel(label)
199
- self.text = QLabel()
200
- # self.text_browser.textChanged.connect(self.resize_height)
201
-
202
- layout.addWidget(self.label)
203
- layout.addWidget(self.text)
204
-
205
- layout.addStretch()
206
-
207
- def set_text(self, text):
208
- self.text.setText(text)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
qt/components/bonuses.py DELETED
@@ -1,239 +0,0 @@
1
- from general.gains.team import TEAM_GAIN_LIMIT
2
- from qt.components import ComboWithLabel, SpinWithLabel, RadioWithLabel
3
- from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QTabWidget
4
-
5
-
6
- class FormationWidget(QWidget):
7
- def __init__(self):
8
- super().__init__()
9
- layout = QHBoxLayout()
10
- self.setLayout(layout)
11
-
12
- self.formation = ComboWithLabel("阵法")
13
- layout.addWidget(self.formation)
14
- self.core_rate = SpinWithLabel("四重覆盖(%)", maximum=100)
15
- layout.addWidget(self.core_rate)
16
- self.rate = SpinWithLabel("五重覆盖(%)", maximum=100)
17
- layout.addWidget(self.rate)
18
-
19
-
20
- class TeamGainsWidget(QWidget):
21
- def __init__(self):
22
- super().__init__()
23
- layout = QVBoxLayout(self)
24
-
25
- self.team_gains = {}
26
-
27
- self.real_formulation = RadioWithLabel("开启真实团队增益模拟(仅包括存在覆盖率的角色BUFF,不包含目标和常驻BUFF)")
28
-
29
- layout.addWidget(self.real_formulation)
30
-
31
- tabs = QTabWidget()
32
- layout.addWidget(tabs)
33
-
34
- tab = QWidget()
35
- tab_layout = QGridLayout(tab)
36
- tabs.addTab(tab, "七秀")
37
-
38
- self.team_gains["袖气"] = RadioWithLabel("袖气", "常驻")
39
- tab_layout.addWidget(self.team_gains["袖气"], 0, 0)
40
-
41
- self.team_gains["左旋右转"] = {
42
- "stack": SpinWithLabel("左旋右转", "层数", maximum=TEAM_GAIN_LIMIT["左旋右转"]["stack"]),
43
- "rate": SpinWithLabel("左旋右转", "覆盖(%)", maximum=100)
44
- }
45
- tab_layout.addWidget(self.team_gains["左旋右转"]["stack"], 1, 0)
46
- tab_layout.addWidget(self.team_gains["左旋右转"]["rate"], 1, 1)
47
- self.team_gains["泠风解怀"] = {
48
- "rate": SpinWithLabel("泠风解怀", "覆盖(%)", maximum=100)
49
- }
50
- tab_layout.addWidget(self.team_gains["泠风解怀"]["rate"], 2, 0)
51
-
52
- tab = QWidget()
53
- tab_layout = QGridLayout(tab)
54
- tabs.addTab(tab, "天策")
55
-
56
- self.team_gains["撼如雷"] = RadioWithLabel("撼如雷", "常驻")
57
- tab_layout.addWidget(self.team_gains["撼如雷"], 0, 0)
58
-
59
- self.team_gains["破风"] = {
60
- "variety": ComboWithLabel("破风", "种类", ["", "破风", "劲风"])
61
- }
62
- tab_layout.addWidget(self.team_gains["破风"]["variety"], 1, 0)
63
-
64
- self.team_gains["乘龙箭"] = {
65
- "rate": SpinWithLabel("乘龙箭", "覆盖(%)", maximum=100)
66
- }
67
- tab_layout.addWidget(self.team_gains["乘龙箭"]["rate"], 2, 0)
68
-
69
- self.team_gains["号令三军"] = {
70
- "stack": SpinWithLabel("号令三军", "层数", maximum=TEAM_GAIN_LIMIT["号令三军"]["stack"]),
71
- "rate": SpinWithLabel("号令三军", "覆盖(%)", maximum=100)
72
- }
73
- tab_layout.addWidget(self.team_gains["号令三军"]["stack"], 3, 0)
74
- tab_layout.addWidget(self.team_gains["号令三军"]["rate"], 3, 1)
75
-
76
- self.team_gains["激雷"] = {
77
- "rate": SpinWithLabel("激雷", "覆盖(%)", maximum=100)
78
- }
79
- tab_layout.addWidget(self.team_gains["激雷"]["rate"], 4, 0)
80
-
81
- tab = QWidget()
82
- tab_layout = QGridLayout(tab)
83
- tabs.addTab(tab, "少林")
84
-
85
- self.team_gains["立地成佛"] = {
86
- "rate": SpinWithLabel("立地成佛", "覆盖(%)", maximum=100)
87
- }
88
- tab_layout.addWidget(self.team_gains["立地成佛"]["rate"], 0, 0)
89
-
90
- self.team_gains["舍身弘法"] = {
91
- "stack": SpinWithLabel("舍身弘法", "层数", maximum=TEAM_GAIN_LIMIT["舍身弘法"]["stack"]),
92
- "rate": SpinWithLabel("舍身弘法", "覆盖(%)", maximum=100)
93
- }
94
- tab_layout.addWidget(self.team_gains["舍身弘法"]["stack"], 1, 0)
95
- tab_layout.addWidget(self.team_gains["舍身弘法"]["rate"], 1, 1)
96
-
97
- tab = QWidget()
98
- tab_layout = QGridLayout(tab)
99
- tabs.addTab(tab, "万花")
100
-
101
- self.team_gains["秋肃"] = RadioWithLabel("秋肃", "常驻")
102
- tab_layout.addWidget(self.team_gains["秋肃"], 0, 0)
103
-
104
- self.team_gains["皎素"] = {
105
- "rate": SpinWithLabel("皎素", "覆盖(%)", maximum=100)
106
- }
107
- tab_layout.addWidget(self.team_gains["皎素"]["rate"], 1, 0)
108
-
109
- tab = QWidget()
110
- tab_layout = QGridLayout(tab)
111
- tabs.addTab(tab, "纯阳")
112
-
113
- self.team_gains["碎星辰"] = RadioWithLabel("碎星辰", "常驻")
114
- tab_layout.addWidget(self.team_gains["碎星辰"], 0, 0)
115
-
116
- self.team_gains["破苍穹"] = RadioWithLabel("破苍穹", "常驻")
117
- tab_layout.addWidget(self.team_gains["破苍穹"], 1, 0)
118
-
119
- tab = QWidget()
120
- tab_layout = QGridLayout(tab)
121
- tabs.addTab(tab, "藏剑")
122
-
123
- self.team_gains["剑锋百锻"] = {
124
- "rate": SpinWithLabel("剑锋百锻", "覆盖(%)", maximum=100)
125
- }
126
- tab_layout.addWidget(self.team_gains["剑锋百锻"]["rate"], 0, 0)
127
-
128
- tab = QWidget()
129
- tab_layout = QGridLayout(tab)
130
- tabs.addTab(tab, "五毒")
131
-
132
- self.team_gains["仙王蛊鼎"] = {
133
- "rate": SpinWithLabel("仙王蛊鼎", "覆盖(%)", maximum=100)
134
- }
135
- tab_layout.addWidget(self.team_gains["仙王蛊鼎"]["rate"], 0, 0)
136
-
137
- tab = QWidget()
138
- tab_layout = QGridLayout(tab)
139
- tabs.addTab(tab, "明教")
140
-
141
- self.team_gains["戒火"] = RadioWithLabel("戒火", "常驻")
142
- tab_layout.addWidget(self.team_gains["戒火"], 0, 0)
143
-
144
- self.team_gains["朝圣言"] = {
145
- "stack": SpinWithLabel("朝圣言", "层数", maximum=TEAM_GAIN_LIMIT["朝圣言"]["stack"]),
146
- "rate": SpinWithLabel("朝圣言", "覆盖(%)", maximum=100),
147
- "variety": ComboWithLabel("朝圣言", "种类", ["", "朝圣言", "圣浴明心"])
148
- }
149
- tab_layout.addWidget(self.team_gains["朝圣言"]["variety"], 1, 0)
150
- tab_layout.addWidget(self.team_gains["朝圣言"]["stack"], 1, 1)
151
- tab_layout.addWidget(self.team_gains["朝圣言"]["rate"], 1, 2)
152
-
153
- tab = QWidget()
154
- tab_layout = QGridLayout(tab)
155
- tabs.addTab(tab, "丐帮")
156
-
157
- self.team_gains["酒中仙"] = RadioWithLabel("酒中仙", "常驻")
158
- tab_layout.addWidget(self.team_gains["酒中仙"], 0, 0)
159
-
160
- tab = QWidget()
161
- tab_layout = QGridLayout(tab)
162
- tabs.addTab(tab, "苍云")
163
-
164
- self.team_gains["虚弱"] = RadioWithLabel("虚弱", "常驻")
165
- tab_layout.addWidget(self.team_gains["虚弱"], 0, 0)
166
-
167
- self.team_gains["寒啸千军"] = {
168
- "rate": SpinWithLabel("寒啸千军", "覆盖(%)", maximum=100)
169
- }
170
- tab_layout.addWidget(self.team_gains["寒啸千军"]["rate"], 1, 0)
171
-
172
- self.team_gains["振奋"] = {
173
- "stack": SpinWithLabel("振奋", "层数", maximum=TEAM_GAIN_LIMIT["振奋"]["stack"]),
174
- "rate": SpinWithLabel("振奋", "覆盖(%)", maximum=100)
175
- }
176
- tab_layout.addWidget(self.team_gains["振奋"]["stack"], 2, 0)
177
- tab_layout.addWidget(self.team_gains["振奋"]["rate"], 2, 1)
178
-
179
- tab = QWidget()
180
- tab_layout = QGridLayout(tab)
181
- tabs.addTab(tab, "长歌")
182
-
183
- self.team_gains["庄周梦"] = {
184
- "stack": SpinWithLabel("庄周梦", "层数", maximum=TEAM_GAIN_LIMIT["庄周梦"]["stack"]),
185
- "rate": SpinWithLabel("庄周梦", "覆盖(%)", maximum=100)
186
- }
187
- tab_layout.addWidget(self.team_gains["庄周梦"]["stack"], 0, 0)
188
- tab_layout.addWidget(self.team_gains["庄周梦"]["rate"], 0, 1)
189
- self.team_gains["弄梅"] = {
190
- "rate": SpinWithLabel("弄梅", "覆盖(%)", maximum=100)
191
- }
192
- tab_layout.addWidget(self.team_gains["弄梅"]["rate"], 1, 0)
193
-
194
- tab = QWidget()
195
- tab_layout = QGridLayout(tab)
196
- tabs.addTab(tab, "霸刀")
197
-
198
- self.team_gains["疏狂"] = {
199
- "rate": SpinWithLabel("疏狂", "覆盖(%)", maximum=100)
200
- }
201
- tab_layout.addWidget(self.team_gains["疏狂"]["rate"], 0, 0)
202
-
203
- tab = QWidget()
204
- tab_layout = QGridLayout(tab)
205
- tabs.addTab(tab, "药宗")
206
-
207
- self.team_gains["配伍"] = {
208
- "rate": SpinWithLabel("配伍", "覆盖(%)", maximum=100)
209
- }
210
- tab_layout.addWidget(self.team_gains["配伍"]["rate"], 0, 0)
211
-
212
- # self.team_gains["飘黄"] = {
213
- # "rate": SpinWithLabel("飘黄", "覆盖", maximum=100)
214
- # }
215
- # tab_layout.addWidget(self.team_gains["飘黄"]["rate"], 1, 0)
216
-
217
- layout.addStretch()
218
-
219
- def __getitem__(self, item):
220
- return self.team_gains[item]
221
-
222
- def items(self):
223
- return self.team_gains.items()
224
-
225
-
226
- class BonusesWidget(QWidget):
227
- def __init__(self):
228
- super().__init__()
229
- layout = QVBoxLayout()
230
- self.setLayout(layout)
231
-
232
- self.tab = QTabWidget()
233
- layout.addWidget(self.tab)
234
- self.formation = FormationWidget()
235
- self.tab.addTab(self.formation, "阵法")
236
- self.team_gains = TeamGainsWidget()
237
- self.tab.addTab(self.team_gains, "团队增益")
238
-
239
- layout.addStretch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
qt/components/config.py DELETED
@@ -1,26 +0,0 @@
1
- from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton
2
-
3
- from qt.components import ComboWithLabel, TextWithLabel
4
-
5
-
6
- class ConfigWidget(QWidget):
7
- def __init__(self):
8
- super().__init__()
9
- layout = QVBoxLayout(self)
10
- top_layout = QHBoxLayout()
11
- layout.addLayout(top_layout)
12
- bottom_layout = QHBoxLayout()
13
- layout.addLayout(bottom_layout)
14
-
15
- self.config_select = ComboWithLabel("选择预设方案")
16
- top_layout.addWidget(self.config_select, 1)
17
- self.config_category = ComboWithLabel("选择导入类别", items=["全部", "装备", "消耗品", "增益"])
18
- top_layout.addWidget(self.config_category, 1)
19
- self.load_config = QPushButton("导入预设方案")
20
- bottom_layout.addWidget(self.load_config, 2)
21
- self.config_name = TextWithLabel("设置预设方案")
22
- top_layout.addWidget(self.config_name, 2)
23
- self.save_config = QPushButton("保存预设方案")
24
- bottom_layout.addWidget(self.save_config, 1)
25
- self.delete_config = QPushButton("删除预设方案")
26
- bottom_layout.addWidget(self.delete_config, 1)