Spaces:
				
			
			
	
			
			
		Runtime error
		
	
	
	
			
			
	
	
	
	
		
		
		Runtime error
		
	
		ango
		
	commited on
		
		
					Commit 
							
							·
						
						2452398
	
1
								Parent(s):
							
							f0b1638
								
04.10 commit
Browse files- base/attribute.py +4 -3
 - base/buff.py +30 -24
 - base/calculator.py +0 -50
 - base/constant.py +1 -1
 - base/recipe.py +7 -10
 - base/skill.py +6 -2
 - general/recipes.py +66 -0
 - qt/app.py +25 -18
 - qt/components/__init__.py +18 -9
 - qt/components/dashboard.py +80 -0
 - qt/components/equipments.py +7 -6
 - qt/components/recipes.py +27 -0
 - qt/constant.py +43 -4
 - qt/scripts/__init__.py +0 -0
 - qt/scripts/dashboard.py +103 -0
 - qt/scripts/equipments.py +29 -24
 - qt/scripts/recipes.py +39 -0
 - qt/scripts/top.py +45 -15
 - schools/first/__init__.py +2 -1
 - schools/first/recipes.py +57 -65
 - schools/first/skills.py +7 -2
 - schools/first/talents.py +19 -14
 - schools/first/test.py +2 -2
 - utils/analyzer.py +89 -0
 - {base → utils}/damage.py +0 -0
 
    	
        base/attribute.py
    CHANGED
    
    | 
         @@ -147,7 +147,7 @@ class Major: 
     | 
|
| 147 | 
         
             
                _magical_overcome: float = 0
         
     | 
| 148 | 
         | 
| 149 | 
         
             
                """ Major Attr Function"""
         
     | 
| 150 | 
         
            -
             
     | 
| 151 | 
         
             
                @property
         
     | 
| 152 | 
         
             
                def all_major_base(self):
         
     | 
| 153 | 
         
             
                    return self._all_major_base
         
     | 
| 
         @@ -779,7 +779,7 @@ class Minor: 
     | 
|
| 779 | 
         | 
| 780 | 
         
             
                @property
         
     | 
| 781 | 
         
             
                def physical_critical_power_percent(self):
         
     | 
| 782 | 
         
            -
                    return  
     | 
| 783 | 
         | 
| 784 | 
         
             
                @physical_critical_power_percent.setter
         
     | 
| 785 | 
         
             
                def physical_critical_power_percent(self, physical_critical_power_percent):
         
     | 
| 
         @@ -814,7 +814,7 @@ class Minor: 
     | 
|
| 814 | 
         | 
| 815 | 
         
             
                @property
         
     | 
| 816 | 
         
             
                def magical_critical_power_percent(self):
         
     | 
| 817 | 
         
            -
                    return  
     | 
| 818 | 
         | 
| 819 | 
         
             
                @magical_critical_power_percent.setter
         
     | 
| 820 | 
         
             
                def magical_critical_power_percent(self, magical_critical_power_percent):
         
     | 
| 
         @@ -954,6 +954,7 @@ class Attribute(Major, Minor, Target): 
     | 
|
| 954 | 
         | 
| 955 | 
         
             
                def __init__(self):
         
     | 
| 956 | 
         
             
                    self.all_major_base += MAJOR_BASE
         
     | 
| 
         | 
|
| 957 | 
         | 
| 958 | 
         
             
                @property
         
     | 
| 959 | 
         
             
                def level_reduction(self):
         
     | 
| 
         | 
|
| 147 | 
         
             
                _magical_overcome: float = 0
         
     | 
| 148 | 
         | 
| 149 | 
         
             
                """ Major Attr Function"""
         
     | 
| 150 | 
         
            +
             
     | 
| 151 | 
         
             
                @property
         
     | 
| 152 | 
         
             
                def all_major_base(self):
         
     | 
| 153 | 
         
             
                    return self._all_major_base
         
     | 
| 
         | 
|
| 779 | 
         | 
| 780 | 
         
             
                @property
         
     | 
| 781 | 
         
             
                def physical_critical_power_percent(self):
         
     | 
| 782 | 
         
            +
                    return BASE_CRITICAL_POWER + self._physical_critical_power_percent
         
     | 
| 783 | 
         | 
| 784 | 
         
             
                @physical_critical_power_percent.setter
         
     | 
| 785 | 
         
             
                def physical_critical_power_percent(self, physical_critical_power_percent):
         
     | 
| 
         | 
|
| 814 | 
         | 
| 815 | 
         
             
                @property
         
     | 
| 816 | 
         
             
                def magical_critical_power_percent(self):
         
     | 
| 817 | 
         
            +
                    return BASE_CRITICAL_POWER + self._magical_critical_power_percent
         
     | 
| 818 | 
         | 
| 819 | 
         
             
                @magical_critical_power_percent.setter
         
     | 
| 820 | 
         
             
                def magical_critical_power_percent(self, magical_critical_power_percent):
         
     | 
| 
         | 
|
| 954 | 
         | 
| 955 | 
         
             
                def __init__(self):
         
     | 
| 956 | 
         
             
                    self.all_major_base += MAJOR_BASE
         
     | 
| 957 | 
         
            +
                    self.all_critical_power_base = 0  # init critical power attr
         
     | 
| 958 | 
         | 
| 959 | 
         
             
                @property
         
     | 
| 960 | 
         
             
                def level_reduction(self):
         
     | 
    	
        base/buff.py
    CHANGED
    
    | 
         @@ -1,5 +1,5 @@ 
     | 
|
| 1 | 
         
             
            from dataclasses import dataclass
         
     | 
| 2 | 
         
            -
            from typing import Dict, List, Union 
     | 
| 3 | 
         | 
| 4 | 
         
             
            from base.attribute import Attribute
         
     | 
| 5 | 
         
             
            from base.skill import Skill
         
     | 
| 
         @@ -9,11 +9,10 @@ ATTR_DICT = Dict[str, Union[List[int], int]] 
     | 
|
| 9 | 
         | 
| 10 | 
         
             
            @dataclass
         
     | 
| 11 | 
         
             
            class Buff:
         
     | 
| 12 | 
         
            -
                buff_id: int
         
     | 
| 13 | 
         
            -
                buff_name: str
         
     | 
| 14 | 
         
             
                buff_level: int = 0
         
     | 
| 15 | 
         
            -
             
     | 
| 16 | 
         
            -
                stack: int = 1
         
     | 
| 17 | 
         | 
| 18 | 
         
             
                gain_skills: Dict[int, ATTR_DICT] = None
         
     | 
| 19 | 
         
             
                gain_attributes: ATTR_DICT = None
         
     | 
| 
         @@ -22,22 +21,29 @@ class Buff: 
     | 
|
| 22 | 
         
             
                    self.gain_skills = {}
         
     | 
| 23 | 
         
             
                    self.gain_attributes = {}
         
     | 
| 24 | 
         | 
| 25 | 
         
            -
                 
     | 
| 26 | 
         
            -
             
     | 
| 27 | 
         
            -
                     
     | 
| 28 | 
         
            -
             
     | 
| 29 | 
         
            -
             
     | 
| 30 | 
         
            -
             
     | 
| 31 | 
         
            -
             
     | 
| 32 | 
         
            -
             
     | 
| 33 | 
         
            -
                     
     | 
| 34 | 
         
            -
             
     | 
| 35 | 
         
            -
             
     | 
| 36 | 
         
            -
             
     | 
| 37 | 
         
            -
             
     | 
| 38 | 
         
            -
             
     | 
| 39 | 
         
            -
             
     | 
| 40 | 
         
            -
             
     | 
| 41 | 
         
            -
                     
     | 
| 42 | 
         
            -
                         
     | 
| 43 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
             
            from dataclasses import dataclass
         
     | 
| 2 | 
         
            +
            from typing import Dict, List, Union
         
     | 
| 3 | 
         | 
| 4 | 
         
             
            from base.attribute import Attribute
         
     | 
| 5 | 
         
             
            from base.skill import Skill
         
     | 
| 
         | 
|
| 9 | 
         | 
| 10 | 
         
             
            @dataclass
         
     | 
| 11 | 
         
             
            class Buff:
         
     | 
| 12 | 
         
            +
                buff_id: int = 0
         
     | 
| 13 | 
         
            +
                buff_name: str = ""
         
     | 
| 14 | 
         
             
                buff_level: int = 0
         
     | 
| 15 | 
         
            +
                buff_stack: int = 0
         
     | 
| 
         | 
|
| 16 | 
         | 
| 17 | 
         
             
                gain_skills: Dict[int, ATTR_DICT] = None
         
     | 
| 18 | 
         
             
                gain_attributes: ATTR_DICT = None
         
     | 
| 
         | 
|
| 21 | 
         
             
                    self.gain_skills = {}
         
     | 
| 22 | 
         
             
                    self.gain_attributes = {}
         
     | 
| 23 | 
         | 
| 24 | 
         
            +
                @property
         
     | 
| 25 | 
         
            +
                def display_name(self):
         
     | 
| 26 | 
         
            +
                    return f"{self.buff_name}/{self.buff_id}-{self.buff_level}-{self.buff_stack}"
         
     | 
| 27 | 
         
            +
             
     | 
| 28 | 
         
            +
                def __radd__(self, other: Union[Attribute, Dict[int, Skill]]):
         
     | 
| 29 | 
         
            +
                    if isinstance(other, Attribute):
         
     | 
| 30 | 
         
            +
                        for attr, value in self.gain_attributes.items():
         
     | 
| 31 | 
         
            +
                            setattr(other, attr, getattr(other, attr) + value * self.buff_stack)
         
     | 
| 32 | 
         
            +
                    else:
         
     | 
| 33 | 
         
            +
                        for skill_id, gain in self.gain_skills.items():
         
     | 
| 34 | 
         
            +
                            skill = other[skill_id]
         
     | 
| 35 | 
         
            +
                            for attr, value in gain.items():
         
     | 
| 36 | 
         
            +
                                setattr(skill, attr, getattr(skill, attr) + value * self.buff_stack)
         
     | 
| 37 | 
         
            +
                    return other
         
     | 
| 38 | 
         
            +
             
     | 
| 39 | 
         
            +
                def __rsub__(self, other: Union[Attribute, Dict[int, Skill]]):
         
     | 
| 40 | 
         
            +
                    if isinstance(other, Attribute):
         
     | 
| 41 | 
         
            +
                        for attr, value in self.gain_attributes.items():
         
     | 
| 42 | 
         
            +
                            setattr(other, attr, getattr(other, attr) - value * self.buff_stack)
         
     | 
| 43 | 
         
            +
                    else:
         
     | 
| 44 | 
         
            +
                        for skill_id, gain in self.gain_skills.items():
         
     | 
| 45 | 
         
            +
                            skill = other[skill_id]
         
     | 
| 46 | 
         
            +
                            for attr, value in gain.items():
         
     | 
| 47 | 
         
            +
                                setattr(skill, attr, getattr(skill, attr) - value * self.buff_stack)
         
     | 
| 48 | 
         
            +
                    return other
         
     | 
| 49 | 
         
            +
             
     | 
    	
        base/calculator.py
    DELETED
    
    | 
         @@ -1,50 +0,0 @@ 
     | 
|
| 1 | 
         
            -
            from base.attribute import Attribute
         
     | 
| 2 | 
         
            -
            from qt.scripts.top import Parser, School
         
     | 
| 3 | 
         
            -
             
     | 
| 4 | 
         
            -
             
     | 
| 5 | 
         
            -
            def refresh_status(existed_buffs, buffs, attribute: Attribute, school: School):
         
     | 
| 6 | 
         
            -
                for buff in [buff for buff in existed_buffs if buff not in buffs]:
         
     | 
| 7 | 
         
            -
                    existed_buffs.remove(buff)
         
     | 
| 8 | 
         
            -
                    buff_id, buff_level, buff_stack = buff
         
     | 
| 9 | 
         
            -
                    buff = school.buffs[buff_id]
         
     | 
| 10 | 
         
            -
                    buff.buff_level = buff_level
         
     | 
| 11 | 
         
            -
                    for _ in range(buff_stack):
         
     | 
| 12 | 
         
            -
                        attribute, school.skills = (attribute, school.skills) - buff
         
     | 
| 13 | 
         
            -
             
     | 
| 14 | 
         
            -
                for buff in [buff for buff in buffs if buff not in existed_buffs]:
         
     | 
| 15 | 
         
            -
                    existed_buffs.append(buff)
         
     | 
| 16 | 
         
            -
                    buff_id, buff_level, buff_stack = buff
         
     | 
| 17 | 
         
            -
                    buff = school.buffs[buff_id]
         
     | 
| 18 | 
         
            -
                    buff.buff_level = buff_level
         
     | 
| 19 | 
         
            -
                    for _ in range(buff_stack):
         
     | 
| 20 | 
         
            -
                        attribute, school.skills = (attribute, school.skills) + buff
         
     | 
| 21 | 
         
            -
             
     | 
| 22 | 
         
            -
             
     | 
| 23 | 
         
            -
            def analyze_details(parser: Parser, attribute: Attribute):
         
     | 
| 24 | 
         
            -
                existed_buffs = []
         
     | 
| 25 | 
         
            -
                for start_time, record in parser.records.items():
         
     | 
| 26 | 
         
            -
                    for skill, status in record.items():
         
     | 
| 27 | 
         
            -
                        skill_id, skill_level = skill
         
     | 
| 28 | 
         
            -
                        skill = parser.school.skills[skill_id]
         
     | 
| 29 | 
         
            -
                        skill.skill_level = skill_level
         
     | 
| 30 | 
         
            -
                        for buffs, timeline in status.items():
         
     | 
| 31 | 
         
            -
                            refresh_status(existed_buffs, buffs, attribute, parser.school)
         
     | 
| 32 | 
         
            -
             
     | 
| 33 | 
         
            -
                            damage, critical_damage, expected_damage = skill(attribute)
         
     | 
| 34 | 
         
            -
             
     | 
| 35 | 
         
            -
                            status[buffs] = {
         
     | 
| 36 | 
         
            -
                                "damage": damage, "critical_damage": critical_damage, "expected_damage": expected_damage,
         
     | 
| 37 | 
         
            -
                                "timeline": [round(t / 1000, 2) for t in timeline],
         
     | 
| 38 | 
         
            -
                                "gradients": analyze_gradients(skill, attribute)
         
     | 
| 39 | 
         
            -
                            }
         
     | 
| 40 | 
         
            -
                    refresh_status(existed_buffs, [], attribute, parser.school)
         
     | 
| 41 | 
         
            -
             
     | 
| 42 | 
         
            -
             
     | 
| 43 | 
         
            -
            def analyze_gradients(skill, attribute):
         
     | 
| 44 | 
         
            -
                results = {}
         
     | 
| 45 | 
         
            -
                for attr, value in attribute.grad_attrs.items():
         
     | 
| 46 | 
         
            -
                    origin_value = getattr(attribute, attr)
         
     | 
| 47 | 
         
            -
                    setattr(attribute, attr, origin_value + value)
         
     | 
| 48 | 
         
            -
                    _, _, results[attr] = skill(attribute)
         
     | 
| 49 | 
         
            -
                    setattr(attribute, attr, origin_value)
         
     | 
| 50 | 
         
            -
                return results
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
    	
        base/constant.py
    CHANGED
    
    | 
         @@ -31,7 +31,7 @@ SHIELD_BASE_MAP = { 
     | 
|
| 31 | 
         
             
            }
         
     | 
| 32 | 
         | 
| 33 | 
         
             
            MAJOR_BASE = 41
         
     | 
| 34 | 
         
            -
             
     | 
| 35 | 
         | 
| 36 | 
         
             
            AGILITY_TO_CRITICAL_STRIKE = 655 / BINARY_SCALE
         
     | 
| 37 | 
         
             
            STRENGTH_TO_ATTACK_POWER = 153 / BINARY_SCALE
         
     | 
| 
         | 
|
| 31 | 
         
             
            }
         
     | 
| 32 | 
         | 
| 33 | 
         
             
            MAJOR_BASE = 41
         
     | 
| 34 | 
         
            +
            BASE_CRITICAL_POWER = 1.75
         
     | 
| 35 | 
         | 
| 36 | 
         
             
            AGILITY_TO_CRITICAL_STRIKE = 655 / BINARY_SCALE
         
     | 
| 37 | 
         
             
            STRENGTH_TO_ATTACK_POWER = 153 / BINARY_SCALE
         
     | 
    	
        base/recipe.py
    CHANGED
    
    | 
         @@ -1,22 +1,19 @@ 
     | 
|
| 
         | 
|
| 1 | 
         | 
| 2 | 
         | 
| 3 | 
         
             
            def damage_addition_recipe(skill_ids, value, name="伤害增加"):
         
     | 
| 4 | 
         
            -
                return  
     | 
| 5 | 
         
            -
                     
     | 
| 6 | 
         
            -
                    "gain_skills": {
         
     | 
| 7 | 
         
             
                        skill_id: {
         
     | 
| 8 | 
         
             
                            "skill_damage_addition": value
         
     | 
| 9 | 
         
             
                        } for skill_id in skill_ids
         
     | 
| 10 | 
         
            -
                    }
         
     | 
| 11 | 
         
            -
                }
         
     | 
