-
Notifications
You must be signed in to change notification settings - Fork 788
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
Final Fantasy IV Free Enterprise: Add New Game #3897
base: main
Are you sure you want to change the base?
Final Fantasy IV Free Enterprise: Add New Game #3897
Conversation
…dling doesn't support 3.10.
…or a randomizer seed.
Alrighty! Above comments have been addressed, more testing has happened, features are now where they need to be, and I'm confident everything is where it needs to be, functionally. I throw this into you all's overworked and underpaid hands to scrutinize at your leisure. |
add_rule(self.get_location(location.name), | ||
lambda state, tier=i: state.has_group("characters", | ||
self.player, | ||
FERules.logical_gating[tier]["characters"]) and | ||
state.has_group("key_items", | ||
self.player, | ||
FERules.logical_gating[tier]["key_items"])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will it create issues if someone adds a character to their start_inventory
? Since the randomizer might see "ah, you have 2 of character A and 1 of character B, so you can get this check that requires 3 characters".
If that would be an issue, you should use has_group_unique
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Characters are not unique, so it's correct to not use has_group_unique. While it's true adding them to start inventory will cause the generator to think there are checks that are now "in logic", this will have little effect in practice:
- characters in start inventory don't do anything (they're items for convenience's sake on the part of options and the code, not because they're equivalent to a Life potion or whatnot),
- the gating logic is about spreading things out so at least some progression is located in less difficult areas.
- that gating logic still requires key items as well, so nothing will change.
- and even if there were changes, it makes things slightly more difficult for the player but doesn't render the game unbeatable.
"location_data": location_data.to_json(), | ||
"item_data": ItemData.create_ap_item().to_json(), | ||
"item_name": location.item.name, | ||
"player_name": self.multiworld.player_name[location.item.player] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"player_name": self.multiworld.player_name[location.item.player] | |
"player_name": self.player_name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The placement dictionary includes names for all player's items, not just the FE player. I need to use the lookup to get those names too so text like "got Silver Sword for Player5" can be written into the game.
…nto Final-Fantasy-4-Free-Enterprise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't make it through everything, but I'm out of time for review today.
worlds/ff4fe/__init__.py
Outdated
|
||
|
||
class FF4FESettings(settings.Group): | ||
class RomFile(settings.UserFilePath): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class RomFile(settings.UserFilePath): | |
class RomFile(settings.SNESRomPath): |
Using this will automatically strip the header, so no additional hashes or manual removal of headers needed.
worlds/ff4fe/__init__.py
Outdated
settings: typing.ClassVar[FF4FESettings] | ||
|
||
web = FF4FEWebWorld() | ||
topology_present = True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK FE doesn't support any manner of entrance rando, so is this correct?
topology_present
adds the region connections to the spoiler log. If they are always static, then there is no reason for this to be true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I definitely maybe thought I had a good reason at one point, but mostly it let me confirm I set the regions and locations up correctly, so it can be removed, yeah. Will do so.
worlds/ff4fe/__init__.py
Outdated
overworld.locations.append(new_location) | ||
|
||
def create_item(self, item: str) -> FF4FEItem: | ||
item_data: ItemData = [item_data for item_data in all_items if item_data.name == item].pop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty sure this will result in a unhelpful exception if a player attempts to plando a nonsense item into FF4 (rather than telling the player that item does not exist for FF4).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
item_data: ItemData = [item_data for item_data in all_items if item_data.name == item].pop() | |
item_data: ItemData = next((item_data for item_data in all_items if item_data.name == item), None) | |
if not item_data: | |
raise Exception(f"{item} is not a valid item name for Final Fantasy 4 Free Enterprise") |
One way to solve it, but probably not the best?
worlds/ff4fe/__init__.py
Outdated
restricted_character_allow_locations = list(set(character_locations) - set(locations.restricted_character_locations)).copy() | ||
restricted_character_forbid_locations = list(set(character_locations) - set(restricted_character_allow_locations)).copy() | ||
self.random.shuffle(restricted_character_allow_locations) | ||
self.random.shuffle(restricted_character_forbid_locations) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
restricted_character_allow_locations = list(set(character_locations) - set(locations.restricted_character_locations)).copy() | |
restricted_character_forbid_locations = list(set(character_locations) - set(restricted_character_allow_locations)).copy() | |
self.random.shuffle(restricted_character_allow_locations) | |
self.random.shuffle(restricted_character_forbid_locations) | |
restricted_character_allow_locations = sorted(set(character_locations) - set(locations.restricted_character_locations)) | |
restricted_character_forbid_locations = sorted(set(character_locations) - set(restricted_character_allow_locations)) | |
self.random.shuffle(restricted_character_allow_locations) | |
self.random.shuffle(restricted_character_forbid_locations) |
The order of restricted_character_allow_locations
and restricted_character_forbid_locations
are non-deterministic here. This will cause the outcome of the following shuffle to also be non-deterministic, leading to non-determinism in character placement.
worlds/ff4fe/__init__.py
Outdated
item_pool_result = create_itempool(locations.all_locations, self) | ||
item_pool = item_pool_result[0] | ||
self.chosen_character = item_pool_result[1] | ||
self.second_character = item_pool_result[2] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
item_pool_result = create_itempool(locations.all_locations, self) | |
item_pool = item_pool_result[0] | |
self.chosen_character = item_pool_result[1] | |
self.second_character = item_pool_result[2] | |
item_pool, self.chosen_character, self.second_character = create_itempool(locations.all_locations, self) |
@@ -28,9 +29,12 @@ | |||
*multisave | |||
*.archipelago | |||
*.apsave | |||
*.BIN |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The *.BIN
ignore still needs to be added back in, even though you've included the necessary files.
FEExternalDataLoader.py
Outdated
|
||
|
||
|
||
root = tk.Tk() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is intended to be included and not just a development file, not every system has tkinter so it would need to be checked.
worlds/ff4fe/Client.py
Outdated
for sentinel in Rom.sentinel_addresses: # Defend against RAM initialized to 0xFF everywhere. | ||
sentinel_data = await snes_read(ctx, sentinel, 1) | ||
if sentinel_data is None: | ||
return | ||
sentinel_value = sentinel_data[0] | ||
if sentinel_value == 0xFF: | ||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would happen if ram is initialized to a value other than 0xFF? SNES9X initializes to 0x55, which would be valid here and trip victory if read fast enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be noted that no particular value can be checked against here, since a real SNES has effectively junk data upon initialization.
worlds/ff4fe/topology.py
Outdated
"LunarPalace" | ||
] | ||
|
||
overworld_areas = [area for area in areas if area not in [*hook_areas, *underworld_areas, *moon_areas]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
overworld_areas = [area for area in areas if area not in [*hook_areas, *underworld_areas, *moon_areas]] | |
overworld_areas = [area for area in areas if area not in [*hook_areas, *underworld_areas, *moon_areas]] | |
Updated according to review suggestion Co-authored-by: Silvris <[email protected]>
…Rosalie-A/Archipelago into Final-Fantasy-4-Free-Enterprise
Updated according to PR comments. I could click "resolve" on all of them but not sure if that's desired. I also removed the FEExternalDataLoader program in favor of |
…ed common Lark files to data to enable loading inside APWorld when built.
What is this fixing or adding?
Implementing a fork of the open source version of the Final Fantasy IV: Free Enterprise randomizer as a new game in Archipelago
How was this tested?
Multiple private beta tests, some public ones, and single player games by both myself and contributing testers.
If this makes graphical changes, please attach screenshots.
I'm putting this up as a draft for now. I still need to implement the WebWorld side of things and make proper documentation, but I figured I'd put this up now to get eyes on it for anything that needs to be changed (especially re: how I'm doing locations and rules) while I do that so I'm not just spinning my wheels when I want to work on this.