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)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|