| 12 | 
         | 
| 13 | 
         | 
| 14 | 
         
             
            def critical_strike_recipe(skill_ids, value, name="会心增加"):
         
     | 
| 15 | 
         
            -
                return  
     | 
| 16 | 
         
            -
                     
     | 
| 17 | 
         
            -
                    "gain_skills": {
         
     | 
| 18 | 
         
             
                        skill_id: {
         
     | 
| 19 | 
         
             
                            "skill_critical_strike": value
         
     | 
| 20 | 
         
             
                        } for skill_id in skill_ids
         
     | 
| 21 | 
         
            -
                    }
         
     | 
| 22 | 
         
            -
                }
         
     | 
| 
         | 
|
| 1 | 
         
            +
            from base.buff import Buff
         
     | 
| 2 | 
         | 
| 3 | 
         | 
| 4 | 
         
             
            def damage_addition_recipe(skill_ids, value, name="伤害增加"):
         
     | 
| 5 | 
         
            +
                return Buff(
         
     | 
| 6 | 
         
            +
                    -1, name, gain_skills={
         
     | 
| 
         | 
|
| 7 | 
         
             
                        skill_id: {
         
     | 
| 8 | 
         
             
                            "skill_damage_addition": value
         
     | 
| 9 | 
         
             
                        } for skill_id in skill_ids
         
     | 
| 10 | 
         
            +
                    })
         
     | 
| 
         | 
|
| 11 | 
         | 
| 12 | 
         | 
| 13 | 
         
             
            def critical_strike_recipe(skill_ids, value, name="会心增加"):
         
     | 
| 14 | 
         
            +
                return Buff(
         
     | 
| 15 | 
         
            +
                    -1, name, gain_skills={
         
     | 
| 
         | 
|
| 16 | 
         
             
                        skill_id: {
         
     | 
| 17 | 
         
             
                            "skill_critical_strike": value
         
     | 
| 18 | 
         
             
                        } for skill_id in skill_ids
         
     | 
| 19 | 
         
            +
                    })
         
     | 
| 
         | 
    	
        base/skill.py
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 1 | 
         
             
            from base.attribute import Attribute
         
     | 
| 2 | 
         
             
            from base.constant import *
         
     | 
| 3 | 
         
            -
            from  
     | 
| 4 | 
         | 
| 5 | 
         
             
            from typing import List, Union
         
     | 
| 6 | 
         
             
            from dataclasses import dataclass
         
     | 
| 
         @@ -31,6 +31,10 @@ class Skill: 
     | 
|
| 31 | 
         
             
                _skill_critical_strike: int = 0
         
     | 
| 32 | 
         
             
                _skill_critical_power: int = 0
         
     | 
| 33 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 34 | 
         
             
                @property
         
     | 
| 35 | 
         
             
                def damage_base(self):
         
     | 
| 36 | 
         
             
                    if isinstance(self._damage_base, list):
         
     | 
| 
         @@ -154,7 +158,7 @@ class Skill: 
     | 
|
| 154 | 
         | 
| 155 | 
         
             
                    expected_damage = critical_strike * critical_damage + (1 - critical_strike) * damage
         
     | 
| 156 | 
         | 
| 157 | 
         
            -
                    return damage, critical_damage, expected_damage
         
     | 
| 158 | 
         | 
| 159 | 
         | 
| 160 | 
         
             
            class PhysicalDamage(Skill):
         
     | 
| 
         | 
|
| 1 | 
         
             
            from base.attribute import Attribute
         
     | 
| 2 | 
         
             
            from base.constant import *
         
     | 
| 3 | 
         
            +
            from utils.damage import *
         
     | 
| 4 | 
         | 
| 5 | 
         
             
            from typing import List, Union
         
     | 
| 6 | 
         
             
            from dataclasses import dataclass
         
     | 
| 
         | 
|
| 31 | 
         
             
                _skill_critical_strike: int = 0
         
     | 
| 32 | 
         
             
                _skill_critical_power: int = 0
         
     | 
| 33 | 
         | 
| 34 | 
         
            +
                @property
         
     | 
| 35 | 
         
            +
                def display_name(self):
         
     | 
| 36 | 
         
            +
                    return f"{self.skill_name}/{self.skill_id}-{self.skill_level}"
         
     | 
| 37 | 
         
            +
             
     | 
| 38 | 
         
             
                @property
         
     | 
| 39 | 
         
             
                def damage_base(self):
         
     | 
| 40 | 
         
             
                    if isinstance(self._damage_base, list):
         
     | 
| 
         | 
|
| 158 | 
         | 
| 159 | 
         
             
                    expected_damage = critical_strike * critical_damage + (1 - critical_strike) * damage
         
     | 
| 160 | 
         | 
| 161 | 
         
            +
                    return damage, critical_strike, critical_damage, expected_damage
         
     | 
| 162 | 
         | 
| 163 | 
         | 
| 164 | 
         
             
            class PhysicalDamage(Skill):
         
     | 
    	
        general/recipes.py
    ADDED
    
    | 
         @@ -0,0 +1,66 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            from base.status import Status
         
     | 
| 2 | 
         
            +
             
     | 
| 3 | 
         
            +
             
     | 
| 4 | 
         
            +
            class EmptyRecipe:
         
     | 
| 5 | 
         
            +
                def __call__(self, status: Status):
         
     | 
| 6 | 
         
            +
                    pass
         
     | 
| 7 | 
         
            +
             
     | 
| 8 | 
         
            +
             
     | 
| 9 | 
         
            +
            class DamageRecipe:
         
     | 
| 10 | 
         
            +
                def __init__(self, skills, value):
         
     | 
| 11 | 
         
            +
                    self.skills = skills
         
     | 
| 12 | 
         
            +
                    self.value = value
         
     | 
| 13 | 
         
            +
             
     | 
| 14 | 
         
            +
                def __call__(self, status: Status):
         
     | 
| 15 | 
         
            +
                    for skill in self.skills:
         
     | 
| 16 | 
         
            +
                        status.skills[skill].skill_damage_addition += self.value
         
     | 
| 17 | 
         
            +
             
     | 
| 18 | 
         
            +
             
     | 
| 19 | 
         
            +
            class AttackPowerRecipe:
         
     | 
| 20 | 
         
            +
                def __init__(self, skills, value):
         
     | 
| 21 | 
         
            +
                    self.skills = skills
         
     | 
| 22 | 
         
            +
                    self.value = value
         
     | 
| 23 | 
         
            +
             
     | 
| 24 | 
         
            +
                def __call__(self, status: Status):
         
     | 
| 25 | 
         
            +
                    for skill in self.skills:
         
     | 
| 26 | 
         
            +
                        status.skills[skill].attack_power_cof_gain += self.value
         
     | 
| 27 | 
         
            +
             
     | 
| 28 | 
         
            +
             
     | 
| 29 | 
         
            +
            class CriticalRecipe:
         
     | 
| 30 | 
         
            +
                def __init__(self, skills, value):
         
     | 
| 31 | 
         
            +
                    self.skills = skills
         
     | 
| 32 | 
         
            +
                    self.value = value
         
     | 
| 33 | 
         
            +
             
     | 
| 34 | 
         
            +
                def __call__(self, status: Status):
         
     | 
| 35 | 
         
            +
                    for skill in self.skills:
         
     | 
| 36 | 
         
            +
                        status.skills[skill].skill_critical_strike += self.value
         
     | 
| 37 | 
         
            +
             
     | 
| 38 | 
         
            +
             
     | 
| 39 | 
         
            +
            class CDReductionRecipe:
         
     | 
| 40 | 
         
            +
                def __init__(self, skills, value):
         
     | 
| 41 | 
         
            +
                    self.skills = skills
         
     | 
| 42 | 
         
            +
                    self.value = value
         
     | 
| 43 | 
         
            +
             
     | 
| 44 | 
         
            +
                def __call__(self, status: Status):
         
     | 
| 45 | 
         
            +
                    for skill in self.skills:
         
     | 
| 46 | 
         
            +
                        status.skills[skill].cd_base -= self.value
         
     | 
| 47 | 
         
            +
             
     | 
| 48 | 
         
            +
             
     | 
| 49 | 
         
            +
            class TickIncreaseRecipe:
         
     | 
| 50 | 
         
            +
                def __init__(self, skills, value):
         
     | 
| 51 | 
         
            +
                    self.skills = skills
         
     | 
| 52 | 
         
            +
                    self.value = value
         
     | 
| 53 | 
         
            +
             
     | 
| 54 | 
         
            +
                def __call__(self, status: Status):
         
     | 
| 55 | 
         
            +
                    for skill in self.skills:
         
     | 
| 56 | 
         
            +
                        status.skills[skill].tick_base += self.value
         
     | 
| 57 | 
         
            +
             
     | 
| 58 | 
         
            +
             
     | 
| 59 | 
         
            +
            class IntervalReductionRecipe:
         
     | 
| 60 | 
         
            +
                def __init__(self, skills, value):
         
     | 
| 61 | 
         
            +
                    self.skills = skills
         
     | 
| 62 | 
         
            +
                    self.value = value
         
     | 
| 63 | 
         
            +
             
     | 
| 64 | 
         
            +
                def __call__(self, status: Status):
         
     | 
| 65 | 
         
            +
                    for skill in self.skills:
         
     | 
| 66 | 
         
            +
                        status.skills[skill].interval_base -= self.value
         
     | 
    	
        qt/app.py
    CHANGED
    
    | 
         @@ -8,18 +8,17 @@ from qt.scripts.top import top_script 
     | 
|
| 8 | 
         
             
            from qt.components.equipments import EquipmentsWidget
         
     | 
| 9 | 
         
             
            from qt.scripts.equipments import equipments_script
         
     | 
| 10 | 
         
             
            from qt.components.talents import TalentsWidget
         
     | 
| 11 | 
         
            -
             
     | 
| 12 | 
         
            -
             
     | 
| 13 | 
         
            -
             
     | 
| 14 | 
         
             
            # from qt.components.consumables import ConsumablesWidget
         
     | 
| 15 | 
         
             
            # from qt.scripts.consumables import consumables_script
         
     | 
| 16 | 
         
             
            # from qt.components.bonuses import BonusesWidget
         
     | 
| 17 | 
         
             
            # from qt.scripts.bonuses import bonuses_script
         
     | 
| 18 | 
         
            -
             
     | 
| 19 | 
         
            -
             
     | 
| 20 | 
         | 
| 21 | 
         
            -
            from PySide6.QtWidgets import QApplication, QMainWindow, QStyleFactory,  
     | 
| 22 | 
         
            -
                QGridLayout
         
     | 
| 23 | 
         | 
| 24 | 
         | 
| 25 | 
         
             
            class MainWindow(QMainWindow):
         
     | 
| 
         @@ -30,9 +29,6 @@ class MainWindow(QMainWindow): 
     | 
|
| 30 | 
         | 
| 31 | 
         
             
                    icon = QIcon("qt/assets/icon.ico")
         
     | 
| 32 | 
         
             
                    self.setWindowIcon(icon)
         
     | 
| 33 | 
         
            -
                    self.message_box = QMessageBox()
         
     | 
| 34 | 
         
            -
             
     | 
| 35 | 
         
            -
                    self.message_box.setWindowIcon(icon)
         
     | 
| 36 | 
         | 
| 37 | 
         
             
                    self.central_widget = QWidget(self)
         
     | 
| 38 | 
         
             
                    self.setCentralWidget(self.central_widget)
         
     | 
| 
         @@ -46,20 +42,31 @@ class MainWindow(QMainWindow): 
     | 
|
| 46 | 
         
             
                    layout.addWidget(self.top_widget)
         
     | 
| 47 | 
         
             
                    layout.addWidget(self.config_widget)
         
     | 
| 48 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 49 | 
         
             
                    self.equipments_widget = EquipmentsWidget()
         
     | 
| 50 | 
         
             
                    config_layout.addWidget(self.equipments_widget, 0, 0)
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 51 | 
         | 
| 52 | 
         
            -
                    self. 
     | 
| 53 | 
         
            -
                    config_layout.addWidget(self. 
     | 
| 
         | 
|
| 54 | 
         | 
| 55 | 
         
            -
                    parser = top_script( 
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 56 | 
         
             
                    equipments = equipments_script(self.equipments_widget)
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 57 | 
         | 
| 58 | 
         
            -
                    #
         
     | 
| 59 | 
         
            -
                    # config_layout.addWidget(self.equipments_widget, 1, 0)
         
     | 
| 60 | 
         
            -
                    #
         
     | 
| 61 | 
         
            -
                    # config_layout.addWidget(self.equipments_widget, 1, 1)
         
     | 
| 62 | 
         
            -
                    #
         
     | 
| 63 | 
         
             
                    # self.talents_widget = TalentsWidget()
         
     | 
| 64 | 
         
             
                    # self.tab_widget.addTab(self.talents_widget, "奇穴")
         
     | 
| 65 | 
         
             
                    #
         
     | 
| 
         | 
|
| 8 | 
         
             
            from qt.components.equipments import EquipmentsWidget
         
     | 
| 9 | 
         
             
            from qt.scripts.equipments import equipments_script
         
     | 
| 10 | 
         
             
            from qt.components.talents import TalentsWidget
         
     | 
| 11 | 
         
            +
            from qt.scripts.talents import talents_script
         
     | 
| 12 | 
         
            +
            from qt.components.recipes import RecipesWidget
         
     | 
| 13 | 
         
            +
            from qt.scripts.recipes import recipes_script
         
     | 
| 14 | 
         
             
            # from qt.components.consumables import ConsumablesWidget
         
     | 
| 15 | 
         
             
            # from qt.scripts.consumables import consumables_script
         
     | 
| 16 | 
         
             
            # from qt.components.bonuses import BonusesWidget
         
     | 
| 17 | 
         
             
            # from qt.scripts.bonuses import bonuses_script
         
     | 
| 18 | 
         
            +
            from qt.components.dashboard import DashboardWidget
         
     | 
| 19 | 
         
            +
            from qt.scripts.dashboard import dashboard_script
         
     | 
| 20 | 
         | 
| 21 | 
         
            +
            from PySide6.QtWidgets import QApplication, QMainWindow, QStyleFactory, QVBoxLayout, QGridLayout, QWidget, QSizePolicy
         
     | 
| 
         | 
|
| 22 | 
         | 
| 23 | 
         | 
| 24 | 
         
             
            class MainWindow(QMainWindow):
         
     | 
| 
         | 
|
| 29 | 
         | 
| 30 | 
         
             
                    icon = QIcon("qt/assets/icon.ico")
         
     | 
| 31 | 
         
             
                    self.setWindowIcon(icon)
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 32 | 
         | 
| 33 | 
         
             
                    self.central_widget = QWidget(self)
         
     | 
| 34 | 
         
             
                    self.setCentralWidget(self.central_widget)
         
     | 
| 
         | 
|
| 42 | 
         
             
                    layout.addWidget(self.top_widget)
         
     | 
| 43 | 
         
             
                    layout.addWidget(self.config_widget)
         
     | 
| 44 | 
         | 
| 45 | 
         
            +
                    self.dashboard_widget = DashboardWidget()
         
     | 
| 46 | 
         
            +
                    config_layout.addWidget(self.dashboard_widget, 0, 1)
         
     | 
| 47 | 
         
            +
                    self.dashboard_widget.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.MinimumExpanding)
         
     | 
| 48 | 
         
            +
             
     | 
| 49 | 
         
             
                    self.equipments_widget = EquipmentsWidget()
         
     | 
| 50 | 
         
             
                    config_layout.addWidget(self.equipments_widget, 0, 0)
         
     | 
| 51 | 
         
            +
                    # self.equipments_widget.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.MinimumExpanding)
         
     | 
| 52 | 
         
            +
             
     | 
| 53 | 
         
            +
                    self.talents_widget = TalentsWidget()
         
     | 
| 54 | 
         
            +
                    config_layout.addWidget(self.talents_widget, 1, 0)
         
     | 
| 55 | 
         
            +
                    # self.talents_widget.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.MinimumExpanding)
         
     | 
| 56 | 
         | 
| 57 | 
         
            +
                    self.recipes_widget = RecipesWidget()
         
     | 
| 58 | 
         
            +
                    config_layout.addWidget(self.recipes_widget, 2, 0)
         
     | 
| 59 | 
         
            +
                    # self.recipes_widget.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.MinimumExpanding)
         
     | 
| 60 | 
         | 
| 61 | 
         
            +
                    parser = top_script(
         
     | 
| 62 | 
         
            +
                        self.top_widget, self.config_widget, self.dashboard_widget,
         
     | 
| 63 | 
         
            +
                        self.equipments_widget, self.talents_widget, self.recipes_widget
         
     | 
| 64 | 
         
            +
                    )
         
     | 
| 65 | 
         
             
                    equipments = equipments_script(self.equipments_widget)
         
     | 
| 66 | 
         
            +
                    talents = talents_script(self.talents_widget)
         
     | 
| 67 | 
         
            +
                    recipes = recipes_script(self.recipes_widget)
         
     | 
| 68 | 
         
            +
                    dashboard_script(parser, equipments, talents, recipes, self.dashboard_widget)
         
     | 
| 69 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 70 | 
         
             
                    # self.talents_widget = TalentsWidget()
         
     | 
| 71 | 
         
             
                    # self.tab_widget.addTab(self.talents_widget, "奇穴")
         
     | 
| 72 | 
         
             
                    #
         
     | 
    	
        qt/components/__init__.py
    CHANGED
    
    | 
         @@ -1,5 +1,5 @@ 
     | 
|
| 1 | 
         
             
            from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QAbstractItemView, QTableWidgetItem, \
         
     | 
| 2 | 
         
            -
                QHeaderView, QSizePolicy
         
     | 
| 3 | 
         
             
            from PySide6.QtWidgets import QComboBox, QRadioButton, QTextBrowser, QTextEdit, QSpinBox, QListWidget, QTableWidget
         
     | 
| 4 | 
         
             
            from PySide6.QtCore import Qt
         
     | 
| 5 | 
         | 
| 
         @@ -31,34 +31,39 @@ class TableWithLabel(LabelWidget): 
     | 
|
| 31 | 
         
             
                    if headers:
         
     | 
| 32 | 
         
             
                        self.table.setColumnCount(len(headers))
         
     | 
| 33 | 
         
             
                        self.table.setHorizontalHeaderLabels(headers)
         
     | 
| 
         | 
|
| 
         | 
|
| 34 | 
         | 
| 35 | 
         
             
                    self.table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 36 | 
         | 
| 37 | 
         
             
                    layout.addWidget(self.label)
         
     | 
| 38 | 
         
             
                    layout.addWidget(self.table)
         
     | 
| 39 | 
         | 
| 40 | 
         
            -
                    layout.addStretch()
         
     | 
| 41 | 
         
            -
             
     | 
| 42 | 
         
             
                def set_content(self, content):
         
     | 
| 43 | 
         
             
                    self.table.setRowCount(len(content))
         
     | 
| 44 | 
         | 
| 45 | 
         
             
                    for i, row in enumerate(content):
         
     | 
| 46 | 
         
             
                        for j, e in enumerate(row):
         
     | 
| 47 | 
         
             
                            self.table.setItem(i, j, QTableWidgetItem(e))
         
     | 
| 
         | 
|
| 48 | 
         
             
                    self.table.resizeColumnsToContents()
         
     | 
| 49 | 
         | 
| 50 | 
         | 
| 51 | 
         
             
            class ListWithLabel(LabelWidget):
         
     | 
| 52 | 
         
            -
                def __init__(self, label, items: list = None):
         
     | 
| 53 | 
         
             
                    super().__init__(label)
         
     | 
| 54 | 
         
            -
                    layout = QVBoxLayout()
         
     | 
| 55 | 
         
            -
             
     | 
| 
         | 
|
| 56 | 
         | 
| 57 | 
         
             
                    self.list = QListWidget()
         
     | 
| 58 | 
         
             
                    self.list.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection)
         
     | 
