Support five new log sections

We add support for...
  - MAGITEK
  - DANCES
  - ESPERS
  - ITEM MAGIC
  - COLOSSEUM
This commit is contained in:
Trysdyn Black 2024-10-13 02:14:11 -07:00
parent ae9451f336
commit 6a0ad9c7ea
2 changed files with 151 additions and 11 deletions

View file

@ -34,12 +34,7 @@ BCCE is in active development and this may break at any time; see the first para
These sections in the BCEX/BCCE spoiler logs currently have no logic and I'm aware of it. That doesn't mean sections *not* listed here have support; they may not and I'm not aware of them.
- MAGITEK
- DANCES
- ESPERS
- ITEM MAGIC
- ITEM EFFECTS
- COLOSSEUM
- SHOPS
- TREASURE CHESTS
- JUNCTIONS

157
main.py
View file

@ -2,7 +2,7 @@
"""Parse BCEX (or BCCE) logs into json objects."""
__version__ = "0.4.1"
__version__ = "0.4.2"
__author__ = "Trysdyn Black"
import json
@ -15,12 +15,7 @@ class Parser:
BCEX/BCCE spoiler logfile parser.
Sections missing support:
- MAGITEK
- DANCES
- ESPERS
- ITEM MAGIC
- ITEM EFFECTS
- COLOSSEUM
- SHOPS
- TREASURE CHESTS
- JUNCTIONS
@ -365,6 +360,156 @@ class Parser:
return replacements
@staticmethod
def parse_MAGITEK(data: str) -> dict[str, list]:
"""
Parse the BCCE-only MAGITEK section.
This section contains info on what Terra and the guards have in their magitek skill
lists at the start of the game. Unfortunately like the STATS block, this keys on slot
name and not randomized name, but at least it's super simple.
"""
result = {"terra": [], "others": []}
mode = None
for line in data.split("\n"):
if line.startswith("Terra Magitek"):
mode = "terra"
elif line.startswith("Other Actor"):
mode = "others"
elif line.strip() and mode:
result[mode].append(line.strip())
return result
@staticmethod
def parse_DANCES(data: str) -> dict[str, dict]:
"""
Parse the BCCE-only DANCES section.
This section's a list of dances with their effects chances. Each dance seems to
always have four effects, spaced at specific locations in the string, so we chomp
by hardcoded locations. Brittle.
"""
result = {}
dance = None
for line in data.split("\n"):
# Formatting line
if "-----" in line:
continue
# Result list
if line.startswith(" "):
# This is more brittle than I'd like but the logs space results out by
# character position and some dance results have spaces so it's hard to
# split properly.
for i in range(2, 57, 18):
chance, effect = line[i : i + 18].split(" ", 1)
result[dance][effect.strip()] = chance.strip()
# New dance section
elif line.strip():
dance = line.strip()
if dance not in result:
result[dance] = {}
return result
@staticmethod
def parse_ESPERS(data: str) -> dict[str, dict]:
"""
Parse the ESPERS section.
This section lists espers, what they teach, their bonuses, and locations. We
assume any line with a : in it is either BONUS or LOCATION and just k=v it. Any
line after a blank line is an esper name, and anything else is a spell learn option.
"""
result = {}
esper = None
next_esper = False
for line in data.split("\n"):
# Formatting line
if "-----" in line:
continue
# Blank lines divide esper sections
if not line.strip():
next_esper = True
# The first line in a new section is the esper name
elif next_esper:
esper = line.strip()
if esper not in result:
result[esper] = {"learnset": {}}
next_esper = False
# Any line with ":" is a k=v we should just shove into the dict
elif ": " in line:
k, v = line.split(": ")
result[esper][k.lower()] = v.strip()
# Everything else should be spell learnset
else:
spell, mult = line.split(" x")
result[esper]["learnset"][spell.strip()] = f"x{mult}"
return result
@staticmethod
def parse_ITEM_MAGIC(data: str) -> dict[str, dict]:
"""
Parse the ITEM MAGIC section.
This section is actually three distinct subsections. Breakable items and procs
we can just store as k=v in sub-dicts. The spell-teaching items section we treat
like the esper learnset and store spell_name = learn multiplier.
"""
result = {}
section = None
for line in data.split("\n"):
# Formatting lines
if "-----" in line or not line.strip():
continue
# Anything with ":" is a k=v to insert
if ":" in line:
k, v = line.split(": ")
# Spell-teaching needs special logic to get the {spell: multiplier} format
if section == "spell-teaching":
spell, mult = v.split(" x")
result[section][k.strip()] = {spell.strip(): f"x{mult}"}
else:
result[section][k.strip()] = v.strip()
# Anything else should be a section header. Use the first word unless it's "ITEM"
else:
tok_line = line.split()
section = tok_line[1].lower() if "ITEM" in tok_line[0] else tok_line[0].lower()
result[section] = {}
return result
@staticmethod
def parse_COLOSSEUM(data: str) -> dict[str, dict]:
"""
Parse the COLOSSEUM section.
Each line is one item offered, which has a resulting item, a monster level, and a
a monster name. This results in basic string splitting giving us all the data we
need.
"""
result = {}
for line in data.split("\n"):
if "-----" in line or not line.strip():
continue
item, tok_line = line.split("->")
new_item, tok_line = tok_line.split(": LV ")
level, name = tok_line.split(" ", 1)
result[item.strip()] = {
"becomes": new_item.strip(),
"battle": {"monster": name.strip(), "level": int(level.strip())},
}
return result
@staticmethod
def cleanup_STATS(data: dict) -> bool:
"""