Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mario & Luigi: Superstar Saga: Implement New Game #2754

Merged
merged 123 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
77bb3c3
Commit for PR
jamesbrq Jan 22, 2024
d0e7d65
Commit for PR
jamesbrq Jan 22, 2024
b38968c
Update worlds/mlss/Client.py
jamesbrq Jan 22, 2024
4234e81
Update worlds/mlss/__init__.py
jamesbrq Jan 22, 2024
e40f24b
Update worlds/mlss/__init__.py
jamesbrq Jan 22, 2024
a8792e1
Update worlds/mlss/docs/setup_en.md
jamesbrq Jan 22, 2024
0bbdae2
Remove deprecated import. Updated settings and romfile syntax
jamesbrq Jan 22, 2024
b86d7ef
Updated Options to new system. Changed all references from MultiWorld…
jamesbrq Jan 23, 2024
94dcb26
Changed switch statements to if else
jamesbrq Jan 23, 2024
908c609
Update en_Mario & Luigi Superstar Saga.md
jamesbrq Jan 23, 2024
d9942ac
Updated client.py
jamesbrq Jan 23, 2024
aed0896
Update Client.py
jamesbrq Jan 24, 2024
2ea54ce
Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md
jamesbrq Jan 31, 2024
d97e66d
Merge branch 'main' into mlss
jamesbrq Feb 9, 2024
5f2a75b
Updated logic, Updated patch implementation, Removed unused imports, …
jamesbrq Feb 9, 2024
cd1e634
Merge branch 'mlss' of https://github.com/jamesbrq/ArchipelagoMainMLS…
jamesbrq Feb 9, 2024
009cf45
Update __init__.py
jamesbrq Feb 12, 2024
ba9e953
Merge branch 'main' into mlss
jamesbrq Feb 12, 2024
2614960
Changed reference from world to mlssworld
jamesbrq Feb 18, 2024
458fae4
Merge branch 'main' into mlss
jamesbrq Feb 18, 2024
fddad3b
Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md
jamesbrq Feb 24, 2024
1ef8eef
Merge branch 'main' into mlss
jamesbrq Feb 24, 2024
9ab2b95
Merge branch 'main' into mlss
jamesbrq Feb 27, 2024
420fbc8
Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md
jamesbrq Mar 5, 2024
e9a661d
Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md
jamesbrq Mar 5, 2024
4b762ce
Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md
jamesbrq Mar 5, 2024
cedc00f
Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md
jamesbrq Mar 5, 2024
5db0825
Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md
jamesbrq Mar 5, 2024
b8dee7a
Fix merge conflict + update prep
jamesbrq Mar 5, 2024
f8c5f7e
Merge branch 'main' into mlss
jamesbrq Mar 5, 2024
972b275
v1.2
jamesbrq Mar 6, 2024
38a5f16
Merge branch 'main' into mlss
jamesbrq Mar 6, 2024
3ba10d1
Leftover print commands
jamesbrq Mar 6, 2024
43922ab
Merge branch 'main' into mlss
jamesbrq Mar 6, 2024
2a8d7da
Update basepatch.bsdiff
jamesbrq Mar 8, 2024
64e1a3c
Merge branch 'mlss' of https://github.com/jamesbrq/ArchipelagoMainMLS…
jamesbrq Mar 8, 2024
ce30be2
Update basepatch.bsdiff
jamesbrq Mar 10, 2024
2ba5508
Merge branch 'main' into mlss
jamesbrq Mar 13, 2024
9772bf5
Merge branch 'main' into mlss
jamesbrq Mar 15, 2024
a47b02b
Merge branch 'main' into mlss
jamesbrq Mar 20, 2024
16b407b
Merge branch 'main' into mlss
jamesbrq Mar 22, 2024
4d6dbbf
Merge branch 'main' into mlss
jamesbrq Mar 26, 2024
399498f
v1.3
jamesbrq Mar 27, 2024
b0d31f9
Update Rom.py
jamesbrq Mar 27, 2024
db96389
Merge branch 'main' into mlss
jamesbrq Apr 1, 2024
3c294ac
Merge branch 'main' into mlss
jamesbrq Apr 15, 2024
3f4f316
Change tracker locations to serverside, no longer locations. Various …
jamesbrq Apr 15, 2024
2c52c08
Event removal continuation.
jamesbrq Apr 15, 2024
2fad6ab
Partial Implementation of APPP (Incomplete))
jamesbrq Apr 15, 2024
2947f58
v1.4 Implemented APPP
jamesbrq Apr 16, 2024
2835f67
Merge branch 'main' into mlss
jamesbrq Apr 16, 2024
f9df53a
Docs Updated
jamesbrq Apr 16, 2024
0ed7abe
Update Rom.py
jamesbrq Apr 17, 2024
4c0ae0c
Merge branch 'mlss' of https://github.com/jamesbrq/ArchipelagoMainMLS…
jamesbrq Apr 17, 2024
fc32c08
Update setup_en.md
jamesbrq Apr 17, 2024
edcf162
Merge branch 'main' into mlss
jamesbrq Apr 17, 2024
58f629f
Merge branch 'main' into mlss
jamesbrq Apr 18, 2024
46aa71d
Update Rom.py
jamesbrq Apr 18, 2024
6f5b015
Update Rules.py
jamesbrq Apr 18, 2024
f541476
Merge branch 'mlss' of https://github.com/jamesbrq/ArchipelagoMainMLS…
jamesbrq Apr 18, 2024
b65100a
Merge branch 'main' into mlss
jamesbrq Apr 18, 2024
f0b1ded
Fix for APPP being broken on webhost
jamesbrq Apr 19, 2024
51cecd2
Merge branch 'mlss' of https://github.com/jamesbrq/ArchipelagoMainMLS…
jamesbrq Apr 19, 2024
362d494
Merge branch 'main' into mlss
jamesbrq Apr 19, 2024
7e9ed1b
Update Rom.py
jamesbrq Apr 19, 2024
dc218f9
Update Rom.py
jamesbrq Apr 20, 2024
91fa7f1
Location name fixes + pants color fixes
jamesbrq Apr 20, 2024
8421095
Update Rules.py
jamesbrq Apr 20, 2024
f0d109e
Fix for ultra hammer cutscene
jamesbrq Apr 21, 2024
7176e53
Fixed compat. issues with python ver. 3.8
jamesbrq Apr 21, 2024
5f3a1b1
Merge branch 'ArchipelagoMW:main' into mlss
jamesbrq Apr 21, 2024
72ad9ea
Updated hidden block yaml option
jamesbrq Apr 22, 2024
a02cdb8
Merge branch 'main' into mlss
jamesbrq Apr 22, 2024
7d84c7f
pre-v1.5
jamesbrq Apr 22, 2024
84179f1
Update Client.py
jamesbrq Apr 22, 2024
07476c4
Update basepatch.bsdiff
jamesbrq Apr 23, 2024
248ec56
v1.5
jamesbrq Apr 23, 2024
7f812d6
Update XP multiplier to have a minimum of 0
jamesbrq Apr 23, 2024
8265c1b
Merge branch 'main' into mlss
jamesbrq Apr 23, 2024
873eb85
Merge branch 'main' into mlss
jamesbrq Apr 25, 2024
d688ffa
Update 'Beanfruit' to 'Bean Fruit'
jamesbrq Apr 26, 2024
39b9b20
Merge branch 'main' into mlss
jamesbrq Apr 28, 2024
b5ad56f
v1.6
jamesbrq Apr 29, 2024
9333a33
Merge branch 'main' into mlss
jamesbrq Apr 29, 2024
cfaf261
Merge branch 'main' into mlss
jamesbrq Apr 29, 2024
5ad7f36
Update Rom.py
jamesbrq Apr 30, 2024
fc9c782
Update basepatch.bsdiff
jamesbrq May 1, 2024
950a5a7
Initial review refactor
jamesbrq May 1, 2024
939bc99
Revert state logic changes. Continuation of refactor.
jamesbrq May 1, 2024
c2de51e
Fixed failed generations. Finished refactor.
jamesbrq May 2, 2024
7cb2d05
Merge branch 'main' into mlss
jamesbrq May 2, 2024
20d47e7
Reworked colors. Removed all .txt files
jamesbrq May 2, 2024
301143b
Merge branch 'mlss' of https://github.com/jamesbrq/ArchipelagoMainMLS…
jamesbrq May 2, 2024
1b11836
Actually removed the .txt files this time
jamesbrq May 2, 2024
fa9c377
Merge branch 'main' into mlss
NewSoupVi May 2, 2024
e2dd67d
Merge branch 'main' into mlss
jamesbrq May 2, 2024
7046a25
Update Rom.py
jamesbrq May 2, 2024
27c646d
Update README.md
jamesbrq May 2, 2024
ca421fc
Update worlds/mlss/Options.py
jamesbrq May 2, 2024
9011f93
Update worlds/mlss/Client.py
jamesbrq May 2, 2024
b2b07f0
Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md
jamesbrq May 2, 2024
26bce0e
Update worlds/mlss/__init__.py
jamesbrq May 2, 2024
8aef451
Update worlds/mlss/docs/en_Mario & Luigi Superstar Saga.md
jamesbrq May 2, 2024
679dcee
Update worlds/mlss/Data.py
jamesbrq May 2, 2024
362628a
Review refactor.
jamesbrq May 2, 2024
87ef32e
Merge branch 'mlss' of https://github.com/jamesbrq/ArchipelagoMainMLS…
jamesbrq May 2, 2024
ea1c0c7
Update README.md
jamesbrq May 2, 2024
6eb4b53
Update worlds/mlss/Rules.py
jamesbrq May 2, 2024
6883b98
Add coin blocks to LocationName
jamesbrq May 2, 2024
c072bd9
Refactor.
jamesbrq May 2, 2024
ddc9c45
Merge branch 'main' into mlss
jamesbrq May 2, 2024
07385c8
Update Items.py
jamesbrq May 2, 2024
227df52
Merge branch 'mlss' of https://github.com/jamesbrq/ArchipelagoMainMLS…
jamesbrq May 2, 2024
f9f6241
Delete mlss.apworld
jamesbrq May 2, 2024
ded8b73
Small asm bugfix
jamesbrq May 3, 2024
f42dc0b
Merge branch 'main' into mlss
jamesbrq May 3, 2024
1f2c353
Merge branch 'main' into mlss
jamesbrq May 3, 2024
e010d71
Merge branch 'main' into mlss
jamesbrq May 3, 2024
c3e4b57
Update basepatch.bsdiff
jamesbrq May 3, 2024
de68994
Merge branch 'main' into mlss
jamesbrq May 5, 2024
54f8ab1
Client sends less messages to server
jamesbrq May 6, 2024
99e3031
Merge branch 'main' into mlss
jamesbrq May 6, 2024
da807d4
Update basepatch.bsdiff
jamesbrq May 6, 2024
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Currently, the following games are supported:
* Landstalker: The Treasures of King Nole
* Final Fantasy Mystic Quest
* TUNIC
* Mario & Luigi: Superstar Saga
jamesbrq marked this conversation as resolved.
Show resolved Hide resolved