| 59 | 
         | 
| 60 | 
         
             
                    if items:
         
     | 
| 61 | 
         
            -
                        self. 
     | 
| 62 | 
         
             
                    layout.addWidget(self.label)
         
     | 
| 63 | 
         
             
                    layout.addWidget(self.list)
         
     | 
| 64 | 
         | 
| 
         @@ -86,11 +91,12 @@ class ComboWithLabel(LabelWidget): 
     | 
|
| 86 | 
         | 
| 87 | 
         
             
                    layout.addStretch()
         
     | 
| 88 | 
         | 
| 89 | 
         
            -
                def set_items(self, items):
         
     | 
| 90 | 
         
             
                    self.combo_box.blockSignals(True)
         
     | 
| 91 | 
         
             
                    self.combo_box.clear()
         
     | 
| 92 | 
         
             
                    self.combo_box.addItems(items)
         
     | 
| 93 | 
         
             
                    self.combo_box.blockSignals(False)
         
     | 
| 
         | 
|
| 94 | 
         | 
| 95 | 
         | 
| 96 | 
         
             
            class RadioWithLabel(LabelWidget):
         
     | 
| 
         @@ -125,7 +131,7 @@ class SpinWithLabel(LabelWidget): 
     | 
|
| 125 | 
         
             
                    if maximum:
         
     | 
| 126 | 
         
             
                        self.spin_box.setMaximum(maximum + 1)
         
     | 
| 127 | 
         
             
                    else:
         
     | 
| 128 | 
         
            -
                        self.spin_box.setMaximum( 
     | 
| 129 | 
         | 
| 130 | 
         
             
                    if value:
         
     | 
| 131 | 
         
             
                        self.spin_box.setValue(value)
         
     | 
| 
         @@ -173,3 +179,6 @@ class LabelWithLabel(QWidget): 
     | 
|
| 173 | 
         
             
                    layout.addWidget(self.text)
         
     | 
| 174 | 
         | 
| 175 | 
         
             
                    layout.addStretch()
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
             
            from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QAbstractItemView, QTableWidgetItem, \
         
     | 
| 2 | 
         
            +
                QHeaderView, QSizePolicy, QListWidgetItem, QSpacerItem
         
     | 
| 3 | 
         
             
            from PySide6.QtWidgets import QComboBox, QRadioButton, QTextBrowser, QTextEdit, QSpinBox, QListWidget, QTableWidget
         
     | 
| 4 | 
         
             
            from PySide6.QtCore import Qt
         
     | 
| 5 | 
         | 
| 
         | 
|
| 31 | 
         
             
                    if headers:
         
     | 
| 32 | 
         
             
                        self.table.setColumnCount(len(headers))
         
     | 
| 33 | 
         
             
                        self.table.setHorizontalHeaderLabels(headers)
         
     | 
| 34 | 
         
            +
                    else:
         
     | 
| 35 | 
         
            +
                        self.table.horizontalHeader().setVisible(False)
         
     | 
| 36 | 
         | 
| 37 | 
         
             
                    self.table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
         
     | 
| 38 | 
         
            +
                    self.table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
         
     | 
| 39 | 
         
            +
                    self.table.verticalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
         
     | 
| 40 | 
         
            +
                    self.table.verticalHeader().setVisible(False)
         
     | 
| 41 | 
         | 
| 42 | 
         
             
                    layout.addWidget(self.label)
         
     | 
| 43 | 
         
             
                    layout.addWidget(self.table)
         
     | 
| 44 | 
         | 
| 
         | 
|
| 
         | 
|
| 45 | 
         
             
                def set_content(self, content):
         
     | 
| 46 | 
         
             
                    self.table.setRowCount(len(content))
         
     | 
| 47 | 
         | 
| 48 | 
         
             
                    for i, row in enumerate(content):
         
     | 
| 49 | 
         
             
                        for j, e in enumerate(row):
         
     | 
| 50 | 
         
             
                            self.table.setItem(i, j, QTableWidgetItem(e))
         
     | 
| 51 | 
         
            +
             
     | 
| 52 | 
         
             
                    self.table.resizeColumnsToContents()
         
     | 
| 53 | 
         | 
| 54 | 
         | 
| 55 | 
         
             
            class ListWithLabel(LabelWidget):
         
     | 
| 56 | 
         
            +
                def __init__(self, label, max_select: int = 4, items: list = None):
         
     | 
| 57 | 
         
             
                    super().__init__(label)
         
     | 
| 58 | 
         
            +
                    layout = QVBoxLayout(self)
         
     | 
| 59 | 
         
            +
             
     | 
| 60 | 
         
            +
                    self.max_select = max_select
         
     | 
| 61 | 
         | 
| 62 | 
         
             
                    self.list = QListWidget()
         
     | 
| 63 | 
         
             
                    self.list.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection)
         
     | 
| 64 | 
         | 
| 65 | 
         
             
                    if items:
         
     | 
| 66 | 
         
            +
                        self.set_items(items)
         
     | 
| 67 | 
         
             
                    layout.addWidget(self.label)
         
     | 
| 68 | 
         
             
                    layout.addWidget(self.list)
         
     | 
| 69 | 
         | 
| 
         | 
|
| 91 | 
         | 
| 92 | 
         
             
                    layout.addStretch()
         
     | 
| 93 | 
         | 
| 94 | 
         
            +
                def set_items(self, items, default_index=0):
         
     | 
| 95 | 
         
             
                    self.combo_box.blockSignals(True)
         
     | 
| 96 | 
         
             
                    self.combo_box.clear()
         
     | 
| 97 | 
         
             
                    self.combo_box.addItems(items)
         
     | 
| 98 | 
         
             
                    self.combo_box.blockSignals(False)
         
     | 
| 99 | 
         
            +
                    self.combo_box.setCurrentIndex(default_index)
         
     | 
| 100 | 
         | 
| 101 | 
         | 
| 102 | 
         
             
            class RadioWithLabel(LabelWidget):
         
     | 
| 
         | 
|
| 131 | 
         
             
                    if maximum:
         
     | 
| 132 | 
         
             
                        self.spin_box.setMaximum(maximum + 1)
         
     | 
| 133 | 
         
             
                    else:
         
     | 
| 134 | 
         
            +
                        self.spin_box.setMaximum(10 ** 8)
         
     | 
| 135 | 
         | 
| 136 | 
         
             
                    if value:
         
     | 
| 137 | 
         
             
                        self.spin_box.setValue(value)
         
     | 
| 
         | 
|
| 179 | 
         
             
                    layout.addWidget(self.text)
         
     | 
| 180 | 
         | 
| 181 | 
         
             
                    layout.addStretch()
         
     | 
| 182 | 
         
            +
             
     | 
| 183 | 
         
            +
                def set_text(self, text):
         
     | 
| 184 | 
         
            +
                    self.text.setText(text)
         
     | 
    	
        qt/components/dashboard.py
    ADDED
    
    | 
         @@ -0,0 +1,80 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QTabWidget
         
     | 
| 2 | 
         
            +
             
     | 
| 3 | 
         
            +
            from qt.components import ComboWithLabel, SpinWithLabel, TextWithLabel, LabelWithLabel, TableWithLabel
         
     | 
| 4 | 
         
            +
            from base.constant import SHIELD_BASE_MAP
         
     | 
| 5 | 
         
            +
             
     | 
| 6 | 
         
            +
             
     | 
| 7 | 
         
            +
            class DashboardWidget(QWidget):
         
     | 
| 8 | 
         
            +
                def __init__(self):
         
     | 
| 9 | 
         
            +
                    super().__init__()
         
     | 
| 10 | 
         
            +
                    layout = QVBoxLayout()
         
     | 
| 11 | 
         
            +
                    self.setLayout(layout)
         
     | 
| 12 | 
         
            +
             
     | 
| 13 | 
         
            +
                    top = QWidget()
         
     | 
| 14 | 
         
            +
                    top_layout = QHBoxLayout(top)
         
     | 
| 15 | 
         
            +
                    layout.addWidget(top)
         
     | 
| 16 | 
         
            +
             
     | 
| 17 | 
         
            +
                    self.fight_select = ComboWithLabel("选择战斗")
         
     | 
| 18 | 
         
            +
                    top_layout.addWidget(self.fight_select)
         
     | 
| 19 | 
         
            +
                    self.target_level = ComboWithLabel("目标等级", items=[str(level) for level in SHIELD_BASE_MAP])
         
     | 
| 20 | 
         
            +
                    top_layout.addWidget(self.target_level)
         
     | 
| 21 | 
         
            +
                    self.duration = SpinWithLabel("战斗时长", maximum=3600, value=180)
         
     | 
| 22 | 
         
            +
                    top_layout.addWidget(self.duration)
         
     | 
| 23 | 
         
            +
             
     | 
| 24 | 
         
            +
                    self.button = QPushButton(text="开始模拟!")
         
     | 
| 25 | 
         
            +
                    layout.addWidget(self.button)
         
     | 
| 26 | 
         
            +
             
     | 
| 27 | 
         
            +
                    bottom = QWidget()
         
     | 
| 28 | 
         
            +
                    bottom_layout = QHBoxLayout(bottom)
         
     | 
| 29 | 
         
            +
                    layout.addWidget(bottom)
         
     | 
| 30 | 
         
            +
             
     | 
| 31 | 
         
            +
                    tab = QTabWidget()
         
     | 
| 32 | 
         
            +
                    bottom_layout.addWidget(tab, 2)
         
     | 
| 33 | 
         
            +
                    result = QWidget()
         
     | 
| 34 | 
         
            +
                    result_layout = QVBoxLayout(result)
         
     | 
| 35 | 
         
            +
                    bottom_layout.addWidget(result, 1)
         
     | 
| 36 | 
         
            +
             
     | 
| 37 | 
         
            +
                    attribute = QWidget()
         
     | 
| 38 | 
         
            +
                    attribute_layout = QHBoxLayout(attribute)
         
     | 
| 39 | 
         
            +
                    tab.addTab(attribute, "属性")
         
     | 
| 40 | 
         
            +
             
     | 
| 41 | 
         
            +
                    self.init_attribute = TableWithLabel("增益前属性", column_count=2)
         
     | 
| 42 | 
         
            +
                    attribute_layout.addWidget(self.init_attribute)
         
     | 
| 43 | 
         
            +
                    self.final_attribute = TableWithLabel("增益后属性", column_count=2)
         
     | 
| 44 | 
         
            +
                    attribute_layout.addWidget(self.final_attribute)
         
     | 
| 45 | 
         
            +
             
     | 
| 46 | 
         
            +
                    detail = QWidget()
         
     | 
| 47 | 
         
            +
                    detail_layout = QVBoxLayout(detail)
         
     | 
| 48 | 
         
            +
                    tab.addTab(detail, "伤害总结")
         
     | 
| 49 | 
         
            +
                    self.details = {}
         
     | 
| 50 | 
         
            +
                    self.skill_combo = ComboWithLabel("选择技能")
         
     | 
| 51 | 
         
            +
                    detail_layout.addWidget(self.skill_combo)
         
     | 
| 52 | 
         
            +
                    self.status_combo = ComboWithLabel("选择增益")
         
     | 
| 53 | 
         
            +
                    detail_layout.addWidget(self.status_combo)
         
     | 
| 54 | 
         
            +
                    detail_table = QWidget()
         
     | 
| 55 | 
         
            +
                    detail_table_layout = QHBoxLayout(detail_table)
         
     | 
| 56 | 
         
            +
                    self.damage_detail = TableWithLabel("伤害细节", column_count=2)
         
     | 
| 57 | 
         
            +
                    detail_table_layout.addWidget(self.damage_detail)
         
     | 
| 58 | 
         
            +
                    self.gradient_detail = TableWithLabel("属性收益", column_count=2)
         
     | 
| 59 | 
         
            +
                    detail_table_layout.addWidget(self.damage_detail)
         
     | 
| 60 | 
         
            +
                    detail_layout.addWidget(detail_table)
         
     | 
| 61 | 
         
            +
             
     | 
| 62 | 
         
            +
                    detail_layout.addStretch()
         
     | 
| 63 | 
         
            +
             
     | 
| 64 | 
         
            +
                    self.summary = TableWithLabel("伤害统计", headers=["技能/次数", "命中/%", "会心/%", "伤害/%"])
         
     | 
| 65 | 
         
            +
             
     | 
| 66 | 
         
            +
                    tab.addTab(self.summary, "战斗总结")
         
     | 
| 67 | 
         
            +
             
     | 
| 68 | 
         
            +
                    self.dps = LabelWithLabel("每秒伤害")
         
     | 
| 69 | 
         
            +
                    result_layout.addWidget(self.dps)
         
     | 
| 70 | 
         
            +
             
     | 
| 71 | 
         
            +
                    self.gradients = TableWithLabel("属性收益", column_count=2)
         
     | 
| 72 | 
         
            +
             
     | 
| 73 | 
         
            +
                    result_layout.addWidget(self.gradients)
         
     | 
| 74 | 
         
            +
             
     | 
| 75 | 
         
            +
                    result_layout.addStretch()
         
     | 
| 76 | 
         
            +
             
     | 
| 77 | 
         
            +
                    layout.addStretch()
         
     | 
| 78 | 
         
            +
             
     | 
| 79 | 
         
            +
             
     | 
| 80 | 
         
            +
             
     | 
    	
        qt/components/equipments.py
    CHANGED
    
    | 
         @@ -3,8 +3,8 @@ import os 
     | 
|
| 3 | 
         | 
| 4 | 
         
             
            from qt.constant import POSITION_MAP, STONES_POSITIONS, EQUIPMENTS_DIR, ENCHANTS_DIR, STONES_DIR, MAX_STONE_ATTR
         
     | 
| 5 | 
         
             
            from qt.constant import EMBED_POSITIONS, MAX_EMBED_LEVEL, MAX_STONE_LEVEL, SPECIAL_ENCHANT_POSITIONS
         
     | 
| 6 | 
         
            -
            from qt.components import ComboWithLabel, RadioWithLabel,  
     | 
| 7 | 
         
            -
            from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QTabWidget
         
     | 
| 8 | 
         
             
            from PySide6.QtCore import Qt
         
     | 
| 9 | 
         | 
| 10 | 
         | 
| 
         @@ -72,14 +72,15 @@ class EquipmentWidget(QWidget): 
     | 
|
| 72 | 
         
             
                            stone_attr = ComboWithLabel(f"五彩石属性-{i + 1}")
         
     | 
| 73 | 
         
             
                            self.stone_attrs.append(stone_attr)
         
     | 
