Initial work on ROE. Still in progress.
This commit is contained in:
parent
5e3de6e8ff
commit
308df75423
6 changed files with 89 additions and 0 deletions
2
poetry.toml
Normal file
2
poetry.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[virtualenvs]
|
||||||
|
in-project = true
|
19
pyproject.toml
Normal file
19
pyproject.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[tool.poetry]
|
||||||
|
name = "elfish-tools"
|
||||||
|
version = "0.0.1"
|
||||||
|
description = "Tools for handling fish data from the 1993 game EL-Fish."
|
||||||
|
authors = ["Josh Washburne <josh@jodh.us>"]
|
||||||
|
readme = "README.md"
|
||||||
|
packages = [{include = "elfish", from = "src"}]
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = ">=3.10"
|
||||||
|
|
||||||
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
pylint = ">=3.0.3"
|
||||||
|
black = ">=24.1.1"
|
||||||
|
mypy = ">=1.8.0"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
0
src/elfish/__init__.py
Normal file
0
src/elfish/__init__.py
Normal file
15
src/elfish/exceptions.py
Normal file
15
src/elfish/exceptions.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
"""Custom exceptions for fish parsing."""
|
||||||
|
|
||||||
|
class AuthorError(ValueError):
|
||||||
|
"""
|
||||||
|
The author must be no more than 15 characters in length and may only
|
||||||
|
contain a subset of special characters.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidFSHFileError(ValueError):
|
||||||
|
"""The FSH file provided is not valid and cannot be parsed safely."""
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidROEFileError(ValueError):
|
||||||
|
"""The ROE file provided is not valid and cannot be parsed safely."""
|
48
src/elfish/roe.py
Normal file
48
src/elfish/roe.py
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
"""Tools for parsing a ROE file."""
|
||||||
|
|
||||||
|
from os import SEEK_CUR, SEEK_SET
|
||||||
|
from os.path import basename, splitext
|
||||||
|
from struct import unpack
|
||||||
|
|
||||||
|
from .exceptions import InvalidROEFileError
|
||||||
|
from .utils import nibble_flip
|
||||||
|
|
||||||
|
|
||||||
|
class Roe:
|
||||||
|
"""The DNA of an electronic fish with an embedded icon."""
|
||||||
|
def __init__(self, name: str = "", author: str | None = None) -> None:
|
||||||
|
self.name: str = name
|
||||||
|
self.author: str | None = author
|
||||||
|
self.is_mutant: bool = False
|
||||||
|
self.unknowns: dict[str, bytes] = {}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_file(cls, filename: str) -> "Roe":
|
||||||
|
"""Factory for importing roe from a .ROE file."""
|
||||||
|
|
||||||
|
# Unlike .FSH files, the name comes from the filename itself. Since
|
||||||
|
# DOS was limited to the 8.3 naming convention, a fish's name has a
|
||||||
|
# forced limit of only eight characters.
|
||||||
|
name = splitext(basename(filename))[0][0:8]
|
||||||
|
roe = cls(name)
|
||||||
|
|
||||||
|
with open(filename, "rb") as rfile:
|
||||||
|
# First byte of file determines mutant status. Non-zero = mutant.
|
||||||
|
# Second byte is padding.
|
||||||
|
roe.is_mutant = unpack("?x", rfile.read(2))[0]
|
||||||
|
|
||||||
|
# Next two bytes are unknown.
|
||||||
|
roe.unknowns["00000002"] = unpack("2s", rfile.read(2))[0]
|
||||||
|
|
||||||
|
# Next sixteen bytes is a nibble-flipped encoding of the original
|
||||||
|
# author with a zero null termination byte.
|
||||||
|
author = ""
|
||||||
|
flipped_author = unpack("16s", rfile.read(16))[0]
|
||||||
|
for letter in flipped_author:
|
||||||
|
code = nibble_flip(letter)
|
||||||
|
if code == 0:
|
||||||
|
break
|
||||||
|
author += chr(code)
|
||||||
|
roe.author = author.upper()
|
||||||
|
|
||||||
|
return roe
|
5
src/elfish/utils.py
Normal file
5
src/elfish/utils.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
"""Miscellaneous functions commonly used by all classes."""
|
||||||
|
|
||||||
|
def nibble_flip(num: int) -> int:
|
||||||
|
"""Swaps the high and low nibbles in a byte. (Ex: 0x1a -> 0xa1)"""
|
||||||
|
return (num >> 4) | (num << 4) & 0xFF
|
Loading…
Reference in a new issue