For setup and instructions check out our [tutorials page](https://archipelago.gg/tutorial/).
Downloads can be found at [Releases](https://github.com/ArchipelagoMW/Archipelago/releases), including compiled
Expand Down
3 changes: 3 additions & 0 deletions docs/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@
/worlds/lufia2ac/ @el-u
/worlds/lufia2ac/docs/ @wordfcuk @el-u

# Mario & Luigi: Superstar Saga
/worlds/mlss/ @jamesbrq

# Meritous
/worlds/meritous/ @FelicitusNeko

Expand Down
241 changes: 241 additions & 0 deletions worlds/mlss/Client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
from typing import TYPE_CHECKING, Optional, Set
import struct
from NetUtils import ClientStatus
from .Locations import roomCount, nonBlock, beanstones, roomException, shop, badge, pants, eReward
from .Items import items_by_id

import asyncio

import worlds._bizhawk as bizhawk
from worlds._bizhawk.client import BizHawkClient

if TYPE_CHECKING:
from worlds._bizhawk.context import BizHawkClientContext

ROOM_ARRAY_POINTER = 0x51fa00

class MLSSClient(BizHawkClient):
game = "Mario & Luigi Superstar Saga"
system = "GBA"
patch_suffix = ".apmlss"
local_checked_locations: Set[int]
goal_flag: int
rom_slot_name: Optional[str]
eCount: int
eUsed: [int]
player_name: Optional[str]
checked_flags: dict[int, list] = {}

def __init__(self) -> None:
super().__init__()
self.local_checked_locations = set()
self.local_set_events = {}
self.local_found_key_items = {}
self.rom_slot_name = None
self.eCount = 0
self.eUsed = []

async def validate_rom(self, ctx: "BizHawkClientContext") -> bool:
from CommonClient import logger

try:
# Check ROM name/patch version
rom_name_bytes = ((await bizhawk.read(ctx.bizhawk_ctx, [(0xA0, 14, "ROM")]))[0])
rom_name = bytes([byte for byte in rom_name_bytes if byte != 0]).decode("UTF-8")
if not rom_name.startswith("MARIO&LUIGIU"):
return False
if rom_name == "MARIO&LUIGIUA8":
logger.info("ERROR: You appear to be running an unpatched version of Mario & Luigi Superstar Saga. "
"You need to generate a patch file and use it to create a patched ROM.")
return False
if rom_name != "MARIO&LUIGIUAP":
logger.info("ERROR: The patch file used to create this ROM is not compatible with "
"this client. Double check your client version against the version being "
"used by the generator.")
return False
except UnicodeDecodeError:
return False
except bizhawk.RequestFailedError:
return False # Should verify on the next pass

ctx.game = self.game
ctx.items_handling = 0b101
ctx.want_slot_data = True
ctx.watcher_timeout = 0.125
self.rom_slot_name = rom_name
name_bytes = ((await bizhawk.read(ctx.bizhawk_ctx, [(0xB0, 16, "ROM")]))[0])
name = bytes([byte for byte in name_bytes if byte != 0]).decode("UTF-8")
self.player_name = name
logger.info(name)

for i in range(59):
self.checked_flags[i] = []

return True

async def set_auth(self, ctx: "BizHawkClientContext") -> None:
ctx.auth = self.player_name

async def game_watcher(self, ctx: "BizHawkClientContext") -> None:
try:
read_state = await bizhawk.read(ctx.bizhawk_ctx, [(0x4564, 59, "EWRAM"),
(0x2330, 2, "IWRAM"), (0x3FE0, 1, "IWRAM"), (0x304A, 1, "EWRAM"),
(0x304B, 1, "EWRAM"), (0x304C, 4, "EWRAM"), (0x4800, 6, "EWRAM"),
(0x4808, 2, "EWRAM"), (0x4407, 1, "EWRAM"), (0x2339, 1, "IWRAM")])
flags = read_state[0]
room = (read_state[1][1] << 8) + read_state[1][0]
shop_init = read_state[2][0]
shop_scroll = read_state[3][0] & 0x1F
is_buy = (read_state[4][0] != 0)
shop_address = (struct.unpack('<I', read_state[5])[0]) & 0xFFFFFF
logo = bytes([byte for byte in read_state[6] if byte < 0x70]).decode("UTF-8")
received_index = (read_state[7][0] << 8) + read_state[7][1]
cackletta = (read_state[8][0] & 0x40)
shopping = (read_state[9][0] & 0xF)

if logo != "MLSSAP":
return

locs_to_send = set()

# Checking shop purchases
if is_buy:
await bizhawk.write(ctx.bizhawk_ctx, [(0x304A, [0x0, 0x0], "EWRAM")])
if shop_address != 0x3c0618 and shop_address != 0x3c0684:
location = shop[shop_address][shop_scroll]
else:
if shop_init & 0x1 != 0:
location = badge[shop_address][shop_scroll]
else:
location = pants[shop_address][shop_scroll]
if location in ctx.server_locations:
locs_to_send.add(location)
jamesbrq marked this conversation as resolved.
Show resolved Hide resolved

# Loop for recieving items. Item is written as an ID into 0x3057.
jamesbrq marked this conversation as resolved.
Show resolved Hide resolved
# ASM read the ID in a loop and give the player the item before resetting the RAM address to 0x0.
# If RAM address isn't 0x0 yet break out and try again later to give the rest of the items
for i in range(len(ctx.items_received) - received_index):
item_data = items_by_id[ctx.items_received[received_index + i].item]
b = await bizhawk.read(ctx.bizhawk_ctx, [(0x3057, 1, "EWRAM")])
if b[0][0] == 0:
await bizhawk.write(ctx.bizhawk_ctx, [(0x3057, [id_to_RAM(item_data.itemID)], "EWRAM"), (0x4808, [(received_index + i + 1) // 0x100, (received_index + i + 1) % 0x100], "EWRAM")])
await asyncio.sleep(.05)
else:
break

# Early return and location send if you are currently in a shop,
# since other flags aren't going to change
if shopping & 0x3 == 0x3:
if locs_to_send != self.local_checked_locations:
self.local_checked_locations = locs_to_send

if locs_to_send is not None:
await ctx.send_msgs([{
"cmd": "LocationChecks",
"locations": list(locs_to_send)
}])
return

# Checking flags that aren't digspots or blocks
for item in nonBlock:
address, mask, location = item
if location in self.local_checked_locations:
continue
flag_bytes = await bizhawk.read(ctx.bizhawk_ctx, [(address, 1, "EWRAM"), (0x4800, 6, "EWRAM")])
flag_byte = flag_bytes[0][0]
backup_logo = bytes([byte for byte in flag_bytes[1] if byte < 0x70]).decode("UTF-8")
if backup_logo != "MLSSAP":
return
if flag_byte & mask != 0:
if location in roomException:
if roomException[location] != room:
if (location == 0xDA0001 or location == 0x2578e7) and room == 0x79:
exception = False
else:
exception = True
else:
exception = False
else:
exception = True

if location in eReward:
if location not in self.eUsed:
self.eUsed += [location]
location = eReward[len(self.eUsed) - 1]
else:
continue
if (location in ctx.server_locations) and exception:
locs_to_send.add(location)

# Check for set location flags.
for byte_i, byte in enumerate(bytearray(flags)):
for j in range(8):
if j in self.checked_flags[byte_i]:
continue
and_value = 1 << j
if byte & and_value != 0:
flag_id = byte_i * 8 + (j + 1)
room, item = find_key(roomCount, flag_id)
pointer_arr = await bizhawk.read(ctx.bizhawk_ctx,
[(ROOM_ARRAY_POINTER + ((room - 1) * 4), 4, "ROM")])
jamesbrq marked this conversation as resolved.
Show resolved Hide resolved
pointer = (struct.unpack('<I', pointer_arr[0])[0])
pointer = pointer & 0xFFFFFF
offset = await bizhawk.read(ctx.bizhawk_ctx, [(pointer, 1, "ROM")])
offset = offset[0][0]
if offset != 0:
offset = 2
pointer += (item * 8) + 1 + offset
for key, value in beanstones.items():
if pointer == value:
pointer = key
break
if pointer in ctx.server_locations:
self.checked_flags[byte_i] += [j]
locs_to_send.add(pointer)

if not ctx.finished_game and cackletta != 0:
await ctx.send_msgs([{
"cmd": "StatusUpdate",
"status": ClientStatus.CLIENT_GOAL
}])

await ctx.send_msgs([{
"cmd": "Set",
"key": f"mlss_room_{ctx.team}_{ctx.slot}",
"default": 0,
"want_reply": False,
"operations": [{"operation": "replace", "value": room}]
}])

# Send locations if there are any to send.
if locs_to_send != self.local_checked_locations:
self.local_checked_locations = locs_to_send

if locs_to_send is not None:
await ctx.send_msgs([{
"cmd": "LocationChecks",
"locations": list(locs_to_send)
}])

except bizhawk.RequestFailedError:
# Exit handler and return to main loop to reconnect.
pass


def find_key(dictionary, target):
leftover = target

for key, value in dictionary.items():
if leftover > value:
leftover -= value
else:
return key, leftover


def id_to_RAM(id_: int):
code = id_
if code == 0x1D or code == 0x1E:
code += 0xE
if 0x20 <= code <= 0x26:
code -= 0x4
return code
Loading