Compare commits

...

8 Commits

Author SHA1 Message Date
Duck
ecb22642af Tests: Handle optional args for get_all_state patch (#5297)
* Make `use_cache` optional

* Pass all kwargs
2025-08-09 00:24:19 +02:00
Exempt-Medic
17ccfdc266 DS3: Don't Create Disabled Locations (#5292) 2025-08-08 15:07:36 -04:00
Scipio Wright
4633f12972 Docs: Use / instead of . for the reference to lttp's options.py (#5300)
* Update options api.md

* o -> O
2025-08-07 20:14:09 +02:00
Silvris
1f6c99635e FF1: fix client breaking other NES games (#5293) 2025-08-05 22:25:11 +02:00
threeandthreee
4e92cac171 LADX: Update Docs (#5290)
* convert ladxr section to markdown, other adjustments
make links clickable
crow icon -> open tracker
adjust for removed sprite sheets
some adjustments in ladxr section for differences in the ap version:
we don't have a casual logic
we don't have stealing options

* fix link, and another correction
2025-08-04 11:46:05 -04:00
Scipio Wright
3b88630b0d TUNIC: Fix zig skip showing up in decoupled + fixed shop #5289 2025-08-04 14:21:58 +02:00
Ishigh1
e6d2d8f455 Core: Added a leading 0 to classification.as_flag #5291 2025-08-04 14:19:51 +02:00
massimilianodelliubaldini
84c2d70d9a Fix regression on 404 redirects 2025-08-03 03:06:42 +00:00
8 changed files with 100 additions and 70 deletions

View File

@@ -1571,7 +1571,7 @@ class ItemClassification(IntFlag):
def as_flag(self) -> int:
"""As Network API flag int."""
return int(self & 0b0111)
return int(self & 0b00111)
class Item:

View File

@@ -87,19 +87,22 @@ def start_playing():
@cache.cached()
def game_info(game, lang):
"""Game Info Pages"""
theme = get_world_theme(game)
secure_game_name = secure_filename(game)
lang = secure_filename(lang)
document = render_markdown(os.path.join(
app.static_folder, "generated", "docs",
secure_game_name, f"{lang}_{secure_game_name}.md"
))
return render_template(
"markdown_document.html",
title=f"{game} Guide",
html_from_markdown=document,
theme=theme,
)
try:
theme = get_world_theme(game)
secure_game_name = secure_filename(game)
lang = secure_filename(lang)
document = render_markdown(os.path.join(
app.static_folder, "generated", "docs",
secure_game_name, f"{lang}_{secure_game_name}.md"
))
return render_template(
"markdown_document.html",
title=f"{game} Guide",
html_from_markdown=document,
theme=theme,
)
except FileNotFoundError:
return abort(404)
@app.route('/games')
@@ -112,19 +115,22 @@ def games():
@app.route('/tutorial/<string:game>/<string:file>')
@cache.cached()
def tutorial(game: str, file: str):
theme = get_world_theme(game)
secure_game_name = secure_filename(game)
file = secure_filename(file)
document = render_markdown(os.path.join(
app.static_folder, "generated", "docs",
secure_game_name, file+".md"
))
return render_template(
"markdown_document.html",
title=f"{game} Guide",
html_from_markdown=document,
theme=theme,
)
try:
theme = get_world_theme(game)
secure_game_name = secure_filename(game)
file = secure_filename(file)
document = render_markdown(os.path.join(
app.static_folder, "generated", "docs",
secure_game_name, file+".md"
))
return render_template(
"markdown_document.html",
title=f"{game} Guide",
html_from_markdown=document,
theme=theme,
)
except FileNotFoundError:
return abort(404)
@app.route('/tutorial/')

View File

@@ -344,7 +344,7 @@ names, and `def can_place_boss`, which passes a boss and location, allowing you
your game. When this function is called, `bosses`, `locations`, and the passed strings will all be lowercase. There is
also a `duplicate_bosses` attribute allowing you to define if a boss can be placed multiple times in your world. False
by default, and will reject duplicate boss names from the user. For an example of using this class, refer to
`worlds.alttp.options.py`
`worlds/alttp/Options.py`
### OptionDict
This option returns a dictionary. Setting a default here is recommended as it will output the dictionary to the

View File

@@ -48,13 +48,14 @@ class TestBase(unittest.TestCase):
original_get_all_state = multiworld.get_all_state
def patched_get_all_state(use_cache: bool, allow_partial_entrances: bool = False):
def patched_get_all_state(use_cache: bool | None = None, allow_partial_entrances: bool = False,
**kwargs):
self.assertTrue(allow_partial_entrances, (
"Before the connect_entrances step finishes, other worlds might still have partial entrances. "
"As such, any call to get_all_state must use allow_partial_entrances = True."
))
return original_get_all_state(use_cache, allow_partial_entrances)
return original_get_all_state(use_cache, allow_partial_entrances, **kwargs)
multiworld.get_all_state = patched_get_all_state

View File

@@ -267,6 +267,10 @@ class DarkSouls3World(World):
# Don't allow missable duplicates of progression items to be expected progression.
if location.name in self.missable_dupe_prog_locs: continue
# Don't create DLC and NGP locations if those are disabled
if location.dlc and not self.options.enable_dlc: continue
if location.ngp and not self.options.enable_ngp: continue
# Replace non-randomized items with events that give the default item
event_item = (
self.create_item(location.default_item_name) if location.default_item_name

View File

@@ -89,11 +89,15 @@ class FF1Client(BizHawkClient):
async def validate_rom(self, ctx: "BizHawkClientContext") -> bool:
try:
if (await bizhawk.get_memory_size(ctx.bizhawk_ctx, self.rom)) < rom_name_location + 0x0D:
return False # ROM is not large enough to be a Final Fantasy 1 ROM
# Check ROM name/patch version
rom_name = ((await bizhawk.read(ctx.bizhawk_ctx, [(rom_name_location, 0x0D, self.rom)]))[0])
rom_name = rom_name.decode("ascii")
if rom_name != "FINAL FANTASY":
return False # Not a Final Fantasy 1 ROM
except UnicodeDecodeError:
return False # rom_name returned invalid text
except bizhawk.RequestFailedError:
return False # Not able to get a response, say no for now

View File

@@ -34,62 +34,75 @@ business!
## I don't know what to do!
That's not a question - but I'd suggest clicking the crow icon on your client, which will load an AP compatible autotracker for LADXR.
That's not a question - but I'd suggest clicking the **Open Tracker** button in your client, which will load an AP compatible autotracker for LADXR.
## What is this randomizer based on?
This randomizer is based on (forked from) the wonderful work daid did on LADXR - https://github.com/daid/LADXR
This randomizer is based on (forked from) the wonderful work daid did on [LADXR](https://github.com/daid/LADXR)
The autotracker code for communication with magpie tracker is directly copied from kbranch's repo - https://github.com/kbranch/Magpie/tree/master/autotracking
The autotracker code for communication with magpie tracker is directly copied from [kbranch's repo](https://github.com/kbranch/Magpie)
### Graphics
The following sprite sheets have been included with permission of their respective authors:
* by Madam Materia (https://www.twitch.tv/isabelle_zephyr)
* by [Madam Materia](https://www.twitch.tv/isabelle_zephyr)
* Matty_LA
* by Linker (https://twitter.com/BenjaminMaksym)
* Bowwow
* Bunny
* Luigi
* Mario
* Richard
* Tarin
Title screen graphics by toomanyteeth✨ (https://instagram.com/toomanyyyteeth)
Title screen graphics by [toomanyteeth✨](https://instagram.com/toomanyyyteeth)
## Some tips from LADXR...
<h3>Locations</h3>
<p>All chests and dungeon keys are always randomized. Also, the 3 songs (Marin, Mambo, and Manu) give a you an item if you present them the Ocarina. The seashell mansion 20 shells reward is also shuffled, but the 5 and 10 shell reward is not, as those can be missed.</p>
<p>The moblin cave with Bowwow contains a chest instead. The color dungeon gives 2 items at the end instead of a choice of tunic. Other item locations are: The toadstool, the reward for delivering the toadstool, hidden seashells, heart pieces, heart containers, golden leaves, the Mad Batters (capacity upgrades), the shovel/bow in the shop, the rooster's grave, and all of the keys' (tail,slime,angler,face,bird) locations.</p>
<p>Finally, new players often forget the following locations: the heart piece hidden in the water at the castle, the heart piece hidden in the bomb cave (screen before the honey), bonk seashells (run with pegasus boots against the tree in at the Tail Cave, and the tree right of Mabe Village, next to the phone booth), and the hookshop drop from Master Stalfos in D5.</p>
### Locations
<h3>Color Dungeon</h3>
<p>The Color Dungeon is part of the item shuffle, and the red/blue tunics are shuffled in the item pool. Which means the fairy at the end of the color dungeon gives out two random items.</p>
<p>To access the color dungeon, you need the power bracelet, and you need to push the gravestones in the right order: "down, left, up, right, up", going from the lower right gravestone, to the one left of it, above it, and then to the right.</p>
All chests and dungeon keys are always randomized. Also, the 3 songs (Marin, Mambo, and Manu) give a you an item if you present them the Ocarina. The seashell mansion 20 shells reward is also shuffled, but the 5 and 10 shell reward is not, as those can be missed.
<h3>Bowwow</h3>
<p>Bowwow is in a chest, somewhere. After you find him, he will always be in the swamp with you, but not anywhere else.</p>
The moblin cave with Bowwow contains a chest instead. The color dungeon gives 2 items at the end instead of a choice of tunic. Other item locations are: The toadstool, the reward for delivering the toadstool, hidden seashells, heart pieces, heart containers, golden leaves, the Mad Batters (capacity upgrades), the shovel/bow in the shop, the rooster's grave, and all of the keys' (tail,slime,angler,face,bird) locations.
<h3>Added things</h3>
<p>In your save and quit menu, there is a 3rd option to return to your home. This has two main uses: it speeds up the game, and prevents softlocks (common in entrance rando).</p>
<p>If you have weapons that require ammunition (bombs, powder, arrows), a ghost will show up inside Marin's house. He will refill you up to 10 ammunition, so you do not run out.</p>
<p>The flying rooster is (optionally) available as an item.</p>
<p>You can access the Bird Key cave item with the L2 Power Bracelet.</p>
<p>Boomerang cave is now a random item gift by default (available post-bombs), and boomerang is in the item pool.</p>
<p>Your inventory has been increased by four, to accommodate these items now coexisting with eachother.</p>
Finally, new players often forget the following locations: the heart piece hidden in the water at the castle, the heart piece hidden in the bomb cave (screen before the honey), bonk seashells (run with pegasus boots against the tree in at the Tail Cave, and the tree right of Mabe Village, next to the phone booth), and the hookshop drop from Master Stalfos in D5.
<h3>Removed things</h3>
<p>The ghost mini-quest after D4 never shows up, his seashell reward is always available.</p>
<p>The walrus is moved a bit, so that you can access the desert without taking Marin on a date.</p>
### Color Dungeon
<h3>Logic</h3>
<p>Depending on your options, you can only steal after you find the sword, always, or never.</p>
<p>Do not forget that there are two items in the rafting ride. You can access this with just Hookshot or Flippers.</p>
<p>Killing enemies with bombs is in normal logic. You can switch to casual logic if you do not want this.</p>
<p>D7 confuses some people, but by dropping down pits on the 2nd floor you can access almost all of this dungeon, even without feather and power bracelet.</p>
The Color Dungeon is part of the item shuffle, and the red/blue tunics are shuffled in the item pool. Which means the fairy at the end of the color dungeon gives out two random items.
<h3>Tech</h3>
<p>The toadstool and magic powder used to be the same type of item. LADXR turns this into two items that you can have a the same time. 4 extra item slots in your inventory were added to support this extra item, and have the ability to own the boomerang.</p>
<p>The glitch where the slime key is effectively a 6th golden leaf is fixed, and golden leaves can be collected fine next to the slime key.</p>
To access the color dungeon, you need the power bracelet, and you need to push the gravestones in the right order: "down, left, up, right, up", going from the lower right gravestone, to the one left of it, above it, and then to the right.
### Bowwow
Bowwow is in a chest, somewhere. After you find him, he will always be in the swamp with you, but not anywhere else.
### Added things
In your save and quit menu, there is a 3rd option to return to your home. This has two main uses: it speeds up the game, and prevents softlocks (common in entrance rando).
If you have weapons that require ammunition (bombs, powder, arrows), a ghost will show up inside Marin's house. He will refill you up to 10 ammunition, so you do not run out.
The flying rooster is (optionally) available as an item.
If the rooster is disabled, you can access the Bird Key cave item with the L2 Power Bracelet.
Boomerang cave is now a random item gift by default (available post-bombs), and boomerang is in the item pool.
Your inventory has been increased by four, to accommodate these items now coexisting with eachother.
### Removed things
The ghost mini-quest after D4 never shows up, his seashell reward is always available.
The walrus is moved a bit, so that you can access the desert without taking Marin on a date.
### Logic
You can only steal after you find the sword.
Do not forget that there are two items in the rafting ride. You can access this with just Hookshot or Flippers.
Killing enemies with bombs is in logic.
D7 confuses some people, but by dropping down pits on the 2nd floor you can access almost all of this dungeon, even without feather and power bracelet.
### Tech
The toadstool and magic powder used to be the same type of item. LADXR turns this into two items that you can have a the same time. 4 extra item slots in your inventory were added to support this extra item, and have the ability to own the boomerang.
The glitch where the slime key is effectively a 6th golden leaf is fixed, and golden leaves can be collected fine next to the slime key.

View File

@@ -255,8 +255,10 @@ def pair_portals(world: "TunicWorld", regions: Dict[str, Region]) -> Dict[Portal
else:
dead_ends.append(portal)
dead_end_direction_tracker[portal.direction] += 1
if portal.region == "Zig Skip Exit" and entrance_layout == EntranceLayout.option_fixed_shop:
if (portal.region == "Zig Skip Exit" and entrance_layout == EntranceLayout.option_fixed_shop
and not decoupled):
# direction isn't meaningful here since zig skip cannot be in direction pairs mode
# don't add it in decoupled
two_plus.append(portal)
# now we generate the shops and add them to the dead ends list