Spaces:
Runtime error
Runtime error
:sparkles:(features): add support for Zixiagong (#1)
Browse files- .gitignore +324 -0
- schools/__init__.py +10 -2
- schools/zi_xia_gong/__init__.py +10 -0
- schools/zi_xia_gong/attribute.py +21 -0
- schools/zi_xia_gong/buffs.py +78 -0
- schools/zi_xia_gong/gains.py +27 -0
- schools/zi_xia_gong/recipes.py +34 -0
- schools/zi_xia_gong/skills.py +123 -0
- schools/zi_xia_gong/talents.py +92 -0
- utils/parser.py +95 -151
.gitignore
ADDED
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
### JetBrains template
|
2 |
+
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
3 |
+
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
4 |
+
|
5 |
+
# User-specific stuff
|
6 |
+
.idea/**/workspace.xml
|
7 |
+
.idea/**/tasks.xml
|
8 |
+
.idea/**/usage.statistics.xml
|
9 |
+
.idea/**/dictionaries
|
10 |
+
.idea/**/shelf
|
11 |
+
|
12 |
+
# AWS User-specific
|
13 |
+
.idea/**/aws.xml
|
14 |
+
|
15 |
+
# Generated files
|
16 |
+
.idea/**/contentModel.xml
|
17 |
+
|
18 |
+
# Sensitive or high-churn files
|
19 |
+
.idea/**/dataSources/
|
20 |
+
.idea/**/dataSources.ids
|
21 |
+
.idea/**/dataSources.local.xml
|
22 |
+
.idea/**/sqlDataSources.xml
|
23 |
+
.idea/**/dynamic.xml
|
24 |
+
.idea/**/uiDesigner.xml
|
25 |
+
.idea/**/dbnavigator.xml
|
26 |
+
|
27 |
+
# Gradle
|
28 |
+
.idea/**/gradle.xml
|
29 |
+
.idea/**/libraries
|
30 |
+
|
31 |
+
# Gradle and Maven with auto-import
|
32 |
+
# When using Gradle or Maven with auto-import, you should exclude module files,
|
33 |
+
# since they will be recreated, and may cause churn. Uncomment if using
|
34 |
+
# auto-import.
|
35 |
+
# .idea/artifacts
|
36 |
+
# .idea/compiler.xml
|
37 |
+
# .idea/jarRepositories.xml
|
38 |
+
# .idea/modules.xml
|
39 |
+
# .idea/*.iml
|
40 |
+
# .idea/modules
|
41 |
+
# *.iml
|
42 |
+
# *.ipr
|
43 |
+
|
44 |
+
# CMake
|
45 |
+
cmake-build-*/
|
46 |
+
|
47 |
+
# Mongo Explorer plugin
|
48 |
+
.idea/**/mongoSettings.xml
|
49 |
+
|
50 |
+
# File-based project format
|
51 |
+
*.iws
|
52 |
+
|
53 |
+
# IntelliJ
|
54 |
+
out/
|
55 |
+
|
56 |
+
# mpeltonen/sbt-idea plugin
|
57 |
+
.idea_modules/
|
58 |
+
|
59 |
+
# JIRA plugin
|
60 |
+
atlassian-ide-plugin.xml
|
61 |
+
|
62 |
+
# Cursive Clojure plugin
|
63 |
+
.idea/replstate.xml
|
64 |
+
|
65 |
+
# SonarLint plugin
|
66 |
+
.idea/sonarlint/
|
67 |
+
|
68 |
+
# Crashlytics plugin (for Android Studio and IntelliJ)
|
69 |
+
com_crashlytics_export_strings.xml
|
70 |
+
crashlytics.properties
|
71 |
+
crashlytics-build.properties
|
72 |
+
fabric.properties
|
73 |
+
|
74 |
+
# Editor-based Rest Client
|
75 |
+
.idea/httpRequests
|
76 |
+
|
77 |
+
# Android studio 3.1+ serialized cache file
|
78 |
+
.idea/caches/build_file_checksums.ser
|
79 |
+
|
80 |
+
### Qt template
|
81 |
+
# C++ objects and libs
|
82 |
+
*.slo
|
83 |
+
*.lo
|
84 |
+
*.o
|
85 |
+
*.a
|
86 |
+
*.la
|
87 |
+
*.lai
|
88 |
+
*.so
|
89 |
+
*.so.*
|
90 |
+
*.dll
|
91 |
+
*.dylib
|
92 |
+
|
93 |
+
# Qt-es
|
94 |
+
object_script.*.Release
|
95 |
+
object_script.*.Debug
|
96 |
+
*_plugin_import.cpp
|
97 |
+
/.qmake.cache
|
98 |
+
/.qmake.stash
|
99 |
+
*.pro.user
|
100 |
+
*.pro.user.*
|
101 |
+
*.qbs.user
|
102 |
+
*.qbs.user.*
|
103 |
+
*.moc
|
104 |
+
moc_*.cpp
|
105 |
+
moc_*.h
|
106 |
+
qrc_*.cpp
|
107 |
+
ui_*.h
|
108 |
+
*.qmlc
|
109 |
+
*.jsc
|
110 |
+
Makefile*
|
111 |
+
*build-*
|
112 |
+
*.qm
|
113 |
+
*.prl
|
114 |
+
|
115 |
+
# Qt unit tests
|
116 |
+
target_wrapper.*
|
117 |
+
|
118 |
+
# QtCreator
|
119 |
+
*.autosave
|
120 |
+
|
121 |
+
# QtCreator Qml
|
122 |
+
*.qmlproject.user
|
123 |
+
*.qmlproject.user.*
|
124 |
+
|
125 |
+
# QtCreator CMake
|
126 |
+
CMakeLists.txt.user*
|
127 |
+
|
128 |
+
# QtCreator 4.8< compilation database
|
129 |
+
compile_commands.json
|
130 |
+
|
131 |
+
# QtCreator local machine specific files for imported projects
|
132 |
+
*creator.user*
|
133 |
+
|
134 |
+
*_qmlcache.qrc
|
135 |
+
|
136 |
+
### macOS template
|
137 |
+
# General
|
138 |
+
.DS_Store
|
139 |
+
.AppleDouble
|
140 |
+
.LSOverride
|
141 |
+
|
142 |
+
# Icon must end with two \r
|
143 |
+
Icon
|
144 |
+
|
145 |
+
# Thumbnails
|
146 |
+
._*
|
147 |
+
|
148 |
+
# Files that might appear in the root of a volume
|
149 |
+
.DocumentRevisions-V100
|
150 |
+
.fseventsd
|
151 |
+
.Spotlight-V100
|
152 |
+
.TemporaryItems
|
153 |
+
.Trashes
|
154 |
+
.VolumeIcon.icns
|
155 |
+
.com.apple.timemachine.donotpresent
|
156 |
+
|
157 |
+
# Directories potentially created on remote AFP share
|
158 |
+
.AppleDB
|
159 |
+
.AppleDesktop
|
160 |
+
Network Trash Folder
|
161 |
+
Temporary Items
|
162 |
+
.apdisk
|
163 |
+
|
164 |
+
### Python template
|
165 |
+
# Byte-compiled / optimized / DLL files
|
166 |
+
__pycache__/
|
167 |
+
*.py[cod]
|
168 |
+
*$py.class
|
169 |
+
|
170 |
+
# C extensions
|
171 |
+
|
172 |
+
# Distribution / packaging
|
173 |
+
.Python
|
174 |
+
build/
|
175 |
+
develop-eggs/
|
176 |
+
dist/
|
177 |
+
downloads/
|
178 |
+
eggs/
|
179 |
+
.eggs/
|
180 |
+
lib/
|
181 |
+
lib64/
|
182 |
+
parts/
|
183 |
+
sdist/
|
184 |
+
var/
|
185 |
+
wheels/
|
186 |
+
share/python-wheels/
|
187 |
+
*.egg-info/
|
188 |
+
.installed.cfg
|
189 |
+
*.egg
|
190 |
+
MANIFEST
|
191 |
+
|
192 |
+
# PyInstaller
|
193 |
+
# Usually these files are written by a python script from a template
|
194 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
195 |
+
*.manifest
|
196 |
+
*.spec
|
197 |
+
|
198 |
+
# Installer logs
|
199 |
+
pip-log.txt
|
200 |
+
pip-delete-this-directory.txt
|
201 |
+
|
202 |
+
# Unit test / coverage reports
|
203 |
+
htmlcov/
|
204 |
+
.tox/
|
205 |
+
.nox/
|
206 |
+
.coverage
|
207 |
+
.coverage.*
|
208 |
+
.cache
|
209 |
+
nosetests.xml
|
210 |
+
coverage.xml
|
211 |
+
*.cover
|
212 |
+
*.py,cover
|
213 |
+
.hypothesis/
|
214 |
+
.pytest_cache/
|
215 |
+
cover/
|
216 |
+
|
217 |
+
# Translations
|
218 |
+
*.mo
|
219 |
+
*.pot
|
220 |
+
|
221 |
+
# Django stuff:
|
222 |
+
*.log
|
223 |
+
local_settings.py
|
224 |
+
db.sqlite3
|
225 |
+
db.sqlite3-journal
|
226 |
+
|
227 |
+
# Flask stuff:
|
228 |
+
instance/
|
229 |
+
.webassets-cache
|
230 |
+
|
231 |
+
# Scrapy stuff:
|
232 |
+
.scrapy
|
233 |
+
|
234 |
+
# Sphinx documentation
|
235 |
+
docs/_build/
|
236 |
+
|
237 |
+
# PyBuilder
|
238 |
+
.pybuilder/
|
239 |
+
target/
|
240 |
+
|
241 |
+
# Jupyter Notebook
|
242 |
+
.ipynb_checkpoints
|
243 |
+
|
244 |
+
# IPython
|
245 |
+
profile_default/
|
246 |
+
ipython_config.py
|
247 |
+
|
248 |
+
# pyenv
|
249 |
+
# For a library or package, you might want to ignore these files since the code is
|
250 |
+
# intended to run in multiple environments; otherwise, check them in:
|
251 |
+
# .python-version
|
252 |
+
|
253 |
+
# pipenv
|
254 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
255 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
256 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
257 |
+
# install all needed dependencies.
|
258 |
+
#Pipfile.lock
|
259 |
+
|
260 |
+
# poetry
|
261 |
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
262 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
263 |
+
# commonly ignored for libraries.
|
264 |
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
265 |
+
#poetry.lock
|
266 |
+
|
267 |
+
# pdm
|
268 |
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
269 |
+
#pdm.lock
|
270 |
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
271 |
+
# in version control.
|
272 |
+
# https://pdm.fming.dev/#use-with-ide
|
273 |
+
.pdm.toml
|
274 |
+
|
275 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
276 |
+
__pypackages__/
|
277 |
+
|
278 |
+
# Celery stuff
|
279 |
+
celerybeat-schedule
|
280 |
+
celerybeat.pid
|
281 |
+
|
282 |
+
# SageMath parsed files
|
283 |
+
*.sage.py
|
284 |
+
|
285 |
+
# Environments
|
286 |
+
.env
|
287 |
+
.venv
|
288 |
+
env/
|
289 |
+
venv/
|
290 |
+
ENV/
|
291 |
+
env.bak/
|
292 |
+
venv.bak/
|
293 |
+
|
294 |
+
# Spyder project settings
|
295 |
+
.spyderproject
|
296 |
+
.spyproject
|
297 |
+
|
298 |
+
# Rope project settings
|
299 |
+
.ropeproject
|
300 |
+
|
301 |
+
# mkdocs documentation
|
302 |
+
/site
|
303 |
+
|
304 |
+
# mypy
|
305 |
+
.mypy_cache/
|
306 |
+
.dmypy.json
|
307 |
+
dmypy.json
|
308 |
+
|
309 |
+
# Pyre type checker
|
310 |
+
.pyre/
|
311 |
+
|
312 |
+
# pytype static type analyzer
|
313 |
+
.pytype/
|
314 |
+
|
315 |
+
# Cython debug symbols
|
316 |
+
cython_debug/
|
317 |
+
|
318 |
+
# PyCharm
|
319 |
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
320 |
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
321 |
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
322 |
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
323 |
+
#.idea/
|
324 |
+
|
schools/__init__.py
CHANGED
@@ -9,7 +9,7 @@ from base.skill import Skill
|
|
9 |
from schools import bei_ao_jue, gu_feng_jue
|
10 |
from schools import shan_hai_xin_jue, ling_hai_jue, tai_xu_jian_yi, fen_shan_jing
|
11 |
from schools import yi_jin_jing, tian_luo_gui_dao, hua_jian_you
|
12 |
-
from schools import wu_fang, bing_xin_jue, mo_wen
|
13 |
|
14 |
|
15 |
@dataclass
|
@@ -100,6 +100,14 @@ SUPPORT_SCHOOL = {
|
|
100 |
recipe_gains=yi_jin_jing.RECIPE_GAINS, recipes=yi_jin_jing.RECIPES,
|
101 |
gains=yi_jin_jing.GAINS, display_attrs={"spunk": "元气", **MAGICAL_DISPLAY_ATTRS}
|
102 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
10015: School(
|
104 |
school="纯阳", major="身法", kind="外功", attribute=tai_xu_jian_yi.TaiXuJianYi, formation="北斗七星阵",
|
105 |
skills=tai_xu_jian_yi.SKILLS, buffs=tai_xu_jian_yi.BUFFS, prepare=tai_xu_jian_yi.prepare,
|
@@ -188,4 +196,4 @@ SUPPORT_SCHOOL = {
|
|
188 |
recipe_gains=shan_hai_xin_jue.RECIPE_GAINS, recipes=shan_hai_xin_jue.RECIPES,
|
189 |
gains=shan_hai_xin_jue.GAINS, display_attrs={"agility": "身法", **PHYSICAL_DISPLAY_ATTRS}
|
190 |
),
|
191 |
-
}
|
|
|
9 |
from schools import bei_ao_jue, gu_feng_jue
|
10 |
from schools import shan_hai_xin_jue, ling_hai_jue, tai_xu_jian_yi, fen_shan_jing
|
11 |
from schools import yi_jin_jing, tian_luo_gui_dao, hua_jian_you
|
12 |
+
from schools import wu_fang, bing_xin_jue, mo_wen, zi_xia_gong
|
13 |
|
14 |
|
15 |
@dataclass
|
|
|
100 |
recipe_gains=yi_jin_jing.RECIPE_GAINS, recipes=yi_jin_jing.RECIPES,
|
101 |
gains=yi_jin_jing.GAINS, display_attrs={"spunk": "元气", **MAGICAL_DISPLAY_ATTRS}
|
102 |
),
|
103 |
+
10014: School(
|
104 |
+
school="纯阳", major="根骨", kind="内功", attribute=zi_xia_gong.ZiXiaGong, formation="九宫八卦阵",
|
105 |
+
skills=zi_xia_gong.SKILLS, buffs=zi_xia_gong.BUFFS, prepare=zi_xia_gong.prepare,
|
106 |
+
talent_gains=zi_xia_gong.TALENT_GAINS, talents=zi_xia_gong.TALENTS,
|
107 |
+
talent_decoder=zi_xia_gong.TALENT_DECODER, talent_encoder=zi_xia_gong.TALENT_ENCODER,
|
108 |
+
recipe_gains=zi_xia_gong.RECIPE_GAINS, recipes=zi_xia_gong.RECIPES,
|
109 |
+
gains=zi_xia_gong.GAINS, display_attrs={"spirit": "根骨", **MAGICAL_DISPLAY_ATTRS}
|
110 |
+
),
|
111 |
10015: School(
|
112 |
school="纯阳", major="身法", kind="外功", attribute=tai_xu_jian_yi.TaiXuJianYi, formation="北斗七星阵",
|
113 |
skills=tai_xu_jian_yi.SKILLS, buffs=tai_xu_jian_yi.BUFFS, prepare=tai_xu_jian_yi.prepare,
|
|
|
196 |
recipe_gains=shan_hai_xin_jue.RECIPE_GAINS, recipes=shan_hai_xin_jue.RECIPES,
|
197 |
gains=shan_hai_xin_jue.GAINS, display_attrs={"agility": "身法", **PHYSICAL_DISPLAY_ATTRS}
|
198 |
),
|
199 |
+
}
|
schools/zi_xia_gong/__init__.py
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from schools.zi_xia_gong.skills import SKILLS
|
2 |
+
from schools.zi_xia_gong.buffs import BUFFS
|
3 |
+
from schools.zi_xia_gong.talents import TALENT_GAINS, TALENTS, TALENT_DECODER, TALENT_ENCODER
|
4 |
+
from schools.zi_xia_gong.recipes import RECIPE_GAINS, RECIPES
|
5 |
+
from schools.zi_xia_gong.gains import GAINS
|
6 |
+
from schools.zi_xia_gong.attribute import ZiXiaGong
|
7 |
+
|
8 |
+
|
9 |
+
def prepare(self, player_id):
|
10 |
+
self.status[player_id][(17918, 1)] = 1
|
schools/zi_xia_gong/attribute.py
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from base.attribute import MagicalAttribute
|
2 |
+
from base.constant import BINARY_SCALE
|
3 |
+
|
4 |
+
|
5 |
+
class ZiXiaGong(MagicalAttribute):
|
6 |
+
SPIRIT_TO_ATTACK_POWER = 1792 / BINARY_SCALE
|
7 |
+
SPIRIT_TO_CRITICAL_STRIKE = 573 / BINARY_SCALE
|
8 |
+
|
9 |
+
def __init__(self):
|
10 |
+
super().__init__()
|
11 |
+
self.magical_attack_power_base += 3725
|
12 |
+
self.magical_critical_strike_base += 1788
|
13 |
+
self.pve_addition += 51
|
14 |
+
|
15 |
+
@property
|
16 |
+
def extra_magical_attack_power(self):
|
17 |
+
return int(self.spirit * self.SPIRIT_TO_ATTACK_POWER)
|
18 |
+
|
19 |
+
@property
|
20 |
+
def extra_magical_critical_strike(self):
|
21 |
+
return int(self.spirit * self.SPIRIT_TO_CRITICAL_STRIKE)
|
schools/zi_xia_gong/buffs.py
ADDED
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Dict
|
2 |
+
|
3 |
+
from base.buff import Buff
|
4 |
+
from general.buffs import GENERAL_BUFFS
|
5 |
+
|
6 |
+
BUFFS: Dict[int, Buff | dict] = {
|
7 |
+
375: {
|
8 |
+
"buff_name": "破苍穹",
|
9 |
+
"gain_attributes": {
|
10 |
+
"magical_critical_strike_gain": [300, 350, 400, 450, 0, 600, 700, 800, 900, 500, 500, 1000, 500, 1000],
|
11 |
+
"magical_critical_power_gain": [61, 71, 81, 82, 102, 122, 143, 163, 184, 102, 102, 204, 102, 204],
|
12 |
+
"all_shield_ignore": [0] * 12 + [614] * 2
|
13 |
+
}
|
14 |
+
},
|
15 |
+
1439: {
|
16 |
+
"buff_name": "气涌",
|
17 |
+
"activate": False,
|
18 |
+
"gain_attributes": {
|
19 |
+
"magical_critical_strike_gain": 400,
|
20 |
+
"magical_critical_power_gain": 41
|
21 |
+
}
|
22 |
+
},
|
23 |
+
1908: {
|
24 |
+
"buff_name": "会神",
|
25 |
+
"gain_attributes": {
|
26 |
+
"magical_critical_power_gain": 204,
|
27 |
+
}
|
28 |
+
},
|
29 |
+
2757: {
|
30 |
+
"buff_name": "紫气东来",
|
31 |
+
"gain_attributes": {
|
32 |
+
"physical_attack_power_gain": [256, 256, 512, 256],
|
33 |
+
"magical_attack_power_gain": [256, 256, 512, 256],
|
34 |
+
"all_critical_strike_gain": 2500,
|
35 |
+
"all_critical_power_gain": 256
|
36 |
+
}
|
37 |
+
},
|
38 |
+
9966: {
|
39 |
+
"buff_name": "六合独尊加伤害实际表现",
|
40 |
+
"gain_skills": {
|
41 |
+
18670: {
|
42 |
+
"skill_damage_addition": [358, 716, 1075, 1433]
|
43 |
+
}
|
44 |
+
}
|
45 |
+
},
|
46 |
+
# 12550: {
|
47 |
+
# "buff_name": "气剑提升四象轮回伤害",
|
48 |
+
# "gain_skills": {
|
49 |
+
# 896: {
|
50 |
+
# "skill_damage_addition": [40, 81, 122, 163, 204]
|
51 |
+
# }
|
52 |
+
# }
|
53 |
+
# },
|
54 |
+
# 12551: {
|
55 |
+
# "buff_name": "气剑提升两仪化形伤害",
|
56 |
+
# "gain_skills": {
|
57 |
+
# skill_id: {
|
58 |
+
# "skill_damage_addition": [40, 81, 122, 163, 204]
|
59 |
+
# } for skill_id in (3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448)
|
60 |
+
# }
|
61 |
+
# },
|
62 |
+
17918: {
|
63 |
+
"buff_name": "镇山河",
|
64 |
+
"gain_skills": {
|
65 |
+
skill_id: {
|
66 |
+
"skill_pve_addition": 1331
|
67 |
+
} for skill_id in (18649, 18650, 18651, 18652, 18653, 22014)
|
68 |
+
}
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
for buff_id, detail in BUFFS.items():
|
73 |
+
BUFFS[buff_id] = Buff(buff_id)
|
74 |
+
for attr, value in detail.items():
|
75 |
+
setattr(BUFFS[buff_id], attr, value)
|
76 |
+
|
77 |
+
for buff_id, buff in GENERAL_BUFFS.items():
|
78 |
+
BUFFS[buff_id] = buff
|
schools/zi_xia_gong/gains.py
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from base.recipe import damage_addition_recipe, critical_strike_recipe
|
2 |
+
from general.gains.equipment import EQUIPMENT_GAINS, CriticalSet
|
3 |
+
from base.gain import Gain
|
4 |
+
|
5 |
+
GAINS = {
|
6 |
+
# 气涌4%双会套装
|
7 |
+
1914: CriticalSet(1439),
|
8 |
+
# 万世不竭10%套装
|
9 |
+
818: damage_addition_recipe([18649, 18650, 18651, 18652, 18653, 22014], 102),
|
10 |
+
# 无界套装
|
11 |
+
4602: Gain(),
|
12 |
+
# 四象轮回5%橙武
|
13 |
+
1520: damage_addition_recipe([896], 51),
|
14 |
+
# TODO 太极无极5%橙武
|
15 |
+
1521: Gain(),
|
16 |
+
# 四象轮回5%小橙武
|
17 |
+
1136: critical_strike_recipe([896], 500),
|
18 |
+
# 橙武特效
|
19 |
+
2418: Gain(),
|
20 |
+
# 四象轮回·神兵
|
21 |
+
1931: Gain(),
|
22 |
+
# 无界特效1
|
23 |
+
17300: Gain(),
|
24 |
+
# 无界特效2
|
25 |
+
17239: Gain(),
|
26 |
+
**EQUIPMENT_GAINS,
|
27 |
+
}
|
schools/zi_xia_gong/recipes.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Dict, List
|
2 |
+
|
3 |
+
from base.gain import Gain
|
4 |
+
from base.recipe import damage_addition_recipe, critical_strike_recipe
|
5 |
+
|
6 |
+
RECIPE_GAINS: Dict[str, Dict[str, Gain]] = {
|
7 |
+
"两仪化形": {
|
8 |
+
"5%伤害": damage_addition_recipe([3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448], 51),
|
9 |
+
"4%伤害": damage_addition_recipe([3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448], 41),
|
10 |
+
"3%伤害": damage_addition_recipe([3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448], 31),
|
11 |
+
"4%会心": critical_strike_recipe([3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448], 400),
|
12 |
+
"3%会心": critical_strike_recipe([3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448], 300),
|
13 |
+
"2%会心": critical_strike_recipe([3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448], 200),
|
14 |
+
},
|
15 |
+
"四象轮回": {
|
16 |
+
"5%伤害": damage_addition_recipe([896], 51),
|
17 |
+
"4%伤害": damage_addition_recipe([896], 41),
|
18 |
+
"3%伤害": damage_addition_recipe([896], 31),
|
19 |
+
"4%会心": critical_strike_recipe([896], 400),
|
20 |
+
"3%会心": critical_strike_recipe([896], 300),
|
21 |
+
"2%会心": critical_strike_recipe([896], 200),
|
22 |
+
},
|
23 |
+
"万世不竭": {
|
24 |
+
"5%伤害": damage_addition_recipe([18649, 18650, 18651, 18652, 18653, 22014], 51),
|
25 |
+
"4%伤害": damage_addition_recipe([18649, 18650, 18651, 18652, 18653, 22014], 41),
|
26 |
+
"3%伤害": damage_addition_recipe([18649, 18650, 18651, 18652, 18653, 22014], 31),
|
27 |
+
}
|
28 |
+
}
|
29 |
+
|
30 |
+
RECIPES: Dict[str, List[str]] = {
|
31 |
+
"两仪化形": ["5%伤害", "4%伤害", "4%会心", "3%伤害", "3%会心", "2%会心"],
|
32 |
+
"四象轮回": ["5%伤害", "4%伤害", "4%会心", "3%伤害", "3%会心", "2%会心"],
|
33 |
+
"万世不竭": ["5%伤害", "4%伤害", "3%伤害"]
|
34 |
+
}
|
schools/zi_xia_gong/skills.py
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Dict
|
2 |
+
|
3 |
+
from base.skill import Skill, DotSkill, PhysicalDamage, MagicalDamage, MagicalDotDamage
|
4 |
+
from general.skills import GENERAL_SKILLS
|
5 |
+
|
6 |
+
SKILLS: Dict[int, Skill | dict] = {
|
7 |
+
303: {
|
8 |
+
"skill_class": MagicalDamage,
|
9 |
+
"skill_name": "三才化生",
|
10 |
+
"damage_base": 780 * 0.1,
|
11 |
+
"damage_rand": 78 * 0.1,
|
12 |
+
"attack_power_cof": 16
|
13 |
+
},
|
14 |
+
**{
|
15 |
+
skill_id: {
|
16 |
+
"skill_class": MagicalDamage,
|
17 |
+
"skill_name": "五方行尽",
|
18 |
+
"damage_base": [(51 * i / 100) for i in range(1, 11)],
|
19 |
+
"attack_power_cof": [(8 * i * 1.4) for i in range(1, 11)],
|
20 |
+
} for skill_id in (327, 328, 329, 330, 331, 461, 462, 463, 464, 465)
|
21 |
+
},
|
22 |
+
896: {
|
23 |
+
"skill_class": MagicalDamage,
|
24 |
+
"skill_name": "四象轮回",
|
25 |
+
"damage_base": 1260 + 827 - 1907,
|
26 |
+
"damage_rand": 20,
|
27 |
+
"attack_power_cof": 170 * 1.1 * 1.1 * 0.95 * 0.9 * 1.05 * 1.05 * 1.1 * 2.07
|
28 |
+
},
|
29 |
+
**{
|
30 |
+
skill_id: {
|
31 |
+
"skill_class": MagicalDamage,
|
32 |
+
"skill_name": "两仪化形",
|
33 |
+
"damage_base": [(16526 + 10742 * i / 100) for i in range(1, 11)],
|
34 |
+
"damage_rand": [273 * i / 100 for i in range(1, 11)],
|
35 |
+
"attack_power_cof": [(22.5 * i * 0.85 * 1.1 * 1.1 * 1.05 * 0.9 * 1.05 * 1.05 * 1.1 * 1.1 * 1.32) for i in
|
36 |
+
range(1, 11)],
|
37 |
+
} for skill_id in (3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448)
|
38 |
+
},
|
39 |
+
**{
|
40 |
+
skill_id: {
|
41 |
+
"skill_class": MagicalDamage,
|
42 |
+
"skill_name": "两仪化形",
|
43 |
+
"damage_base": 1298 * 2.1,
|
44 |
+
"damage_rand": 1298 * 2.1,
|
45 |
+
"attack_power_cof": [(14 * i * 0.8) for i in range(1, 11)],
|
46 |
+
} for skill_id in (6091, 6092, 6093, 6094, 6095, 6096, 6097, 6098, 6099, 6100)
|
47 |
+
},
|
48 |
+
6424: {
|
49 |
+
"skill_class": MagicalDotDamage,
|
50 |
+
"skill_name": "气竭(DOT)",
|
51 |
+
"damage_base": 10,
|
52 |
+
"attack_power_cof": 229 * 1.7,
|
53 |
+
"interval": 48
|
54 |
+
},
|
55 |
+
18121: {
|
56 |
+
"skill_class": PhysicalDamage,
|
57 |
+
"skill_name": "三柴剑法",
|
58 |
+
"attack_power_cof": 16,
|
59 |
+
"weapon_damage_cof": 1024,
|
60 |
+
"skill_damage_addition": 205
|
61 |
+
},
|
62 |
+
**{
|
63 |
+
skill_id: {
|
64 |
+
"skill_class": MagicalDamage,
|
65 |
+
"skill_name": "飞剑",
|
66 |
+
"damage_base": 50,
|
67 |
+
"attack_power_cof": 40 * 0.75 * 1.15 * 1.1 * 1.45,
|
68 |
+
} for skill_id in (18649, 18650, 18651, 18652, 18653)
|
69 |
+
},
|
70 |
+
18670: {
|
71 |
+
"skill_class": MagicalDamage,
|
72 |
+
"skill_name": "六合独尊",
|
73 |
+
"damage_base": 1038 / 16,
|
74 |
+
"damage_rand": 104 / 2,
|
75 |
+
"attack_power_cof": 82 * 2
|
76 |
+
},
|
77 |
+
22014: {
|
78 |
+
"skill_class": MagicalDamage,
|
79 |
+
"skill_name": "万世不竭",
|
80 |
+
"damage_base": 1150,
|
81 |
+
"damage_rand": 78,
|
82 |
+
"attack_power_cof": 300 * 1.1 * 1.15 * 1.1 * 1.12
|
83 |
+
},
|
84 |
+
25770: {
|
85 |
+
"skill_class": MagicalDamage,
|
86 |
+
"skill_name": "四象轮回·神兵",
|
87 |
+
"damage_base": 20,
|
88 |
+
"damage_rand": 2,
|
89 |
+
"attack_power_cof": 65
|
90 |
+
},
|
91 |
+
32813: {
|
92 |
+
"skill_class": MagicalDamage,
|
93 |
+
"skill_name": "破",
|
94 |
+
"surplus_cof": [
|
95 |
+
1024 * 1024 * (0.06 - 1),
|
96 |
+
1024 * 1024 * (0.30 - 1),
|
97 |
+
1024 * 1024 * (0.83 - 1),
|
98 |
+
1024 * 1024 * (0.60 - 1)
|
99 |
+
]
|
100 |
+
},
|
101 |
+
33592: {
|
102 |
+
"skill_class": DotSkill,
|
103 |
+
"skill_name": "气竭",
|
104 |
+
"bind_skill": 6424,
|
105 |
+
"max_stack": 3,
|
106 |
+
"tick": 10
|
107 |
+
},
|
108 |
+
36439: {
|
109 |
+
"skill_class": MagicalDamage,
|
110 |
+
"skill_name": "颠越苍穹击",
|
111 |
+
"damage_base": 1038,
|
112 |
+
"damage_rand": 104,
|
113 |
+
"attack_power_cof": 155 * 0.9
|
114 |
+
}
|
115 |
+
}
|
116 |
+
|
117 |
+
for skill_id, detail in SKILLS.items():
|
118 |
+
SKILLS[skill_id] = detail.pop('skill_class')(skill_id)
|
119 |
+
for attr, value in detail.items():
|
120 |
+
setattr(SKILLS[skill_id], attr, value)
|
121 |
+
|
122 |
+
for skill_id, skill in GENERAL_SKILLS.items():
|
123 |
+
SKILLS[skill_id] = skill
|
schools/zi_xia_gong/talents.py
ADDED
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Dict
|
2 |
+
|
3 |
+
from base.gain import Gain
|
4 |
+
from base.skill import Skill
|
5 |
+
|
6 |
+
|
7 |
+
class 雾锁(Gain):
|
8 |
+
def add_skills(self, skills: Dict[int, Skill]):
|
9 |
+
skills[896].skill_damage_addition += 102
|
10 |
+
|
11 |
+
def sub_skills(self, skills: Dict[int, Skill]):
|
12 |
+
skills[896].skill_damage_addition -= 102
|
13 |
+
|
14 |
+
|
15 |
+
class 白虹(Gain):
|
16 |
+
def add_skills(self, skills: Dict[int, Skill]):
|
17 |
+
skills[896].skill_critical_strike += 1000
|
18 |
+
skills[896].skill_critical_power += 102
|
19 |
+
|
20 |
+
def sub_skills(self, skills: Dict[int, Skill]):
|
21 |
+
skills[896].skill_critical_strike -= 1000
|
22 |
+
skills[896].skill_critical_power -= 102
|
23 |
+
|
24 |
+
|
25 |
+
class 霜锋(Gain):
|
26 |
+
def add_skills(self, skills: Dict[int, Skill]):
|
27 |
+
for skill_id in (3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448):
|
28 |
+
skills[skill_id].skill_damage_addition += 102
|
29 |
+
skills[18670].skill_damage_addition += 102
|
30 |
+
|
31 |
+
def sub_skills(self, skills: Dict[int, Skill]):
|
32 |
+
for skill_id in (3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448):
|
33 |
+
skills[skill_id].skill_damage_addition -= 102
|
34 |
+
skills[18670].skill_damage_addition -= 102
|
35 |
+
|
36 |
+
|
37 |
+
class 跬步(Gain):
|
38 |
+
def add_skills(self, skills: Dict[int, Skill]):
|
39 |
+
skills[896].skill_damage_addition += 204
|
40 |
+
for skill_id in (3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448):
|
41 |
+
skills[skill_id].skill_damage_addition += 204
|
42 |
+
|
43 |
+
def sub_skills(self, skills: Dict[int, Skill]):
|
44 |
+
skills[896].skill_damage_addition -= 204
|
45 |
+
for skill_id in (3439, 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, 3448):
|
46 |
+
skills[skill_id].skill_damage_addition -= 204
|
47 |
+
|
48 |
+
|
49 |
+
class 重光(Gain):
|
50 |
+
def add_skills(self, skills: Dict[int, Skill]):
|
51 |
+
for i, skill_id in enumerate([18649, 18650, 18651, 18652, 18653]):
|
52 |
+
skills[skill_id].skill_damage_addition += int(i * 0.15 * 1024)
|
53 |
+
|
54 |
+
def sub_skills(self, skills: Dict[int, Skill]):
|
55 |
+
for i, skill_id in enumerate([18649, 18650, 18651, 18652, 18653]):
|
56 |
+
skills[skill_id].skill_damage_addition -= int(i * 0.15 * 1024)
|
57 |
+
|
58 |
+
|
59 |
+
TALENT_GAINS: Dict[int, Gain] = {
|
60 |
+
5840: 雾锁("雾锁"),
|
61 |
+
5827: 白虹("白虹"),
|
62 |
+
5823: Gain("心固"),
|
63 |
+
5828: 霜锋("霜锋"),
|
64 |
+
357: Gain("化三清"),
|
65 |
+
5846: Gain("无形"),
|
66 |
+
23614: Gain("归元"),
|
67 |
+
5819: Gain("同尘"),
|
68 |
+
18695: 跬步("跬步"),
|
69 |
+
32411: Gain("正气"),
|
70 |
+
14834: Gain("抱阳"),
|
71 |
+
18679: Gain("浮生"),
|
72 |
+
24945: Gain("破势"),
|
73 |
+
18669: 重光("重光"),
|
74 |
+
14613: Gain("固本"),
|
75 |
+
}
|
76 |
+
|
77 |
+
TALENTS = [
|
78 |
+
[5840, 5827],
|
79 |
+
[5823, 5828],
|
80 |
+
[357, 5846],
|
81 |
+
[23614],
|
82 |
+
[5819],
|
83 |
+
[18695],
|
84 |
+
[32411],
|
85 |
+
[14834],
|
86 |
+
[18679],
|
87 |
+
[24945],
|
88 |
+
[18669],
|
89 |
+
[14613]
|
90 |
+
]
|
91 |
+
TALENT_DECODER = {talent_id: talent.gain_name for talent_id, talent in TALENT_GAINS.items()}
|
92 |
+
TALENT_ENCODER = {v: k for k, v in TALENT_DECODER.items()}
|
utils/parser.py
CHANGED
@@ -4,17 +4,19 @@ from base.constant import FRAME_PER_SECOND
|
|
4 |
from schools import *
|
5 |
from utils.lua import parse
|
6 |
|
7 |
-
FRAME_TYPE, PLAYER_ID_TYPE, PLAYER_NAME_TYPE,
|
8 |
CASTER_ID_TYPE = PLAYER_ID_TYPE | PET_ID_TYPE
|
9 |
SKILL_ID_TYPE, SKILL_LEVEL_TYPE, SKILL_STACK_TYPE, SKILL_CRITICAL_TYPE = int, int, int, bool
|
|
|
10 |
SKILL_TYPE = Tuple[SKILL_ID_TYPE, SKILL_LEVEL_TYPE, SKILL_STACK_TYPE]
|
11 |
BUFF_ID_TYPE, BUFF_LEVEL_TYPE, BUFF_STACK_TYPE = int, int, int
|
12 |
BUFF_TYPE = Tuple[BUFF_ID_TYPE, BUFF_LEVEL_TYPE]
|
|
|
13 |
|
14 |
-
|
15 |
-
|
16 |
-
TIMELINE_TYPE = Tuple[FRAME_TYPE, SKILL_CRITICAL_TYPE]
|
17 |
-
SUB_RECORD_TYPE = Dict[
|
18 |
RECORD_TYPE = Dict[SKILL_TYPE, SUB_RECORD_TYPE]
|
19 |
|
20 |
LABEL_MAPPING = {
|
@@ -33,33 +35,30 @@ LABEL_MAPPING = {
|
|
33 |
}
|
34 |
EMBED_MAPPING: Dict[tuple, int] = {(5, 24449 - i): 8 - i for i in range(8)}
|
35 |
|
|
|
|
|
36 |
|
37 |
class Parser:
|
38 |
current_player: PLAYER_ID_TYPE
|
39 |
current_caster: CASTER_ID_TYPE
|
40 |
-
current_target: TARGET_ID_TYPE
|
41 |
-
current_skill: SKILL_ID_TYPE
|
42 |
current_frame: FRAME_TYPE
|
|
|
43 |
|
44 |
-
id2name: Dict[PLAYER_ID_TYPE
|
45 |
-
name2id: Dict[PLAYER_NAME_TYPE, PLAYER_ID_TYPE
|
46 |
pets: Dict[PET_ID_TYPE, PLAYER_ID_TYPE]
|
47 |
-
records: Dict[PLAYER_ID_TYPE,
|
48 |
-
|
49 |
-
shift_buffs: Dict[FRAME_TYPE, Dict[PLAYER_ID_TYPE, Dict[BUFF_TYPE, BUFF_STACK_TYPE]]]
|
50 |
-
hidden_buffs: Dict[TARGET_ID_TYPE, Dict[PLAYER_ID_TYPE, Dict[BUFF_TYPE, FRAME_TYPE]]]
|
51 |
|
52 |
-
|
53 |
-
|
|
|
54 |
|
55 |
-
stacks: Dict[
|
56 |
-
ticks: Dict[
|
57 |
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
last_dot: Dict[TARGET_ID_TYPE, Dict[PLAYER_ID_TYPE, Dict[SKILL_ID_TYPE, Tuple[SKILL_TYPE, Tuple[tuple, tuple]]]]]
|
62 |
-
next_dot: Dict[TARGET_ID_TYPE, Dict[PLAYER_ID_TYPE, Dict[SKILL_ID_TYPE, int]]]
|
63 |
|
64 |
start_frame: FRAME_TYPE
|
65 |
end_frame: FRAME_TYPE
|
@@ -67,59 +66,43 @@ class Parser:
|
|
67 |
select_talents: Dict[PLAYER_ID_TYPE, List[int]]
|
68 |
select_equipments: Dict[PLAYER_ID_TYPE, Dict[int, Dict[str, int | list]]]
|
69 |
|
70 |
-
|
71 |
-
targets: Dict[PLAYER_ID_TYPE, List[TARGET_ID_TYPE]]
|
72 |
|
73 |
@property
|
74 |
def current_school(self):
|
75 |
-
return self.
|
76 |
-
|
77 |
-
@property
|
78 |
-
def current_targets(self):
|
79 |
-
return self.targets[self.current_player]
|
80 |
|
81 |
@property
|
82 |
def current_records(self):
|
83 |
-
return self.records[self.current_player]
|
84 |
|
85 |
@property
|
86 |
def current_hidden_buffs(self):
|
87 |
-
return self.hidden_buffs[self.
|
88 |
-
|
89 |
-
@property
|
90 |
-
def current_player_buffs(self):
|
91 |
-
return self.player_buffs[self.current_player]
|
92 |
|
93 |
@property
|
94 |
-
def
|
95 |
-
return self.
|
96 |
|
97 |
@property
|
98 |
def current_snapshot(self):
|
99 |
-
|
100 |
-
return self.pet_snapshot[self.current_caster]
|
101 |
-
else:
|
102 |
-
return self.dot_snapshot[self.current_target][self.current_player].get(self.current_skill, {})
|
103 |
-
|
104 |
-
@property
|
105 |
-
def current_dot_snapshot(self):
|
106 |
-
return self.dot_snapshot[self.current_target][self.current_player]
|
107 |
|
108 |
@property
|
109 |
def current_stacks(self):
|
110 |
-
return self.stacks[self.
|
111 |
|
112 |
@property
|
113 |
def current_ticks(self):
|
114 |
-
return self.ticks[self.
|
115 |
|
116 |
@property
|
117 |
def current_last_dot(self):
|
118 |
-
return self.last_dot[self.
|
119 |
|
120 |
@property
|
121 |
def current_next_dot(self):
|
122 |
-
return self.next_dot[self.
|
123 |
|
124 |
@property
|
125 |
def duration(self):
|
@@ -128,33 +111,29 @@ class Parser:
|
|
128 |
def reset(self):
|
129 |
self.current_frame = 0
|
130 |
|
|
|
|
|
131 |
self.id2name = {}
|
132 |
self.name2id = {}
|
133 |
self.pets = {}
|
134 |
|
135 |
-
self.records = defaultdict(lambda: defaultdict(lambda: defaultdict(
|
136 |
-
|
137 |
-
self.hidden_buffs = defaultdict(lambda: defaultdict(dict))
|
138 |
-
self.shift_buffs = defaultdict(lambda: defaultdict(dict))
|
139 |
-
|
140 |
-
self.player_buffs = defaultdict(dict)
|
141 |
-
self.target_buffs = defaultdict(lambda: defaultdict(dict))
|
142 |
|
143 |
-
self.
|
144 |
-
self.
|
|
|
145 |
|
146 |
-
self.
|
147 |
-
self.
|
148 |
-
self.
|
149 |
-
self.
|
|
|
150 |
|
151 |
self.start_frame = 0
|
152 |
|
153 |
self.select_talents = {}
|
154 |
self.select_equipments = {}
|
155 |
-
|
156 |
-
self.players = {}
|
157 |
-
self.targets = defaultdict(list)
|
158 |
|
159 |
@staticmethod
|
160 |
def parse_equipments(detail):
|
@@ -176,90 +155,70 @@ class Parser:
|
|
176 |
def parse_talents(detail):
|
177 |
return [row[1] for row in detail]
|
178 |
|
179 |
-
def
|
180 |
detail = row.strip("{}").split(",")
|
181 |
player_id, school_id = int(detail[0]), int(detail[3])
|
182 |
if player_id in self.id2name or school_id not in SUPPORT_SCHOOL:
|
183 |
return
|
184 |
-
|
185 |
-
if isinstance(detail := parse(row), list) and (school := SUPPORT_SCHOOL.get(detail[3])):
|
186 |
player_name = detail[1]
|
187 |
self.id2name[player_id] = player_name
|
188 |
self.name2id[player_name] = player_id
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
def parse_npc(self, row):
|
196 |
-
detail = row.strip("{}").split(",")
|
197 |
-
npc_id, player_id = int(detail[0]), int(detail[3])
|
198 |
-
if npc_id in self.id2name:
|
199 |
-
return
|
200 |
-
|
201 |
-
npc_name = detail[1]
|
202 |
-
self.id2name[npc_id] = npc_name
|
203 |
-
self.name2id[npc_name] = npc_id
|
204 |
-
if player_id:
|
205 |
-
self.pets[npc_id] = player_id
|
206 |
-
|
207 |
-
def parse_pet(self, row):
|
208 |
-
detail = row.strip("{}").split(",")
|
209 |
-
pet_id, player_id = int(detail[0]), int(detail[3])
|
210 |
-
if pet_id in self.pets:
|
211 |
-
self.pet_snapshot[pet_id] = self.player_buffs[player_id].copy()
|
212 |
|
213 |
def parse_shift_buff(self, row):
|
214 |
detail = row.strip("{}").split(",")
|
215 |
player_id = int(detail[0])
|
216 |
-
if player_id not in self.
|
217 |
return
|
218 |
-
|
219 |
buff_id, buff_stack, buff_level = int(detail[4]), int(detail[5]), int(detail[8])
|
220 |
-
if buff_id not in self.
|
221 |
return
|
222 |
|
223 |
-
frame_shift = self.
|
224 |
if frame_shift:
|
225 |
-
self.
|
226 |
|
227 |
def parse_shift_status(self):
|
228 |
-
for frame in list(self.
|
229 |
if frame > self.current_frame:
|
230 |
break
|
231 |
-
for player_id,
|
232 |
-
for buff, buff_stack in
|
233 |
if buff_stack:
|
234 |
-
self.
|
235 |
else:
|
236 |
-
self.
|
237 |
|
238 |
def parse_hidden_buffs(self):
|
239 |
-
for
|
240 |
-
for
|
241 |
-
|
242 |
-
|
243 |
-
self.target_buffs[target_id][player_id].pop(buff, None)
|
244 |
|
245 |
-
def
|
246 |
detail = row.strip("{}").split(",")
|
247 |
player_id = int(detail[0])
|
248 |
-
if player_id not in self.
|
249 |
return
|
250 |
|
251 |
buff_id, buff_stack, buff_level = int(detail[4]), int(detail[5]), int(detail[8])
|
252 |
-
if buff_id not in self.
|
253 |
return
|
254 |
|
255 |
-
frame_shift = self.
|
256 |
if frame_shift:
|
257 |
return
|
258 |
|
259 |
if buff_stack:
|
260 |
-
self.
|
261 |
else:
|
262 |
-
self.
|
263 |
|
264 |
def parse_skill(self, row):
|
265 |
detail = row.strip("{}").split(",")
|
@@ -269,56 +228,51 @@ class Parser:
|
|
269 |
else:
|
270 |
player_id = caster_id
|
271 |
|
272 |
-
if player_id not in self.
|
273 |
return
|
274 |
|
275 |
react, skill_id, skill_level, critical = int(detail[2]), int(detail[4]), int(detail[5]), detail[6] == "true"
|
276 |
-
if react or skill_id not in self.
|
277 |
return
|
278 |
|
279 |
if not self.start_frame:
|
280 |
-
self.start_frame = self.current_frame
|
281 |
|
282 |
self.current_player = player_id
|
283 |
self.current_caster = caster_id
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
|
|
|
|
|
|
|
|
|
|
293 |
current_status = []
|
294 |
-
for (buff_id, buff_level), buff_stack in self.
|
295 |
buff = self.current_school.buffs[buff_id]
|
296 |
if buff.gain_attributes:
|
297 |
current_status.append((buff_id, buff_level, buff_stack))
|
298 |
elif buff.gain_skills and skill_id in buff.gain_skills:
|
299 |
current_status.append((buff_id, buff_level, buff_stack))
|
300 |
|
301 |
-
self.current_skill = skill_id
|
302 |
snapshot_status = []
|
303 |
-
for (buff_id, buff_level), buff_stack in self.current_snapshot.items():
|
304 |
buff = self.current_school.buffs[buff_id]
|
305 |
if buff.gain_attributes:
|
306 |
snapshot_status.append((buff_id, buff_level, buff_stack))
|
307 |
elif buff.gain_skills and skill_id in buff.gain_skills:
|
308 |
snapshot_status.append((buff_id, buff_level, buff_stack))
|
309 |
|
310 |
-
|
311 |
-
for (buff_id, buff_level), buff_stack in self.current_target_buffs.items():
|
312 |
-
buff = self.current_school.buffs[buff_id]
|
313 |
-
if buff.gain_attributes:
|
314 |
-
target_status.append((buff_id, buff_level, buff_stack))
|
315 |
-
elif buff.gain_skills and skill_id in buff.gain_skills:
|
316 |
-
target_status.append((buff_id, buff_level, buff_stack))
|
317 |
-
|
318 |
-
return tuple(current_status), tuple(snapshot_status), tuple(target_status)
|
319 |
|
320 |
def __call__(self, file_name):
|
321 |
-
self.file_name = file_name
|
322 |
self.reset()
|
323 |
lines = open(file_name).readlines()
|
324 |
rows = []
|
@@ -326,11 +280,9 @@ class Parser:
|
|
326 |
row = line.split("\t")
|
327 |
rows.append(row)
|
328 |
if row[4] == "4":
|
329 |
-
self.
|
330 |
-
elif row[4] == "8":
|
331 |
-
self.parse_npc(row[-1])
|
332 |
|
333 |
-
for player_id, school in self.
|
334 |
school.prepare(self, player_id)
|
335 |
for talent_id in self.select_talents[player_id]:
|
336 |
school.talent_gains[talent_id].add_skills(school.skills)
|
@@ -347,24 +299,16 @@ class Parser:
|
|
347 |
if row[4] == "8":
|
348 |
self.parse_pet(row[-1])
|
349 |
elif row[4] == "13":
|
350 |
-
self.
|
351 |
elif row[4] == "21":
|
352 |
self.parse_skill(row[-1])
|
353 |
|
354 |
self.end_frame = self.current_frame
|
355 |
|
356 |
-
for player_id, school in self.
|
357 |
for talent_id in self.select_talents[player_id]:
|
358 |
school.talent_gains[talent_id].sub_skills(school.skills)
|
359 |
|
360 |
-
for player_id in self.records:
|
361 |
-
player_record = defaultdict(lambda: defaultdict(list))
|
362 |
-
for target_id, records in self.records[player_id].items():
|
363 |
-
for skill_tuple, status in records.items():
|
364 |
-
for status_tuple, timeline in status.items():
|
365 |
-
player_record[skill_tuple][status_tuple] += timeline
|
366 |
-
self.records[player_id][0] = player_record
|
367 |
-
|
368 |
|
369 |
if __name__ == '__main__':
|
370 |
parser = Parser()
|
|
|
4 |
from schools import *
|
5 |
from utils.lua import parse
|
6 |
|
7 |
+
FRAME_TYPE, PLAYER_ID_TYPE, PLAYER_NAME_TYPE, PET_ID_TYPE = int, int, int, int
|
8 |
CASTER_ID_TYPE = PLAYER_ID_TYPE | PET_ID_TYPE
|
9 |
SKILL_ID_TYPE, SKILL_LEVEL_TYPE, SKILL_STACK_TYPE, SKILL_CRITICAL_TYPE = int, int, int, bool
|
10 |
+
SKILL_BUFFER_TYPE = Tuple[SKILL_ID_TYPE, SKILL_LEVEL_TYPE, SKILL_CRITICAL_TYPE]
|
11 |
SKILL_TYPE = Tuple[SKILL_ID_TYPE, SKILL_LEVEL_TYPE, SKILL_STACK_TYPE]
|
12 |
BUFF_ID_TYPE, BUFF_LEVEL_TYPE, BUFF_STACK_TYPE = int, int, int
|
13 |
BUFF_TYPE = Tuple[BUFF_ID_TYPE, BUFF_LEVEL_TYPE]
|
14 |
+
STATUS_TYPE = Tuple[BUFF_ID_TYPE, BUFF_LEVEL_TYPE, BUFF_STACK_TYPE]
|
15 |
|
16 |
+
SNAPSHOT_TYPE = Dict[SKILL_ID_TYPE | PET_ID_TYPE, Dict[BUFF_TYPE, BUFF_STACK_TYPE]]
|
17 |
+
|
18 |
+
TIMELINE_TYPE = List[Tuple[FRAME_TYPE, SKILL_CRITICAL_TYPE]]
|
19 |
+
SUB_RECORD_TYPE = Dict[Tuple[tuple, tuple], TIMELINE_TYPE]
|
20 |
RECORD_TYPE = Dict[SKILL_TYPE, SUB_RECORD_TYPE]
|
21 |
|
22 |
LABEL_MAPPING = {
|
|
|
35 |
}
|
36 |
EMBED_MAPPING: Dict[tuple, int] = {(5, 24449 - i): 8 - i for i in range(8)}
|
37 |
|
38 |
+
BUFFER_DELAY = 0
|
39 |
+
|
40 |
|
41 |
class Parser:
|
42 |
current_player: PLAYER_ID_TYPE
|
43 |
current_caster: CASTER_ID_TYPE
|
|
|
|
|
44 |
current_frame: FRAME_TYPE
|
45 |
+
frames: List[FRAME_TYPE]
|
46 |
|
47 |
+
id2name: Dict[PLAYER_ID_TYPE, PLAYER_NAME_TYPE]
|
48 |
+
name2id: Dict[PLAYER_NAME_TYPE, PLAYER_ID_TYPE]
|
49 |
pets: Dict[PET_ID_TYPE, PLAYER_ID_TYPE]
|
50 |
+
records: Dict[PLAYER_ID_TYPE, RECORD_TYPE]
|
|
|
|
|
|
|
51 |
|
52 |
+
hidden_buffs: Dict[PLAYER_ID_TYPE, Dict[BUFF_TYPE, FRAME_TYPE]]
|
53 |
+
shift_status: Dict[FRAME_TYPE, Dict[PLAYER_ID_TYPE, Dict[BUFF_TYPE, BUFF_STACK_TYPE]]]
|
54 |
+
status: Dict[PLAYER_ID_TYPE, Dict[BUFF_TYPE, BUFF_STACK_TYPE]]
|
55 |
|
56 |
+
stacks: Dict[PLAYER_ID_TYPE, Dict[SKILL_ID_TYPE, int]]
|
57 |
+
ticks: Dict[PLAYER_ID_TYPE, Dict[SKILL_ID_TYPE, int]]
|
58 |
|
59 |
+
snapshot: Dict[PLAYER_ID_TYPE, SNAPSHOT_TYPE]
|
60 |
+
last_dot: Dict[PLAYER_ID_TYPE, Dict[SKILL_ID_TYPE, Tuple[SKILL_TYPE, Tuple[tuple, tuple]]]]
|
61 |
+
next_dot: Dict[PLAYER_ID_TYPE, Dict[SKILL_ID_TYPE, int]]
|
|
|
|
|
62 |
|
63 |
start_frame: FRAME_TYPE
|
64 |
end_frame: FRAME_TYPE
|
|
|
66 |
select_talents: Dict[PLAYER_ID_TYPE, List[int]]
|
67 |
select_equipments: Dict[PLAYER_ID_TYPE, Dict[int, Dict[str, int | list]]]
|
68 |
|
69 |
+
school: Dict[PLAYER_ID_TYPE, School]
|
|
|
70 |
|
71 |
@property
|
72 |
def current_school(self):
|
73 |
+
return self.school[self.current_player]
|
|
|
|
|
|
|
|
|
74 |
|
75 |
@property
|
76 |
def current_records(self):
|
77 |
+
return self.records[self.current_player]
|
78 |
|
79 |
@property
|
80 |
def current_hidden_buffs(self):
|
81 |
+
return self.hidden_buffs[self.current_player]
|
|
|
|
|
|
|
|
|
82 |
|
83 |
@property
|
84 |
+
def current_status(self):
|
85 |
+
return self.status[self.current_player]
|
86 |
|
87 |
@property
|
88 |
def current_snapshot(self):
|
89 |
+
return self.snapshot[self.current_player]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
|
91 |
@property
|
92 |
def current_stacks(self):
|
93 |
+
return self.stacks[self.current_player]
|
94 |
|
95 |
@property
|
96 |
def current_ticks(self):
|
97 |
+
return self.ticks[self.current_player]
|
98 |
|
99 |
@property
|
100 |
def current_last_dot(self):
|
101 |
+
return self.last_dot[self.current_player]
|
102 |
|
103 |
@property
|
104 |
def current_next_dot(self):
|
105 |
+
return self.next_dot[self.current_player]
|
106 |
|
107 |
@property
|
108 |
def duration(self):
|
|
|
111 |
def reset(self):
|
112 |
self.current_frame = 0
|
113 |
|
114 |
+
self.frames = []
|
115 |
+
|
116 |
self.id2name = {}
|
117 |
self.name2id = {}
|
118 |
self.pets = {}
|
119 |
|
120 |
+
self.records = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
|
122 |
+
self.hidden_buffs = defaultdict(dict)
|
123 |
+
self.shift_status = defaultdict(lambda: defaultdict(dict))
|
124 |
+
self.status = defaultdict(lambda: defaultdict(int))
|
125 |
|
126 |
+
self.stacks = defaultdict(lambda: defaultdict(lambda: 1))
|
127 |
+
self.ticks = defaultdict(lambda: defaultdict(lambda: 0))
|
128 |
+
self.snapshot = defaultdict(dict)
|
129 |
+
self.last_dot = defaultdict(dict)
|
130 |
+
self.next_dot = defaultdict(dict)
|
131 |
|
132 |
self.start_frame = 0
|
133 |
|
134 |
self.select_talents = {}
|
135 |
self.select_equipments = {}
|
136 |
+
self.school = {}
|
|
|
|
|
137 |
|
138 |
@staticmethod
|
139 |
def parse_equipments(detail):
|
|
|
155 |
def parse_talents(detail):
|
156 |
return [row[1] for row in detail]
|
157 |
|
158 |
+
def parse_info(self, row):
|
159 |
detail = row.strip("{}").split(",")
|
160 |
player_id, school_id = int(detail[0]), int(detail[3])
|
161 |
if player_id in self.id2name or school_id not in SUPPORT_SCHOOL:
|
162 |
return
|
163 |
+
if isinstance(detail := parse(row), list):
|
|
|
164 |
player_name = detail[1]
|
165 |
self.id2name[player_id] = player_name
|
166 |
self.name2id[player_name] = player_id
|
167 |
+
if school := SUPPORT_SCHOOL.get(detail[3]):
|
168 |
+
self.select_equipments[player_id] = self.parse_equipments(detail[5])
|
169 |
+
self.select_talents[player_id] = self.parse_talents(detail[6])
|
170 |
+
if any(talent not in school.talent_gains for talent in self.select_talents[player_id]):
|
171 |
+
return
|
172 |
+
self.school[player_id] = school
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
|
174 |
def parse_shift_buff(self, row):
|
175 |
detail = row.strip("{}").split(",")
|
176 |
player_id = int(detail[0])
|
177 |
+
if player_id not in self.school:
|
178 |
return
|
|
|
179 |
buff_id, buff_stack, buff_level = int(detail[4]), int(detail[5]), int(detail[8])
|
180 |
+
if buff_id not in self.school[player_id].buffs:
|
181 |
return
|
182 |
|
183 |
+
frame_shift = self.school[player_id].buffs[buff_id].frame_shift
|
184 |
if frame_shift:
|
185 |
+
self.shift_status[self.current_frame + frame_shift][player_id][(buff_id, buff_level)] = buff_stack
|
186 |
|
187 |
def parse_shift_status(self):
|
188 |
+
for frame in list(self.shift_status):
|
189 |
if frame > self.current_frame:
|
190 |
break
|
191 |
+
for player_id, status_buffer in self.shift_status.pop(frame).items():
|
192 |
+
for buff, buff_stack in status_buffer.items():
|
193 |
if buff_stack:
|
194 |
+
self.status[player_id][buff] = buff_stack
|
195 |
else:
|
196 |
+
self.status[player_id].pop(buff, None)
|
197 |
|
198 |
def parse_hidden_buffs(self):
|
199 |
+
for player_id, hidden_buffs in self.hidden_buffs.items():
|
200 |
+
for buff, end_frame in hidden_buffs.items():
|
201 |
+
if end_frame < self.current_frame:
|
202 |
+
self.status[player_id].pop(buff, None)
|
|
|
203 |
|
204 |
+
def parse_status(self, row):
|
205 |
detail = row.strip("{}").split(",")
|
206 |
player_id = int(detail[0])
|
207 |
+
if player_id not in self.school:
|
208 |
return
|
209 |
|
210 |
buff_id, buff_stack, buff_level = int(detail[4]), int(detail[5]), int(detail[8])
|
211 |
+
if buff_id not in self.school[player_id].buffs:
|
212 |
return
|
213 |
|
214 |
+
frame_shift = self.school[player_id].buffs[buff_id].frame_shift
|
215 |
if frame_shift:
|
216 |
return
|
217 |
|
218 |
if buff_stack:
|
219 |
+
self.status[player_id][(buff_id, buff_level)] = buff_stack
|
220 |
else:
|
221 |
+
self.status[player_id].pop((buff_id, buff_level), None)
|
222 |
|
223 |
def parse_skill(self, row):
|
224 |
detail = row.strip("{}").split(",")
|
|
|
228 |
else:
|
229 |
player_id = caster_id
|
230 |
|
231 |
+
if player_id not in self.school:
|
232 |
return
|
233 |
|
234 |
react, skill_id, skill_level, critical = int(detail[2]), int(detail[4]), int(detail[5]), detail[6] == "true"
|
235 |
+
if react or skill_id not in self.school[player_id].skills:
|
236 |
return
|
237 |
|
238 |
if not self.start_frame:
|
239 |
+
self.start_frame = self.current_frame - 1
|
240 |
|
241 |
self.current_player = player_id
|
242 |
self.current_caster = caster_id
|
243 |
+
skill = self.school[player_id].skills[skill_id]
|
244 |
+
skill.record(skill_level, critical, self)
|
245 |
+
|
246 |
+
def parse_pet(self, row):
|
247 |
+
detail = row.strip("{}").split(",")
|
248 |
+
pet_id, player_id = int(detail[0]), int(detail[3])
|
249 |
+
if player_id in self.school:
|
250 |
+
self.pets[pet_id] = player_id
|
251 |
+
self.snapshot[player_id][pet_id] = self.status[player_id].copy()
|
252 |
+
|
253 |
+
def available_status(self, skill_id, snapshot_id=None):
|
254 |
+
if not snapshot_id:
|
255 |
+
snapshot_id = skill_id
|
256 |
+
|
257 |
current_status = []
|
258 |
+
for (buff_id, buff_level), buff_stack in self.current_status.items():
|
259 |
buff = self.current_school.buffs[buff_id]
|
260 |
if buff.gain_attributes:
|
261 |
current_status.append((buff_id, buff_level, buff_stack))
|
262 |
elif buff.gain_skills and skill_id in buff.gain_skills:
|
263 |
current_status.append((buff_id, buff_level, buff_stack))
|
264 |
|
|
|
265 |
snapshot_status = []
|
266 |
+
for (buff_id, buff_level), buff_stack in self.current_snapshot.get(snapshot_id, {}).items():
|
267 |
buff = self.current_school.buffs[buff_id]
|
268 |
if buff.gain_attributes:
|
269 |
snapshot_status.append((buff_id, buff_level, buff_stack))
|
270 |
elif buff.gain_skills and skill_id in buff.gain_skills:
|
271 |
snapshot_status.append((buff_id, buff_level, buff_stack))
|
272 |
|
273 |
+
return tuple(current_status), tuple(snapshot_status)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
274 |
|
275 |
def __call__(self, file_name):
|
|
|
276 |
self.reset()
|
277 |
lines = open(file_name).readlines()
|
278 |
rows = []
|
|
|
280 |
row = line.split("\t")
|
281 |
rows.append(row)
|
282 |
if row[4] == "4":
|
283 |
+
self.parse_info(row[-1])
|
|
|
|
|
284 |
|
285 |
+
for player_id, school in self.school.items():
|
286 |
school.prepare(self, player_id)
|
287 |
for talent_id in self.select_talents[player_id]:
|
288 |
school.talent_gains[talent_id].add_skills(school.skills)
|
|
|
299 |
if row[4] == "8":
|
300 |
self.parse_pet(row[-1])
|
301 |
elif row[4] == "13":
|
302 |
+
self.parse_status(row[-1])
|
303 |
elif row[4] == "21":
|
304 |
self.parse_skill(row[-1])
|
305 |
|
306 |
self.end_frame = self.current_frame
|
307 |
|
308 |
+
for player_id, school in self.school.items():
|
309 |
for talent_id in self.select_talents[player_id]:
|
310 |
school.talent_gains[talent_id].sub_skills(school.skills)
|
311 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
312 |
|
313 |
if __name__ == '__main__':
|
314 |
parser = Parser()
|