diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..9d140eb --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,5 @@ + diff --git a/.github/verify_newsfragments.py b/.github/verify_newsfragments.py new file mode 100644 index 0000000..d8c7a53 --- /dev/null +++ b/.github/verify_newsfragments.py @@ -0,0 +1,29 @@ +import re +import sys +from os import listdir +from pathlib import Path + +NEWS_TYPES = ("feature", "bugfix", "doc", "removal", "misc") + +NEWS_PATTERN = re.compile(r"(\d+|\+.+)\.(" + "|".join(NEWS_TYPES) + r")\.md") + +NEWSFRAGMENTS_FIR = Path(__file__).parent.parent / "Dolphin scripts" / \ + "Entrance Randomizer" / "newsfragments" + + +def main(): + invalid_filenames = [ + filename for filename + in listdir(NEWSFRAGMENTS_FIR) + if not NEWS_PATTERN.fullmatch(filename) + ] + + if invalid_filenames: + sys.exit( + "The following newsfragments don't match the " + + f"{NEWS_PATTERN} pattern: {invalid_filenames}", + ) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/pack-randomizer-release.yaml b/.github/workflows/pack-randomizer-release.yaml new file mode 100644 index 0000000..bbd93a1 --- /dev/null +++ b/.github/workflows/pack-randomizer-release.yaml @@ -0,0 +1,46 @@ +name: Pack Randomizer (Release) + +on: + workflow_dispatch: # Allows manual triggers + push: + branches: + - main + paths: + # Release trigger + - "Dolphin scripts/Entrance Randomizer/CHANGELOG.md" + pull_request: + branches: + - main + paths: + # Release tooling + - "Dolphin scripts/pack-rando.ps1" + - ".github/workflows/pack-randomizer-release.yaml" + +env: + PIP_DISABLE_PIP_VERSION_CHECK: 1 + FORCE_COLOR: 1 + +jobs: + pack: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: '& "Dolphin scripts/pack-rando.ps1" -Release' + shell: pwsh + # upload-artifact will double zip, so unpack first + # https://github.com/actions/upload-artifact/issues/39 + - name: Get pack filename + id: packname + run: | + echo "packname=$( + find -name 'Entrance Randomizer v*.zip' | sed 's/\.zip$//1' | sed 's/^\.\///1' + )" >> $GITHUB_OUTPUT + - name: Extract premade archive + run: | + 7z x \ + '${{ steps.packname.outputs.packname }}.zip' \ + -o'${{ steps.packname.outputs.packname }}' + - uses: actions/upload-artifact@v4 + with: + name: ${{ steps.packname.outputs.packname }} + path: ${{ steps.packname.outputs.packname }}/* diff --git a/.github/workflows/pack-randomizer.yaml b/.github/workflows/pack-randomizer.yaml index db37c96..047fb6f 100644 --- a/.github/workflows/pack-randomizer.yaml +++ b/.github/workflows/pack-randomizer.yaml @@ -24,12 +24,26 @@ env: FORCE_COLOR: 1 jobs: - pack-randomizer: + pack: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: '& "Dolphin scripts/pack-rando.ps1"' shell: pwsh + # upload-artifact will double zip, so unpack first + # https://github.com/actions/upload-artifact/issues/39 + - name: Get pack filename + id: packname + run: | + echo "packname=$( + find -name 'Entrance Randomizer v*.zip' | sed 's/\.zip$//1' | sed 's/^\.\///1' + )" >> $GITHUB_OUTPUT + - name: Extract premade archive + run: | + 7z x \ + '${{ steps.packname.outputs.packname }}.zip' \ + -o'${{ steps.packname.outputs.packname }}' - uses: actions/upload-artifact@v4 with: - path: "Entrance Randomizer v*.zip" + name: ${{ steps.packname.outputs.packname }} + path: ${{ steps.packname.outputs.packname }}/* diff --git a/.github/workflows/typecheck.yaml b/.github/workflows/tests.yaml similarity index 76% rename from .github/workflows/typecheck.yaml rename to .github/workflows/tests.yaml index a1711a2..f7fcca8 100644 --- a/.github/workflows/typecheck.yaml +++ b/.github/workflows/tests.yaml @@ -1,4 +1,4 @@ -name: Typecheck +name: Tests on: workflow_dispatch: # Allows manual triggers @@ -41,3 +41,13 @@ jobs: - uses: jakebailey/pyright-action@v2 with: version: ${{ steps.pyright_version.outputs.PYRIGHT_VERSION }} + + verify_newsfragments: + name: Verify Newsfragments + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: python .github/verify_newsfragments.py + - run: python -m pip install towncrier + # - run: python -m towncrier check + - run: python -m towncrier build --draft --version check diff --git a/.markdownlint.jsonc b/.markdownlint.jsonc new file mode 100644 index 0000000..ce4064d --- /dev/null +++ b/.markdownlint.jsonc @@ -0,0 +1,4 @@ +{ + "MD041": false, + "MD013": false, +} diff --git a/Dolphin scripts/Entrance Randomizer/CHANGELOG.md b/Dolphin scripts/Entrance Randomizer/CHANGELOG.md new file mode 100644 index 0000000..c7a7169 --- /dev/null +++ b/Dolphin scripts/Entrance Randomizer/CHANGELOG.md @@ -0,0 +1,97 @@ +# Changelog + +All notable changes to the Entrance Randomizer will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). The version semantics are inspired by [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and go as follow: + +```txt +Major.Minor.Patch + +Major: New major feature or functionality (stays 0 until the first "stable" release) +Minor: Affects seed +Patch: Does't affect seed (assuming same settings) +``` + +This project uses [*towncrier*](https://towncrier.readthedocs.io/) and the changes for the upcoming release can be found in [newsfragments](./newsfragments). + +To add a changelog entry, add a new file `..md` to the `newsfragments` folder. +(See the different [fragment types](https://towncrier.readthedocs.io/en/latest/tutorial.html#creating-news-fragments)) + + + +## 0.4.0 - 2024-07-13 + +### Features + +- - Add back crash site now that we can avoid the default entrance that resets progression + - Added back teleporters as they're possibly fixed to activate when entering the right entrance + - Add more info on-screen and in logs about entrances and unrandomized transitions + + -- by @Avasam ([#37](https://github.com/Avasam/ptle-tools/issues/37)) +- - Guaranteed that if `CONFIGS.LINKED_TRANSITIONS == True` then all connections in the game are actually 2-way with the correct entrances + - Added all four basic 1-way transitions (the geysers for instance) to the randomization process and made them randomized as well + - Added Algorithm that guarantees that if `CONFIGS.LINKED_TRANSITIONS == True` then all levels are linked together in 1 big map, preventing any levels from being disconnected from the rest and therefore becoming unreachable + - Updated transition_infos.json to include all levels in the entire game (even the one's we're not randomizing yet) + - Updated list of levels we do NOT want to randomly pick as our starting_area + + -- by @wossnameGitHub ([#40](https://github.com/Avasam/ptle-tools/issues/40)) +- Add graph of connections in `.graphml` format -- by @wossnameGitHub ([#42](https://github.com/Avasam/ptle-tools/issues/42)) +- Added option to keep Jag1 & Jag2, or to skip jaguar fights entirely -- by @wossnameGitHub ([#45](https://github.com/Avasam/ptle-tools/issues/45)) +- - No longer spoiling the start area in the UI as it doesn't affect randomization anymore + - Added anti-softlock from missing items in Apu Illapu Shrine (Spinjas) and Scorpion Temple + - Prevent starting area being a cutscene, Native Minigame, or Twin Outpost + + -- by @Avasam ([#49](https://github.com/Avasam/ptle-tools/issues/49)) + +### Bugfixes + +- - Added anti-softlock from running into closed doors by bumping Harry's height in certain entrances + - Fix `global _shaman_shop_prices` error + + -- by @Avasam ([#37](https://github.com/Avasam/ptle-tools/issues/37)) + - Fix altar of ages not being accessible (made rando impossible) + - Fix non-existant transitions in list (could lead to impossible seed) + + -- by @wossnameGitHub ([#37](https://github.com/Avasam/ptle-tools/issues/37)) +- - St. Claire's Camp bugfix (now Day & Night works properly, and the Rando is now proven to be fully functional New Game until Credits) + - added 2 missing transitions (Twin Outposts -> Turtle Monument & Crystal Cavern -> Abandoned Cavern) + + -- by @wossnameGitHub ([#40](https://github.com/Avasam/ptle-tools/issues/40)) +- Improve starting area randomization: + + - Manual vs random starting area won't affect the seed + - Remove more unwanted starting areas possibilities + + -- by @wossnameGitHub ([#47](https://github.com/Avasam/ptle-tools/issues/47)) + +### Improved Documentation + +- Improve various texts: + + - Fixed displaying non-random starting area + - Changed how transition mapping is written in spoiler logs + - Added rando features and more known issues to the readme + - Fixed a few typos + + -- by @Avasam & @wossnameGitHub ([#46](https://github.com/Avasam/ptle-tools/issues/46)) + +### Deprecations and Removals + +- Temporarily removed 3 levels from the rando pool (Scorpion Temple (Harry), Mouth of Inti, Twin Outposts (Underwater)) -- by @wossnameGitHub ([#40](https://github.com/Avasam/ptle-tools/issues/40)) +- No longer spoiling the start area in the UI as it doesn't affect randomization anymore -- by @Avasam ([#49](https://github.com/Avasam/ptle-tools/issues/49)) + +### Misc + +- [#43](https://github.com/Avasam/ptle-tools/issues/43) + +## 0.3.0 - 2023-03-17 + +- Now comes with a readme! +- Linked transitions should now be a thing, although: "Non-vanilla transitions will always spawn Harry at the default entrance. This can be a bit confusing when using linked transitions." +- Crash Site and Teleports have been taken out of randomization (even if I could randomize at least the exits in non-linked transitions, I decided it's easier for now to just keep them vanilla) +- The Altar of Ages shortcut back to BBCamp after the cutscene from the first visit has been disabled. This standardizes exits. +- St. Claire's Excavation Camp Day and Night are now considered the same map for the Randomizer. And visiting Altar of Ages to get night camp is now enforced. +- Removed St. Claire's Excavation Camp, Apu Illapu Shrine (aka Spinjas) and Scorpion Temple from possible random starting areas (avoids immediate impossible seeds and getting TNT as your first area). +- Added Spoiler logs! (should be under dolphin-scripting-preview2/User/Logs, check Dolphin logs to see the exact location). You can now validate the seed is even possible. If a transition isn't listed in the spoiler log, it's vanilla. + +Other than that, still no logic, this prototype is still mainly focused on exploring possibilities, finding issues and edgecases. diff --git a/Dolphin scripts/Entrance Randomizer/lib/constants.py b/Dolphin scripts/Entrance Randomizer/lib/constants.py index 0f14d67..5609001 100644 --- a/Dolphin scripts/Entrance Randomizer/lib/constants.py +++ b/Dolphin scripts/Entrance Randomizer/lib/constants.py @@ -10,14 +10,10 @@ from dolphin import memory # pyright: ignore[reportMissingModuleSource] from lib.transition_infos import transition_infos -__version__ = "0.4.5" -""" -Major: New major feature or functionality - -Minor: Affects seed - -Patch: Does't affect seed (assuming same settings) -""" +__version = "0.4.0" +"""See CHANGELOG.md for version semantics.""" +__dev_version = "local" +__version__ = f"{__version}-{__dev_version}" print(f"Python version: {sys.version}") print(f"Rando version: {__version__}") diff --git a/Dolphin scripts/Entrance Randomizer/lib/graph_creation.py b/Dolphin scripts/Entrance Randomizer/lib/graph_creation.py index 440fc1e..8ff5405 100644 --- a/Dolphin scripts/Entrance Randomizer/lib/graph_creation.py +++ b/Dolphin scripts/Entrance Randomizer/lib/graph_creation.py @@ -1,7 +1,6 @@ from __future__ import annotations -from collections.abc import Mapping, MutableMapping, Sequence -from copy import copy +from collections.abc import Mapping, Sequence from enum import IntEnum, auto from pathlib import Path @@ -192,15 +191,14 @@ def create_edges( def create_graphml( - transitions_map: MutableMapping[tuple[int, int], tuple[int, int]], + transitions_map: Mapping[tuple[int, int], tuple[int, int]], temp_disabled_exits: Sequence[tuple[int, int]], closed_door_exits: Container[tuple[int, int]], seed_string: SeedType, starting_area: int, ): - all_transitions = copy(transitions_map) - for item in temp_disabled_exits: - all_transitions[item] = item + # In Python 3.9 this can be simplified to | + all_transitions = {**transitions_map, **{item: item for item in temp_disabled_exits}} graphml_text = ( '' diff --git a/Dolphin scripts/Entrance Randomizer/newsfragments/.gitignore b/Dolphin scripts/Entrance Randomizer/newsfragments/.gitignore new file mode 100644 index 0000000..2f550f6 --- /dev/null +++ b/Dolphin scripts/Entrance Randomizer/newsfragments/.gitignore @@ -0,0 +1 @@ +# This only exists to keep this folder in git. Even when empty. diff --git a/Dolphin scripts/Entrance Randomizer/newsfragments/65.feature.md b/Dolphin scripts/Entrance Randomizer/newsfragments/65.feature.md new file mode 100644 index 0000000..1d197ae --- /dev/null +++ b/Dolphin scripts/Entrance Randomizer/newsfragments/65.feature.md @@ -0,0 +1 @@ +"Immediate spirit fights" is optional and configurable -- by @Avasam diff --git a/Dolphin scripts/Entrance Randomizer/newsfragments/69.doc.md b/Dolphin scripts/Entrance Randomizer/newsfragments/69.doc.md new file mode 100644 index 0000000..c756066 --- /dev/null +++ b/Dolphin scripts/Entrance Randomizer/newsfragments/69.doc.md @@ -0,0 +1 @@ +Development versions are now automatically packed and uploaded as artefacts. Link added to readme. -- by @Avasam diff --git a/Dolphin scripts/Entrance Randomizer/newsfragments/70.doc.md b/Dolphin scripts/Entrance Randomizer/newsfragments/70.doc.md new file mode 100644 index 0000000..077dc1a --- /dev/null +++ b/Dolphin scripts/Entrance Randomizer/newsfragments/70.doc.md @@ -0,0 +1 @@ +Initialized the changelog using Towncrier & automatically pack release versions -- by @Avasam diff --git a/Dolphin scripts/Entrance Randomizer/newsfragments/87.feature.md b/Dolphin scripts/Entrance Randomizer/newsfragments/87.feature.md new file mode 100644 index 0000000..8b2e89a --- /dev/null +++ b/Dolphin scripts/Entrance Randomizer/newsfragments/87.feature.md @@ -0,0 +1 @@ +When being sent to an Animal Temple that you haven't beaten yet, you will now instead be redirected to the Spirit Fight immediately -- by @wossnameGitHub diff --git a/Dolphin scripts/README.md b/Dolphin scripts/README.md index 0256513..755d8ae 100644 --- a/Dolphin scripts/README.md +++ b/Dolphin scripts/README.md @@ -33,7 +33,13 @@ Shaman Shop: 1. Use this fork of Dolphin . 2. Turn on "Scripting" logs and set Verbosity to "Error" or any option below (not "Notice"). -3. Download the zip file from Discord or zip it yourself using `pack-rando.ps1`. +3. Download the randomizer zip file, either: + - latest release: + - from [#randomizer](https://discord.com/channels/334793217138622464/1083867986068254760) channel on Discord; + - [release artefacts](https://github.com/Avasam/ptle-tools/actions/workflows/pack-randomizer-release.yaml?query=branch%3Amain+is%3Asuccess+event%3Apush) (requires a GitHub account); + - development build: + - zip it yourself using `pack-rando.ps1`; + - [development builds](https://github.com/Avasam/ptle-tools/actions/workflows/pack-randomizer.yaml?query=branch%3Amain+is%3Asuccess+event%3Apush) (requires a GitHub account); 4. Open this zip file and drop "Scripts" at the root of your Dolphin installation (the location and names are important!). 5. Configurations are found in `Scripts/Entrance Randomizer/CONFIGS.py`. 6. In Dolphin, under "Scripts", click "Add new Scripts" and select `Scripts/Entrance Randomizer/__main__.py`. @@ -57,12 +63,11 @@ In order to display the generated map take these steps: - Some seeds will result in impossible to complete configurations, because you might need some items to progress that you don't have yet. - When using `LINKED_TRANSITIONS = False` the generated `.graphml` map will become very hard to read, given the extreme amount of connections that will be drawn. - In rare occasions, a transition might send you to the game-intended level instead of the level decided by the randomizer (this is an issue with the script patching the destination). -- In very rare occasions, a transition might not make you enter a level from the correct entrance, but make you enter from the default entrance instead +- In rare occasions, a transition might not make you enter a level from the correct entrance, but make you enter from the default entrance instead - The odds of this happening increase dramatically if at any point in the run Harry died or a save file was loaded. - Some linked transitions are not spawning at the right entrance and use the default entrance instead. Known cases: - Jungle Canyon from Punchau Shrine - Bittenbinder's Camp from Mysterious Temple -- With `LINKED_TRANSITIONS = True`, one-way transitions are not randomized at all. ### Developing @@ -71,3 +76,12 @@ In order to display the generated map take these steps: 3. Clone this repository. 4. Run `symlink-scripts.ps1 ""`. 5. In Dolphin, under "Scripts", click "Add new Scripts" and select `Scripts/Entrance Randomizer/__main__.py`. + +#### Creating a release + +This section serves as a reminder for myself. To create a new release: + +1. Run [version-bump.ps1](/Dolphin%20scripts/version-bump.ps1). +2. Push to `main`. Any change to `CHANGELOG.md` should trigger a release pack. +3. Share on Discord with a link to the latest release section. +4. Unpin old version message, pin new version message. diff --git a/Dolphin scripts/pack-rando.ps1 b/Dolphin scripts/pack-rando.ps1 index 3d5c3a5..9ca79a8 100644 --- a/Dolphin scripts/pack-rando.ps1 +++ b/Dolphin scripts/pack-rando.ps1 @@ -1,9 +1,24 @@ +param ( + [switch] $Release = $False +) + $ScriptsFolder = "$PSScriptRoot\Scripts" $RandoFolderName = 'Entrance Randomizer' -$VersionLine = Get-Content "$PSScriptRoot\$RandoFolderName/lib/constants.py" | Select-String -Pattern '^__version__\s*=\s*".*"' -$RandoVersion = $VersionLine -replace '^\s*__version__\s*=\s*"', '' -replace '".*$', '' +$VersionFilePath = "$ScriptsFolder\$RandoFolderName/lib/constants.py" Remove-Item -Path $ScriptsFolder -Recurse -ErrorAction SilentlyContinue Copy-Item -Path "$PSScriptRoot\$RandoFolderName" -Destination "$ScriptsFolder\$RandoFolderName" -Recurse Copy-Item -Path "$PSScriptRoot\..\Various technical notes\transition_infos.json" -Destination "$ScriptsFolder\$RandoFolderName\lib" -Compress-Archive -Path $ScriptsFolder -DestinationPath "$RandoFolderName v$RandoVersion.zip" -Force -Remove-Item -Path $ScriptsFolder -Recurse + +$VersionFileContent = Get-Content $VersionFilePath +$VersionLine = $VersionFileContent | Select-String -Pattern '^__version\s*=\s*".*"' +$RandoVersion = $VersionLine -replace '^\s*__version\s*=\s*"', '' -replace '".*$', '' +if ($Release) { + $DevVersion = '' +} +else { + $DevVersion = git rev-parse --short HEAD +} +$VersionFileContent -replace '^\s*__dev_version.*', "__dev_version = `"$DevVersion`"" | Set-Content $VersionFilePath + +Compress-Archive -Path $ScriptsFolder -DestinationPath "$RandoFolderName v$RandoVersion-$DevVersion.zip" -Force +Remove-Item -Path $ScriptsFolder -Recurse -ErrorAction SilentlyContinue diff --git a/Dolphin scripts/version-bump.ps1 b/Dolphin scripts/version-bump.ps1 new file mode 100644 index 0000000..19eaf67 --- /dev/null +++ b/Dolphin scripts/version-bump.ps1 @@ -0,0 +1,8 @@ +$RandoFolderName = 'Entrance Randomizer' +$VersionFilePath = "$PSScriptRoot\$RandoFolderName/lib/constants.py" + +$RandoVersion = Read-Host 'Version number (X.X.X)' +$VersionFileContent = Get-Content $VersionFilePath +$VersionFileContent -replace '^\s*__version = .*', "__version = `"$RandoVersion`"" | Set-Content $VersionFilePath + +towncrier build --yes --version $RandoVersion diff --git a/pyproject.toml b/pyproject.toml index 56c9427..e18c699 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -193,3 +193,15 @@ reportUnnecessaryComparison = "warning" # Too strict reportMissingSuperCall = "none" reportUnusedCallResult = "none" + +# Once we have multiple changelogs to maintain, see +# https://towncrier.readthedocs.io/en/latest/monorepo.html +[tool.towncrier] +directory = "Dolphin scripts/Entrance Randomizer/newsfragments" +filename = "Dolphin scripts/Entrance Randomizer/CHANGELOG.md" +issue_format = "[#{issue}](https://github.com/Avasam/ptle-tools/issues/{issue})" +package = "Entrance Randomizer" +package_dir = "Dolphin scripts" +start_string = "\n" +title_format = "## {version} - {project_date}" +underlines = ["", "", ""]