Fix behavior for the #LEVELHOLD
command (#54)
Previously, I had translated the existing levelhold behavior in WHMHammer's tja parsing code, assuming that it would produce the correct behavior for fumen charts. However, that is not the case -- the behavior is completely wrong. So, this PR takes out all the old `flag_levelhold` behavior and instead properly sets the `branch_info` bytes whenever #LEVELHOLD is present on a branch. This PR also prepares `shoto9.tja` for further testing, but I'm leaving that for later... Fixes #52.
This commit is contained in:
parent
59046c22ec
commit
c0442f3721
@ -82,8 +82,8 @@ If there is an unsupported feature that you would like support for, please make
|
||||
| `#DELAY` | `✅` | `❌` | See [#27](https://github.com/Fluto/TakoTako/issues/27) |
|
||||
| `#BRANCHSTART`, `#BRANCHEND` | `✅` | `✅` | |
|
||||
| `#N`, `#E`, `#M` | `✅` | `✅` | |
|
||||
| `#SECTION` | `⚠️` | `❌` | See [#52](https://github.com/vivaria/tja2fumen/issues/52), [#27](https://github.com/Fluto/TakoTako/issues/27) |
|
||||
| `#LEVELHOLD` | `⚠️` | `❌` | See [#52](https://github.com/vivaria/tja2fumen/issues/52) |
|
||||
| `#SECTION` | `⚠️` | `❌` | See [#53](https://github.com/vivaria/tja2fumen/issues/53), [#27](https://github.com/Fluto/TakoTako/issues/27) |
|
||||
| `#LEVELHOLD` | `✅` | `❌` | |
|
||||
| `#BMSCROLL`, `#LYRIC`,<br>`#DIRECTION`, etc. | `⚪️` | `❌` | Other simulator-specific chart commands are currently ignored. |
|
||||
|
||||
## Reporting bugs
|
||||
|
@ -52,6 +52,8 @@ def process_tja_commands(tja):
|
||||
measure_tja_processed.branch_start = data.value
|
||||
elif data.name == 'section':
|
||||
measure_tja_processed.section = data.value
|
||||
elif data.name == 'levelhold':
|
||||
measure_tja_processed.levelhold = True
|
||||
elif data.name == 'barline':
|
||||
current_barline = bool(int(data.value))
|
||||
measure_tja_processed.barline = current_barline
|
||||
@ -181,6 +183,7 @@ def convert_tja_to_fumen(tja):
|
||||
branch_points_total = 0
|
||||
branch_points_measure = 0
|
||||
current_drumroll = None
|
||||
current_levelhold = False
|
||||
branch_conditions = []
|
||||
course_balloons = tja.balloon.copy()
|
||||
|
||||
@ -226,10 +229,14 @@ def convert_tja_to_fumen(tja):
|
||||
measure_fumen.set_branch_info(
|
||||
branch_condition, branch_points_total, current_branch,
|
||||
first_branch_condition=(not branch_conditions),
|
||||
has_section=bool(measure_tja.section)
|
||||
has_section=bool(measure_tja.section),
|
||||
has_levelhold=current_levelhold
|
||||
)
|
||||
# Reset the points to prepare for the next `#BRANCHSTART p`
|
||||
branch_points_total = 0
|
||||
# Reset the levelhold value (so that future branch_conditions
|
||||
# work normally)
|
||||
current_levelhold = False
|
||||
# Keep track of the branch conditions (to later determine how
|
||||
# to set the header bytes for branches)
|
||||
branch_conditions.append(branch_condition)
|
||||
@ -244,6 +251,12 @@ def convert_tja_to_fumen(tja):
|
||||
# calculation with notes "one measure before".
|
||||
branch_points_total += branch_points_measure
|
||||
|
||||
# LEVELHOLD essentially means "ignore the branch condition for
|
||||
# the next `#BRANCHSTART` command", so we check this value after
|
||||
# we've already processed the branch condition for this measure.
|
||||
if measure_tja.levelhold:
|
||||
current_levelhold = True
|
||||
|
||||
# Create notes based on TJA measure data
|
||||
branch_points_measure = 0
|
||||
for idx_d, data in enumerate(measure_tja.data):
|
||||
|
@ -175,7 +175,6 @@ def parse_tja_course_data(course):
|
||||
has_branches = bool([d for d in course.data if d.startswith('#BRANCH')])
|
||||
current_branch = 'all' if has_branches else 'normal'
|
||||
branch_condition = None
|
||||
flag_levelhold = False
|
||||
|
||||
# Process course lines
|
||||
idx_m = 0
|
||||
@ -210,7 +209,7 @@ def parse_tja_course_data(course):
|
||||
# 2. Parse measure commands that produce an "event"
|
||||
elif command in ['GOGOSTART', 'GOGOEND', 'BARLINEON', 'BARLINEOFF',
|
||||
'DELAY', 'SCROLL', 'BPMCHANGE', 'MEASURE',
|
||||
'SECTION', 'BRANCHSTART']:
|
||||
'LEVELHOLD', 'SECTION', 'BRANCHSTART']:
|
||||
# Get position of the event
|
||||
for branch in (course.branches.keys() if current_branch == 'all'
|
||||
else [current_branch]):
|
||||
@ -233,6 +232,8 @@ def parse_tja_course_data(course):
|
||||
current_event = TJAData('bpm', float(value), pos)
|
||||
elif command == 'MEASURE':
|
||||
current_event = TJAData('measure', value, pos)
|
||||
elif command == 'LEVELHOLD':
|
||||
current_event = TJAData('levelhold', None, pos)
|
||||
elif command == 'SECTION':
|
||||
# If #SECTION occurs before a #BRANCHSTART, then ensure that
|
||||
# it's present on every branch. Otherwise, #SECTION will only
|
||||
@ -247,8 +248,6 @@ def parse_tja_course_data(course):
|
||||
current_event = TJAData('branch_start', branch_condition,
|
||||
pos)
|
||||
elif command == 'BRANCHSTART':
|
||||
if flag_levelhold:
|
||||
continue
|
||||
# Ensure that the #BRANCHSTART command is added to all branches
|
||||
current_branch = 'all'
|
||||
branch_condition = value.split(',')
|
||||
@ -272,9 +271,6 @@ def parse_tja_course_data(course):
|
||||
else:
|
||||
if command == 'START' or command == 'END':
|
||||
current_branch = 'all' if has_branches else 'normal'
|
||||
flag_levelhold = False
|
||||
elif command == 'LEVELHOLD':
|
||||
flag_levelhold = True
|
||||
elif command == 'N':
|
||||
current_branch = 'normal'
|
||||
idx_m = idx_m_branchstart
|
||||
|
@ -70,8 +70,8 @@ class TJAMeasureProcessed(DefaultObject):
|
||||
the number of `TJAMeasure` objects for a given song.))
|
||||
"""
|
||||
def __init__(self, bpm, scroll, gogo, barline, time_sig, subdivisions,
|
||||
pos_start=0, pos_end=0, delay=0, section=None,
|
||||
branch_start=None, data=None):
|
||||
pos_start=0, pos_end=0, delay=0, levelhold=False,
|
||||
section=None, branch_start=None, data=None):
|
||||
self.bpm = bpm
|
||||
self.scroll = scroll
|
||||
self.gogo = gogo
|
||||
@ -82,6 +82,7 @@ class TJAMeasureProcessed(DefaultObject):
|
||||
self.pos_end = pos_end
|
||||
self.delay = delay
|
||||
self.section = section
|
||||
self.levelhold = levelhold
|
||||
self.branch_start = branch_start
|
||||
self.data = [] if data is None else data
|
||||
|
||||
@ -160,14 +161,25 @@ class FumenMeasure(DefaultObject):
|
||||
self.offset_end = self.offset_start + self.duration
|
||||
|
||||
def set_branch_info(self, branch_condition, branch_points_total,
|
||||
current_branch, first_branch_condition, has_section):
|
||||
current_branch, first_branch_condition,
|
||||
has_section, has_levelhold):
|
||||
"""Compute the values that represent branching/diverge conditions."""
|
||||
# If levelhold is set, force the branch to stay the same,
|
||||
# regardless of the value of the current branch condition.
|
||||
if has_levelhold:
|
||||
if current_branch == 'normal':
|
||||
self.branch_info[0:2] = [999, 999] # Forces fail/fail
|
||||
elif current_branch == 'professional':
|
||||
self.branch_info[2:4] = [0, 999] # Forces pass/fail
|
||||
elif current_branch == 'master':
|
||||
self.branch_info[4:6] = [0, 0] # Forces pass/pass
|
||||
|
||||
# Handle branch conditions for percentage accuracy
|
||||
# There are three cases for interpreting #BRANCHSTART p:
|
||||
# 1. Percentage is between 0% and 100%
|
||||
# 2. Percentage is above 100% (guaranteed level down)
|
||||
# 3. Percentage is 0% (guaranteed level up)
|
||||
if branch_condition[0] == 'p':
|
||||
elif branch_condition[0] == 'p':
|
||||
vals = []
|
||||
for percent in branch_condition[1:]:
|
||||
if 0 < percent <= 1:
|
||||
@ -190,24 +202,14 @@ class FumenMeasure(DefaultObject):
|
||||
# has a #SECTION command to reset the accuracy.
|
||||
# 3. It's not the first branching condition, and it
|
||||
# doesn't have a #SECTION command.
|
||||
# For the first two cases, the branching conditions are the
|
||||
# same no matter what branch you're currently on, so we just
|
||||
# use the values as-is: [c1, c2, c1, c2, c1, c2]
|
||||
# But, for the third case, since there is no #SECTION, the
|
||||
# accuracy is not reset. This results in the following
|
||||
# condition: [999, 999, c1, c2, c2, c2]
|
||||
# - Normal can't advance to professional/master
|
||||
# - Professional can stay, or advance to master.
|
||||
# - Master can only stay in master.
|
||||
# TODO: Determine the behavior for these 3 conditions
|
||||
elif branch_condition[0] == 'r':
|
||||
if first_branch_condition or has_section:
|
||||
self.branch_info = branch_condition[1:] * 3
|
||||
else:
|
||||
self.branch_info = (
|
||||
[999, 999] +
|
||||
[branch_condition[1]] +
|
||||
[branch_condition[2]] * 3
|
||||
)
|
||||
if current_branch == 'normal':
|
||||
self.branch_info[0:2] = branch_condition[1:]
|
||||
elif current_branch == 'professional':
|
||||
self.branch_info[2:4] = branch_condition[1:]
|
||||
elif current_branch == 'master':
|
||||
self.branch_info[4:6] = branch_condition[1:]
|
||||
|
||||
|
||||
class FumenBranch(DefaultObject):
|
||||
|
@ -32,6 +32,7 @@ SCOREDIFF:95
|
||||
2021002020102020,
|
||||
#BRANCHSTART r,5,6
|
||||
#N
|
||||
#LEVELHOLD
|
||||
100000000100000000200000500000000008000000100200,
|
||||
1000202210201120,
|
||||
#E
|
||||
@ -40,12 +41,13 @@ SCOREDIFF:95
|
||||
#M
|
||||
100000000100000000200000500000000008000000100200,
|
||||
1000202210201120,
|
||||
#SECTION
|
||||
#BRANCHSTART r,7,8
|
||||
#BRANCHEND
|
||||
500000000008000000200200100000200200200200200200,
|
||||
1010202210201020,
|
||||
#SECTION
|
||||
#BRANCHSTART r,4,5
|
||||
|
||||
#N
|
||||
1001001070080000,
|
||||
100
|
||||
|
Loading…
Reference in New Issue
Block a user