Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/mars_patcher/auto_generated_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,16 @@
Messagelanguages: typ.TypeAlias = dict[Validlanguages, str]

class Itemmessages(typ.TypedDict, total=False):
Kind: typ.Required[Itemmessageskind]
Languages: Messagelanguages
Centered: bool = True
MessageID: typ.Annotated[int, '0 <= value <= 56']
"""The Message ID, will display one of the predefined messages in the ROM"""

Itemmessageskind = typ.Literal[
'CustomMessage',
'MessageID'
]

class BlocklayerItem(typ.TypedDict, total=False):
X: Typeu8
Expand Down
7 changes: 7 additions & 0 deletions src/mars_patcher/constants/items.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,15 @@ class ItemSprite(Enum):
KEY_ITEM: Final = "Item"
KEY_ITEM_SPRITE: Final = "ItemSprite"
KEY_ITEM_MESSAGES: Final = "ItemMessages"
KEY_ITEM_MESSAGES_KIND: Final = "Kind"
KEY_LANGUAGES: Final = "Languages"
KEY_CENTERED: Final = "Centered"
KEY_MESSAGE_ID: Final = "MessageID"


class ItemMessagesKind(Enum):
CUSTOM_MESSAGE = 0
MESSAGE_ID = 1


SOURCE_ENUMS = {
Expand Down
2 changes: 1 addition & 1 deletion src/mars_patcher/constants/reserved_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class ReservedConstants:

# Pointers, offset by language value, that store the message table location
MESSAGE_TABLE_LOOKUP_ADDR = 0x79CDF4
FIRST_CUSTOM_MESSAGE_ID = 0x38 # The first 0x37 messages are reserved for standard messages
FIRST_CUSTOM_MESSAGE_ID = 0x39 # The first 0x38 messages are reserved for standard messages

PATCHER_FREE_SPACE_ADDR = 0x7D0000
PATCHER_FREE_SPACE_END = PATCHER_FREE_SPACE_ADDR + 0x20000
Expand Down
49 changes: 43 additions & 6 deletions src/mars_patcher/data/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -922,15 +922,52 @@
"ItemMessages": {
"type": "object",
"properties": {
"Languages": {
"$ref": "#/$defs/MessageLanguages"
},
"Centered": {
"type": "boolean",
"default": true
"Kind": {
"$ref": "#/$defs/ItemMessagesKind"
}
},
"required": ["Kind"],
"if": {
"properties": {
"Kind": {"const": "CustomMessage" }
}
},
"then": {
"properties": {
"Kind": {
"$ref": "#/$defs/ItemMessagesKind"
},
"Languages": {
"$ref": "#/$defs/MessageLanguages"
},
"Centered": {
"type": "boolean",
"default": true
}
},
"required": ["Languages"],
"additionalProperties": false
},
"else": {
"properties": {
"Kind": {
"$ref": "#/$defs/ItemMessagesKind"
},
"MessageID": {
"type": "integer",
"minimum": 0,
"maximum": 56,
"description": "The Message ID, will display one of the predefined messages in the ROM"
}
},
"required": ["MessageID"],
"additionalProperties": false
}
},
"ItemMessagesKind":{
"type": "string",
"enum": ["CustomMessage", "MessageID"]
},
"BlockLayer": {
"type": "array",
"uniqueItems": true,
Expand Down
71 changes: 43 additions & 28 deletions src/mars_patcher/item_patcher.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
from mars_patcher.auto_generated_types import MarsschemaTankincrements
from mars_patcher.constants.reserved_space import ReservedConstants
from mars_patcher.locations import ItemMessages, ItemSprite, ItemType, LocationSettings
from mars_patcher.locations import (
ItemMessages,
ItemMessagesKind,
ItemSprite,
ItemType,
LocationSettings,
)
from mars_patcher.rom import Rom
from mars_patcher.room_entry import RoomEntry
from mars_patcher.text import Language, MessageType, encode_text
Expand Down Expand Up @@ -130,23 +136,27 @@ def write_items(self) -> None:
rom.write_8(item_addr + 5, min_loc.new_item.value)
if min_loc.item_sprite != ItemSprite.UNCHANGED:
rom.write_8(item_addr + 6, min_loc.item_sprite.value)
# Handle custom messages
# Handle item messages
if min_loc.item_messages is not None:
# If we already encountered the message before, just write the message id.
messages = min_loc.item_messages
if messages in item_messages_to_custom_id:
rom.write_8(item_addr + 7, item_messages_to_custom_id[messages])
# If the kind is Custom Message, write the message to free space, and set the ID
if messages.kind == ItemMessagesKind.CUSTOM_MESSAGE:
# If we already encountered the message before, write the existing message id.
if messages in item_messages_to_custom_id:
rom.write_8(item_addr + 7, item_messages_to_custom_id[messages])
else:
self.write_custom_message(
custom_message_id,
message_table_addrs,
item_addr,
min_loc.item_messages,
False,
)
item_messages_to_custom_id[messages] = custom_message_id
custom_message_id += 1
# If the kind is Message ID, write that ID
else:
self.write_custom_message(
custom_message_id,
message_table_addrs,
item_addr,
min_loc.item_messages,
False,
)
item_messages_to_custom_id[messages] = custom_message_id
custom_message_id += 1

rom.write_8(item_addr + 7, messages.message_id)
# Handle major locations
for maj_loc in self.settings.major_locs:
# Write to majors table
Expand All @@ -155,22 +165,27 @@ def write_items(self) -> None:
total_metroids += 1
addr = MAJOR_LOCS_ADDR + (maj_loc.major_src.value * MAJOR_LOC_SIZE)
rom.write_8(addr, maj_loc.new_item.value)
# Handle custom messages
# Handle item messages
if maj_loc.item_messages is not None:
# If we already encountered the message before, just write the message id.
messages = maj_loc.item_messages
if messages in item_messages_to_custom_id:
rom.write_8(addr + 1, item_messages_to_custom_id[messages])
# If the kind is Custom Message, write the message to free space, and set the ID
if messages.kind == ItemMessagesKind.CUSTOM_MESSAGE:
# If we already encountered the message before, write the existing id.
if messages in item_messages_to_custom_id:
rom.write_8(addr + 1, item_messages_to_custom_id[messages])
else:
self.write_custom_message(
custom_message_id,
message_table_addrs,
addr,
maj_loc.item_messages,
True,
)
item_messages_to_custom_id[messages] = custom_message_id
custom_message_id += 1
# If the kind is Message ID, write that ID
else:
self.write_custom_message(
custom_message_id,
message_table_addrs,
addr,
maj_loc.item_messages,
True,
)
item_messages_to_custom_id[messages] = custom_message_id
custom_message_id += 1
rom.write_8(addr + 1, messages.message_id)

# Write total metroid count
rom.write_8(TOTAL_METROID_COUNT_ADDR, total_metroids)
Expand Down
27 changes: 22 additions & 5 deletions src/mars_patcher/locations.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,17 @@
KEY_HIDDEN,
KEY_ITEM,
KEY_ITEM_MESSAGES,
KEY_ITEM_MESSAGES_KIND,
KEY_ITEM_SPRITE,
KEY_LANGUAGES,
KEY_MAJOR_LOCS,
KEY_MESSAGE_ID,
KEY_MINOR_LOCS,
KEY_ORIGINAL,
KEY_ROOM,
KEY_SOURCE,
SOURCE_ENUMS,
ItemMessagesKind,
ItemSprite,
ItemType,
MajorSource,
Expand Down Expand Up @@ -91,8 +94,10 @@ def __init__(

@dataclass(frozen=True)
class ItemMessages:
kind: ItemMessagesKind
item_messages: frozendict[Language, str]
centered: bool
message_id: int

LANG_ENUMS: ClassVar[dict[str, Language]] = {
"JapaneseKanji": Language.JAPANESE_KANJI,
Expand All @@ -104,14 +109,26 @@ class ItemMessages:
"Spanish": Language.SPANISH,
}

KIND_ENUMS: ClassVar[dict[str, ItemMessagesKind]] = {
"CustomMessage": ItemMessagesKind.CUSTOM_MESSAGE,
"MessageID": ItemMessagesKind.MESSAGE_ID,
}

@classmethod
def from_json(cls, data: Itemmessages) -> ItemMessages:
item_messages: dict[Language, str] = {}
for lang_name, message in data[KEY_LANGUAGES].items():
lang = cls.LANG_ENUMS[lang_name]
item_messages[lang] = message
centered = data.get(KEY_CENTERED, True)
return cls(frozendict(item_messages), centered)
centered = True
kind: ItemMessagesKind = cls.KIND_ENUMS[data[KEY_ITEM_MESSAGES_KIND]]
message_id = 0
if kind == ItemMessagesKind.CUSTOM_MESSAGE:
for lang_name, message in data[KEY_LANGUAGES].items():
lang = cls.LANG_ENUMS[lang_name]
item_messages[lang] = message
centered = data.get(KEY_CENTERED, True)
else:
message_id = data[KEY_MESSAGE_ID]

return cls(kind, frozendict(item_messages), centered, message_id)


class LocationSettings:
Expand Down