Spaces:
Runtime error
Runtime error
ango
commited on
Commit
•
c145eab
1
Parent(s):
581e199
5.14 commit
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .github/workflows/nuitka-app.yml +2 -2
- .github/workflows/pyinstaller-app.yml +45 -4
- {qt → assets}/constant.py +1 -14
- {qt/assets → assets}/enchants/belt +0 -0
- {qt/assets → assets}/enchants/bottoms +0 -0
- {qt/assets → assets}/enchants/hat +0 -0
- {qt/assets → assets}/enchants/jacket +0 -0
- {qt/assets → assets}/enchants/necklace +0 -0
- {qt/assets → assets}/enchants/pendant +0 -0
- {qt/assets → assets}/enchants/primary_weapon +0 -0
- {qt/assets → assets}/enchants/ring +0 -0
- {qt/assets → assets}/enchants/secondary_weapon +0 -0
- {qt/assets → assets}/enchants/shoes +0 -0
- {qt/assets → assets}/enchants/tertiary_weapon +0 -0
- {qt/assets → assets}/enchants/wrist +0 -0
- {qt/assets → assets}/equipments/belt +0 -0
- {qt/assets → assets}/equipments/bottoms +0 -0
- {qt/assets → assets}/equipments/hat +0 -0
- {qt/assets → assets}/equipments/jacket +0 -0
- {qt/assets → assets}/equipments/necklace +0 -0
- {qt/assets → assets}/equipments/pendant +0 -0
- {qt/assets → assets}/equipments/primary_weapon +0 -0
- {qt/assets → assets}/equipments/ring +0 -0
- {qt/assets → assets}/equipments/secondary_weapon +0 -0
- {qt/assets → assets}/equipments/shoes +0 -0
- {qt/assets → assets}/equipments/tertiary_weapon +0 -0
- {qt/assets → assets}/equipments/wrist +0 -0
- assets/icon.icns +0 -0
- {qt/assets → assets}/icon.ico +0 -0
- assets/stones.json +0 -0
- get_assets.py +6 -5
- {qt → gr}/__init__.py +0 -0
- gr/app.py +42 -0
- {qt/scripts → gr/components}/__init__.py +0 -0
- gr/components/combat.py +32 -0
- gr/components/equipments.py +81 -0
- gr/components/recipes.py +24 -0
- gr/components/talents.py +25 -0
- gr/components/top.py +13 -0
- gr/scripts/__init__.py +0 -0
- gr/scripts/combat.py +151 -0
- {qt → gr}/scripts/equipments.py +132 -96
- {qt → gr}/scripts/recipes.py +12 -15
- {qt → gr}/scripts/talents.py +8 -13
- gr/scripts/top.py +174 -0
- qt/app.py +0 -94
- qt/assets/stones.json +0 -0
- qt/components/__init__.py +0 -208
- qt/components/bonuses.py +0 -239
- 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:
|
39 |
nofollow-import-to: http,email
|
40 |
-
include-data-dir:
|
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
|
73 |
mv dist Formulator
|
74 |
-
|
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:
|
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 |
-
|
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
|
9 |
-
from
|
10 |
-
from
|
11 |
-
from
|
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 |
-
|
|
|
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
|
6 |
-
from
|
7 |
-
from
|
8 |
-
from
|
|
|
|
|
9 |
|
10 |
|
11 |
class Enchant:
|
@@ -97,18 +101,27 @@ class Equipment:
|
|
97 |
|
98 |
@property
|
99 |
def base_attr_content(self):
|
100 |
-
return
|
|
|
|
|
101 |
|
102 |
@property
|
103 |
def magic_attr_content(self):
|
104 |
if strength_attr := self.strength_attr:
|
105 |
-
return
|
|
|
|
|
|
|
106 |
else:
|
107 |
-
return
|
|
|
|
|
108 |
|
109 |
@property
|
110 |
def embed_attr_content(self):
|
111 |
-
return
|
|
|
|
|
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(
|
181 |
equipments = Equipments()
|
182 |
|
183 |
-
def
|
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 |
-
|
192 |
-
|
|
|
|
|
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 =
|
201 |
for k, v in equipment_detail.items():
|
202 |
setattr(equipment, k, v)
|
203 |
|
204 |
if equipment.base:
|
205 |
-
|
206 |
-
|
|
|
207 |
else:
|
208 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
209 |
|
210 |
if max_strength:
|
211 |
equipment.strength_level = equipment.max_strength
|
212 |
|
213 |
-
|
214 |
-
|
|
|
|
|
|
|
|
|
215 |
|
216 |
if equipment.embed:
|
217 |
-
for i,
|
218 |
-
|
219 |
-
|
220 |
-
|
|
|
|
|
|
|
|
|
221 |
else:
|
222 |
-
|
|
|
223 |
|
224 |
-
|
225 |
-
|
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
|
235 |
-
widget = equipments_widget.equipments[label]
|
236 |
-
equipment = equipments[label]
|
237 |
-
|
238 |
def inner(enchant_name):
|
|
|
|
|
239 |
if enchant_name:
|
240 |
-
enchant_detail =
|
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
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
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
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
def inner(index):
|
266 |
-
equipment.strength_level = index
|
267 |
if magic_attr_content := equipment.magic_attr_content:
|
268 |
-
|
269 |
-
widget.magic_attr.show()
|
270 |
else:
|
271 |
-
|
272 |
|
273 |
return inner
|
274 |
|
275 |
-
def
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
def inner(index):
|
280 |
-
equipment.embed_levels[i] = index
|
281 |
if embed_attr_content := equipment.embed_attr_content:
|
282 |
-
|
283 |
-
widget.embed_attr.show()
|
284 |
else:
|
285 |
-
|
286 |
|
287 |
return inner
|
288 |
|
289 |
-
def
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
def inner(_):
|
294 |
-
level = widget.stone_level.combo_box.currentText()
|
295 |
|
296 |
-
current =
|
297 |
i = 0
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
current = current[attr]
|
302 |
i += 1
|
303 |
else:
|
304 |
break
|
305 |
-
|
306 |
-
|
|
|
|
|
|
|
307 |
setattr(equipment.stone, k, v)
|
308 |
-
|
309 |
-
|
310 |
-
|
|
|
|
|
|
|
311 |
|
312 |
i += 1
|
313 |
-
while i < len(
|
314 |
-
|
|
|
|
|
315 |
i += 1
|
|
|
316 |
|
317 |
return inner
|
318 |
|
319 |
-
for equipment_label,
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
2 |
|
3 |
-
from
|
4 |
|
5 |
|
6 |
class Recipes:
|
@@ -15,25 +15,22 @@ class Recipes:
|
|
15 |
|
16 |
@property
|
17 |
def gains(self):
|
18 |
-
return
|
19 |
|
20 |
|
21 |
-
def recipes_script(
|
22 |
recipes = Recipes()
|
23 |
|
24 |
-
def
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
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,
|
37 |
-
|
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
|
2 |
|
3 |
-
from
|
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(
|
22 |
talents = Talents()
|
23 |
|
24 |
-
def
|
25 |
-
|
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,
|
36 |
-
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|