endfield-py 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- endfield/__init__.py +3 -0
- endfield/calculator.py +271 -0
- endfield/client.py +693 -0
- endfield/decoder.py +37 -0
- endfield/errors.py +47 -0
- endfield/models/__init__.py +5 -0
- endfield/models/character.py +135 -0
- endfield/models/equipment.py +42 -0
- endfield/models/profile.py +36 -0
- endfield/models/showcase.py +11 -0
- endfield/models/weapon.py +44 -0
- endfield/resolver.py +101 -0
- endfield/update.py +41 -0
- endfield_py-1.0.0.dist-info/METADATA +267 -0
- endfield_py-1.0.0.dist-info/RECORD +18 -0
- endfield_py-1.0.0.dist-info/WHEEL +5 -0
- endfield_py-1.0.0.dist-info/licenses/LICENSE.txt +21 -0
- endfield_py-1.0.0.dist-info/top_level.txt +1 -0
endfield/__init__.py
ADDED
endfield/calculator.py
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
from typing import Optional, Union, List, Dict, Literal
|
|
2
|
+
|
|
3
|
+
from .models.character import (
|
|
4
|
+
ComputedStats, TalentInfo, SkillInfo, CharacterData,
|
|
5
|
+
TalentPassiveNode, TalentFactoryNode,
|
|
6
|
+
)
|
|
7
|
+
from .models.equipment import EquipData, SuitSet
|
|
8
|
+
from .models.weapon import WeaponData
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
F_TYPES = Literal["BaseAddition", "BaseMultiplier", "BaseFinalAddition", "BaseFinalMultiplier"]
|
|
12
|
+
ATTRI_IDS = Literal["39", "40", "41", "42"]
|
|
13
|
+
|
|
14
|
+
ID_TO_PROP: Dict[str, str] = {
|
|
15
|
+
"1": "MaxHp_base",
|
|
16
|
+
"2": "Atk_base",
|
|
17
|
+
"3": "Def_base",
|
|
18
|
+
"9": "CriticalRate_base",
|
|
19
|
+
"10": "CriticalDamage_base",
|
|
20
|
+
"17": "NormalAtkDamageIncrease_base",
|
|
21
|
+
"28": "UltimateSkillDamageIncrease_base",
|
|
22
|
+
"29": "HealOutputIncrease_base",
|
|
23
|
+
"30": "HealTakenIncrease_base",
|
|
24
|
+
"32": "NormalSkillDamageIncrease_base",
|
|
25
|
+
"33": "ComboSkillDamageIncrease_base",
|
|
26
|
+
"39": "Str_base",
|
|
27
|
+
"40": "Agi_base",
|
|
28
|
+
"41": "Wisd_base",
|
|
29
|
+
"42": "Will_base",
|
|
30
|
+
"44": "UltimateSpGainScalar_base",
|
|
31
|
+
"50": "PhysicalDamageIncrease_base",
|
|
32
|
+
"51": "FireDamageIncrease_base",
|
|
33
|
+
"52": "PulseDamageIncrease_base",
|
|
34
|
+
"53": "CrystDamageIncrease_base",
|
|
35
|
+
"54": "NaturalDamageIncrease_base",
|
|
36
|
+
"55": "EtherDamageIncrease_base",
|
|
37
|
+
"87": "PhysicalAndSpellInflictionEnhance_base",
|
|
38
|
+
"10000": "Main_ratio",
|
|
39
|
+
"10001": "Sub_ratio",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
ID_TO_OBJ_MAP: Dict[str, str] = {
|
|
43
|
+
"1": "hp",
|
|
44
|
+
"2": "atk",
|
|
45
|
+
"3": "defense",
|
|
46
|
+
"9": "crit_rate",
|
|
47
|
+
"10": "crit_dmg",
|
|
48
|
+
"17": "normal_atk_dmg_bonus",
|
|
49
|
+
"28": "ult_skill_dmg_bonus",
|
|
50
|
+
"29": "healing_bonus",
|
|
51
|
+
"30": "healing_received_bonus",
|
|
52
|
+
"32": "normal_skill_dmg_bonus",
|
|
53
|
+
"33": "combo_skill_dmg_bonus",
|
|
54
|
+
"39": "str",
|
|
55
|
+
"40": "agi",
|
|
56
|
+
"41": "wisd",
|
|
57
|
+
"42": "will",
|
|
58
|
+
"44": "ultimate_gain_efficiency",
|
|
59
|
+
"50": "physical_dmg_bonus",
|
|
60
|
+
"51": "fire_dmg_bonus",
|
|
61
|
+
"52": "pulse_dmg_bonus",
|
|
62
|
+
"53": "cryst_dmg_bonus",
|
|
63
|
+
"54": "natural_dmg_bonus",
|
|
64
|
+
"55": "ether_dmg_bonus",
|
|
65
|
+
"87": "infliction_enhance",
|
|
66
|
+
"10000": "main_attri_ratio",
|
|
67
|
+
"10001": "sub_attri_ratio",
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
INT_FIELDS = {"hp", "atk", "defense", "str", "agi", "wisd", "will"}
|
|
71
|
+
CHAR_ATTRI = {"39", "40", "41", "42"}
|
|
72
|
+
SPECIAL_IDS = {"10000", "10001"}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class _HpState:
|
|
76
|
+
__slots__ = ("mult", "flat", "final_mult")
|
|
77
|
+
|
|
78
|
+
def __init__(self):
|
|
79
|
+
self.mult: float = 0.0
|
|
80
|
+
self.flat: float = 0.0
|
|
81
|
+
self.final_mult: float = 0.0
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def apply_prop(
|
|
86
|
+
computed: ComputedStats,
|
|
87
|
+
prop_id: str,
|
|
88
|
+
value: int | float,
|
|
89
|
+
formula: F_TYPES = "BaseAddition",
|
|
90
|
+
main_attri_id: ATTRI_IDS = "39",
|
|
91
|
+
sub_attri_id: ATTRI_IDS = "40",
|
|
92
|
+
base_attri_value: int | float = 0,
|
|
93
|
+
sub_attri_value: int | float = 0,
|
|
94
|
+
base_atk: int = 0,
|
|
95
|
+
base_hp: int = 0,
|
|
96
|
+
base_attributes: dict | None = None,
|
|
97
|
+
hp_state: _HpState | None = None,
|
|
98
|
+
) -> None:
|
|
99
|
+
|
|
100
|
+
if prop_id in SPECIAL_IDS:
|
|
101
|
+
attri_id = main_attri_id if prop_id == "10000" else sub_attri_id
|
|
102
|
+
if attri_id not in CHAR_ATTRI:
|
|
103
|
+
return
|
|
104
|
+
base_val = base_attri_value if prop_id == "10000" else sub_attri_value
|
|
105
|
+
obj = ID_TO_OBJ_MAP[attri_id]
|
|
106
|
+
cur = getattr(computed, obj, 0) or 0
|
|
107
|
+
if value <= 1.5 or formula == "BaseMultiplier":
|
|
108
|
+
new_val = cur + cur * value
|
|
109
|
+
else:
|
|
110
|
+
new_val = cur + value
|
|
111
|
+
setattr(computed, obj, int(new_val) if obj in INT_FIELDS else new_val)
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
obj = ID_TO_OBJ_MAP.get(prop_id)
|
|
115
|
+
if obj is None:
|
|
116
|
+
print(f"[apply_prop] Unknown prop_id: {prop_id}")
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
cur = getattr(computed, obj, None)
|
|
120
|
+
if cur is None:
|
|
121
|
+
cur = 0
|
|
122
|
+
|
|
123
|
+
if prop_id == "1" and hp_state is not None:
|
|
124
|
+
if formula == "BaseMultiplier":
|
|
125
|
+
hp_state.mult += value
|
|
126
|
+
elif formula in ("BaseAddition", "BaseFinalAddition"):
|
|
127
|
+
hp_state.flat += value
|
|
128
|
+
elif formula == "BaseFinalMultiplier":
|
|
129
|
+
hp_state.final_mult += value
|
|
130
|
+
else:
|
|
131
|
+
print(f"[apply_prop] Unknown HP formula: {formula}")
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
if formula == "BaseAddition":
|
|
135
|
+
new_val = cur + value
|
|
136
|
+
|
|
137
|
+
elif formula == "BaseMultiplier":
|
|
138
|
+
if prop_id == "2":
|
|
139
|
+
base_val = base_atk
|
|
140
|
+
elif prop_id == "1":
|
|
141
|
+
base_val = base_hp
|
|
142
|
+
elif base_attributes and prop_id in base_attributes:
|
|
143
|
+
base_val = base_attributes[prop_id].value
|
|
144
|
+
else:
|
|
145
|
+
print(f"[apply_prop] BaseMultiplier: no base value for prop_id={prop_id}")
|
|
146
|
+
return
|
|
147
|
+
if not base_val:
|
|
148
|
+
print(f"[apply_prop] BaseMultiplier: base_val is zero for prop_id={prop_id}")
|
|
149
|
+
return
|
|
150
|
+
new_val = cur + base_val * value
|
|
151
|
+
|
|
152
|
+
elif formula == "BaseFinalAddition":
|
|
153
|
+
new_val = cur + value
|
|
154
|
+
|
|
155
|
+
elif formula == "BaseFinalMultiplier":
|
|
156
|
+
new_val = cur + cur * value
|
|
157
|
+
|
|
158
|
+
else:
|
|
159
|
+
print(f"[apply_prop] Unknown formula: {formula}")
|
|
160
|
+
return
|
|
161
|
+
|
|
162
|
+
if obj in INT_FIELDS:
|
|
163
|
+
new_val = int(new_val)
|
|
164
|
+
setattr(computed, obj, new_val)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def compute_final_stats(character: CharacterData) -> ComputedStats:
|
|
169
|
+
base_atk_char = character.base_atk.value
|
|
170
|
+
base_hp = character.base_hp.value
|
|
171
|
+
|
|
172
|
+
main_attri_id = character.main_attribute.attri_id
|
|
173
|
+
sub_attri_id = character.sub_attribute.attri_id
|
|
174
|
+
|
|
175
|
+
all_base_attri = {item.attri_id: item for item in character.base_attribute}
|
|
176
|
+
main_attri_value = all_base_attri[main_attri_id].value
|
|
177
|
+
sub_attri_value = all_base_attri[sub_attri_id].value
|
|
178
|
+
|
|
179
|
+
base_str = all_base_attri["39"].value
|
|
180
|
+
base_agi = all_base_attri["40"].value
|
|
181
|
+
base_wisd = all_base_attri["41"].value
|
|
182
|
+
base_will = all_base_attri["42"].value
|
|
183
|
+
|
|
184
|
+
weapon_base_atk = character.weapon.base_atk
|
|
185
|
+
weapon_skills = {skill.skill_id: skill for skill in character.weapon.skills}
|
|
186
|
+
|
|
187
|
+
total_base_atk = base_atk_char + weapon_base_atk
|
|
188
|
+
|
|
189
|
+
computed = ComputedStats(
|
|
190
|
+
str=int(base_str),
|
|
191
|
+
agi=int(base_agi),
|
|
192
|
+
wisd=int(base_wisd),
|
|
193
|
+
will=int(base_will),
|
|
194
|
+
hp=int(base_hp),
|
|
195
|
+
atk=int(total_base_atk),
|
|
196
|
+
defense=0,
|
|
197
|
+
crit_rate=0.05,
|
|
198
|
+
crit_dmg=0.5,
|
|
199
|
+
arts_intensity=0.0,
|
|
200
|
+
healing_received_bonus=0.0,
|
|
201
|
+
ultimate_gain_efficiency=1.0,
|
|
202
|
+
healing_bonus=0.0,
|
|
203
|
+
normal_atk_dmg_bonus=0.0,
|
|
204
|
+
normal_skill_dmg_bonus=0.0,
|
|
205
|
+
combo_skill_dmg_bonus=0.0,
|
|
206
|
+
ult_skill_dmg_bonus=0.0,
|
|
207
|
+
physical_dmg_bonus=0.0,
|
|
208
|
+
fire_dmg_bonus=0.0,
|
|
209
|
+
pulse_dmg_bonus=0.0,
|
|
210
|
+
cryst_dmg_bonus=0.0,
|
|
211
|
+
natural_dmg_bonus=0.0,
|
|
212
|
+
ether_dmg_bonus=0.0,
|
|
213
|
+
infliction_enhance=0.0,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
hp_state = _HpState()
|
|
217
|
+
|
|
218
|
+
def _apply(prop_id, value, formula):
|
|
219
|
+
apply_prop(
|
|
220
|
+
computed, prop_id, value, formula,
|
|
221
|
+
main_attri_id, sub_attri_id,
|
|
222
|
+
main_attri_value, sub_attri_value,
|
|
223
|
+
int(total_base_atk), int(base_hp),
|
|
224
|
+
all_base_attri, hp_state,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
for equip in character.equips:
|
|
229
|
+
for attri in equip.attr_modifiers:
|
|
230
|
+
_apply(str(attri.attr_type), attri.value, attri.formula)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
if character.talents and character.talents.attr_nodes:
|
|
234
|
+
t = character.talents.attr_nodes
|
|
235
|
+
_apply(t.attri_id, t.total_value, t.formula)
|
|
236
|
+
|
|
237
|
+
if character.suit_sets:
|
|
238
|
+
for prop in character.suit_sets.active_bonus.propmap:
|
|
239
|
+
_apply(prop.prop_id, prop.value, prop.formula)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
if character.talents.potential_attributes:
|
|
243
|
+
for pote_attr in character.talents.potential_attributes:
|
|
244
|
+
for attr in pote_attr.attributes:
|
|
245
|
+
_apply(attr.attri_id, attr.value, attr.formula)
|
|
246
|
+
|
|
247
|
+
for skill in weapon_skills.values():
|
|
248
|
+
if type(skill.prop_id) == str:
|
|
249
|
+
_apply(skill.prop_id, skill.value, skill.formula)
|
|
250
|
+
elif type(skill.prop_id) == list:
|
|
251
|
+
for i , prop_id in enumerate(skill.prop_id):
|
|
252
|
+
val = skill.value[i]
|
|
253
|
+
formula = skill.formula[i]
|
|
254
|
+
_apply(prop_id, val, formula)
|
|
255
|
+
|
|
256
|
+
hp_before_mult = base_hp + computed.str * 5
|
|
257
|
+
computed.hp = int(hp_before_mult * (1.0 + hp_state.mult) + hp_state.flat)
|
|
258
|
+
if hp_state.final_mult:
|
|
259
|
+
computed.hp = int(computed.hp * (1.0 + hp_state.final_mult))
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _final_attri(attri_id: str) -> int:
|
|
263
|
+
return {"39": computed.str, "40": computed.agi,
|
|
264
|
+
"41": computed.wisd, "42": computed.will}.get(attri_id, 0)
|
|
265
|
+
|
|
266
|
+
atk_mult = 1.0 + _final_attri(main_attri_id) * 0.005 + _final_attri(sub_attri_id) * 0.002
|
|
267
|
+
computed.atk = int(computed.atk * atk_mult)
|
|
268
|
+
|
|
269
|
+
computed.healing_received_bonus = round(computed.will * 0.001, 6)
|
|
270
|
+
|
|
271
|
+
return computed
|