| 74 | 
         
             
                            detail_layout.addWidget(stone_attr, 2, i + 1)
         
     | 
| 
         | 
|
| 75 | 
         | 
| 76 | 
         
            -
                    self.base_attr =  
     | 
| 77 | 
         
             
                    output_layout.addWidget(self.base_attr)
         
     | 
| 78 | 
         
            -
                    self.magic_attr =  
     | 
| 79 | 
         
             
                    output_layout.addWidget(self.magic_attr)
         
     | 
| 80 | 
         
            -
                    self.embed_attr =  
     | 
| 81 | 
         
             
                    output_layout.addWidget(self.embed_attr)
         
     | 
| 82 | 
         
            -
                     
     | 
| 83 | 
         | 
| 84 | 
         | 
| 85 | 
         
             
            class EquipmentsWidget(QTabWidget):
         
     | 
| 
         | 
|
| 3 | 
         | 
| 4 | 
         
             
            from qt.constant import POSITION_MAP, STONES_POSITIONS, EQUIPMENTS_DIR, ENCHANTS_DIR, STONES_DIR, MAX_STONE_ATTR
         
     | 
| 5 | 
         
             
            from qt.constant import EMBED_POSITIONS, MAX_EMBED_LEVEL, MAX_STONE_LEVEL, SPECIAL_ENCHANT_POSITIONS
         
     | 
| 6 | 
         
            +
            from qt.components import ComboWithLabel, RadioWithLabel, TableWithLabel
         
     | 
| 7 | 
         
            +
            from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QTabWidget, QSizePolicy, QSpacerItem
         
     | 
| 8 | 
         
             
            from PySide6.QtCore import Qt
         
     | 
| 9 | 
         | 
| 10 | 
         | 
| 
         | 
|
| 72 | 
         
             
                            stone_attr = ComboWithLabel(f"五彩石属性-{i + 1}")
         
     | 
| 73 | 
         
             
                            self.stone_attrs.append(stone_attr)
         
     | 
| 74 | 
         
             
                            detail_layout.addWidget(stone_attr, 2, i + 1)
         
     | 
| 75 | 
         
            +
                    self.detail_widget.hide()
         
     | 
| 76 | 
         | 
| 77 | 
         
            +
                    self.base_attr = TableWithLabel("基本属性", column_count=2)
         
     | 
| 78 | 
         
             
                    output_layout.addWidget(self.base_attr)
         
     | 
| 79 | 
         
            +
                    self.magic_attr = TableWithLabel("精炼属性", column_count=2)
         
     | 
| 80 | 
         
             
                    output_layout.addWidget(self.magic_attr)
         
     | 
| 81 | 
         
            +
                    self.embed_attr = TableWithLabel("镶嵌属性", column_count=2)
         
     | 
| 82 | 
         
             
                    output_layout.addWidget(self.embed_attr)
         
     | 
| 83 | 
         
            +
                    self.output_widget.hide()
         
     | 
| 84 | 
         | 
| 85 | 
         | 
| 86 | 
         
             
            class EquipmentsWidget(QTabWidget):
         
     | 
    	
        qt/components/recipes.py
    ADDED
    
    | 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            from qt.components import ListWithLabel
         
     | 
| 2 | 
         
            +
            from PySide6.QtWidgets import QWidget, QGridLayout
         
     | 
| 3 | 
         
            +
             
     | 
| 4 | 
         
            +
            from qt.constant import MAX_RECIPE_SKILLS
         
     | 
| 5 | 
         
            +
             
     | 
| 6 | 
         
            +
             
     | 
| 7 | 
         
            +
            class RecipesWidget(QWidget):
         
     | 
| 8 | 
         
            +
                def __init__(self):
         
     | 
| 9 | 
         
            +
                    super().__init__()
         
     | 
| 10 | 
         
            +
                    layout = QGridLayout()
         
     | 
| 11 | 
         
            +
                    self.setLayout(layout)
         
     | 
| 12 | 
         
            +
             
     | 
| 13 | 
         
            +
                    self.recipes = []
         
     | 
| 14 | 
         
            +
             
     | 
| 15 | 
         
            +
                    columns = 6
         
     | 
| 16 | 
         
            +
                    rows = MAX_RECIPE_SKILLS // columns
         
     | 
| 17 | 
         
            +
                    for i in range(rows):
         
     | 
| 18 | 
         
            +
                        for j in range(columns):
         
     | 
| 19 | 
         
            +
                            recipe = ListWithLabel("")
         
     | 
| 20 | 
         
            +
                            self.recipes.append(recipe)
         
     | 
| 21 | 
         
            +
                            layout.addWidget(recipe, i, j)
         
     | 
| 22 | 
         
            +
                    
         
     | 
| 23 | 
         
            +
                def __getitem__(self, item) -> ListWithLabel:
         
     | 
| 24 | 
         
            +
                    return self.recipes[item]
         
     | 
| 25 | 
         
            +
             
     | 
| 26 | 
         
            +
                def values(self) -> list[ListWithLabel]:
         
     | 
| 27 | 
         
            +
                    return self.recipes
         
     | 
    	
        qt/constant.py
    CHANGED
    
    | 
         @@ -1,10 +1,13 @@ 
     | 
|
| 1 | 
         
             
            import os
         
     | 
| 
         | 
|
| 
         | 
|
| 2 | 
         
             
            from dataclasses import dataclass
         
     | 
| 3 | 
         
            -
            from typing import Type,  
     | 
| 4 | 
         | 
| 5 | 
         
             
            from base.attribute import Attribute
         
     | 
| 6 | 
         
             
            from base.buff import Buff
         
     | 
| 7 | 
         
             
            from base.skill import Skill
         
     | 
| 
         | 
|
| 8 | 
         
             
            # from general.gains import equipment
         
     | 
| 9 | 
         | 
| 10 | 
         
             
            from schools import first
         
     | 
| 
         @@ -126,9 +129,24 @@ class School: 
     | 
|
| 126 | 
         
             
                kind: str
         
     | 
| 127 | 
         
             
                attribute: Type[Attribute]
         
     | 
| 128 | 
         
             
                formation: str
         
     | 
| 129 | 
         
            -
                 
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 130 | 
         
             
                skills: Dict[int, Skill]
         
     | 
| 131 | 
         
             
                buffs: Dict[int, Buff]
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 132 | 
         | 
| 133 | 
         | 
| 134 | 
         
             
            SUPPORT_SCHOOL = {
         
     | 
| 
         @@ -138,9 +156,30 @@ SUPPORT_SCHOOL = { 
     | 
|
| 138 | 
         
             
                    kind="外功",
         
     | 
| 139 | 
         
             
                    attribute=first.BeiAoJue,
         
     | 
| 140 | 
         
             
                    formation="霜岚洗锋阵",
         
     | 
| 141 | 
         
            -
                     
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 142 | 
         
             
                    skills=first.SKILLS,
         
     | 
| 143 | 
         
            -
                    buffs=first.BUFFS
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 144 | 
         
             
                )
         
     | 
| 145 | 
         
             
            }
         
     | 
| 146 | 
         | 
| 
         | 
|
| 1 | 
         
             
            import os
         
     | 
| 2 | 
         
            +
             
     | 
| 3 | 
         
            +
             
     | 
| 4 | 
         
             
            from dataclasses import dataclass
         
     | 
| 5 | 
         
            +
            from typing import Type, List, Dict
         
     | 
| 6 | 
         | 
| 7 | 
         
             
            from base.attribute import Attribute
         
     | 
| 8 | 
         
             
            from base.buff import Buff
         
     | 
| 9 | 
         
             
            from base.skill import Skill
         
     | 
| 10 | 
         
            +
             
     | 
| 11 | 
         
             
            # from general.gains import equipment
         
     | 
| 12 | 
         | 
| 13 | 
         
             
            from schools import first
         
     | 
| 
         | 
|
| 129 | 
         
             
                kind: str
         
     | 
| 130 | 
         
             
                attribute: Type[Attribute]
         
     | 
| 131 | 
         
             
                formation: str
         
     | 
| 132 | 
         
            +
                talent_gains: List[Dict[int, Buff]]
         
     | 
| 133 | 
         
            +
                talent_decoder: Dict[int, str]
         
     | 
| 134 | 
         
            +
                talent_encoder: Dict[str, int]
         
     | 
| 135 | 
         
            +
                recipe_gains: Dict[str, Dict[str, Buff]]
         
     | 
| 136 | 
         
            +
                recipes: Dict[str, List[str]]
         
     | 
| 137 | 
         
             
                skills: Dict[int, Skill]
         
     | 
| 138 | 
         
             
                buffs: Dict[int, Buff]
         
     | 
| 139 | 
         
            +
                display_attrs: Dict[str, str]
         
     | 
| 140 | 
         
            +
             
     | 
| 141 | 
         
            +
                def attr_content(self, attribute):
         
     | 
| 142 | 
         
            +
                    content = []
         
     | 
| 143 | 
         
            +
                    for attr, name in self.display_attrs.items():
         
     | 
| 144 | 
         
            +
                        value = getattr(attribute, attr)
         
     | 
| 145 | 
         
            +
                        if isinstance(value, int):
         
     | 
| 146 | 
         
            +
                            content.append([name, f"{value}"])
         
     | 
| 147 | 
         
            +
                        else:
         
     | 
| 148 | 
         
            +
                            content.append([name, f"{round(value * 100, 2)}%"])
         
     | 
| 149 | 
         
            +
                    return content
         
     | 
| 150 | 
         | 
| 151 | 
         | 
| 152 | 
         
             
            SUPPORT_SCHOOL = {
         
     | 
| 
         | 
|
| 156 | 
         
             
                    kind="外功",
         
     | 
| 157 | 
         
             
                    attribute=first.BeiAoJue,
         
     | 
| 158 | 
         
             
                    formation="霜岚洗锋阵",
         
     | 
| 159 | 
         
            +
                    talent_gains=first.TALENT_GAINS,
         
     | 
| 160 | 
         
            +
                    talent_decoder=first.TALENT_DECODER,
         
     | 
| 161 | 
         
            +
                    talent_encoder=first.TALENT_ENCODER,
         
     | 
| 162 | 
         
            +
                    recipe_gains=first.RECIPE_GAINS,
         
     | 
| 163 | 
         
            +
                    recipes=first.RECIPES,
         
     | 
| 164 | 
         
             
                    skills=first.SKILLS,
         
     | 
| 165 | 
         
            +
                    buffs=first.BUFFS,
         
     | 
| 166 | 
         
            +
                    display_attrs={
         
     | 
| 167 | 
         
            +
                        "strength": "力道",
         
     | 
| 168 | 
         
            +
                        "base_physical_attack_power": "基础攻击",
         
     | 
| 169 | 
         
            +
                        "physical_attack_power": "攻击",
         
     | 
| 170 | 
         
            +
                        "base_physical_critical_strike": "会心等级",
         
     | 
| 171 | 
         
            +
                        "physical_critical_strike": "会心",
         
     | 
| 172 | 
         
            +
                        "physical_critical_power_base": "会效等级",
         
     | 
| 173 | 
         
            +
                        "physical_critical_power": "会效",
         
     | 
| 174 | 
         
            +
                        "base_physical_overcome": "基础破防",
         
     | 
| 175 | 
         
            +
                        "final_physical_overcome": "最终破防",
         
     | 
| 176 | 
         
            +
                        "physical_overcome": "破防",
         
     | 
| 177 | 
         
            +
                        "weapon_damage_base": "基础武器伤害",
         
     | 
| 178 | 
         
            +
                        "weapon_damage_rand": "浮动武器伤害",
         
     | 
| 179 | 
         
            +
                        "strain_base": "无双等级",
         
     | 
| 180 | 
         
            +
                        "strain": "无双",
         
     | 
| 181 | 
         
            +
                        "surplus": "破招",
         
     | 
| 182 | 
         
            +
                    }
         
     | 
| 183 | 
         
             
                )
         
     | 
| 184 | 
         
             
            }
         
     | 
| 185 | 
         | 
    	
        qt/scripts/__init__.py
    ADDED
    
    | 
         
            File without changes
         
     | 
    	
        qt/scripts/dashboard.py
    ADDED
    
    | 
         @@ -0,0 +1,103 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            from PySide6.QtWidgets import QMessageBox
         
     | 
| 2 | 
         
            +
             
     | 
| 3 | 
         
            +
            from qt.components.dashboard import DashboardWidget
         
     | 
| 4 | 
         
            +
            from qt.constant import ATTR_TYPE_TRANSLATE
         
     | 
| 5 | 
         
            +
            from qt.scripts.top import Parser
         
     | 
| 6 | 
         
            +
            from qt.scripts.equipments import Equipments
         
     | 
| 7 | 
         
            +
            # from qt.scripts.consumables import Consumables
         
     | 
| 8 | 
         
            +
            # from qt.scripts.bonuses import Bonuses
         
     | 
| 9 | 
         
            +
            from qt.scripts.recipes import Recipes
         
     | 
| 10 | 
         
            +
            from qt.scripts.talents import Talents
         
     | 
| 11 | 
         
            +
            from utils.analyzer import analyze_details
         
     | 
| 12 | 
         
            +
             
     | 
| 13 | 
         
            +
             
     | 
| 14 | 
         
            +
            def summary_content(summary, total_damage):
         
     | 
| 15 | 
         
            +
                content = []
         
     | 
| 16 | 
         
            +
                for skill in sorted(summary, key=lambda x: summary[x]['damage'], reverse=True):
         
     | 
| 17 | 
         
            +
                    detail = summary[skill]
         
     | 
| 18 | 
         
            +
                    critical = round(detail['critical'], 2)
         
     | 
| 19 | 
         
            +
                    critical_rate = round(detail['critical'] / detail['count'] * 100, 2)
         
     | 
| 20 | 
         
            +
                    hit = round(detail['count'] - critical, 2)
         
     | 
| 21 | 
         
            +
                    hit_rate = round(100 - critical_rate, 2)
         
     | 
| 22 | 
         
            +
                    damage = round(detail['damage'], 2)
         
     | 
| 23 | 
         
            +
                    damage_rate = round(damage / total_damage * 100, 2)
         
     | 
| 24 | 
         
            +
                    content.append(
         
     | 
| 25 | 
         
            +
                        [f"{skill}/{detail['count']}",
         
     | 
| 26 | 
         
            +
                         f"{hit}/{hit_rate}%", f"{critical}/{critical_rate}%", f"{damage}/{damage_rate}%"]
         
     | 
| 27 | 
         
            +
                    )
         
     | 
| 28 | 
         
            +
                return content
         
     | 
| 29 | 
         
            +
             
     | 
| 30 | 
         
            +
             
     | 
| 31 | 
         
            +
            def detail_content(detail):
         
     | 
| 32 | 
         
            +
                damage_content = [
         
     | 
| 33 | 
         
            +
                    ["命中伤害", f"{detail['damage']}"],
         
     | 
| 34 | 
         
            +
                    ["会心伤害", f"{detail['critical_damage']}"],
         
     | 
| 35 | 
         
            +
                    ["期望会心", f"{round(detail['critical_strike'] * 100, 2)}%"],
         
     | 
| 36 | 
         
            +
                    ["期望伤害", f"{round(detail['expected_damage'], 2)}"]
         
     | 
| 37 | 
         
            +
                ]
         
     | 
| 38 | 
         
            +
                gradient_content = [
         
     | 
| 39 | 
         
            +
                    [ATTR_TYPE_TRANSLATE[k], f"{round(v / detail['expected_damage'] * 100, 2)}%"]
         
     | 
| 40 | 
         
            +
                    for k, v in detail['gradients'].items()
         
     | 
| 41 | 
         
            +
                ]
         
     | 
| 42 | 
         
            +
             
     | 
| 43 | 
         
            +
                return damage_content, gradient_content
         
     | 
| 44 | 
         
            +
             
     | 
| 45 | 
         
            +
             
     | 
| 46 | 
         
            +
            def dashboard_script(parser: Parser,
         
     | 
| 47 | 
         
            +
                                 equipments: Equipments, talents: Talents, recipes: Recipes,
         
     | 
| 48 | 
         
            +
                                 # consumables: Consumables, bonuses: Bonuses,
         
     | 
| 49 | 
         
            +
                                 dashboard_widget: DashboardWidget):
         
     | 
| 50 | 
         
            +
             
     | 
| 51 | 
         
            +
                def select_fight(text):
         
     | 
| 52 | 
         
            +
                    index = parser.record_index[text]
         
     | 
| 53 | 
         
            +
                    dashboard_widget.duration.set_value(parser.duration(index))
         
     | 
| 54 | 
         
            +
             
     | 
| 55 | 
         
            +
                dashboard_widget.fight_select.combo_box.currentTextChanged.connect(select_fight)
         
     | 
| 56 | 
         
            +
             
     | 
| 57 | 
         
            +
                def formulate():
         
     | 
| 58 | 
         
            +
                    duration = dashboard_widget.duration.spin_box.value()
         
     | 
| 59 | 
         
            +
                    record = parser.records[parser.record_index[dashboard_widget.fight_select.combo_box.currentText()]]
         
     | 
| 60 | 
         
            +
             
     | 
| 61 | 
         
            +
                    school = parser.school
         
     | 
| 62 | 
         
            +
                    attribute = school.attribute()
         
     | 
