ff9mapkit 1.0.0b4__tar.gz → 1.0.0b5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/PKG-INFO +1 -1
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/__init__.py +1 -1
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/build.py +14 -3
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/config.py +120 -16
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/extract.py +15 -5
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit.egg-info/PKG-INFO +1 -1
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/pyproject.toml +1 -1
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_ate.py +17 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_setup.py +41 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_verbatim.py +59 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/LICENSE +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/README.md +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/__main__.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_animdb.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_animdb_all.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_fieldtable.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_fieldtext.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_held_poses.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_itemdb.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_modeldb.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_narrowmap_data.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_npcparams.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_regen_animdb.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_regen_animdb_all.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_regen_fieldtable.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_regen_fieldtext.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_regen_modeldb.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_regen_npcparams.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_regen_scenedb.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/_scenedb.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/abilities.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/animations.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/archetypes.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/areatitle.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/__init__.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/abilityfeatures.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/actiondelta.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/aiauthor.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/ailint.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/aipatch.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/battleai.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/battlecsv.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/battlepatch.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/build.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/camera_codec.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/camera_data.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/characterdelta.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/event_data.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/extract.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/fbx.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/reskin.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/scene_codec.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/scene_data.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/scenelint.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/seqasm.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/seqauthor.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/seqcodec.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/seqdis.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle/seqpatch.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/battle_bgm.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/binutils.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/campaign.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/catalog.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/chain.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/cli.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/__init__.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/areatitle.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/ate.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/camera.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/chest.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/choice.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/conductor.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/cutscene.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/encounter.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/entry_settle.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/equipment.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/event.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/gateway.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/inventory.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/itemdata.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/itemtext.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/jump.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/ladder.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/movement.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/music.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/npc.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/object.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/onentry.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/party.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/pathfind.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/platform.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/player.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/prop.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/region.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/reinit.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/savepoint.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/shop.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/sps_trigger.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/startup.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/synthesis.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/text.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/textcarry.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/verbatim.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/content/walkmesh_hotfix.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/data/__init__.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/data/_regen_provenance.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/data/provenance/blank.es.patch +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/data/provenance/blank.fr.patch +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/data/provenance/blank.gr.patch +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/data/provenance/blank.it.patch +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/data/provenance/blank.jp.patch +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/data/provenance/blank.uk.patch +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/data/provenance/blank.us.patch +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/data/provenance/manifest.json +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/data/provenance/region_template.patch +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/data/reference_arcs.toml +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/data/region_catalog.toml +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/deploystack.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/dialogue.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/eb/__init__.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/eb/_exprtable.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/eb/_membertable.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/eb/_optables.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/eb/_regen_optables.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/eb/cmdasm.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/eb/disasm.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/eb/edit.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/eb/exprasm.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/eb/model.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/eb/opcodes.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/eblint.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/editor/__init__.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/editor/app.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/editor/battle_forms.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/editor/breadcrumb.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/editor/dialogs.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/editor/feedback.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/editor/forms.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/editor/graphview.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/editor/jobs.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/editor/model.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/editor/picker.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/editor/theme.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/eventscan.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/flags.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/forkreport.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/hub.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/idgated.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/infohub.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/items.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/itemstats.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/journey.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/keyitems.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/logic_add.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/logic_edit.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/logic_map.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/memoria.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/pack.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/playerswap.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/prop_archetypes.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/provision.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/refarc.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/save.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/save_items.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/scene/__init__.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/scene/arena.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/scene/bgart.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/scene/bgi.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/scene/bgs.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/scene/bgx.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/scene/cam.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/scene/guide.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/scene/paint.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/scene/placeholder.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/sjbinary.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/sps/__init__.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/sps/author.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/sps/catalog.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/sps/codec.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/sps/edit.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/sps/lint.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/sps/render.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/sps/templates.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/sps/texture.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/walkmesh_hotfixes.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/workspace/__init__.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/workspace/battledoc.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/workspace/builddoc.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/workspace/forms_qt.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/workspace/importdoc.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/workspace/mapview.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/workspace/palette.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/workspace/savedoc.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/workspace/shell.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/workspace/style.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit/workspace/tuningdialog.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit.egg-info/SOURCES.txt +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit.egg-info/dependency_links.txt +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit.egg-info/entry_points.txt +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit.egg-info/requires.txt +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/ff9mapkit.egg-info/top_level.txt +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/setup.cfg +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_abilities.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_abilityfeatures.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_actiondelta.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_ai_phase_insert.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_ai_phase_insert_adversary.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_aiauthor.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_ailint.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_aipatch.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_animations.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_archetypes.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_areatitle.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_arming.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_battle.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_battle_bgm.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_battle_forms.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_battle_scene_codec.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_battle_seq.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_battleai.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_battlecsv.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_battlepatch.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_bgart.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_bgs.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_build.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_cameras.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_campaign.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_capstone.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_carry_text_lint.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_catalog.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_chain.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_characterdelta.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_choice.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_cli_entry.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_cmdasm.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_cmdasm_relocate.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_content.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_deploy_campaign.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_deploystack.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_dialogue.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_eb.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_eblint.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_editor_app.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_editor_breadcrumb.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_editor_feedback.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_editor_forms.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_editor_integration.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_editor_jobs.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_editor_model.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_editor_theme.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_entry_settle.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_eventscan.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_export.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_exprasm.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_extract_area.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_find_field.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_flags.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_forkreport.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_gateway_advance.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_graphview.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_hub_gen.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_idgated.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_import_borrow.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_infohub.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_itemdata.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_items.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_itemstats.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_itemtext.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_journey.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_journey_merge.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_jump.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_ladder.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_lint.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_logic_add.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_logic_edit.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_logic_map.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_movement.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_npc_model.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_npc_verbatim.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_npcparams.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_object_graft.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_occlusion.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_on_entry.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_pack.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_paint.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_party.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_platform.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_player_graft.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_playerswap.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_prop_archetypes.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_provision.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_refarc.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_repaint_native.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_reskin.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_save.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_save_items.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_savepoint.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_scene.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_scenelint.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_scroll.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_shared_text_block.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_shop.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_showcase.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_sjbinary.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_spawn.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_sps.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_startstate.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_startup.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_synthesis.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_text.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_textcarry.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_walkmesh_hotfix.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_workspace_style.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_world_hub.py +0 -0
- {ff9mapkit-1.0.0b4 → ff9mapkit-1.0.0b5}/tests/test_yaw_movement.py +0 -0
|
@@ -15,4 +15,4 @@ Public surface is organized as:
|
|
|
15
15
|
ff9mapkit.battle — the battle.toml -> custom battle-background (BBG) builder (fork/edit/build a 3D battle map)
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
__version__ = "1.0.
|
|
18
|
+
__version__ = "1.0.0b5" # keep in lockstep with [project] version in pyproject.toml
|
|
@@ -1839,6 +1839,16 @@ def lint_logic(project: FieldProject) -> list[str]:
|
|
|
1839
1839
|
for ln in _text.overflow_lines(t, wrap):
|
|
1840
1840
|
out.append(f"{who} has a word too wide to fit one line ({ln!r}) -- it will overflow; "
|
|
1841
1841
|
f"shorten it or raise [dialogue] wrap.")
|
|
1842
|
+
# DEPRECATION: `[cutscene] ate = true` is the OLD, unfaithful forced-ATE model -- a grey banner held over
|
|
1843
|
+
# THIS in-place cutscene. A real grey ATE WARPS you to a dedicated scene and back (verified vs 6 real grey
|
|
1844
|
+
# ATEs; see project-ff9-ate-system). Steer to the faithful trigger; the held-banner still builds (not an error).
|
|
1845
|
+
_cs = raw.get("cutscene")
|
|
1846
|
+
if isinstance(_cs, dict) and _cs.get("ate"):
|
|
1847
|
+
out.append("[cutscene] ate = true is the OLD held-banner ATE styling (a grey banner over this in-place "
|
|
1848
|
+
"cutscene) -- NOT how a real grey ATE works (it WARPS you to a scene, plays it, and warps you "
|
|
1849
|
+
"back). For a faithful forced ATE use `[[gateway]] ate = true` (the warp-in trigger: banner "
|
|
1850
|
+
"warning + centered title window, then the warp) + a plain [cutscene] + exit_warp on the "
|
|
1851
|
+
"destination field. This held-banner flavor still builds, but it isn't faithful.")
|
|
1842
1852
|
|
|
1843
1853
|
# reference-data sanity (Info Hub): an [[npc]] model id / animation id the engine won't recognise.
|
|
1844
1854
|
# A model NAME is handled by validate() (fatal); here we WARN on a raw id outside the known tables
|
|
@@ -3183,9 +3193,10 @@ _UID_HOTFIX_DONORS = frozenset((900, 2803))
|
|
|
3183
3193
|
|
|
3184
3194
|
|
|
3185
3195
|
def _verbatim_donor_id(project: FieldProject):
|
|
3186
|
-
"""Best-effort donor field id of
|
|
3187
|
-
records it as ``[verbatim_eb] donor
|
|
3188
|
-
|
|
3196
|
+
"""Best-effort donor field id of ANY fork (verbatim OR native/synth), for engine-hotfix warnings AND the
|
|
3197
|
+
deploy-time ForkDonorPatch `<forkId> <donorId>` mapping. The import records it as ``[verbatim_eb] donor``
|
|
3198
|
+
(verbatim) or ``[field] source_field`` (native/synth); ``borrow_field`` is the BG-borrow form. ``None``
|
|
3199
|
+
when an older fork's toml lacks it (the warn/emit is then skipped -- pre-record forks need a hand-added line)."""
|
|
3189
3200
|
for blk, key in (("verbatim_eb", "donor"), ("field", "source_field"), ("field", "borrow_field")):
|
|
3190
3201
|
v = (project.raw.get(blk) or {}).get(key)
|
|
3191
3202
|
if isinstance(v, bool):
|
|
@@ -46,6 +46,15 @@ _COMMON_STEAM_PATHS = (
|
|
|
46
46
|
r"D:\SteamLibrary\steamapps\common\FINAL FANTASY IX",
|
|
47
47
|
)
|
|
48
48
|
|
|
49
|
+
# FF9 store identifiers -- used to read the per-game install path from the Windows registry (the SAME keys
|
|
50
|
+
# Memoria's patcher reads, so we resolve exactly the folder it patches -- correct even on a secondary drive
|
|
51
|
+
# / custom Steam library). Steam + GOG are the same Unity port with an identical on-disk layout; the
|
|
52
|
+
# Microsoft Store / Xbox Game Pass build is a different, non-Unity, DRM-locked package Memoria can't patch,
|
|
53
|
+
# so the detector never targets it. Refs: Albeoris/Memoria Memoria.Patcher/GameInfo/.
|
|
54
|
+
_STEAM_APPID = "377840"
|
|
55
|
+
_GOG_GAMEID = "1375008492"
|
|
56
|
+
_FF9_DIRNAME = "FINAL FANTASY IX"
|
|
57
|
+
|
|
49
58
|
|
|
50
59
|
class ConfigError(RuntimeError):
|
|
51
60
|
"""Raised when a required path cannot be resolved or does not exist."""
|
|
@@ -80,34 +89,129 @@ def save_game_path(game_path: str | os.PathLike) -> Path:
|
|
|
80
89
|
return USER_CONFIG
|
|
81
90
|
|
|
82
91
|
|
|
92
|
+
def _is_ff9_root(p: Path) -> bool:
|
|
93
|
+
"""True if ``p`` is a real, MODDABLE FF9 install (Steam or GOG -- same layout). Keys off Memoria's own
|
|
94
|
+
sentinel (``FF9_Launcher.exe``) plus ``StreamingAssets`` and the managed-DLL tree -- which also rejects
|
|
95
|
+
the un-moddable Microsoft Store build (no launcher / no Managed dir) and stale empty folders."""
|
|
96
|
+
try:
|
|
97
|
+
return ((p / "FF9_Launcher.exe").is_file()
|
|
98
|
+
and (p / "StreamingAssets").is_dir()
|
|
99
|
+
and ((p / "x64" / "FF9_Data" / "Managed").is_dir()
|
|
100
|
+
or (p / "x86" / "FF9_Data" / "Managed").is_dir()))
|
|
101
|
+
except OSError:
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _reg_str(hive, subkey: str, value: str) -> str | None:
|
|
106
|
+
"""Read one registry string value, trying the 64-bit THEN 32-bit view (FF9's keys live under
|
|
107
|
+
``WOW6432Node`` on 64-bit Windows). Windows-only; returns None elsewhere or if the key/value is absent."""
|
|
108
|
+
if os.name != "nt":
|
|
109
|
+
return None
|
|
110
|
+
import winreg # noqa: PLC0415 - Windows-only, lazy
|
|
111
|
+
for view in (winreg.KEY_WOW64_64KEY, winreg.KEY_WOW64_32KEY):
|
|
112
|
+
try:
|
|
113
|
+
with winreg.OpenKeyEx(hive, subkey, 0, winreg.KEY_READ | view) as key:
|
|
114
|
+
data, _ = winreg.QueryValueEx(key, value)
|
|
115
|
+
if data:
|
|
116
|
+
return str(data)
|
|
117
|
+
except OSError:
|
|
118
|
+
continue
|
|
119
|
+
return None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _registry_candidates() -> list[Path]:
|
|
123
|
+
"""FF9 roots from the per-game Steam + GOG registry keys (the exact keys Memoria reads). These point at
|
|
124
|
+
the ACTUAL install dir, so they find FF9 even on a secondary drive or a custom-named Steam library."""
|
|
125
|
+
if os.name != "nt":
|
|
126
|
+
return []
|
|
127
|
+
import winreg # noqa: PLC0415
|
|
128
|
+
out: list[Path] = []
|
|
129
|
+
steam = _reg_str(winreg.HKEY_LOCAL_MACHINE,
|
|
130
|
+
rf"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App {_STEAM_APPID}",
|
|
131
|
+
"InstallLocation")
|
|
132
|
+
if steam:
|
|
133
|
+
out.append(Path(steam))
|
|
134
|
+
gog = _reg_str(winreg.HKEY_LOCAL_MACHINE, rf"SOFTWARE\GOG.com\Games\{_GOG_GAMEID}", "path")
|
|
135
|
+
if gog:
|
|
136
|
+
out.append(Path(gog))
|
|
137
|
+
return out
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _parse_vdf_library_paths(text: str) -> list[str]:
|
|
141
|
+
"""Library-folder paths from a Steam ``libraryfolders.vdf`` -- handles both the old ``"1" "<path>"`` and
|
|
142
|
+
the new ``"path" "<path>"`` schemas (and ignores the new schema's ``"apps"`` appid->buildid map). The
|
|
143
|
+
file doubles its backslashes, so they're unescaped here."""
|
|
144
|
+
keyed = re.findall(r'"path"\s+"([^"]+)"', text) if '"path"' in text \
|
|
145
|
+
else re.findall(r'"\d+"\s+"([^"]+)"', text)
|
|
146
|
+
return [p.replace("\\\\", "\\") for p in keyed]
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _steam_library_candidates() -> list[Path]:
|
|
150
|
+
"""FF9 under every Steam library (a fallback when the per-game Uninstall key is missing): locate Steam
|
|
151
|
+
via the registry, parse ``libraryfolders.vdf``, and join ``steamapps/common/FINAL FANTASY IX``."""
|
|
152
|
+
if os.name != "nt":
|
|
153
|
+
return []
|
|
154
|
+
import winreg # noqa: PLC0415
|
|
155
|
+
steam = (_reg_str(winreg.HKEY_CURRENT_USER, r"Software\Valve\Steam", "SteamPath")
|
|
156
|
+
or _reg_str(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\WOW6432Node\Valve\Steam", "InstallPath"))
|
|
157
|
+
if not steam:
|
|
158
|
+
return []
|
|
159
|
+
steam_dir = Path(steam)
|
|
160
|
+
out: list[Path] = [steam_dir / "steamapps" / "common" / _FF9_DIRNAME]
|
|
161
|
+
for vdf in (steam_dir / "steamapps" / "libraryfolders.vdf", steam_dir / "config" / "libraryfolders.vdf"):
|
|
162
|
+
try:
|
|
163
|
+
text = vdf.read_text(encoding="utf-8", errors="ignore")
|
|
164
|
+
except OSError:
|
|
165
|
+
continue
|
|
166
|
+
for lib in _parse_vdf_library_paths(text):
|
|
167
|
+
out.append(Path(lib) / "steamapps" / "common" / _FF9_DIRNAME)
|
|
168
|
+
return out
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _fallback_candidates() -> list[Path]:
|
|
172
|
+
"""Last-resort default install folders (Steam + GOG) if registry/library lookups don't resolve."""
|
|
173
|
+
gog = [Path(b) / _FF9_DIRNAME for b in
|
|
174
|
+
(r"C:\GOG Games", r"D:\GOG Games", r"C:\Program Files (x86)\GOG Galaxy\Games")]
|
|
175
|
+
return [Path(p) for p in _COMMON_STEAM_PATHS] + gog
|
|
176
|
+
|
|
177
|
+
|
|
83
178
|
def find_game_path(explicit: str | os.PathLike | None = None) -> Path:
|
|
84
179
|
"""Resolve the Final Fantasy IX install folder.
|
|
85
180
|
|
|
86
|
-
Order: explicit arg >
|
|
87
|
-
|
|
181
|
+
Order: explicit arg > ``$FF9_GAME_PATH`` > ``~/.ff9mapkit.toml`` (``game_path``) > auto-detect. The
|
|
182
|
+
auto-detector mirrors Memoria's: the per-game Steam + GOG registry keys, then a Steam-library scan, then
|
|
183
|
+
the common default folders. Explicit/env/config paths are trusted if they exist; auto-detected ones are
|
|
184
|
+
validated as a real, moddable FF9 install (which also skips the un-moddable Microsoft Store build).
|
|
185
|
+
Raises ConfigError with actionable guidance if nothing resolves.
|
|
88
186
|
"""
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
env = os.environ.get("FF9_GAME_PATH")
|
|
93
|
-
if env:
|
|
94
|
-
candidates.append(Path(env))
|
|
95
|
-
cfg = _read_user_config().get("game_path")
|
|
96
|
-
if cfg:
|
|
97
|
-
candidates.append(Path(cfg))
|
|
98
|
-
candidates.extend(Path(p) for p in _COMMON_STEAM_PATHS)
|
|
99
|
-
|
|
100
|
-
for c in candidates:
|
|
187
|
+
# 1) user-specified -- trusted on existence
|
|
188
|
+
for c in (Path(p) for p in (explicit, os.environ.get("FF9_GAME_PATH"),
|
|
189
|
+
_read_user_config().get("game_path")) if p):
|
|
101
190
|
if c.is_dir():
|
|
102
191
|
return c.resolve()
|
|
103
192
|
|
|
193
|
+
# 2) auto-detect Steam + GOG, validated as a real install; de-dupe by resolved path
|
|
194
|
+
seen: set[Path] = set()
|
|
195
|
+
for c in _registry_candidates() + _steam_library_candidates() + _fallback_candidates():
|
|
196
|
+
try:
|
|
197
|
+
rc = c.resolve()
|
|
198
|
+
except OSError:
|
|
199
|
+
continue
|
|
200
|
+
if rc in seen:
|
|
201
|
+
continue
|
|
202
|
+
seen.add(rc)
|
|
203
|
+
if _is_ff9_root(c):
|
|
204
|
+
return rc
|
|
205
|
+
|
|
104
206
|
raise ConfigError(
|
|
105
|
-
"Could not locate the Final Fantasy IX install folder
|
|
207
|
+
"Could not locate the Final Fantasy IX install folder (checked Steam + GOG via the registry,\n"
|
|
208
|
+
"the Steam libraries, and the common install paths).\n"
|
|
106
209
|
"Set it one of these ways:\n"
|
|
107
210
|
" - pass --game \"<path>\" on the command line\n"
|
|
108
211
|
" - export FF9_GAME_PATH=\"<path>\"\n"
|
|
109
212
|
f" - add game_path = \"<path>\" to {USER_CONFIG}\n"
|
|
110
|
-
"The folder should contain FF9_Launcher.exe and a StreamingAssets directory
|
|
213
|
+
"The folder should contain FF9_Launcher.exe and a StreamingAssets directory.\n"
|
|
214
|
+
"(The Microsoft Store / Xbox Game Pass version is not moddable -- use the Steam or GOG release.)"
|
|
111
215
|
)
|
|
112
216
|
|
|
113
217
|
|
|
@@ -1829,6 +1829,16 @@ def write_native_project(field: str, out_dir, *, name: str | None = None, field_
|
|
|
1829
1829
|
wb = meta["walkmesh_bounds"]
|
|
1830
1830
|
x, z = meta["player_start"]
|
|
1831
1831
|
scroll = "[camera.scroll]\nenabled = true\n" if meta["scrolling"] else ""
|
|
1832
|
+
# The donor's REAL field id (FBG -> id): a fork MIRRORS this field's geometry, so deploy auto-emits the
|
|
1833
|
+
# ForkDonorPatch `<forkId> <donorId>` -> the engine's name-keyed fidelity (s31 occlusion z-offset,
|
|
1834
|
+
# FieldLocationName) resolves for the custom id. Recorded as `[verbatim_eb] donor` (verbatim) OR
|
|
1835
|
+
# `[field] source_field` (native/synth) -- both read by build._verbatim_donor_id + emitted by deploy_field.
|
|
1836
|
+
from .dialogue import _resolve_field_id as _rfi
|
|
1837
|
+
try:
|
|
1838
|
+
_src_fid = _rfi(field)
|
|
1839
|
+
except (FileNotFoundError, ValueError):
|
|
1840
|
+
_src_fid = None
|
|
1841
|
+
source_field_line = ""
|
|
1832
1842
|
if verbatim:
|
|
1833
1843
|
# VERBATIM .eb fork (docs/FORK_FIDELITY.md, the entry-0 carry): ship the donor's WHOLE event script;
|
|
1834
1844
|
# the build runs the real logic instead of synthesizing. No declarative content (it's all in the .eb).
|
|
@@ -1845,11 +1855,7 @@ def write_native_project(field: str, out_dir, *, name: str | None = None, field_
|
|
|
1845
1855
|
# Donor battle BGM: a verbatim fork carries the real Battle()/BattleEx() ops, but its custom id misses
|
|
1846
1856
|
# the engine's (fldMapNo, scene) song lookup -> the boss/special theme is lost. Auto-emit [[battle_bgm]]
|
|
1847
1857
|
# for the donor's scripted battle scenes whose song is non-zero (build -> a scene-keyed Music: line).
|
|
1848
|
-
|
|
1849
|
-
try:
|
|
1850
|
-
_donor_fid = _resolve_field_id(field)
|
|
1851
|
-
except (FileNotFoundError, ValueError):
|
|
1852
|
-
_donor_fid = None
|
|
1858
|
+
_donor_fid = _src_fid
|
|
1853
1859
|
bgm_pairs = _donor_battle_bgm_pairs(donor_eb, _donor_fid, game)
|
|
1854
1860
|
bgm_blocks = _render_battle_bgm_blocks(bgm_pairs)
|
|
1855
1861
|
# retarget the Field() exits: import-chain pre-fills a LIVE table (doors warp into the chain's own
|
|
@@ -1894,6 +1900,9 @@ def write_native_project(field: str, out_dir, *, name: str | None = None, field_
|
|
|
1894
1900
|
field, game, out_dir=out, name=name, id_remap=id_remap, live_seams=live_seams,
|
|
1895
1901
|
graft_player_funcs=graft_player_funcs, carry_text=carry_text, graft_savepoint=graft_savepoint)
|
|
1896
1902
|
meta["imported_content"] = content_summary
|
|
1903
|
+
if _src_fid is not None and _src_fid != field_id: # record the donor -> deploy auto-emits ForkDonorPatch
|
|
1904
|
+
source_field_line = (f"source_field = {_src_fid} # the real field this NATIVE fork mirrors; deploy "
|
|
1905
|
+
f"emits ForkDonorPatch so name-keyed fidelity (occlusion/location) resolves\n")
|
|
1897
1906
|
control_line = (f"control_direction = {control_dir} # imported WASD-vs-camera tuning\n"
|
|
1898
1907
|
if control_dir is not None else "")
|
|
1899
1908
|
content_tail = (
|
|
@@ -1913,6 +1922,7 @@ def write_native_project(field: str, out_dir, *, name: str | None = None, field_
|
|
|
1913
1922
|
f'name = "{name}"\n'
|
|
1914
1923
|
f"area = {safe_area}\n"
|
|
1915
1924
|
f"text_block = {text_block}\n"
|
|
1925
|
+
f"{source_field_line}"
|
|
1916
1926
|
f"{_walkmesh_hotfix_line(field)}"
|
|
1917
1927
|
f"{_area_title_hide_lines(meta, verbatim=verbatim)}"
|
|
1918
1928
|
f'bgs = "scene.bgs.bytes" # NATIVE scene (per-tile depth) -> seamless render, NO .bgx / no tile seams\n'
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ff9mapkit"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.0b5"
|
|
8
8
|
description = "Author novel custom field maps for Final Fantasy IX (Memoria engine) from a declarative TOML project file."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11" # tomllib is stdlib from 3.11
|
|
@@ -369,3 +369,20 @@ def _w(tmp_path, toml):
|
|
|
369
369
|
p = tmp_path / "ok.field.toml"
|
|
370
370
|
p.write_text(toml, encoding="utf-8")
|
|
371
371
|
return p
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def test_legacy_cutscene_ate_is_deprecated(tmp_path):
|
|
375
|
+
"""`[cutscene] ate = true` (the OLD held-banner model) now lint-warns toward the faithful `[[gateway]] ate`
|
|
376
|
+
warp-in trigger -- it still builds (a warning, not an error)."""
|
|
377
|
+
from ff9mapkit.build import FieldProject, lint_logic, validate
|
|
378
|
+
base = ('[field]\nid = 4003\nname = "D"\narea = 11\ntext_block = 1073\n\n'
|
|
379
|
+
'[camera]\npitch = 45\nfov = 42.2\n\n'
|
|
380
|
+
'[walkmesh]\nquad = [[-200,-200],[200,-200],[200,200],[-200,200]]\n\n'
|
|
381
|
+
'[player]\nspawn = [0, 0]\n\n')
|
|
382
|
+
p = tmp_path / "d.field.toml"
|
|
383
|
+
p.write_text(base + '[cutscene]\nate = true\nsteps = [ { say = "An ATE." } ]\n', encoding="utf-8")
|
|
384
|
+
proj = FieldProject.load(p)
|
|
385
|
+
assert any("held-banner" in w and "[[gateway]] ate" in w for w in lint_logic(proj))
|
|
386
|
+
assert validate(proj) == [] # deprecated, but still valid (warning, not error)
|
|
387
|
+
p.write_text(base + '[cutscene]\nsteps = [ { say = "Hi." } ]\n', encoding="utf-8") # no ate -> no warning
|
|
388
|
+
assert not any("held-banner" in w for w in lint_logic(FieldProject.load(p)))
|
|
@@ -132,3 +132,44 @@ def test_install_engine_refuses_without_memoria(tmp_path):
|
|
|
132
132
|
def test_bundle_missing_dll_raises(tmp_path):
|
|
133
133
|
with pytest.raises(ValueError):
|
|
134
134
|
memoria.bundle_dll_members(_make_bundle(tmp_path, complete=False))
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
# ---- game-install detection (Steam + GOG; rejects MS Store) ----------------------------------------
|
|
138
|
+
def _make_ff9_root(tmp_path, *, launcher=True, streaming=True, managed=True):
|
|
139
|
+
root = tmp_path / "FINAL FANTASY IX"
|
|
140
|
+
root.mkdir(parents=True, exist_ok=True)
|
|
141
|
+
if launcher:
|
|
142
|
+
(root / "FF9_Launcher.exe").write_bytes(b"")
|
|
143
|
+
if streaming:
|
|
144
|
+
(root / "StreamingAssets").mkdir(exist_ok=True)
|
|
145
|
+
if managed:
|
|
146
|
+
(root / "x64" / "FF9_Data" / "Managed").mkdir(parents=True, exist_ok=True)
|
|
147
|
+
return root
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def test_is_ff9_root_accepts_real_layout(tmp_path):
|
|
151
|
+
assert config._is_ff9_root(_make_ff9_root(tmp_path)) is True
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def test_is_ff9_root_rejects_incomplete(tmp_path):
|
|
155
|
+
assert config._is_ff9_root(_make_ff9_root(tmp_path / "a", launcher=False)) is False # MS Store-like
|
|
156
|
+
assert config._is_ff9_root(_make_ff9_root(tmp_path / "b", streaming=False)) is False
|
|
157
|
+
assert config._is_ff9_root(_make_ff9_root(tmp_path / "c", managed=False)) is False
|
|
158
|
+
assert config._is_ff9_root(tmp_path / "nope") is False
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def test_parse_vdf_new_schema():
|
|
162
|
+
text = (
|
|
163
|
+
'"libraryfolders"\n{\n'
|
|
164
|
+
' "0"\n {\n'
|
|
165
|
+
' "path" "C:\\\\Program Files (x86)\\\\Steam"\n'
|
|
166
|
+
' "apps" { "377840" "12345678" }\n' # appid->buildid must NOT be read as a library
|
|
167
|
+
' }\n'
|
|
168
|
+
' "1"\n {\n "path" "E:\\\\SteamLibrary"\n }\n}\n'
|
|
169
|
+
)
|
|
170
|
+
assert config._parse_vdf_library_paths(text) == [r"C:\Program Files (x86)\Steam", r"E:\SteamLibrary"]
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def test_parse_vdf_old_schema():
|
|
174
|
+
text = '"LibraryFolders"\n{\n "1" "E:\\\\Games\\\\Steam"\n "2" "F:\\\\Steam"\n}\n'
|
|
175
|
+
assert config._parse_vdf_library_paths(text) == [r"E:\Games\Steam", r"F:\Steam"]
|
|
@@ -90,6 +90,21 @@ def test_remap_fields_patches_destinations():
|
|
|
90
90
|
assert _vb.remap_fields(eb, {}) == eb
|
|
91
91
|
|
|
92
92
|
|
|
93
|
+
def test_fork_donor_id_reads_native_source_field():
|
|
94
|
+
"""deploy_field auto-emits ForkDonorPatch for NATIVE/SYNTH forks too: build._verbatim_donor_id resolves the
|
|
95
|
+
donor from `[field] source_field` (the native import's record), not only `[verbatim_eb] donor`."""
|
|
96
|
+
from ff9mapkit.build import _verbatim_donor_id
|
|
97
|
+
|
|
98
|
+
class _P:
|
|
99
|
+
def __init__(self, raw):
|
|
100
|
+
self.raw = raw
|
|
101
|
+
|
|
102
|
+
assert _verbatim_donor_id(_P({"field": {"source_field": 351}})) == 351 # native fork
|
|
103
|
+
assert _verbatim_donor_id(_P({"verbatim_eb": {"donor": 1860}})) == 1860 # verbatim fork (unchanged)
|
|
104
|
+
assert _verbatim_donor_id(_P({"field": {"borrow_field": 100}})) == 100 # BG-borrow form
|
|
105
|
+
assert _verbatim_donor_id(_P({"field": {}})) is None # a non-fork synth field -> no emit
|
|
106
|
+
|
|
107
|
+
|
|
93
108
|
def _game_ready():
|
|
94
109
|
try:
|
|
95
110
|
import UnityPy # noqa: F401,PLC0415
|
|
@@ -136,6 +151,22 @@ def test_import_verbatim_ships_the_whole_donor_eb(tmp_path):
|
|
|
136
151
|
assert 4100 in _fields(shipped) and exits[0] not in _fields(shipped)
|
|
137
152
|
|
|
138
153
|
|
|
154
|
+
@pytest.mark.skipif(not _game_ready(), reason="needs the FF9 install + UnityPy")
|
|
155
|
+
def test_native_import_records_donor_for_forkdonorpatch(tmp_path):
|
|
156
|
+
# A NATIVE (non-verbatim) import now records `[field] source_field = <donor real id>`, so deploy_field can
|
|
157
|
+
# auto-emit ForkDonorPatch (name-keyed occlusion/location fidelity) -- no more hand-written `<fork> <donor>`.
|
|
158
|
+
from ff9mapkit import extract
|
|
159
|
+
from ff9mapkit.build import FieldProject, _verbatim_donor_id
|
|
160
|
+
from ff9mapkit.dialogue import _resolve_field_id
|
|
161
|
+
fbg = "fbg_n06_vgdl_map101_dl_inn_0"
|
|
162
|
+
donor = _resolve_field_id(fbg)
|
|
163
|
+
_m, toml = extract.write_native_project(fbg, tmp_path, name="DV") # native scene, NOT verbatim
|
|
164
|
+
proj = FieldProject.load(toml)
|
|
165
|
+
assert "verbatim_eb" not in proj.raw # it's a native fork
|
|
166
|
+
assert proj.raw["field"].get("source_field") == donor # donor recorded in [field]
|
|
167
|
+
assert _verbatim_donor_id(proj) == donor # -> deploy_field emits ForkDonorPatch
|
|
168
|
+
|
|
169
|
+
|
|
139
170
|
@pytest.mark.skipif(not _game_ready(), reason="needs the FF9 install + UnityPy")
|
|
140
171
|
def test_build_field_verbatim_with_logic_edit_end_to_end(tmp_path):
|
|
141
172
|
# REGRESSION: a FULL build of a verbatim fork must run build_field's per-language loop (which reads
|
|
@@ -374,6 +405,34 @@ def test_build_field_verbatim_player_walk_end_to_end(tmp_path):
|
|
|
374
405
|
assert (2, 250, 20) in calls # conductor RunScriptSync(2, player=250, 20)
|
|
375
406
|
|
|
376
407
|
|
|
408
|
+
@pytest.mark.skipif(not _game_ready(), reason="needs the FF9 install + UnityPy")
|
|
409
|
+
def test_build_field_verbatim_conductor_exit_warp_end_to_end(tmp_path):
|
|
410
|
+
# A conductor on a verbatim fork with `exit_warp`: the below-band director ENDS with a fade + Field(target)
|
|
411
|
+
# (the warp-back) instead of EnableMove -- the player is warped out after the scene (the same lever the
|
|
412
|
+
# forced-ATE scene uses to return the player). exit_warp sits OUTSIDE the once-gate so it always fires.
|
|
413
|
+
from ff9mapkit import build, extract
|
|
414
|
+
from ff9mapkit.eb import EbScript
|
|
415
|
+
from ff9mapkit.content import object as _object
|
|
416
|
+
_meta, toml = extract.write_native_project("fbg_n06_vgdl_map101_dl_inn_0", tmp_path, name="DV", verbatim=True)
|
|
417
|
+
donor = EbScript.from_bytes(extract.extract_event_script("fbg_n06_vgdl_map101_dl_inn_0"))
|
|
418
|
+
project = build.FieldProject.load(toml)
|
|
419
|
+
project.raw["npc"] = [{"name": "lefty", "preset": "vivi", "pos": [100, 200], "dialogue": "."}]
|
|
420
|
+
project.raw["cutscene"] = {"once": True, "actor": ["lefty"], "exit_warp": 1153,
|
|
421
|
+
"steps": [{"actor": "lefty", "say": "The scene ends -- and out you go."}]}
|
|
422
|
+
assert build.validate(project) == []
|
|
423
|
+
out = tmp_path / "mod"
|
|
424
|
+
build.build_mod([project], out, mod_name="FF9CustomMap") # must not raise
|
|
425
|
+
band_lo = donor.entry_count - _object.PARTY_BAND_SIZE # lefty=band_lo, conductor=band_lo+1
|
|
426
|
+
ebs = [p for p in out.rglob("*.eb.bytes")]
|
|
427
|
+
assert ebs
|
|
428
|
+
for p in ebs:
|
|
429
|
+
s = EbScript.from_bytes(p.read_bytes())
|
|
430
|
+
cond = s.entry(band_lo + 1).func_by_tag(0)
|
|
431
|
+
ops = [i.op for i in s.instrs(cond)]
|
|
432
|
+
assert 1153 in [i.imm(0) for i in s.instrs(cond) if i.op == 0x2B] # ends with Field(exit_warp) -- the warp-back
|
|
433
|
+
assert 0x2E not in ops # NO EnableMove (the destination restores control)
|
|
434
|
+
|
|
435
|
+
|
|
377
436
|
@pytest.mark.skipif(not _game_ready(), reason="needs the FF9 install + UnityPy")
|
|
378
437
|
def test_build_field_verbatim_with_readable_prop_end_to_end(tmp_path):
|
|
379
438
|
# A readable [[prop]] (dialogue=) ADDED to a verbatim fork: the below-band prop object is NON-bare -- it
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|