| 63 | 
         
            +
                    attribute.target_level = int(dashboard_widget.target_level.combo_box.currentText())
         
     | 
| 64 | 
         
            +
                    for attr, value in equipments.attrs.items():
         
     | 
| 65 | 
         
            +
                        setattr(attribute, attr, getattr(attribute, attr) + value)
         
     | 
| 66 | 
         
            +
                    # for attr, value in consumables.attrs.items():
         
     | 
| 67 | 
         
            +
                    #     setattr(attribute, attr, getattr(attribute, attr) + value)
         
     | 
| 68 | 
         
            +
             
     | 
| 69 | 
         
            +
                    dashboard_widget.init_attribute.set_content(school.attr_content(attribute))
         
     | 
| 70 | 
         
            +
                    # gains = sum([equipments.gains, talents.gains, recipes.gains, bonuses.gains], [])
         
     | 
| 71 | 
         
            +
                    #
         
     | 
| 72 | 
         
            +
                    # dashboard_widget.final_attribute.set_text(school.attr_text(attribute))
         
     | 
| 73 | 
         
            +
                    total_damage, total_gradient, details, summary = analyze_details(record, attribute, school)
         
     | 
| 74 | 
         
            +
                    dashboard_widget.dps.set_text(str(round(total_damage / duration)))
         
     | 
| 75 | 
         
            +
                    dashboard_widget.gradients.set_content(
         
     | 
| 76 | 
         
            +
                        [[ATTR_TYPE_TRANSLATE[k], f"{round(v, 2)}%"] for k, v in total_gradient.items()]
         
     | 
| 77 | 
         
            +
                    )
         
     | 
| 78 | 
         
            +
                    dashboard_widget.details = details
         
     | 
| 79 | 
         
            +
                    dashboard_widget.skill_combo.set_items(list(details), default_index=-1)
         
     | 
| 80 | 
         
            +
                    dashboard_widget.summary.set_content(summary_content(summary, total_damage))
         
     | 
| 81 | 
         
            +
             
     | 
| 82 | 
         
            +
                dashboard_widget.button.clicked.connect(formulate)
         
     | 
| 83 | 
         
            +
             
     | 
| 84 | 
         
            +
                def select_skill(skill):
         
     | 
| 85 | 
         
            +
                    if skill:
         
     | 
| 86 | 
         
            +
                        dashboard_widget.status_combo.set_items(list(dashboard_widget.details[skill]))
         
     | 
| 87 | 
         
            +
                    else:
         
     | 
| 88 | 
         
            +
                        dashboard_widget.status_combo.combo_box.clear()
         
     | 
| 89 | 
         
            +
             
     | 
| 90 | 
         
            +
                dashboard_widget.skill_combo.combo_box.currentTextChanged.connect(select_skill)
         
     | 
| 91 | 
         
            +
             
     | 
| 92 | 
         
            +
                def select_status(status):
         
     | 
| 93 | 
         
            +
                    if status:
         
     | 
| 94 | 
         
            +
                        skill = dashboard_widget.skill_combo.combo_box.currentText()
         
     | 
| 95 | 
         
            +
                        detail = dashboard_widget.details[skill][status]
         
     | 
| 96 | 
         
            +
                        damage_content, gradient_content = detail_content(detail)
         
     | 
| 97 | 
         
            +
                        dashboard_widget.damage_detail.set_content(damage_content)
         
     | 
| 98 | 
         
            +
                        dashboard_widget.gradient_detail.set_content(gradient_content)
         
     | 
| 99 | 
         
            +
                    else:
         
     | 
| 100 | 
         
            +
                        dashboard_widget.damage_detail.table.clear()
         
     | 
| 101 | 
         
            +
                        dashboard_widget.gradient_detail.table.clear()
         
     | 
| 102 | 
         
            +
             
     | 
| 103 | 
         
            +
                dashboard_widget.status_combo.combo_box.currentTextChanged.connect(select_status)
         
     | 
    	
        qt/scripts/equipments.py
    CHANGED
    
    | 
         @@ -11,6 +11,9 @@ class Enchant: 
     | 
|
| 11 | 
         
             
                name: str
         
     | 
| 12 | 
         
             
                attr: Dict[str, int]
         
     | 
| 13 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 14 | 
         
             
                def clear(self):
         
     | 
| 15 | 
         
             
                    self.name = ""
         
     | 
| 16 | 
         
             
                    self.attr = {}
         
     | 
| 
         @@ -21,6 +24,9 @@ class Stone: 
     | 
|
| 21 | 
         
             
                level: int
         
     | 
| 22 | 
         
             
                attr: Dict[str, int]
         
     | 
| 23 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 24 | 
         
             
                def clear(self):
         
     | 
| 25 | 
         
             
                    self.name = ""
         
     | 
| 26 | 
         
             
                    self.attr = {}
         
     | 
| 
         @@ -40,6 +46,8 @@ class Equipment: 
     | 
|
| 40 | 
         
             
                set_gain: Dict[int, List[int]]
         
     | 
| 41 | 
         | 
| 42 | 
         
             
                def __init__(self, label):
         
     | 
| 
         | 
|
| 
         | 
|
| 43 | 
         
             
                    self.label = label
         
     | 
| 44 | 
         
             
                    self.position = POSITION_MAP[label]
         
     | 
| 45 | 
         | 
| 
         @@ -87,21 +95,19 @@ class Equipment: 
     | 
|
| 87 | 
         
             
                    }
         
     | 
| 88 | 
         | 
| 89 | 
         
             
                @property
         
     | 
| 90 | 
         
            -
                def  
     | 
| 91 | 
         
            -
                    return  
     | 
| 92 | 
         | 
| 93 | 
         
             
                @property
         
     | 
| 94 | 
         
            -
                def  
     | 
| 95 | 
         
             
                    if strength_attr := self.strength_attr:
         
     | 
| 96 | 
         
            -
                        return " 
     | 
| 97 | 
         
            -
                            f"{ATTR_TYPE_TRANSLATE[k]}:\t{v}(+{strength_attr[k]})" for k, v in self.magic_attr.items()
         
     | 
| 98 | 
         
            -
                        ])
         
     | 
| 99 | 
         
             
                    else:
         
     | 
| 100 | 
         
            -
                        return  
     | 
| 101 | 
         | 
| 102 | 
         
             
                @property
         
     | 
| 103 | 
         
            -
                def  
     | 
| 104 | 
         
            -
                    return  
     | 
| 105 | 
         | 
| 106 | 
         | 
| 107 | 
         
             
            class Equipments:
         
     | 
| 
         @@ -177,8 +183,7 @@ def equipments_script(equipments_widget: EquipmentsWidget): 
     | 
|
| 177 | 
         
             
                    widget = equipments_widget[label]
         
     | 
| 178 | 
         
             
                    equipment = equipments[label]
         
     | 
| 179 | 
         | 
| 180 | 
         
            -
                    def inner( 
     | 
| 181 | 
         
            -
                        equipment_name = widget.equipment.combo_box.currentText()
         
     | 
| 182 | 
         | 
| 183 | 
         
             
                        if not equipment_name:
         
     | 
| 184 | 
         
             
                            equipment.clear()
         
     | 
| 
         @@ -197,7 +202,7 @@ def equipments_script(equipments_widget: EquipmentsWidget): 
     | 
|
| 197 | 
         
             
                            setattr(equipment, k, v)
         
     | 
| 198 | 
         | 
| 199 | 
         
             
                        if equipment.base:
         
     | 
| 200 | 
         
            -
                            widget.base_attr. 
     | 
| 201 | 
         
             
                            widget.base_attr.show()
         
     | 
| 202 | 
         
             
                        else:
         
     | 
| 203 | 
         
             
                            widget.base_attr.hide()
         
     | 
| 
         @@ -211,7 +216,7 @@ def equipments_script(equipments_widget: EquipmentsWidget): 
     | 
|
| 211 | 
         
             
                        if equipment.embed:
         
     | 
| 212 | 
         
             
                            for i, (attr, value) in enumerate(equipment.embed.items()):
         
     | 
| 213 | 
         
             
                                widget.embed_levels[i].set_label(f"镶嵌等级-{ATTR_TYPE_TRANSLATE[attr]}")
         
     | 
| 214 | 
         
            -
                            widget.embed_attr. 
     | 
| 215 | 
         
             
                            widget.embed_attr.show()
         
     | 
| 216 | 
         
             
                        else:
         
     | 
| 217 | 
         
             
                            widget.embed_attr.hide()
         
     | 
| 
         @@ -228,8 +233,7 @@ def equipments_script(equipments_widget: EquipmentsWidget): 
     | 
|
| 228 | 
         
             
                    widget = equipments_widget.equipments[label]
         
     | 
| 229 | 
         
             
                    equipment = equipments[label]
         
     | 
| 230 | 
         | 
| 231 | 
         
            -
                    def inner( 
     | 
| 232 | 
         
            -
                        enchant_name = widget.enchant.combo_box.currentText()
         
     | 
| 233 | 
         
             
                        if enchant_name:
         
     | 
| 234 | 
         
             
                            enchant_detail = widget.enchant_json[enchant_name]
         
     | 
| 235 | 
         
             
                            equipment.enchant.name = enchant_name
         
     | 
| 
         @@ -244,7 +248,7 @@ def equipments_script(equipments_widget: EquipmentsWidget): 
     | 
|
| 244 | 
         
             
                    widget = equipments_widget.equipments[label]
         
     | 
| 245 | 
         
             
                    equipment = equipments[label]
         
     | 
| 246 | 
         | 
| 247 | 
         
            -
                    def inner( 
     | 
| 248 | 
         
             
                        if widget.special_enchant and widget.special_enchant.radio_button.isChecked():
         
     | 
| 249 | 
         
             
                            equipment.special_enchant_gain = equipment.special_enchant
         
     | 
| 250 | 
         
             
                        else:
         
     | 
| 
         @@ -258,8 +262,8 @@ def equipments_script(equipments_widget: EquipmentsWidget): 
     | 
|
| 258 | 
         | 
| 259 | 
         
             
                    def inner(index):
         
     | 
| 260 | 
         
             
                        equipment.strength_level = index
         
     | 
| 261 | 
         
            -
                        if  
     | 
| 262 | 
         
            -
                            widget.magic_attr. 
     | 
| 263 | 
         
             
                            widget.magic_attr.show()
         
     | 
| 264 | 
         
             
                        else:
         
     | 
| 265 | 
         
             
                            widget.magic_attr.hide()
         
     | 
| 
         @@ -272,8 +276,8 @@ def equipments_script(equipments_widget: EquipmentsWidget): 
     | 
|
| 272 | 
         | 
| 273 | 
         
             
                    def inner(index):
         
     | 
| 274 | 
         
             
                        equipment.embed_levels[i] = index
         
     | 
| 275 | 
         
            -
                        if  
     | 
| 276 | 
         
            -
                            widget.embed_attr. 
     | 
| 277 | 
         
             
                            widget.embed_attr.show()
         
     | 
| 278 | 
         
             
                        else:
         
     | 
| 279 | 
         
             
                            widget.embed_attr.hide()
         
     | 
| 
         @@ -284,7 +288,7 @@ def equipments_script(equipments_widget: EquipmentsWidget): 
     | 
|
| 284 | 
         
             
                    widget = equipments_widget.equipments[label]
         
     | 
| 285 | 
         
             
                    equipment = equipments[label]
         
     | 
| 286 | 
         | 
| 287 | 
         
            -
                    def inner( 
     | 
| 288 | 
         
             
                        level = widget.stone_level.combo_box.currentText()
         
     | 
| 289 | 
         | 
| 290 | 
         
             
                        current = widget.stones_json
         
     | 
| 
         @@ -297,10 +301,11 @@ def equipments_script(equipments_widget: EquipmentsWidget): 
     | 
|
| 297 | 
         
             
                            else:
         
     | 
| 298 | 
         
             
                                break
         
     | 
| 299 | 
         
             
                        if level in current:
         
     | 
| 300 | 
         
            -
                            for k, v in current[level]:
         
     | 
| 301 | 
         
             
                                setattr(equipment.stone, k, v)
         
     | 
| 302 | 
         
             
                        else:
         
     | 
| 303 | 
         
             
                            widget.stone_attrs[i].set_items([""] + [ATTR_TYPE_TRANSLATE[k] for k in current])
         
     | 
| 
         | 
|
| 304 | 
         | 
| 305 | 
         
             
                        i += 1
         
     | 
| 306 | 
         
             
                        while i < len(widget.stone_attrs):
         
     | 
| 
         @@ -311,11 +316,11 @@ def equipments_script(equipments_widget: EquipmentsWidget): 
     | 
|
| 311 | 
         | 
| 312 | 
         
             
                for equipment_label, equipment_widget in equipments_widget.items():
         
     | 
| 313 | 
         | 
| 314 | 
         
            -
                    equipment_widget.equipment.combo_box. 
     | 
| 315 | 
         
             
                    if equipment_widget.special_enchant:
         
     | 
| 316 | 
         
             
                        equipment_widget.special_enchant.radio_button.clicked.connect(special_enchant_update(equipment_label))
         
     | 
| 317 | 
         
             
                    if equipment_widget.enchant:
         
     | 
| 318 | 
         
            -
                        equipment_widget.enchant.combo_box. 
     | 
| 319 | 
         
             
                    equipment_widget.strength_level.combo_box.currentIndexChanged.connect(strength_level_update(equipment_label))
         
     | 
| 320 | 
         
             
                    for n, embed_widget in enumerate(equipment_widget.embed_levels):
         
     | 
| 321 | 
         
             
                        embed_widget.combo_box.currentIndexChanged.connect(embed_level_update(n, equipment_label))
         
     | 
| 
         | 
|
| 11 | 
         
             
                name: str
         
     | 
| 12 | 
         
             
                attr: Dict[str, int]
         
     | 
| 13 | 
         | 
| 14 | 
         
            +
                def __init__(self):
         
     | 
| 15 | 
         
            +
                    self.clear()
         
     | 
| 16 | 
         
            +
             
     | 
| 17 | 
         
             
                def clear(self):
         
     | 
| 18 | 
         
             
                    self.name = ""
         
     | 
| 19 | 
         
             
                    self.attr = {}
         
     | 
| 
         | 
|
| 24 | 
         
             
                level: int
         
     | 
| 25 | 
         
             
                attr: Dict[str, int]
         
     | 
| 26 | 
         | 
| 27 | 
         
            +
                def __init__(self):
         
     | 
| 28 | 
         
            +
                    self.clear()
         
     | 
| 29 | 
         
            +
             
     | 
| 30 | 
         
             
                def clear(self):
         
     | 
| 31 | 
         
             
                    self.name = ""
         
     | 
| 32 | 
         
             
                    self.attr = {}
         
     | 
| 
         | 
|
| 46 | 
         
             
                set_gain: Dict[int, List[int]]
         
     | 
| 47 | 
         | 
| 48 | 
         
             
                def __init__(self, label):
         
     | 
| 49 | 
         
            +
                    self.clear()
         
     | 
| 50 | 
         
            +
             
     | 
| 51 | 
         
             
                    self.label = label
         
     | 
| 52 | 
         
             
                    self.position = POSITION_MAP[label]
         
     | 
| 53 | 
         | 
| 
         | 
|
| 95 | 
         
             
                    }
         
     | 
| 96 | 
         | 
| 97 | 
         
             
                @property
         
     | 
| 98 | 
         
            +
                def base_attr_content(self):
         
     | 
| 99 | 
         
            +
                    return [[ATTR_TYPE_TRANSLATE[k], str(v)] for k, v in self.base_attr.items()]
         
     | 
| 100 | 
         | 
| 101 | 
         
             
                @property
         
     | 
| 102 | 
         
            +
                def magic_attr_content(self):
         
     | 
| 103 | 
         
             
                    if strength_attr := self.strength_attr:
         
     | 
| 104 | 
         
            +
                        return [[ATTR_TYPE_TRANSLATE[k], f"{v}(+{strength_attr[k]})"] for k, v in self.magic_attr.items()]
         
     | 
| 
         | 
|
| 
         | 
|
| 105 | 
         
             
                    else:
         
     | 
| 106 | 
         
            +
                        return [[ATTR_TYPE_TRANSLATE[k], f"{v}"] for k, v in self.magic_attr.items()]
         
     | 
| 107 | 
         | 
| 108 | 
         
             
                @property
         
     | 
| 109 | 
         
            +
                def embed_attr_content(self):
         
     | 
| 110 | 
         
            +
                    return [[ATTR_TYPE_TRANSLATE[k], str(v)] for k, v in self.embed_attr.items()]
         
     | 
| 111 | 
         | 
| 112 | 
         | 
| 113 | 
         
             
            class Equipments:
         
     | 
| 
         | 
|
| 183 | 
         
             
                    widget = equipments_widget[label]
         
     | 
| 184 | 
         
             
                    equipment = equipments[label]
         
     | 
| 185 | 
         | 
| 186 | 
         
            +
                    def inner(equipment_name):
         
     | 
| 
         | 
|
| 187 | 
         | 
| 188 | 
         
             
                        if not equipment_name:
         
     | 
| 189 | 
         
             
                            equipment.clear()
         
     | 
| 
         | 
|
| 202 | 
         
             
                            setattr(equipment, k, v)
         
     | 
| 203 | 
         | 
| 204 | 
         
             
                        if equipment.base:
         
     | 
| 205 | 
         
            +
                            widget.base_attr.set_content(equipment.base_attr_content)
         
     | 
| 206 | 
         
             
                            widget.base_attr.show()
         
     | 
| 207 | 
         
             
                        else:
         
     | 
| 208 | 
         
             
                            widget.base_attr.hide()
         
     | 
| 
         | 
|
| 216 | 
         
             
                        if equipment.embed:
         
     | 
| 217 | 
         
             
                            for i, (attr, value) in enumerate(equipment.embed.items()):
         
     | 
| 218 | 
         
             
                                widget.embed_levels[i].set_label(f"镶嵌等级-{ATTR_TYPE_TRANSLATE[attr]}")
         
     | 
| 219 | 
         
            +
                            widget.embed_attr.set_content(equipment.embed_attr_content)
         
     | 
| 220 | 
         
             
                            widget.embed_attr.show()
         
     | 
| 221 | 
         
             
                        else:
         
     | 
| 222 | 
         
             
                            widget.embed_attr.hide()
         
     | 
| 
         | 
|
| 233 | 
         
             
                    widget = equipments_widget.equipments[label]
         
     | 
| 234 | 
         
             
                    equipment = equipments[label]
         
     | 
| 235 | 
         | 
| 236 | 
         
            +
                    def inner(enchant_name):
         
     | 
| 
         | 
|
| 237 | 
         
             
                        if enchant_name:
         
     | 
| 238 | 
         
             
                            enchant_detail = widget.enchant_json[enchant_name]
         
     | 
| 239 | 
         
             
                            equipment.enchant.name = enchant_name
         
     | 
| 
         | 
|
| 248 | 
         
             
                    widget = equipments_widget.equipments[label]
         
     | 
| 249 | 
         
             
                    equipment = equipments[label]
         
     | 
| 250 | 
         | 
| 251 | 
         
            +
                    def inner(_):
         
     | 
| 252 | 
         
             
                        if widget.special_enchant and widget.special_enchant.radio_button.isChecked():
         
     | 
| 253 | 
         
             
                            equipment.special_enchant_gain = equipment.special_enchant
         
     | 
| 254 | 
         
             
                        else:
         
     | 
| 
         | 
|
| 262 | 
         | 
| 263 | 
         
             
                    def inner(index):
         
     | 
| 264 | 
         
             
                        equipment.strength_level = index
         
     | 
| 265 | 
         
            +
                        if magic_attr_content := equipment.magic_attr_content:
         
     | 
| 266 | 
         
            +
                            widget.magic_attr.set_content(magic_attr_content)
         
     | 
| 267 | 
         
             
                            widget.magic_attr.show()
         
     | 
| 268 | 
         
             
                        else:
         
     | 
| 269 | 
         
             
                            widget.magic_attr.hide()
         
     | 
| 
         | 
|
| 276 | 
         | 
| 277 | 
         
             
                    def inner(index):
         
     | 
| 278 | 
         
             
                        equipment.embed_levels[i] = index
         
     | 
| 279 | 
         
            +
                        if embed_attr_content := equipment.embed_attr_content:
         
     | 
| 280 | 
         
            +
                            widget.embed_attr.set_content(embed_attr_content)
         
     | 
| 281 | 
         
             
                            widget.embed_attr.show()
         
     | 
| 282 | 
         
             
                        else:
         
     | 
| 283 | 
         
             
                            widget.embed_attr.hide()
         
     | 
| 
         | 
|
| 288 | 
         
             
                    widget = equipments_widget.equipments[label]
         
     | 
| 289 | 
         
             
                    equipment = equipments[label]
         
     | 
| 290 | 
         | 
| 291 | 
         
            +
                    def inner(_):
         
     | 
| 292 | 
         
             
                        level = widget.stone_level.combo_box.currentText()
         
     | 
| 293 | 
         | 
| 294 | 
         
             
                        current = widget.stones_json
         
     | 
| 
         | 
|
| 301 | 
         
             
                            else:
         
     | 
| 302 | 
         
             
                                break
         
     | 
| 303 | 
         
             
                        if level in current:
         
     | 
| 304 | 
         
            +
                            for k, v in current[level].items():
         
     | 
| 305 | 
         
             
                                setattr(equipment.stone, k, v)
         
     | 
| 306 | 
         
             
                        else:
         
     | 
| 307 | 
         
             
                            widget.stone_attrs[i].set_items([""] + [ATTR_TYPE_TRANSLATE[k] for k in current])
         
     | 
| 308 | 
         
            +
                            equipment.stone = {}
         
     | 
| 309 | 
         | 
| 310 | 
         
             
                        i += 1
         
     | 
| 311 | 
         
             
                        while i < len(widget.stone_attrs):
         
     | 
| 
         | 
|
| 316 | 
         | 
| 317 | 
         
             
                for equipment_label, equipment_widget in equipments_widget.items():
         
     | 
| 318 | 
         | 
| 319 | 
         
            +
                    equipment_widget.equipment.combo_box.currentTextChanged.connect(equipment_update(equipment_label))
         
     | 
| 320 | 
         
             
                    if equipment_widget.special_enchant:
         
     | 
| 321 | 
         
             
                        equipment_widget.special_enchant.radio_button.clicked.connect(special_enchant_update(equipment_label))
         
     | 
| 322 | 
         
             
                    if equipment_widget.enchant:
         
     | 
| 323 | 
         
            +
                        equipment_widget.enchant.combo_box.currentTextChanged.connect(enchant_update(equipment_label))
         
     | 
| 324 | 
         
             
                    equipment_widget.strength_level.combo_box.currentIndexChanged.connect(strength_level_update(equipment_label))
         
     | 
| 325 | 
         
             
                    for n, embed_widget in enumerate(equipment_widget.embed_levels):
         
     | 
| 326 | 
         
             
                        embed_widget.combo_box.currentIndexChanged.connect(embed_level_update(n, equipment_label))
         
     | 
    	
        qt/scripts/recipes.py
    ADDED
    
    | 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            from qt.components.recipes import RecipesWidget
         
     | 
| 2 | 
         
            +
             
     | 
| 3 | 
         
            +
            from qt.constant import MAX_RECIPE_SKILLS, MAX_RECIPES
         
     | 
| 4 | 
         
            +
             
     | 
| 5 | 
         
            +
             
     | 
| 6 | 
         
            +
            class Recipes:
         
     | 
| 7 | 
         
            +
                def __init__(self):
         
     | 
| 8 | 
         
            +
                    self.recipes = [[] for _ in range(MAX_RECIPE_SKILLS)]
         
     | 
| 9 | 
         
            +
             
     | 
| 10 | 
         
            +
                def __getitem__(self, item):
         
     | 
| 11 | 
         
            +
                    return self.recipes[item]
         
     | 
| 12 | 
         
            +
             
     | 
| 13 | 
         
            +
                def __setitem__(self, key, value):
         
     | 
| 14 | 
         
            +
                    self.recipes[key] = value
         
     | 
| 15 | 
         
            +
             
     | 
| 16 | 
         
            +
                @property
         
     | 
| 17 | 
         
            +
                def gains(self):
         
     | 
| 18 | 
         
            +
                    return [recipe for recipes in self.recipes for recipe in recipes]
         
     | 
| 19 | 
         
            +
             
     | 
| 20 | 
         
            +
             
     | 
| 21 | 
         
            +
            def recipes_script(recipes_widget: RecipesWidget):
         
     | 
| 22 | 
         
            +
                recipes = Recipes()
         
     | 
| 23 | 
         
            +
             
     | 
| 24 | 
         
            +
                def recipe_update(i):
         
     | 
| 25 | 
         
            +
                    widget = recipes_widget[i]
         
     | 
| 26 | 
         
            +
             
     | 
| 27 | 
         
            +
                    def inner():
         
     | 
| 28 | 
         
            +
                        skill = widget.label.text()
         
     | 
| 29 | 
         
            +
                        if selected_items := widget.list.selectedItems():
         
     | 
| 30 | 
         
            +
                            while len(selected_items) > MAX_RECIPES:
         
     | 
| 31 | 
         
            +
                                selected_items.pop().setSelected(False)
         
     | 
| 32 | 
         
            +
                        recipes[i] = [(skill, item.text()) for item in selected_items]
         
     | 
| 33 | 
         
            +
             
     | 
| 34 | 
         
            +
                    return inner
         
     | 
| 35 | 
         
            +
             
     | 
| 36 | 
         
            +
                for n, recipe_widget in enumerate(recipes_widget.values()):
         
     | 
| 37 | 
         
            +
                    recipe_widget.list.itemSelectionChanged.connect(recipe_update(n))
         
     | 
| 38 | 
         
            +
             
     | 
| 39 | 
         
            +
                return recipes
         
     | 
    	
        qt/scripts/top.py
    CHANGED
    
    | 
         @@ -4,7 +4,9 @@ from PySide6.QtWidgets import QTabWidget, QFileDialog, QWidget 
     | 
|
| 4 | 
         | 
| 5 | 
         
             
            from base.buff import Buff
         
     | 
| 6 | 
         
             
            from base.skill import Skill
         
     | 
| 
         | 
|
| 7 | 
         
             
            from qt.components.equipments import EquipmentsWidget
         
     | 
| 
         | 
|
| 8 | 
         
             
            from qt.components.talents import TalentsWidget
         
     | 
| 9 | 
         
             
            from utils.lua import parse
         
     | 
| 10 | 
         
             
            # from qt.components.equipments import EquipmentsWidget
         
     | 
| 
         @@ -21,11 +23,12 @@ from qt.constant import School, SUPPORT_SCHOOL, MAX_RECIPES, MAX_STONE_LEVEL 
     | 
|
| 21 | 
         | 
| 22 | 
         | 
| 23 | 
         
             
            class Parser:
         
     | 
| 24 | 
         
            -
                records:  
     | 
| 25 | 
         
             
                status: dict
         
     | 
| 26 | 
         | 
| 27 | 
         
             
                start_time: list
         
     | 
| 28 | 
         
             
                end_time: list
         
     | 
| 
         | 
|
| 29 | 
         | 
| 30 | 
         
             
                fight_flag: bool
         
     | 
| 31 | 
         | 
| 
         @@ -33,15 +36,20 @@ class Parser: 
     | 
|
| 33 | 
         | 
| 34 | 
         
             
                school: School | None
         
     | 
| 35 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 36 | 
         
             
                def reset(self):
         
     | 
| 37 | 
         
             
                    self.fight_flag = False
         
     | 
| 38 | 
         | 
| 39 | 
         
            -
                    self.records =  
     | 
| 40 | 
         
             
                    self.status = {}
         
     | 
| 41 | 
         | 
| 42 | 
         
             
                    self.start_time = []
         
     | 
| 43 | 
         
             
                    self.end_time = []
         
     | 
| 44 | 
         | 
| 
         | 
|
| 
         | 
|
| 45 | 
         
             
                    self.school = None
         
     | 
| 46 | 
         | 
| 47 | 
         
             
                def parse_info(self, detail):
         
     | 
| 
         @@ -55,7 +63,7 @@ class Parser: 
     | 
|
| 55 | 
         
             
                def parse_time(self, detail, timestamp):
         
     | 
| 56 | 
         
             
                    if detail[1]:
         
     | 
| 57 | 
         
             
                        self.start_time.append(int(timestamp))
         
     | 
| 58 | 
         
            -
                        self.records 
     | 
| 59 | 
         
             
                        self.fight_flag = True
         
     | 
| 60 | 
         
             
                    else:
         
     | 
| 61 | 
         
             
                        self.end_time.append(int(timestamp))
         
     | 
| 
         @@ -75,7 +83,7 @@ class Parser: 
     | 
|
| 75 | 
         
             
                    if skill[0] not in self.school.skills:
         
     | 
| 76 | 
         
             
                        return
         
     | 
| 77 | 
         | 
| 78 | 
         
            -
                    current_record = self.records[self.start_time 
     | 
| 79 | 
         
             
                    if skill not in current_record:
         
     | 
| 80 | 
         
             
                        current_record[skill] = {}
         
     | 
| 81 | 
         
             
                    status = tuple(
         
     | 
| 
         @@ -102,26 +110,35 @@ class Parser: 
     | 
|
| 102 | 
         
             
                        elif row[4] == "21" and self.fight_flag:
         
     | 
| 103 | 
         
             
                            self.parse_skill(parse(row[-1]), row[3])
         
     | 
| 104 | 
         | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 105 | 
         | 
| 106 | 
         
            -
             
     | 
| 107 | 
         
            -
             
     | 
| 
         | 
|
| 108 | 
         
             
                           ):
         
     | 
| 109 | 
         
            -
             
     | 
| 110 | 
         
            -
             
     | 
| 111 | 
         
            -
             
     | 
| 112 | 
         
             
                parser = Parser()
         
     | 
| 113 | 
         | 
| 114 | 
         
             
                def upload_logs():
         
     | 
| 115 | 
         
             
                    file_name = QFileDialog(top_widget, "Choose File").getOpenFileName()
         
     | 
| 116 | 
         
             
                    parser(file_name[0])
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 117 | 
         | 
| 118 | 
         
             
                    """ Update equipment options """
         
     | 
| 119 | 
         
             
                    for equipment_widget in equipments_widget.values():
         
     | 
| 120 | 
         
             
                        choices = [""]
         
     | 
| 121 | 
         
             
                        for name, detail in equipment_widget.equipment_json.items():
         
     | 
| 122 | 
         
            -
                            if detail['kind'] not in ( 
     | 
| 123 | 
         
             
                                continue
         
     | 
| 124 | 
         
            -
                            if detail['school'] not in ("精简", "通用",  
     | 
| 125 | 
         
             
                                continue
         
     | 
| 126 | 
         
             
                            choices.append(name)
         
     | 
| 127 | 
         | 
| 
         @@ -132,10 +149,23 @@ def top_script(top_widget: TopWidget, config_widget: QWidget, 
     | 
|
| 132 | 
         | 
| 133 | 
         
             
                    """ Update talent options """
         
     | 
| 134 | 
         
             
                    for i, talent_widget in enumerate(talents_widget.values()):
         
     | 
| 135 | 
         
            -
                        talents =  
     | 
| 136 | 
         
            -
                        default_index =  
     | 
| 137 | 
         
            -
                        talent_widget.set_items([""] +  
     | 
| 138 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 139 | 
         
             
                    config_widget.show()
         
     | 
| 140 | 
         | 
| 141 | 
         
             
                top_widget.upload_button.clicked.connect(upload_logs)
         
     | 
| 
         | 
|
| 4 | 
         | 
| 5 | 
         
             
            from base.buff import Buff
         
     | 
| 6 | 
         
             
            from base.skill import Skill
         
     | 
| 7 | 
         
            +
            from qt.components.dashboard import DashboardWidget
         
     | 
| 8 | 
         
             
            from qt.components.equipments import EquipmentsWidget
         
     | 
| 9 | 
         
            +
            from qt.components.recipes import RecipesWidget
         
     | 
| 10 | 
         
             
            from qt.components.talents import TalentsWidget
         
     | 
| 11 | 
         
             
            from utils.lua import parse
         
     | 
| 12 | 
         
             
            # from qt.components.equipments import EquipmentsWidget
         
     | 
| 
         | 
|
| 23 | 
         | 
| 24 | 
         | 
| 25 | 
         
             
            class Parser:
         
     | 
| 26 | 
         
            +
                records: list
         
     | 
| 27 | 
         
             
                status: dict
         
     | 
| 28 | 
         | 
| 29 | 
         
             
                start_time: list
         
     | 
| 30 | 
         
             
                end_time: list
         
     | 
| 31 | 
         
            +
                record_index: Dict[str, int]
         
     | 
| 32 | 
         | 
| 33 | 
         
             
                fight_flag: bool
         
     | 
| 34 | 
         | 
| 
         | 
|
| 36 | 
         | 
| 37 | 
         
             
                school: School | None
         
     | 
| 38 | 
         | 
| 39 | 
         
            +
                def duration(self, i):
         
     | 
| 40 | 
         
            +
                    return round((self.end_time[i] - self.start_time[i]) / 1000, 3)
         
     | 
| 41 | 
         
            +
             
     | 
| 42 | 
         
             
                def reset(self):
         
     | 
| 43 | 
         
             
                    self.fight_flag = False
         
     | 
| 44 | 
         | 
| 45 | 
         
            +
                    self.records = []
         
     | 
| 46 | 
         
             
                    self.status = {}
         
     | 
| 47 | 
         | 
| 48 | 
         
             
                    self.start_time = []
         
     | 
| 49 | 
         
             
                    self.end_time = []
         
     | 
| 50 | 
         | 
| 51 | 
         
            +
                    self.record_index = {}
         
     | 
| 52 | 
         
            +
             
     | 
| 53 | 
         
             
                    self.school = None
         
     | 
| 54 | 
         | 
| 55 | 
         
             
                def parse_info(self, detail):
         
     | 
| 
         | 
|
| 63 | 
         
             
                def parse_time(self, detail, timestamp):
         
     | 
| 64 | 
         
             
                    if detail[1]:
         
     | 
| 65 | 
         
             
                        self.start_time.append(int(timestamp))
         
     | 
| 66 | 
         
            +
                        self.records.append({})
         
     | 
| 67 | 
         
             
                        self.fight_flag = True
         
     | 
| 68 | 
         
             
                    else:
         
     | 
| 69 | 
         
             
                        self.end_time.append(int(timestamp))
         
     | 
| 
         | 
|
| 83 | 
         
             
                    if skill[0] not in self.school.skills:
         
     | 
| 84 | 
         
             
                        return
         
     | 
| 85 | 
         | 
| 86 | 
         
            +
                    current_record = self.records[len(self.start_time) - 1]
         
     | 
| 87 | 
         
             
                    if skill not in current_record:
         
     | 
| 88 | 
         
             
                        current_record[skill] = {}
         
     | 
| 89 | 
         
             
                    status = tuple(
         
     | 
| 
         | 
|
| 110 | 
         
             
                        elif row[4] == "21" and self.fight_flag:
         
     | 
| 111 | 
         
             
                            self.parse_skill(parse(row[-1]), row[3])
         
     | 
| 112 | 
         | 
| 113 | 
         
            +
                    self.record_index = {
         
     | 
| 114 | 
         
            +
                        f"{i + 1}:{round((end_time - self.start_time[i]) / 1000, 3)}": i for i, end_time in enumerate(self.end_time)
         
     | 
| 115 | 
         
            +
                    }
         
     | 
| 116 | 
         | 
| 117 | 
         
            +
             
     | 
| 118 | 
         
            +
            def top_script(top_widget: TopWidget, config_widget: QWidget, dashboard_widget: DashboardWidget,
         
     | 
| 119 | 
         
            +
                           equipments_widget: EquipmentsWidget, talents_widget: TalentsWidget, recipes_widget: RecipesWidget,
         
     | 
| 120 | 
         
             
                           ):
         
     | 
| 121 | 
         
            +
                # equipments_widget: EquipmentsWidget, talents_widget: TalentsWidget, recipes_widget: RecipesWidget,
         
     | 
| 122 | 
         
            +
                # consumables_widget: ConsumablesWidget, bonuses_widget: BonusesWidget,
         
     | 
| 123 | 
         
            +
                # combat_widget: CombatWidget):
         
     | 
| 124 | 
         
             
                parser = Parser()
         
     | 
| 125 | 
         | 
| 126 | 
         
             
                def upload_logs():
         
     | 
| 127 | 
         
             
                    file_name = QFileDialog(top_widget, "Choose File").getOpenFileName()
         
     | 
| 128 | 
         
             
                    parser(file_name[0])
         
     | 
| 129 | 
         
            +
                    school = parser.school
         
     | 
| 130 | 
         
            +
                    """ Update dashboard """
         
     | 
| 131 | 
         
            +
                    record_index = list(parser.record_index)
         
     | 
| 132 | 
         
            +
                    dashboard_widget.fight_select.set_items(record_index)
         
     | 
| 133 | 
         
            +
                    dashboard_widget.duration.set_value(parser.duration(parser.record_index[record_index[0]]))
         
     | 
| 134 | 
         | 
| 135 | 
         
             
                    """ Update equipment options """
         
     | 
| 136 | 
         
             
                    for equipment_widget in equipments_widget.values():
         
     | 
| 137 | 
         
             
                        choices = [""]
         
     | 
| 138 | 
         
             
                        for name, detail in equipment_widget.equipment_json.items():
         
     | 
| 139 | 
         
            +
                            if detail['kind'] not in (school.kind, school.major):
         
     | 
| 140 | 
         
             
                                continue
         
     | 
| 141 | 
         
            +
                            if detail['school'] not in ("精简", "通用", school.school):
         
     | 
| 142 | 
         
             
                                continue
         
     | 
| 143 | 
         
             
                            choices.append(name)
         
     | 
| 144 | 
         | 
| 
         | 
|
| 149 | 
         | 
| 150 | 
         
             
                    """ Update talent options """
         
     | 
| 151 | 
         
             
                    for i, talent_widget in enumerate(talents_widget.values()):
         
     | 
| 152 | 
         
            +
                        talents = list(school.talent_gains[i])
         
     | 
| 153 | 
         
            +
                        default_index = talents.index(parser.select_talents[i]) + 1
         
     | 
| 154 | 
         
            +
                        talent_widget.set_items([""] + [school.talent_decoder[talent] for talent in talents],
         
     | 
| 155 | 
         
            +
                                                default_index=default_index)
         
     | 
| 156 | 
         
            +
             
     | 
| 157 | 
         
            +
                    """ Update recipe options """
         
     | 
| 158 | 
         
            +
                    for recipe_widget in recipes_widget.values():
         
     | 
| 159 | 
         
            +
                        recipe_widget.list.clear()
         
     | 
| 160 | 
         
            +
                        recipe_widget.hide()
         
     | 
| 161 | 
         
            +
             
     | 
| 162 | 
         
            +
                    for i, (skill, recipes) in enumerate(school.recipes.items()):
         
     | 
| 163 | 
         
            +
                        recipes_widget[i].set_label(skill)
         
     | 
| 164 | 
         
            +
                        recipes_widget[i].set_items(recipes)
         
     | 
| 165 | 
         
            +
                        for n in range(MAX_RECIPES):
         
     | 
| 166 | 
         
            +
                            recipes_widget[i].list.item(n).setSelected(True)
         
     | 
| 167 | 
         
            +
                        recipes_widget[i].show()
         
     | 
| 168 | 
         
            +
             
     | 
| 169 | 
         
             
                    config_widget.show()
         
     | 
| 170 | 
         | 
| 171 | 
         
             
                top_widget.upload_button.clicked.connect(upload_logs)
         
     | 
    	
        schools/first/__init__.py
    CHANGED
    
    | 
         @@ -1,4 +1,5 @@ 
     | 
|
| 1 | 
         
             
            from schools.first.skills import SKILLS
         
     | 
| 2 | 
         
             
            from schools.first.buffs import BUFFS
         
     | 
| 3 | 
         
            -
            from schools.first.talents import  
     | 
| 
         | 
|
| 4 | 
         
             
            from schools.first.attribute import BeiAoJue
         
     | 
| 
         | 
|
| 1 | 
         
             
            from schools.first.skills import SKILLS
         
     | 
| 2 | 
         
             
            from schools.first.buffs import BUFFS
         
     | 
| 3 | 
         
            +
            from schools.first.talents import TALENT_GAINS, TALENT_DECODER, TALENT_ENCODER
         
     | 
| 4 | 
         
            +
            from schools.first.recipes import RECIPE_GAINS, RECIPES
         
     | 
| 5 | 
         
             
            from schools.first.attribute import BeiAoJue
         
     | 
    	
        schools/first/recipes.py
    CHANGED
    
    | 
         @@ -1,71 +1,63 @@ 
     | 
|
| 1 | 
         
            -
            from typing import Dict, List 
     | 
| 2 | 
         | 
| 3 | 
         
             
            from base.buff import Buff
         
     | 
| 4 | 
         
             
            from base.recipe import damage_addition_recipe, critical_strike_recipe
         
     | 
| 5 | 
         | 
| 6 | 
         
            -
             
     | 
| 7 | 
         
            -
                "雷走风切":  
     | 
| 8 | 
         
            -
                     
     | 
| 9 | 
         
            -
                     
     | 
| 10 | 
         
            -
                     
     | 
| 11 | 
         
            -
                     
     | 
| 12 | 
         
            -
                     
     | 
| 13 | 
         
            -
                     
     | 
| 14 | 
         
            -
                 
     | 
| 15 | 
         
            -
                 
     | 
| 16 | 
         
            -
             
     | 
| 17 | 
         
            -
             
     | 
| 18 | 
         
            -
                     
     | 
| 19 | 
         
            -
                     
     | 
| 20 | 
         
            -
                     
     | 
| 21 | 
         
            -
                     
     | 
| 22 | 
         
            -
             
     | 
| 23 | 
         
            -
             
     | 
| 24 | 
         
            -
             
     | 
| 25 | 
         
            -
             
     | 
| 26 | 
         
            -
             
     | 
| 27 | 
         
            -
             
     | 
| 28 | 
         
            -
                     
     | 
| 29 | 
         
            -
                     
     | 
| 30 | 
         
            -
             
     | 
| 31 | 
         
            -
             
     | 
| 32 | 
         
            -
                     
     | 
| 33 | 
         
            -
                     
     | 
| 34 | 
         
            -
             
     | 
| 35 | 
         
            -
             
     | 
| 36 | 
         
            -
             
     | 
| 37 | 
         
            -
             
     | 
| 38 | 
         
            -
             
     | 
| 39 | 
         
            -
             
     | 
| 40 | 
         
            -
                     
     | 
| 41 | 
         
            -
                     
     | 
| 42 | 
         
            -
                     
     | 
| 43 | 
         
            -
                     
     | 
| 44 | 
         
            -
             
     | 
| 45 | 
         
            -
             
     | 
| 46 | 
         
            -
             
     | 
| 47 | 
         
            -
                " 
     | 
| 48 | 
         
            -
                     
     | 
| 49 | 
         
            -
                     
     | 
| 50 | 
         
            -
                     
     | 
| 51 | 
         
            -
                     
     | 
| 52 | 
         
            -
                     
     | 
| 53 | 
         
            -
             
     | 
| 54 | 
         
            -
                ],
         
     | 
| 55 | 
         
            -
                "刀啸风吟": [
         
     | 
| 56 | 
         
            -
                    ("5%伤害", damage_addition_recipe([16610], 51)),
         
     | 
| 57 | 
         
            -
                    ("4%伤害", damage_addition_recipe([16610], 41)),
         
     | 
| 58 | 
         
            -
                    ("4%会心", critical_strike_recipe([16610], 400)),
         
     | 
| 59 | 
         
            -
                    ("3%会心", critical_strike_recipe([16610], 300)),
         
     | 
| 60 | 
         
            -
                    ("2%会心", critical_strike_recipe([16610], 200)),
         
     | 
| 61 | 
         
            -
                ]
         
     | 
| 62 | 
         
            -
             
     | 
| 63 | 
         
             
            }
         
     | 
| 64 | 
         | 
| 65 | 
         
            -
             
     | 
| 66 | 
         
            -
                 
     | 
| 67 | 
         
            -
             
     | 
| 68 | 
         
            -
             
     | 
| 69 | 
         
            -
             
     | 
| 70 | 
         
            -
             
     | 
| 71 | 
         
            -
             
     | 
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            from typing import Dict, List
         
     | 
| 2 | 
         | 
| 3 | 
         
             
            from base.buff import Buff
         
     | 
| 4 | 
         
             
            from base.recipe import damage_addition_recipe, critical_strike_recipe
         
     | 
| 5 | 
         | 
| 6 | 
         
            +
            RECIPE_GAINS: Dict[str, Dict[str, dict | Buff]] = {
         
     | 
| 7 | 
         
            +
                "雷走风切": {
         
     | 
| 8 | 
         
            +
                    "5%伤害": damage_addition_recipe([16631, 16599], 51),
         
     | 
| 9 | 
         
            +
                    "4%伤害": damage_addition_recipe([16631, 16599], 41),
         
     | 
| 10 | 
         
            +
                    "3%伤害": damage_addition_recipe([16631, 16599], 31),
         
     | 
| 11 | 
         
            +
                    "4%会心": critical_strike_recipe([16631, 16599], 400),
         
     | 
| 12 | 
         
            +
                    "3%会心": critical_strike_recipe([16631, 16599], 300),
         
     | 
| 13 | 
         
            +
                    "2%会心": critical_strike_recipe([16631, 16599], 200),
         
     | 
| 14 | 
         
            +
                },
         
     | 
| 15 | 
         
            +
                "项王击鼎": {
         
     | 
| 16 | 
         
            +
                    "5%伤害": damage_addition_recipe([16760, 16382], 51),
         
     | 
| 17 | 
         
            +
                    "4%伤害": damage_addition_recipe([16760, 16382], 41),
         
     | 
| 18 | 
         
            +
                    "3%伤害": damage_addition_recipe([16760, 16382], 31),
         
     | 
| 19 | 
         
            +
                    "4%会心": critical_strike_recipe([16760, 16382], 400),
         
     | 
| 20 | 
         
            +
                    "3%会心": critical_strike_recipe([16760, 16382], 300),
         
     | 
| 21 | 
         
            +
                    "2%会心": critical_strike_recipe([16760, 16382], 200),
         
     | 
| 22 | 
         
            +
                },
         
     | 
| 23 | 
         
            +
                "破釜沉舟": {
         
     | 
| 24 | 
         
            +
                    "5%伤害": damage_addition_recipe([20991], 51),
         
     | 
| 25 | 
         
            +
                    "4%伤害": damage_addition_recipe([20991], 41),
         
     | 
| 26 | 
         
            +
                    "3%伤害": damage_addition_recipe([20991], 31),
         
     | 
| 27 | 
         
            +
                    "4%会心": critical_strike_recipe([20991], 400),
         
     | 
| 28 | 
         
            +
                    "3%会心": critical_strike_recipe([20991], 300),
         
     | 
| 29 | 
         
            +
                    "2%会心": critical_strike_recipe([20991], 200),
         
     | 
| 30 | 
         
            +
                },
         
     | 
| 31 | 
         
            +
                "上将军印": {
         
     | 
| 32 | 
         
            +
                    "4%伤害": damage_addition_recipe([16803, 16802, 16801, 16800, 17043, 19423, 19424, 32859], 41),
         
     | 
| 33 | 
         
            +
                    "3%伤害": damage_addition_recipe([16803, 16802, 16801, 16800, 17043, 19423, 19424, 32859], 31),
         
     | 
| 34 | 
         
            +
                    "2%伤害": damage_addition_recipe([16803, 16802, 16801, 16800, 17043, 19423, 19424, 32859], 21),
         
     | 
| 35 | 
         
            +
                    "4%会心": critical_strike_recipe([16803, 16802, 16801, 16800, 17043, 19423, 19424], 400),
         
     | 
| 36 | 
         
            +
                    "3%会心": critical_strike_recipe([16803, 16802, 16801, 16800, 17043, 19423, 19424], 300),
         
     | 
| 37 | 
         
            +
                    "2%会心": critical_strike_recipe([16803, 16802, 16801, 16800, 17043, 19423, 19424], 200),
         
     | 
| 38 | 
         
            +
                },
         
     | 
| 39 | 
         
            +
                "擒龙六斩": {
         
     | 
| 40 | 
         
            +
                    "5%伤���": damage_addition_recipe([16933, 16934, 16935, 16936, 16937, 16938], 51),
         
     | 
| 41 | 
         
            +
                    "4%伤害": damage_addition_recipe([16933, 16934, 16935, 16936, 16937, 16938], 41),
         
     | 
| 42 | 
         
            +
                    "3%伤害": damage_addition_recipe([16933, 16934, 16935, 16936, 16937, 16938], 31),
         
     | 
| 43 | 
         
            +
                    "4%会心": critical_strike_recipe([16933, 16934, 16935, 16936, 16937, 16938], 400),
         
     | 
| 44 | 
         
            +
                    "3%会心": critical_strike_recipe([16933, 16934, 16935, 16936, 16937, 16938], 300),
         
     | 
| 45 | 
         
            +
                    "2%会心": critical_strike_recipe([16933, 16934, 16935, 16936, 16937, 16938], 200),
         
     | 
| 46 | 
         
            +
                },
         
     | 
| 47 | 
         
            +
                "刀啸风吟": {
         
     | 
| 48 | 
         
            +
                    "5%伤害": damage_addition_recipe([16610], 51),
         
     | 
| 49 | 
         
            +
                    "4%伤害": damage_addition_recipe([16610], 41),
         
     | 
| 50 | 
         
            +
                    "4%会心": critical_strike_recipe([16610], 400),
         
     | 
| 51 | 
         
            +
                    "3%会心": critical_strike_recipe([16610], 300),
         
     | 
| 52 | 
         
            +
                    "2%会心": critical_strike_recipe([16610], 200),
         
     | 
| 53 | 
         
            +
                }
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 54 | 
         
             
            }
         
     | 
| 55 | 
         | 
| 56 | 
         
            +
            RECIPES: Dict[str, List[str]] = {
         
     | 
| 57 | 
         
            +
                "雷走风切": ["5%伤害", "4%伤害", "3%伤害", "4%会心", "3%会心", "2%会心"], 
         
     | 
| 58 | 
         
            +
                "项王击鼎": ["5%伤害", "4%伤害", "3%伤害", "4%会心", "3%会心", "2%会心"], 
         
     | 
| 59 | 
         
            +
                "破釜沉舟": ["5%伤害", "4%伤害", "3%伤害", "4%会心", "3%会心", "2%会心"], 
         
     | 
| 60 | 
         
            +
                "上将军印": ["4%伤害", "3%伤害", "2%伤害", "4%会心", "3%会心", "2%会心"], 
         
     | 
| 61 | 
         
            +
                "擒龙六斩": ["5%伤害", "4%伤害", "3%伤害", "4%会心", "3%会心", "2%会心"], 
         
     | 
| 62 | 
         
            +
                "刀啸风吟": ["5%伤害", "4%伤害", "4%会心", "3%会心", "2%会心"]
         
     | 
| 63 | 
         
            +
            }
         
     | 
    	
        schools/first/skills.py
    CHANGED
    
    | 
         @@ -1,6 +1,8 @@ 
     | 
|
| 1 | 
         
            -
            from  
     | 
| 2 | 
         | 
| 3 | 
         
            -
             
     | 
| 
         | 
|
| 
         | 
|
| 4 | 
         
             
                32823: {
         
     | 
| 5 | 
         
             
                    "skill_class": PhysicalDamage,
         
     | 
| 6 | 
         
             
                    "skill_name": "破",
         
     | 
| 
         @@ -288,3 +290,6 @@ for skill_id, detail in SKILLS.items(): 
     | 
|
| 288 | 
         
             
                SKILLS[skill_id] = detail.pop('skill_class')(skill_id, detail.pop('skill_name'))
         
     | 
| 289 | 
         
             
                for attr, value in detail.items():
         
     | 
| 290 | 
         
             
                    setattr(SKILLS[skill_id], attr, value)
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            from typing import Dict
         
     | 
| 2 | 
         | 
| 3 | 
         
            +
            from base.skill import PhysicalDamage, PhysicalDotDamage, Skill
         
     | 
| 4 | 
         
            +
             
     | 
| 5 | 
         
            +
            SKILLS: Dict[int, Skill | dict] = {
         
     | 
| 6 | 
         
             
                32823: {
         
     | 
| 7 | 
         
             
                    "skill_class": PhysicalDamage,
         
     | 
| 8 | 
         
             
                    "skill_name": "破",
         
     | 
| 
         | 
|
| 290 | 
         
             
                SKILLS[skill_id] = detail.pop('skill_class')(skill_id, detail.pop('skill_name'))
         
     | 
| 291 | 
         
             
                for attr, value in detail.items():
         
     | 
| 292 | 
         
             
                    setattr(SKILLS[skill_id], attr, value)
         
     | 
| 293 | 
         
            +
             
     | 
| 294 | 
         
            +
            SKILL_DECODER = {skill_id: skill.skill_name for skill_id, skill in SKILLS.items()}
         
     | 
| 295 | 
         
            +
            SKILL_ENCODER = {v: k for k, v in SKILL_DECODER.items()}
         
     | 
    	
        schools/first/talents.py
    CHANGED
    
    | 
         @@ -2,9 +2,9 @@ from typing import Dict, List 
     | 
|
| 2 | 
         | 
| 3 | 
         
             
            from base.buff import Buff
         
     | 
| 4 | 
         | 
| 5 | 
         
            -
             
     | 
| 6 | 
         
            -
                {16691: {}},
         
     | 
| 7 | 
         
            -
                {16847: {}},
         
     | 
| 8 | 
         
             
                {
         
     | 
| 9 | 
         
             
                    26904: {
         
     | 
| 10 | 
         
             
                        "buff_name": "冥鼔",
         
     | 
| 
         @@ -35,12 +35,12 @@ TALENTS: List[Dict[int, dict | Buff]] = [ 
     | 
|
| 35 | 
         
             
                        }
         
     | 
| 36 | 
         
             
                    }
         
     | 
| 37 | 
         
             
                },
         
     | 
| 38 | 
         
            -
                {16799: {}},
         
     | 
| 39 | 
         
            -
                {25633: {}},
         
     | 
| 40 | 
         
            -
                {32857: {}},
         
     | 
| 41 | 
         
            -
                {17047: {}},
         
     | 
| 42 | 
         
             
                {
         
     | 
| 43 | 
         
            -
                    25258: {},
         
     | 
| 44 | 
         
             
                    16728: {
         
     | 
| 45 | 
         
             
                        "buff_name": "星火",
         
     | 
| 46 | 
         
             
                        "gain_attributes": {
         
     | 
| 
         @@ -56,7 +56,7 @@ TALENTS: List[Dict[int, dict | Buff]] = [ 
     | 
|
| 56 | 
         
             
                        }
         
     | 
| 57 | 
         
             
                    }
         
     | 
| 58 | 
         
             
                },
         
     | 
| 59 | 
         
            -
                {16737: {}},
         
     | 
| 60 | 
         
             
                {
         
     | 
| 61 | 
         
             
                    17056: {
         
     | 
| 62 | 
         
             
                        "buff_name": "绝期",
         
     | 
| 
         @@ -67,14 +67,19 @@ TALENTS: List[Dict[int, dict | Buff]] = [ 
     | 
|
| 67 | 
         
             
                        }
         
     | 
| 68 | 
         
             
                    }
         
     | 
| 69 | 
         
             
                },
         
     | 
| 70 | 
         
            -
                {16893: {}},
         
     | 
| 71 | 
         
            -
                {21858: {}}
         
     | 
| 72 | 
         
             
            ]
         
     | 
| 73 | 
         | 
| 74 | 
         
            -
            for talent in  
     | 
| 75 | 
         
             
                for talent_id, detail in talent.items():
         
     | 
| 76 | 
         
             
                    if not detail:
         
     | 
| 77 | 
         
            -
                         
     | 
| 78 | 
         
            -
                     
     | 
| 
         | 
|
| 79 | 
         
             
                    for attr, value in detail.items():
         
     | 
| 80 | 
         
             
                        setattr(talent[talent_id], attr, value)
         
     | 
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 2 | 
         | 
| 3 | 
         
             
            from base.buff import Buff
         
     | 
| 4 | 
         | 
| 5 | 
         
            +
            TALENT_GAINS: List[Dict[int, dict | Buff]] = [
         
     | 
| 6 | 
         
            +
                {16691: {"buff_name": "龙息"}},
         
     | 
| 7 | 
         
            +
                {16847: {"buff_name": "归酣"}},
         
     | 
| 8 | 
         
             
                {
         
     | 
| 9 | 
         
             
                    26904: {
         
     | 
| 10 | 
         
             
                        "buff_name": "冥鼔",
         
     | 
| 
         | 
|
| 35 | 
         
             
                        }
         
     | 
| 36 | 
         
             
                    }
         
     | 
| 37 | 
         
             
                },
         
     | 
| 38 | 
         
            +
                {16799: {"buff_name": "霜天"}},
         
     | 
| 39 | 
         
            +
                {25633: {"buff_name": "含风"}},
         
     | 
| 40 | 
         
            +
                {32857: {"buff_name": "见尘"}},
         
     | 
| 41 | 
         
            +
                {17047: {"buff_name": "分疆"}},
         
     | 
| 42 | 
         
             
                {
         
     | 
| 43 | 
         
            +
                    25258: {"buff_name": "掠关"},
         
     | 
| 44 | 
         
             
                    16728: {
         
     | 
| 45 | 
         
             
                        "buff_name": "星火",
         
     | 
| 46 | 
         
             
                        "gain_attributes": {
         
     | 
| 
         | 
|
| 56 | 
         
             
                        }
         
     | 
| 57 | 
         
             
                    }
         
     | 
| 58 | 
         
             
                },
         
     | 
| 59 | 
         
            +
                {16737: {"buff_name": "楚歌"}},
         
     | 
| 60 | 
         
             
                {
         
     | 
| 61 | 
         
             
                    17056: {
         
     | 
| 62 | 
         
             
                        "buff_name": "绝期",
         
     | 
| 
         | 
|
| 67 | 
         
             
                        }
         
     | 
| 68 | 
         
             
                    }
         
     | 
| 69 | 
         
             
                },
         
     | 
| 70 | 
         
            +
                {16893: {"buff_name": "重烟"}},
         
     | 
| 71 | 
         
            +
                {21858: {"buff_name": "降麒式"}}
         
     | 
| 72 | 
         
             
            ]
         
     | 
| 73 | 
         | 
| 74 | 
         
            +
            for talent in TALENT_GAINS:
         
     | 
| 75 | 
         
             
                for talent_id, detail in talent.items():
         
     | 
| 76 | 
         
             
                    if not detail:
         
     | 
| 77 | 
         
            +
                        talent[talent_id] = Buff()
         
     | 
| 78 | 
         
            +
                    else:
         
     | 
| 79 | 
         
            +
                        talent[talent_id] = Buff(talent_id, detail.pop("buff_name"))
         
     | 
| 80 | 
         
             
                    for attr, value in detail.items():
         
     | 
| 81 | 
         
             
                        setattr(talent[talent_id], attr, value)
         
     | 
| 82 | 
         
            +
             
     | 
| 83 | 
         
            +
             
     | 
| 84 | 
         
            +
            TALENT_DECODER = {talent_id: talent.buff_name for talents in TALENT_GAINS for talent_id, talent in talents.items()}
         
     | 
| 85 | 
         
            +
            TALENT_ENCODER = {v: k for k, v in TALENT_DECODER.items()}
         
     | 
    	
        schools/first/test.py
    CHANGED
    
    | 
         @@ -1,4 +1,4 @@ 
     | 
|
| 1 | 
         
            -
            from  
     | 
| 2 | 
         
             
            from qt.scripts.top import Parser
         
     | 
| 3 | 
         
             
            from schools.first.attribute import BeiAoJue
         
     | 
| 4 | 
         | 
| 
         @@ -17,5 +17,5 @@ if __name__ == '__main__': 
     | 
|
| 17 | 
         | 
| 18 | 
         
             
                parser = Parser()
         
     | 
| 19 | 
         
             
                parser("logs.jcl")
         
     | 
| 20 | 
         
            -
                analyze_details(parser, attribute)
         
     | 
| 21 | 
         
             
                print(parser.records)
         
     | 
| 
         | 
|
| 1 | 
         
            +
            from utils.analyzer import analyze_details
         
     | 
| 2 | 
         
             
            from qt.scripts.top import Parser
         
     | 
| 3 | 
         
             
            from schools.first.attribute import BeiAoJue
         
     | 
| 4 | 
         | 
| 
         | 
|
| 17 | 
         | 
| 18 | 
         
             
                parser = Parser()
         
     | 
| 19 | 
         
             
                parser("logs.jcl")
         
     | 
| 20 | 
         
            +
                analyze_details(parser, attribute, parser.school)
         
     | 
| 21 | 
         
             
                print(parser.records)
         
     | 
    	
        utils/analyzer.py
    ADDED
    
    | 
         @@ -0,0 +1,89 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            from base.attribute import Attribute
         
     | 
| 2 | 
         
            +
            from qt.scripts.top import School
         
     | 
| 3 | 
         
            +
             
     | 
| 4 | 
         
            +
             
     | 
| 5 | 
         
            +
            def refresh_status(existed_buffs, buffs, attribute: Attribute, school: School):
         
     | 
| 6 | 
         
            +
                for buff in [buff for buff in existed_buffs if buff not in buffs]:
         
     | 
| 7 | 
         
            +
                    existed_buffs.remove(buff)
         
     | 
| 8 | 
         
            +
                    buff_id, buff_level, buff_stack = buff
         
     | 
| 9 | 
         
            +
                    buff = school.buffs[buff_id]
         
     | 
| 10 | 
         
            +
                    buff.buff_level, buff.buff_stack = buff_level, buff_stack
         
     | 
| 11 | 
         
            +
                    attribute = attribute - buff
         
     | 
| 12 | 
         
            +
                    school.skills = school.skills - buff
         
     | 
| 13 | 
         
            +
             
     | 
| 14 | 
         
            +
                for buff in [buff for buff in buffs if buff not in existed_buffs]:
         
     | 
| 15 | 
         
            +
                    existed_buffs.append(buff)
         
     | 
| 16 | 
         
            +
                    buff_id, buff_level, buff_stack = buff
         
     | 
| 17 | 
         
            +
                    buff = school.buffs[buff_id]
         
     | 
| 18 | 
         
            +
                    buff.buff_level, buff.buff_stack = buff_level, buff_stack
         
     | 
| 19 | 
         
            +
                    attribute = attribute + buff
         
     | 
| 20 | 
         
            +
                    school.skills = school.skills + buff
         
     | 
| 21 | 
         
            +
             
     | 
| 22 | 
         
            +
             
     | 
| 23 | 
         
            +
            def analyze_details(record, attribute: Attribute, school: School):
         
     | 
| 24 | 
         
            +
                details = {}
         
     | 
| 25 | 
         
            +
                total_damage = 0
         
     | 
| 26 | 
         
            +
                total_gradients = {attr: 0 for attr in attribute.grad_attrs}
         
     | 
| 27 | 
         
            +
             
     | 
| 28 | 
         
            +
                existed_buffs = []
         
     | 
| 29 | 
         
            +
                for skill, status in record.items():
         
     | 
| 30 | 
         
            +
                    skill_id, skill_level = skill
         
     | 
| 31 | 
         
            +
                    skill = school.skills[skill_id]
         
     | 
| 32 | 
         
            +
                    skill.skill_level = skill_level
         
     | 
| 33 | 
         
            +
             
     | 
| 34 | 
         
            +
                    skill_detail = {}
         
     | 
| 35 | 
         
            +
                    details[skill.display_name] = skill_detail
         
     | 
| 36 | 
         
            +
                    for buffs, timeline in status.items():
         
     | 
| 37 | 
         
            +
                        refresh_status(existed_buffs, buffs, attribute, school)
         
     | 
| 38 | 
         
            +
             
     | 
| 39 | 
         
            +
                        damage, critical_strike, critical_damage, expected_damage = skill(attribute)
         
     | 
| 40 | 
         
            +
                        gradients = analyze_gradients(skill, attribute)
         
     | 
| 41 | 
         
            +
             
     | 
| 42 | 
         
            +
                        total_damage += expected_damage * len(timeline)
         
     | 
| 43 | 
         
            +
                        for attr, residual_damage in gradients.items():
         
     | 
| 44 | 
         
            +
                            total_gradients[attr] += residual_damage * len(timeline)
         
     | 
| 45 | 
         
            +
             
     | 
| 46 | 
         
            +
                        buffs = ";".join(school.buffs[buff_id].display_name for buff_id, _, _ in buffs)
         
     | 
| 47 | 
         
            +
                        if not buffs:
         
     | 
| 48 | 
         
            +
                            buffs = "~-~-~"
         
     | 
| 49 | 
         
            +
                        skill_detail[buffs] = dict(
         
     | 
| 50 | 
         
            +
                            damage=damage,
         
     | 
| 51 | 
         
            +
                            critical_strike=critical_strike,
         
     | 
| 52 | 
         
            +
                            critical_damage=critical_damage,
         
     | 
| 53 | 
         
            +
                            expected_damage=expected_damage,
         
     | 
| 54 | 
         
            +
                            # "timeline": [round(t / 1000, 3) for t in timeline],
         
     | 
| 55 | 
         
            +
                            count=len(timeline),
         
     | 
| 56 | 
         
            +
                            gradients=gradients
         
     | 
| 57 | 
         
            +
                        )
         
     | 
| 58 | 
         
            +
             
     | 
| 59 | 
         
            +
                refresh_status(existed_buffs, [], attribute, school)
         
     | 
| 60 | 
         
            +
             
     | 
| 61 | 
         
            +
                for attr, residual_damage in total_gradients.items():
         
     | 
| 62 | 
         
            +
                    total_gradients[attr] = round(residual_damage / total_damage * 100, 4)
         
     | 
| 63 | 
         
            +
             
     | 
| 64 | 
         
            +
                summary = analyze_summary(details)
         
     | 
| 65 | 
         
            +
                return total_damage, total_gradients, details, summary
         
     | 
| 66 | 
         
            +
             
     | 
| 67 | 
         
            +
             
     | 
| 68 | 
         
            +
            def analyze_summary(details):
         
     | 
| 69 | 
         
            +
                summary = {}
         
     | 
| 70 | 
         
            +
                for skill, skill_detail in details.items():
         
     | 
| 71 | 
         
            +
                    skill = skill.split("/")[0]
         
     | 
| 72 | 
         
            +
                    if skill not in summary:
         
     | 
| 73 | 
         
            +
                        summary[skill] = {"count": 0, "hit": 0, "critical": 0, "damage": 0}
         
     | 
| 74 | 
         
            +
                    for buff, detail in skill_detail.items():
         
     | 
| 75 | 
         
            +
                        summary[skill]["count"] += detail['count']
         
     | 
| 76 | 
         
            +
                        summary[skill]["critical"] += detail['count'] * detail['critical_strike']
         
     | 
| 77 | 
         
            +
                        summary[skill]["damage"] += detail['count'] * detail['expected_damage']
         
     | 
| 78 | 
         
            +
             
     | 
| 79 | 
         
            +
                return summary
         
     | 
| 80 | 
         
            +
             
     | 
| 81 | 
         
            +
             
     | 
| 82 | 
         
            +
            def analyze_gradients(skill, attribute):
         
     | 
| 83 | 
         
            +
                results = {}
         
     | 
| 84 | 
         
            +
                for attr, value in attribute.grad_attrs.items():
         
     | 
| 85 | 
         
            +
                    origin_value = getattr(attribute, attr)
         
     | 
| 86 | 
         
            +
                    setattr(attribute, attr, origin_value + value)
         
     | 
| 87 | 
         
            +
                    _, _, _, results[attr] = skill(attribute)
         
     | 
| 88 | 
         
            +
                    setattr(attribute, attr, origin_value)
         
     | 
| 89 | 
         
            +
                return results
         
     | 
    	
        {base → utils}/damage.py
    RENAMED
    
    | 
         
            File without changes
         
     |